Program Listing for File primes.hpp
↰ Return to documentation for file (include/primes.hpp)
#pragma once
#include "primes/euler_sieve_mult.hpp"
#include "primes/euler_sieve_sqrt.hpp"
using madlib::euler_sieve_mult;
using madlib::euler_sieve_sqrt;
using madlib::primes_interface;
#ifndef DEFAULT_PRIMES_IMPLEMENTATION
#define DEFAULT_PRIMES_IMPLEMENTATION euler_sieve_sqrt
#endif
namespace madlib {
// class declarations
template <typename PRIMES_IMPLEMENTATION> class primes;
template <class PRIMES_IMPLEMENTATION> class primes_iterator;
template <class PRIMES_IMPLEMENTATION> class primes_generator;
class primes_iterator_sentinel_t {};
constexpr primes_iterator_sentinel_t primes_iterator_sentinel;
// class definitions
template <class PRIMES_IMPLEMENTATION = DEFAULT_PRIMES_IMPLEMENTATION>
class primes_iterator {
/*
Since this iterator needs to index into a container which may over the
course of its operation invalidate iterators, both the owning class and and
the raw index it is using need to be kept.
*/
primes<PRIMES_IMPLEMENTATION> *owning_object;
size_t raw_idx;
public:
using value_type = typename madlib::prime_type;
using difference_type = ssize_t;
// Required by std::semi_regular, but if you use it then you are doing this
// wrong and your code _will_ break.
PRIMES_CONSTEXPR primes_iterator();
explicit PRIMES_CONSTEXPR
primes_iterator(primes<PRIMES_IMPLEMENTATION> *from);
explicit PRIMES_CONSTEXPR
primes_iterator(primes<PRIMES_IMPLEMENTATION> *from,
const unsigned_integral auto &initial_idx);
friend PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
operator+(const integral auto &lhs,
const primes_iterator<PRIMES_IMPLEMENTATION> &rhs);
friend PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
operator+(const primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const integral auto &rhs);
friend PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> &
operator+=(primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const integral auto &rhs);
friend PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
operator-(const integral auto &lhs,
const primes_iterator<PRIMES_IMPLEMENTATION> &rhs);
friend PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
operator-(const primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const integral auto &rhs);
template <class PRIMES_IMPLEMENTATION_OTHER>
friend PRIMES_CONSTEXPR difference_type
operator-(const primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const primes_iterator<PRIMES_IMPLEMENTATION_OTHER> &rhs);
friend PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> &
operator-=(primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const integral auto &rhs);
PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> &operator++();
PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> operator++(int);
PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> &operator--();
PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> operator--(int);
PRIMES_CONSTEXPR value_type operator*() const;
template <class PRIMES_IMPLEMENTATION_OTHER>
friend PRIMES_CONSTEXPR bool
operator==(const primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const primes_iterator<PRIMES_IMPLEMENTATION_OTHER> &rhs) {
return lhs.raw_idx == rhs.raw_idx;
}
PRIMES_CONSTEXPR bool operator==(primes_iterator_sentinel_t) { // NOLINT
return false;
}
template <class PRIMES_IMPLEMENTATION_OTHER>
PRIMES_CONSTEXPR auto
operator<=>(const primes_iterator<PRIMES_IMPLEMENTATION_OTHER> &rhs) const {
return static_cast<long>(raw_idx) <=> static_cast<long>(rhs.raw_idx);
}
PRIMES_CONSTEXPR value_type operator[](const integral auto &index_from) const;
};
// Ensure at compile time that at least the declarations for the iterator are
// compliant to std::random_access_iterator.
static_assert(std::random_access_iterator<primes_iterator<euler_sieve_sqrt>>);
template <typename PRIMES_IMPLEMENTATION = DEFAULT_PRIMES_IMPLEMENTATION>
class primes : public PRIMES_IMPLEMENTATION {
public:
using value_type = prime_type;
using iterator = primes_iterator<PRIMES_IMPLEMENTATION>;
using const_iterator = const iterator;
using difference_type =
typename primes_iterator<PRIMES_IMPLEMENTATION>::difference_type;
PRIMES_CONSTEXPR primes() : PRIMES_IMPLEMENTATION() {}
explicit PRIMES_CONSTEXPR
primes(const unsigned_integral auto &initially_through);
explicit PRIMES_CONSTEXPR
primes(const signed_integral auto &initially_through);
PRIMES_CONSTEXPR primes<PRIMES_IMPLEMENTATION> &
calculate_primes_through(const unsigned_integral auto &through_value);
PRIMES_CONSTEXPR primes<PRIMES_IMPLEMENTATION> &
calculate_primes_through(const signed_integral auto &through_value);
PRIMES_CONSTEXPR bool is_prime(const unsigned_integral auto &number);
PRIMES_CONSTEXPR bool is_prime(const signed_integral auto &number);
PRIMES_CONSTEXPR prime_type get_nth_prime(const unsigned_integral auto &n);
PRIMES_CONSTEXPR void auto_expand_mapped_primes();
PRIMES_CONSTEXPR void map_next_prime();
PRIMES_CONSTEXPR size_t number_of_mapped_primes();
PRIMES_CONSTEXPR prime_type highest_odd_number_mapped();
PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> begin();
PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> cbegin() const;
static constexpr primes_iterator_sentinel_t end() {
return primes_iterator_sentinel;
}
};
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes<PRIMES_IMPLEMENTATION>::primes(
const unsigned_integral auto &initially_through)
: PRIMES_IMPLEMENTATION(initially_through) {}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes<PRIMES_IMPLEMENTATION>::primes(
const signed_integral auto &initially_through)
: PRIMES_IMPLEMENTATION(initially_through > 0
? static_cast<prime_type>(initially_through)
: 0) {}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes<PRIMES_IMPLEMENTATION> &
primes<PRIMES_IMPLEMENTATION>::calculate_primes_through(
const unsigned_integral auto &through_value) {
return static_cast<primes<PRIMES_IMPLEMENTATION> &>(
primes_interface<PRIMES_IMPLEMENTATION>::
_interface_calculate_primes_through(through_value));
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes<PRIMES_IMPLEMENTATION> &
primes<PRIMES_IMPLEMENTATION>::calculate_primes_through(
const signed_integral auto &through_value) {
if (through_value < 1) {
return static_cast<primes<PRIMES_IMPLEMENTATION> &>(*this);
}
return calculate_primes_through(static_cast<prime_type>(through_value));
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR bool
primes<PRIMES_IMPLEMENTATION>::is_prime(const unsigned_integral auto &number) {
return primes_interface<PRIMES_IMPLEMENTATION>::_interface_is_prime(number);
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR bool
primes<PRIMES_IMPLEMENTATION>::is_prime(const signed_integral auto &number) {
if (number < 2) {
return false;
}
return is_prime(static_cast<prime_type>(number));
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR prime_type
primes<PRIMES_IMPLEMENTATION>::get_nth_prime(const unsigned_integral auto &n) {
return primes_interface<PRIMES_IMPLEMENTATION>::_interface_get_nth_prime(n);
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR void
primes<PRIMES_IMPLEMENTATION>::auto_expand_mapped_primes() {
primes_interface<
PRIMES_IMPLEMENTATION>::_interface_auto_expand_mapped_primes();
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR void primes<PRIMES_IMPLEMENTATION>::map_next_prime() {
primes_interface<PRIMES_IMPLEMENTATION>::_interface_map_next_prime();
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR size_t
primes<PRIMES_IMPLEMENTATION>::number_of_mapped_primes() {
return primes_interface<
PRIMES_IMPLEMENTATION>::_interface_number_of_mapped_primes();
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR prime_type
primes<PRIMES_IMPLEMENTATION>::highest_odd_number_mapped() {
return primes_interface<
PRIMES_IMPLEMENTATION>::_interface_highest_odd_number_mapped();
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
primes<PRIMES_IMPLEMENTATION>::begin() {
return primes_iterator<PRIMES_IMPLEMENTATION>(
static_cast<primes<PRIMES_IMPLEMENTATION> *>(this));
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
primes<PRIMES_IMPLEMENTATION>::cbegin() const {
return primes_iterator<PRIMES_IMPLEMENTATION>(
static_cast<primes<PRIMES_IMPLEMENTATION> *>(this));
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR
primes_iterator<PRIMES_IMPLEMENTATION>::primes_iterator()
: owning_object(static_cast<primes<PRIMES_IMPLEMENTATION>>(nullptr)),
raw_idx(0) {}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>::primes_iterator(
primes<PRIMES_IMPLEMENTATION> *from)
: owning_object(from), raw_idx(0) {}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>::primes_iterator(
primes<PRIMES_IMPLEMENTATION> *from,
const unsigned_integral auto &initial_idx)
: owning_object(from), raw_idx(initial_idx) {}
// Tell Doxygen to skip considering this code.
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
operator+(const integral auto &lhs,
const primes_iterator<PRIMES_IMPLEMENTATION> &rhs) {
return primes_iterator(rhs.owning_object,
static_cast<size_t>(lhs) + rhs.raw_idx);
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
operator+(const primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const integral auto &rhs) {
return primes_iterator(lhs.owning_object,
lhs.raw_idx + static_cast<size_t>(rhs));
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> &
operator+=(primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const integral auto &rhs) {
lhs.raw_idx += rhs;
return lhs;
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
operator-(const integral auto &lhs,
const primes_iterator<PRIMES_IMPLEMENTATION> &rhs) {
return primes_iterator(rhs.owning_object,
static_cast<size_t>(lhs) - rhs.raw_idx);
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
operator-(const primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const integral auto &rhs) {
return primes_iterator(lhs.owning_object,
lhs.raw_idx + static_cast<size_t>(rhs));
}
template <class PRIMES_IMPLEMENTATION_LEFT, class PRIMES_IMPLEMENTATION_RIGHT>
inline PRIMES_CONSTEXPR ssize_t
operator-(const primes_iterator<PRIMES_IMPLEMENTATION_LEFT> &lhs,
const primes_iterator<PRIMES_IMPLEMENTATION_RIGHT> &rhs) {
return static_cast<ssize_t>(lhs.raw_idx - rhs.raw_idx);
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> &
operator-=(primes_iterator<PRIMES_IMPLEMENTATION> &lhs,
const integral auto &rhs) {
lhs.raw_idx -= rhs;
return lhs;
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> &
primes_iterator<PRIMES_IMPLEMENTATION>::operator++() {
++raw_idx;
return *this;
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
primes_iterator<PRIMES_IMPLEMENTATION>::operator++(int) {
primes_iterator old = *this;
++raw_idx;
return old;
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION> &
primes_iterator<PRIMES_IMPLEMENTATION>::operator--() {
--raw_idx;
return *this;
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR primes_iterator<PRIMES_IMPLEMENTATION>
primes_iterator<PRIMES_IMPLEMENTATION>::operator--(int) {
primes_iterator old = *this;
--raw_idx;
return old;
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR
typename primes_iterator<PRIMES_IMPLEMENTATION>::value_type
primes_iterator<PRIMES_IMPLEMENTATION>::operator*() const {
return owning_object->get_nth_prime(raw_idx);
}
template <class PRIMES_IMPLEMENTATION>
inline PRIMES_CONSTEXPR
typename primes_iterator<PRIMES_IMPLEMENTATION>::value_type
primes_iterator<PRIMES_IMPLEMENTATION>::operator[](
const integral auto &index_from) const {
// Here is a dragon.
return owning_object->get_nth_prime(
static_cast<size_t>(raw_idx + index_from));
}
template <class PRIMES_IMPLEMENTATION = DEFAULT_PRIMES_IMPLEMENTATION>
class prime_generator {
typename primes<PRIMES_IMPLEMENTATION>::size_type prime_idx = 0;
primes<PRIMES_IMPLEMENTATION> prime_object;
public:
PRIMES_CONSTEXPR typename primes<PRIMES_IMPLEMENTATION>::value_type
operator()() {
return prime_object.get_nth_prime(prime_idx++);
}
};
} // namespace madlib