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*/
46template<typename Element_type, bool has_trivial_destructor>
47class Mem_root_array
48{
49public:
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
230private:
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