1// Copyright 2023 Matt Borland
2// Distributed under the Boost Software License, Version 1.0.
3// https://www.boost.org/LICENSE_1_0.txt
4
5#include <boost/config.hpp>
6
7#ifdef BOOST_HAS_INT128
8
9// We need to define these operator<< overloads before
10// including boost/core/lightweight_test.hpp, or they
11// won't be visible to BOOST_TEST_EQ
12// LCOV_EXCL_START
13
14#include <ostream>
15
16static char* mini_to_chars( char (&buffer)[ 64 ], boost::uint128_type v )
17{
18 char* p = buffer + 64;
19 *--p = '\0';
20
21 do
22 {
23 *--p = "0123456789"[ v % 10 ];
24 v /= 10;
25 }
26 while ( v != 0 );
27
28 return p;
29}
30
31std::ostream& operator<<( std::ostream& os, boost::uint128_type v )
32{
33 char buffer[ 64 ];
34
35 os << mini_to_chars( buffer, v );
36 return os;
37}
38
39std::ostream& operator<<( std::ostream& os, boost::int128_type v )
40{
41 char buffer[ 64 ];
42 char* p;
43
44 if( v >= 0 )
45 {
46 p = mini_to_chars( buffer, v: static_cast<boost::uint128_type>(v) );
47 }
48 else
49 {
50 p = mini_to_chars( buffer, v: -static_cast<boost::uint128_type>(v) );
51 *--p = '-';
52 }
53
54 os << p;
55 return os;
56}
57
58// LCOV_EXCL_STOP
59
60#endif // #ifdef BOOST_HAS_INT128
61
62#include <boost/charconv/detail/emulated128.hpp>
63#include <boost/core/lightweight_test.hpp>
64#include <limits>
65#include <iostream>
66#include <climits>
67#include <cstdint>
68
69using boost::charconv::detail::uint128;
70using boost::charconv::detail::trivial_uint128;
71
72template <typename T>
73void test_relational_operators(T val = (std::numeric_limits<T>::max)())
74{
75 uint128 test_val = UINT64_MAX;
76 test_val += 1;
77
78 BOOST_TEST(test_val > val);
79 BOOST_TEST(!(test_val < val));
80 BOOST_TEST(!(test_val == val));
81 BOOST_TEST(test_val != val);
82
83 const uint128 equal_val = val;
84
85 BOOST_TEST(!(equal_val > val));
86 BOOST_TEST(equal_val >= val);
87 BOOST_TEST(!(equal_val < val));
88 BOOST_TEST(equal_val <= val);
89 BOOST_TEST(equal_val == val);
90 BOOST_TEST(!(equal_val != val));
91
92 int negative_val = -100;
93
94 BOOST_TEST(test_val > negative_val);
95 BOOST_TEST(!(test_val < negative_val));
96 BOOST_TEST(!(test_val == negative_val));
97 BOOST_TEST(test_val != negative_val);
98}
99
100void test_arithmetic_operators()
101{
102 // Only using low word
103 const auto fixed_val = UINT64_MAX / 2;
104 uint128 test_val = fixed_val;
105 BOOST_TEST(test_val / 2 == UINT64_MAX / 4);
106 BOOST_TEST(test_val + 1 == fixed_val + 1);
107 test_val++;
108 BOOST_TEST(test_val == fixed_val + 1);
109 BOOST_TEST(test_val % fixed_val == 1);
110 test_val--;
111 BOOST_TEST(test_val == fixed_val);
112 BOOST_TEST(test_val % fixed_val == 0);
113 BOOST_TEST(test_val / fixed_val == 1);
114
115
116 test_val = 2;
117 std::uint64_t comp_val = 1;
118 while (test_val < UINT64_MAX)
119 {
120 comp_val *= 2;
121 if(!BOOST_TEST(test_val == comp_val))
122 {
123 // LCOV_EXCL_START
124 std::cerr << "Target: " << comp_val
125 << "\ntest_val: " << test_val.low << std::endl;
126 // LCOV_EXCL_STOP
127 }
128 test_val *= 2;
129 }
130
131 // And back down
132 while (test_val >= 2)
133 {
134 test_val /= 2;
135 if(!BOOST_TEST(test_val == comp_val))
136 {
137 // LCOV_EXCL_START
138 std::cerr << "Target: " << comp_val
139 << "\ntest_val: " << test_val.low << std::endl;
140 // LCOV_EXCL_STOP
141 }
142 comp_val /= 2;
143 }
144
145
146 // Add the high word
147 uint128 test_high_word = UINT64_MAX;
148 ++test_high_word;
149 BOOST_TEST(test_high_word.high == 1 && test_high_word.low == 0);
150 --test_high_word;
151
152 #ifdef BOOST_CHARCONV_HAS_INT128
153 boost::uint128_type reference = UINT64_MAX;
154 BOOST_TEST(test_high_word == reference);
155
156 for (int i = 0; i < 63; ++i)
157 {
158 if(!BOOST_TEST(test_high_word == reference))
159 {
160 // LCOV_EXCL_START
161 std::cerr << "i: " << i
162 << "\nTarget: " << reference
163 << "\ntest_val: " << test_high_word.high << " " << test_high_word.low << std::endl;
164 // // LCOV_EXCL_STOP
165 }
166 test_high_word *= 2;
167 reference *= 2;
168 }
169
170 while (test_high_word >= 2)
171 {
172 BOOST_TEST(test_high_word == reference);
173 test_high_word /= 2;
174 reference /= 2;
175 }
176
177 #endif
178}
179
180void test_bitwise_operators()
181{
182 #ifdef BOOST_CHARCONV_HAS_INT128
183 boost::uint128_type ref = UINT64_MAX;
184 uint128 test_val = UINT64_MAX;
185
186 ref <<= 1;
187 test_val <<= 1;
188 BOOST_TEST(test_val == ref);
189
190 ref >>= 2;
191 test_val >>= 2;
192 BOOST_TEST(test_val == ref);
193
194 BOOST_TEST((test_val | 1) == (ref | 1));
195 BOOST_TEST((test_val & 1) == (ref & 1));
196 BOOST_TEST(~test_val == ~ref);
197 #endif
198}
199
200void test_memcpy()
201{
202 #if defined(BOOST_CHARCONV_HAS_FLOAT128) && defined(BOOST_CHARCONV_HAS_INT128)
203 __float128 fval = 1e4000Q;
204 boost::uint128_type ref;
205 trivial_uint128 cpyval;
206
207 std::memcpy(&cpyval, &fval, sizeof(fval));
208 std::memcpy(&ref, &fval, sizeof(fval));
209
210 uint128 test_val = cpyval;
211
212 BOOST_TEST(test_val == ref);
213 #endif
214}
215
216void test_limits()
217{
218 BOOST_TEST(std::numeric_limits<uint128>::min() == 0);
219 BOOST_TEST(std::numeric_limits<uint128>::max() == uint128(UINT64_MAX, UINT64_MAX));
220 BOOST_TEST(std::numeric_limits<uint128>::is_signed == false);
221 BOOST_TEST(std::numeric_limits<uint128>::is_integer == true);
222 BOOST_TEST(std::numeric_limits<uint128>::digits == CHAR_BIT * sizeof(std::uint64_t) * 2);
223
224 // Max value is 340,282,366,920,938,463,463,374,607,431,768,211,455 (39 digits) so 38 without change
225 BOOST_TEST(std::numeric_limits<uint128>::digits10 == 38);
226}
227
228int main()
229{
230 test_relational_operators<char>();
231 test_relational_operators<signed char>();
232 test_relational_operators<short>();
233 test_relational_operators<int>();
234 test_relational_operators<long>();
235 test_relational_operators<long long>();
236 test_relational_operators<unsigned char>();
237 test_relational_operators<unsigned short>();
238 test_relational_operators<unsigned>();
239 test_relational_operators<unsigned long>();
240 test_relational_operators<unsigned long long>();
241
242 test_arithmetic_operators();
243
244 test_bitwise_operators();
245
246 test_memcpy();
247
248 test_limits();
249
250 return boost::report_errors();
251}
252

source code of boost/libs/charconv/test/test_128bit_emulation.cpp