MySQL 9.7.0
Source Code Documentation
mem_root_deque.h
Go to the documentation of this file.
1/* Copyright (c) 2019, 2026, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is designed to work with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have either included with
13 the program or referenced in the documentation.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24#ifndef MEM_ROOT_DEQUE_H
25#define MEM_ROOT_DEQUE_H
26
27#include <algorithm>
28#include <memory>
29#include <type_traits>
30#include <utility>
31
32#include <assert.h>
33#include <stdint.h>
34
35#include "my_alloc.h"
36
37template <class Element_type>
38static constexpr size_t FindElementsPerBlock() {
39 // Aim for 1 kB.
40 size_t base_number_elems =
41 1024 / sizeof(Element_type); // NOLINT(bugprone-sizeof-expression)
42
43 // Find the next power of two, rounded up. We should have at least 16 elements
44 // per block to avoid allocating way too often (although the code itself
45 // should work fine with 1, for debugging purposes).
46 for (size_t block_size = 16; block_size < 1024; ++block_size) {
47 if (block_size >= base_number_elems) {
48 return block_size;
49 }
50 }
51 return 1024;
52}
53
54/**
55 A (partial) implementation of std::deque allocating its blocks on a MEM_ROOT.
56
57 This class works pretty much like an std::deque with a Mem_root_allocator,
58 and used to be a forwarder to it. However, libstdc++ has a very complicated
59 implementation of std::deque, leading to code blowup (e.g., operator[] is
60 23 instructions on x86-64, including two branches), and we cannot easily use
61 libc++ on all platforms. This version is instead:
62
63 - Optimized for small, straight-through machine code (few and simple
64 instructions, few branches).
65 - Optimized for few elements; in particular, zero elements is an important
66 special case, much more so than 10,000.
67
68 It gives mostly the same guarantees as std::deque; elements can be
69 inserted efficiently on both front and back [1]. {push,pop}_{front,back}
70 guarantees reference stability except for to removed elements (obviously),
71 and invalidates iterators. (Iterators are forcefully invalidated using
72 asserts.) erase() does the same. Note that unlike std::deque, insert()
73 at begin() will invalidate references. Some functionality, like several
74 constructors, resize(), shrink_to_fit(), swap(), etc. is missing.
75
76 The implementation is the same as classic std::deque: Elements are held in
77 blocks of about 1 kB each. Once an element is in a block, it never moves
78 (giving the aforementioned pointer stability). The blocks are held in an
79 array, which can be reallocated when more blocks are needed. The
80 implementation keeps track of the used items in terms of “physical indexes”;
81 element 0 starts at the first byte of the first block, element 1 starts
82 immediately after 0, and so on. So you can have something like (assuming very
83 small blocks of only 4 elements each for the sake of drawing):
84
85 block 0 block 1 block 2
86 ↓ ↓ ↓
87 [x x 2 3] [4 5 6 7] [8 9 x x]
88 ↑ ↑
89 begin_idx = 2 end_idx = 10
90
91 end_idx counts as is customary one-past-the-end, so in this case, the elements
92 [2,9) would be valid, and e.g. (*this)[4] would give physical index 6, which
93 points to the third element (index 2) in the middle block (block 1). Inserting
94 a new element at the front is as easy as putting it in physical index 1 and
95 adjusting begin_idx to the left. This means a lookup by index requires some
96 shifting, masking and a double indirect load.
97
98 Iterators keep track of which deque they belong to, and what physical index
99 they point to. (So lookup by iterator also requires a double indirect load,
100 but the alternative would be caching the block pointer and having an extra
101 branch when advancing the iterator.) Inserting a new block at the beginning
102 would move around all the physical indexes (which is why iterators get
103 invalidated; we could probably get around this by having an “offset to first
104 block”, but it's likely not worth it.)
105
106 [1] The blocks array uses exponential growth (doubling), so insertions
107 are amortized O(1). The blocks array is reallocated rarely (O(log n) times
108 for n insertions).
109
110 To support exponential growth, we track additional state beyond the blocks
111 array pointer:
112
113 m_block_slots - Total slots in the blocks array (may exceed
114 num_blocks).
115 m_first_block_idx - Index where used blocks start (enables front
116 spare).
117 m_back_growth_exp - Growth exponent for back (next growth adds 2^exp
118 slots).
119 m_front_growth_exp - Growth exponent for front (next growth adds 2^exp
120 slots).
121
122 The growth exponents track history, not current state. After growing back
123 3 times, we've created 1+2+4=7 spare slots. But some may be consumed, so we
124 can't derive the exponent from current spare - we must track it explicitly.
125
126 Example: Growth triggered by push_back (back-only expansion)
127
128 Initial state (3 used blocks, no spare):
129 m_blocks: [B0][B1][B2]
130 m_first_block_idx: 0
131 m_block_slots: 3
132 m_back_growth_exp: 0
133
134 After 1st back growth (adds 2^0 = 1 spare slot at back):
135 m_blocks: [B0][B1][B2][ ]
136 ↑ spare
137 m_block_slots: 4
138 m_back_growth_exp: 1
139
140 After 2nd back growth (adds 2^1 = 2 spare slots at back):
141 m_blocks: [B0][B1][B2][B3][ ][ ]
142 ↑ spare
143 m_block_slots: 6
144 m_back_growth_exp: 2
145
146 Example: Growth triggered by push_front (front-only expansion)
147
148 Initial state (3 used blocks, no spare at front):
149 m_blocks: [B0][B1][B2]
150 m_first_block_idx: 0
151 m_front_growth_exp: 0
152
153 After 1st front growth (adds 2^0 = 1 spare slot at front):
154 m_blocks: [ ][B0][B1][B2]
155 ↑ spare
156 m_first_block_idx: 1 (new block goes here, then decrements to 0)
157 m_block_slots: 4
158 m_front_growth_exp: 1
159
160 After 2nd front growth (adds 2^1 = 2 spare slots at front):
161 m_blocks: [ ][ ][ ][B0][B1][B2]
162 ↑ spare
163 m_first_block_idx: 3 (new block goes at index 2)
164 m_block_slots: 6
165 m_front_growth_exp: 2
166
167 Each direction grows independently. A deque with many push_back calls will
168 have large m_back_growth_exp but m_front_growth_exp stays 0 until push_front
169 triggers growth.
170 */
171template <class Element_type>
173 public:
174 /// Used to conform to STL algorithm demands.
175 using size_type = size_t;
176 using difference_type = ptrdiff_t;
177 using value_type = Element_type;
178 using pointer = Element_type *;
179 using reference = Element_type &;
180 using const_pointer = const Element_type *;
181 using const_reference = const Element_type &;
182
183 /// Constructor. Leaves the array in an empty, valid state.
185
186 // Copy constructor and assignment. We could probably be a bit smarter
187 // about these for large arrays, if the source array has e.g. empty blocks.
189 : m_begin_idx(other.m_begin_idx),
190 m_end_idx(other.m_end_idx),
191 m_capacity(other.m_capacity),
196 m_root(other.m_root) {
198 for (size_t block_idx = 0; block_idx < num_blocks(); ++block_idx) {
200 }
201 for (size_t idx = m_begin_idx; idx != m_end_idx; ++idx) {
202 new (&get(idx)) Element_type(other.get(idx));
203 }
204 }
206 if (this != &other) {
207 clear();
208 for (const Element_type &elem : other) {
209 push_back(elem);
210 }
211 }
212 return *this;
213 }
214
215 // Move constructor and assignment.
217 : m_blocks(other.m_blocks),
219 m_end_idx(other.m_end_idx),
220 m_capacity(other.m_capacity),
225 m_root(other.m_root) {
226 other.m_blocks = nullptr;
227 other.m_begin_idx = other.m_end_idx = other.m_capacity = 0;
228 other.m_block_slots = other.m_first_block_idx = 0;
229 other.m_back_growth_exp = other.m_front_growth_exp = 0;
230 other.invalidate_iterators();
231 }
233 if (this != &other) {
234 this->~mem_root_deque();
235 new (this) mem_root_deque(std::move(other));
236 }
237 return *this;
238 }
239
241
242 Element_type &operator[](size_t idx) const { return get(idx + m_begin_idx); }
243
244 /**
245 Adds the given element to the end of the deque.
246 The element is a copy of the given one.
247
248 @returns true on OOM (no change is done if so)
249 */
250 bool push_back(const Element_type &element) {
251 if (m_end_idx == m_capacity) {
252 if (add_block_back()) {
253 return true;
254 }
255 }
256 new (&get(m_end_idx++)) Element_type(element);
258 return false;
259 }
260
261 /**
262 Adds the given element to the end of the deque.
263 The element is moved into place.
264
265 @returns true on OOM (no change is done if so)
266 */
267 bool push_back(Element_type &&element) {
268 if (m_end_idx == m_capacity) {
269 if (add_block_back()) {
270 return true;
271 }
272 }
273 new (&get(m_end_idx++)) Element_type(std::move(element));
275 return false;
276 }
277
278 /**
279 Adds the given element to the beginning of the deque.
280 The element is a copy of the given one.
281
282 @returns true on OOM (no change is done if so)
283 */
284 bool push_front(const Element_type &element) {
285 if (m_begin_idx == 0) {
286 if (add_block_front()) {
287 return true;
288 }
289 assert(m_begin_idx != 0);
290 }
291 new (&get(--m_begin_idx)) Element_type(element);
293 return false;
294 }
295
296 /**
297 Adds the given element to the end of the deque.
298 The element is moved into place.
299 */
300 bool push_front(Element_type &&element) {
301 if (m_begin_idx == 0) {
302 if (add_block_front()) {
303 return true;
304 }
305 assert(m_begin_idx != 0);
306 }
307 new (&get(--m_begin_idx)) Element_type(std::move(element));
309 return false;
310 }
311
312 /// Removes the last element from the deque.
313 void pop_back() {
314 assert(!empty());
317 }
318
319 /// Removes the first element from the deque.
320 void pop_front() {
321 assert(!empty());
324 }
325
326 /// Returns the first element in the deque.
327 Element_type &front() {
328 assert(!empty());
329 return get(m_begin_idx);
330 }
331
332 const Element_type &front() const {
333 assert(!empty());
334 return get(m_begin_idx);
335 }
336
337 /// Returns the last element in the deque.
338 Element_type &back() {
339 assert(!empty());
340 return get(m_end_idx - 1);
341 }
342
343 const Element_type &back() const {
344 assert(!empty());
345 return get(m_end_idx - 1);
346 }
347
348 /// Removes all elements from the deque. Destructors are called,
349 /// but since the elements themselves are allocated on the MEM_ROOT,
350 /// their memory cannot be freed.
351 void clear() {
352 for (size_t idx = m_begin_idx; idx != m_end_idx; ++idx) {
353 ::destroy_at(&get(idx));
354 }
357 }
358
359 size_t block_slots() const { return m_block_slots; }
360 size_t first_block_idx() const { return m_first_block_idx; }
361 uint8_t back_growth_exp() const { return m_back_growth_exp; }
362 uint8_t front_growth_exp() const { return m_front_growth_exp; }
363 size_t capacity() const { return m_capacity; }
364
365 template <class Iterator_element_type>
366 class Iterator {
367 public:
368 using difference_type = ptrdiff_t;
369 using value_type = Iterator_element_type;
370 using pointer = Iterator_element_type *;
371 using reference = Iterator_element_type &;
372 using iterator_category = std::random_access_iterator_tag;
373
374 // DefaultConstructible (required for ForwardIterator).
375 Iterator() = default;
376
377 Iterator(const mem_root_deque *deque, size_t physical_idx)
378 : m_deque(deque), m_physical_idx(physical_idx) {
379#ifndef NDEBUG
381#endif
382 }
383
384 /// For const_iterator: Implicit conversion from iterator.
385 /// This is written in a somewhat cumbersome fashion to avoid
386 /// declaring an explicit copy constructor for iterator,
387 /// which causes compiler warnings other places for some compilers.
388 // NOLINTNEXTLINE(google-explicit-constructor): Intentional.
389 template <
390 class T,
391 typename = std::enable_if_t<
393 std::is_same<typename T::value_type,
394 std::remove_const_t<Iterator_element_type>>::value>>
395 Iterator(const T &other)
397#ifndef NDEBUG
398 m_generation = other.m_generation;
399#endif
400 }
401
402 // Iterator (required for InputIterator).
403 Iterator_element_type &operator*() const {
405 return m_deque->get(m_physical_idx);
406 }
410 return *this;
411 }
412
413 // EqualityComparable (required for InputIterator).
414 bool operator==(const Iterator &other) const {
416 assert(m_deque == other.m_deque);
417 return m_physical_idx == other.m_physical_idx;
418 }
419
420 // InputIterator (required for ForwardIterator).
421 bool operator!=(const Iterator &other) const { return !(*this == other); }
422
423 Iterator_element_type *operator->() const {
425 return &m_deque->get(m_physical_idx);
426 }
427
428 // ForwardIterator (required for RandomAccessIterator).
431 Iterator ret = *this;
433 return ret;
434 }
435
436 // BidirectionalIterator (required for RandomAccessIterator).
440 return *this;
441 }
444 Iterator ret = *this;
446 return ret;
447 }
448
449 // RandomAccessIterator.
453 return *this;
454 }
455
459 return *this;
460 }
461
464 return Iterator{m_deque, m_physical_idx + offset};
465 }
466
469 return Iterator{m_deque, m_physical_idx - offset};
470 }
471
472 difference_type operator-(const Iterator &other) const {
474 assert(m_deque == other.m_deque);
475 return m_physical_idx - other.m_physical_idx;
476 }
477
478 Iterator_element_type &operator[](size_t idx) const {
479 return *(*this + idx);
480 }
481
482 bool operator<(const Iterator &other) const {
484 assert(m_deque == other.m_deque);
485 return m_physical_idx < other.m_physical_idx;
486 }
487
488 bool operator<=(const Iterator &other) const { return !(*this > other); }
489
490 bool operator>(const Iterator &other) const {
492 assert(m_deque == other.m_deque);
493 return m_physical_idx > other.m_physical_idx;
494 }
495
496 bool operator>=(const Iterator &other) const { return !(*this < other); }
497
498 private:
499 const mem_root_deque *m_deque = nullptr;
500 size_t m_physical_idx = 0;
501#ifndef NDEBUG
502 size_t m_generation = 0;
503#endif
504
506 assert(m_generation == m_deque->generation());
507 }
508
509 friend class mem_root_deque;
510 };
511
514 using reverse_iterator = std::reverse_iterator<iterator>;
515 using reverse_const_iterator = std::reverse_iterator<const_iterator>;
516
517 iterator begin() { return iterator{this, m_begin_idx}; }
518 iterator end() { return iterator{this, m_end_idx}; }
519 reverse_iterator rbegin() { return std::make_reverse_iterator(end()); }
520 reverse_iterator rend() { return std::make_reverse_iterator(begin()); }
524 const_iterator end() const { return const_iterator{this, m_end_idx}; }
526 return std::make_reverse_iterator(end());
527 }
529 return std::make_reverse_iterator(begin());
530 }
532 return std::make_reverse_iterator(end());
533 }
535 return std::make_reverse_iterator(begin());
536 }
537
538 size_t size() const { return m_end_idx - m_begin_idx; }
539 bool empty() const { return size() == 0; }
540
541 /**
542 Erase all the elements in the specified range.
543
544 @param first iterator that points to the first element to remove
545 @param last iterator that points to the element after the
546 last one to remove
547 @return an iterator to the first element after the removed range
548 */
550 iterator pos = begin() + (first - cbegin());
551 if (first != last) {
552 iterator new_end = std::move(last, cend(), pos);
553 for (size_t idx = new_end.m_physical_idx; idx != m_end_idx; ++idx) {
554 ::destroy_at(&get(idx));
555 }
556 m_end_idx = new_end.m_physical_idx;
557 }
559#ifndef NDEBUG
560 pos.m_generation = m_generation; // Re-validate.
561#endif
562 return pos;
563 }
564
565 /**
566 Removes a single element from the array.
567
568 @param position iterator that points to the element to remove
569
570 @return an iterator to the first element after the removed range
571 */
573 return erase(position, std::next(position));
574 }
575
576 /**
577 Insert an element at a given position.
578 The element is a copy of the given one.
579
580 @param pos the new element is inserted before the element
581 at this position
582 @param value the value of the new element
583 @return an iterator that points to the inserted element
584 */
585 iterator insert(const_iterator pos, const Element_type &value) {
586 difference_type idx = pos - cbegin();
588 std::rotate(begin() + idx, end() - 1, end());
590 return begin() + idx;
591 }
592
593 /**
594 Insert an element at a given position.
595 The element is moved into place.
596
597 @param pos the new element is inserted before the element
598 at this position
599 @param value the value of the new element
600 @return an iterator that points to the inserted element
601 */
602 iterator insert(const_iterator pos, Element_type &&value) {
603 difference_type idx = pos - cbegin();
604 push_back(std::move(value));
605 std::rotate(begin() + idx, end() - 1, end());
607 return begin() + idx;
608 }
609
610 template <class ForwardIt>
611 iterator insert(const_iterator pos, ForwardIt first, ForwardIt last) {
612 difference_type idx = pos - cbegin();
613 for (ForwardIt it = first; it != last; ++it) {
614 push_back(*it);
615 }
616 std::rotate(begin() + idx, end() - (last - first), end());
618 return begin() + idx;
619 }
620
621 private:
622 /// Number of elements in each block.
623 static constexpr size_t block_elements = FindElementsPerBlock<Element_type>();
624
625 // A block capable of storing <block_elements> elements. Deliberately
626 // has no constructor, since it wouldn't help any of the code that actually
627 // allocates any blocks (all it would do would be to hinder using
628 // ArrayAlloc when allocating new blocks).
629 struct Block {
630 Element_type *elements;
631
633 // Use Alloc instead of ArrayAlloc, so that no constructors are called.
634 elements = static_cast<Element_type *>(mem_root->Alloc(
636 sizeof(Element_type))); // NOLINT(bugprone-sizeof-expression)
637 return elements == nullptr;
638 }
639 };
640
641 /// Pointer to the first block. Can be nullptr if there are no elements
642 /// (this makes the constructor cheaper). Stored on the MEM_ROOT,
643 /// and needs no destruction, so just a raw pointer.
644 Block *m_blocks = nullptr;
645
646 /// Physical index to the first valid element.
647 size_t m_begin_idx = 0;
648
649 /// Physical index one past the last valid element. If begin == end,
650 /// the array is empty (and then it doesn't matter what the values are).
651 size_t m_end_idx = 0;
652
653 /// Number of blocks, multiplied by block_elements. (Storing this instead
654 /// of the number of blocks itself makes testing in push_back cheaper.)
655 size_t m_capacity = 0;
656
657 /// Number of Block slots allocated in m_blocks array. This may be larger
658 /// than num_blocks() to allow for exponential growth without reallocating
659 /// on every new block.
660 size_t m_block_slots = 0;
661
662 /// Index in m_blocks where the first initialized block is stored.
663 /// Blocks are stored contiguously from m_first_block_idx to
664 /// m_first_block_idx + num_blocks() - 1. Spare slots before this index
665 /// can be used for push_front without reallocating.
667
668 /// Growth exponent for back expansion. When push_back needs to grow,
669 /// we add 2^m_back_growth_exp spare slots at the back, then increment.
670 /// This gives independent exponential growth: 1, 2, 4, 8, 16...
671 uint8_t m_back_growth_exp = 0;
672
673 /// Growth exponent for front expansion. When push_front needs to grow,
674 /// we add 2^m_front_growth_exp spare slots at the front, then increment.
676
677 /// Pointer to the MEM_ROOT that we store our blocks and elements on.
679
680#ifndef NDEBUG
681 /// Incremented each time we make an operation that would invalidate
682 /// iterators. Asserts use this value in debug mode to be able to
683 /// verify that they have not been invalidated. (In optimized mode,
684 /// using an invalidated iterator incurs undefined behavior.)
685 size_t m_generation = 0;
687#else
688 void invalidate_iterators() {}
689#endif
690
691 /// Adds the first block of elements.
694 if (m_blocks == nullptr) {
695 return true;
696 }
697 if (m_blocks[0].init(m_root)) {
698 return true;
699 }
702 m_block_slots = 1;
703 return false;
704 }
705
706 // Not inlined, to get them off of the hot path.
707 bool add_block_back();
708 bool add_block_front();
709
710 size_t num_blocks() const { return m_capacity / block_elements; }
711
712 /// Gets a reference to the memory used to store an element with the given
713 /// physical index, starting from zero. Note that block_elements is always
714 /// a power of two, so the division and modulus operations are cheap.
715 Element_type &get(size_t physical_idx) const {
716 return m_blocks[m_first_block_idx + physical_idx / block_elements]
717 .elements[physical_idx % block_elements];
718 }
719
720#ifndef NDEBUG
721 size_t generation() const { return m_generation; }
722#endif
723};
724
725template <class Element_type>
727 if (m_blocks == nullptr) {
728 return add_initial_block();
729 }
730
731 // Check if we have spare capacity at the end of the blocks array.
732 // Blocks are stored at m_first_block_idx to m_first_block_idx + num_blocks()
733 // - 1.
734 size_t next_block_idx = m_first_block_idx + num_blocks();
735 if (next_block_idx < m_block_slots) {
736 // We have spare capacity - just initialize the next block.
737 if (m_blocks[next_block_idx].init(m_root)) {
738 return true;
739 }
740 m_capacity += block_elements;
741 return false;
742 }
743
744 // No spare capacity at back - grow with exponential growth.
745 // Add 2^m_back_growth_exp spare slots at the back, then increment exponent.
746 size_t growth = size_t{1} << m_back_growth_exp;
747 size_t new_blocks_allocated = m_block_slots + growth;
748 Block *new_blocks = m_root->ArrayAlloc<Block>(new_blocks_allocated);
749 if (new_blocks == nullptr) {
750 return true;
751 }
752 // Copy existing blocks to the same position (back-only growth).
753 std::copy_n(m_blocks + m_first_block_idx, num_blocks(),
754 new_blocks + m_first_block_idx);
755 // Initialize the new block right after the existing ones.
756 if (new_blocks[next_block_idx].init(m_root)) {
757 return true;
758 }
759
760 m_blocks = new_blocks;
761 m_block_slots = new_blocks_allocated;
762 m_capacity += block_elements;
763 ++m_back_growth_exp;
764 return false;
765}
766
767template <class Element_type>
769 if (m_blocks == nullptr) {
770 if (add_initial_block()) {
771 return true;
772 }
773 if (m_begin_idx == 0) {
774 // Only relevant for very small values of block_elements.
775 m_begin_idx = m_end_idx = 1;
776 }
777 return false;
778 }
779
780 // Check if we have spare capacity at the front of the blocks array.
781 if (m_first_block_idx > 0) {
782 // We have spare capacity - use the slot before the first block.
783 --m_first_block_idx;
784 if (m_blocks[m_first_block_idx].init(m_root)) {
785 ++m_first_block_idx; // Restore on failure.
786 return true;
787 }
788 m_begin_idx += block_elements;
789 m_end_idx += block_elements;
790 m_capacity += block_elements;
791 return false;
792 }
793
794 // No spare capacity at front - grow the blocks array with exponential growth.
795 // Add 2^m_front_growth_exp spare slots at the front, then increment exponent.
796 size_t growth = size_t{1} << m_front_growth_exp;
797 size_t new_blocks_allocated = m_block_slots + growth;
798 Block *new_blocks = m_root->ArrayAlloc<Block>(new_blocks_allocated);
799 if (new_blocks == nullptr) {
800 return true;
801 }
802 // Place existing blocks at the end of the new array (front-only growth).
803 // new_first_block_idx points to where the NEW block will go.
804 // Existing blocks will be at new_first_block_idx + 1 onwards.
805 size_t new_first_block_idx = growth - 1;
806 std::copy_n(m_blocks + m_first_block_idx, num_blocks(),
807 new_blocks + new_first_block_idx + 1);
808 // Initialize the new block at new_first_block_idx.
809 if (new_blocks[new_first_block_idx].init(m_root)) {
810 return true;
811 }
812
813 m_blocks = new_blocks;
814 m_block_slots = new_blocks_allocated;
815 m_first_block_idx = new_first_block_idx;
816 m_begin_idx += block_elements;
817 m_end_idx += block_elements;
818 m_capacity += block_elements;
819 ++m_front_growth_exp;
820 return false;
821}
822
823#endif // MEM_ROOT_DEQUE_H
static mysql_service_status_t init()
Component initialization.
Definition: audit_api_message_emit.cc:566
Definition: mem_root_deque.h:366
Iterator_element_type * operator->() const
Definition: mem_root_deque.h:423
bool operator>(const Iterator &other) const
Definition: mem_root_deque.h:490
Iterator operator+(difference_type offset) const
Definition: mem_root_deque.h:462
bool operator>=(const Iterator &other) const
Definition: mem_root_deque.h:496
bool operator==(const Iterator &other) const
Definition: mem_root_deque.h:414
Iterator operator--(int)
Definition: mem_root_deque.h:442
bool operator<(const Iterator &other) const
Definition: mem_root_deque.h:482
size_t m_generation
Definition: mem_root_deque.h:502
difference_type operator-(const Iterator &other) const
Definition: mem_root_deque.h:472
std::random_access_iterator_tag iterator_category
Definition: mem_root_deque.h:372
Iterator(const mem_root_deque *deque, size_t physical_idx)
Definition: mem_root_deque.h:377
bool operator<=(const Iterator &other) const
Definition: mem_root_deque.h:488
Iterator_element_type * pointer
Definition: mem_root_deque.h:370
Iterator_element_type & operator[](size_t idx) const
Definition: mem_root_deque.h:478
Iterator & operator--()
Definition: mem_root_deque.h:437
Iterator operator-(difference_type offset) const
Definition: mem_root_deque.h:467
void assert_not_invalidated() const
Definition: mem_root_deque.h:505
Iterator & operator++()
Definition: mem_root_deque.h:407
Iterator_element_type & operator*() const
Definition: mem_root_deque.h:403
Iterator & operator-=(difference_type diff)
Definition: mem_root_deque.h:456
Iterator_element_type & reference
Definition: mem_root_deque.h:371
Iterator operator++(int)
Definition: mem_root_deque.h:429
Iterator(const T &other)
For const_iterator: Implicit conversion from iterator.
Definition: mem_root_deque.h:395
Iterator & operator+=(difference_type diff)
Definition: mem_root_deque.h:450
const mem_root_deque * m_deque
Definition: mem_root_deque.h:499
ptrdiff_t difference_type
Definition: mem_root_deque.h:368
Iterator_element_type value_type
Definition: mem_root_deque.h:369
size_t m_physical_idx
Definition: mem_root_deque.h:500
bool operator!=(const Iterator &other) const
Definition: mem_root_deque.h:421
A (partial) implementation of std::deque allocating its blocks on a MEM_ROOT.
Definition: mem_root_deque.h:172
uint8_t m_back_growth_exp
Growth exponent for back expansion.
Definition: mem_root_deque.h:671
Element_type & operator[](size_t idx) const
Definition: mem_root_deque.h:242
reverse_iterator rbegin()
Definition: mem_root_deque.h:519
iterator insert(const_iterator pos, Element_type &&value)
Insert an element at a given position.
Definition: mem_root_deque.h:602
std::reverse_iterator< const_iterator > reverse_const_iterator
Definition: mem_root_deque.h:515
const Element_type * const_pointer
Definition: mem_root_deque.h:180
void invalidate_iterators()
Definition: mem_root_deque.h:686
size_t m_first_block_idx
Index in m_blocks where the first initialized block is stored.
Definition: mem_root_deque.h:666
iterator erase(const_iterator first, const_iterator last)
Erase all the elements in the specified range.
Definition: mem_root_deque.h:549
size_t size() const
Definition: mem_root_deque.h:538
iterator insert(const_iterator pos, ForwardIt first, ForwardIt last)
Definition: mem_root_deque.h:611
uint8_t back_growth_exp() const
Definition: mem_root_deque.h:361
size_t m_block_slots
Number of Block slots allocated in m_blocks array.
Definition: mem_root_deque.h:660
bool push_back(Element_type &&element)
Adds the given element to the end of the deque.
Definition: mem_root_deque.h:267
static constexpr size_t block_elements
Number of elements in each block.
Definition: mem_root_deque.h:623
reverse_const_iterator rbegin() const
Definition: mem_root_deque.h:531
size_t size_type
Used to conform to STL algorithm demands.
Definition: mem_root_deque.h:175
reverse_const_iterator rend() const
Definition: mem_root_deque.h:534
reverse_const_iterator crbegin() const
Definition: mem_root_deque.h:525
Element_type & front()
Returns the first element in the deque.
Definition: mem_root_deque.h:327
bool add_initial_block()
Adds the first block of elements.
Definition: mem_root_deque.h:692
bool add_block_back()
Definition: mem_root_deque.h:726
const_iterator cend()
Definition: mem_root_deque.h:522
size_t capacity() const
Definition: mem_root_deque.h:363
size_t m_begin_idx
Physical index to the first valid element.
Definition: mem_root_deque.h:647
uint8_t front_growth_exp() const
Definition: mem_root_deque.h:362
const Element_type & back() const
Definition: mem_root_deque.h:343
uint8_t m_front_growth_exp
Growth exponent for front expansion.
Definition: mem_root_deque.h:675
mem_root_deque(const mem_root_deque &other)
Definition: mem_root_deque.h:188
size_t m_end_idx
Physical index one past the last valid element.
Definition: mem_root_deque.h:651
Element_type value_type
Definition: mem_root_deque.h:177
bool push_back(const Element_type &element)
Adds the given element to the end of the deque.
Definition: mem_root_deque.h:250
void clear()
Removes all elements from the deque.
Definition: mem_root_deque.h:351
reverse_iterator rend()
Definition: mem_root_deque.h:520
ptrdiff_t difference_type
Definition: mem_root_deque.h:176
std::reverse_iterator< iterator > reverse_iterator
Definition: mem_root_deque.h:514
iterator erase(const_iterator position)
Removes a single element from the array.
Definition: mem_root_deque.h:572
const Element_type & front() const
Definition: mem_root_deque.h:332
const Element_type & const_reference
Definition: mem_root_deque.h:181
Block * m_blocks
Pointer to the first block.
Definition: mem_root_deque.h:644
mem_root_deque & operator=(mem_root_deque &&other)
Definition: mem_root_deque.h:232
size_t first_block_idx() const
Definition: mem_root_deque.h:360
const_iterator end() const
Definition: mem_root_deque.h:524
size_t block_slots() const
Definition: mem_root_deque.h:359
iterator insert(const_iterator pos, const Element_type &value)
Insert an element at a given position.
Definition: mem_root_deque.h:585
bool push_front(const Element_type &element)
Adds the given element to the beginning of the deque.
Definition: mem_root_deque.h:284
mem_root_deque(MEM_ROOT *mem_root)
Constructor. Leaves the array in an empty, valid state.
Definition: mem_root_deque.h:184
mem_root_deque & operator=(const mem_root_deque &other)
Definition: mem_root_deque.h:205
size_t m_capacity
Number of blocks, multiplied by block_elements.
Definition: mem_root_deque.h:655
Element_type & reference
Definition: mem_root_deque.h:179
Element_type & back()
Returns the last element in the deque.
Definition: mem_root_deque.h:338
Element_type * pointer
Definition: mem_root_deque.h:178
reverse_const_iterator crend() const
Definition: mem_root_deque.h:528
Element_type & get(size_t physical_idx) const
Gets a reference to the memory used to store an element with the given physical index,...
Definition: mem_root_deque.h:715
const_iterator begin() const
Definition: mem_root_deque.h:523
~mem_root_deque()
Definition: mem_root_deque.h:240
const_iterator cbegin()
Definition: mem_root_deque.h:521
void pop_front()
Removes the first element from the deque.
Definition: mem_root_deque.h:320
bool empty() const
Definition: mem_root_deque.h:539
bool push_front(Element_type &&element)
Adds the given element to the end of the deque.
Definition: mem_root_deque.h:300
size_t num_blocks() const
Definition: mem_root_deque.h:710
iterator begin()
Definition: mem_root_deque.h:517
size_t generation() const
Definition: mem_root_deque.h:721
MEM_ROOT * m_root
Pointer to the MEM_ROOT that we store our blocks and elements on.
Definition: mem_root_deque.h:678
void pop_back()
Removes the last element from the deque.
Definition: mem_root_deque.h:313
bool add_block_front()
Definition: mem_root_deque.h:768
iterator end()
Definition: mem_root_deque.h:518
size_t m_generation
Incremented each time we make an operation that would invalidate iterators.
Definition: mem_root_deque.h:685
mem_root_deque(mem_root_deque &&other)
Definition: mem_root_deque.h:216
static MEM_ROOT mem_root
Definition: client_plugin.cc:114
static Bigint * diff(Bigint *a, Bigint *b, Stack_alloc *alloc)
Definition: dtoa.cc:1081
#define T
Definition: jit_executor_value.cc:373
static constexpr size_t FindElementsPerBlock()
Definition: mem_root_deque.h:38
This file follows Google coding style, except for the name MEM_ROOT (which is kept for historical rea...
void destroy_at(T *ptr)
Definition: my_alloc.h:462
uint16_t value_type
Definition: vt100.h:184
ValueType value(const std::optional< ValueType > &v)
Definition: gtid.h:83
The MEM_ROOT is a simple arena, where allocations are carved out of larger blocks.
Definition: my_alloc.h:83
T * ArrayAlloc(size_t num, Args... args)
Allocate 'num' objects of type T, and initialize them to a default value that is created by passing t...
Definition: my_alloc.h:180
void * Alloc(size_t length)
Allocate memory.
Definition: my_alloc.h:145
Definition: mem_root_deque.h:629
Element_type * elements
Definition: mem_root_deque.h:630
bool init(MEM_ROOT *mem_root)
Definition: mem_root_deque.h:632