LCOV - code coverage report
Current view: top level - third_party/fast_float - bigint.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 228 0.0 %
Date: 2024-05-15 13:15:52 Functions: 0 36 0.0 %

          Line data    Source code
       1             : #ifndef FASTFLOAT_BIGINT_H
       2             : #define FASTFLOAT_BIGINT_H
       3             : 
       4             : #include <algorithm>
       5             : #include <cstdint>
       6             : #include <climits>
       7             : #include <cstring>
       8             : 
       9             : #include "float_common.h"
      10             : 
      11             : namespace fast_float {
      12             : 
      13             : // the limb width: we want efficient multiplication of double the bits in
      14             : // limb, or for 64-bit limbs, at least 64-bit multiplication where we can
      15             : // extract the high and low parts efficiently. this is every 64-bit
      16             : // architecture except for sparc, which emulates 128-bit multiplication.
      17             : // we might have platforms where `CHAR_BIT` is not 8, so let's avoid
      18             : // doing `8 * sizeof(limb)`.
      19             : #if defined(FASTFLOAT_64BIT) && !defined(__sparc)
      20             : #define FASTFLOAT_64BIT_LIMB 1
      21             : typedef uint64_t limb;
      22             : constexpr size_t limb_bits = 64;
      23             : #else
      24             : #define FASTFLOAT_32BIT_LIMB
      25             : typedef uint32_t limb;
      26             : constexpr size_t limb_bits = 32;
      27             : #endif
      28             : 
      29             : typedef span<limb> limb_span;
      30             : 
      31             : // number of bits in a bigint. this needs to be at least the number
      32             : // of bits required to store the largest bigint, which is
      33             : // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or
      34             : // ~3600 bits, so we round to 4000.
      35             : constexpr size_t bigint_bits = 4000;
      36             : constexpr size_t bigint_limbs = bigint_bits / limb_bits;
      37             : 
      38             : // vector-like type that is allocated on the stack. the entire
      39             : // buffer is pre-allocated, and only the length changes.
      40             : template <uint16_t size>
      41             : struct stackvec {
      42             :   limb data[size];
      43             :   // we never need more than 150 limbs
      44             :   uint16_t length{0};
      45             : 
      46           0 :   stackvec() = default;
      47             :   stackvec(const stackvec &) = delete;
      48             :   stackvec &operator=(const stackvec &) = delete;
      49             :   stackvec(stackvec &&) = delete;
      50             :   stackvec &operator=(stackvec &&other) = delete;
      51             : 
      52             :   // create stack vector from existing limb span.
      53           0 :   FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) {
      54           0 :     FASTFLOAT_ASSERT(try_extend(s));
      55           0 :   }
      56             : 
      57           0 :   FASTFLOAT_CONSTEXPR14 limb& operator[](size_t index) noexcept {
      58             :     FASTFLOAT_DEBUG_ASSERT(index < length);
      59           0 :     return data[index];
      60             :   }
      61           0 :   FASTFLOAT_CONSTEXPR14 const limb& operator[](size_t index) const noexcept {
      62             :     FASTFLOAT_DEBUG_ASSERT(index < length);
      63           0 :     return data[index];
      64             :   }
      65             :   // index from the end of the container
      66           0 :   FASTFLOAT_CONSTEXPR14 const limb& rindex(size_t index) const noexcept {
      67             :     FASTFLOAT_DEBUG_ASSERT(index < length);
      68           0 :     size_t rindex = length - index - 1;
      69           0 :     return data[rindex];
      70             :   }
      71             : 
      72             :   // set the length, without bounds checking.
      73           0 :   FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept {
      74           0 :     length = uint16_t(len);
      75           0 :   }
      76           0 :   constexpr size_t len() const noexcept {
      77           0 :     return length;
      78             :   }
      79           0 :   constexpr bool is_empty() const noexcept {
      80           0 :     return length == 0;
      81             :   }
      82           0 :   constexpr size_t capacity() const noexcept {
      83           0 :     return size;
      84             :   }
      85             :   // append item to vector, without bounds checking
      86           0 :   FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept {
      87           0 :     data[length] = value;
      88           0 :     length++;
      89           0 :   }
      90             :   // append item to vector, returning if item was added
      91           0 :   FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept {
      92           0 :     if (len() < capacity()) {
      93           0 :       push_unchecked(value);
      94           0 :       return true;
      95             :     } else {
      96           0 :       return false;
      97             :     }
      98             :   }
      99             :   // add items to the vector, from a span, without bounds checking
     100           0 :   FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept {
     101           0 :     limb* ptr = data + length;
     102           0 :     std::copy_n(s.ptr, s.len(), ptr);
     103           0 :     set_len(len() + s.len());
     104           0 :   }
     105             :   // try to add items to the vector, returning if items were added
     106           0 :   FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept {
     107           0 :     if (len() + s.len() <= capacity()) {
     108           0 :       extend_unchecked(s);
     109           0 :       return true;
     110             :     } else {
     111           0 :       return false;
     112             :     }
     113             :   }
     114             :   // resize the vector, without bounds checking
     115             :   // if the new size is longer than the vector, assign value to each
     116             :   // appended item.
     117             :   FASTFLOAT_CONSTEXPR20
     118           0 :   void resize_unchecked(size_t new_len, limb value) noexcept {
     119           0 :     if (new_len > len()) {
     120           0 :       size_t count = new_len - len();
     121           0 :       limb* first = data + len();
     122           0 :       limb* last = first + count;
     123           0 :       ::std::fill(first, last, value);
     124           0 :       set_len(new_len);
     125             :     } else {
     126           0 :       set_len(new_len);
     127             :     }
     128           0 :   }
     129             :   // try to resize the vector, returning if the vector was resized.
     130           0 :   FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept {
     131           0 :     if (new_len > capacity()) {
     132           0 :       return false;
     133             :     } else {
     134           0 :       resize_unchecked(new_len, value);
     135           0 :       return true;
     136             :     }
     137             :   }
     138             :   // check if any limbs are non-zero after the given index.
     139             :   // this needs to be done in reverse order, since the index
     140             :   // is relative to the most significant limbs.
     141           0 :   FASTFLOAT_CONSTEXPR14 bool nonzero(size_t index) const noexcept {
     142           0 :     while (index < len()) {
     143           0 :       if (rindex(index) != 0) {
     144           0 :         return true;
     145             :       }
     146           0 :       index++;
     147             :     }
     148           0 :     return false;
     149             :   }
     150             :   // normalize the big integer, so most-significant zero limbs are removed.
     151           0 :   FASTFLOAT_CONSTEXPR14 void normalize() noexcept {
     152           0 :     while (len() > 0 && rindex(0) == 0) {
     153           0 :       length--;
     154             :     }
     155           0 :   }
     156             : };
     157             : 
     158             : fastfloat_really_inline FASTFLOAT_CONSTEXPR14
     159             : uint64_t empty_hi64(bool& truncated) noexcept {
     160           0 :   truncated = false;
     161           0 :   return 0;
     162             : }
     163             : 
     164             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
     165             : uint64_t uint64_hi64(uint64_t r0, bool& truncated) noexcept {
     166           0 :   truncated = false;
     167           0 :   int shl = leading_zeroes(r0);
     168           0 :   return r0 << shl;
     169             : }
     170             : 
     171             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
     172             : uint64_t uint64_hi64(uint64_t r0, uint64_t r1, bool& truncated) noexcept {
     173           0 :   int shl = leading_zeroes(r0);
     174           0 :   if (shl == 0) {
     175           0 :     truncated = r1 != 0;
     176           0 :     return r0;
     177             :   } else {
     178           0 :     int shr = 64 - shl;
     179           0 :     truncated = (r1 << shl) != 0;
     180           0 :     return (r0 << shl) | (r1 >> shr);
     181             :   }
     182             : }
     183             : 
     184             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
     185             : uint64_t uint32_hi64(uint32_t r0, bool& truncated) noexcept {
     186             :   return uint64_hi64(r0, truncated);
     187             : }
     188             : 
     189             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
     190             : uint64_t uint32_hi64(uint32_t r0, uint32_t r1, bool& truncated) noexcept {
     191             :   uint64_t x0 = r0;
     192             :   uint64_t x1 = r1;
     193             :   return uint64_hi64((x0 << 32) | x1, truncated);
     194             : }
     195             : 
     196             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
     197             : uint64_t uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool& truncated) noexcept {
     198             :   uint64_t x0 = r0;
     199             :   uint64_t x1 = r1;
     200             :   uint64_t x2 = r2;
     201             :   return uint64_hi64(x0, (x1 << 32) | x2, truncated);
     202             : }
     203             : 
     204             : // add two small integers, checking for overflow.
     205             : // we want an efficient operation. for msvc, where
     206             : // we don't have built-in intrinsics, this is still
     207             : // pretty fast.
     208             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
     209             : limb scalar_add(limb x, limb y, bool& overflow) noexcept {
     210             :   limb z;
     211             : // gcc and clang
     212             : #if defined(__has_builtin)
     213             :   #if __has_builtin(__builtin_add_overflow)
     214             :     if (!cpp20_and_in_constexpr()) {
     215             :       overflow = __builtin_add_overflow(x, y, &z);
     216             :       return z;
     217             :     }
     218             :   #endif
     219             : #endif
     220             : 
     221             :   // generic, this still optimizes correctly on MSVC.
     222           0 :   z = x + y;
     223           0 :   overflow = z < x;
     224           0 :   return z;
     225             : }
     226             : 
     227             : // multiply two small integers, getting both the high and low bits.
     228             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
     229             : limb scalar_mul(limb x, limb y, limb& carry) noexcept {
     230             : #ifdef FASTFLOAT_64BIT_LIMB
     231             :   #if defined(__SIZEOF_INT128__)
     232             :   // GCC and clang both define it as an extension.
     233           0 :   __uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry);
     234           0 :   carry = limb(z >> limb_bits);
     235           0 :   return limb(z);
     236             :   #else
     237             :   // fallback, no native 128-bit integer multiplication with carry.
     238             :   // on msvc, this optimizes identically, somehow.
     239             :   value128 z = full_multiplication(x, y);
     240             :   bool overflow;
     241             :   z.low = scalar_add(z.low, carry, overflow);
     242             :   z.high += uint64_t(overflow);  // cannot overflow
     243             :   carry = z.high;
     244             :   return z.low;
     245             :   #endif
     246             : #else
     247             :   uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry);
     248             :   carry = limb(z >> limb_bits);
     249             :   return limb(z);
     250             : #endif
     251             : }
     252             : 
     253             : // add scalar value to bigint starting from offset.
     254             : // used in grade school multiplication
     255             : template <uint16_t size>
     256             : inline FASTFLOAT_CONSTEXPR20
     257           0 : bool small_add_from(stackvec<size>& vec, limb y, size_t start) noexcept {
     258           0 :   size_t index = start;
     259           0 :   limb carry = y;
     260             :   bool overflow;
     261           0 :   while (carry != 0 && index < vec.len()) {
     262           0 :     vec[index] = scalar_add(vec[index], carry, overflow);
     263           0 :     carry = limb(overflow);
     264           0 :     index += 1;
     265             :   }
     266           0 :   if (carry != 0) {
     267           0 :     FASTFLOAT_TRY(vec.try_push(carry));
     268             :   }
     269           0 :   return true;
     270             : }
     271             : 
     272             : // add scalar value to bigint.
     273             : template <uint16_t size>
     274             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
     275             : bool small_add(stackvec<size>& vec, limb y) noexcept {
     276           0 :   return small_add_from(vec, y, 0);
     277             : }
     278             : 
     279             : // multiply bigint by scalar value.
     280             : template <uint16_t size>
     281             : inline FASTFLOAT_CONSTEXPR20
     282           0 : bool small_mul(stackvec<size>& vec, limb y) noexcept {
     283           0 :   limb carry = 0;
     284           0 :   for (size_t index = 0; index < vec.len(); index++) {
     285           0 :     vec[index] = scalar_mul(vec[index], y, carry);
     286             :   }
     287           0 :   if (carry != 0) {
     288           0 :     FASTFLOAT_TRY(vec.try_push(carry));
     289             :   }
     290           0 :   return true;
     291             : }
     292             : 
     293             : // add bigint to bigint starting from index.
     294             : // used in grade school multiplication
     295             : template <uint16_t size>
     296             : FASTFLOAT_CONSTEXPR20
     297           0 : bool large_add_from(stackvec<size>& x, limb_span y, size_t start) noexcept {
     298             :   // the effective x buffer is from `xstart..x.len()`, so exit early
     299             :   // if we can't get that current range.
     300           0 :   if (x.len() < start || y.len() > x.len() - start) {
     301           0 :       FASTFLOAT_TRY(x.try_resize(y.len() + start, 0));
     302             :   }
     303             : 
     304           0 :   bool carry = false;
     305           0 :   for (size_t index = 0; index < y.len(); index++) {
     306           0 :     limb xi = x[index + start];
     307           0 :     limb yi = y[index];
     308           0 :     bool c1 = false;
     309           0 :     bool c2 = false;
     310           0 :     xi = scalar_add(xi, yi, c1);
     311           0 :     if (carry) {
     312           0 :       xi = scalar_add(xi, 1, c2);
     313             :     }
     314           0 :     x[index + start] = xi;
     315           0 :     carry = c1 | c2;
     316             :   }
     317             : 
     318             :   // handle overflow
     319           0 :   if (carry) {
     320           0 :     FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start));
     321             :   }
     322           0 :   return true;
     323             : }
     324             : 
     325             : // add bigint to bigint.
     326             : template <uint16_t size>
     327             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
     328             : bool large_add_from(stackvec<size>& x, limb_span y) noexcept {
     329             :   return large_add_from(x, y, 0);
     330             : }
     331             : 
     332             : // grade-school multiplication algorithm
     333             : template <uint16_t size>
     334             : FASTFLOAT_CONSTEXPR20
     335           0 : bool long_mul(stackvec<size>& x, limb_span y) noexcept {
     336           0 :   limb_span xs = limb_span(x.data, x.len());
     337           0 :   stackvec<size> z(xs);
     338           0 :   limb_span zs = limb_span(z.data, z.len());
     339             : 
     340           0 :   if (y.len() != 0) {
     341           0 :     limb y0 = y[0];
     342           0 :     FASTFLOAT_TRY(small_mul(x, y0));
     343           0 :     for (size_t index = 1; index < y.len(); index++) {
     344           0 :       limb yi = y[index];
     345           0 :       stackvec<size> zi;
     346           0 :       if (yi != 0) {
     347             :         // re-use the same buffer throughout
     348           0 :         zi.set_len(0);
     349           0 :         FASTFLOAT_TRY(zi.try_extend(zs));
     350           0 :         FASTFLOAT_TRY(small_mul(zi, yi));
     351           0 :         limb_span zis = limb_span(zi.data, zi.len());
     352           0 :         FASTFLOAT_TRY(large_add_from(x, zis, index));
     353             :       }
     354             :     }
     355             :   }
     356             : 
     357           0 :   x.normalize();
     358           0 :   return true;
     359             : }
     360             : 
     361             : // grade-school multiplication algorithm
     362             : template <uint16_t size>
     363             : FASTFLOAT_CONSTEXPR20
     364           0 : bool large_mul(stackvec<size>& x, limb_span y) noexcept {
     365           0 :   if (y.len() == 1) {
     366           0 :     FASTFLOAT_TRY(small_mul(x, y[0]));
     367             :   } else {
     368           0 :     FASTFLOAT_TRY(long_mul(x, y));
     369             :   }
     370           0 :   return true;
     371             : }
     372             : 
     373             : template <typename = void>
     374             : struct pow5_tables {
     375             :   static constexpr uint32_t large_step = 135;
     376             :   static constexpr uint64_t small_power_of_5[] = {
     377             :     1UL, 5UL, 25UL, 125UL, 625UL, 3125UL, 15625UL, 78125UL, 390625UL,
     378             :     1953125UL, 9765625UL, 48828125UL, 244140625UL, 1220703125UL,
     379             :     6103515625UL, 30517578125UL, 152587890625UL, 762939453125UL,
     380             :     3814697265625UL, 19073486328125UL, 95367431640625UL, 476837158203125UL,
     381             :     2384185791015625UL, 11920928955078125UL, 59604644775390625UL,
     382             :     298023223876953125UL, 1490116119384765625UL, 7450580596923828125UL,
     383             :   };
     384             : #ifdef FASTFLOAT_64BIT_LIMB
     385             :   constexpr static limb large_power_of_5[] = {
     386             :     1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL,
     387             :     10482974169319127550UL, 198276706040285095UL};
     388             : #else
     389             :   constexpr static limb large_power_of_5[] = {
     390             :     4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U,
     391             :     1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U};
     392             : #endif
     393             : };
     394             : 
     395             : template <typename T>
     396             : constexpr uint32_t pow5_tables<T>::large_step;
     397             : 
     398             : template <typename T>
     399             : constexpr uint64_t pow5_tables<T>::small_power_of_5[];
     400             : 
     401             : template <typename T>
     402             : constexpr limb pow5_tables<T>::large_power_of_5[];
     403             : 
     404             : // big integer type. implements a small subset of big integer
     405             : // arithmetic, using simple algorithms since asymptotically
     406             : // faster algorithms are slower for a small number of limbs.
     407             : // all operations assume the big-integer is normalized.
     408             : struct bigint : pow5_tables<> {
     409             :   // storage of the limbs, in little-endian order.
     410             :   stackvec<bigint_limbs> vec;
     411             : 
     412           0 :   FASTFLOAT_CONSTEXPR20 bigint(): vec() {}
     413             :   bigint(const bigint &) = delete;
     414             :   bigint &operator=(const bigint &) = delete;
     415             :   bigint(bigint &&) = delete;
     416             :   bigint &operator=(bigint &&other) = delete;
     417             : 
     418           0 :   FASTFLOAT_CONSTEXPR20 bigint(uint64_t value): vec() {
     419             : #ifdef FASTFLOAT_64BIT_LIMB
     420           0 :     vec.push_unchecked(value);
     421             : #else
     422             :     vec.push_unchecked(uint32_t(value));
     423             :     vec.push_unchecked(uint32_t(value >> 32));
     424             : #endif
     425           0 :     vec.normalize();
     426           0 :   }
     427             : 
     428             :   // get the high 64 bits from the vector, and if bits were truncated.
     429             :   // this is to get the significant digits for the float.
     430           0 :   FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool& truncated) const noexcept {
     431             : #ifdef FASTFLOAT_64BIT_LIMB
     432           0 :     if (vec.len() == 0) {
     433           0 :       return empty_hi64(truncated);
     434           0 :     } else if (vec.len() == 1) {
     435           0 :       return uint64_hi64(vec.rindex(0), truncated);
     436             :     } else {
     437           0 :       uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated);
     438           0 :       truncated |= vec.nonzero(2);
     439           0 :       return result;
     440             :     }
     441             : #else
     442             :     if (vec.len() == 0) {
     443             :       return empty_hi64(truncated);
     444             :     } else if (vec.len() == 1) {
     445             :       return uint32_hi64(vec.rindex(0), truncated);
     446             :     } else if (vec.len() == 2) {
     447             :       return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated);
     448             :     } else {
     449             :       uint64_t result = uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated);
     450             :       truncated |= vec.nonzero(3);
     451             :       return result;
     452             :     }
     453             : #endif
     454             :   }
     455             : 
     456             :   // compare two big integers, returning the large value.
     457             :   // assumes both are normalized. if the return value is
     458             :   // negative, other is larger, if the return value is
     459             :   // positive, this is larger, otherwise they are equal.
     460             :   // the limbs are stored in little-endian order, so we
     461             :   // must compare the limbs in ever order.
     462           0 :   FASTFLOAT_CONSTEXPR20 int compare(const bigint& other) const noexcept {
     463           0 :     if (vec.len() > other.vec.len()) {
     464           0 :       return 1;
     465           0 :     } else if (vec.len() < other.vec.len()) {
     466           0 :       return -1;
     467             :     } else {
     468           0 :       for (size_t index = vec.len(); index > 0; index--) {
     469           0 :         limb xi = vec[index - 1];
     470           0 :         limb yi = other.vec[index - 1];
     471           0 :         if (xi > yi) {
     472           0 :           return 1;
     473           0 :         } else if (xi < yi) {
     474           0 :           return -1;
     475             :         }
     476             :       }
     477           0 :       return 0;
     478             :     }
     479             :   }
     480             : 
     481             :   // shift left each limb n bits, carrying over to the new limb
     482             :   // returns true if we were able to shift all the digits.
     483           0 :   FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept {
     484             :     // Internally, for each item, we shift left by n, and add the previous
     485             :     // right shifted limb-bits.
     486             :     // For example, we transform (for u8) shifted left 2, to:
     487             :     //      b10100100 b01000010
     488             :     //      b10 b10010001 b00001000
     489             :     FASTFLOAT_DEBUG_ASSERT(n != 0);
     490             :     FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8);
     491             : 
     492           0 :     size_t shl = n;
     493           0 :     size_t shr = limb_bits - shl;
     494           0 :     limb prev = 0;
     495           0 :     for (size_t index = 0; index < vec.len(); index++) {
     496           0 :       limb xi = vec[index];
     497           0 :       vec[index] = (xi << shl) | (prev >> shr);
     498           0 :       prev = xi;
     499             :     }
     500             : 
     501           0 :     limb carry = prev >> shr;
     502           0 :     if (carry != 0) {
     503           0 :       return vec.try_push(carry);
     504             :     }
     505           0 :     return true;
     506             :   }
     507             : 
     508             :   // move the limbs left by `n` limbs.
     509           0 :   FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept {
     510             :     FASTFLOAT_DEBUG_ASSERT(n != 0);
     511           0 :     if (n + vec.len() > vec.capacity()) {
     512           0 :       return false;
     513           0 :     } else if (!vec.is_empty()) {
     514             :       // move limbs
     515           0 :       limb* dst = vec.data + n;
     516           0 :       const limb* src = vec.data;
     517           0 :       std::copy_backward(src, src + vec.len(), dst + vec.len());
     518             :       // fill in empty limbs
     519           0 :       limb* first = vec.data;
     520           0 :       limb* last = first + n;
     521           0 :       ::std::fill(first, last, 0);
     522           0 :       vec.set_len(n + vec.len());
     523           0 :       return true;
     524             :     } else {
     525           0 :       return true;
     526             :     }
     527             :   }
     528             : 
     529             :   // move the limbs left by `n` bits.
     530           0 :   FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept {
     531           0 :     size_t rem = n % limb_bits;
     532           0 :     size_t div = n / limb_bits;
     533           0 :     if (rem != 0) {
     534           0 :       FASTFLOAT_TRY(shl_bits(rem));
     535             :     }
     536           0 :     if (div != 0) {
     537           0 :       FASTFLOAT_TRY(shl_limbs(div));
     538             :     }
     539           0 :     return true;
     540             :   }
     541             : 
     542             :   // get the number of leading zeros in the bigint.
     543           0 :   FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept {
     544           0 :     if (vec.is_empty()) {
     545           0 :       return 0;
     546             :     } else {
     547             : #ifdef FASTFLOAT_64BIT_LIMB
     548           0 :       return leading_zeroes(vec.rindex(0));
     549             : #else
     550             :       // no use defining a specialized leading_zeroes for a 32-bit type.
     551             :       uint64_t r0 = vec.rindex(0);
     552             :       return leading_zeroes(r0 << 32);
     553             : #endif
     554             :     }
     555             :   }
     556             : 
     557             :   // get the number of bits in the bigint.
     558           0 :   FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept {
     559           0 :     int lz = ctlz();
     560           0 :     return int(limb_bits * vec.len()) - lz;
     561             :   }
     562             : 
     563           0 :   FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept {
     564           0 :     return small_mul(vec, y);
     565             :   }
     566             : 
     567           0 :   FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept {
     568           0 :     return small_add(vec, y);
     569             :   }
     570             : 
     571             :   // multiply as if by 2 raised to a power.
     572           0 :   FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept {
     573           0 :     return shl(exp);
     574             :   }
     575             : 
     576             :   // multiply as if by 5 raised to a power.
     577           0 :   FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept {
     578             :     // multiply by a power of 5
     579           0 :     size_t large_length = sizeof(large_power_of_5) / sizeof(limb);
     580           0 :     limb_span large = limb_span(large_power_of_5, large_length);
     581           0 :     while (exp >= large_step) {
     582           0 :       FASTFLOAT_TRY(large_mul(vec, large));
     583           0 :       exp -= large_step;
     584             :     }
     585             : #ifdef FASTFLOAT_64BIT_LIMB
     586           0 :     uint32_t small_step = 27;
     587           0 :     limb max_native = 7450580596923828125UL;
     588             : #else
     589             :     uint32_t small_step = 13;
     590             :     limb max_native = 1220703125U;
     591             : #endif
     592           0 :     while (exp >= small_step) {
     593           0 :       FASTFLOAT_TRY(small_mul(vec, max_native));
     594           0 :       exp -= small_step;
     595             :     }
     596           0 :     if (exp != 0) {
     597             :       // Work around clang bug https://godbolt.org/z/zedh7rrhc
     598             :       // This is similar to https://github.com/llvm/llvm-project/issues/47746,
     599             :       // except the workaround described there don't work here
     600           0 :       FASTFLOAT_TRY(
     601             :         small_mul(vec, limb(((void)small_power_of_5[0], small_power_of_5[exp])))
     602             :       );
     603             :     }
     604             : 
     605           0 :     return true;
     606             :   }
     607             : 
     608             :   // multiply as if by 10 raised to a power.
     609           0 :   FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept {
     610           0 :     FASTFLOAT_TRY(pow5(exp));
     611           0 :     return pow2(exp);
     612             :   }
     613             : };
     614             : 
     615             : } // namespace fast_float
     616             : 
     617             : #endif

Generated by: LCOV version 1.14