MySQL 8.4.2
Source Code Documentation
ut0lst.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 1995, 2024, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is designed to work with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation. The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have either included with
15the program or referenced in the documentation.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20for more details.
21
22You should have received a copy of the GNU General Public License along with
23this program; if not, write to the Free Software Foundation, Inc.,
2451 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26*****************************************************************************/
27
28/** @file include/ut0lst.h
29 List utilities
30
31 Created 9/10/1995 Heikki Tuuri
32 Rewritten by Sunny Bains Dec 2011.
33 ***********************************************************************/
34
35#ifndef ut0lst_h
36#define ut0lst_h
37
38/* Do not include univ.i because univ.i includes this. */
39
40#include <atomic>
41#include "ut0dbg.h"
42
43/* This module implements the two-way linear list. Note that a single
44list node may belong to two or more lists, but is only on one list
45at a time. */
46
47/** The two way list node.
48 @tparam Type the list node type name */
49template <typename Type>
51 Type *prev; /*!< pointer to the previous
52 node, NULL if start of list */
53 Type *next; /*!< pointer to next node,
54 NULL if end of list */
55
56 void reverse() {
57 Type *tmp = prev;
58 prev = next;
59 next = tmp;
60 }
61};
62
63/** Macro used for legacy reasons */
64#define UT_LIST_NODE_T(t) ut_list_node<t>
65
66#ifdef UNIV_DEBUG
67#define UT_LIST_INITIALISED 0xCAFE
68#endif /* UNIV_DEBUG */
69
70#define UT_LIST_IS_INITIALISED(b) ((b).init == UT_LIST_INITIALISED)
71
72/** The two-way list base node. The base node contains pointers to both ends
73 of the list and a count of nodes in the list (excluding the base node
74 from the count). We also store a pointer to the member field so that it
75 doesn't have to be specified when doing list operations.
76 @tparam Type the type of the list element
77 @tparam NodeGetter a class which has a static member
78 ut_list_node<Type> get_node(const Type & e) which knows how to extract
79 a node from an element */
80template <typename Type, typename NodeGetter>
82 using elem_type = Type;
84 static const node_type &get_node(const elem_type &e) {
85 return NodeGetter::get_node(e);
86 }
88 return const_cast<node_type &>(get_node(const_cast<const elem_type &>(e)));
89 }
90 static const elem_type *next(const elem_type &e) { return get_node(e).next; }
91 static elem_type *next(elem_type &e) {
92 return const_cast<elem_type *>(next(const_cast<const elem_type &>(e)));
93 }
94 static const elem_type *prev(const elem_type &e) { return get_node(e).prev; }
95 static elem_type *prev(elem_type &e) {
96 return const_cast<elem_type *>(prev(const_cast<const elem_type &>(e)));
97 }
98
99 /** Pointer to list start, NULL if empty. */
101 /** Pointer to list end, NULL if empty. */
103#ifdef UNIV_DEBUG
104 /** UT_LIST_INITIALISED if the list was initialised with the constructor. It
105 is used to detect if the ut_list_base object is used directly after
106 allocating memory from malloc-like calls that do not run constructor. */
108#endif /* UNIV_DEBUG */
109
110 /** Returns number of nodes currently present in the list. */
111 size_t get_length() const {
113 return count.load(std::memory_order_acquire);
114 }
115
116 /** Updates the length of the list by the amount specified.
117 @param diff the value by which to increase the length. Can be negative. */
118 void update_length(int diff) {
119 ut_ad(diff > 0 || static_cast<size_t>(-diff) <= get_length());
120 count.store(get_length() + diff, std::memory_order_release);
121 }
122
123 void clear() {
125 first_element = nullptr;
126 last_element = nullptr;
127 count.store(0);
128 }
129
130 void reverse() {
131 Type *tmp = first_element;
133 last_element = tmp;
134 }
135
136 private:
137 /** Number of nodes in list. It is atomic to allow unprotected reads. Writes
138 must be protected by some external latch. */
139 std::atomic<size_t> count{0};
140
141 template <typename E>
143 private:
145
146 public:
147 base_iterator(E *elem) : m_elem(elem) {}
148 bool operator==(const base_iterator &other) const {
149 return m_elem == other.m_elem;
150 }
151 bool operator!=(const base_iterator &other) const {
152 return !(*this == other);
153 }
154 E *operator*() const { return m_elem; }
156 m_elem = next(*m_elem);
157 return *this;
158 }
159 };
160
161 public:
165 iterator end() { return nullptr; }
167 const_iterator end() const { return nullptr; }
168
169 /** A helper wrapper class for the list, which exposes begin(),end() iterators
170 which let you remove the current item or items after it during the loop, while
171 still having O(1) space and time complexity.
172 NOTE: do not attempt to (re)move the previous element! */
173 class Removable {
174 private:
176
177 public:
178 class iterator {
179 private:
183
184 public:
186 : m_list{list},
187 m_elem{elem},
188 m_prev_elem{elem ? prev(*elem) : nullptr} {
189 // We haven't really tested any other case yet:
190 ut_ad(m_prev_elem == nullptr);
191 }
192 bool operator==(const iterator &other) const {
193 return m_elem == other.m_elem;
194 }
195 bool operator!=(const iterator &other) const { return !(*this == other); }
196 elem_type *operator*() const { return m_elem; }
198 /* if m_prev_elem existed before, then it should still belong to the
199 list, which we verify partially here, by checking it's linked to next
200 element or is the last. If this assert fails, it means the m_prev_elem
201 was removed from the list during loop, which is violation of the
202 contract with the user of .removable(). */
205 /* The reason this is so complicated is that we want to support cases in
206 which the body of the loop removed not only the current element, but
207 also some elements even further after it. */
208 auto here =
210 if (here != m_elem) {
211 m_elem = here;
212 } else {
214 m_elem = next(*m_elem);
215 }
216 return *this;
217 }
218 };
221 iterator end() { return iterator{m_list, nullptr}; }
222 };
223 /** Returns a wrapper which lets you remove current item or items after it.
224 It can be used like in this example:
225 for (auto lock : table->locks.removable()) {
226 lock_remove_all_on_table_for_trx(table, lock->trx,..);
227 }
228 Or in general:
229 for (auto item : list.removable()) {
230 remove_items_which_are_similar_to(item);
231 }
232 Basically you can remove any item, except for prev(item).
233
234 You can also insert to the list during iteration, keeping in mind that the
235 position you insert the element at has following impact:
236 - after the current item: the new item WILL be processed eventually,
237 - before the previous item: the new item WILL NOT be processed,
238 - right before the current item: DON'T DO IT, as you risk an endless loop!
239 A safe subcase of this is reinserting the current item, in which case it
240 won't be processed again. This lets you implement "move to front" easily.
241 @see Removable */
242 Removable removable() { return Removable{*this}; }
243};
244template <typename Type, ut_list_node<Type> Type::*node_ptr>
246 static const ut_list_node<Type> &get_node(const Type &element) {
247 return element.*node_ptr;
248 }
249};
250/** A type of a list storing pointers to t, chained by member m of t.
251NOTE: In cases in which definition of t is not yet in scope and thus you can't
252refer to t::m at this point yet, use UT_LIST_BASE_NODE_T_EXTERN macro instead.*/
253#define UT_LIST_BASE_NODE_T(t, m) \
254 ut_list_base<t, ut_list_base_explicit_getter<t, &t::m>>
255
256/** A helper for the UT_LIST_BASE_NODE_T_EXTERN which builds a name of a node
257getter struct from the name of elem type t, and its member name m */
258#define UT_LIST_NODE_GETTER(t, m) t##_##m##_node_getter
259
260/** A helper for the UT_LIST_BASE_NODE_T_EXTERN which declares a node getter
261struct which extracts member m from element of type t. Note that the definition
262of the get_node function is inline, so this declaration/definition can appear
263multiple times in our codebase, and the intent is that you simply put it in the
264header which defines member m of t for the first time, so that it is accessible.
265This way all the places in codebase which know how to access m from t, will be
266also able to use this node getter, and thus iterate over a list chained by it.
267This also ensures, that for(auto elem: list) loops can be fully inlined by the
268compiler as it can see through the get_node implementation, because each place
269in code which knows that get_node exists also knows its implementation.*/
270#define UT_LIST_NODE_GETTER_DEFINITION(t, m) \
271 struct UT_LIST_NODE_GETTER(t, m) \
272 : public ut_list_base_explicit_getter<t, &t::m> {};
273
274/** A variant of UT_LIST_BASE_NODE_T to be used in rare cases where the full
275definition of t is not yet in scope, and thus UT_LIST_BASE_NODE_T can't be used
276yet as it needs to know how to access member m of t. The trick used here is to
277forward declare UT_LIST_NODE_GETTER(t,m) struct to be defined later by the
278UT_LIST_NODE_GETTER_DEFINITION(t,m) once t::m is defined. */
279#define UT_LIST_BASE_NODE_T_EXTERN(t, m) \
280 ut_list_base<t, struct UT_LIST_NODE_GETTER(t, m)>
281
282/** Initializes the base node of a two-way list.
283 @param b the list base node
284*/
285#define UT_LIST_INIT(b) \
286 { \
287 auto &list_ref = (b); \
288 new (&list_ref) std::remove_reference_t<decltype(list_ref)>(); \
289 }
290
291/** Adds the node as the first element in a two-way linked list.
292 @param list the base node (not a pointer to it)
293 @param elem the element to add */
294template <typename List>
295void ut_list_prepend(List &list, typename List::elem_type *elem) {
296 auto &elem_node = List::get_node(*elem);
297
299
300 elem_node.prev = nullptr;
301 elem_node.next = list.first_element;
302
303 if (list.first_element != nullptr) {
304 ut_ad(list.first_element != elem);
305
306 List::get_node(*list.first_element).prev = elem;
307 }
308
309 list.first_element = elem;
310
311 if (list.last_element == nullptr) {
312 list.last_element = elem;
313 }
314
315 list.update_length(1);
316}
317
318/** Adds the node as the first element in a two-way linked list.
319 @param LIST the base node (not a pointer to it)
320 @param ELEM the element to add */
321#define UT_LIST_ADD_FIRST(LIST, ELEM) ut_list_prepend(LIST, ELEM)
322
323/** Adds the node as the last element in a two-way linked list.
324 @param list list
325 @param elem the element to add
326 */
327template <typename List>
328void ut_list_append(List &list, typename List::elem_type *elem) {
329 auto &elem_node = List::get_node(*elem);
330
332
333 elem_node.next = nullptr;
334 elem_node.prev = list.last_element;
335
336 if (list.last_element != nullptr) {
337 ut_ad(list.last_element != elem);
338
339 List::get_node(*list.last_element).next = elem;
340 }
341
342 list.last_element = elem;
343
344 if (list.first_element == nullptr) {
345 list.first_element = elem;
346 }
347
348 list.update_length(1);
349}
350
351/** Adds the node as the last element in a two-way linked list.
352 @param LIST list base node (not a pointer to it)
353 @param ELEM the element to add */
354#define UT_LIST_ADD_LAST(LIST, ELEM) ut_list_append(LIST, ELEM)
355
356/** Inserts a ELEM2 after ELEM1 in a list.
357 @param list the base node
358 @param elem1 node after which ELEM2 is inserted
359 @param elem2 node being inserted after ELEM1 */
360template <typename List>
361void ut_list_insert(List &list, typename List::elem_type *elem1,
362 typename List::elem_type *elem2) {
363 ut_ad(elem1 != elem2);
364 ut_ad(elem1 != nullptr);
365 ut_ad(elem2 != nullptr);
367
368 auto &elem1_node = List::get_node(*elem1);
369 auto &elem2_node = List::get_node(*elem2);
370
371 elem2_node.prev = elem1;
372 elem2_node.next = elem1_node.next;
373 ut_ad((elem2_node.next == nullptr) == (list.last_element == elem1));
374 if (elem2_node.next != nullptr) {
375 List::get_node(*elem2_node.next).prev = elem2;
376 } else {
377 list.last_element = elem2;
378 }
379
380 elem1_node.next = elem2;
381
382 list.update_length(1);
383}
384
385/** Inserts a ELEM2 after ELEM1 in a list.
386 @param LIST list base node (not a pointer to it)
387 @param ELEM1 node after which ELEM2 is inserted
388 @param ELEM2 node being inserted after ELEM1 */
389#define UT_LIST_INSERT_AFTER(LIST, ELEM1, ELEM2) \
390 ut_list_insert(LIST, ELEM1, ELEM2)
391
392/** Removes a node from a two-way linked list.
393 @param list the base node (not a pointer to it)
394 @param elem pointer to the element to remove from the list
395*/
396template <typename List>
397void ut_list_remove(List &list, typename List::elem_type *elem) {
398 ut_a(list.get_length() > 0);
400
401 auto &node = List::get_node(*elem);
402 if (node.next != nullptr) {
403 List::get_node(*node.next).prev = node.prev;
404 } else {
405 list.last_element = node.prev;
406 }
407
408 if (node.prev != nullptr) {
409 List::get_node(*node.prev).next = node.next;
410 } else {
411 list.first_element = node.next;
412 }
413
414 node.next = nullptr;
415 node.prev = nullptr;
416
417 list.update_length(-1);
418}
419
420/** Removes a node from a two-way linked list.
421 @param LIST the base node (not a pointer to it)
422 @param ELEM node to be removed from the list */
423#define UT_LIST_REMOVE(LIST, ELEM) ut_list_remove(LIST, ELEM)
424
425/** Gets the next node in a two-way list.
426 @param NAME list name
427 @param N pointer to a node
428 @return the successor of N in NAME, or NULL */
429#define UT_LIST_GET_NEXT(NAME, N) (((N)->NAME).next)
430
431/** Gets the previous node in a two-way list.
432 @param NAME list name
433 @param N pointer to a node
434 @return the predecessor of N in NAME, or NULL */
435#define UT_LIST_GET_PREV(NAME, N) (((N)->NAME).prev)
436
437/** Alternative macro to get the number of nodes in a two-way list, i.e.,
438 its length.
439 @param BASE the base node (not a pointer to it).
440 @return the number of nodes in the list */
441#define UT_LIST_GET_LEN(BASE) (BASE).get_length()
442
443/** Gets the first node in a two-way list.
444 @param BASE the base node (not a pointer to it)
445 @return first node, or NULL if the list is empty */
446#define UT_LIST_GET_FIRST(BASE) (BASE).first_element
447
448/** Gets the last node in a two-way list.
449 @param BASE the base node (not a pointer to it)
450 @return last node, or NULL if the list is empty */
451#define UT_LIST_GET_LAST(BASE) (BASE).last_element
452
454 void operator()(const void *) {}
455};
456
457/** Iterate over all the elements and call the functor for each element.
458 @param[in] list base node (not a pointer to it)
459 @param[in,out] functor Functor that is called for each element in the list */
460template <typename List, class Functor>
461void ut_list_map(const List &list, Functor &functor) {
462 size_t count = 0;
463
465
466 for (auto elem : list) {
467 functor(elem);
468 ++count;
469 }
470
471 ut_a(count == list.get_length());
472}
473
474template <typename List>
477 // NOTE: we use List::prev to iterate forward as .reverse() swaps arrows
478 for (auto elem = list.first_element; elem != nullptr;
479 elem = List::prev(*elem)) {
480 List::get_node(*elem).reverse();
481 }
482
483 list.reverse();
484}
485
486#define UT_LIST_REVERSE(LIST) ut_list_reverse(LIST)
487
488/** Checks the consistency of a two-way list.
489 @param[in] list base node (not a pointer to it)
490 @param[in,out] functor Functor that is called for each element in
491 the list */
492template <typename List, class Functor>
493void ut_list_validate(const List &list, Functor &functor) {
494 ut_list_map(list, functor);
495 /* Validate the list backwards. */
496 size_t count = 0;
497
498 for (auto elem = list.last_element; elem != nullptr;
499 elem = List::prev(*elem)) {
500 ++count;
501 }
502
503 ut_a(count == list.get_length());
504}
505
506/** Check the consistency of a two-way list.
507@param[in] LIST base node reference */
508#define UT_LIST_CHECK(LIST) \
509 do { \
510 NullValidate nullV; \
511 ut_list_validate(LIST, nullV); \
512 } while (0)
513
514/** Move the given element to the beginning of the list.
515@param[in,out] list the list object
516@param[in] elem the element of the list which will be moved
517 to the beginning of the list. */
518template <typename List>
519void ut_list_move_to_front(List &list, typename List::elem_type *elem) {
520 ut_ad(ut_list_exists(list, elem));
521
522 if (list.first_element != elem) {
523 ut_list_remove(list, elem);
524 ut_list_prepend(list, elem);
525 }
526}
527
528#ifdef UNIV_DEBUG
529/** Check if the given element exists in the list.
530@param[in,out] list the list object
531@param[in] elem the element of the list which will be checked */
532template <typename List>
533bool ut_list_exists(List &list, typename List::elem_type *elem) {
535 for (auto e1 : list) {
536 if (elem == e1) {
537 return true;
538 }
539 }
540 return false;
541}
542#endif
543
544#endif /* ut0lst.h */
Kerberos Client Authentication nullptr
Definition: auth_kerberos_client_plugin.cc:251
Definition: sql_list.h:467
Definition: ut0lst.h:178
bool operator!=(const iterator &other) const
Definition: ut0lst.h:195
elem_type * m_elem
Definition: ut0lst.h:181
elem_type * operator*() const
Definition: ut0lst.h:196
bool operator==(const iterator &other) const
Definition: ut0lst.h:192
ut_list_base & m_list
Definition: ut0lst.h:180
iterator(ut_list_base &list, elem_type *elem)
Definition: ut0lst.h:185
iterator & operator++()
Definition: ut0lst.h:197
elem_type * m_prev_elem
Definition: ut0lst.h:182
A helper wrapper class for the list, which exposes begin(),end() iterators which let you remove the c...
Definition: ut0lst.h:173
ut_list_base & m_list
Definition: ut0lst.h:175
iterator begin()
Definition: ut0lst.h:220
Removable(ut_list_base &list)
Definition: ut0lst.h:219
iterator end()
Definition: ut0lst.h:221
Definition: ut0lst.h:142
base_iterator & operator++()
Definition: ut0lst.h:155
bool operator==(const base_iterator &other) const
Definition: ut0lst.h:148
E * operator*() const
Definition: ut0lst.h:154
E * m_elem
Definition: ut0lst.h:144
base_iterator(E *elem)
Definition: ut0lst.h:147
bool operator!=(const base_iterator &other) const
Definition: ut0lst.h:151
static Bigint * diff(Bigint *a, Bigint *b, Stack_alloc *alloc)
Definition: dtoa.cc:1076
static int count
Definition: myisam_ftdump.cc:45
Type
Definition: resource_group_basic_types.h:33
std::list< T, ut::allocator< T > > list
Specialization of list which uses ut_allocator.
Definition: ut0new.h:2878
Definition: ut0lst.h:453
void operator()(const void *)
Definition: ut0lst.h:454
Definition: ut0lst.h:245
static const ut_list_node< Type > & get_node(const Type &element)
Definition: ut0lst.h:246
The two-way list base node.
Definition: ut0lst.h:81
static const elem_type * next(const elem_type &e)
Definition: ut0lst.h:90
iterator end()
Definition: ut0lst.h:165
const_iterator begin() const
Definition: ut0lst.h:166
static elem_type * next(elem_type &e)
Definition: ut0lst.h:91
elem_type * first_element
Pointer to list start, NULL if empty.
Definition: ut0lst.h:100
elem_type * last_element
Pointer to list end, NULL if empty.
Definition: ut0lst.h:102
const_iterator end() const
Definition: ut0lst.h:167
void update_length(int diff)
Updates the length of the list by the amount specified.
Definition: ut0lst.h:118
std::atomic< size_t > count
Number of nodes in list.
Definition: ut0lst.h:139
void clear()
Definition: ut0lst.h:123
static elem_type * prev(elem_type &e)
Definition: ut0lst.h:95
static const node_type & get_node(const elem_type &e)
Definition: ut0lst.h:84
static const elem_type * prev(const elem_type &e)
Definition: ut0lst.h:94
iterator begin()
Definition: ut0lst.h:164
size_t get_length() const
Returns number of nodes currently present in the list.
Definition: ut0lst.h:111
Type elem_type
Definition: ut0lst.h:82
void reverse()
Definition: ut0lst.h:130
static node_type & get_node(elem_type &e)
Definition: ut0lst.h:87
Removable removable()
Returns a wrapper which lets you remove current item or items after it.
Definition: ut0lst.h:242
ulint init
UT_LIST_INITIALISED if the list was initialised with the constructor.
Definition: ut0lst.h:107
The two way list node.
Definition: ut0lst.h:50
Type * prev
pointer to the previous node, NULL if start of list
Definition: ut0lst.h:51
void reverse()
Definition: ut0lst.h:56
Type * next
pointer to next node, NULL if end of list
Definition: ut0lst.h:53
unsigned long int ulint
Definition: univ.i:406
Debug utilities for Innobase.
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:105
#define ut_a(EXPR)
Abort execution if EXPR does not evaluate to nonzero.
Definition: ut0dbg.h:93
#define UT_LIST_IS_INITIALISED(b)
Definition: ut0lst.h:70
void ut_list_validate(const List &list, Functor &functor)
Checks the consistency of a two-way list.
Definition: ut0lst.h:493
void ut_list_map(const List &list, Functor &functor)
Iterate over all the elements and call the functor for each element.
Definition: ut0lst.h:461
void ut_list_prepend(List &list, typename List::elem_type *elem)
Adds the node as the first element in a two-way linked list.
Definition: ut0lst.h:295
void ut_list_remove(List &list, typename List::elem_type *elem)
Removes a node from a two-way linked list.
Definition: ut0lst.h:397
#define UT_LIST_INITIALISED
Definition: ut0lst.h:67
void ut_list_append(List &list, typename List::elem_type *elem)
Adds the node as the last element in a two-way linked list.
Definition: ut0lst.h:328
void ut_list_reverse(List &list)
Definition: ut0lst.h:475
void ut_list_insert(List &list, typename List::elem_type *elem1, typename List::elem_type *elem2)
Inserts a ELEM2 after ELEM1 in a list.
Definition: ut0lst.h:361
void ut_list_move_to_front(List &list, typename List::elem_type *elem)
Move the given element to the beginning of the list.
Definition: ut0lst.h:519
bool ut_list_exists(List &list, typename List::elem_type *elem)
Check if the given element exists in the list.
Definition: ut0lst.h:533