MySQL 9.2.0
Source Code Documentation
mem_root_array.h
Go to the documentation of this file.
1/* Copyright (c) 2011, 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_ARRAY_INCLUDED
25#define MEM_ROOT_ARRAY_INCLUDED
26
27#include <assert.h>
28#include <algorithm>
29#include <memory>
30#include <type_traits>
31#include <utility>
32
33#include "my_alloc.h"
34
35#include "sql/thr_malloc.h"
36
37/**
38 A typesafe replacement for DYNAMIC_ARRAY.
39 We use MEM_ROOT for allocating storage, rather than the C++ heap.
40 The interface is chosen to be similar to std::vector.
41
42 @remark
43 Mem_root_array_YY is constructor-less for use in the parser stack of unions.
44 For other needs please use Mem_root_array.
45
46 @remark
47 Unlike DYNAMIC_ARRAY, elements are properly copied
48 (rather than memcpy()d) if the underlying array needs to be expanded.
49
50 @remark
51 Unless Element_type's destructor is trivial, we destroy objects when they are
52 removed from the array (including when the array object itself is destroyed).
53
54 @remark
55 Note that MEM_ROOT has no facility for reusing free space,
56 so don't use this if multiple re-expansions are likely to happen.
57
58 @tparam Element_type The type of the elements of the container.
59 Elements must be copyable.
60*/
61template <typename Element_type>
63 /**
64 Is Element_type trivially destructible? If it is, we don't destroy
65 elements when they are removed from the array or when the array is
66 destroyed.
67 */
68 static constexpr bool has_trivial_destructor =
69 std::is_trivially_destructible<Element_type>::value;
70
71 public:
72 /// Convenience typedef, same typedef name as std::vector
73 typedef Element_type value_type;
74
75 void init(MEM_ROOT *root) {
76 assert(root != nullptr);
77
78 m_root = root;
79 m_array = nullptr;
80 m_size = 0;
81 m_capacity = 0;
82 }
83
84 /// Initialize empty array that we aren't going to grow
86 m_root = nullptr;
87 m_array = nullptr;
88 m_size = 0;
89 m_capacity = 0;
90 }
91
92 Element_type *data() { return m_array; }
93 const Element_type *data() const { return m_array; }
94
95 Element_type &at(size_t n) {
96 assert(n < size());
97 return m_array[n];
98 }
99
100 const Element_type &at(size_t n) const {
101 assert(n < size());
102 return m_array[n];
103 }
104
105 Element_type &operator[](size_t n) { return at(n); }
106 const Element_type &operator[](size_t n) const { return at(n); }
107
108 Element_type &back() { return at(size() - 1); }
109 const Element_type &back() const { return at(size() - 1); }
110
111 /// Random access iterators to value_type and const value_type.
112 typedef Element_type *iterator;
113 typedef const Element_type *const_iterator;
114
115 /// Returns a pointer to the first element in the array.
116 Element_type *begin() { return &m_array[0]; }
117 const Element_type *begin() const { return &m_array[0]; }
118
119 /// Returns a pointer to the past-the-end element in the array.
120 Element_type *end() { return &m_array[size()]; }
121 const Element_type *end() const { return &m_array[size()]; }
122
123 /// Returns a constant pointer to the first element in the array.
124 const_iterator cbegin() const { return begin(); }
125
126 /// Returns a constant pointer to the past-the-end element in the array.
127 const_iterator cend() const { return end(); }
128
129 /// Erases all of the elements.
130 void clear() {
131 if (!empty()) chop(0);
132 }
133
134 /**
135 Chops the tail off the array, erasing all tail elements.
136 @param pos Index of first element to erase.
137 */
138 void chop(const size_t pos) {
139 assert(pos < m_size);
141 for (size_t ix = pos; ix < m_size; ++ix) {
142 Element_type *p = &m_array[ix];
143 p->~Element_type(); // Destroy discarded element.
144 }
145 }
146 m_size = pos;
147 }
148
149 /**
150 Reserves space for array elements.
151 Copies over existing elements, in case we are re-expanding the array.
152
153 @param n number of elements.
154 @retval true if out-of-memory, false otherwise.
155 */
156 bool reserve(size_t n) {
157 if (n <= m_capacity) return false;
158
159 void *mem = m_root->Alloc(n * element_size());
160 if (!mem) return true;
161 Element_type *array = static_cast<Element_type *>(mem);
162
163 // Copy all the existing elements into the new array.
164 for (size_t ix = 0; ix < m_size; ++ix) {
165 Element_type *new_p = &array[ix];
166 Element_type *old_p = &m_array[ix];
167 ::new (new_p)
168 Element_type(std::move(*old_p)); // Copy or move into new location.
170 old_p->~Element_type(); // Destroy the old element.
171 }
172
173 // Forget the old array.
174 m_array = array;
175 m_capacity = n;
176 return false;
177 }
178
179 /**
180 Adds a new element at the end of the array, after its current last
181 element. The content of this new element is initialized to a copy of
182 the input argument.
183
184 @param element Object to copy.
185 @retval true if out-of-memory, false otherwise.
186 */
187 bool push_back(const Element_type &element) { return emplace_back(element); }
188
189 /**
190 Adds a new element at the end of the array, after its current last
191 element. The content of this new element is initialized by moving
192 the input element.
193
194 @param element Object to move.
195 @retval true if out-of-memory, false otherwise.
196 */
197 bool push_back(Element_type &&element) {
198 return emplace_back(std::move(element));
199 }
200
201 /**
202 Constructs an element at the back of the array in-place.
203
204 @param args Arguments to pass to the constructor.
205 @return true if out-of-memory, false otherwise.
206 */
207 template <typename... Args>
208 bool emplace_back(Args &&...args) {
209 constexpr size_t min_capacity = 20;
210 constexpr size_t expansion_factor = 2;
211 if (m_size == m_capacity) {
212 if (reserve(std::max(min_capacity, m_capacity * expansion_factor))) {
213 return true;
214 }
215 }
216 Element_type *p = &m_array[m_size++];
217 ::new (p) Element_type(std::forward<Args>(args)...);
218 return false;
219 }
220
221 /**
222 Adds a new element at the beginning of the array.
223 The content of this new element is initialized to a copy of
224 the input argument.
225
226 @param element Object to copy.
227 @retval true if out-of-memory, false otherwise.
228 */
229 bool push_front(const Element_type &element) {
230 if (push_back(element)) return true;
231 std::rotate(begin(), end() - 1, end());
232 return false;
233 }
234
235 /**
236 Adds a new element at the front of the array.
237 The content of this new element is initialized by moving the input element.
238
239 @param element Object to move.
240 @retval true if out-of-memory, false otherwise.
241 */
242 bool push_front(Element_type &&element) {
243 if (push_back(std::move(element))) return true;
244 std::rotate(begin(), end() - 1, end());
245 return false;
246 }
247
248 /**
249 Removes the last element in the array, effectively reducing the
250 container size by one. This destroys the removed element.
251 */
252 void pop_back() {
253 assert(!empty());
254 if (!has_trivial_destructor) back().~Element_type();
255 m_size -= 1;
256 }
257
258 /**
259 Resizes the container so that it contains n elements.
260
261 If n is smaller than the current container size, the content is
262 reduced to its first n elements, removing those beyond (and
263 destroying them).
264
265 If n is greater than the current container size, the content is
266 expanded by inserting at the end as many elements as needed to
267 reach a size of n. If val is specified, the new elements are
268 initialized as copies of val, otherwise, they are
269 value-initialized.
270
271 If n is also greater than the current container capacity, an automatic
272 reallocation of the allocated storage space takes place.
273
274 Notice that this function changes the actual content of the
275 container by inserting or erasing elements from it.
276
277 @param n The new size of the container.
278 @param val The value to copy into new elements.
279 @return True if out of memory, false otherwise.
280 */
281 [[nodiscard]] bool resize(size_t n, const value_type &val) {
282 if (n > m_size) {
283 if (reserve(n)) {
284 return true;
285 }
286 std::uninitialized_fill(m_array + m_size, m_array + n, val);
287 m_size = n;
288 } else if (n < m_size) {
289 chop(n);
290 }
291 return false;
292 }
293
294 /**
295 Same as resize(size_t, const value_type &val), but value-initializes
296 the new elements. This allows one to resize containers even if
297 value_type is not copy-constructible.
298
299 @param n The new size of the container.
300 @return True if out of memory, false otherwise.
301 */
302 [[nodiscard]] bool resize(size_t n) {
303 if (n > m_size) {
304 if (reserve(n)) {
305 return true;
306 }
307 std::uninitialized_value_construct(m_array + m_size, m_array + n);
308 m_size = n;
309 } else if (n < m_size) {
310 chop(n);
311 }
312 return false;
313 }
314
315 /**
316 Erase all the elements in the specified range.
317
318 @param first iterator that points to the first element to remove
319 @param last iterator that points to the element after the
320 last one to remove
321 @return an iterator to the first element after the removed range
322 */
324 iterator pos = begin() + (first - cbegin());
325 if (first != last) {
326 iterator new_end = std::move(last, cend(), pos);
327 chop(new_end - begin());
328 }
329 return pos;
330 }
331
332 /**
333 Removes a single element from the array.
334
335 @param position iterator that points to the element to remove
336
337 @return an iterator to the first element after the removed range
338 */
340 return erase(position, std::next(position));
341 }
342
343 /**
344 Removes a single element from the array.
345
346 @param ix zero-based number of the element to remove
347
348 @return an iterator to the first element after the removed range
349 */
350 iterator erase(size_t ix) {
351 assert(ix < size());
352 return erase(std::next(this->cbegin(), ix));
353 }
354
355 /**
356 Insert an element at a given position.
357
358 @param pos the new element is inserted before the element
359 at this position
360 @param value the value of the new element
361 @return an iterator that points to the inserted element
362 */
363 iterator insert(const_iterator pos, const Element_type &value) {
364 ptrdiff_t idx = pos - cbegin();
365 if (!push_back(value)) std::rotate(begin() + idx, end() - 1, end());
366 return begin() + idx;
367 }
368
369 /**
370 Removes a single element from the array by value.
371 The removed element is destroyed. This effectively reduces the
372 container size by one.
373 Note that if there are multiple elements having the same
374 value, only the first element is removed.
375
376 This is generally an inefficient operation, since we need to copy
377 elements to fill the "hole" in the array.
378
379 We use std::copy to move objects, hence Element_type must be
380 assignable.
381
382 @retval number of elements removed, 0 or 1.
383 */
384 size_t erase_value(const value_type &val) {
385 iterator position = std::find(begin(), end(), val);
386 if (position != end()) {
387 erase(position);
388 return 1;
389 }
390 return 0; // Not found
391 }
392
393 /**
394 Removes a single element from the array.
395 The removed element is destroyed.
396 This effectively reduces the container size by one.
397
398 This is generally an inefficient operation, since we need to copy
399 elements to fill the "hole" in the array.
400
401 We use std::copy to move objects, hence Element_type must be assignable.
402 */
404 assert(position != end());
405 if (position + 1 != end()) std::copy(position + 1, end(), position);
406 this->pop_back();
407 return position;
408 }
409
410 size_t capacity() const { return m_capacity; }
411 size_t element_size() const { return sizeof(Element_type); }
412 bool empty() const { return size() == 0; }
413 size_t size() const { return m_size; }
414
415 protected:
417 Element_type *m_array;
418 size_t m_size;
420
421 // No CTOR/DTOR for this class!
422 // Mem_root_array_YY(const Mem_root_array_YY&);
423 // Mem_root_array_YY &operator=(const Mem_root_array_YY&);
424};
425
426/**
427 A typesafe replacement for DYNAMIC_ARRAY.
428
429 @see Mem_root_array_YY.
430*/
431template <typename Element_type>
432class Mem_root_array : public Mem_root_array_YY<Element_type> {
434
435 public:
436 /// Convenience typedef, same typedef name as std::vector
437 typedef Element_type value_type;
438
440
442
443 explicit Mem_root_array(MEM_ROOT *root) { super::init(root); }
444
445 /// Move constructor and assignment.
447 this->m_root = other.m_root;
448 this->m_array = other.m_array;
449 this->m_size = other.m_size;
450 this->m_capacity = other.m_capacity;
451 other.init_empty_const();
452 other.m_root = this->m_root;
453 }
455 if (this != &other) {
456 this->~Mem_root_array();
457 new (this) Mem_root_array(std::move(other));
458 }
459 return *this;
460 }
461
462 Mem_root_array(MEM_ROOT *root, size_t n) {
463 super::init(root);
464 (void)super::resize(n);
465 }
466
467 Mem_root_array(MEM_ROOT *root, size_t n, const value_type &val) {
468 super::init(root);
469 (void)super::resize(n, val);
470 }
471
472 /**
473 Range constructor.
474
475 Constructs a container with as many elements as the range [first,last),
476 with each element constructed from its corresponding element in that range,
477 in the same order.
478
479 @param root MEM_ROOT to use for memory allocation.
480 @param first iterator that points to the first element to copy
481 @param last iterator that points to the element after the
482 last one to copy
483 */
485 super::init(root);
486 if (this->reserve(last - first)) return;
487 for (auto it = first; it != last; ++it) this->push_back(*it);
488 }
489
491 : Mem_root_array(root, x.cbegin(), x.cend()) {}
492
493 Mem_root_array(std::initializer_list<Element_type> elements)
494 : Mem_root_array(*THR_MALLOC, begin(elements), end(elements)) {}
495
497
498 // Not (yet) implemented.
501};
502
503#endif // MEM_ROOT_ARRAY_INCLUDED
A typesafe replacement for DYNAMIC_ARRAY.
Definition: mem_root_array.h:62
bool push_back(Element_type &&element)
Adds a new element at the end of the array, after its current last element.
Definition: mem_root_array.h:197
const Element_type * const_iterator
Definition: mem_root_array.h:113
iterator erase(iterator position)
Removes a single element from the array.
Definition: mem_root_array.h:403
bool push_front(Element_type &&element)
Adds a new element at the front of the array.
Definition: mem_root_array.h:242
bool emplace_back(Args &&...args)
Constructs an element at the back of the array in-place.
Definition: mem_root_array.h:208
const Element_type & at(size_t n) const
Definition: mem_root_array.h:100
bool empty() const
Definition: mem_root_array.h:412
void init(MEM_ROOT *root)
Definition: mem_root_array.h:75
MEM_ROOT * m_root
Definition: mem_root_array.h:416
bool push_back(const Element_type &element)
Adds a new element at the end of the array, after its current last element.
Definition: mem_root_array.h:187
Element_type * begin()
Returns a pointer to the first element in the array.
Definition: mem_root_array.h:116
size_t capacity() const
Definition: mem_root_array.h:410
iterator erase(size_t ix)
Removes a single element from the array.
Definition: mem_root_array.h:350
Element_type & back()
Definition: mem_root_array.h:108
Element_type & at(size_t n)
Definition: mem_root_array.h:95
size_t size() const
Definition: mem_root_array.h:413
size_t m_capacity
Definition: mem_root_array.h:419
void chop(const size_t pos)
Chops the tail off the array, erasing all tail elements.
Definition: mem_root_array.h:138
static constexpr bool has_trivial_destructor
Is Element_type trivially destructible? If it is, we don't destroy elements when they are removed fro...
Definition: mem_root_array.h:68
size_t erase_value(const value_type &val)
Removes a single element from the array by value.
Definition: mem_root_array.h:384
Element_type * iterator
Random access iterators to value_type and const value_type.
Definition: mem_root_array.h:112
Element_type value_type
Convenience typedef, same typedef name as std::vector.
Definition: mem_root_array.h:73
const_iterator cend() const
Returns a constant pointer to the past-the-end element in the array.
Definition: mem_root_array.h:127
const Element_type * end() const
Definition: mem_root_array.h:121
size_t m_size
Definition: mem_root_array.h:418
const Element_type * begin() const
Definition: mem_root_array.h:117
bool push_front(const Element_type &element)
Adds a new element at the beginning of the array.
Definition: mem_root_array.h:229
Element_type * end()
Returns a pointer to the past-the-end element in the array.
Definition: mem_root_array.h:120
Element_type & operator[](size_t n)
Definition: mem_root_array.h:105
const Element_type & operator[](size_t n) const
Definition: mem_root_array.h:106
Element_type * data()
Definition: mem_root_array.h:92
iterator insert(const_iterator pos, const Element_type &value)
Insert an element at a given position.
Definition: mem_root_array.h:363
const_iterator cbegin() const
Returns a constant pointer to the first element in the array.
Definition: mem_root_array.h:124
bool resize(size_t n)
Same as resize(size_t, const value_type &val), but value-initializes the new elements.
Definition: mem_root_array.h:302
bool resize(size_t n, const value_type &val)
Resizes the container so that it contains n elements.
Definition: mem_root_array.h:281
size_t element_size() const
Definition: mem_root_array.h:411
Element_type * m_array
Definition: mem_root_array.h:417
iterator erase(const_iterator first, const_iterator last)
Erase all the elements in the specified range.
Definition: mem_root_array.h:323
void clear()
Erases all of the elements.
Definition: mem_root_array.h:130
const Element_type * data() const
Definition: mem_root_array.h:93
void pop_back()
Removes the last element in the array, effectively reducing the container size by one.
Definition: mem_root_array.h:252
bool reserve(size_t n)
Reserves space for array elements.
Definition: mem_root_array.h:156
void init_empty_const()
Initialize empty array that we aren't going to grow.
Definition: mem_root_array.h:85
const Element_type & back() const
Definition: mem_root_array.h:109
iterator erase(const_iterator position)
Removes a single element from the array.
Definition: mem_root_array.h:339
A typesafe replacement for DYNAMIC_ARRAY.
Definition: mem_root_array.h:432
Mem_root_array(MEM_ROOT *root, const_iterator first, const_iterator last)
Range constructor.
Definition: mem_root_array.h:484
Mem_root_array(Mem_root_array &&other)
Move constructor and assignment.
Definition: mem_root_array.h:446
Mem_root_array(MEM_ROOT *root, size_t n)
Definition: mem_root_array.h:462
Mem_root_array & operator=(Mem_root_array &&other)
Definition: mem_root_array.h:454
Mem_root_array & operator=(const Mem_root_array &)=delete
Mem_root_array(MEM_ROOT *root, size_t n, const value_type &val)
Definition: mem_root_array.h:467
Element_type value_type
Convenience typedef, same typedef name as std::vector.
Definition: mem_root_array.h:437
Mem_root_array(const Mem_root_array &)=delete
Mem_root_array()
Definition: mem_root_array.h:441
~Mem_root_array()
Definition: mem_root_array.h:496
Mem_root_array(std::initializer_list< Element_type > elements)
Definition: mem_root_array.h:493
Mem_root_array_YY< Element_type > super
Definition: mem_root_array.h:433
Mem_root_array(MEM_ROOT *root, const Mem_root_array &x)
Definition: mem_root_array.h:490
super::const_iterator const_iterator
Definition: mem_root_array.h:439
Mem_root_array(MEM_ROOT *root)
Definition: mem_root_array.h:443
const char * p
Definition: ctype-mb.cc:1225
This file follows Google coding style, except for the name MEM_ROOT (which is kept for historical rea...
thread_local MEM_ROOT ** THR_MALLOC
Definition: mysqld.cc:1577
void copy(Shards< COUNT > &dst, const Shards< COUNT > &src) noexcept
Copy the counters, overwrite destination.
Definition: ut0counter.h:354
Container::const_iterator find(const Container &c, Value &&value)
Definition: generic.h:39
static MEM_ROOT mem
Definition: sql_servers.cc:100
The MEM_ROOT is a simple arena, where allocations are carved out of larger blocks.
Definition: my_alloc.h:83
void * Alloc(size_t length)
Allocate memory.
Definition: my_alloc.h:145
int n
Definition: xcom_base.cc:509