forked from scylladb/scylladb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmultiprecision_int.hh
220 lines (211 loc) · 6.89 KB
/
multiprecision_int.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/*
* Copyright (C) 2020-present ScyllaDB
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
*/
#pragma once
#include <boost/multiprecision/cpp_int.hpp>
#include <compare>
#include <iosfwd>
namespace utils {
// multiprecision_int is a thin wrapper around boost::multiprecision::cpp_int.
// cpp_int is worth about 20,000 lines of header files that are rarely used.
// Forward-declaring cpp_int is very difficult as it is a complicated template,
// hence this wrapper.
//
// Because cpp_int uses a lot of expression templates, the code below contains
// many casts since the expression templates defeat regular C++ conversion rules.
class multiprecision_int final {
public:
using cpp_int = boost::multiprecision::cpp_int;
private:
cpp_int _v;
private:
// maybe_unwrap() selectively unwraps multiprecision_int values (leaving
// anything else unchanged), so avoid confusing boost::multiprecision.
static const cpp_int& maybe_unwrap(const multiprecision_int& x) {
return x._v;
}
template <typename T>
static const T& maybe_unwrap(const T& x) {
return x;
}
public:
multiprecision_int() = default;
multiprecision_int(cpp_int x) : _v(std::move(x)) {}
explicit multiprecision_int(int x) : _v(x) {}
explicit multiprecision_int(unsigned x) : _v(x) {}
explicit multiprecision_int(long x) : _v(x) {}
explicit multiprecision_int(unsigned long x) : _v(x) {}
explicit multiprecision_int(long long x) : _v(x) {}
explicit multiprecision_int(unsigned long long x) : _v(x) {}
explicit multiprecision_int(float x) : _v(x) {}
explicit multiprecision_int(double x) : _v(x) {}
explicit multiprecision_int(long double x) : _v(x) {}
explicit multiprecision_int(const std::string x) : _v(x) {}
explicit multiprecision_int(const char* x) : _v(x) {}
operator const cpp_int&() const {
return _v;
}
explicit operator signed char() const {
return static_cast<signed char>(_v);
}
explicit operator unsigned char() const {
return static_cast<unsigned char>(_v);
}
explicit operator short() const {
return static_cast<short>(_v);
}
explicit operator unsigned short() const {
return static_cast<unsigned short>(_v);
}
explicit operator int() const {
return static_cast<int>(_v);
}
explicit operator unsigned() const {
return static_cast<unsigned>(_v);
}
explicit operator long() const {
return static_cast<long>(_v);
}
explicit operator unsigned long() const {
return static_cast<unsigned long>(_v);
}
explicit operator long long() const {
return static_cast<long long>(_v);
}
explicit operator unsigned long long() const {
return static_cast<unsigned long long>(_v);
}
explicit operator float() const {
return static_cast<float>(_v);
}
explicit operator double() const {
return static_cast<double>(_v);
}
explicit operator long double() const {
return static_cast<long double>(_v);
}
template <typename T>
multiprecision_int& operator+=(const T& x) {
_v += maybe_unwrap(x);
return *this;
}
template <typename T>
multiprecision_int& operator-=(const T& x) {
_v -= maybe_unwrap(x);
return *this;
}
template <typename T>
multiprecision_int& operator*=(const T& x) {
_v *= maybe_unwrap(x);
return *this;
}
template <typename T>
multiprecision_int& operator/=(const T& x) {
_v /= maybe_unwrap(x);
return *this;
}
template <typename T>
multiprecision_int& operator%=(const T& x) {
_v %= maybe_unwrap(x);
return *this;
}
template <typename T>
multiprecision_int& operator<<=(const T& x) {
_v <<= maybe_unwrap(x);
return *this;
}
template <typename T>
multiprecision_int& operator>>=(const T& x) {
_v >>= maybe_unwrap(x);
return *this;
}
multiprecision_int operator-() const {
return cpp_int(-_v);
}
multiprecision_int operator+(const multiprecision_int& x) const {
return cpp_int(_v + x._v);
}
template <typename T>
multiprecision_int operator+(const T& x) const {
return cpp_int(_v + maybe_unwrap(x));
}
template <typename T>
multiprecision_int operator-(const T& x) const {
return cpp_int(_v - maybe_unwrap(x));
}
template <typename T>
multiprecision_int operator*(const T& x) const {
return cpp_int(_v * maybe_unwrap(x));
}
template <typename T>
multiprecision_int operator/(const T& x) const {
return cpp_int(_v / maybe_unwrap(x));
}
template <typename T>
multiprecision_int operator%(const T& x) const {
return cpp_int(_v % maybe_unwrap(x));
}
template <typename T>
multiprecision_int operator<<(const T& x) const {
return cpp_int(_v << maybe_unwrap(x));
}
template <typename T>
multiprecision_int operator>>(const T& x) const {
return cpp_int(_v >> maybe_unwrap(x));
}
std::strong_ordering operator<=>(const multiprecision_int& x) const = default;
template <typename T>
bool operator==(const T& x) const {
return _v == maybe_unwrap(x);
}
template <typename T>
bool operator>(const T& x) const {
return _v > maybe_unwrap(x);
}
template <typename T>
bool operator>=(const T& x) const {
return _v >= maybe_unwrap(x);
}
template <typename T>
bool operator<(const T& x) const {
return _v < maybe_unwrap(x);
}
template <typename T>
bool operator<=(const T& x) const {
return _v <= maybe_unwrap(x);
}
template <typename T>
friend multiprecision_int operator+(const T& x, const multiprecision_int& y) {
return cpp_int(maybe_unwrap(x) + y._v);
}
template <typename T>
friend multiprecision_int operator-(const T& x, const multiprecision_int& y) {
return cpp_int(maybe_unwrap(x) - y._v);
}
template <typename T>
friend multiprecision_int operator*(const T& x, const multiprecision_int& y) {
return cpp_int(maybe_unwrap(x) * y._v);
}
template <typename T>
friend multiprecision_int operator/(const T& x, const multiprecision_int& y) {
return cpp_int(maybe_unwrap(x) / y._v);
}
template <typename T>
friend multiprecision_int operator%(const T& x, const multiprecision_int& y) {
return cpp_int(maybe_unwrap(x) % y._v);
}
template <typename T>
friend multiprecision_int operator<<(const T& x, const multiprecision_int& y) {
return cpp_int(maybe_unwrap(x) << y._v);
}
template <typename T>
friend multiprecision_int operator>>(const T& x, const multiprecision_int& y) {
return cpp_int(maybe_unwrap(x) >> y._v);
}
std::string str() const;
friend std::ostream& operator<<(std::ostream& os, const multiprecision_int& x);
};
}