/* Copyright (c) 2011, 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 as published by the Free Software Foundation; version 2 of the License. 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MEM_ROOT_ARRAY_INCLUDED #define MEM_ROOT_ARRAY_INCLUDED #include /** 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 Unlike DYNAMIC_ARRAY, elements are properly copied (rather than memcpy()d) if the underlying array needs to be expanded. @remark Depending on has_trivial_destructor, we destroy objects which 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. @param Element_type The type of the elements of the container. Elements must be copyable. @param has_trivial_destructor If true, we don't destroy elements. We could have used type traits to determine this. __has_trivial_destructor is supported by some (but not all) compilers we use. */ template class Mem_root_array { public: Mem_root_array(MEM_ROOT *root) : m_root(root), m_array(NULL), m_size(0), m_capacity(0) { DBUG_ASSERT(m_root != NULL); } ~Mem_root_array() { clear(); } 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]; } // Returns a pointer to the first element in the array. Element_type *begin() { return &m_array[0]; } // Returns a pointer to the past-the-end element in the array. Element_type *end() { return &m_array[size()]; } // 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= alloc_root(m_root, n * element_size()); if (!mem) return true; Element_type *array= static_cast(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(*old_p); // Copy 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; } 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 *const m_root; Element_type *m_array; size_t m_size; size_t m_capacity; // Not (yet) implemented. Mem_root_array(const Mem_root_array&); Mem_root_array &operator=(const Mem_root_array&); }; #endif // MEM_ROOT_ARRAY_INCLUDED