#ifndef PRIMES_HPP
#define PRIMES_HPP

#include <cstdlib>
#include <utility>

namespace primes_impl {

   using Integer = std::size_t;
   template<Integer prime>
   constexpr bool is_prime(Integer candidate) {
      return candidate % prime;
   }
   template<Integer prime, Integer next, Integer... primes>
   constexpr bool is_prime(Integer candidate) {
      if (candidate % prime == 0) return false;
      return is_prime<next, primes...>(candidate);
   }
   template<Integer... primes>
   constexpr Integer seek_prime(Integer candidate) {
      if (is_prime<primes...>(candidate)) return candidate;
      return seek_prime<primes...>(candidate + 1);
   }
   template<Integer prime, Integer... primes>
   struct sequence {
      using next = sequence<
	 seek_prime<prime, primes...>(prime + 1),
	 prime, primes...
      >;
   };
   template<Integer N> struct gen_sequence {
      using type = typename gen_sequence<N-1>::type::next;
   };
   template<> struct gen_sequence<0> {
      using type = sequence<2>;
   };

} // namespace primes_impl

/* note that this generates a reversed sequence of primes,
   e.g. make_primes_sequence<3> delivers primes_sequence<5, 3, 2> */

template<std::size_t N>
using make_primes_sequence = typename primes_impl::gen_sequence<N>::type;
template<std::size_t... Primes>
using primes_sequence = typename primes_impl::sequence<Primes...>;

#endif
