123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- /* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License, version 2.0,
- as published by the Free Software Foundation.
- This program is also distributed with certain software (including
- but not limited to OpenSSL) that is licensed under separate terms,
- as designated in a particular file or component or in included license
- documentation. The authors of MySQL hereby grant you an additional
- permission to link the program and your derivative works with the
- separately licensed software that they have included with MySQL.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License, version 2.0, for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
- #ifndef MEM_ROOT_ARRAY_INCLUDED
- #define MEM_ROOT_ARRAY_INCLUDED
- #include <algorithm>
- #include <type_traits>
- #include "my_alloc.h"
- #include "my_dbug.h"
- /**
- A typesafe replacement for DYNAMIC_ARRAY.
- We use MEM_ROOT for allocating storage, rather than the C++ heap.
- The interface is chosen to be similar to std::vector.
- @remark
- Mem_root_array_YY is constructor-less for use in the parser stack of unions.
- For other needs please use Mem_root_array.
- @remark
- Unlike DYNAMIC_ARRAY, elements are properly copied
- (rather than memcpy()d) if the underlying array needs to be expanded.
- @remark
- Unless Element_type's destructor is trivial, we destroy objects when they are
- removed from the array (including when the array object itself is destroyed).
- @remark
- Note that MEM_ROOT has no facility for reusing free space,
- so don't use this if multiple re-expansions are likely to happen.
- @tparam Element_type The type of the elements of the container.
- Elements must be copyable.
- */
- template <typename Element_type>
- class Mem_root_array_YY {
- /**
- Is Element_type trivially destructible? If it is, we don't destroy
- elements when they are removed from the array or when the array is
- destroyed.
- */
- static constexpr bool has_trivial_destructor =
- std::is_trivially_destructible<Element_type>::value;
- public:
- /// Convenience typedef, same typedef name as std::vector
- typedef Element_type value_type;
- void init(MEM_ROOT *root) {
- DBUG_ASSERT(root != NULL);
- m_root = root;
- m_array = NULL;
- m_size = 0;
- m_capacity = 0;
- }
- /// Initialize empty array that we aren't going to grow
- void init_empty_const() {
- m_root = NULL;
- m_array = NULL;
- m_size = 0;
- m_capacity = 0;
- }
- /**
- Switches mem-root, in case original mem-root was copied.
- NOTE: m_root should really be const, i.e. never change after initialization.
- */
- void set_mem_root(MEM_ROOT *new_root) {
- m_root = new_root;
- DBUG_ASSERT(m_root != NULL);
- }
- Element_type &at(size_t n) {
- DBUG_ASSERT(n < size());
- return m_array[n];
- }
- const Element_type &at(size_t n) const {
- DBUG_ASSERT(n < size());
- return m_array[n];
- }
- Element_type &operator[](size_t n) { return at(n); }
- const Element_type &operator[](size_t n) const { return at(n); }
- Element_type &back() { return at(size() - 1); }
- const Element_type &back() const { return at(size() - 1); }
- /// Random access iterators to value_type and const value_type.
- typedef Element_type *iterator;
- typedef const Element_type *const_iterator;
- /// Returns a pointer to the first element in the array.
- Element_type *begin() { return &m_array[0]; }
- const Element_type *begin() const { return &m_array[0]; }
- /// Returns a pointer to the past-the-end element in the array.
- Element_type *end() { return &m_array[size()]; }
- const Element_type *end() const { return &m_array[size()]; }
- /// Returns a constant pointer to the first element in the array.
- const_iterator cbegin() const { return begin(); }
- /// Returns a constant pointer to the past-the-end element in the array.
- const_iterator cend() const { return end(); }
- /// Erases all of the elements.
- void clear() {
- if (!empty()) chop(0);
- }
- /**
- Chops the tail off the array, erasing all tail elements.
- @param pos Index of first element to erase.
- */
- void chop(const size_t pos) {
- DBUG_ASSERT(pos < m_size);
- if (!has_trivial_destructor) {
- for (size_t ix = pos; ix < m_size; ++ix) {
- Element_type *p = &m_array[ix];
- p->~Element_type(); // Destroy discarded element.
- }
- }
- m_size = pos;
- }
- /**
- Reserves space for array elements.
- Copies over existing elements, in case we are re-expanding the array.
- @param n number of elements.
- @retval true if out-of-memory, false otherwise.
- */
- bool reserve(size_t n) {
- if (n <= m_capacity) return false;
- void *mem = m_root->Alloc(n * element_size());
- if (!mem) return true;
- Element_type *array = static_cast<Element_type *>(mem);
- // Copy all the existing elements into the new array.
- for (size_t ix = 0; ix < m_size; ++ix) {
- Element_type *new_p = &array[ix];
- Element_type *old_p = &m_array[ix];
- ::new (new_p)
- Element_type(std::move(*old_p)); // Copy or move into new location.
- if (!has_trivial_destructor)
- old_p->~Element_type(); // Destroy the old element.
- }
- // Forget the old array.
- m_array = array;
- m_capacity = n;
- return false;
- }
- /**
- Adds a new element at the end of the array, after its current last
- element. The content of this new element is initialized to a copy of
- the input argument.
- @param element Object to copy.
- @retval true if out-of-memory, false otherwise.
- */
- bool push_back(const Element_type &element) {
- const size_t min_capacity = 20;
- const size_t expansion_factor = 2;
- if (0 == m_capacity && reserve(min_capacity)) return true;
- if (m_size == m_capacity && reserve(m_capacity * expansion_factor))
- return true;
- Element_type *p = &m_array[m_size++];
- ::new (p) Element_type(element);
- return false;
- }
- /**
- Adds a new element at the end of the array, after its current last
- element. The content of this new element is initialized by moving
- the input element.
- @param element Object to move.
- @retval true if out-of-memory, false otherwise.
- */
- bool push_back(Element_type &&element) {
- const size_t min_capacity = 20;
- const size_t expansion_factor = 2;
- if (0 == m_capacity && reserve(min_capacity)) return true;
- if (m_size == m_capacity && reserve(m_capacity * expansion_factor))
- return true;
- Element_type *p = &m_array[m_size++];
- ::new (p) Element_type(std::move(element));
- return false;
- }
- /**
- Removes the last element in the array, effectively reducing the
- container size by one. This destroys the removed element.
- */
- void pop_back() {
- DBUG_ASSERT(!empty());
- if (!has_trivial_destructor) back().~Element_type();
- m_size -= 1;
- }
- /**
- Resizes the container so that it contains n elements.
- If n is smaller than the current container size, the content is
- reduced to its first n elements, removing those beyond (and
- destroying them).
- If n is greater than the current container size, the content is
- expanded by inserting at the end as many elements as needed to
- reach a size of n. If val is specified, the new elements are
- initialized as copies of val, otherwise, they are
- value-initialized.
- If n is also greater than the current container capacity, an automatic
- reallocation of the allocated storage space takes place.
- Notice that this function changes the actual content of the
- container by inserting or erasing elements from it.
- */
- void resize(size_t n, const value_type &val) {
- if (n == m_size) return;
- if (n > m_size) {
- if (!reserve(n)) {
- while (n != m_size) push_back(val);
- }
- return;
- }
- if (!has_trivial_destructor) {
- while (n != m_size) pop_back();
- }
- m_size = n;
- }
- /**
- Same as resize(size_t, const value_type &val), but default-constructs
- the new elements. This allows one to resize containers even if
- value_type is not copy-constructible.
- */
- void resize(size_t n) {
- if (n == m_size) return;
- if (n > m_size) {
- if (!reserve(n)) {
- while (n != m_size) push_back(value_type());
- }
- return;
- }
- if (!has_trivial_destructor) {
- while (n != m_size) pop_back();
- }
- m_size = n;
- }
- /**
- Erase all the elements in the specified range.
- @param first iterator that points to the first element to remove
- @param last iterator that points to the element after the
- last one to remove
- @return an iterator to the first element after the removed range
- */
- iterator erase(const_iterator first, const_iterator last) {
- iterator pos = begin() + (first - cbegin());
- if (first != last) {
- iterator new_end = std::move(last, cend(), pos);
- chop(new_end - begin());
- }
- return pos;
- }
- /**
- Removes a single element from the array.
- @param position iterator that points to the element to remove
- @return an iterator to the first element after the removed range
- */
- iterator erase(const_iterator position) {
- return erase(position, std::next(position));
- }
- /**
- Removes a single element from the array.
- @param ix zero-based number of the element to remove
- @return an iterator to the first element after the removed range
- */
- iterator erase(size_t ix) {
- DBUG_ASSERT(ix < size());
- return erase(std::next(this->cbegin(), ix));
- }
- /**
- Insert an element at a given position.
- @param pos the new element is inserted before the element
- at this position
- @param value the value of the new element
- @return an iterator that points to the inserted element
- */
- iterator insert(const_iterator pos, const Element_type &value) {
- ptrdiff_t idx = pos - cbegin();
- if (!push_back(value)) std::rotate(begin() + idx, end() - 1, end());
- return begin() + idx;
- }
- /**
- Removes a single element from the array by value.
- The removed element is destroyed. This effectively reduces the
- container size by one.
- Note that if there are multiple elements having the same
- value, only the first element is removed.
- This is generally an inefficient operation, since we need to copy
- elements to fill the "hole" in the array.
- We use std::copy to move objects, hence Element_type must be
- assignable.
- @retval number of elements removed, 0 or 1.
- */
- size_t erase_value(const value_type &val) {
- iterator position = std::find(begin(), end(), val);
- if (position != end()) {
- erase(position);
- return 1;
- }
- return 0; // Not found
- }
- /**
- Removes a single element from the array.
- The removed element is destroyed.
- This effectively reduces the container size by one.
- This is generally an inefficient operation, since we need to copy
- elements to fill the "hole" in the array.
- We use std::copy to move objects, hence Element_type must be assignable.
- */
- iterator erase(iterator position) {
- DBUG_ASSERT(position != end());
- if (position + 1 != end()) std::copy(position + 1, end(), position);
- this->pop_back();
- return position;
- }
- size_t capacity() const { return m_capacity; }
- size_t element_size() const { return sizeof(Element_type); }
- bool empty() const { return size() == 0; }
- size_t size() const { return m_size; }
- private:
- MEM_ROOT *m_root;
- Element_type *m_array;
- size_t m_size;
- size_t m_capacity;
- // No CTOR/DTOR for this class!
- // Mem_root_array_YY(const Mem_root_array_YY&);
- // Mem_root_array_YY &operator=(const Mem_root_array_YY&);
- };
- /**
- A typesafe replacement for DYNAMIC_ARRAY.
- @see Mem_root_array_YY.
- */
- template <typename Element_type>
- class Mem_root_array : public Mem_root_array_YY<Element_type> {
- typedef Mem_root_array_YY<Element_type> super;
- public:
- /// Convenience typedef, same typedef name as std::vector
- typedef Element_type value_type;
- typedef typename super::const_iterator const_iterator;
- explicit Mem_root_array(MEM_ROOT *root) { super::init(root); }
- Mem_root_array(MEM_ROOT *root, size_t n) {
- super::init(root);
- super::resize(n);
- }
- Mem_root_array(MEM_ROOT *root, size_t n, const value_type &val) {
- super::init(root);
- super::resize(n, val);
- }
- /**
- Range constructor.
- Constructs a container with as many elements as the range [first,last),
- with each element constructed from its corresponding element in that range,
- in the same order.
- @param root MEM_ROOT to use for memory allocation.
- @param first iterator that points to the first element to copy
- @param last iterator that points to the element after the
- last one to copy
- */
- Mem_root_array(MEM_ROOT *root, const_iterator first, const_iterator last) {
- super::init(root);
- if (this->reserve(last - first)) return;
- for (auto it = first; it != last; ++it) this->push_back(*it);
- }
- Mem_root_array(MEM_ROOT *root, const Mem_root_array &x)
- : Mem_root_array(root, x.cbegin(), x.cend()) {}
- ~Mem_root_array() { super::clear(); }
- private:
- // Not (yet) implemented.
- Mem_root_array(const Mem_root_array &);
- Mem_root_array &operator=(const Mem_root_array &);
- };
- #endif // MEM_ROOT_ARRAY_INCLUDED
|