LLVM 24.0.0git
Eytzinger.h
Go to the documentation of this file.
1//===- Eytzinger.h - Eytzinger Search Tree Span -----------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file defines the EytzingerTableSpan class, a non-owning view of a
11/// buffer formatted as a complete binary search tree in Eytzinger
12/// (breadth-first) order.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_ADT_EYTZINGER_H
17#define LLVM_ADT_EYTZINGER_H
18
19#include "llvm/ADT/STLExtras.h"
20#include <cassert>
21#include <cstddef>
22#include <optional>
23#include <utility>
24#include <vector>
25
26namespace llvm {
27
28/// Non-owning view of a buffer formatted as a complete binary search tree in
29/// Eytzinger (breadth-first) order.
30template <typename T> class EytzingerTableSpan {
31public:
32 using iterator = const T *;
33 using const_iterator = const T *;
34
35 EytzingerTableSpan() = default;
36 EytzingerTableSpan(const T *Data, size_t NumEntries)
37 : Data(Data), NumEntries(NumEntries) {}
38
39 [[nodiscard]] iterator begin() const { return Data; }
40 [[nodiscard]] iterator end() const { return Data + NumEntries; }
41 [[nodiscard]] const T *data() const { return Data; }
42 [[nodiscard]] bool empty() const { return !Data || NumEntries == 0; }
43 [[nodiscard]] size_t size() const { return NumEntries; }
44 [[nodiscard]] const T &operator[](size_t Idx) const {
45 assert(Idx < NumEntries && "Index out of bounds");
46 return Data[Idx];
47 }
48
49 /// Search this Eytzinger table for Target. Returns the 0-based array index if
50 /// found.
51 ///
52 /// KeyT enables heterogeneous lookups, allowing callers to search tables of
53 /// endian-specific wrappers (e.g., support::ulittle64_t) using native integer
54 /// keys without explicit conversions at the call site.
55 template <typename KeyT = T>
56 [[nodiscard]] std::optional<size_t> findIndex(const KeyT &Target) const {
57 size_t I = 0;
58 while (I < NumEntries) {
59 if (Data[I] == Target)
60 return I;
61 I = 2 * I + 1 + (Data[I] < Target);
62 }
63 return std::nullopt;
64 }
65
66 /// Check if this Eytzinger table contains Target.
67 template <typename KeyT = T>
68 [[nodiscard]] bool contains(const KeyT &Target) const {
69 return findIndex(Target).has_value();
70 }
71
72 /// Verify whether the buffer satisfies strictly ascending binary search tree
73 /// order in Eytzinger layout. Runs iteratively in O(N) time and O(1) space.
74 [[nodiscard]] bool isSorted() const {
75 if (empty())
76 return true;
77
78 auto Left = [](size_t I) { return 2 * I + 1; };
79 auto Right = [](size_t I) { return 2 * I + 2; };
80 auto Parent = [](size_t I) { return (I - 1) / 2; };
81 auto IsRightChild = [](size_t I) { return I > 0 && I % 2 == 0; };
82 auto HasLeft = [&](size_t I) { return Left(I) < NumEntries; };
83 auto HasRight = [&](size_t I) { return Right(I) < NumEntries; };
84
85 // Start at the leftmost leaf (in-order minimum).
86 size_t Curr = 0;
87 while (HasLeft(Curr))
88 Curr = Left(Curr);
89
90 const T *Prev = nullptr;
91 while (Curr < NumEntries) {
92 if (Prev && !(*Prev < Data[Curr]))
93 return false;
94 Prev = &Data[Curr];
95
96 // Step to the in-order successor of Curr.
97 if (HasRight(Curr)) {
98 // If Curr has a right subtree, successor is its leftmost leaf.
99 Curr = Right(Curr);
100 while (HasLeft(Curr))
101 Curr = Left(Curr);
102 } else {
103 // Otherwise, walk upward while we are in the right branch.
104 while (IsRightChild(Curr))
105 Curr = Parent(Curr);
106 // Traversed the entire tree; done.
107 if (Curr == 0)
108 break;
109 // Step up from left child to parent.
110 Curr = Parent(Curr);
111 }
112 }
113 return true;
114 }
115
116private:
117 const T *Data = nullptr;
118 size_t NumEntries = 0;
119};
120
121/// Owning container that stores elements in a complete binary search tree
122/// formatted in Eytzinger (breadth-first) order.
123template <typename T> class EytzingerTable {
124 std::vector<T> Storage;
125
126 explicit EytzingerTable(std::vector<T> Buffer) : Storage(std::move(Buffer)) {}
127
128public:
129 using iterator = typename std::vector<T>::const_iterator;
130 using const_iterator = typename std::vector<T>::const_iterator;
131
132 EytzingerTable() = default;
133
134 /// Construct an Eytzinger search tree from a vector of keys by sorting,
135 /// deduplicating, and reordering elements into breadth-first layout.
136 /// KeyT may differ from T (e.g., creating EytzingerTable<ulittle64_t> from
137 /// a vector of uint64_t).
138 template <typename KeyT = T>
139 static EytzingerTable<T> create(std::vector<KeyT> Keys) {
140 llvm::sort(Keys);
141 Keys.erase(llvm::unique(Keys), Keys.end());
142
143 std::vector<T> Eytzinger(Keys.size());
144 size_t InIdx = 0;
145 auto EytzingerInOrder = [&](auto &Self, size_t K) -> void {
146 if (K > Keys.size())
147 return;
148 Self(Self, 2 * K);
149 Eytzinger[K - 1] = T(std::move(Keys[InIdx++]));
150 Self(Self, 2 * K + 1);
151 };
152 EytzingerInOrder(EytzingerInOrder, 1);
153 return EytzingerTable<T>(std::move(Eytzinger));
154 }
155
156 [[nodiscard]] EytzingerTableSpan<T> asSpan() const {
157 return EytzingerTableSpan<T>(Storage.data(), Storage.size());
158 }
159
160 template <typename KeyT = T>
161 [[nodiscard]] std::optional<size_t> findIndex(const KeyT &Target) const {
162 return asSpan().findIndex(Target);
163 }
164
165 template <typename KeyT = T>
166 [[nodiscard]] bool contains(const KeyT &Target) const {
167 return asSpan().contains(Target);
168 }
169
170 [[nodiscard]] bool isSorted() const { return asSpan().isSorted(); }
171
172 [[nodiscard]] iterator begin() { return Storage.begin(); }
173 [[nodiscard]] const_iterator begin() const { return Storage.begin(); }
174 [[nodiscard]] iterator end() { return Storage.end(); }
175 [[nodiscard]] const_iterator end() const { return Storage.end(); }
176
177 [[nodiscard]] const T *data() const { return Storage.data(); }
178 [[nodiscard]] size_t size() const { return Storage.size(); }
179 [[nodiscard]] bool empty() const { return Storage.empty(); }
180 [[nodiscard]] const T &operator[](size_t Idx) const {
181 assert(Idx < Storage.size() && "Index out of bounds");
182 return Storage[Idx];
183 }
184};
185
186} // namespace llvm
187
188#endif // LLVM_ADT_EYTZINGER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define I(x, y, z)
Definition MD5.cpp:57
#define T
This file contains some templates that are useful if you are working with the STL at all.
Non-owning view of a buffer formatted as a complete binary search tree in Eytzinger (breadth-first) o...
Definition Eytzinger.h:30
iterator end() const
Definition Eytzinger.h:40
bool contains(const KeyT &Target) const
Check if this Eytzinger table contains Target.
Definition Eytzinger.h:68
EytzingerTableSpan(const T *Data, size_t NumEntries)
Definition Eytzinger.h:36
bool isSorted() const
Verify whether the buffer satisfies strictly ascending binary search tree order in Eytzinger layout.
Definition Eytzinger.h:74
iterator begin() const
Definition Eytzinger.h:39
std::optional< size_t > findIndex(const KeyT &Target) const
Search this Eytzinger table for Target.
Definition Eytzinger.h:56
const T & operator[](size_t Idx) const
Definition Eytzinger.h:44
size_t size() const
Definition Eytzinger.h:43
const T * data() const
Definition Eytzinger.h:41
EytzingerTable()=default
const T & operator[](size_t Idx) const
Definition Eytzinger.h:180
typename std::vector< T >::const_iterator iterator
Definition Eytzinger.h:129
const T * data() const
Definition Eytzinger.h:177
bool isSorted() const
Definition Eytzinger.h:170
typename std::vector< T >::const_iterator const_iterator
Definition Eytzinger.h:130
size_t size() const
Definition Eytzinger.h:178
const_iterator begin() const
Definition Eytzinger.h:173
static EytzingerTable< T > create(std::vector< KeyT > Keys)
Construct an Eytzinger search tree from a vector of keys by sorting, deduplicating,...
Definition Eytzinger.h:139
bool empty() const
Definition Eytzinger.h:179
std::optional< size_t > findIndex(const KeyT &Target) const
Definition Eytzinger.h:161
EytzingerTableSpan< T > asSpan() const
Definition Eytzinger.h:156
bool contains(const KeyT &Target) const
Definition Eytzinger.h:166
const_iterator end() const
Definition Eytzinger.h:175
Target - Wrapper for Target specific information.
This is an optimization pass for GlobalISel generic memory operations.
auto unique(Range &&R, Predicate P)
Definition STLExtras.h:2134
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636