| 1 | /* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. |
| 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 as published by |
| 5 | the Free Software Foundation; version 2 of the License. |
| 6 | |
| 7 | This program is distributed in the hope that it will be useful, |
| 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 10 | GNU General Public License for more details. |
| 11 | |
| 12 | You should have received a copy of the GNU General Public License |
| 13 | along with this program; if not, write to the Free Software |
| 14 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ |
| 15 | |
| 16 | |
| 17 | #ifndef MEM_ROOT_ARRAY_INCLUDED |
| 18 | #define MEM_ROOT_ARRAY_INCLUDED |
| 19 | |
| 20 | #include <my_alloc.h> |
| 21 | |
| 22 | /** |
| 23 | A typesafe replacement for DYNAMIC_ARRAY. |
| 24 | We use MEM_ROOT for allocating storage, rather than the C++ heap. |
| 25 | The interface is chosen to be similar to std::vector. |
| 26 | |
| 27 | @remark |
| 28 | Unlike DYNAMIC_ARRAY, elements are properly copied |
| 29 | (rather than memcpy()d) if the underlying array needs to be expanded. |
| 30 | |
| 31 | @remark |
| 32 | Depending on has_trivial_destructor, we destroy objects which are |
| 33 | removed from the array (including when the array object itself is destroyed). |
| 34 | |
| 35 | @remark |
| 36 | Note that MEM_ROOT has no facility for reusing free space, |
| 37 | so don't use this if multiple re-expansions are likely to happen. |
| 38 | |
| 39 | @param Element_type The type of the elements of the container. |
| 40 | Elements must be copyable. |
| 41 | @param has_trivial_destructor If true, we don't destroy elements. |
| 42 | We could have used type traits to determine this. |
| 43 | __has_trivial_destructor is supported by some (but not all) |
| 44 | compilers we use. |
| 45 | */ |
| 46 | template<typename Element_type, bool has_trivial_destructor> |
| 47 | class Mem_root_array |
| 48 | { |
| 49 | public: |
| 50 | /// Convenience typedef, same typedef name as std::vector |
| 51 | typedef Element_type value_type; |
| 52 | |
| 53 | Mem_root_array(MEM_ROOT *root) |
| 54 | : m_root(root), m_array(NULL), m_size(0), m_capacity(0) |
| 55 | { |
| 56 | DBUG_ASSERT(m_root != NULL); |
| 57 | } |
| 58 | |
| 59 | Mem_root_array(MEM_ROOT *root, size_t n, const value_type &val= value_type()) |
| 60 | : m_root(root), m_array(NULL), m_size(0), m_capacity(0) |
| 61 | { |
| 62 | resize(n, val); |
| 63 | } |
| 64 | |
| 65 | ~Mem_root_array() |
| 66 | { |
| 67 | clear(); |
| 68 | } |
| 69 | |
| 70 | Element_type &at(size_t n) |
| 71 | { |
| 72 | DBUG_ASSERT(n < size()); |
| 73 | return m_array[n]; |
| 74 | } |
| 75 | |
| 76 | const Element_type &at(size_t n) const |
| 77 | { |
| 78 | DBUG_ASSERT(n < size()); |
| 79 | return m_array[n]; |
| 80 | } |
| 81 | |
| 82 | Element_type &operator[](size_t n) { return at(n); } |
| 83 | const Element_type &operator[](size_t n) const { return at(n); } |
| 84 | |
| 85 | Element_type &back() { return at(size() - 1); } |
| 86 | const Element_type &back() const { return at(size() - 1); } |
| 87 | |
| 88 | // Returns a pointer to the first element in the array. |
| 89 | Element_type *begin() { return &m_array[0]; } |
| 90 | |
| 91 | // Returns a pointer to the past-the-end element in the array. |
| 92 | Element_type *end() { return &m_array[size()]; } |
| 93 | |
| 94 | // Erases all of the elements. |
| 95 | void clear() |
| 96 | { |
| 97 | if (!empty()) |
| 98 | chop(0); |
| 99 | } |
| 100 | |
| 101 | /* |
| 102 | Chops the tail off the array, erasing all tail elements. |
| 103 | @param pos Index of first element to erase. |
| 104 | */ |
| 105 | void chop(const size_t pos) |
| 106 | { |
| 107 | DBUG_ASSERT(pos < m_size); |
| 108 | if (!has_trivial_destructor) |
| 109 | { |
| 110 | for (size_t ix= pos; ix < m_size; ++ix) |
| 111 | { |
| 112 | Element_type *p= &m_array[ix]; |
| 113 | p->~Element_type(); // Destroy discarded element. |
| 114 | } |
| 115 | } |
| 116 | m_size= pos; |
| 117 | } |
| 118 | |
| 119 | /* |
| 120 | Reserves space for array elements. |
| 121 | Copies over existing elements, in case we are re-expanding the array. |
| 122 | |
| 123 | @param n number of elements. |
| 124 | @retval true if out-of-memory, false otherwise. |
| 125 | */ |
| 126 | bool reserve(size_t n) |
| 127 | { |
| 128 | if (n <= m_capacity) |
| 129 | return false; |
| 130 | |
| 131 | void *mem= alloc_root(m_root, n * element_size()); |
| 132 | if (!mem) |
| 133 | return true; |
| 134 | Element_type *array= static_cast<Element_type*>(mem); |
| 135 | |
| 136 | // Copy all the existing elements into the new array. |
| 137 | for (size_t ix= 0; ix < m_size; ++ix) |
| 138 | { |
| 139 | Element_type *new_p= &array[ix]; |
| 140 | Element_type *old_p= &m_array[ix]; |
| 141 | new (new_p) Element_type(*old_p); // Copy into new location. |
| 142 | if (!has_trivial_destructor) |
| 143 | old_p->~Element_type(); // Destroy the old element. |
| 144 | } |
| 145 | |
| 146 | // Forget the old array. |
| 147 | m_array= array; |
| 148 | m_capacity= n; |
| 149 | return false; |
| 150 | } |
| 151 | |
| 152 | /* |
| 153 | Adds a new element at the end of the array, after its current last |
| 154 | element. The content of this new element is initialized to a copy of |
| 155 | the input argument. |
| 156 | |
| 157 | @param element Object to copy. |
| 158 | @retval true if out-of-memory, false otherwise. |
| 159 | */ |
| 160 | bool push_back(const Element_type &element) |
| 161 | { |
| 162 | const size_t min_capacity= 20; |
| 163 | const size_t expansion_factor= 2; |
| 164 | if (0 == m_capacity && reserve(min_capacity)) |
| 165 | return true; |
| 166 | if (m_size == m_capacity && reserve(m_capacity * expansion_factor)) |
| 167 | return true; |
| 168 | Element_type *p= &m_array[m_size++]; |
| 169 | new (p) Element_type(element); |
| 170 | return false; |
| 171 | } |
| 172 | |
| 173 | /** |
| 174 | Removes the last element in the array, effectively reducing the |
| 175 | container size by one. This destroys the removed element. |
| 176 | */ |
| 177 | void pop_back() |
| 178 | { |
| 179 | DBUG_ASSERT(!empty()); |
| 180 | if (!has_trivial_destructor) |
| 181 | back().~Element_type(); |
| 182 | m_size-= 1; |
| 183 | } |
| 184 | |
| 185 | /** |
| 186 | Resizes the container so that it contains n elements. |
| 187 | |
| 188 | If n is smaller than the current container size, the content is |
| 189 | reduced to its first n elements, removing those beyond (and |
| 190 | destroying them). |
| 191 | |
| 192 | If n is greater than the current container size, the content is |
| 193 | expanded by inserting at the end as many elements as needed to |
| 194 | reach a size of n. If val is specified, the new elements are |
| 195 | initialized as copies of val, otherwise, they are |
| 196 | value-initialized. |
| 197 | |
| 198 | If n is also greater than the current container capacity, an automatic |
| 199 | reallocation of the allocated storage space takes place. |
| 200 | |
| 201 | Notice that this function changes the actual content of the |
| 202 | container by inserting or erasing elements from it. |
| 203 | */ |
| 204 | void resize(size_t n, const value_type &val= value_type()) |
| 205 | { |
| 206 | if (n == m_size) |
| 207 | return; |
| 208 | if (n > m_size) |
| 209 | { |
| 210 | if (!reserve(n)) |
| 211 | { |
| 212 | while (n != m_size) |
| 213 | push_back(val); |
| 214 | } |
| 215 | return; |
| 216 | } |
| 217 | if (!has_trivial_destructor) |
| 218 | { |
| 219 | while (n != m_size) |
| 220 | pop_back(); |
| 221 | } |
| 222 | m_size= n; |
| 223 | } |
| 224 | |
| 225 | size_t capacity() const { return m_capacity; } |
| 226 | size_t element_size() const { return sizeof(Element_type); } |
| 227 | bool empty() const { return size() == 0; } |
| 228 | size_t size() const { return m_size; } |
| 229 | |
| 230 | private: |
| 231 | MEM_ROOT *const m_root; |
| 232 | Element_type *m_array; |
| 233 | size_t m_size; |
| 234 | size_t m_capacity; |
| 235 | |
| 236 | // Not (yet) implemented. |
| 237 | Mem_root_array(const Mem_root_array&); |
| 238 | Mem_root_array &operator=(const Mem_root_array&); |
| 239 | }; |
| 240 | |
| 241 | |
| 242 | #endif // MEM_ROOT_ARRAY_INCLUDED |
| 243 | |