MySQL 9.1.0
Source Code Documentation
mem_root_deque.h
Go to the documentation of this file.
1/* Copyright (c) 2019, 2024, 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] Actually, it's O(n), since there's no exponential growth of the blocks
107 array. But the blocks are reallocated very rarely, so it is generally
108 efficient nevertheless.
109 */
110template <class Element_type>
112 public:
113 /// Used to conform to STL algorithm demands.
114 using size_type = size_t;
115 using difference_type = ptrdiff_t;
116 using value_type = Element_type;
117 using pointer = Element_type *;
118 using reference = Element_type &;
119 using const_pointer = const Element_type *;
120 using const_reference = const Element_type &;
121
122 /// Constructor. Leaves the array in an empty, valid state.
124
125 // Copy constructor and assignment. We could probably be a bit smarter
126 // about these for large arrays, if the source array has e.g. empty blocks.
128 : m_begin_idx(other.m_begin_idx),
129 m_end_idx(other.m_end_idx),
130 m_capacity(other.m_capacity),
131 m_root(other.m_root) {
133 for (size_t block_idx = 0; block_idx < num_blocks(); ++block_idx) {
134 m_blocks[block_idx].init(m_root);
135 }
136 for (size_t idx = m_begin_idx; idx != m_end_idx; ++idx) {
137 new (&get(idx)) Element_type(other.get(idx));
138 }
139 }
141 if (this != &other) {
142 clear();
143 for (const Element_type &elem : other) {
144 push_back(elem);
145 }
146 }
147 return *this;
148 }
149
150 // Move constructor and assignment.
152 : m_blocks(other.m_blocks),
154 m_end_idx(other.m_end_idx),
155 m_root(other.m_root) {
156 other.m_blocks = nullptr;
157 other.m_begin_idx = other.m_end_idx = other.m_capacity = 0;
158 other.invalidate_iterators();
159 }
161 if (this != &other) {
162 this->~mem_root_deque();
163 new (this) mem_root_deque(std::move(other));
164 }
165 return *this;
166 }
167
169
170 Element_type &operator[](size_t idx) const { return get(idx + m_begin_idx); }
171
172 /**
173 Adds the given element to the end of the deque.
174 The element is a copy of the given one.
175
176 @returns true on OOM (no change is done if so)
177 */
178 bool push_back(const Element_type &element) {
179 if (m_end_idx == m_capacity) {
180 if (add_block_back()) {
181 return true;
182 }
183 }
184 new (&get(m_end_idx++)) Element_type(element);
186 return false;
187 }
188
189 /**
190 Adds the given element to the end of the deque.
191 The element is moved into place.
192
193 @returns true on OOM (no change is done if so)
194 */
195 bool push_back(Element_type &&element) {
196 if (m_end_idx == m_capacity) {
197 if (add_block_back()) {
198 return true;
199 }
200 }
201 new (&get(m_end_idx++)) Element_type(std::move(element));
203 return false;
204 }
205
206 /**
207 Adds the given element to the beginning of the deque.
208 The element is a copy of the given one.
209
210 @returns true on OOM (no change is done if so)
211 */
212 bool push_front(const Element_type &element) {
213 if (m_begin_idx == 0) {
214 if (add_block_front()) {
215 return true;
216 }
217 assert(m_begin_idx != 0);
218 }
219 new (&get(--m_begin_idx)) Element_type(element);
221 return false;
222 }
223
224 /**
225 Adds the given element to the end of the deque.
226 The element is moved into place.
227 */
228 bool push_front(Element_type &&element) {
229 if (m_begin_idx == 0) {
230 if (add_block_front()) {
231 return true;
232 }
233 assert(m_begin_idx != 0);
234 }
235 new (&get(--m_begin_idx)) Element_type(std::move(element));
237 return false;
238 }
239
240 /// Removes the last element from the deque.
241 void pop_back() {
242 assert(!empty());
245 }
246
247 /// Removes the first element from the deque.
248 void pop_front() {
249 assert(!empty());
252 }
253
254 /// Returns the first element in the deque.
255 Element_type &front() {
256 assert(!empty());
257 return get(m_begin_idx);
258 }
259
260 const Element_type &front() const {
261 assert(!empty());
262 return get(m_begin_idx);
263 }
264
265 /// Returns the last element in the deque.
266 Element_type &back() {
267 assert(!empty());
268 return get(m_end_idx - 1);
269 }
270
271 const Element_type &back() const {
272 assert(!empty());
273 return get(m_end_idx - 1);
274 }
275
276 /// Removes all elements from the deque. Destructors are called,
277 /// but since the elements themselves are allocated on the MEM_ROOT,
278 /// their memory cannot be freed.
279 void clear() {
280 for (size_t idx = m_begin_idx; idx != m_end_idx; ++idx) {
281 ::destroy_at(&get(idx));
282 }
285 }
286
287 template <class Iterator_element_type>
288 class Iterator {
289 public:
290 using difference_type = ptrdiff_t;
291 using value_type = Iterator_element_type;
292 using pointer = Iterator_element_type *;
293 using reference = Iterator_element_type &;
294 using iterator_category = std::random_access_iterator_tag;
295
296 // DefaultConstructible (required for ForwardIterator).
297 Iterator() = default;
298
299 Iterator(const mem_root_deque *deque, size_t physical_idx)
300 : m_deque(deque), m_physical_idx(physical_idx) {
301#ifndef NDEBUG
303#endif
304 }
305
306 /// For const_iterator: Implicit conversion from iterator.
307 /// This is written in a somewhat cumbersome fashion to avoid
308 /// declaring an explicit copy constructor for iterator,
309 /// which causes compiler warnings other places for some compilers.
310 // NOLINTNEXTLINE(google-explicit-constructor): Intentional.
311 template <
312 class T,
313 typename = std::enable_if_t<
314 std::is_const<Iterator_element_type>::value &&
315 std::is_same<typename T::value_type,
316 std::remove_const_t<Iterator_element_type>>::value>>
317 Iterator(const T &other)
319#ifndef NDEBUG
320 m_generation = other.m_generation;
321#endif
322 }
323
324 // Iterator (required for InputIterator).
325 Iterator_element_type &operator*() const {
327 return m_deque->get(m_physical_idx);
328 }
332 return *this;
333 }
334
335 // EqualityComparable (required for InputIterator).
336 bool operator==(const Iterator &other) const {
338 assert(m_deque == other.m_deque);
339 return m_physical_idx == other.m_physical_idx;
340 }
341
342 // InputIterator (required for ForwardIterator).
343 bool operator!=(const Iterator &other) const { return !(*this == other); }
344
345 Iterator_element_type *operator->() const {
347 return &m_deque->get(m_physical_idx);
348 }
349
350 // ForwardIterator (required for RandomAccessIterator).
353 Iterator ret = *this;
355 return ret;
356 }
357
358 // BidirectionalIterator (required for RandomAccessIterator).
362 return *this;
363 }
366 Iterator ret = *this;
368 return ret;
369 }
370
371 // RandomAccessIterator.
375 return *this;
376 }
377
381 return *this;
382 }
383
386 return Iterator{m_deque, m_physical_idx + offset};
387 }
388
391 return Iterator{m_deque, m_physical_idx - offset};
392 }
393
394 difference_type operator-(const Iterator &other) const {
396 assert(m_deque == other.m_deque);
397 return m_physical_idx - other.m_physical_idx;
398 }
399
400 Iterator_element_type &operator[](size_t idx) const {
401 return *(*this + idx);
402 }
403
404 bool operator<(const Iterator &other) const {
406 assert(m_deque == other.m_deque);
407 return m_physical_idx < other.m_physical_idx;
408 }
409
410 bool operator<=(const Iterator &other) const { return !(*this > other); }
411
412 bool operator>(const Iterator &other) const {
414 assert(m_deque == other.m_deque);
415 return m_physical_idx > other.m_physical_idx;
416 }
417
418 bool operator>=(const Iterator &other) const { return !(*this < other); }
419
420 private:
421 const mem_root_deque *m_deque = nullptr;
422 size_t m_physical_idx = 0;
423#ifndef NDEBUG
424 size_t m_generation = 0;
425#endif
426
428 assert(m_generation == m_deque->generation());
429 }
430
431 friend class mem_root_deque;
432 };
433
436 using reverse_iterator = std::reverse_iterator<iterator>;
437 using reverse_const_iterator = std::reverse_iterator<const_iterator>;
438
439 iterator begin() { return iterator{this, m_begin_idx}; }
440 iterator end() { return iterator{this, m_end_idx}; }
441 reverse_iterator rbegin() { return std::make_reverse_iterator(end()); }
442 reverse_iterator rend() { return std::make_reverse_iterator(begin()); }
446 const_iterator end() const { return const_iterator{this, m_end_idx}; }
448 return std::make_reverse_iterator(end());
449 }
451 return std::make_reverse_iterator(begin());
452 }
454 return std::make_reverse_iterator(end());
455 }
457 return std::make_reverse_iterator(begin());
458 }
459
460 size_t size() const { return m_end_idx - m_begin_idx; }
461 bool empty() const { return size() == 0; }
462
463 /**
464 Erase all the elements in the specified range.
465
466 @param first iterator that points to the first element to remove
467 @param last iterator that points to the element after the
468 last one to remove
469 @return an iterator to the first element after the removed range
470 */
472 iterator pos = begin() + (first - cbegin());
473 if (first != last) {
474 iterator new_end = std::move(last, cend(), pos);
475 for (size_t idx = new_end.m_physical_idx; idx != m_end_idx; ++idx) {
476 ::destroy_at(&get(idx));
477 }
478 m_end_idx = new_end.m_physical_idx;
479 }
481#ifndef NDEBUG
482 pos.m_generation = m_generation; // Re-validate.
483#endif
484 return pos;
485 }
486
487 /**
488 Removes a single element from the array.
489
490 @param position iterator that points to the element to remove
491
492 @return an iterator to the first element after the removed range
493 */
495 return erase(position, std::next(position));
496 }
497
498 /**
499 Insert an element at a given position.
500 The element is a copy of the given one.
501
502 @param pos the new element is inserted before the element
503 at this position
504 @param value the value of the new element
505 @return an iterator that points to the inserted element
506 */
507 iterator insert(const_iterator pos, const Element_type &value) {
508 difference_type idx = pos - cbegin();
509 push_back(value);
510 std::rotate(begin() + idx, end() - 1, end());
512 return begin() + idx;
513 }
514
515 /**
516 Insert an element at a given position.
517 The element is moved into place.
518
519 @param pos the new element is inserted before the element
520 at this position
521 @param value the value of the new element
522 @return an iterator that points to the inserted element
523 */
524 iterator insert(const_iterator pos, Element_type &&value) {
525 difference_type idx = pos - cbegin();
526 push_back(std::move(value));
527 std::rotate(begin() + idx, end() - 1, end());
529 return begin() + idx;
530 }
531
532 template <class ForwardIt>
533 iterator insert(const_iterator pos, ForwardIt first, ForwardIt last) {
534 difference_type idx = pos - cbegin();
535 for (ForwardIt it = first; it != last; ++it) {
536 push_back(*it);
537 }
538 std::rotate(begin() + idx, end() - (last - first), end());
540 return begin() + idx;
541 }
542
543 private:
544 /// Number of elements in each block.
545 static constexpr size_t block_elements = FindElementsPerBlock<Element_type>();
546
547 // A block capable of storing <block_elements> elements. Deliberately
548 // has no constructor, since it wouldn't help any of the code that actually
549 // allocates any blocks (all it would do would be to hinder using
550 // ArrayAlloc when allocating new blocks).
551 struct Block {
552 Element_type *elements;
553
555 // Use Alloc instead of ArrayAlloc, so that no constructors are called.
556 elements = static_cast<Element_type *>(mem_root->Alloc(
558 sizeof(Element_type))); // NOLINT(bugprone-sizeof-expression)
559 return elements == nullptr;
560 }
561 };
562
563 /// Pointer to the first block. Can be nullptr if there are no elements
564 /// (this makes the constructor cheaper). Stored on the MEM_ROOT,
565 /// and needs no destruction, so just a raw pointer.
566 Block *m_blocks = nullptr;
567
568 /// Physical index to the first valid element.
569 size_t m_begin_idx = 0;
570
571 /// Physical index one past the last valid element. If begin == end,
572 /// the array is empty (and then it doesn't matter what the values are).
573 size_t m_end_idx = 0;
574
575 /// Number of blocks, multiplied by block_elements. (Storing this instead
576 /// of the number of blocks itself makes testing in push_back cheaper.)
577 size_t m_capacity = 0;
578
579 /// Pointer to the MEM_ROOT that we store our blocks and elements on.
581
582#ifndef NDEBUG
583 /// Incremented each time we make an operation that would invalidate
584 /// iterators. Asserts use this value in debug mode to be able to
585 /// verify that they have not been invalidated. (In optimized mode,
586 /// using an invalidated iterator incurs undefined behavior.)
587 size_t m_generation = 0;
589#else
590 void invalidate_iterators() {}
591#endif
592
593 /// Adds the first block of elements.
596 if (m_blocks == nullptr) {
597 return true;
598 }
599 if (m_blocks[0].init(m_root)) {
600 return true;
601 }
604 return false;
605 }
606
607 // Not inlined, to get them off of the hot path.
608 bool add_block_back();
609 bool add_block_front();
610
611 size_t num_blocks() const { return m_capacity / block_elements; }
612
613 /// Gets a reference to the memory used to store an element with the given
614 /// physical index, starting from zero. Note that block_elements is always
615 /// a power of two, so the division and modulus operations are cheap.
616 Element_type &get(size_t physical_idx) const {
617 return m_blocks[physical_idx / block_elements]
618 .elements[physical_idx % block_elements];
619 }
620
621#ifndef NDEBUG
622 size_t generation() const { return m_generation; }
623#endif
624};
625
626// TODO(sgunders): Consider storing spare blocks at either end to have
627// exponential growth and get true O(1) allocation.
628
629template <class Element_type>
631 if (m_blocks == nullptr) {
632 return add_initial_block();
633 }
634 Block *new_blocks = m_root->ArrayAlloc<Block>(num_blocks() + 1);
635 if (new_blocks == nullptr) {
636 return true;
637 }
638 memcpy(new_blocks, m_blocks, sizeof(Block) * num_blocks());
639 if (new_blocks[num_blocks()].init(m_root)) {
640 return true;
641 }
642
643 m_blocks = new_blocks;
644 m_capacity += block_elements;
645 return false;
646}
647
648template <class Element_type>
650 if (m_blocks == nullptr) {
651 if (add_initial_block()) {
652 return true;
653 }
654 if (m_begin_idx == 0) {
655 // Only relevant for very small values of block_elements.
656 m_begin_idx = m_end_idx = 1;
657 }
658 return false;
659 }
660 Block *new_blocks = m_root->ArrayAlloc<Block>(num_blocks() + 1);
661 memcpy(new_blocks + 1, m_blocks, sizeof(Block) * num_blocks());
662 if (new_blocks[0].init(m_root)) {
663 return true;
664 }
665
666 m_blocks = new_blocks;
667 m_begin_idx += block_elements;
668 m_end_idx += block_elements;
669 m_capacity += block_elements;
670 return false;
671}
672
673#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:288
Iterator_element_type * operator->() const
Definition: mem_root_deque.h:345
bool operator>(const Iterator &other) const
Definition: mem_root_deque.h:412
Iterator operator+(difference_type offset) const
Definition: mem_root_deque.h:384
bool operator>=(const Iterator &other) const
Definition: mem_root_deque.h:418
bool operator==(const Iterator &other) const
Definition: mem_root_deque.h:336
Iterator operator--(int)
Definition: mem_root_deque.h:364
bool operator<(const Iterator &other) const
Definition: mem_root_deque.h:404
size_t m_generation
Definition: mem_root_deque.h:424
difference_type operator-(const Iterator &other) const
Definition: mem_root_deque.h:394
std::random_access_iterator_tag iterator_category
Definition: mem_root_deque.h:294
Iterator(const mem_root_deque *deque, size_t physical_idx)
Definition: mem_root_deque.h:299
bool operator<=(const Iterator &other) const
Definition: mem_root_deque.h:410
Iterator_element_type * pointer
Definition: mem_root_deque.h:292
Iterator_element_type & operator[](size_t idx) const
Definition: mem_root_deque.h:400
Iterator & operator--()
Definition: mem_root_deque.h:359
Iterator operator-(difference_type offset) const
Definition: mem_root_deque.h:389
void assert_not_invalidated() const
Definition: mem_root_deque.h:427
Iterator & operator++()
Definition: mem_root_deque.h:329
Iterator_element_type & operator*() const
Definition: mem_root_deque.h:325
Iterator & operator-=(difference_type diff)
Definition: mem_root_deque.h:378
Iterator_element_type & reference
Definition: mem_root_deque.h:293
Iterator operator++(int)
Definition: mem_root_deque.h:351
Iterator(const T &other)
For const_iterator: Implicit conversion from iterator.
Definition: mem_root_deque.h:317
Iterator & operator+=(difference_type diff)
Definition: mem_root_deque.h:372
const mem_root_deque * m_deque
Definition: mem_root_deque.h:421
ptrdiff_t difference_type
Definition: mem_root_deque.h:290
Iterator_element_type value_type
Definition: mem_root_deque.h:291
size_t m_physical_idx
Definition: mem_root_deque.h:422
bool operator!=(const Iterator &other) const
Definition: mem_root_deque.h:343
A (partial) implementation of std::deque allocating its blocks on a MEM_ROOT.
Definition: mem_root_deque.h:111
Element_type & operator[](size_t idx) const
Definition: mem_root_deque.h:170
reverse_iterator rbegin()
Definition: mem_root_deque.h:441
iterator insert(const_iterator pos, Element_type &&value)
Insert an element at a given position.
Definition: mem_root_deque.h:524
std::reverse_iterator< const_iterator > reverse_const_iterator
Definition: mem_root_deque.h:437
const Element_type * const_pointer
Definition: mem_root_deque.h:119
void invalidate_iterators()
Definition: mem_root_deque.h:588
iterator erase(const_iterator first, const_iterator last)
Erase all the elements in the specified range.
Definition: mem_root_deque.h:471
size_t size() const
Definition: mem_root_deque.h:460
iterator insert(const_iterator pos, ForwardIt first, ForwardIt last)
Definition: mem_root_deque.h:533
bool push_back(Element_type &&element)
Adds the given element to the end of the deque.
Definition: mem_root_deque.h:195
static constexpr size_t block_elements
Number of elements in each block.
Definition: mem_root_deque.h:545
reverse_const_iterator rbegin() const
Definition: mem_root_deque.h:453
size_t size_type
Used to conform to STL algorithm demands.
Definition: mem_root_deque.h:114
reverse_const_iterator rend() const
Definition: mem_root_deque.h:456
reverse_const_iterator crbegin() const
Definition: mem_root_deque.h:447
Element_type & front()
Returns the first element in the deque.
Definition: mem_root_deque.h:255
bool add_initial_block()
Adds the first block of elements.
Definition: mem_root_deque.h:594
bool add_block_back()
Definition: mem_root_deque.h:630
const_iterator cend()
Definition: mem_root_deque.h:444
size_t m_begin_idx
Physical index to the first valid element.
Definition: mem_root_deque.h:569
const Element_type & back() const
Definition: mem_root_deque.h:271
mem_root_deque(const mem_root_deque &other)
Definition: mem_root_deque.h:127
size_t m_end_idx
Physical index one past the last valid element.
Definition: mem_root_deque.h:573
Element_type value_type
Definition: mem_root_deque.h:116
bool push_back(const Element_type &element)
Adds the given element to the end of the deque.
Definition: mem_root_deque.h:178
void clear()
Removes all elements from the deque.
Definition: mem_root_deque.h:279
reverse_iterator rend()
Definition: mem_root_deque.h:442
ptrdiff_t difference_type
Definition: mem_root_deque.h:115
std::reverse_iterator< iterator > reverse_iterator
Definition: mem_root_deque.h:436
iterator erase(const_iterator position)
Removes a single element from the array.
Definition: mem_root_deque.h:494
const Element_type & front() const
Definition: mem_root_deque.h:260
const Element_type & const_reference
Definition: mem_root_deque.h:120
Block * m_blocks
Pointer to the first block.
Definition: mem_root_deque.h:566
mem_root_deque & operator=(mem_root_deque &&other)
Definition: mem_root_deque.h:160
const_iterator end() const
Definition: mem_root_deque.h:446
iterator insert(const_iterator pos, const Element_type &value)
Insert an element at a given position.
Definition: mem_root_deque.h:507
bool push_front(const Element_type &element)
Adds the given element to the beginning of the deque.
Definition: mem_root_deque.h:212
mem_root_deque(MEM_ROOT *mem_root)
Constructor. Leaves the array in an empty, valid state.
Definition: mem_root_deque.h:123
mem_root_deque & operator=(const mem_root_deque &other)
Definition: mem_root_deque.h:140
size_t m_capacity
Number of blocks, multiplied by block_elements.
Definition: mem_root_deque.h:577
Element_type & reference
Definition: mem_root_deque.h:118
Element_type & back()
Returns the last element in the deque.
Definition: mem_root_deque.h:266
Element_type * pointer
Definition: mem_root_deque.h:117
reverse_const_iterator crend() const
Definition: mem_root_deque.h:450
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:616
const_iterator begin() const
Definition: mem_root_deque.h:445
~mem_root_deque()
Definition: mem_root_deque.h:168
const_iterator cbegin()
Definition: mem_root_deque.h:443
void pop_front()
Removes the first element from the deque.
Definition: mem_root_deque.h:248
bool empty() const
Definition: mem_root_deque.h:461
bool push_front(Element_type &&element)
Adds the given element to the end of the deque.
Definition: mem_root_deque.h:228
size_t num_blocks() const
Definition: mem_root_deque.h:611
iterator begin()
Definition: mem_root_deque.h:439
size_t generation() const
Definition: mem_root_deque.h:622
MEM_ROOT * m_root
Pointer to the MEM_ROOT that we store our blocks and elements on.
Definition: mem_root_deque.h:580
void pop_back()
Removes the last element from the deque.
Definition: mem_root_deque.h:241
bool add_block_front()
Definition: mem_root_deque.h:649
iterator end()
Definition: mem_root_deque.h:440
size_t m_generation
Incremented each time we make an operation that would invalidate iterators.
Definition: mem_root_deque.h:587
mem_root_deque(mem_root_deque &&other)
Definition: mem_root_deque.h:151
static MEM_ROOT mem_root
Definition: client_plugin.cc:114
static Bigint * diff(Bigint *a, Bigint *b, Stack_alloc *alloc)
Definition: dtoa.cc:1081
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
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:551
Element_type * elements
Definition: mem_root_deque.h:552
bool init(MEM_ROOT *mem_root)
Definition: mem_root_deque.h:554