/src/duckdb/third_party/skiplist/HeadNode.h
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file |
3 | | * |
4 | | * Project: skiplist |
5 | | * |
6 | | * Created by Paul Ross on 03/12/2015. |
7 | | * |
8 | | * Copyright (c) 2015-2023 Paul Ross. All rights reserved. |
9 | | * |
10 | | * @code |
11 | | * MIT License |
12 | | * |
13 | | * Copyright (c) 2017-2023 Paul Ross |
14 | | * |
15 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
16 | | * of this software and associated documentation files (the "Software"), to deal |
17 | | * in the Software without restriction, including without limitation the rights |
18 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
19 | | * copies of the Software, and to permit persons to whom the Software is |
20 | | * furnished to do so, subject to the following conditions: |
21 | | * |
22 | | * The above copyright notice and this permission notice shall be included in all |
23 | | * copies or substantial portions of the Software. |
24 | | * |
25 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
26 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
27 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
28 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
29 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
30 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
31 | | * SOFTWARE. |
32 | | * @endcode |
33 | | */ |
34 | | |
35 | | #ifndef SkipList_HeadNode_h |
36 | | #define SkipList_HeadNode_h |
37 | | |
38 | | #include <functional> |
39 | | //#ifdef SKIPLIST_THREAD_SUPPORT |
40 | | // #include <mutex> |
41 | | //#endif |
42 | | #include <vector> |
43 | | |
44 | | #ifdef INCLUDE_METHODS_THAT_USE_STREAMS |
45 | | #include <sstream> |
46 | | #endif // INCLUDE_METHODS_THAT_USE_STREAMS |
47 | | |
48 | | #include "IntegrityEnums.h" |
49 | | |
50 | | /** HeadNode |
51 | | * |
52 | | * @brief A HeadNode is a skip list. This is the single node leading to all other content Nodes. |
53 | | * |
54 | | * Example: |
55 | | * |
56 | | * @code |
57 | | * OrderedStructs::SkipList::HeadNode<double> sl; |
58 | | * for (int i = 0; i < 100; ++i) { |
59 | | * sl.insert(i * 22.0 / 7.0); |
60 | | * } |
61 | | * sl.size(); // 100 |
62 | | * sl.at(50); // Value of 50 pi |
63 | | * sl.remove(sl.at(50)); // Remove 50 pi |
64 | | * @endcode |
65 | | * |
66 | | * Created by Paul Ross on 03/12/2015. |
67 | | * |
68 | | * Copyright (c) 2015-2023 Paul Ross. All rights reserved. |
69 | | * |
70 | | * @tparam T The type of the Skip List Node values. |
71 | | * @tparam _Compare A comparison function for type T. |
72 | | */ |
73 | | template <typename T, typename _Compare=std::less<T>> |
74 | | class HeadNode { |
75 | | public: |
76 | | /** |
77 | | * Constructor for and Empty Skip List. |
78 | | * |
79 | | * @param cmp The comparison function for comparing Node values. |
80 | | */ |
81 | 0 | HeadNode(_Compare cmp=_Compare()) : _count(0), _compare(cmp), _pool(cmp) { |
82 | | #ifdef INCLUDE_METHODS_THAT_USE_STREAMS |
83 | | _dot_file_subgraph = 0; |
84 | | #endif |
85 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, signed char> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, short> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, int> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, long> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, float> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, double> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> >) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::HeadNode(duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> >) |
86 | | // Const methods |
87 | | // |
88 | | // Returns true if the value is present in the skip list. |
89 | | bool has(const T &value) const; |
90 | | // Returns the value at the index in the skip list. |
91 | | // Will throw an OrderedStructs::SkipList::IndexError if index out of range. |
92 | | const T &at(size_t index) const; |
93 | | // Find the value at index and write count values to dest. |
94 | | // Will throw a SkipList::IndexError if any index out of range. |
95 | | // This is useful for rolling median on even length lists where |
96 | | // the caller might want to implement the mean of two values. |
97 | | void at(size_t index, size_t count, std::vector<T> &dest) const; |
98 | | // Computes index of the first occurrence of a value |
99 | | // Will throw a ValueError if the value does not exist in the skip list |
100 | | size_t index(const T& value) const; |
101 | | // Number of values in the skip list. |
102 | | size_t size() const; |
103 | | // Non-const methods |
104 | | // |
105 | | // Insert a value. |
106 | | void insert(const T &value); |
107 | | // Remove a value and return it. |
108 | | // Will throw a ValueError is value not present. |
109 | | T remove(const T &value); |
110 | | |
111 | | // Const methods that are mostly used for debugging and visualisation. |
112 | | // |
113 | | // Number of linked lists that are in the skip list. |
114 | | size_t height() const; |
115 | | // Number of linked lists that the node at index has. |
116 | | // Will throw a SkipList::IndexError if idx out of range. |
117 | | size_t height(size_t idx) const; |
118 | | // The skip width of the node at index has. |
119 | | // May throw a SkipList::IndexError |
120 | | size_t width(size_t idx, size_t level) const; |
121 | | |
122 | | #ifdef INCLUDE_METHODS_THAT_USE_STREAMS |
123 | | void dotFile(std::ostream &os) const; |
124 | | void dotFileFinalise(std::ostream &os) const; |
125 | | #endif // INCLUDE_METHODS_THAT_USE_STREAMS |
126 | | |
127 | | // Returns non-zero if the integrity of this data structure is compromised |
128 | | // This is a thorough but expensive check! |
129 | | IntegrityCheck lacksIntegrity() const; |
130 | | // Estimate of the number of bytes used by the skip list |
131 | | size_t size_of() const; |
132 | | virtual ~HeadNode(); |
133 | | |
134 | | protected: |
135 | | void _adjRemoveRefs(size_t level, Node<T, _Compare> *pNode); |
136 | | const Node<T, _Compare> *_nodeAt(size_t idx) const; |
137 | | |
138 | | protected: |
139 | | // Standardised way of throwing a ValueError |
140 | | void _throwValueErrorNotFound(const T &value) const; |
141 | | void _throwIfValueDoesNotCompare(const T &value) const; |
142 | | // Internal integrity checks |
143 | | IntegrityCheck _lacksIntegrityCyclicReferences() const; |
144 | | IntegrityCheck _lacksIntegrityWidthAccumulation() const; |
145 | | IntegrityCheck _lacksIntegrityNodeReferencesNotInList() const; |
146 | | IntegrityCheck _lacksIntegrityOrder() const; |
147 | | protected: |
148 | | /// Number of nodes in the list. |
149 | | size_t _count; |
150 | | /// My node references, the size of this is the largest height in the list |
151 | | SwappableNodeRefStack<T, _Compare> _nodeRefs; |
152 | | /// Comparison function. |
153 | | _Compare _compare; |
154 | | typename Node<T, _Compare>::_Pool _pool; |
155 | | #ifdef INCLUDE_METHODS_THAT_USE_STREAMS |
156 | | /// Used to count how many sub-graphs have been plotted |
157 | | mutable size_t _dot_file_subgraph; |
158 | | #endif |
159 | | |
160 | | private: |
161 | | /// Prevent cctor and operator= |
162 | | HeadNode(const HeadNode &that); |
163 | | HeadNode &operator=(const HeadNode &that) const; |
164 | | }; |
165 | | |
166 | | /** |
167 | | * Returns true if the value is present in the skip list. |
168 | | * |
169 | | * @tparam T Type of the values in the Skip List. |
170 | | * @tparam _Compare Compare function. |
171 | | * @param value Value to check if it is in the Skip List. |
172 | | * @return true if in the Skip List. |
173 | | */ |
174 | | template <typename T, typename _Compare> |
175 | | bool HeadNode<T, _Compare>::has(const T &value) const { |
176 | | _throwIfValueDoesNotCompare(value); |
177 | | #ifdef SKIPLIST_THREAD_SUPPORT |
178 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
179 | | #endif |
180 | | for (size_t l = _nodeRefs.height(); l-- > 0;) { |
181 | | assert(_nodeRefs[l].pNode); |
182 | | if (_nodeRefs[l].pNode->has(value)) { |
183 | | return true; |
184 | | } |
185 | | } |
186 | | return false; |
187 | | } |
188 | | |
189 | | /** |
190 | | * Returns the value at a particular index. |
191 | | * Will throw an OrderedStructs::SkipList::IndexError if index out of range. |
192 | | * |
193 | | * If @ref SKIPLIST_THREAD_SUPPORT is defined this will block. |
194 | | * |
195 | | * See _throw_exceeds_size() that does the throw. |
196 | | * |
197 | | * @tparam T Type of the values in the Skip List. |
198 | | * @tparam _Compare Compare function. |
199 | | * @param index The index. |
200 | | * @return The value at that index. |
201 | | */ |
202 | | template <typename T, typename _Compare> |
203 | | const T &HeadNode<T, _Compare>::at(size_t index) const { |
204 | | #ifdef SKIPLIST_THREAD_SUPPORT |
205 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
206 | | #endif |
207 | | const Node<T, _Compare> *pNode = _nodeAt(index); |
208 | | assert(pNode); |
209 | | return pNode->value(); |
210 | | } |
211 | | |
212 | | /** |
213 | | * Find the count number of value starting at index and write them to dest. |
214 | | * |
215 | | * Will throw a OrderedStructs::SkipList::IndexError if any index out of range. |
216 | | * |
217 | | * This is useful for rolling median on even length lists where the caller might want to implement the mean of two |
218 | | * values. |
219 | | * |
220 | | * @tparam T Type of the values in the Skip List. |
221 | | * @tparam _Compare Compare function. |
222 | | * @param index The index. |
223 | | * @param count The number of values to retrieve. |
224 | | * @param dest The vector of values |
225 | | */ |
226 | | template <typename T, typename _Compare> |
227 | | void HeadNode<T, _Compare>::at(size_t index, size_t count, |
228 | 0 | std::vector<T> &dest) const { |
229 | | #ifdef SKIPLIST_THREAD_SUPPORT |
230 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
231 | | #endif |
232 | 0 | dest.clear(); |
233 | 0 | const Node<T, _Compare> *pNode = _nodeAt(index); |
234 | | // _nodeAt will (should) throw an IndexError so this |
235 | | // assert should always be true |
236 | 0 | assert(pNode); |
237 | 0 | while (count) { |
238 | 0 | if (! pNode) { |
239 | 0 | _throw_exceeds_size(_count); |
240 | 0 | } |
241 | 0 | dest.push_back(pNode->value()); |
242 | 0 | pNode = pNode->next(); |
243 | 0 | --count; |
244 | 0 | } |
245 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, signed char>, std::__1::allocator<std::__1::pair<unsigned long, signed char> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, short>, std::__1::allocator<std::__1::pair<unsigned long, short> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, int>, std::__1::allocator<std::__1::pair<unsigned long, int> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, long>, std::__1::allocator<std::__1::pair<unsigned long, long> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, duckdb::hugeint_t>, std::__1::allocator<std::__1::pair<unsigned long, duckdb::hugeint_t> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, float>, std::__1::allocator<std::__1::pair<unsigned long, float> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, double>, std::__1::allocator<std::__1::pair<unsigned long, double> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, duckdb::interval_t>, std::__1::allocator<std::__1::pair<unsigned long, duckdb::interval_t> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, duckdb::string_t>, std::__1::allocator<std::__1::pair<unsigned long, duckdb::string_t> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, duckdb::date_t>, std::__1::allocator<std::__1::pair<unsigned long, duckdb::date_t> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, duckdb::timestamp_t>, std::__1::allocator<std::__1::pair<unsigned long, duckdb::timestamp_t> > >&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::at(unsigned long, unsigned long, std::__1::vector<std::__1::pair<unsigned long, duckdb::dtime_t>, std::__1::allocator<std::__1::pair<unsigned long, duckdb::dtime_t> > >&) const |
246 | | |
247 | | /** |
248 | | * Computes index of the first occurrence of a value |
249 | | * Will throw a OrderedStructs::SkipList::ValueError if the value does not exist in the skip list |
250 | | * Will throw a OrderedStructs::SkipList::FailedComparison if the value is not comparable. |
251 | | * |
252 | | * @tparam T Type of the values in the Skip List. |
253 | | * @tparam _Compare Compare function. |
254 | | * @param value The value to search for. |
255 | | * @return |
256 | | */ |
257 | | template <typename T, typename _Compare> |
258 | | size_t HeadNode<T, _Compare>::index(const T& value) const { |
259 | | _throwIfValueDoesNotCompare(value); |
260 | | size_t idx; |
261 | | |
262 | | #ifdef SKIPLIST_THREAD_SUPPORT |
263 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
264 | | #endif |
265 | | for (size_t l = _nodeRefs.height(); l-- > 0;) { |
266 | | assert(_nodeRefs[l].pNode); |
267 | | if (_nodeRefs[l].pNode->index(value, idx, l)) { |
268 | | idx += _nodeRefs[l].width; |
269 | | assert(idx > 0); |
270 | | return idx - 1; |
271 | | } |
272 | | } |
273 | | _throwValueErrorNotFound(value); |
274 | | return 0; |
275 | | } |
276 | | |
277 | | /** |
278 | | * Return the number of values in the Skip List. |
279 | | * |
280 | | * @tparam T Type of the values in the Skip List. |
281 | | * @tparam _Compare Compare function. |
282 | | * @return The number of values in the Skip List. |
283 | | */ |
284 | | template <typename T, typename _Compare> |
285 | 0 | size_t HeadNode<T, _Compare>::size() const { |
286 | 0 | return _count; |
287 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::size() const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::size() const |
288 | | |
289 | | template <typename T, typename _Compare> |
290 | | size_t HeadNode<T, _Compare>::height() const { |
291 | | #ifdef SKIPLIST_THREAD_SUPPORT |
292 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
293 | | #endif |
294 | | size_t val = _nodeRefs.height(); |
295 | | return val; |
296 | | } |
297 | | |
298 | | /** |
299 | | * Return the number of linked lists that the node at index has. |
300 | | * |
301 | | * Will throw a OrderedStructs::SkipList::IndexError if the index out of range. |
302 | | * |
303 | | * @tparam T Type of the values in the Skip List. |
304 | | * @tparam _Compare Compare function. |
305 | | * @param idx The index of the Skip List node. |
306 | | * @return The number of linked lists that the node at the index has. |
307 | | */ |
308 | | template <typename T, typename _Compare> |
309 | | size_t HeadNode<T, _Compare>::height(size_t idx) const { |
310 | | #ifdef SKIPLIST_THREAD_SUPPORT |
311 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
312 | | #endif |
313 | | const Node<T, _Compare> *pNode = _nodeAt(idx); |
314 | | assert(pNode); |
315 | | return pNode->height(); |
316 | | } |
317 | | |
318 | | /** |
319 | | * The skip width of the Node at index has at the given level. |
320 | | * Will throw an IndexError if the index is out of range. |
321 | | * |
322 | | * @tparam T Type of the values in the Skip List. |
323 | | * @tparam _Compare Compare function. |
324 | | * @param idx The index. |
325 | | * @param level The level. |
326 | | * @return Width of Node. |
327 | | */ |
328 | | template <typename T, typename _Compare> |
329 | | size_t HeadNode<T, _Compare>::width(size_t idx, size_t level) const { |
330 | | #ifdef SKIPLIST_THREAD_SUPPORT |
331 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
332 | | #endif |
333 | | // Will throw if out of range. |
334 | | const Node<T, _Compare> *pNode = _nodeAt(idx); |
335 | | assert(pNode); |
336 | | if (level >= pNode->height()) { |
337 | | _throw_exceeds_size(pNode->height()); |
338 | | } |
339 | | return pNode->nodeRefs()[level].width; |
340 | | } |
341 | | |
342 | | /** |
343 | | * Find the Node at the given index. |
344 | | * Will throw an IndexError if the index is out of range. |
345 | | * |
346 | | * @tparam T Type of the values in the Skip List. |
347 | | * @tparam _Compare Compare function. |
348 | | * @param idx The index. |
349 | | * @return The Node. |
350 | | */ |
351 | | template <typename T, typename _Compare> |
352 | 0 | const Node<T, _Compare> *HeadNode<T, _Compare>::_nodeAt(size_t idx) const { |
353 | 0 | if (idx < _count) { |
354 | 0 | for (size_t l = _nodeRefs.height(); l-- > 0;) { |
355 | 0 | if (_nodeRefs[l].pNode && _nodeRefs[l].width <= idx + 1) { |
356 | 0 | size_t new_index = idx + 1 - _nodeRefs[l].width; |
357 | 0 | const Node<T, _Compare> *pNode = _nodeRefs[l].pNode->at(new_index); |
358 | 0 | if (pNode) { |
359 | 0 | return pNode; |
360 | 0 | } |
361 | 0 | } |
362 | 0 | } |
363 | 0 | } |
364 | 0 | assert(idx >= _count); |
365 | 0 | _throw_exceeds_size(_count); |
366 | | // Should not get here as _throw_exceeds_size() will always throw. |
367 | 0 | return NULL; |
368 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::_nodeAt(unsigned long) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::_nodeAt(unsigned long) const |
369 | | |
370 | | /** |
371 | | * Insert a value. |
372 | | * |
373 | | * @tparam T Type of the values in the Skip List. |
374 | | * @tparam _Compare Compare function. |
375 | | * @param value |
376 | | */ |
377 | | template <typename T, typename _Compare> |
378 | 0 | void HeadNode<T, _Compare>::insert(const T &value) { |
379 | | #ifdef SKIPLIST_THREAD_SUPPORT |
380 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
381 | | #ifdef SKIPLIST_THREAD_SUPPORT_TRACE |
382 | | std::cout << "HeadNode insert() thread: " << std::this_thread::get_id() << std::endl; |
383 | | #endif |
384 | | #endif |
385 | 0 | Node<T, _Compare> *pNode = nullptr; |
386 | 0 | size_t level = _nodeRefs.height(); |
387 | |
|
388 | 0 | _throwIfValueDoesNotCompare(value); |
389 | 0 | while (level-- > 0) { |
390 | 0 | assert(_nodeRefs[level].pNode); |
391 | 0 | pNode = _nodeRefs[level].pNode->insert(value); |
392 | 0 | if (pNode) { |
393 | 0 | break; |
394 | 0 | } |
395 | 0 | } |
396 | 0 | if (! pNode) { |
397 | 0 | pNode = _pool.Allocate(value); |
398 | 0 | level = 0; |
399 | 0 | } |
400 | 0 | assert(pNode); |
401 | 0 | SwappableNodeRefStack<T, _Compare> &thatRefs = pNode->nodeRefs(); |
402 | 0 | if (thatRefs.canSwap()) { |
403 | | // Expand this to that |
404 | 0 | while (_nodeRefs.height() < thatRefs.height()) { |
405 | 0 | _nodeRefs.push_back(nullptr, _count + 1); |
406 | 0 | } |
407 | 0 | if (level < thatRefs.swapLevel()) { |
408 | | // Happens when we were originally, say 3 high (max height of any |
409 | | // previously seen node). Then a node is created |
410 | | // say 5 high. In that case this will be at level 2 and |
411 | | // thatRefs.swapLevel() will be 3 |
412 | 0 | assert(level + 1 == thatRefs.swapLevel()); |
413 | 0 | thatRefs[thatRefs.swapLevel()].width += _nodeRefs[level].width; |
414 | 0 | ++level; |
415 | 0 | } |
416 | | // Now swap |
417 | 0 | while (level < _nodeRefs.height() && thatRefs.canSwap()) { |
418 | 0 | assert(thatRefs.canSwap()); |
419 | 0 | assert(level == thatRefs.swapLevel()); |
420 | 0 | _nodeRefs[level].width -= thatRefs[level].width - 1; |
421 | 0 | thatRefs.swap(_nodeRefs); |
422 | 0 | if (thatRefs.canSwap()) { |
423 | 0 | assert(thatRefs[thatRefs.swapLevel()].width == 0); |
424 | 0 | thatRefs[thatRefs.swapLevel()].width = _nodeRefs[level].width; |
425 | 0 | } |
426 | 0 | ++level; |
427 | 0 | } |
428 | | // Check all references swapped |
429 | 0 | assert(! thatRefs.canSwap()); |
430 | | // Check that all 'this' pointers created on construction have been moved |
431 | 0 | assert(thatRefs.noNodePointerMatches(pNode)); |
432 | 0 | } |
433 | 0 | if (level < thatRefs.swapLevel()) { |
434 | | // Happens when we are, say 5 high then a node is created |
435 | | // and consumed by the next node say 3 high. In that case this will be |
436 | | // at level 2 and thatRefs.swapLevel() will be 3 |
437 | 0 | assert(level + 1 == thatRefs.swapLevel()); |
438 | 0 | ++level; |
439 | 0 | } |
440 | | // Increment my widths as my references are now going over the top of |
441 | | // pNode. |
442 | 0 | while (level < _nodeRefs.height() && level >= thatRefs.height()) { |
443 | 0 | _nodeRefs[level++].width += 1; |
444 | 0 | } |
445 | 0 | ++_count; |
446 | | #ifdef SKIPLIST_THREAD_SUPPORT |
447 | | #ifdef SKIPLIST_THREAD_SUPPORT_TRACE |
448 | | std::cout << "HeadNode insert() thread: " << std::this_thread::get_id() << " DONE" << std::endl; |
449 | | #endif |
450 | | #endif |
451 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::insert(std::__1::pair<unsigned long, signed char> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::insert(std::__1::pair<unsigned long, short> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::insert(std::__1::pair<unsigned long, int> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::insert(std::__1::pair<unsigned long, long> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::insert(std::__1::pair<unsigned long, duckdb::hugeint_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::insert(std::__1::pair<unsigned long, float> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::insert(std::__1::pair<unsigned long, double> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::insert(std::__1::pair<unsigned long, duckdb::interval_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::insert(std::__1::pair<unsigned long, duckdb::string_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::insert(std::__1::pair<unsigned long, duckdb::date_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::insert(std::__1::pair<unsigned long, duckdb::timestamp_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::insert(std::__1::pair<unsigned long, duckdb::dtime_t> const&) |
452 | | |
453 | | /** |
454 | | * Adjust references >= level for removal of the node pNode. |
455 | | * |
456 | | * @tparam T Type of the values in the Skip List. |
457 | | * @tparam _Compare Compare function. |
458 | | * @param level Current level. |
459 | | * @param pNode Node to swap references with. |
460 | | */ |
461 | | template <typename T, typename _Compare> |
462 | | void HeadNode<T, _Compare>::_adjRemoveRefs(size_t level, |
463 | 0 | Node<T, _Compare> *pNode) { |
464 | 0 | assert(pNode); |
465 | 0 | SwappableNodeRefStack<T, _Compare> &thatRefs = pNode->nodeRefs(); |
466 | | |
467 | | // Swap all remaining levels |
468 | | // This assertion checks that if swapping can take place we must be at the |
469 | | // same level. |
470 | 0 | assert(! thatRefs.canSwap() || level == thatRefs.swapLevel()); |
471 | 0 | while (level < _nodeRefs.height() && thatRefs.canSwap()) { |
472 | 0 | assert(level == thatRefs.swapLevel()); |
473 | | // Compute the new width for the new node |
474 | 0 | thatRefs[level].width += _nodeRefs[level].width - 1; |
475 | 0 | thatRefs.swap(_nodeRefs); |
476 | 0 | ++level; |
477 | 0 | if (! thatRefs.canSwap()) { |
478 | 0 | break; |
479 | 0 | } |
480 | 0 | } |
481 | 0 | assert(! thatRefs.canSwap()); |
482 | | // Decrement my widths as my references are now going over the top of |
483 | | // pNode. |
484 | 0 | while (level < _nodeRefs.height()) { |
485 | 0 | _nodeRefs[level++].width -= 1; |
486 | 0 | } |
487 | | // Decrement my stack while top has a NULL pointer. |
488 | 0 | while (_nodeRefs.height() && ! _nodeRefs[_nodeRefs.height() - 1].pNode) { |
489 | 0 | _nodeRefs.pop_back(); |
490 | 0 | } |
491 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >*) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::_adjRemoveRefs(unsigned long, duckdb_skiplistlib::skip_list::Node<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >*) |
492 | | |
493 | | /** |
494 | | * Remove a Node with a value. |
495 | | * May throw a ValueError if the value is not found. |
496 | | * |
497 | | * @tparam T Type of the values in the Skip List. |
498 | | * @tparam _Compare Compare function. |
499 | | * @param value The value in the Node to remove. |
500 | | * @return The value removed. |
501 | | */ |
502 | | template <typename T, typename _Compare> |
503 | 0 | T HeadNode<T, _Compare>::remove(const T &value) { |
504 | | #ifdef SKIPLIST_THREAD_SUPPORT |
505 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
506 | | #ifdef SKIPLIST_THREAD_SUPPORT_TRACE |
507 | | std::cout << "HeadNode remove() thread: " << std::this_thread::get_id() << std::endl; |
508 | | #endif |
509 | | #endif |
510 | 0 | Node<T, _Compare> *pNode = nullptr; |
511 | 0 | size_t level; |
512 | |
|
513 | 0 | _throwIfValueDoesNotCompare(value); |
514 | 0 | for (level = _nodeRefs.height(); level-- > 0;) { |
515 | 0 | assert(_nodeRefs[level].pNode); |
516 | 0 | pNode = _nodeRefs[level].pNode->remove(level, value); |
517 | 0 | if (pNode) { |
518 | 0 | break; |
519 | 0 | } |
520 | 0 | } |
521 | 0 | if (! pNode) { |
522 | 0 | _throwValueErrorNotFound(value); |
523 | 0 | } |
524 | | // Take swap level as some swaps will have been dealt with by the remove() above. |
525 | 0 | _adjRemoveRefs(pNode->nodeRefs().swapLevel(), pNode); |
526 | 0 | --_count; |
527 | 0 | T ret_val = _pool.Release(pNode); |
528 | | #ifdef SKIPLIST_THREAD_SUPPORT_TRACE |
529 | | std::cout << "HeadNode remove() thread: " << std::this_thread::get_id() << " DONE" << std::endl; |
530 | | #endif |
531 | 0 | return ret_val; |
532 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::remove(std::__1::pair<unsigned long, signed char> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::remove(std::__1::pair<unsigned long, short> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::remove(std::__1::pair<unsigned long, int> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::remove(std::__1::pair<unsigned long, long> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::remove(std::__1::pair<unsigned long, duckdb::hugeint_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::remove(std::__1::pair<unsigned long, float> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::remove(std::__1::pair<unsigned long, double> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::remove(std::__1::pair<unsigned long, duckdb::interval_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::remove(std::__1::pair<unsigned long, duckdb::string_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::remove(std::__1::pair<unsigned long, duckdb::date_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::remove(std::__1::pair<unsigned long, duckdb::timestamp_t> const&) Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::remove(std::__1::pair<unsigned long, duckdb::dtime_t> const&) |
533 | | |
534 | | /** |
535 | | * Throw a ValueError in a consistent fashion. |
536 | | * |
537 | | * @tparam T Type of the values in the Skip List. |
538 | | * @tparam _Compare Compare function. |
539 | | * @param value The value to put into the ValueError. |
540 | | */ |
541 | | template <typename T, typename _Compare> |
542 | 0 | void HeadNode<T, _Compare>::_throwValueErrorNotFound(const T &value) const { |
543 | | #ifdef INCLUDE_METHODS_THAT_USE_STREAMS |
544 | | std::ostringstream oss; |
545 | | oss << "Value " << value << " not found."; |
546 | | std::string err_msg = oss.str(); |
547 | | #else |
548 | 0 | std::string err_msg = "Value not found."; |
549 | 0 | #endif |
550 | 0 | throw ValueError(err_msg); |
551 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, signed char> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, short> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, int> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, long> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, duckdb::hugeint_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, float> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, double> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, duckdb::interval_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, duckdb::string_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, duckdb::date_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, duckdb::timestamp_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::_throwValueErrorNotFound(std::__1::pair<unsigned long, duckdb::dtime_t> const&) const |
552 | | |
553 | | /** |
554 | | * Checks that the value == value. |
555 | | * This will throw a FailedComparison if that is not the case, for example NaN. |
556 | | * |
557 | | * @note |
558 | | * The Node class is (should be) not directly accessible by the user so we can just assert(value == value) in Node. |
559 | | * |
560 | | * @tparam T Type of the values in the Skip List. |
561 | | * @tparam _Compare Compare function. |
562 | | * @param value |
563 | | */ |
564 | | template <typename T, typename _Compare> |
565 | 0 | void HeadNode<T, _Compare>::_throwIfValueDoesNotCompare(const T &value) const { |
566 | 0 | if (value != value) { |
567 | 0 | throw FailedComparison( |
568 | 0 | "Can not work with something that does not compare equal to itself."); |
569 | 0 | } |
570 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, signed char> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, short> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, int> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, long> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, duckdb::hugeint_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, float> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, double> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, duckdb::interval_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, duckdb::string_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, duckdb::date_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, duckdb::timestamp_t> const&) const Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::_throwIfValueDoesNotCompare(std::__1::pair<unsigned long, duckdb::dtime_t> const&) const |
571 | | |
572 | | /** |
573 | | * This tests that at every level >= 0 the sequence of node pointers |
574 | | * at that level does not contain a cyclic reference. |
575 | | * |
576 | | * @tparam T Type of the values in the Skip List. |
577 | | * @tparam _Compare Compare function. |
578 | | * @return An IntegrityCheck enum. |
579 | | */ |
580 | | template <typename T, typename _Compare> |
581 | | IntegrityCheck HeadNode<T, _Compare>::_lacksIntegrityCyclicReferences() const { |
582 | | assert(_nodeRefs.height()); |
583 | | // Check for cyclic references at each level |
584 | | for (size_t level = 0; level < _nodeRefs.height(); ++level) { |
585 | | Node<T, _Compare> *p1 = _nodeRefs[level].pNode; |
586 | | Node<T, _Compare> *p2 = _nodeRefs[level].pNode; |
587 | | while (p1 && p2) { |
588 | | p1 = p1->nodeRefs()[level].pNode; |
589 | | if (p2->nodeRefs()[level].pNode) { |
590 | | p2 = p2->nodeRefs()[level].pNode->nodeRefs()[level].pNode; |
591 | | } else { |
592 | | p2 = nullptr; |
593 | | } |
594 | | if (p1 && p2 && p1 == p2) { |
595 | | return HEADNODE_DETECTS_CYCLIC_REFERENCE; |
596 | | } |
597 | | } |
598 | | } |
599 | | return INTEGRITY_SUCCESS; |
600 | | } |
601 | | |
602 | | /** |
603 | | * This tests that at every level > 0 the node to node width is the same |
604 | | * as the accumulated node to node widths at level - 1. |
605 | | * |
606 | | * @tparam T Type of the values in the Skip List. |
607 | | * @tparam _Compare Compare function. |
608 | | * @return An IntegrityCheck enum. |
609 | | */ |
610 | | template <typename T, typename _Compare> |
611 | | IntegrityCheck HeadNode<T, _Compare>::_lacksIntegrityWidthAccumulation() const { |
612 | | assert(_nodeRefs.height()); |
613 | | for (size_t level = 1; level < _nodeRefs.height(); ++level) { |
614 | | const Node<T, _Compare> *pl = _nodeRefs[level].pNode; |
615 | | const Node<T, _Compare> *pl_1 = _nodeRefs[level - 1].pNode; |
616 | | assert(pl && pl_1); // No nulls allowed in HeadNode |
617 | | size_t wl = _nodeRefs[level].width; |
618 | | size_t wl_1 = _nodeRefs[level - 1].width; |
619 | | while (true) { |
620 | | while (pl != pl_1) { |
621 | | assert(pl_1); // Could only happen if a lower reference was NULL and the higher non-NULL. |
622 | | wl_1 += pl_1->width(level - 1); |
623 | | pl_1 = pl_1->pNode(level - 1); |
624 | | } |
625 | | if (wl != wl_1) { |
626 | | return HEADNODE_LEVEL_WIDTHS_MISMATCH; |
627 | | } |
628 | | if (pl == nullptr && pl_1 == nullptr) { |
629 | | break; |
630 | | } |
631 | | wl = pl->width(level); |
632 | | wl_1 = pl_1->width(level - 1); |
633 | | pl = pl->pNode(level); |
634 | | pl_1 = pl_1->pNode(level - 1); |
635 | | } |
636 | | } |
637 | | return INTEGRITY_SUCCESS; |
638 | | } |
639 | | |
640 | | /** |
641 | | * This tests the integrity of each Node. |
642 | | * |
643 | | * @tparam T Type of the values in the Skip List. |
644 | | * @tparam _Compare Compare function. |
645 | | * @return An IntegrityCheck enum. |
646 | | */ |
647 | | template <typename T, typename _Compare> |
648 | | IntegrityCheck HeadNode<T, _Compare>::_lacksIntegrityNodeReferencesNotInList() const { |
649 | | assert(_nodeRefs.height()); |
650 | | |
651 | | IntegrityCheck result; |
652 | | std::set<const Node<T, _Compare>*> nodeSet; |
653 | | const Node<T, _Compare> *pNode = _nodeRefs[0].pNode; |
654 | | assert(pNode); |
655 | | |
656 | | // First gather all nodes, slightly awkward code here is so that |
657 | | // NULL is always included. |
658 | | nodeSet.insert(pNode); |
659 | | do { |
660 | | pNode = pNode->next(); |
661 | | nodeSet.insert(pNode); |
662 | | } while (pNode); |
663 | | assert(nodeSet.size() == _count + 1); // All nodes plus NULL |
664 | | // Then test each node does not have pointers that are not in nodeSet |
665 | | pNode = _nodeRefs[0].pNode; |
666 | | while (pNode) { |
667 | | result = pNode->lacksIntegrityRefsInSet(nodeSet); |
668 | | if (result) { |
669 | | return result; |
670 | | } |
671 | | pNode = pNode->next(); |
672 | | } |
673 | | return INTEGRITY_SUCCESS; |
674 | | } |
675 | | |
676 | | /** |
677 | | * Integrity check. Traverse the lowest level and check that the ordering |
678 | | * is correct according to the compare function. The HeadNode checks that the |
679 | | * Node(s) have correctly applied the compare function. |
680 | | * |
681 | | * @tparam T Type of the values in the Skip List. |
682 | | * @tparam _Compare Compare function. |
683 | | * @return An IntegrityCheck enum. |
684 | | */ |
685 | | template <typename T, typename _Compare> |
686 | | IntegrityCheck HeadNode<T, _Compare>::_lacksIntegrityOrder() const { |
687 | | if (_nodeRefs.height()) { |
688 | | // Traverse the lowest level list iteratively deleting as we go |
689 | | // Doing this recursivley could be expensive as we are at level 0. |
690 | | const Node<T, _Compare> *node = _nodeRefs[0].pNode; |
691 | | const Node<T, _Compare> *next; |
692 | | while (node) { |
693 | | next = node->next(); |
694 | | if (next && _compare(next->value(), node->value())) { |
695 | | return HEADNODE_DETECTS_OUT_OF_ORDER; |
696 | | } |
697 | | node = next; |
698 | | } |
699 | | } |
700 | | return INTEGRITY_SUCCESS; |
701 | | } |
702 | | |
703 | | /** |
704 | | * Full integrity check. |
705 | | * This calls the other integrity check functions. |
706 | | * |
707 | | * @tparam T Type of the values in the Skip List. |
708 | | * @tparam _Compare Compare function. |
709 | | * @return An IntegrityCheck enum. |
710 | | */ |
711 | | template <typename T, typename _Compare> |
712 | | IntegrityCheck HeadNode<T, _Compare>::lacksIntegrity() const { |
713 | | #ifdef SKIPLIST_THREAD_SUPPORT |
714 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
715 | | #endif |
716 | | if (_nodeRefs.height()) { |
717 | | IntegrityCheck result = _nodeRefs.lacksIntegrity(); |
718 | | if (result) { |
719 | | return result; |
720 | | } |
721 | | if (! _nodeRefs.noNodePointerMatches(nullptr)) { |
722 | | return HEADNODE_CONTAINS_NULL; |
723 | | } |
724 | | // Check all nodes for integrity |
725 | | const Node<T, _Compare> *pNode = _nodeRefs[0].pNode; |
726 | | while (pNode) { |
727 | | result = pNode->lacksIntegrity(_nodeRefs.height()); |
728 | | if (result) { |
729 | | return result; |
730 | | } |
731 | | pNode = pNode->next(); |
732 | | } |
733 | | // Check count against total number of nodes |
734 | | pNode = _nodeRefs[0].pNode; |
735 | | size_t total = 0; |
736 | | while (pNode) { |
737 | | total += pNode->nodeRefs()[0].width; |
738 | | pNode = pNode->next(); |
739 | | } |
740 | | if (total != _count) { |
741 | | return HEADNODE_COUNT_MISMATCH; |
742 | | } |
743 | | result = _lacksIntegrityWidthAccumulation(); |
744 | | if (result) { |
745 | | return result; |
746 | | } |
747 | | result = _lacksIntegrityCyclicReferences(); |
748 | | if (result) { |
749 | | return result; |
750 | | } |
751 | | result = _lacksIntegrityNodeReferencesNotInList(); |
752 | | if (result) { |
753 | | return result; |
754 | | } |
755 | | result = _lacksIntegrityOrder(); |
756 | | if (result) { |
757 | | return result; |
758 | | } |
759 | | } |
760 | | return INTEGRITY_SUCCESS; |
761 | | } |
762 | | |
763 | | /** |
764 | | * Returns an estimate of the memory usage of an instance. |
765 | | * |
766 | | * @tparam T Type of the values in the Skip List. |
767 | | * @tparam _Compare Compare function. |
768 | | * @return The size of the memory estimate. |
769 | | */ |
770 | | template <typename T, typename _Compare> |
771 | | size_t HeadNode<T, _Compare>::size_of() const { |
772 | | #ifdef SKIPLIST_THREAD_SUPPORT |
773 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
774 | | #endif |
775 | | // sizeof(*this) includes the size of _nodeRefs but _nodeRefs.size_of() |
776 | | // includes sizeof(_nodeRefs) so we need to subtract to avoid double counting |
777 | | size_t ret_val = sizeof(*this) + _nodeRefs.size_of() - sizeof(_nodeRefs); |
778 | | if (_nodeRefs.height()) { |
779 | | const Node<T, _Compare> *node = _nodeRefs[0].pNode; |
780 | | while (node) { |
781 | | ret_val += node->size_of(); |
782 | | node = node->next(); |
783 | | } |
784 | | } |
785 | | return ret_val; |
786 | | } |
787 | | |
788 | | /** |
789 | | * Destructor. |
790 | | * This deletes all Nodes. |
791 | | * |
792 | | * @tparam T Type of the values in the Skip List. |
793 | | * @tparam _Compare Compare function. |
794 | | */ |
795 | | template <typename T, typename _Compare> |
796 | 0 | HeadNode<T, _Compare>::~HeadNode() { |
797 | | // Hmm could this deadlock? |
798 | | #ifdef SKIPLIST_THREAD_SUPPORT |
799 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
800 | | #endif |
801 | 0 | if (_nodeRefs.height()) { |
802 | | // Traverse the lowest level list iteratively deleting as we go |
803 | | // Doing this recursivley could be expensive as we are at level 0. |
804 | 0 | const Node<T, _Compare> *node = _nodeRefs[0].pNode; |
805 | 0 | const Node<T, _Compare> *next; |
806 | 0 | while (node) { |
807 | 0 | next = node->next(); |
808 | 0 | delete node; |
809 | 0 | --_count; |
810 | 0 | node = next; |
811 | 0 | } |
812 | 0 | } |
813 | 0 | assert(_count == 0); |
814 | 0 | } Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, signed char>, duckdb::SkipLess<std::__1::pair<unsigned long, signed char> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, short>, duckdb::SkipLess<std::__1::pair<unsigned long, short> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, int>, duckdb::SkipLess<std::__1::pair<unsigned long, int> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, long>, duckdb::SkipLess<std::__1::pair<unsigned long, long> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::hugeint_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::hugeint_t> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, float>, duckdb::SkipLess<std::__1::pair<unsigned long, float> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, double>, duckdb::SkipLess<std::__1::pair<unsigned long, double> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::interval_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::interval_t> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::string_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::string_t> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::date_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::date_t> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::timestamp_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::timestamp_t> > >::~HeadNode() Unexecuted instantiation: duckdb_skiplistlib::skip_list::HeadNode<std::__1::pair<unsigned long, duckdb::dtime_t>, duckdb::SkipLess<std::__1::pair<unsigned long, duckdb::dtime_t> > >::~HeadNode() |
815 | | |
816 | | #ifdef INCLUDE_METHODS_THAT_USE_STREAMS |
817 | | |
818 | | /** |
819 | | * Create a DOT file of the internal representation. |
820 | | * |
821 | | * @tparam T Type of the values in the Skip List. |
822 | | * @tparam _Compare Compare function. |
823 | | * @param os Where to write the DOT file. |
824 | | */ |
825 | | template <typename T, typename _Compare> |
826 | | void HeadNode<T, _Compare>::dotFile(std::ostream &os) const { |
827 | | #ifdef SKIPLIST_THREAD_SUPPORT |
828 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
829 | | #endif |
830 | | if (_dot_file_subgraph == 0) { |
831 | | os << "digraph SkipList {" << std::endl; |
832 | | os << "label = \"SkipList.\"" << std::endl; |
833 | | os << "graph [rankdir = \"LR\"];" << std::endl; |
834 | | os << "node [fontsize = \"12\" shape = \"ellipse\"];" << std::endl; |
835 | | os << "edge [];" << std::endl; |
836 | | os << std::endl; |
837 | | } |
838 | | os << "subgraph cluster" << _dot_file_subgraph << " {" << std::endl; |
839 | | os << "style=dashed" << std::endl; |
840 | | os << "label=\"Skip list iteration " << _dot_file_subgraph << "\"" << std::endl; |
841 | | os << std::endl; |
842 | | os << "\"HeadNode" << _dot_file_subgraph; |
843 | | os << "\" [" << std::endl; |
844 | | os << "label = \""; |
845 | | // Write out the fields |
846 | | if (_nodeRefs.height()) { |
847 | | for (size_t level = _nodeRefs.height(); level-- > 0;) { |
848 | | os << "{ " << _nodeRefs[level].width << " | "; |
849 | | os << "<f" << level + 1 << "> "; |
850 | | os << std::hex << _nodeRefs[level].pNode << std::dec; |
851 | | os << "}"; |
852 | | if (level > 0) { |
853 | | os << " | "; |
854 | | } |
855 | | } |
856 | | } else { |
857 | | os << "Empty HeadNode"; |
858 | | } |
859 | | os << "\"" << std::endl; |
860 | | os << "shape = \"record\"" << std::endl; |
861 | | os << "];" << std::endl; |
862 | | // Edges for head node |
863 | | for (size_t level = 0; level < _nodeRefs.height(); ++level) { |
864 | | os << "\"HeadNode"; |
865 | | os << _dot_file_subgraph; |
866 | | os << "\":f" << level + 1 << " -> "; |
867 | | _nodeRefs[level].pNode->writeNode(os, _dot_file_subgraph); |
868 | | os << ":w" << level + 1 << " [];" << std::endl; |
869 | | } |
870 | | os << std::endl; |
871 | | // Now all nodes via level 0, if non-empty |
872 | | if (_nodeRefs.height()) { |
873 | | Node<T, _Compare> *pNode = this->_nodeRefs[0].pNode; |
874 | | pNode->dotFile(os, _dot_file_subgraph); |
875 | | } |
876 | | os << std::endl; |
877 | | // NULL, the sentinal node |
878 | | if (_nodeRefs.height()) { |
879 | | os << "\"node"; |
880 | | os << _dot_file_subgraph; |
881 | | os << "0x0\" [label = \""; |
882 | | for (size_t level = _nodeRefs.height(); level-- > 0;) { |
883 | | os << "<w" << level + 1 << "> NULL"; |
884 | | if (level) { |
885 | | os << " | "; |
886 | | } |
887 | | } |
888 | | os << "\" shape = \"record\"];" << std::endl; |
889 | | } |
890 | | // End: "subgraph cluster1 {" |
891 | | os << "}" << std::endl; |
892 | | os << std::endl; |
893 | | _dot_file_subgraph += 1; |
894 | | } |
895 | | |
896 | | /** |
897 | | * Finalise the DOT file of the internal representation. |
898 | | * |
899 | | * @tparam T Type of the values in the Skip List. |
900 | | * @tparam _Compare Compare function. |
901 | | * @param os Where to write the DOT file. |
902 | | */ |
903 | | template <typename T, typename _Compare> |
904 | | void HeadNode<T, _Compare>::dotFileFinalise(std::ostream &os) const { |
905 | | #ifdef SKIPLIST_THREAD_SUPPORT |
906 | | std::lock_guard<std::mutex> lock(gSkipListMutex); |
907 | | #endif |
908 | | if (_dot_file_subgraph > 0) { |
909 | | // Link the nodes together with an invisible node. |
910 | | // node0 [shape=record, label = "<f0> | <f1> | <f2> | <f3> | <f4> | <f5> | <f6> | <f7> | <f8> | ", |
911 | | // style=invis, |
912 | | // width=0.01]; |
913 | | os << "node0 [shape=record, label = \""; |
914 | | for (size_t i = 0; i < _dot_file_subgraph; ++i) { |
915 | | os << "<f" << i << "> | "; |
916 | | } |
917 | | os << "\", style=invis, width=0.01];" << std::endl; |
918 | | // Now: |
919 | | // node0:f0 -> HeadNode [style=invis]; |
920 | | // node0:f1 -> HeadNode1 [style=invis]; |
921 | | for (size_t i = 0; i < _dot_file_subgraph; ++i) { |
922 | | os << "node0:f" << i << " -> HeadNode" << i; |
923 | | os << " [style=invis];" << std::endl; |
924 | | } |
925 | | _dot_file_subgraph = 0; |
926 | | } |
927 | | os << "}" << std::endl; |
928 | | } |
929 | | |
930 | | #endif // INCLUDE_METHODS_THAT_USE_STREAMS |
931 | | |
932 | | /************************** END: HeadNode *******************************/ |
933 | | |
934 | | #endif // SkipList_HeadNode_h |