Skip to content

libprimesieve 8.0 ABI changes

Kim Walisch edited this page Jun 12, 2022 · 13 revisions

There have been a few changes in the ABI (Application binary interface) of libprimesieve-8.0 compared to libprimesieve-7.x. This ABI break was necessary to fix undefined behavior present in libprimesieve-7.x (in primesieve::iterator). The API remains backwards compatible. If your program uses libprimesieve, simply recompiling your program against the latest libprimesieve-8.0 should be enough. If on the other hand you have written libprimesieve bindings for another programming language you need to migrate your code to the new ABI.

C ABI changes

Below are the ABI changes of the primesieve_iterator struct (header: primesieve/include/iterator.h) compared to libprimesieve-7.x. Pay attention to the primesieve_prev_prime() function, its decrementing has subtly changed in a non backwards compatible way.

--- a/include/primesieve/iterator.h
+++ b/include/primesieve/iterator.h
@@ -39,12 +39,9 @@ typedef struct
   size_t i;
-  size_t last_idx;
+  size_t size;
   uint64_t start;
-  uint64_t stop;
   uint64_t stop_hint;
-  uint64_t dist;
   uint64_t* primes;
-  void* vector;
-  void* primeGenerator;
+  void* memory;
   int is_error;
 } primesieve_iterator;

 static inline uint64_t primesieve_next_prime(primesieve_iterator* it)
 {
-  if (it->i++ == it->last_idx)
+  it->i += 1;
+  if (it->i >= it->size)
     primesieve_generate_next_primes(it);
   return it->primes[it->i];
 }

 static inline uint64_t primesieve_prev_prime(primesieve_iterator* it)
 {
-  if (it->i-- == 0)
+  if (it->i == 0)
     primesieve_generate_prev_primes(it);
+  it->i -= 1;
   return it->primes[it->i];
 }

If you want your code to support both libprimesieve-7.x and libprimesieve-8.x you can use something like this:

#include <primesieve.h>

#if PRIMESIEVE_VERSION_MAJOR >= 8
    typedef struct
    {
        size_t i;
        size_t size;
        uint64_t start;
        uint64_t stop_hint;
        uint64_t* primes;
        void* memory;
        int is_error;
    } primesieve_iterator; 

    static inline uint64_t primesieve_prev_prime(primesieve_iterator* it)
    {
      if (it->i == 0)
        primesieve_generate_prev_primes(it);
      it->i -= 1;
      return it->primes[it->i];
    }
#else
    typedef struct
    {
        size_t i;
        size_t last_idx;
        uint64_t start;
        uint64_t stop;
        uint64_t stop_hint;
        uint64_t dist;
        uint64_t* primes;
        void* vector;
        void* primeGenerator;
        int is_error;
    } primesieve_iterator;

    static inline uint64_t primesieve_prev_prime(primesieve_iterator* it)
    {
      if (it->i-- == 0)
        primesieve_generate_prev_primes(it);
      return it->primes[it->i];
    }
#endif

C++ ABI changes

Below are the ABI changes of the primesieve::iterator struct (header: primesieve/include/iterator.hpp) compared to libprimesieve-7.x. Pay attention to the prev_prime() method, its decrementing has subtly changed in a non backwards compatible way.

--- a/include/primesieve/iterator.hpp
+++ b/include/primesieve/iterator.hpp
@@ -14,32 +14,41 @@
-class PrimeGenerator;
-uint64_t get_max_stop();

-class iterator
+struct iterator
 {
-public:
-  iterator(uint64_t start = 0, uint64_t stop_hint = get_max_stop());
-  void skipto(uint64_t start, uint64_t stop_hint = get_max_stop());
+  iterator() noexcept;
+  iterator(uint64_t start, uint64_t stop_hint = std::numeric_limits<uint64_t>::max()) noexcept;
+  void skipto(uint64_t start, uint64_t stop_hint = std::numeric_limits<uint64_t>::max()) noexcept;
+  void clear() noexcept;

   uint64_t next_prime()
   {
-    if (i_++ == last_idx_)
+    i_ += 1;
+    if (i_ >= size_)
       generate_next_primes();
     return primes_[i_];
   }

   uint64_t prev_prime()
   {
-    if (i_-- == 0)
+    if (i_ == 0)
       generate_prev_primes();
+    i_ -= 1;
     return primes_[i_];
   }

@@ -83,17 +94,12 @@ public:
-private:
   std::size_t i_;
-  std::size_t last_idx_;
+  std::size_t size_;
-  std::vector<uint64_t> primes_;
   uint64_t start_;
-  uint64_t stop_;
   uint64_t stop_hint_;
-  uint64_t dist_;
-  std::unique_ptr<PrimeGenerator> primeGenerator_;
-  void generate_next_primes();
-  void generate_prev_primes();
+  uint64_t* primes_;
+  void* memory_;
 };

The signatures of the primesieve::generate_primes() functions from the primesieve.hpp header have also been modified to allow vector types other than std::vector. The API of the primesieve::generate_primes() functions (and of primesieve.hpp) is still backwards compatible to libprimesieve-7.x.

--- a/include/primesieve.hpp
+++ b/include/primesieve.hpp
@@ -13,50 +13,63 @@

 /// Store the primes <= stop in the primes vector.
-template <typename T>
-inline void generate_primes(uint64_t stop, std::vector<T>* primes)
+template <typename vect>
+inline void generate_primes(uint64_t stop, vect* primes)
 {
   if (primes)
     store_primes(0, stop, *primes);
 }

 /// Store the primes within the interval [start, stop] in the primes vector.
-template <typename T>
-inline void generate_primes(uint64_t start, uint64_t stop, std::vector<T>* primes)
+template <typename vect>
+inline void generate_primes(uint64_t start, uint64_t stop, vect* primes)
 {
   if (primes)
     store_primes(start, stop, *primes);
 }
 
 /// Store the first n primes in the primes vector.
-template <typename T>
-inline void generate_n_primes(uint64_t n, std::vector<T>* primes)
+template <typename vect>
+inline void generate_n_primes(uint64_t n, vect* primes)
 {
   if (primes)
     store_n_primes(n, 0, *primes);
 }
 
 /// Store the first n primes >= start in the primes vector.
-template <typename T>
-inline void generate_n_primes(uint64_t n, uint64_t start, std::vector<T>* primes)
+template <typename vect>
+inline void generate_n_primes(uint64_t n, uint64_t start, vect* primes)
 {
   if (primes)
     store_n_primes(n, start, *primes);
 }
Clone this wiki locally