peclet-morton 1.0.2
Fast Morton (Z-order) codes with O(1) arithmetic
Loading...
Searching...
No Matches
wide_uint.hpp
Go to the documentation of this file.
1
11
12#ifndef MORTON_WIDE_UINT_HPP
13#define MORTON_WIDE_UINT_HPP
14
15#include <array>
16#include <cstddef>
17#include <cstdint>
18#include <type_traits>
19
20#include "morton/hd.hpp"
21
22// MORTON_HAS_INT128: set when the compiler provides the `__int128` built-ins (GCC/Clang/nvcc).
23// Defined here rather than in morton.hpp because wide_uint.hpp is the lowest header that needs it.
24#if defined(__SIZEOF_INT128__)
25#define MORTON_HAS_INT128 1
26#endif
27
28namespace morton {
29namespace detail {
30
31#if defined(MORTON_HAS_INT128)
39__extension__ using uint128_t = unsigned __int128;
40#endif
41
45template <std::size_t W>
46struct wide_uint {
47 static_assert(W >= 2, "use a built-in integer for <= 64 bits");
48 std::array<std::uint64_t, W> w{};
49
50 MORTON_HD constexpr wide_uint() = default;
51
52 // From any built-in integral value up to 64 bits (low word).
53 template <typename T, typename = std::enable_if_t<std::is_integral_v<T> && (sizeof(T) <= 8)>>
54 MORTON_HD constexpr wide_uint(T v) : w{} {
55 w[0] = std::uint64_t(static_cast<std::make_unsigned_t<T>>(v));
56 }
57
58#if defined(MORTON_HAS_INT128)
59 // From a 128-bit built-in (fills the low two words).
60 MORTON_HD constexpr wide_uint(uint128_t v) : w{} {
61 w[0] = std::uint64_t(v);
62 if constexpr (W >= 2)
63 w[1] = std::uint64_t(v >> 64);
64 }
65#endif
66
67 // From a wide_uint of a different width (truncate or zero-extend).
68 template <std::size_t W2, typename = std::enable_if_t<W2 != W>>
69 MORTON_HD constexpr explicit wide_uint(const wide_uint<W2>& o) : w{} {
70 for (std::size_t i = 0; i < W && i < W2; ++i)
71 w[i] = o.w[i];
72 }
73
74 MORTON_HD explicit constexpr operator std::uint64_t() const { return w[0]; }
75#if defined(MORTON_HAS_INT128)
76 MORTON_HD explicit constexpr operator uint128_t() const {
77 uint128_t r = w[0];
78 if constexpr (W >= 2)
79 r |= uint128_t(w[1]) << 64;
80 return r;
81 }
82#endif
83 MORTON_HD explicit constexpr operator bool() const {
84 for (std::size_t i = 0; i < W; ++i)
85 if (w[i])
86 return true;
87 return false;
88 }
89
90 // ---- bitwise ----------------------------------------------------------
91 MORTON_HD constexpr wide_uint operator~() const {
92 wide_uint r;
93 for (std::size_t i = 0; i < W; ++i)
94 r.w[i] = ~w[i];
95 return r;
96 }
97 MORTON_HD constexpr wide_uint& operator&=(const wide_uint& o) {
98 for (std::size_t i = 0; i < W; ++i)
99 w[i] &= o.w[i];
100 return *this;
101 }
103 for (std::size_t i = 0; i < W; ++i)
104 w[i] |= o.w[i];
105 return *this;
106 }
108 for (std::size_t i = 0; i < W; ++i)
109 w[i] ^= o.w[i];
110 return *this;
111 }
112 friend MORTON_HD constexpr wide_uint operator&(wide_uint a, const wide_uint& b) { return a &= b; }
113 friend MORTON_HD constexpr wide_uint operator|(wide_uint a, const wide_uint& b) { return a |= b; }
114 friend MORTON_HD constexpr wide_uint operator^(wide_uint a, const wide_uint& b) { return a ^= b; }
115
116 // ---- shifts -----------------------------------------------------------
117 MORTON_HD constexpr wide_uint operator<<(unsigned s) const {
118 wide_uint r;
119 const unsigned ws = s / 64, bs = s % 64;
120 for (int i = int(W) - 1; i >= 0; --i) {
121 const int src = i - int(ws);
122 std::uint64_t v = 0;
123 if (src >= 0) {
124 v = w[std::size_t(src)] << bs;
125 if (bs && src - 1 >= 0)
126 v |= w[std::size_t(src - 1)] >> (64 - bs);
127 }
128 r.w[std::size_t(i)] = v;
129 }
130 return r;
131 }
132 MORTON_HD constexpr wide_uint operator>>(unsigned s) const {
133 wide_uint r;
134 const unsigned ws = s / 64, bs = s % 64;
135 for (std::size_t i = 0; i < W; ++i) {
136 const std::size_t src = i + ws;
137 std::uint64_t v = 0;
138 if (src < W) {
139 v = w[src] >> bs;
140 if (bs && src + 1 < W)
141 v |= w[src + 1] << (64 - bs);
142 }
143 r.w[i] = v;
144 }
145 return r;
146 }
147 MORTON_HD constexpr wide_uint& operator<<=(unsigned s) { return *this = (*this << s); }
148 MORTON_HD constexpr wide_uint& operator>>=(unsigned s) { return *this = (*this >> s); }
149
150 // ---- add / sub (ripple) -----------------------------------------------
151 friend MORTON_HD constexpr wide_uint operator+(const wide_uint& a, const wide_uint& b) {
152 wide_uint r;
153 std::uint64_t carry = 0;
154 for (std::size_t i = 0; i < W; ++i) {
155 std::uint64_t s1 = a.w[i] + b.w[i];
156 std::uint64_t c1 = (s1 < a.w[i]) ? 1u : 0u;
157 std::uint64_t s2 = s1 + carry;
158 std::uint64_t c2 = (s2 < s1) ? 1u : 0u;
159 r.w[i] = s2;
160 carry = c1 | c2;
161 }
162 return r;
163 }
164 friend MORTON_HD constexpr wide_uint operator-(const wide_uint& a, const wide_uint& b) {
165 wide_uint r;
166 std::uint64_t borrow = 0;
167 for (std::size_t i = 0; i < W; ++i) {
168 std::uint64_t d1 = a.w[i] - b.w[i];
169 std::uint64_t b1 = (a.w[i] < b.w[i]) ? 1u : 0u;
170 std::uint64_t d2 = d1 - borrow;
171 std::uint64_t b2 = (d1 < borrow) ? 1u : 0u;
172 r.w[i] = d2;
173 borrow = b1 | b2;
174 }
175 return r;
176 }
177 MORTON_HD constexpr wide_uint& operator++() { return *this = (*this + wide_uint(1)); }
178 MORTON_HD constexpr wide_uint& operator--() { return *this = (*this - wide_uint(1)); }
179
180 // ---- comparison -------------------------------------------------------
181 friend MORTON_HD constexpr bool operator==(const wide_uint& a, const wide_uint& b) {
182 for (std::size_t i = 0; i < W; ++i)
183 if (a.w[i] != b.w[i])
184 return false;
185 return true;
186 }
187 friend MORTON_HD constexpr bool operator!=(const wide_uint& a, const wide_uint& b) {
188 return !(a == b);
189 }
190 friend MORTON_HD constexpr bool operator<(const wide_uint& a, const wide_uint& b) {
191 for (std::size_t i = W; i-- > 0;) {
192 if (a.w[i] != b.w[i])
193 return a.w[i] < b.w[i];
194 }
195 return false;
196 }
197 friend MORTON_HD constexpr bool operator>(const wide_uint& a, const wide_uint& b) {
198 return b < a;
199 }
200 friend MORTON_HD constexpr bool operator<=(const wide_uint& a, const wide_uint& b) {
201 return !(b < a);
202 }
203 friend MORTON_HD constexpr bool operator>=(const wide_uint& a, const wide_uint& b) {
204 return !(a < b);
205 }
206};
207
208} // namespace detail
209} // namespace morton
210
211#endif // MORTON_WIDE_UINT_HPP
The MORTON_HD host/device function marker, shared by every core header.
#define MORTON_HD
Definition hd.hpp:27
unsigned __int128 uint128_t
The built-in 128-bit unsigned, used for 65..128-bit codes.
Definition wide_uint.hpp:39
Definition batch.hpp:26
Fixed-width unsigned integer of.
Definition wide_uint.hpp:46
friend MORTON_HD constexpr bool operator>=(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:203
friend MORTON_HD constexpr wide_uint operator+(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:151
MORTON_HD constexpr wide_uint & operator<<=(unsigned s)
Definition wide_uint.hpp:147
MORTON_HD constexpr wide_uint & operator&=(const wide_uint &o)
Definition wide_uint.hpp:97
friend MORTON_HD constexpr bool operator<(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:190
std::array< std::uint64_t, W > w
Words, little-endian: w[0] is least significant.
Definition wide_uint.hpp:48
friend MORTON_HD constexpr wide_uint operator-(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:164
friend MORTON_HD constexpr wide_uint operator|(wide_uint a, const wide_uint &b)
Definition wide_uint.hpp:113
MORTON_HD constexpr wide_uint & operator++()
Definition wide_uint.hpp:177
friend MORTON_HD constexpr bool operator!=(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:187
friend MORTON_HD constexpr bool operator>(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:197
friend MORTON_HD constexpr bool operator<=(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:200
MORTON_HD constexpr wide_uint(const wide_uint< W2 > &o)
Definition wide_uint.hpp:69
friend MORTON_HD constexpr bool operator==(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:181
MORTON_HD constexpr wide_uint & operator|=(const wide_uint &o)
Definition wide_uint.hpp:102
MORTON_HD constexpr wide_uint operator<<(unsigned s) const
Definition wide_uint.hpp:117
MORTON_HD constexpr wide_uint operator~() const
Definition wide_uint.hpp:91
MORTON_HD constexpr wide_uint & operator>>=(unsigned s)
Definition wide_uint.hpp:148
MORTON_HD constexpr wide_uint & operator^=(const wide_uint &o)
Definition wide_uint.hpp:107
friend MORTON_HD constexpr wide_uint operator&(wide_uint a, const wide_uint &b)
Definition wide_uint.hpp:112
MORTON_HD constexpr wide_uint operator>>(unsigned s) const
Definition wide_uint.hpp:132
MORTON_HD constexpr wide_uint()=default
MORTON_HD constexpr wide_uint & operator--()
Definition wide_uint.hpp:178
friend MORTON_HD constexpr wide_uint operator^(wide_uint a, const wide_uint &b)
Definition wide_uint.hpp:114