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