morton-arithmetic 0.1.0
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
22namespace morton {
23namespace detail {
24
28template <std::size_t W>
29struct wide_uint {
30 static_assert(W >= 2, "use a built-in integer for <= 64 bits");
31 std::array<std::uint64_t, W> w{};
32
33 MORTON_HD constexpr wide_uint() = default;
34
35 // From any built-in integral value up to 64 bits (low word).
36 template <typename T, typename = std::enable_if_t<std::is_integral_v<T> && (sizeof(T) <= 8)>>
37 MORTON_HD constexpr wide_uint(T v) : w{} {
38 w[0] = std::uint64_t(static_cast<std::make_unsigned_t<T>>(v));
39 }
40
41#if defined(__SIZEOF_INT128__)
42 // From a 128-bit built-in (fills the low two words).
43 MORTON_HD constexpr wide_uint(unsigned __int128 v) : w{} {
44 w[0] = std::uint64_t(v);
45 if constexpr (W >= 2)
46 w[1] = std::uint64_t(v >> 64);
47 }
48#endif
49
50 // From a wide_uint of a different width (truncate or zero-extend).
51 template <std::size_t W2, typename = std::enable_if_t<W2 != W>>
52 MORTON_HD constexpr explicit wide_uint(const wide_uint<W2>& o) : w{} {
53 for (std::size_t i = 0; i < W && i < W2; ++i)
54 w[i] = o.w[i];
55 }
56
57 MORTON_HD explicit constexpr operator std::uint64_t() const { return w[0]; }
58#if defined(__SIZEOF_INT128__)
59 MORTON_HD explicit constexpr operator unsigned __int128() const {
60 unsigned __int128 r = w[0];
61 if constexpr (W >= 2)
62 r |= (unsigned __int128)(w[1]) << 64;
63 return r;
64 }
65#endif
66 MORTON_HD explicit constexpr operator bool() const {
67 for (std::size_t i = 0; i < W; ++i)
68 if (w[i])
69 return true;
70 return false;
71 }
72
73 // ---- bitwise ----------------------------------------------------------
74 MORTON_HD constexpr wide_uint operator~() const {
75 wide_uint r;
76 for (std::size_t i = 0; i < W; ++i)
77 r.w[i] = ~w[i];
78 return r;
79 }
80 MORTON_HD constexpr wide_uint& operator&=(const wide_uint& o) {
81 for (std::size_t i = 0; i < W; ++i)
82 w[i] &= o.w[i];
83 return *this;
84 }
85 MORTON_HD constexpr wide_uint& operator|=(const wide_uint& o) {
86 for (std::size_t i = 0; i < W; ++i)
87 w[i] |= o.w[i];
88 return *this;
89 }
90 MORTON_HD constexpr wide_uint& operator^=(const wide_uint& o) {
91 for (std::size_t i = 0; i < W; ++i)
92 w[i] ^= o.w[i];
93 return *this;
94 }
95 friend MORTON_HD constexpr wide_uint operator&(wide_uint a, const wide_uint& b) { return a &= b; }
96 friend MORTON_HD constexpr wide_uint operator|(wide_uint a, const wide_uint& b) { return a |= b; }
97 friend MORTON_HD constexpr wide_uint operator^(wide_uint a, const wide_uint& b) { return a ^= b; }
98
99 // ---- shifts -----------------------------------------------------------
100 MORTON_HD constexpr wide_uint operator<<(unsigned s) const {
101 wide_uint r;
102 const unsigned ws = s / 64, bs = s % 64;
103 for (int i = int(W) - 1; i >= 0; --i) {
104 const int src = i - int(ws);
105 std::uint64_t v = 0;
106 if (src >= 0) {
107 v = w[std::size_t(src)] << bs;
108 if (bs && src - 1 >= 0)
109 v |= w[std::size_t(src - 1)] >> (64 - bs);
110 }
111 r.w[std::size_t(i)] = v;
112 }
113 return r;
114 }
115 MORTON_HD constexpr wide_uint operator>>(unsigned s) const {
116 wide_uint r;
117 const unsigned ws = s / 64, bs = s % 64;
118 for (std::size_t i = 0; i < W; ++i) {
119 const std::size_t src = i + ws;
120 std::uint64_t v = 0;
121 if (src < W) {
122 v = w[src] >> bs;
123 if (bs && src + 1 < W)
124 v |= w[src + 1] << (64 - bs);
125 }
126 r.w[i] = v;
127 }
128 return r;
129 }
130 MORTON_HD constexpr wide_uint& operator<<=(unsigned s) { return *this = (*this << s); }
131 MORTON_HD constexpr wide_uint& operator>>=(unsigned s) { return *this = (*this >> s); }
132
133 // ---- add / sub (ripple) -----------------------------------------------
134 friend MORTON_HD constexpr wide_uint operator+(const wide_uint& a, const wide_uint& b) {
135 wide_uint r;
136 std::uint64_t carry = 0;
137 for (std::size_t i = 0; i < W; ++i) {
138 std::uint64_t s1 = a.w[i] + b.w[i];
139 std::uint64_t c1 = (s1 < a.w[i]) ? 1u : 0u;
140 std::uint64_t s2 = s1 + carry;
141 std::uint64_t c2 = (s2 < s1) ? 1u : 0u;
142 r.w[i] = s2;
143 carry = c1 | c2;
144 }
145 return r;
146 }
147 friend MORTON_HD constexpr wide_uint operator-(const wide_uint& a, const wide_uint& b) {
148 wide_uint r;
149 std::uint64_t borrow = 0;
150 for (std::size_t i = 0; i < W; ++i) {
151 std::uint64_t d1 = a.w[i] - b.w[i];
152 std::uint64_t b1 = (a.w[i] < b.w[i]) ? 1u : 0u;
153 std::uint64_t d2 = d1 - borrow;
154 std::uint64_t b2 = (d1 < borrow) ? 1u : 0u;
155 r.w[i] = d2;
156 borrow = b1 | b2;
157 }
158 return r;
159 }
160 MORTON_HD constexpr wide_uint& operator++() { return *this = (*this + wide_uint(1)); }
161 MORTON_HD constexpr wide_uint& operator--() { return *this = (*this - wide_uint(1)); }
162
163 // ---- comparison -------------------------------------------------------
164 friend MORTON_HD constexpr bool operator==(const wide_uint& a, const wide_uint& b) {
165 for (std::size_t i = 0; i < W; ++i)
166 if (a.w[i] != b.w[i])
167 return false;
168 return true;
169 }
170 friend MORTON_HD constexpr bool operator!=(const wide_uint& a, const wide_uint& b) {
171 return !(a == b);
172 }
173 friend MORTON_HD constexpr bool operator<(const wide_uint& a, const wide_uint& b) {
174 for (std::size_t i = W; i-- > 0;) {
175 if (a.w[i] != b.w[i])
176 return a.w[i] < b.w[i];
177 }
178 return false;
179 }
180 friend MORTON_HD constexpr bool operator>(const wide_uint& a, const wide_uint& b) {
181 return b < a;
182 }
183 friend MORTON_HD constexpr bool operator<=(const wide_uint& a, const wide_uint& b) {
184 return !(b < a);
185 }
186 friend MORTON_HD constexpr bool operator>=(const wide_uint& a, const wide_uint& b) {
187 return !(a < b);
188 }
189};
190
191} // namespace detail
192} // namespace morton
193
194#endif // MORTON_WIDE_UINT_HPP
The MORTON_HD host/device function marker, shared by every core header.
#define MORTON_HD
Definition hd.hpp:27
Definition batch.hpp:26
Fixed-width unsigned integer of.
Definition wide_uint.hpp:29
friend MORTON_HD constexpr bool operator>=(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:186
friend MORTON_HD constexpr wide_uint operator+(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:134
MORTON_HD constexpr wide_uint & operator<<=(unsigned s)
Definition wide_uint.hpp:130
MORTON_HD constexpr wide_uint & operator&=(const wide_uint &o)
Definition wide_uint.hpp:80
friend MORTON_HD constexpr bool operator<(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:173
std::array< std::uint64_t, W > w
Words, little-endian: w[0] is least significant.
Definition wide_uint.hpp:31
friend MORTON_HD constexpr wide_uint operator-(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:147
friend MORTON_HD constexpr wide_uint operator|(wide_uint a, const wide_uint &b)
Definition wide_uint.hpp:96
MORTON_HD constexpr wide_uint & operator++()
Definition wide_uint.hpp:160
friend MORTON_HD constexpr bool operator!=(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:170
friend MORTON_HD constexpr bool operator>(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:180
friend MORTON_HD constexpr bool operator<=(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:183
MORTON_HD constexpr wide_uint(const wide_uint< W2 > &o)
Definition wide_uint.hpp:52
friend MORTON_HD constexpr bool operator==(const wide_uint &a, const wide_uint &b)
Definition wide_uint.hpp:164
MORTON_HD constexpr wide_uint & operator|=(const wide_uint &o)
Definition wide_uint.hpp:85
MORTON_HD constexpr wide_uint operator<<(unsigned s) const
Definition wide_uint.hpp:100
MORTON_HD constexpr wide_uint operator~() const
Definition wide_uint.hpp:74
MORTON_HD constexpr wide_uint & operator>>=(unsigned s)
Definition wide_uint.hpp:131
MORTON_HD constexpr wide_uint & operator^=(const wide_uint &o)
Definition wide_uint.hpp:90
friend MORTON_HD constexpr wide_uint operator&(wide_uint a, const wide_uint &b)
Definition wide_uint.hpp:95
MORTON_HD constexpr wide_uint operator>>(unsigned s) const
Definition wide_uint.hpp:115
MORTON_HD constexpr wide_uint()=default
MORTON_HD constexpr wide_uint & operator--()
Definition wide_uint.hpp:161
friend MORTON_HD constexpr wide_uint operator^(wide_uint a, const wide_uint &b)
Definition wide_uint.hpp:97