Coverage Report

Created: 2026-08-17 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsoncons/include/jsoncons/utility/bigint.hpp
Line
Count
Source
1
// Copyright 2018 Daniel Parker
2
// Distributed under the Boost license, Version 1.0.
3
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5
// See https://github.com/danielaparker/jsoncons for latest version
6
7
#ifndef JSONCONS_UTILITY_BIGINT_HPP
8
#define JSONCONS_UTILITY_BIGINT_HPP
9
10
#include <algorithm> // std::max, std::min, std::reverse
11
#include <cassert> // assert
12
#include <climits>
13
#include <cmath> // std::fmod
14
#include <cstdint>
15
#include <cstring> // std::memcpy
16
#include <ostream>
17
#include <limits> // std::numeric_limits
18
#include <memory> // std::allocator
19
#include <string> // std::string
20
#include <system_error>
21
#include <type_traits> // std::enable_if
22
#include <vector> // std::vector
23
#include <limits> // std::numeric_limits
24
25
#include <jsoncons/config/compiler_support.hpp>
26
#include <jsoncons/config/jsoncons_config.hpp>
27
//#include <jsoncons/conversion_result.hpp>
28
#include <jsoncons/utility/more_type_traits.hpp>
29
30
namespace jsoncons {
31
32
namespace detail {
33
34
// bits per digit in the given radix times 1024
35
// Rounded up to avoid underallocation.
36
JSONCONS_INLINE_CONSTEXPR uint64_t bits_per_digit[] = { 0, 0,
37
    1024, 1624, 2048, 2378, 2648, 2875, 3072, 3247, 3402, 3543, 3672,
38
    3790, 3899, 4001, 4096, 4186, 4271, 4350, 4426, 4498, 4567, 4633,
39
    4696, 4756, 4814, 4870, 4923, 4975, 5025, 5074, 5120, 5166, 5210,
40
    5253, 5295};
41
42
template <typename Allocator>
43
class bigint_storage : private std::allocator_traits<Allocator>:: template rebind_alloc<uint64_t>
44
{
45
public:
46
    using word_allocator_type = typename std::allocator_traits<Allocator>:: template rebind_alloc<uint64_t>;
47
    using size_type = typename std::allocator_traits<word_allocator_type>::size_type;
48
    using word_type = typename std::allocator_traits<word_allocator_type>::value_type;
49
    static constexpr word_type max_word = (std::numeric_limits<word_type>::max)();
50
    static constexpr size_type mem_unit = sizeof(word_type);
51
    static constexpr size_type word_type_bits = sizeof(word_type) * 8;  // Number of bits
52
    static constexpr size_type word_type_half_bits = word_type_bits/2;
53
    static constexpr size_type inlined_capacity = 2;
54
public:
55
56
    template <class ValueType>
57
    class storage_view
58
    {
59
        ValueType* data_;
60
        size_type size_;
61
62
    public:
63
        storage_view(ValueType* data, size_type size)
64
69.4M
            : data_(data), size_(size)
65
69.4M
        {
66
69.4M
        }
jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long> >::storage_view<unsigned long>::storage_view(unsigned long*, unsigned long)
Line
Count
Source
64
62.8M
            : data_(data), size_(size)
65
62.8M
        {
66
62.8M
        }
jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long> >::storage_view<unsigned long const>::storage_view(unsigned long const*, unsigned long)
Line
Count
Source
64
6.61M
            : data_(data), size_(size)
65
6.61M
        {
66
6.61M
        }
67
68
        ValueType& operator[](size_type i) 
69
14.1G
        {
70
14.1G
            return data_[i];
71
14.1G
        }
jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long> >::storage_view<unsigned long>::operator[](unsigned long)
Line
Count
Source
69
14.1G
        {
70
14.1G
            return data_[i];
71
14.1G
        }
jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long> >::storage_view<unsigned long const>::operator[](unsigned long)
Line
Count
Source
69
3.23M
        {
70
3.23M
            return data_[i];
71
3.23M
        }
72
73
        ValueType operator[](size_type i) const
74
        {
75
            return data_[i];
76
        }
77
78
        ValueType* data()
79
1.00G
        {
80
1.00G
            return data_;
81
1.00G
        }
jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long> >::storage_view<unsigned long>::data()
Line
Count
Source
79
1.00G
        {
80
1.00G
            return data_;
81
1.00G
        }
jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long> >::storage_view<unsigned long const>::data()
Line
Count
Source
79
1.65M
        {
80
1.65M
            return data_;
81
1.65M
        }
82
83
        size_type size() const
84
74.2M
        {
85
74.2M
            return size_;
86
74.2M
        }
jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long> >::storage_view<unsigned long>::size() const
Line
Count
Source
84
60.8M
        {
85
60.8M
            return size_;
86
60.8M
        }
jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long> >::storage_view<unsigned long const>::size() const
Line
Count
Source
84
13.4M
        {
85
13.4M
            return size_;
86
13.4M
        }
87
        ValueType* begin()
88
17.8M
        {
89
17.8M
            return data_;
90
17.8M
        }
91
92
        ValueType* end()
93
17.8M
        {
94
17.8M
            return data_ + size_;
95
17.8M
        }
96
    };
97
98
    struct common_storage
99
    {
100
        uint8_t is_allocated_ : 1;
101
        uint8_t is_negative_ : 1;
102
        size_type size_;
103
    };
104
105
    struct inlined_storage
106
    {
107
        uint8_t is_allocated_ : 1;
108
        uint8_t is_negative_ : 1;
109
        size_type size_;
110
        word_type values_[inlined_capacity];
111
112
        inlined_storage()
113
650k
            : is_allocated_(false),
114
650k
            is_negative_(false),
115
650k
            size_(0),
116
650k
            values_{0, 0}
117
650k
        {
118
650k
        }
119
120
        template <typename T>
121
        inlined_storage(T n,
122
            typename std::enable_if<std::is_integral<T>::value &&
123
            sizeof(T) <= sizeof(int64_t) &&
124
            std::is_signed<T>::value>::type* = 0)
125
770k
            : is_allocated_(false),
126
770k
            is_negative_(n < 0),
127
770k
            size_(n == 0 ? 0 : 1)
128
770k
        {
129
770k
            values_[0] = n < 0 ? (word_type(0) - static_cast<word_type>(n)) : static_cast<word_type>(n);
130
770k
            values_[1] = 0;
131
770k
        }
_ZN8jsoncons6detail14bigint_storageINSt3__19allocatorImEEE15inlined_storageC2IiEET_PNS2_9enable_ifIXaaaasr3std11is_integralIS8_EE5valuelestS8_Lm8Esr3std9is_signedIS8_EE5valueEvE4typeE
Line
Count
Source
125
567k
            : is_allocated_(false),
126
567k
            is_negative_(n < 0),
127
567k
            size_(n == 0 ? 0 : 1)
128
567k
        {
129
567k
            values_[0] = n < 0 ? (word_type(0) - static_cast<word_type>(n)) : static_cast<word_type>(n);
130
567k
            values_[1] = 0;
131
567k
        }
_ZN8jsoncons6detail14bigint_storageINSt3__19allocatorImEEE15inlined_storageC2IlEET_PNS2_9enable_ifIXaaaasr3std11is_integralIS8_EE5valuelestS8_Lm8Esr3std9is_signedIS8_EE5valueEvE4typeE
Line
Count
Source
125
203k
            : is_allocated_(false),
126
203k
            is_negative_(n < 0),
127
203k
            size_(n == 0 ? 0 : 1)
128
203k
        {
129
203k
            values_[0] = n < 0 ? (word_type(0) - static_cast<word_type>(n)) : static_cast<word_type>(n);
130
203k
            values_[1] = 0;
131
203k
        }
132
133
        template <typename T>
134
        inlined_storage(T n,
135
            typename std::enable_if<std::is_integral<T>::value &&
136
            sizeof(T) <= sizeof(int64_t) &&
137
            !std::is_signed<T>::value>::type* = 0)
138
1.54M
            : is_allocated_(false),
139
1.54M
            is_negative_(false),
140
1.54M
            size_(n == 0 ? 0 : 1)
141
1.54M
        {
142
1.54M
            values_[0] = n;
143
1.54M
            values_[1] = 0;
144
1.54M
        }
_ZN8jsoncons6detail14bigint_storageINSt3__19allocatorImEEE15inlined_storageC2ImEET_PNS2_9enable_ifIXaaaasr3std11is_integralIS8_EE5valuelestS8_Lm8Entsr3std9is_signedIS8_EE5valueEvE4typeE
Line
Count
Source
138
1.50M
            : is_allocated_(false),
139
1.50M
            is_negative_(false),
140
1.50M
            size_(n == 0 ? 0 : 1)
141
1.50M
        {
142
1.50M
            values_[0] = n;
143
1.50M
            values_[1] = 0;
144
1.50M
        }
_ZN8jsoncons6detail14bigint_storageINSt3__19allocatorImEEE15inlined_storageC2IjEET_PNS2_9enable_ifIXaaaasr3std11is_integralIS8_EE5valuelestS8_Lm8Entsr3std9is_signedIS8_EE5valueEvE4typeE
Line
Count
Source
138
33.9k
            : is_allocated_(false),
139
33.9k
            is_negative_(false),
140
33.9k
            size_(n == 0 ? 0 : 1)
141
33.9k
        {
142
33.9k
            values_[0] = n;
143
33.9k
            values_[1] = 0;
144
33.9k
        }
145
146
        template <typename T>
147
        inlined_storage(T n,
148
            typename std::enable_if < std::is_integral<T>::value &&
149
            sizeof(int64_t) < sizeof(T) &&
150
            std::is_signed<T>::value > ::type* = 0)
151
            : is_allocated_(false),
152
            is_negative_(n < 0),
153
            size_(n == 0 ? 0 : inlined_capacity)
154
        {
155
            using unsigned_type = typename std::make_unsigned<T>::type;
156
157
            auto u = n < 0 ? (unsigned_type(0) - static_cast<unsigned_type>(n)) : static_cast<unsigned_type>(n);
158
            values_[0] = word_type(u & max_word);;
159
            u >>= word_type_bits;
160
            values_[1] = word_type(u & max_word);;
161
        }
162
163
        template <typename T>
164
        inlined_storage(T n,
165
            typename std::enable_if < std::is_integral<T>::value &&
166
            sizeof(int64_t) < sizeof(T) &&
167
            !std::is_signed<T>::value > ::type* = 0)
168
            : is_allocated_(false),
169
            is_negative_(false),
170
            size_(n == 0 ? 0 : inlined_capacity)
171
        {
172
            values_[0] = word_type(n & max_word);;
173
            n >>= word_type_bits;
174
            values_[1] = word_type(n & max_word);;
175
        }
176
177
        inlined_storage(const inlined_storage& stor)
178
3.44M
            : is_allocated_(false),
179
3.44M
            is_negative_(stor.is_negative_),
180
3.44M
            size_(stor.size_)
181
3.44M
        {
182
3.44M
            values_[0] = stor.values_[0];
183
3.44M
            values_[1] = stor.values_[1];
184
3.44M
        }
185
186
        inlined_storage& operator=(const inlined_storage& stor) = delete;
187
        inlined_storage& operator=(inlined_storage&& stor) = delete;
188
    };
189
190
    struct allocated_storage
191
    {
192
        using real_allocator_type = typename std::allocator_traits<Allocator>:: template rebind_alloc<word_type>;
193
        using pointer = typename std::allocator_traits<real_allocator_type>::pointer;
194
        static const size_type max_size = (std::numeric_limits<size_type>::max)()/sizeof(word_type);
195
196
        uint8_t is_allocated_ : 1;
197
        uint8_t is_negative_ : 1;
198
        size_type size_{0};
199
        size_type capacity_{0};
200
        pointer data_{nullptr};
201
202
        allocated_storage()
203
232k
            : is_allocated_(true),
204
232k
            is_negative_(false)
205
232k
        {
206
232k
        }
207
208
        allocated_storage(const allocated_storage& stor, const real_allocator_type& a)
209
1.91M
            : is_allocated_(true),
210
1.91M
              is_negative_(stor.is_negative_),
211
1.91M
              size_(stor.size_),
212
1.91M
              capacity_(stor.capacity_)
213
1.91M
        {
214
1.91M
            real_allocator_type alloc(a);
215
216
1.91M
            data_ = std::allocator_traits<real_allocator_type>::allocate(alloc, capacity_);
217
1.91M
            JSONCONS_TRY
218
1.91M
            {
219
1.91M
                std::allocator_traits<real_allocator_type>::construct(alloc, ext_traits::to_plain_pointer(data_));
220
1.91M
            }
221
1.91M
            JSONCONS_CATCH(...)
222
1.91M
            {
223
0
                std::allocator_traits<real_allocator_type>::deallocate(alloc, data_, capacity_);
224
0
                data_ = nullptr;
225
0
                JSONCONS_RETHROW;
226
0
            }
227
1.91M
            JSONCONS_ASSERT(stor.data_ != nullptr);
228
1.91M
            std::memcpy(data_, stor.data_, size_type(stor.size_ * sizeof(word_type)));
229
1.91M
        }
230
231
        allocated_storage(allocated_storage&& stor) noexcept
232
            : is_allocated_(stor.is_allocated_),
233
            is_negative_(stor.is_negative_),
234
            size_(stor.size_),
235
            capacity_(stor.capacity_),
236
            data_(stor.data_)
237
        {
238
            stor.is_allocated_ = false;
239
            stor.is_negative_ = false;
240
            stor.size_ = 0;
241
            stor.capacity_ = 0;
242
            stor.data_ = nullptr;
243
        }
244
245
        void destroy(const real_allocator_type& a) noexcept
246
2.14M
        {
247
2.14M
            if (data_ != nullptr)
248
2.14M
            {
249
2.14M
                real_allocator_type alloc(a);
250
2.14M
                std::allocator_traits<real_allocator_type>::deallocate(alloc, data_, capacity_);
251
2.14M
            }
252
2.14M
        }
253
254
        void reserve(size_type n, const real_allocator_type& a)
255
232k
        {
256
232k
            JSONCONS_ASSERT(n < max_size);
257
232k
            size_type capacity_new = round_up(n);
258
259
232k
            real_allocator_type alloc(a);
260
232k
            word_type* data_new = std::allocator_traits<real_allocator_type>::allocate(alloc, capacity_new);
261
232k
            if (size_ > 0)
262
0
            {
263
0
                std::memcpy(data_new, data_, size_type(size_ * sizeof(word_type)));
264
0
            }
265
232k
            if (data_ != nullptr)
266
0
            {
267
0
                std::allocator_traits<real_allocator_type>::deallocate(alloc, data_, capacity_);
268
0
            }
269
232k
            capacity_ = capacity_new;
270
232k
            data_ = data_new;
271
232k
        }
272
273
        // Find suitable new block size
274
        static size_type round_up(size_type i) 
275
232k
        {
276
232k
            size_type remainder = i % mem_unit;
277
232k
            size_type off = mem_unit - remainder;
278
232k
            bool testoff = i < max_size - off;
279
232k
            JSONCONS_ASSERT(testoff);
280
281
232k
            return i + off;
282
232k
        }
283
    };
284
285
    union
286
    {
287
        common_storage common_;
288
        inlined_storage inlined_;
289
        allocated_storage allocated_;
290
    };
291
292
    explicit bigint_storage(const Allocator& alloc = Allocator{})
293
650k
        : word_allocator_type(alloc)
294
650k
    {
295
650k
        ::new (&inlined_) inlined_storage();
296
650k
    }
297
298
    bigint_storage(const bigint_storage& other)
299
848k
        : word_allocator_type(other.get_allocator())
300
848k
    {
301
#if defined(__GNUC__) && JSONCONS_GCC_AVAILABLE(12,0,0)
302
# pragma GCC diagnostic push
303
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
304
#endif
305
848k
        if (!other.is_allocated())
306
639k
        {
307
639k
            ::new (&inlined_) inlined_storage(other.inlined_);
308
639k
        }
309
209k
        else
310
209k
        {
311
209k
            ::new (&allocated_) allocated_storage(other.allocated_, get_allocator());
312
209k
        }
313
#if defined(__GNUC__) && JSONCONS_GCC_AVAILABLE(12,0,0)
314
# pragma GCC diagnostic pop
315
#endif
316
848k
    }
317
318
    bigint_storage(const bigint_storage& other, const Allocator& alloc)
319
4.51M
        : word_allocator_type(alloc)
320
4.51M
    {
321
4.51M
        if (!other.is_allocated())
322
2.80M
        {
323
2.80M
            ::new (&inlined_) inlined_storage(other.inlined_);
324
2.80M
        }
325
1.70M
        else
326
1.70M
        {
327
1.70M
            ::new (&allocated_) allocated_storage(other.allocated_, alloc);
328
1.70M
        }
329
4.51M
    }
330
331
    bigint_storage(bigint_storage&& other) noexcept
332
        : word_allocator_type(other.get_allocator())
333
    {
334
        if (!other.is_allocated())
335
        {
336
            ::new (&inlined_) inlined_storage(other.inlined_);
337
        }
338
        else
339
        {
340
            ::new (&allocated_) allocated_storage(std::move(other.allocated_));
341
        }
342
    }
343
344
    bigint_storage(bigint_storage&& other, const Allocator& alloc) noexcept
345
        : word_allocator_type(alloc)
346
    {
347
        if (!other.is_allocated())
348
        {
349
            ::new (&inlined_) inlined_storage(other.inlined_);
350
        }
351
        else
352
        {
353
            ::new (&allocated_) allocated_storage(std::move(other.allocated_), get_allocator());
354
        }
355
    }
356
357
    template <typename Integer>
358
    bigint_storage(Integer n, const Allocator& alloc = Allocator(), 
359
        typename std::enable_if<std::is_integral<Integer>::value>::type* = 0)
360
2.31M
        : word_allocator_type(alloc)
361
2.31M
    {
362
2.31M
        ::new (&inlined_) inlined_storage(n);
363
2.31M
    }
_ZN8jsoncons6detail14bigint_storageINSt3__19allocatorImEEEC2IiEET_RKS4_PNS2_9enable_ifIXsr3std11is_integralIS7_EE5valueEvE4typeE
Line
Count
Source
360
567k
        : word_allocator_type(alloc)
361
567k
    {
362
567k
        ::new (&inlined_) inlined_storage(n);
363
567k
    }
_ZN8jsoncons6detail14bigint_storageINSt3__19allocatorImEEEC2ImEET_RKS4_PNS2_9enable_ifIXsr3std11is_integralIS7_EE5valueEvE4typeE
Line
Count
Source
360
1.50M
        : word_allocator_type(alloc)
361
1.50M
    {
362
1.50M
        ::new (&inlined_) inlined_storage(n);
363
1.50M
    }
_ZN8jsoncons6detail14bigint_storageINSt3__19allocatorImEEEC2IlEET_RKS4_PNS2_9enable_ifIXsr3std11is_integralIS7_EE5valueEvE4typeE
Line
Count
Source
360
203k
        : word_allocator_type(alloc)
361
203k
    {
362
203k
        ::new (&inlined_) inlined_storage(n);
363
203k
    }
_ZN8jsoncons6detail14bigint_storageINSt3__19allocatorImEEEC2IjEET_RKS4_PNS2_9enable_ifIXsr3std11is_integralIS7_EE5valueEvE4typeE
Line
Count
Source
360
33.9k
        : word_allocator_type(alloc)
361
33.9k
    {
362
33.9k
        ::new (&inlined_) inlined_storage(n);
363
33.9k
    }
364
365
    bigint_storage& operator=(const bigint_storage& other)
366
2.28M
    {
367
2.28M
        if (this != &other)
368
2.28M
        {
369
2.28M
            auto other_view = other.get_storage_view();
370
2.28M
            resize(other_view.size());
371
2.28M
            auto this_view = get_storage_view();
372
2.28M
            if (other_view.size() > 0)
373
1.65M
            {
374
1.65M
                common_.is_negative_ = other.common_.is_negative_;
375
1.65M
                std::memcpy(this_view.data(), other_view.data(), size_type(other_view.size()*sizeof(word_type)));
376
1.65M
            }
377
2.28M
        }
378
2.28M
        return *this;
379
2.28M
    }
380
381
    bigint_storage& operator&=(const bigint_storage& a)
382
    {
383
        auto this_view = get_storage_view();
384
        auto a_view = a.get_storage_view();
385
386
        const size_type old_length = this_view.size();
387
        const size_type new_length = (std::min)(old_length, a_view.size());
388
389
        if (new_length != old_length)
390
        {
391
            resize(new_length);
392
            this_view = get_storage_view();
393
        }
394
395
        if (new_length > 0)
396
        {
397
            const word_type* first = this_view.begin();
398
            word_type* p = this_view.end() - 1;
399
            const word_type* q = a_view.begin() + this_view.size() - 1;
400
401
            while ( p >= first )
402
            {
403
                *p-- &= *q--;
404
            }
405
406
            if (old_length > new_length)
407
            {
408
                if (is_allocated())
409
                {
410
                    std::memset(allocated_.data_ + new_length, 0, size_type(old_length - new_length*sizeof(word_type)));
411
                }
412
                else
413
                {
414
                    JSONCONS_ASSERT(new_length <= inlined_capacity);
415
                    for (size_type i = new_length; i < inlined_capacity; ++i)
416
                    {
417
                        inlined_.values_[i] = 0;
418
                    }
419
                }
420
            }
421
        }
422
423
        reduce();
424
425
        return *this;
426
    }
427
428
    void reduce()
429
17.8M
    {
430
17.8M
        if (common_.size_ > 0)
431
17.8M
        {
432
17.8M
            auto this_view = get_storage_view();
433
17.8M
            word_type* p = this_view.end() - 1;
434
17.8M
            word_type* first = this_view.begin();
435
533M
            while ( p >= first )
436
532M
            {
437
532M
                if ( *p )
438
16.9M
                {
439
16.9M
                    break;
440
16.9M
                }
441
515M
                --common_.size_;
442
515M
                --p;
443
515M
            }
444
17.8M
        }
445
17.8M
        if (common_.size_ == 0)
446
836k
        {
447
836k
            common_.is_negative_ = false;
448
836k
        }
449
17.8M
    }
450
451
    void reserve(size_type n)
452
18.3M
    {
453
18.3M
       if (capacity() < n)
454
232k
       {
455
232k
           if (!is_allocated())
456
232k
           {
457
232k
               size_type size = inlined_.size_;
458
232k
               size_type is_neg = inlined_.is_negative_;
459
232k
               word_type values[inlined_capacity] = {inlined_.values_[0], inlined_.values_[1]};
460
461
232k
               ::new (&allocated_) allocated_storage();
462
232k
               allocated_.reserve(n, get_allocator());
463
232k
               allocated_.size_ = size;
464
232k
               allocated_.is_negative_ = is_neg;
465
232k
               if (n >= 1)
466
232k
               {
467
232k
                   allocated_.data_[0] = values[0];
468
232k
               }
469
232k
               if (n >= 2)
470
232k
               {
471
232k
                   allocated_.data_[1] = values[1];
472
232k
               }
473
232k
           }
474
0
           else
475
0
           {
476
0
               allocated_.reserve(n, get_allocator());
477
0
           }
478
232k
       }
479
18.3M
    }
480
481
    const word_allocator_type& get_allocator() const
482
8.93M
    {
483
8.93M
        return static_cast<const word_allocator_type&>(*this);
484
8.93M
    }
485
486
    void destroy() noexcept
487
8.32M
    {
488
8.32M
        if (is_allocated())
489
2.14M
        {
490
2.14M
            allocated_.destroy(get_allocator());
491
2.14M
            allocated_.~allocated_storage();
492
2.14M
        }
493
6.17M
        else
494
6.17M
        {
495
6.17M
            inlined_.~inlined_storage();
496
6.17M
        }
497
8.32M
    }
498
499
    constexpr bool is_allocated() const
500
48.5M
    {
501
48.5M
        return common_.is_allocated_;
502
48.5M
    }
503
504
    constexpr size_type capacity() const
505
18.3M
    {
506
18.3M
        return is_allocated() ? allocated_.capacity_ : inlined_capacity;
507
18.3M
    }
508
509
    bool is_negative() const
510
17.6M
    {
511
17.6M
        return common_.is_negative_;
512
17.6M
    }
513
514
    void set_negative(bool value) 
515
6.03M
    {
516
6.03M
        common_.is_negative_ = value;
517
6.03M
    }
518
519
    storage_view<word_type> get_storage_view()
520
62.8M
    {
521
62.8M
        return common_.is_allocated_ ? 
522
47.0M
            storage_view<word_type>{allocated_.data_, allocated_.size_} :
523
62.8M
            storage_view<word_type>{inlined_.values_, inlined_.size_};
524
62.8M
    }
525
526
    storage_view<const word_type> get_storage_view() const
527
6.61M
    {
528
6.61M
        return common_.is_allocated_ ? 
529
2.75M
            storage_view<const word_type>{allocated_.data_, allocated_.size_} :
530
6.61M
            storage_view<const word_type>{inlined_.values_, inlined_.size_};
531
6.61M
    }
532
533
    void resize(size_type new_length)
534
17.9M
    {
535
17.9M
        size_type old_length = common_.size_;
536
17.9M
        reserve(new_length);
537
17.9M
        common_.size_ = new_length;
538
539
17.9M
        if (old_length < new_length)
540
16.2M
        {
541
16.2M
            if (is_allocated())
542
13.2M
            {
543
13.2M
                std::memset(allocated_.data_+old_length, 0, size_type((new_length-old_length)*sizeof(word_type)));
544
13.2M
            }
545
3.01M
            else
546
3.01M
            {
547
3.01M
                JSONCONS_ASSERT(new_length <= inlined_capacity);
548
7.43M
                for (size_type i = old_length; i < inlined_capacity; ++i)
549
4.42M
                {
550
4.42M
                    inlined_.values_[i] = 0;
551
4.42M
                }
552
3.01M
            }
553
16.2M
        }
554
17.9M
    }
555
};
556
557
} // namespace detail
558
559
template <typename CharT>
560
struct to_bigint_result
561
{
562
    const CharT* ptr;
563
    std::errc ec;
564
    constexpr to_bigint_result(const CharT* ptr_)
565
        : ptr(ptr_), ec(std::errc{})
566
    {
567
    }
568
    constexpr to_bigint_result(const CharT* ptr_, std::errc ec_)
569
23.5k
        : ptr(ptr_), ec(ec_)
570
23.5k
    {
571
23.5k
    }
572
573
    to_bigint_result(const to_bigint_result&) = default;
574
575
    to_bigint_result& operator=(const to_bigint_result&) = default;
576
577
    constexpr explicit operator bool() const noexcept
578
19.2k
    {
579
19.2k
        return ec == std::errc{};
580
19.2k
    }
581
    std::error_code error_code() const
582
    {
583
        return make_error_code(ec);
584
    }
585
};
586
587
template <typename Allocator>
588
class basic_bigint;
589
590
template <typename CharT, typename Allocator>
591
to_bigint_result<CharT> to_bigint(const CharT* data, std::size_t length,
592
    basic_bigint<Allocator>& value, const Allocator& alloc);
593
594
template <typename CharT>
595
to_bigint_result<CharT> to_bigint(const CharT* data, std::size_t length,
596
    basic_bigint<std::allocator<uint64_t>>& value);
597
598
/*
599
This implementation is based on Chapter 2 and Appendix A of
600
Ammeraal, L. (1996) Algorithms and Data Structures in C++,
601
Chichester: John Wiley.
602
603
*/
604
605
606
template <typename Allocator = std::allocator<uint64_t>>
607
class basic_bigint 
608
{
609
    detail::bigint_storage<Allocator> storage_; 
610
public:
611
612
    using allocator_type = Allocator;
613
    using word_allocator_type = typename detail::bigint_storage<Allocator>::word_allocator_type;
614
    using allocator_traits_type = std::allocator_traits<word_allocator_type>;
615
    using stored_allocator_type = allocator_type;
616
    using pointer = typename allocator_traits_type::pointer;
617
    using size_type = typename detail::bigint_storage<Allocator>::size_type;
618
    using ssize_type = typename std::make_signed<size_type>::type;
619
    using word_type = typename detail::bigint_storage<Allocator>::word_type;
620
    using storage_view_type = typename detail::bigint_storage<Allocator>::template storage_view<word_type>;
621
    using const_storage_view_type = typename detail::bigint_storage<Allocator>::template storage_view<const word_type>;
622
623
    static constexpr size_type inlined_capacity = 2;
624
625
    static constexpr word_type max_word = (std::numeric_limits<word_type>::max)();
626
    static constexpr size_type word_type_bits = sizeof(word_type) * 8;  // Number of bits
627
    static constexpr size_type word_type_half_bits = word_type_bits/2;
628
629
    static constexpr uint16_t word_length = 8; // Use multiples of word_length words
630
    static constexpr word_type r_mask = (word_type(1) << word_type_half_bits) - 1;
631
    static constexpr word_type l_mask = max_word - r_mask;
632
    static constexpr word_type l_bit = max_word - (max_word >> 1);
633
    static constexpr word_type max_word_type_div_10 = (std::numeric_limits<word_type>::max)()/10u ;
634
    static constexpr word_type max_word_type_div_16 = (std::numeric_limits<word_type>::max)()/16u ;
635
    static constexpr word_type max_unsigned_power_10 = 10000000000000000000u; // max_unsigned_power_10 = ::pow(10, imax_unsigned_power_10)
636
    static constexpr size_type imax_unsigned_power_10 = 19u;
637
    static constexpr word_type max_unsigned_power_16 = 1152921504606846976u; // max_unsigned_power_16 = ::pow(16, imax_unsigned_power_16)
638
    static constexpr size_type imax_unsigned_power_16 = 15;
639
640
public:
641
153k
    basic_bigint() = default;
642
643
    explicit basic_bigint(const Allocator& alloc)
644
493k
        : storage_(alloc)
645
493k
    {
646
493k
    }
647
648
    template <typename CharT>
649
    basic_bigint(const CharT* s, const Allocator& alloc = Allocator())
650
2.15k
        : storage_(alloc)
651
2.15k
    {
652
2.15k
        auto r = jsoncons::to_bigint(s, std::char_traits<CharT>::length(s), *this, alloc);
653
2.15k
        if (r.ec != std::errc{})
654
0
        {
655
0
            JSONCONS_THROW(std::system_error((int)r.ec, std::system_category()));
656
0
        }
657
2.15k
    }
658
659
    template <typename CharT>
660
    basic_bigint(const CharT* s, size_type length, const Allocator& alloc = Allocator())
661
0
        : storage_(alloc)
662
0
    {
663
0
        auto r = jsoncons::to_bigint(s, length, *this, alloc);
664
0
        if (r.ec != std::errc{})
665
0
        {
666
0
            JSONCONS_THROW(std::system_error((int)r.ec, std::system_category()));
667
0
        }
668
0
    }
669
670
    basic_bigint(const basic_bigint& other)
671
848k
        : storage_(other.storage_)
672
848k
    {
673
848k
    }
674
675
    basic_bigint(const basic_bigint& other, const Allocator& alloc)
676
4.51M
        : storage_(other.storage_, alloc)
677
4.51M
    {
678
4.51M
    }
679
680
    basic_bigint(basic_bigint&& other) noexcept
681
        : storage_(std::move(other.storage_))
682
    {
683
    }
684
685
    basic_bigint(basic_bigint&& other, const Allocator& alloc) noexcept
686
        : storage_(std::move(other.storage_), alloc)
687
    {
688
    }
689
690
    template <typename Integer>
691
    basic_bigint(Integer n, const Allocator& alloc = Allocator(), 
692
                 typename std::enable_if<std::is_integral<Integer>::value>::type* = 0)
693
2.31M
        : storage_(n, alloc)
694
2.31M
    {
695
2.31M
    }
_ZN8jsoncons12basic_bigintINSt3__19allocatorImEEEC2IiEET_RKS3_PNS1_9enable_ifIXsr3std11is_integralIS6_EE5valueEvE4typeE
Line
Count
Source
693
567k
        : storage_(n, alloc)
694
567k
    {
695
567k
    }
_ZN8jsoncons12basic_bigintINSt3__19allocatorImEEEC2ImEET_RKS3_PNS1_9enable_ifIXsr3std11is_integralIS6_EE5valueEvE4typeE
Line
Count
Source
693
1.50M
        : storage_(n, alloc)
694
1.50M
    {
695
1.50M
    }
_ZN8jsoncons12basic_bigintINSt3__19allocatorImEEEC2IlEET_RKS3_PNS1_9enable_ifIXsr3std11is_integralIS6_EE5valueEvE4typeE
Line
Count
Source
693
203k
        : storage_(n, alloc)
694
203k
    {
695
203k
    }
_ZN8jsoncons12basic_bigintINSt3__19allocatorImEEEC2IjEET_RKS3_PNS1_9enable_ifIXsr3std11is_integralIS6_EE5valueEvE4typeE
Line
Count
Source
693
33.9k
        : storage_(n, alloc)
694
33.9k
    {
695
33.9k
    }
696
697
    template <typename StringViewLike,typename=typename std::enable_if<ext_traits::is_string_or_string_view<StringViewLike>::value>::type>
698
    basic_bigint(const StringViewLike& s)
699
2.15k
    {
700
2.15k
        auto r = jsoncons::to_bigint(s.data(), s.size(), *this);
701
2.15k
        if (r.ec != std::errc{})
702
62
        {
703
62
            JSONCONS_THROW(std::system_error((int)r.ec, std::system_category()));
704
62
        }
705
2.15k
    }
706
707
    ~basic_bigint() noexcept
708
8.32M
    {
709
8.32M
        storage_.destroy();
710
8.32M
    }
711
712
    word_allocator_type get_allocator() const
713
5.49M
    {
714
5.49M
        return storage_.get_allocator();
715
5.49M
    }
716
717
    storage_view_type get_storage_view()
718
42.7M
    {
719
42.7M
        return storage_.get_storage_view();
720
42.7M
    }
721
722
    const_storage_view_type get_storage_view() const
723
4.33M
    {
724
4.33M
        return storage_.get_storage_view();
725
4.33M
    }
726
727
    bool is_negative() const
728
17.6M
    {
729
17.6M
        return storage_.is_negative();
730
17.6M
    }
731
732
    void set_negative(bool value) 
733
6.03M
    {
734
6.03M
        storage_.set_negative(value);
735
6.03M
    }
736
737
    template <typename CharT>
738
    static basic_bigint<Allocator> parse_radix(const CharT* data, size_type length, uint8_t radix)
739
0
    {
740
0
        if (!(radix >= 2 && radix <= 16u))
741
0
        {
742
0
            JSONCONS_THROW(std::runtime_error("Unsupported radix"));
743
0
        }
744
745
0
        bool neg;
746
0
        if (*data == '-')
747
0
        {
748
0
            neg = true;
749
0
            data++;
750
0
            --length;
751
0
        }
752
0
        else
753
0
        {
754
0
            neg = false;
755
0
        }
756
757
0
        basic_bigint<Allocator> v = 0;
758
0
        for (size_type i = 0; i < length; i++)
759
0
        {
760
0
            CharT c = data[i];
761
0
            word_type d;
762
0
            switch (c)
763
0
            {
764
0
                case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
765
0
                    d = (word_type)(c - '0');
766
0
                    break;
767
0
                case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':
768
0
                    d = (word_type)(c - ('a' - 10u));
769
0
                    break;
770
0
                case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
771
0
                    d = (word_type)(c - ('A' - 10u));
772
0
                    break;
773
0
                default:
774
0
                    JSONCONS_THROW(std::runtime_error(std::string("Invalid digit in radix ") + std::to_string(radix) + ": \'" + (char)c + "\'"));
775
0
            }
776
0
            if (d >= radix)
777
0
            {
778
0
                JSONCONS_THROW(std::runtime_error(std::string("Invalid digit in radix ") + std::to_string(radix) + ": \'" + (char)c + "\'"));
779
0
            }
780
0
            v *= radix;
781
0
            v += d;
782
0
        }
783
784
0
        if ( neg )
785
0
        {
786
0
            v.set_negative(true);
787
0
        }
788
0
        return v;
789
0
    }
790
791
    static basic_bigint from_bytes_be(int signum, const uint8_t* bytes, size_type n)
792
444k
    {
793
444k
        static const double radix_log2 = std::log2(next_power_of_two(256));
794
        // Estimate how big the result will be, so we can pre-allocate it.
795
444k
        double bits = radix_log2 * n;
796
444k
        double big_digits = std::ceil(bits / 64.0);
797
        //std::cout << "ESTIMATED: " << big_digits << "\n";
798
799
444k
        basic_bigint<Allocator> v = 0;
800
444k
        v.reserve(static_cast<size_type>(big_digits));
801
802
6.86M
        for (size_type i = 0; i < n; i++)
803
6.42M
        {
804
6.42M
            v *= 256;
805
6.42M
            v += (word_type)(bytes[i]);
806
6.42M
        }
807
        //std::cout << "ACTUAL: " << v.size() << "\n";
808
809
444k
        if (signum < 0)
810
0
        {
811
0
            v.set_negative(true);
812
0
        }
813
814
444k
        return v;
815
444k
    }
816
817
    void resize(size_type new_length)
818
15.6M
    {
819
15.6M
        storage_.resize(new_length);
820
15.6M
    }
821
822
    void reserve(size_type n)
823
467k
    {
824
467k
        storage_.reserve(n);
825
467k
    }
826
827
    // operators
828
829
    bool operator!() const
830
    {
831
        return get_storage_view().size() == 0 ? true : false;
832
    }
833
834
    basic_bigint operator-() const
835
113k
    {
836
113k
        basic_bigint<Allocator> v(*this);
837
113k
        v.set_negative(!v.is_negative());
838
113k
        return v;
839
113k
    }
840
841
    basic_bigint& operator=( const basic_bigint& y )
842
2.28M
    {
843
2.28M
        storage_ = y.storage_;
844
2.28M
        return *this;
845
2.28M
    }
846
847
    template <typename IntegerType>
848
    typename std::enable_if<ext_traits::is_signed_integer<IntegerType>::value && sizeof(IntegerType) <= sizeof(word_type), basic_bigint<Allocator>&>::type
849
        operator+=(IntegerType y)
850
    {
851
        if ( is_negative() != (y < 0))
852
            return *this -= -y;
853
854
        if (y < 0)
855
        {
856
            y = -y;
857
        }
858
859
        word_type d;
860
        word_type carry = 0;
861
862
        auto this_view = get_storage_view();
863
        resize(this_view.size() + 1);
864
        this_view = get_storage_view();
865
866
        const size_t this_size = this_view.size();
867
        const size_t y_size = 1;
868
        for (size_type i = 0; i < y_size; i++ )
869
        {
870
            d = this_view[i] + carry;
871
            carry = d < carry;
872
            this_view[i] = d + y;
873
            if (this_view[i] < d)
874
                carry = 1;
875
        }
876
        for (size_type i = y_size; i < this_size && carry != 0; i++ )
877
        {
878
            d = this_view[i] + carry;
879
            carry = d < carry;
880
            this_view[i] = d;
881
        }
882
        reduce();
883
        return *this;
884
    }
885
886
    template <typename IntegerType>
887
    typename std::enable_if<ext_traits::is_unsigned_integer<IntegerType>::value && sizeof(IntegerType) <= sizeof(word_type), basic_bigint<Allocator>&>::type
888
        operator+=(IntegerType y)
889
7.28M
    {
890
7.28M
        if ( is_negative())
891
0
            return *this -= -basic_bigint<Allocator>(y);
892
893
7.28M
        word_type d;
894
7.28M
        word_type carry = 0;
895
896
7.28M
        auto this_view = get_storage_view();
897
7.28M
        resize(this_view.size() + 1);
898
899
7.28M
        this_view = get_storage_view();
900
7.28M
        const size_type this_size = this_view.size();
901
7.28M
        size_type y_size = 1;
902
903
7.28M
        d = this_view[0] + carry;
904
7.28M
        carry = d < carry;
905
7.28M
        this_view[0] = d + y;
906
7.28M
        if (this_view[0] < d)
907
14.9k
            carry = 1;
908
909
7.29M
        for (size_type i = y_size; i < this_size && carry != 0; ++i)
910
15.1k
        {
911
15.1k
            d = this_view[i] + carry;
912
15.1k
            carry = d < carry;
913
15.1k
            this_view[i] = d;
914
15.1k
        }
915
7.28M
        reduce();
916
7.28M
        return *this;
917
7.28M
    }
_ZN8jsoncons12basic_bigintINSt3__19allocatorImEEEpLImEENS1_9enable_ifIXaasr10ext_traits19is_unsigned_integerIT_EE5valuelestS7_Lm8EERS4_E4typeES7_
Line
Count
Source
889
7.22M
    {
890
7.22M
        if ( is_negative())
891
0
            return *this -= -basic_bigint<Allocator>(y);
892
893
7.22M
        word_type d;
894
7.22M
        word_type carry = 0;
895
896
7.22M
        auto this_view = get_storage_view();
897
7.22M
        resize(this_view.size() + 1);
898
899
7.22M
        this_view = get_storage_view();
900
7.22M
        const size_type this_size = this_view.size();
901
7.22M
        size_type y_size = 1;
902
903
7.22M
        d = this_view[0] + carry;
904
7.22M
        carry = d < carry;
905
7.22M
        this_view[0] = d + y;
906
7.22M
        if (this_view[0] < d)
907
2.04k
            carry = 1;
908
909
7.22M
        for (size_type i = y_size; i < this_size && carry != 0; ++i)
910
2.17k
        {
911
2.17k
            d = this_view[i] + carry;
912
2.17k
            carry = d < carry;
913
2.17k
            this_view[i] = d;
914
2.17k
        }
915
7.22M
        reduce();
916
7.22M
        return *this;
917
7.22M
    }
_ZN8jsoncons12basic_bigintINSt3__19allocatorImEEEpLIjEENS1_9enable_ifIXaasr10ext_traits19is_unsigned_integerIT_EE5valuelestS7_Lm8EERS4_E4typeES7_
Line
Count
Source
889
58.5k
    {
890
58.5k
        if ( is_negative())
891
0
            return *this -= -basic_bigint<Allocator>(y);
892
893
58.5k
        word_type d;
894
58.5k
        word_type carry = 0;
895
896
58.5k
        auto this_view = get_storage_view();
897
58.5k
        resize(this_view.size() + 1);
898
899
58.5k
        this_view = get_storage_view();
900
58.5k
        const size_type this_size = this_view.size();
901
58.5k
        size_type y_size = 1;
902
903
58.5k
        d = this_view[0] + carry;
904
58.5k
        carry = d < carry;
905
58.5k
        this_view[0] = d + y;
906
58.5k
        if (this_view[0] < d)
907
12.9k
            carry = 1;
908
909
71.4k
        for (size_type i = y_size; i < this_size && carry != 0; ++i)
910
12.9k
        {
911
12.9k
            d = this_view[i] + carry;
912
12.9k
            carry = d < carry;
913
12.9k
            this_view[i] = d;
914
12.9k
        }
915
58.5k
        reduce();
916
58.5k
        return *this;
917
58.5k
    }
918
919
    basic_bigint& operator+=( const basic_bigint& y )
920
113k
    {
921
113k
        if ( is_negative() != y.is_negative())
922
0
            return *this -= -y;
923
924
113k
        auto y_view = y.get_storage_view();
925
        
926
113k
        word_type d;
927
113k
        word_type carry = 0;
928
929
113k
        auto this_view = get_storage_view();
930
113k
        resize( (std::max)(y_view.size(), this_view.size()) + 1 );
931
113k
        this_view = get_storage_view();
932
933
113k
        const size_t this_size = this_view.size();
934
113k
        const size_t y_size = y_view.size();
935
650k
        for (size_type i = 0; i < y_size; i++ )
936
537k
        {
937
537k
            d = this_view[i] + carry;
938
537k
            carry = d < carry;
939
537k
            this_view[i] = d + y_view[i];
940
537k
            if (this_view[i] < d)
941
6.67k
                carry = 1;
942
537k
        }
943
119k
        for (size_type i = y_size; i < this_size && carry != 0; i++ )
944
5.89k
        {
945
5.89k
            d = this_view[i] + carry;
946
5.89k
            carry = d < carry;
947
5.89k
            this_view[i] = d;
948
5.89k
        }
949
113k
        reduce();
950
113k
        return *this;
951
113k
    }
952
953
    basic_bigint& operator-=(const basic_bigint& y)
954
113k
    {
955
113k
        auto y_view = y.get_storage_view();
956
957
113k
        if ( is_negative() != y.is_negative())
958
113k
            return *this += -y;
959
0
        if ( (!is_negative() && y > *this) || (is_negative() && y < *this) )
960
0
            return *this = -(y - *this);
961
0
        word_type borrow = 0;
962
0
        word_type d;
963
0
        auto this_view = get_storage_view();
964
0
        const size_type this_size = this_view.size();
965
0
        const size_type y_size = y_view.size();
966
967
0
        for (size_type i = 0; i < y_size; i++ )
968
0
        {
969
0
            d = this_view[i] - borrow;
970
0
            borrow = d > this_view[i];
971
0
            this_view[i] = d - y_view[i];
972
0
            if ( this_view[i] > d )
973
0
                borrow = 1;
974
0
        }
975
0
        for (size_type i = y_size; i < this_size && borrow != 0; i++ )
976
0
        {
977
0
            d = this_view[i] - borrow;
978
0
            borrow = d > this_view[i];
979
0
            this_view[i] = d;
980
0
        }
981
0
        reduce();
982
0
        return *this;
983
0
    }
984
985
    template <typename IntegerType>
986
    typename std::enable_if<ext_traits::is_signed_integer<IntegerType>::value, basic_bigint<Allocator>&>::type
987
    operator*=(IntegerType y)
988
6.42M
    {
989
6.42M
        *this *= word_type(y < 0 ? -y : y);
990
6.42M
        if ( y < 0 )
991
0
            set_negative(!is_negative());
992
6.42M
        return *this;
993
6.42M
    }
994
995
    template <typename IntegerType>
996
    typename std::enable_if<ext_traits::is_unsigned_integer<IntegerType>::value, basic_bigint<Allocator>&>::type
997
    operator*=(IntegerType y)
998
7.31M
    {
999
7.31M
        auto this_view = get_storage_view();
1000
7.31M
        size_type len0 = this_view.size();
1001
7.31M
        word_type dig = this_view[0];
1002
7.31M
        word_type carry = 0;
1003
1004
7.31M
        resize(this_view.size() + 1);
1005
7.31M
        this_view = get_storage_view();
1006
1007
7.31M
        size_type i = 0;
1008
3.96G
        for (; i < len0; i++ )
1009
3.96G
        {
1010
3.96G
            word_type hi;
1011
3.96G
            word_type lo;
1012
3.96G
            DDproduct( dig, y, hi, lo );
1013
3.96G
            this_view[i] = lo + carry;
1014
3.96G
            dig = this_view[i+1];
1015
3.96G
            carry = hi + (this_view[i] < lo);
1016
3.96G
        }
1017
7.31M
        this_view[i] = carry;
1018
7.31M
        reduce();
1019
7.31M
        return *this;
1020
7.31M
    }
_ZN8jsoncons12basic_bigintINSt3__19allocatorImEEEmLIjEENS1_9enable_ifIXsr10ext_traits19is_unsigned_integerIT_EE5valueERS4_E4typeES7_
Line
Count
Source
998
690k
    {
999
690k
        auto this_view = get_storage_view();
1000
690k
        size_type len0 = this_view.size();
1001
690k
        word_type dig = this_view[0];
1002
690k
        word_type carry = 0;
1003
1004
690k
        resize(this_view.size() + 1);
1005
690k
        this_view = get_storage_view();
1006
1007
690k
        size_type i = 0;
1008
14.6M
        for (; i < len0; i++ )
1009
13.9M
        {
1010
13.9M
            word_type hi;
1011
13.9M
            word_type lo;
1012
13.9M
            DDproduct( dig, y, hi, lo );
1013
13.9M
            this_view[i] = lo + carry;
1014
13.9M
            dig = this_view[i+1];
1015
13.9M
            carry = hi + (this_view[i] < lo);
1016
13.9M
        }
1017
690k
        this_view[i] = carry;
1018
690k
        reduce();
1019
690k
        return *this;
1020
690k
    }
_ZN8jsoncons12basic_bigintINSt3__19allocatorImEEEmLImEENS1_9enable_ifIXsr10ext_traits19is_unsigned_integerIT_EE5valueERS4_E4typeES7_
Line
Count
Source
998
6.62M
    {
999
6.62M
        auto this_view = get_storage_view();
1000
6.62M
        size_type len0 = this_view.size();
1001
6.62M
        word_type dig = this_view[0];
1002
6.62M
        word_type carry = 0;
1003
1004
6.62M
        resize(this_view.size() + 1);
1005
6.62M
        this_view = get_storage_view();
1006
1007
6.62M
        size_type i = 0;
1008
3.95G
        for (; i < len0; i++ )
1009
3.94G
        {
1010
3.94G
            word_type hi;
1011
3.94G
            word_type lo;
1012
3.94G
            DDproduct( dig, y, hi, lo );
1013
3.94G
            this_view[i] = lo + carry;
1014
3.94G
            dig = this_view[i+1];
1015
3.94G
            carry = hi + (this_view[i] < lo);
1016
3.94G
        }
1017
6.62M
        this_view[i] = carry;
1018
6.62M
        reduce();
1019
6.62M
        return *this;
1020
6.62M
    }
Unexecuted instantiation: _ZN8jsoncons12basic_bigintINSt3__19allocatorImEEEmLIhEENS1_9enable_ifIXsr10ext_traits19is_unsigned_integerIT_EE5valueERS4_E4typeES7_
1021
 
1022
    basic_bigint& operator*=(basic_bigint y) 
1023
    {
1024
        auto this_view = get_storage_view();
1025
        auto y_view = y.get_storage_view();
1026
1027
        if (this_view.size() == 0 || y_view.size() == 0)
1028
        {
1029
            return *this = 0;
1030
        }
1031
1032
        bool difSigns = is_negative() != y.is_negative();
1033
        const size_type y_size = y_view.size();
1034
        if ( this_view.size() + y_size == 2 ) // size() = y.size() = 1
1035
        {
1036
            word_type a = this_view[0], b = y_view[0];
1037
            this_view[0] = a * b;
1038
            if ( this_view[0] / a != b )
1039
            {
1040
                resize(2);
1041
                this_view = get_storage_view();
1042
                DDproduct( a, b, this_view[1], this_view[0] );
1043
            }
1044
            set_negative(difSigns);
1045
            return *this;
1046
        }
1047
1048
        if ( this_view.size() == 1 )  //  && y.size() > 1
1049
        {
1050
            word_type digit = this_view[0];
1051
            *this = y;
1052
            *this *= digit;
1053
        }
1054
        else
1055
        {
1056
            if (y_view.size() == 1)
1057
            {
1058
                *this *= y_view[0];
1059
            }
1060
            else
1061
            {
1062
                size_type lenProd = this_view.size() + y_view.size();
1063
                word_type sumHi = 0, sumLo, hi, lo,
1064
                sumLo_old, sumHi_old, carry=0;
1065
                basic_bigint<Allocator> x = *this;
1066
                auto x_view = x.get_storage_view();
1067
                resize( lenProd ); // Give *this length lenProd
1068
                this_view = get_storage_view();
1069
1070
                for (size_type i = 0; i < lenProd; i++ )
1071
                {
1072
                    sumLo = sumHi;
1073
                    sumHi = carry;
1074
                    carry = 0;
1075
                    for (size_type jA=0; jA < x_view.size(); jA++)
1076
                    {
1077
                        if (JSONCONS_LIKELY(i >= jA))
1078
                        {
1079
                            size_type jB = i - jA;
1080
                            if (jB < y_view.size())
1081
                            {
1082
                                DDproduct( x_view[jA], y_view[jB], hi, lo );
1083
                                sumLo_old = sumLo;
1084
                                sumHi_old = sumHi;
1085
                                sumLo += lo;
1086
                                if ( sumLo < sumLo_old )
1087
                                    sumHi++;
1088
                                sumHi += hi;
1089
                                carry += (sumHi < sumHi_old);
1090
                            }
1091
                        }
1092
                    }
1093
                    this_view[i] = sumLo;
1094
                }
1095
            }
1096
        }
1097
       reduce();
1098
       set_negative(difSigns);
1099
       return *this;
1100
    }
1101
1102
    basic_bigint& operator/=( const basic_bigint& divisor )
1103
507
    {
1104
507
        basic_bigint<Allocator> r;
1105
507
        divide( divisor, *this, r, false );
1106
507
        return *this;
1107
507
    }
1108
1109
    basic_bigint& operator%=( const basic_bigint& divisor )
1110
4.17k
    {
1111
4.17k
        basic_bigint<Allocator> q;
1112
4.17k
        divide( divisor, q, *this, true );
1113
4.17k
        return *this;
1114
4.17k
    }
1115
1116
    basic_bigint& operator<<=(size_type k)
1117
1.55M
    {
1118
1.55M
        auto this_view = get_storage_view();
1119
1.55M
        size_type q = k / word_type_bits;
1120
1.55M
        if ( q ) // Increase storage_.size() by q:
1121
0
        {
1122
0
            resize(this_view.size() + q);
1123
0
            this_view = get_storage_view();
1124
0
            for (size_type i = this_view.size(); i-- > 0; )
1125
0
                this_view[i] = ( i < q ? 0 : this_view[i - q]);
1126
0
            k %= word_type_bits;
1127
0
        }
1128
1.55M
        if ( k )  // 0 < k < word_type_bits:
1129
138k
        {
1130
138k
            size_type k1 = word_type_bits - k;
1131
138k
            word_type mask = (word_type(1) << k) - word_type(1);
1132
138k
            resize( this_view.size() + 1 );
1133
138k
            this_view = get_storage_view();
1134
36.4M
            for (size_type i = this_view.size(); i-- > 0; )
1135
36.2M
            {
1136
36.2M
                this_view[i] <<= k;
1137
36.2M
                if ( i > 0 )
1138
36.1M
                    this_view[i] |= (this_view[i-1] >> k1) & mask;
1139
36.2M
            }
1140
138k
        }
1141
1.55M
        reduce();
1142
1.55M
        return *this;
1143
1.55M
    }
1144
1145
    basic_bigint& operator>>=(size_type k)
1146
69.1k
    {
1147
69.1k
        auto this_view = get_storage_view();
1148
69.1k
        size_type q = k / word_type_bits;
1149
69.1k
        if ( q >= this_view.size())
1150
0
        {
1151
0
            resize( 0 );
1152
0
            return *this;
1153
0
        }
1154
69.1k
        if (q > 0)
1155
0
        {
1156
0
            memmove( this_view.data(), this_view.data()+q, size_type((this_view.size() - q)*sizeof(word_type)) );
1157
0
            resize( size_type(this_view.size() - q) );
1158
0
            k %= word_type_bits;
1159
0
            if ( k == 0 )
1160
0
            {
1161
0
                reduce();
1162
0
                return *this;
1163
0
            }
1164
0
        }
1165
1166
69.1k
        this_view = get_storage_view();
1167
69.1k
        size_type n = size_type(this_view.size() - 1);
1168
69.1k
        ssize_type k1 = word_type_bits - k;
1169
69.1k
        word_type mask = (word_type(1) << k) - 1;
1170
36.1M
        for (size_type i = 0; i <= n; i++)
1171
36.0M
        {
1172
36.0M
            this_view[i] >>= k;
1173
36.0M
            if ( i < n )
1174
36.0M
                this_view[i] |= ((this_view[i+1] & mask) << k1);
1175
36.0M
        }
1176
69.1k
        reduce();
1177
69.1k
        return *this;
1178
69.1k
    }
1179
1180
    basic_bigint& operator++()
1181
    {
1182
        *this += 1;
1183
        return *this;
1184
    }
1185
1186
    basic_bigint<Allocator> operator++(int)
1187
    {
1188
        basic_bigint<Allocator> old = *this;
1189
        ++(*this);
1190
        return old;
1191
    }
1192
1193
    basic_bigint& operator--()
1194
    {
1195
        *this -= 1;
1196
        return *this;
1197
    }
1198
1199
    basic_bigint<Allocator> operator--(int)
1200
    {
1201
        basic_bigint<Allocator> old = *this;
1202
        --(*this);
1203
        return old;
1204
    }
1205
1206
    basic_bigint& operator|=( const basic_bigint& a )
1207
    {
1208
        auto a_view = a.get_storage_view();
1209
1210
        if (a_view.size() > 0)
1211
        {
1212
            auto this_view = get_storage_view();
1213
1214
            if ( this_view.size() < a_view.size())
1215
            {
1216
                resize( a_view.size());
1217
                this_view = get_storage_view();
1218
            }
1219
1220
            const word_type* qfirst = a_view.begin();
1221
            const word_type* q = a_view.end() - 1;
1222
            word_type* p = this_view.begin() + a_view.size() - 1;
1223
1224
            while (q >= qfirst)
1225
            {
1226
                *p-- |= *q--;
1227
            }
1228
            reduce();
1229
        }
1230
1231
        return *this;
1232
    }
1233
1234
    basic_bigint& operator^=( const basic_bigint& a )
1235
    {
1236
        auto a_view = a.get_storage_view();
1237
1238
        if (a_view.size() > 0)
1239
        {
1240
            auto this_view = get_storage_view();
1241
            if (this_view.size() < a_view.size())
1242
            {
1243
                resize(a_view.size());
1244
                this_view = get_storage_view();
1245
            }
1246
1247
            const word_type* qfirst = a_view.begin();
1248
            const word_type* q = a_view.end() - 1;
1249
            word_type* p = this_view.begin() + a_view.size() - 1;
1250
1251
            while (q >= qfirst)
1252
            {
1253
                *p-- ^= *q--;
1254
            }
1255
            reduce();
1256
        }
1257
1258
        return *this;
1259
    }
1260
1261
    basic_bigint& operator&=( const basic_bigint& a )
1262
    {
1263
        storage_ &= a.storage_;
1264
1265
        return *this;
1266
    }
1267
1268
    explicit operator bool() const
1269
    {
1270
       return get_storage_view().size() != 0 ? true : false;
1271
    }
1272
1273
    template <typename Integer, typename = typename std::enable_if<std::is_integral<Integer>::value && sizeof(Integer) <= sizeof(int64_t)>::type>
1274
    explicit operator Integer() const
1275
36.6k
    {
1276
36.6k
        auto this_view = get_storage_view();
1277
36.6k
        Integer x = 0;
1278
36.6k
        if (this_view.size() > 0)
1279
33.6k
        {
1280
33.6k
            x = static_cast<Integer>(this_view[0]);
1281
33.6k
        }
1282
1283
36.6k
        return is_negative() ? x*(-1) : x;
1284
36.6k
    }
Unexecuted instantiation: jsoncons::basic_bigint<std::__1::allocator<unsigned long> >::operator unsigned long<unsigned long, void>() const
jsoncons::basic_bigint<std::__1::allocator<unsigned long> >::operator long<long, void>() const
Line
Count
Source
1275
36.6k
    {
1276
36.6k
        auto this_view = get_storage_view();
1277
36.6k
        Integer x = 0;
1278
36.6k
        if (this_view.size() > 0)
1279
33.6k
        {
1280
33.6k
            x = static_cast<Integer>(this_view[0]);
1281
33.6k
        }
1282
1283
36.6k
        return is_negative() ? x*(-1) : x;
1284
36.6k
    }
1285
1286
    explicit operator double() const
1287
    {
1288
        double x = 0.0;
1289
        double factor = 1.0;
1290
        double values = (double)max_word + 1.0;
1291
1292
        auto this_view = get_storage_view();
1293
1294
        const word_type* p = this_view.begin();
1295
        const word_type* pEnd = this_view.end();
1296
        while ( p < pEnd )
1297
        {
1298
            x += *p*factor;
1299
            factor *= values;
1300
            ++p;
1301
        }
1302
1303
       return is_negative() ? -x : x;
1304
    }
1305
1306
    explicit operator long double() const
1307
    {
1308
        long double x = 0.0;
1309
        long double factor = 1.0;
1310
        long double values = (long double)max_word + 1.0;
1311
1312
        auto this_view = get_storage_view();
1313
1314
        const word_type* p = this_view.begin();
1315
        const word_type* pEnd = this_view.end();
1316
        while ( p < pEnd )
1317
        {
1318
            x += *p*factor;
1319
            factor *= values;
1320
            ++p;
1321
        }
1322
1323
       return is_negative() ? -x : x;
1324
    }
1325
1326
    template <typename Alloc>
1327
    void write_bytes_be(int& signum, std::vector<uint8_t,Alloc>& data) const
1328
0
    {
1329
0
        basic_bigint<Allocator> n(*this);
1330
0
        signum = (n < 0) ? -1 : (n > 0 ? 1 : 0); 
1331
1332
0
        basic_bigint<Allocator> divisor(256);
1333
1334
0
        while (n >= 256)
1335
0
        {
1336
0
            basic_bigint<Allocator> q;
1337
0
            basic_bigint<Allocator> r;
1338
0
            n.divide(divisor, q, r, true);
1339
0
            n = q;
1340
0
            data.push_back((uint8_t)(word_type)r);
1341
0
        }
1342
0
        if (n >= 0)
1343
0
        {
1344
0
            data.push_back((uint8_t)(word_type)n);
1345
0
        }
1346
1347
0
        std::reverse(data.begin(),data.end());
1348
0
    }
1349
1350
    std::string to_string() const
1351
    {
1352
        std::string s;
1353
        write_string(s);
1354
        return s;
1355
    }
1356
1357
    template <typename Ch,typename Traits,typename Alloc>
1358
    void write_string(std::basic_string<Ch,Traits,Alloc>& data) const
1359
544k
    {
1360
544k
        basic_bigint<Allocator> v(*this);
1361
544k
        auto v_view = v.get_storage_view();
1362
1363
544k
        size_type len = (v_view.size() * word_type_bits / 3) + 2;
1364
544k
        data.reserve(len);
1365
1366
544k
        if ( v_view.size() == 0 )
1367
51.4k
        {
1368
51.4k
            data.push_back('0');
1369
51.4k
        }
1370
493k
        else
1371
493k
        {
1372
493k
            word_type r;
1373
493k
            basic_bigint<Allocator> R(get_allocator());
1374
493k
            basic_bigint<Allocator> LP10(max_unsigned_power_10, get_allocator()); 
1375
1376
493k
            do
1377
1.29M
            {
1378
1.29M
                v.divide( LP10, v, R, true );
1379
1.29M
                v_view = v.get_storage_view();
1380
1381
1.29M
                auto R_view = R.get_storage_view();
1382
1.29M
                r = (R_view.size() ? R_view[0] : 0);
1383
18.2M
                for ( size_type j=0; j < imax_unsigned_power_10; j++ )
1384
17.4M
                {
1385
17.4M
                    data.push_back(char(r % 10u + '0'));
1386
17.4M
                    r /= 10u;
1387
17.4M
                    if ( r + v_view.size() == 0 )
1388
493k
                        break;
1389
17.4M
                }
1390
1.29M
            } 
1391
1.29M
            while ( v_view.size() > 0);
1392
1393
493k
            if (is_negative())
1394
111k
            {
1395
111k
                data.push_back('-');
1396
111k
            }
1397
493k
            std::reverse(data.begin(),data.end());
1398
493k
        }
1399
544k
    }
1400
1401
    std::string to_string_hex() const
1402
    {
1403
        std::string s;
1404
        write_string_hex(s);
1405
        return s;
1406
    }
1407
1408
    template <typename Ch,typename Traits,typename Alloc>
1409
    void write_string_hex(std::basic_string<Ch,Traits,Alloc>& data) const
1410
102k
    {
1411
1412
1413
102k
        basic_bigint<Allocator> v(*this);
1414
102k
        auto v_view = v.get_storage_view();
1415
1416
102k
        size_type len = (v_view.size() * basic_bigint<Allocator>::word_type_bits / 3) + 2;
1417
102k
        data.reserve(len);
1418
1419
102k
        if ( v_view.size() == 0 )
1420
9.77k
        {
1421
9.77k
            data.push_back('0');
1422
9.77k
        }
1423
92.6k
        else
1424
92.6k
        {
1425
92.6k
            word_type r;
1426
92.6k
            basic_bigint<Allocator> R;
1427
92.6k
            basic_bigint<Allocator> LP10 = max_unsigned_power_16; // LP10 = max_unsigned_power_16 = ::pow(16, imax_unsigned_power_16)
1428
92.6k
            do
1429
160k
            {
1430
160k
                v.divide( LP10, v, R, true );
1431
160k
                v_view = v.get_storage_view();
1432
160k
                auto R_view = R.get_storage_view();
1433
160k
                r = (R_view.size() ? R_view[0] : 0);
1434
1.48M
                for ( size_type j=0; j < imax_unsigned_power_16; j++ )
1435
1.41M
                {
1436
1.41M
                    uint8_t c = r % 16u;
1437
1.41M
                    data.push_back((c < 10u) ? ('0' + c) : ('A' - 10u + c));
1438
1.41M
                    r /= 16u;
1439
1.41M
                    if ( r + v_view.size() == 0 )
1440
92.6k
                        break;
1441
1.41M
                }
1442
160k
            } 
1443
160k
            while (v_view.size() > 0);
1444
1445
92.6k
            if (is_negative())
1446
2.03k
            {
1447
2.03k
                data.push_back('-');
1448
2.03k
            }
1449
92.6k
            std::reverse(data.begin(),data.end());
1450
92.6k
        }
1451
102k
    }
1452
1453
//  Global Operators
1454
1455
    friend bool operator==( const basic_bigint& x, const basic_bigint& y ) noexcept
1456
    {
1457
        return x.compare(y) == 0 ? true : false;
1458
    }
1459
1460
    friend bool operator==( const basic_bigint& x, int y ) noexcept
1461
    {
1462
        return x.compare(y) == 0 ? true : false;
1463
    }
1464
1465
    friend bool operator!=( const basic_bigint& x, const basic_bigint& y ) noexcept
1466
    {
1467
        return x.compare(y) != 0 ? true : false;
1468
    }
1469
1470
    friend bool operator!=( const basic_bigint& x, int y ) noexcept
1471
19.2k
    {
1472
19.2k
        return x.compare(basic_bigint<Allocator>(y)) != 0 ? true : false;
1473
19.2k
    }
1474
1475
    friend bool operator<( const basic_bigint& x, const basic_bigint& y ) noexcept
1476
1.47M
    {
1477
1.47M
       return x.compare(y) < 0 ? true : false;
1478
1.47M
    }
1479
1480
    friend bool operator<( const basic_bigint& x, int64_t y ) noexcept
1481
92.4k
    {
1482
92.4k
       return x.compare(y) < 0 ? true : false;
1483
92.4k
    }
1484
1485
    friend bool operator>( const basic_bigint& x, const basic_bigint& y ) noexcept
1486
0
    {
1487
0
        return x.compare(y) > 0 ? true : false;
1488
0
    }
1489
1490
    friend bool operator>( const basic_bigint& x, int y ) noexcept
1491
0
    {
1492
0
        return x.compare(basic_bigint<Allocator>(y)) > 0 ? true : false;
1493
0
    }
1494
1495
    friend bool operator<=( const basic_bigint& x, const basic_bigint& y ) noexcept
1496
    {
1497
        return x.compare(y) <= 0 ? true : false;
1498
    }
1499
1500
    friend bool operator<=( const basic_bigint& x, int y ) noexcept
1501
    {
1502
        return x.compare(y) <= 0 ? true : false;
1503
    }
1504
1505
    friend bool operator>=( const basic_bigint& x, const basic_bigint& y ) noexcept
1506
    {
1507
        return x.compare(y) >= 0 ? true : false;
1508
    }
1509
1510
    friend bool operator>=( const basic_bigint& x, int y ) noexcept
1511
0
    {
1512
0
        return x.compare(y) >= 0 ? true : false;
1513
0
    }
1514
1515
    friend basic_bigint<Allocator> operator+( basic_bigint x, const basic_bigint& y )
1516
    {
1517
        return x += y;
1518
    }
1519
1520
    friend basic_bigint<Allocator> operator+( basic_bigint x, int64_t y )
1521
    {
1522
        return x += y;
1523
    }
1524
1525
    friend basic_bigint<Allocator> operator-( basic_bigint x, const basic_bigint& y )
1526
79.7k
    {
1527
79.7k
        return x -= y;
1528
79.7k
    }
1529
1530
    friend basic_bigint<Allocator> operator-( basic_bigint x, int64_t y )
1531
0
    {
1532
0
        return x -= y;
1533
0
    }
1534
1535
    friend basic_bigint<Allocator> operator*( int64_t x, const basic_bigint& y )
1536
    {
1537
        return basic_bigint<Allocator>(y) *= x;
1538
    }
1539
1540
    friend basic_bigint<Allocator> operator*( basic_bigint<Allocator> x, const basic_bigint& y )
1541
    {
1542
        return x *= y;
1543
    }
1544
1545
    friend basic_bigint<Allocator> operator*( basic_bigint<Allocator> x, int64_t y )
1546
    {
1547
        return x *= y;
1548
    }
1549
1550
    friend basic_bigint<Allocator> operator/( basic_bigint<Allocator> x, const basic_bigint& y )
1551
    {
1552
        return x /= y;
1553
    }
1554
1555
    friend basic_bigint<Allocator> operator/( basic_bigint<Allocator> x, int y )
1556
    {
1557
        return x /= y;
1558
    }
1559
1560
    friend basic_bigint<Allocator> operator%( basic_bigint<Allocator> x, const basic_bigint& y )
1561
4.17k
    {
1562
4.17k
        return x %= y;
1563
4.17k
    }
1564
1565
    friend basic_bigint<Allocator> operator<<( basic_bigint<Allocator> u, unsigned k )
1566
    {
1567
        return u <<= k;
1568
    }
1569
1570
    friend basic_bigint<Allocator> operator<<( basic_bigint<Allocator> u, int k )
1571
    {
1572
        return u <<= k;
1573
    }
1574
1575
    friend basic_bigint<Allocator> operator>>( basic_bigint<Allocator> u, unsigned k )
1576
    {
1577
        return u >>= k;
1578
    }
1579
1580
    friend basic_bigint<Allocator> operator>>( basic_bigint<Allocator> u, int k )
1581
    {
1582
        return u >>= k;
1583
    }
1584
1585
    friend basic_bigint<Allocator> operator|( basic_bigint<Allocator> x, const basic_bigint& y )
1586
    {
1587
        return x |= y;
1588
    }
1589
1590
    friend basic_bigint<Allocator> operator|( basic_bigint<Allocator> x, int y )
1591
    {
1592
        return x |= y;
1593
    }
1594
1595
    friend basic_bigint<Allocator> operator|( basic_bigint<Allocator> x, unsigned y )
1596
    {
1597
        return x |= y;
1598
    }
1599
1600
    friend basic_bigint<Allocator> operator^( basic_bigint<Allocator> x, const basic_bigint& y )
1601
    {
1602
        return x ^= y;
1603
    }
1604
1605
    friend basic_bigint<Allocator> operator^( basic_bigint<Allocator> x, int y )
1606
    {
1607
        return x ^= y;
1608
    }
1609
1610
    friend basic_bigint<Allocator> operator^( basic_bigint<Allocator> x, unsigned y )
1611
    {
1612
        return x ^= y;
1613
    }
1614
1615
    friend basic_bigint<Allocator> operator&( basic_bigint<Allocator> x, const basic_bigint& y )
1616
    {
1617
        return x &= y;
1618
    }
1619
1620
    friend basic_bigint<Allocator> operator&( basic_bigint<Allocator> x, int y )
1621
    {
1622
        return x &= y;
1623
    }
1624
1625
    friend basic_bigint<Allocator> operator&( basic_bigint<Allocator> x, unsigned y )
1626
    {
1627
        return x &= y;
1628
    }
1629
1630
    template <typename CharT>
1631
    friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const basic_bigint& v)
1632
    {
1633
        std::basic_string<CharT> s;
1634
        v.write_string(s); 
1635
        os << s;
1636
1637
        return os;
1638
    }
1639
1640
    int compare( const basic_bigint& y ) const noexcept
1641
1.59M
    {
1642
1.59M
        auto this_view = get_storage_view();
1643
1.59M
        auto y_view = y.get_storage_view();
1644
1645
1.59M
        const size_type y_size = y_view.size();
1646
1.59M
        if ( this_view.size() == 0 && y_size == 0 )
1647
13.7k
            return 0;
1648
1.57M
        if ( is_negative() != y.is_negative())
1649
36.9k
            return y.is_negative() - is_negative();
1650
1.54M
        int code = 0;
1651
1.54M
        if ( this_view.size() < y_size)
1652
1.19k
            code = -1;
1653
1.53M
        else if ( this_view.size() > y_size)
1654
841k
            code = +1;
1655
697k
        else
1656
697k
        {
1657
736k
            for (size_type i = this_view.size(); i-- > 0; )
1658
697k
            {
1659
697k
                if (this_view[i] > y_view[i])
1660
71.3k
                {
1661
71.3k
                    code = 1;
1662
71.3k
                    break;
1663
71.3k
                }
1664
626k
                else if (this_view[i] < y_view[i])
1665
587k
                {
1666
587k
                    code = -1;
1667
587k
                    break;
1668
587k
                }
1669
697k
            }
1670
697k
        }
1671
1.54M
        return is_negative() ? -code : code;
1672
1.57M
    }
1673
1674
    void divide(const basic_bigint& denom_, basic_bigint& quot, basic_bigint& rem, bool remDesired ) const
1675
1.47M
    {
1676
1.47M
        basic_bigint<Allocator> denom(denom_, get_allocator());
1677
1.47M
        auto denom_view = denom.get_storage_view();
1678
1679
1.47M
        if (denom_view.size() == 0)
1680
8
        {
1681
8
            JSONCONS_THROW(std::runtime_error( "Zero divide." ));
1682
8
        }
1683
1.47M
        bool quot_neg = is_negative() ^ denom.is_negative();
1684
1.47M
        bool rem_neg = is_negative();
1685
1.47M
        basic_bigint<Allocator> num(*this, get_allocator());
1686
1.47M
        num.set_negative(false);
1687
1.47M
        denom.set_negative(false);
1688
1.47M
        if ( num < denom )
1689
588k
        {
1690
588k
            quot = word_type(0);
1691
588k
            quot.set_negative(quot_neg);
1692
588k
            rem = num;
1693
588k
            rem.set_negative(rem_neg);
1694
588k
            return;
1695
588k
        }
1696
1697
891k
        auto num_view = num.get_storage_view();
1698
891k
        auto quot_view = quot.get_storage_view();
1699
891k
        auto this_view = get_storage_view();
1700
1701
891k
        if ( denom_view.size() == 1 && num_view.size() == 1 )
1702
109k
        {
1703
109k
            quot = word_type( num_view[0]/denom_view[0] );
1704
109k
            rem = word_type( num_view[0]%denom_view[0] );
1705
109k
            quot.set_negative(quot_neg);
1706
109k
            rem.set_negative(rem_neg);
1707
109k
            return;
1708
109k
        }
1709
781k
        if (denom_view.size() == 1 && (denom_view[0] & l_mask) == 0 )
1710
4.45k
        {
1711
            // Denominator fits into a half word
1712
4.45k
            word_type divisor = denom_view[0], dHi = 0, q1, r, q2, dividend;
1713
4.45k
            quot.resize(this_view.size());
1714
4.45k
            quot_view = quot.get_storage_view();
1715
13.3k
            for (size_type i=this_view.size(); i-- > 0; )
1716
8.91k
            {
1717
8.91k
                dividend = (dHi << word_type_half_bits) | (this_view[i] >> word_type_half_bits);
1718
8.91k
                q1 = dividend/divisor;
1719
8.91k
                r = dividend % divisor;
1720
8.91k
                dividend = (r << word_type_half_bits) | (this_view[i] & r_mask);
1721
8.91k
                q2 = dividend/divisor;
1722
8.91k
                dHi = dividend % divisor;
1723
8.91k
                quot_view[i] = (q1 << word_type_half_bits) | q2;
1724
8.91k
            }
1725
4.45k
            quot.reduce();
1726
4.45k
            rem = dHi;
1727
4.45k
            quot.set_negative(quot_neg);
1728
4.45k
            rem.set_negative(rem_neg);
1729
4.45k
            return;
1730
4.45k
        }
1731
777k
        basic_bigint<Allocator> num0(num, get_allocator());
1732
777k
        basic_bigint<Allocator> denom0(denom, get_allocator());
1733
777k
        int x = 0;
1734
777k
        bool second_done = normalize(denom, num, x);
1735
777k
        denom_view = denom.get_storage_view();
1736
777k
        num_view = num.get_storage_view();
1737
1738
777k
        size_type l = denom_view.size() - 1;
1739
777k
        size_type n = num_view.size() - 1;
1740
777k
        quot.resize(n - l);
1741
777k
        quot_view = quot.get_storage_view();
1742
502M
        for (size_type i = quot_view.size(); i-- > 0; )
1743
501M
        {
1744
501M
            quot_view[i] = 0;
1745
501M
        }
1746
777k
        rem = num;
1747
777k
        auto rem_view = rem.get_storage_view();
1748
777k
        if ( rem_view[n] >= denom_view[l] )
1749
9.36k
        {
1750
9.36k
            rem.resize(rem_view.size() + 1);
1751
9.36k
            rem_view = rem.get_storage_view();
1752
9.36k
            n++;
1753
9.36k
            quot.resize(quot_view.size() + 1);
1754
9.36k
            quot_view = quot.get_storage_view();
1755
9.36k
        }
1756
777k
        word_type d = denom_view[l];
1757
1758
502M
        for ( size_type k = n; k > l; k-- )
1759
501M
        {
1760
501M
            word_type q = DDquotient(rem_view[k], rem_view[k-1], d);
1761
501M
            subtractmul( rem_view.data() + (k - l - 1), denom_view.data(), l + 1, q );
1762
501M
            quot_view[k - l - 1] = q;
1763
501M
        }
1764
777k
        quot.reduce();
1765
777k
        quot.set_negative(quot_neg);
1766
777k
        if (remDesired)
1767
776k
        {
1768
776k
            unnormalize(rem, x, second_done);
1769
776k
            rem.set_negative(rem_neg);
1770
776k
        }
1771
777k
    }
1772
private:
1773
1774
    void destroy() noexcept
1775
    {
1776
        storage_.destroy();
1777
    }
1778
    void DDproduct( word_type A, word_type B,
1779
                    word_type& hi, word_type& lo ) const
1780
    // Multiplying two digits: (hi, lo) = A * B
1781
4.46G
    {
1782
4.46G
        word_type hiA = A >> word_type_half_bits, loA = A & r_mask,
1783
4.46G
                   hiB = B >> word_type_half_bits, loB = B & r_mask;
1784
1785
4.46G
        lo = loA * loB;
1786
4.46G
        hi = hiA * hiB;
1787
4.46G
        word_type mid1 = loA * hiB;
1788
4.46G
        word_type mid2 = hiA * loB;
1789
4.46G
        word_type old = lo;
1790
4.46G
        lo += mid1 << word_type_half_bits;
1791
4.46G
            hi += (lo < old) + (mid1 >> word_type_half_bits);
1792
4.46G
        old = lo;
1793
4.46G
        lo += mid2 << word_type_half_bits;
1794
4.46G
            hi += (lo < old) + (mid2 >> word_type_half_bits);
1795
4.46G
    }
1796
1797
    word_type DDquotient( word_type A, word_type B, word_type d ) const
1798
    // Divide double word (A, B) by d. Quotient = (qHi, qLo)
1799
501M
    {
1800
501M
        word_type left, middle, right, qHi, qLo, x, dLo1,
1801
501M
                   dHi = d >> word_type_half_bits, dLo = d & r_mask;
1802
501M
        qHi = A/(dHi + 1);
1803
        // This initial guess of qHi may be too small.
1804
501M
        middle = qHi * dLo;
1805
501M
        left = qHi * dHi;
1806
501M
        x = B - (middle << word_type_half_bits);
1807
501M
        A -= (middle >> word_type_half_bits) + left + (x > B);
1808
501M
        B = x;
1809
501M
        dLo1 = dLo << word_type_half_bits;
1810
        // Increase qHi if necessary:
1811
727M
        while ( A > dHi || (A == dHi && B >= dLo1) )
1812
225M
        {
1813
225M
            x = B - dLo1;
1814
225M
            A -= dHi + (x > B);
1815
225M
            B = x;
1816
225M
            qHi++;
1817
225M
        }
1818
501M
        qLo = ((A << word_type_half_bits) | (B >> word_type_half_bits))/(dHi + 1);
1819
        // This initial guess of qLo may be too small.
1820
501M
        right = qLo * dLo;
1821
501M
        middle = qLo * dHi;
1822
501M
        x = B - right;
1823
501M
        A -= (x > B);
1824
501M
        B = x;
1825
501M
        x = B - (middle << word_type_half_bits);
1826
501M
            A -= (middle >> word_type_half_bits) + (x > B);
1827
501M
        B = x;
1828
        // Increase qLo if necessary:
1829
727M
        while ( A || B >= d )
1830
225M
        {
1831
225M
            x = B - d;
1832
225M
            A -= (x > B);
1833
225M
            B = x;
1834
225M
            qLo++;
1835
225M
        }
1836
501M
        return (qHi << word_type_half_bits) + qLo;
1837
501M
    }
1838
1839
    void subtractmul( word_type* a, word_type* b, size_type n, word_type& q ) const
1840
    // a -= q * b: b in n positions; correct q if necessary
1841
501M
    {
1842
501M
        word_type hi, lo, d, carry = 0;
1843
501M
        size_type i;
1844
1.00G
        for ( i = 0; i < n; i++ )
1845
501M
        {
1846
501M
            DDproduct( b[i], q, hi, lo );
1847
501M
            d = a[i];
1848
501M
            a[i] -= lo;
1849
501M
            if ( a[i] > d )
1850
126M
                carry++;
1851
501M
            d = a[i + 1];
1852
501M
            a[i + 1] -= hi + carry;
1853
501M
            carry = a[i + 1] > d;
1854
501M
        }
1855
501M
        if ( carry ) // q was too large
1856
2.73k
        {
1857
2.73k
            q--;
1858
2.73k
            carry = 0;
1859
8.30k
            for ( i = 0; i < n; i++ )
1860
5.57k
            {
1861
5.57k
                d = a[i] + carry;
1862
5.57k
                carry = d < carry;
1863
5.57k
                a[i] = d + b[i];
1864
5.57k
                if ( a[i] < d )
1865
3.70k
                    carry = 1;
1866
5.57k
            }
1867
2.73k
            a[n] = 0;
1868
2.73k
        }
1869
501M
    }
1870
1871
    bool normalize(basic_bigint& denom, basic_bigint& num, int& x) const
1872
777k
    {
1873
777k
        auto denom_view = denom.get_storage_view();
1874
777k
        if (denom_view.size() == 0)
1875
0
        {
1876
0
            return false;
1877
0
        }
1878
777k
        size_type r = denom_view.size() - 1;
1879
777k
        word_type y = denom_view[r];
1880
1881
777k
        x = 0;
1882
1.02M
        while ( (y & l_bit) == 0 )
1883
245k
        {
1884
245k
            y <<= 1;
1885
245k
            x++;
1886
245k
        }
1887
777k
        denom <<= x;
1888
777k
        num <<= x;
1889
1890
777k
        denom_view = denom.get_storage_view();
1891
777k
        if ( r > 0 && denom_view[r] < denom_view[r-1] )
1892
507
        {
1893
507
            denom *= max_word;
1894
507
            num *= max_word;
1895
507
            return true;
1896
507
        }
1897
776k
        return false;
1898
777k
    }
1899
1900
    void unnormalize(basic_bigint& rem, int x, bool secondDone) const
1901
776k
    {
1902
776k
        if (secondDone)
1903
507
        {
1904
507
            rem /= max_word;
1905
507
        }
1906
776k
        if ( x > 0 )
1907
69.1k
        {
1908
69.1k
            rem >>= x;
1909
69.1k
        }
1910
707k
        else
1911
707k
        {
1912
707k
            rem.reduce();
1913
707k
        }
1914
776k
    }
1915
1916
    void reduce()
1917
17.8M
    {
1918
17.8M
        storage_.reduce();
1919
17.8M
    }
1920
 
1921
2
    static word_type next_power_of_two(word_type n) {
1922
2
        n = n - 1;
1923
2
        n |= n >> 1u;
1924
2
        n |= n >> 2u;
1925
2
        n |= n >> 4u;
1926
2
        n |= n >> 8u;
1927
2
        n |= n >> 16u;
1928
2
        n |= n >> 32u;
1929
2
        return n + 1;
1930
2
    }
1931
1932
    template <typename CharT>
1933
    friend to_bigint_result<CharT> to_bigint(const CharT* s, basic_bigint& val, int radix)
1934
    {
1935
        return to_bigint(s, std::char_traits<CharT>::length(s), val, radix);
1936
    }
1937
1938
    template <typename CharT>
1939
    friend to_bigint_result<CharT> to_bigint(const CharT* s, size_type length, basic_bigint& val, int radix)
1940
    {
1941
        if (!(radix >= 2 && radix <= 16))
1942
        {
1943
            JSONCONS_THROW(std::runtime_error("Unsupported radix"));
1944
        }
1945
1946
        const CharT* cur = s;
1947
        const CharT* last = s + length;
1948
1949
        bool neg;
1950
        if (*cur == '-')
1951
        {
1952
            neg = true;
1953
            cur++;
1954
        }
1955
        else
1956
        {
1957
            neg = false;
1958
        }
1959
1960
        while (cur < last)
1961
        {
1962
            CharT c = *cur;
1963
            word_type d;
1964
            switch (c)
1965
            {
1966
                case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
1967
                    d = (word_type)(c - '0');
1968
                    break;
1969
                case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':
1970
                    d = (word_type)(c - ('a' - 10u));
1971
                    break;
1972
                case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
1973
                    d = (word_type)(c - ('A' - 10u));
1974
                    break;
1975
                default:
1976
                    return to_bigint_result<CharT>(cur, std::errc::invalid_argument);
1977
            }
1978
            if ((int)d >= radix)
1979
            {
1980
                return to_bigint_result<CharT>(cur, std::errc::invalid_argument);
1981
            }
1982
            val *= radix;
1983
            val += d;
1984
            ++cur;
1985
        }
1986
1987
        if ( neg )
1988
        {
1989
            val.set_negative(true);
1990
        }
1991
        return to_bigint_result<CharT>(cur, std::errc{});
1992
    }
1993
};
1994
1995
template <typename Allocator>
1996
basic_bigint<Allocator> babs( const basic_bigint<Allocator>& a )
1997
{
1998
    if ( a.is_negative())
1999
    {
2000
        return -a;
2001
    }
2002
    return a;
2003
}
2004
2005
template <typename Allocator>
2006
basic_bigint<Allocator> bpow(basic_bigint<Allocator> x, unsigned n)
2007
{
2008
    basic_bigint<Allocator> y = 1;
2009
2010
    while ( n )
2011
    {
2012
        if ( n & 1 )
2013
        {
2014
            y *= x;
2015
        }
2016
        x *= x;
2017
        n >>= 1;
2018
    }
2019
2020
    return y;
2021
}
2022
2023
template <typename Allocator>
2024
basic_bigint<Allocator> bsqrt(const basic_bigint<Allocator>& a)
2025
{
2026
    basic_bigint<Allocator> x = a;
2027
    basic_bigint<Allocator> b = a;
2028
    basic_bigint<Allocator> q;
2029
2030
    b <<= 1;
2031
    while ( (void)(b >>= 2), b > 0 )
2032
    {
2033
        x >>= 1;
2034
    }
2035
    while ( x > (q = a/x) + 1 || x < q - 1 )
2036
    {
2037
        x += q;
2038
        x >>= 1;
2039
    }
2040
    return x < q ? x : q;
2041
}
2042
2043
namespace detail {
2044
2045
template <typename CharT, typename Allocator>
2046
to_bigint_result<CharT> to_bigint(const CharT* data, std::size_t length,
2047
    bool neg, basic_bigint<Allocator>& value, const Allocator& alloc)
2048
23.5k
{
2049
23.5k
    if (JSONCONS_UNLIKELY(length == 0))
2050
1
    {
2051
1
        return to_bigint_result<CharT>(data, std::errc::invalid_argument);
2052
1
    }
2053
2054
23.5k
    using word_type = typename basic_bigint<Allocator>::word_type;
2055
2056
23.5k
    const CharT* last = data + length;
2057
23.5k
    const CharT* p = data;
2058
2059
26.7k
    while (p < last && *p == '0')
2060
3.17k
    {
2061
3.17k
        ++p;
2062
3.17k
    }
2063
23.5k
    if (p == last)
2064
980
    {
2065
980
        value = std::move(basic_bigint<Allocator>{0, alloc});
2066
980
        return to_bigint_result<CharT>(last, std::errc{});
2067
980
    }
2068
22.6k
    std::size_t num_digits = last - data;
2069
22.6k
    std::size_t num_words;
2070
22.6k
    if (length < 10)
2071
788
    {
2072
788
        num_words = 1;
2073
788
    }
2074
21.8k
    else
2075
21.8k
    {
2076
21.8k
        std::size_t num_bits = (std::size_t)(((num_digits * detail::bits_per_digit[10]) >> 10) + 1);
2077
21.8k
        num_words = (num_bits + 63) >> 6;
2078
21.8k
    }
2079
2080
22.6k
    basic_bigint<Allocator> v(0, alloc);
2081
22.6k
    v.reserve(num_words);
2082
713k
    for (std::size_t i = 0; i < length; i++)
2083
690k
    {
2084
690k
        CharT c = data[i];
2085
690k
        if (JSONCONS_LIKELY(c >= '0' && c <= '9'))
2086
690k
        {
2087
690k
            v *= 10u;
2088
690k
            v += (word_type)(c - '0');
2089
690k
        }
2090
61
        else
2091
61
        {
2092
61
            return to_bigint_result<CharT>(data + i, std::errc::invalid_argument);
2093
61
        }
2094
690k
    }
2095
2096
22.5k
    if (neg)
2097
2.93k
    {
2098
2.93k
        v.set_negative(true);
2099
2.93k
    }
2100
2101
22.5k
    value = std::move(v);
2102
22.5k
    return to_bigint_result<CharT>(last, std::errc{});
2103
22.6k
}
2104
2105
} // namespace detail
2106
2107
template <typename CharT, typename Allocator>
2108
to_bigint_result<CharT> to_bigint(const CharT* data, std::size_t length,
2109
    basic_bigint<Allocator>& value, const Allocator& alloc)
2110
2.15k
{
2111
2.15k
    if (JSONCONS_UNLIKELY(length == 0))
2112
0
    {
2113
0
        return to_bigint_result<CharT>(data, std::errc::invalid_argument);
2114
0
    }
2115
2116
2.15k
    if (*data == '-')
2117
0
    {
2118
0
        return jsoncons::detail::to_bigint(data + 1, length - 1, true, value, alloc);
2119
0
    }
2120
2.15k
    else
2121
2.15k
    {
2122
2.15k
        return jsoncons::detail::to_bigint(data, length, false, value, alloc);
2123
2.15k
    }
2124
2.15k
}
2125
2126
template <typename CharT>
2127
to_bigint_result<CharT> to_bigint(const CharT* s, basic_bigint<std::allocator<uint64_t>>& value)
2128
{
2129
    return to_bigint(s, std::char_traits<CharT>::length(s), value);
2130
}
2131
2132
template <typename CharT>
2133
to_bigint_result<CharT> to_bigint(const CharT* data, std::size_t length,
2134
    basic_bigint<std::allocator<uint64_t>>& value)
2135
21.4k
{
2136
21.4k
    if (JSONCONS_UNLIKELY(length == 0))
2137
0
    {
2138
0
        return to_bigint_result<CharT>(data, std::errc::invalid_argument);
2139
0
    }
2140
2141
21.4k
    if (*data == '-')
2142
2.93k
    {
2143
2.93k
        return jsoncons::detail::to_bigint(data+1, length-1, true, value, std::allocator<uint64_t>{}); 
2144
2.93k
    }
2145
18.5k
    else
2146
18.5k
    {
2147
18.5k
        return jsoncons::detail::to_bigint(data, length, false, value, std::allocator<uint64_t>{}); 
2148
18.5k
    }
2149
21.4k
}
2150
2151
using bigint = basic_bigint<std::allocator<uint64_t>>;
2152
2153
} // namespace jsoncons
2154
2155
#endif // JSONCONS_UTILITY_BIGINT_HPP