68 using code_type = std::uint32_t;
69 using key_type =
typename TreeKey<Dim>::key_type;
70 using depth_type = std::uint32_t;
71 using size_type = std::size_t;
75 static constexpr code_type
const OFFSET_MASK = ~((~code_type(0)) << Dim);
77 static constexpr std::array<bool, 3>
const ACTIVE{
78 true, std::numeric_limits<key_type>::digits > DEPTHS_PER_IDX,
79 std::numeric_limits<key_type>::digits > 2 * DEPTHS_PER_IDX};
88 constexpr TreeCode()
noexcept =
default;
91 constexpr TreeCode(std::array<code_type, 3>
const& code, depth_type
const& depth)
92 : code_(code), depth_(depth)
97 constexpr explicit TreeCode(std::array<code_type, 3>
const& code) :
TreeCode(code, 0) {}
101 auto k = key << key.depth();
104 if constexpr (ACTIVE[1]) {
107 if constexpr (ACTIVE[2]) {
112 [[nodiscard]]
static constexpr TreeCode invalid()
noexcept
133 [[nodiscard]]
constexpr explicit operator TreeKey<Dim>()
const noexcept
137 if constexpr (ACTIVE[1]) {
139 for (std::size_t j{}; Dim > j; ++j) {
143 if constexpr (ACTIVE[2]) {
145 for (std::size_t j{}; Dim > j; ++j) {
159 [[nodiscard]]
constexpr key_type operator[](size_type pos)
const noexcept
161 assert(size() > pos);
165 if constexpr (ACTIVE[1]) {
168 if constexpr (ACTIVE[2]) {
181 [[nodiscard]]
static constexpr size_type size()
noexcept {
return Dim; }
189 [[nodiscard]]
constexpr bool valid()
const noexcept
191 bool a = maxDepth() >= depth();
202 constexpr void invalidate()
noexcept { depth_ = maxDepth() + 1; }
204 [[nodiscard]]
static constexpr std::size_t branchingFactor()
noexcept
206 return ipow(std::size_t(2),
static_cast<int>(Dim));
211 [[nodiscard]]
static constexpr depth_type maxDepth()
noexcept
213 depth_type max_depth = DEPTHS_PER_IDX;
214 if constexpr (ACTIVE[1]) {
215 max_depth += DEPTHS_PER_IDX;
217 if constexpr (ACTIVE[2]) {
218 max_depth += DEPTHS_PER_IDX;
223 [[nodiscard]]
constexpr depth_type depth()
const noexcept {
return depth_; }
225 [[nodiscard]]
static constexpr bool sameAncestorAtDepth(
TreeCode const& lhs,
227 depth_type depth)
noexcept
229 assert(maxDepth() >= depth);
230 assert(lhs.valid() && rhs.valid());
232 auto i = depth / DEPTHS_PER_IDX;
233 auto d = depth % DEPTHS_PER_IDX;
235 std::array<code_type, 3> m{0 >= i ? ~code_type(0) : code_type(0),
236 1 >= i ? ~code_type(0) : code_type(0),
237 2 >= i ? ~code_type(0) : code_type(0)};
241 return (lhs.code_[0] & m[0]) == (rhs.code_[0] & m[0]) &&
242 (lhs.code_[1] & m[1]) == (rhs.code_[1] & m[1]) &&
243 (lhs.code_[2] & m[2]) == (rhs.code_[2] & m[2]);
246 [[nodiscard]]
constexpr bool isAncestorOf(
TreeCode const& other)
const noexcept
248 return depth() >= other.depth() && sameAncestorAtDepth(*
this, other, depth());
251 [[nodiscard]]
constexpr bool isDescendantOf(
TreeCode const& other)
const noexcept
253 return other.isAncestorOf(*
this);
256 [[nodiscard]]
constexpr bool isSiblingOf(
TreeCode const& other)
const noexcept
258 return depth() == other.depth() && sameAncestorAtDepth(*
this, other, depth() + 1);
261 [[nodiscard]]
static constexpr depth_type lowestCommonAncestor(
264 assert(lhs.valid() && rhs.valid());
267 lhs.code_[2] != rhs.code_[2]
269 :
static_cast<depth_type
>(lhs.code_[1] != rhs.code_[1]) * DEPTHS_PER_IDX;
270 depth = std::max(depth, std::max(lhs.depth(), rhs.depth()));
272 auto i = depth / DEPTHS_PER_IDX;
273 auto d = depth % DEPTHS_PER_IDX;
274 code_type c = (lhs.code_[i] ^ rhs.code_[i]) >> (Dim * d);
275 for (; c; c >>= Dim, ++depth) {
281 [[nodiscard]]
constexpr TreeCode toDepth(depth_type depth)
const
283 assert(maxDepth() >= depth);
290 constexpr void setDepth(depth_type depth)
292 assert(maxDepth() >= depth);
294 auto i = depth / DEPTHS_PER_IDX;
295 auto d = depth % DEPTHS_PER_IDX;
297 std::array<code_type, 3> m{0 >= i ? ~code_type(0) : code_type(0),
298 1 >= i ? ~code_type(0) : code_type(0),
299 2 >= i ? ~code_type(0) : code_type(0)};
314 [[nodiscard]]
constexpr code_type
offset()
const {
return offset(depth_); }
322 [[nodiscard]]
constexpr code_type
offset(depth_type depth)
const
324 assert(maxDepth() >= depth && depth_ <= depth);
326 auto i = depth / DEPTHS_PER_IDX;
327 auto d = depth % DEPTHS_PER_IDX;
328 return (code_[i] >> (Dim * d)) & OFFSET_MASK;
331 constexpr void setOffset(code_type
offset) { setOffset(depth_,
offset); }
333 constexpr void setOffset(depth_type depth, code_type
offset)
335 assert(maxDepth() >= depth && depth_ <= depth && branchingFactor() >
offset);
337 auto i = depth / DEPTHS_PER_IDX;
338 auto d = depth % DEPTHS_PER_IDX;
341 code_[i] &= ((~code_type(0)) << Dim) << (Dim * d);
342 code_[i] |=
static_cast<code_type
>(
offset) << (Dim * d);
345 [[nodiscard]]
constexpr TreeCode parent()
const {
return toDepth(depth_ + 1); }
356 assert(branchingFactor() > idx);
381 ret.setOffset(depth_, idx);
385 [[nodiscard]]
constexpr TreeCode nextSibling()
const
387 assert(branchingFactor() >
offset() + 1);
389 auto i = depth_ / DEPTHS_PER_IDX;
390 auto d = depth_ % DEPTHS_PER_IDX;
393 ret.code_[i] += code_type(1) << (Dim * d);
397 [[nodiscard]]
constexpr TreeCode prevSibling()
const
401 auto i = depth_ / DEPTHS_PER_IDX;
402 auto d = depth_ % DEPTHS_PER_IDX;
404 TreeCode ret = *
this;
405 ret.code_[i] -= code_type(1) << (Dim * d);
420 assert(0 ==
offset(depth_));
421 assert(branchingFactor() > idx);
423 auto i = depth_ / DEPTHS_PER_IDX;
424 auto d = depth_ % DEPTHS_PER_IDX;
427 ret.code_[i] |=
static_cast<code_type
>(idx) << (Dim * d);
483 [[nodiscard]] code_type lowestOffsets()
const {
return code_[0]; }
485 void lowestOffsets(code_type lowest_offsets, depth_type depth = 0)
487 code_[0] = lowest_offsets;
497 friend constexpr bool operator==(TreeCode
const& lhs, TreeCode
const& rhs)
noexcept
499 return lhs.code_ == rhs.code_ && lhs.depth_ == rhs.depth_;
502 friend constexpr bool operator!=(TreeCode
const& lhs, TreeCode
const& rhs)
noexcept
504 return !(lhs == rhs);
507 friend constexpr bool operator<(TreeCode
const& lhs, TreeCode
const& rhs)
noexcept
509 return lhs.code_ < rhs.code_;
512 friend constexpr bool operator<=(TreeCode
const& lhs, TreeCode
const& rhs)
noexcept
514 return lhs.code_ <= rhs.code_;
517 friend constexpr bool operator>(TreeCode
const& lhs, TreeCode
const& rhs)
noexcept
519 return lhs.code_ > rhs.code_;
522 friend constexpr bool operator>=(TreeCode
const& lhs, TreeCode
const& rhs)
noexcept
524 return lhs.code_ >= rhs.code_;
527 friend std::ostream& operator<<(std::ostream& os, TreeCode
const& code)
529 os <<
"code: " << code.code_[0] <<
" ";
530 if constexpr (ACTIVE[1]) {
531 os << code.code_[1] <<
" ";
533 if constexpr (ACTIVE[2]) {
534 os << code.code_[2] <<
" ";
536 return os <<
"depth: " << code.depth();
540 std::array<code_type, 3> code_{};
541 depth_type depth_ = maxDepth() + 1;