/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 |