1 | #ifndef SQL_ARRAY_INCLUDED |
2 | #define SQL_ARRAY_INCLUDED |
3 | |
4 | /* Copyright (c) 2003, 2005-2007 MySQL AB, 2009 Sun Microsystems, Inc. |
5 | Use is subject to license terms. |
6 | |
7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; version 2 of the License. |
10 | |
11 | This program is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
19 | |
20 | #include <my_sys.h> |
21 | |
22 | /** |
23 | A wrapper class which provides array bounds checking. |
24 | We do *not* own the array, we simply have a pointer to the first element, |
25 | and a length. |
26 | |
27 | @remark |
28 | We want the compiler-generated versions of: |
29 | - the copy CTOR (memberwise initialization) |
30 | - the assignment operator (memberwise assignment) |
31 | |
32 | @param Element_type The type of the elements of the container. |
33 | */ |
34 | template <typename Element_type> class Bounds_checked_array |
35 | { |
36 | public: |
37 | Bounds_checked_array() : m_array(NULL), m_size(0) {} |
38 | |
39 | Bounds_checked_array(Element_type *el, size_t size_arg) |
40 | : m_array(el), m_size(size_arg) |
41 | {} |
42 | |
43 | void reset() { m_array= NULL; m_size= 0; } |
44 | |
45 | void reset(Element_type *array_arg, size_t size_arg) |
46 | { |
47 | m_array= array_arg; |
48 | m_size= size_arg; |
49 | } |
50 | |
51 | /** |
52 | Set a new bound on the array. Does not resize the underlying |
53 | array, so the new size must be smaller than or equal to the |
54 | current size. |
55 | */ |
56 | void resize(size_t new_size) |
57 | { |
58 | DBUG_ASSERT(new_size <= m_size); |
59 | m_size= new_size; |
60 | } |
61 | |
62 | Element_type &operator[](size_t n) |
63 | { |
64 | DBUG_ASSERT(n < m_size); |
65 | return m_array[n]; |
66 | } |
67 | |
68 | const Element_type &operator[](size_t n) const |
69 | { |
70 | DBUG_ASSERT(n < m_size); |
71 | return m_array[n]; |
72 | } |
73 | |
74 | size_t element_size() const { return sizeof(Element_type); } |
75 | size_t size() const { return m_size; } |
76 | |
77 | bool is_null() const { return m_array == NULL; } |
78 | |
79 | void pop_front() |
80 | { |
81 | DBUG_ASSERT(m_size > 0); |
82 | m_array+= 1; |
83 | m_size-= 1; |
84 | } |
85 | |
86 | Element_type *array() const { return m_array; } |
87 | |
88 | bool operator==(const Bounds_checked_array<Element_type>&rhs) const |
89 | { |
90 | return m_array == rhs.m_array && m_size == rhs.m_size; |
91 | } |
92 | bool operator!=(const Bounds_checked_array<Element_type>&rhs) const |
93 | { |
94 | return m_array != rhs.m_array || m_size != rhs.m_size; |
95 | } |
96 | |
97 | private: |
98 | Element_type *m_array; |
99 | size_t m_size; |
100 | }; |
101 | |
102 | /* |
103 | A typesafe wrapper around DYNAMIC_ARRAY |
104 | |
105 | TODO: Change creator to take a THREAD_SPECIFIC option. |
106 | */ |
107 | |
108 | template <class Elem> class Dynamic_array |
109 | { |
110 | DYNAMIC_ARRAY array; |
111 | public: |
112 | Dynamic_array(uint prealloc=16, uint increment=16) |
113 | { |
114 | init(prealloc, increment); |
115 | } |
116 | |
117 | Dynamic_array(MEM_ROOT *root, uint prealloc=16, uint increment=16) |
118 | { |
119 | void *init_buffer= alloc_root(root, sizeof(Elem) * prealloc); |
120 | my_init_dynamic_array2(&array, sizeof(Elem), init_buffer, |
121 | prealloc, increment, MYF(0)); |
122 | } |
123 | |
124 | void init(uint prealloc=16, uint increment=16) |
125 | { |
126 | my_init_dynamic_array(&array, sizeof(Elem), prealloc, increment, |
127 | MYF(0)); |
128 | } |
129 | |
130 | /** |
131 | @note Though formally this could be declared "const" it would be |
132 | misleading at it returns a non-const pointer to array's data. |
133 | */ |
134 | Elem& at(size_t idx) |
135 | { |
136 | DBUG_ASSERT(idx < array.elements); |
137 | return *(((Elem*)array.buffer) + idx); |
138 | } |
139 | /// Const variant of at(), which cannot change data |
140 | const Elem& at(size_t idx) const |
141 | { |
142 | return *(((Elem*)array.buffer) + idx); |
143 | } |
144 | |
145 | /// @returns pointer to first element |
146 | Elem *front() |
147 | { |
148 | return (Elem*)array.buffer; |
149 | } |
150 | |
151 | /// @returns pointer to first element |
152 | const Elem *front() const |
153 | { |
154 | return (const Elem*)array.buffer; |
155 | } |
156 | |
157 | /// @returns pointer to last element |
158 | Elem *back() |
159 | { |
160 | return ((Elem*)array.buffer) + array.elements - 1; |
161 | } |
162 | |
163 | /// @returns pointer to last element |
164 | const Elem *back() const |
165 | { |
166 | return ((const Elem*)array.buffer) + array.elements - 1; |
167 | } |
168 | |
169 | /** |
170 | @retval false ok |
171 | @retval true OOM, @c my_error() has been called. |
172 | */ |
173 | bool append(const Elem &el) |
174 | { |
175 | return insert_dynamic(&array, &el); |
176 | } |
177 | |
178 | bool append_val(Elem el) |
179 | { |
180 | return (insert_dynamic(&array, (uchar*)&el)); |
181 | } |
182 | |
183 | bool push(Elem &el) |
184 | { |
185 | return append(el); |
186 | } |
187 | |
188 | /// Pops the last element. Does nothing if array is empty. |
189 | Elem& pop() |
190 | { |
191 | return *((Elem*)pop_dynamic(&array)); |
192 | } |
193 | |
194 | void del(size_t idx) |
195 | { |
196 | DBUG_ASSERT(idx <= array.max_element); |
197 | delete_dynamic_element(&array, (uint)idx); |
198 | } |
199 | |
200 | size_t elements() const |
201 | { |
202 | return array.elements; |
203 | } |
204 | |
205 | void elements(size_t num_elements) |
206 | { |
207 | DBUG_ASSERT(num_elements <= array.max_element); |
208 | array.elements= (uint)num_elements; |
209 | } |
210 | |
211 | void clear() |
212 | { |
213 | elements(0); |
214 | } |
215 | |
216 | void set(uint idx, const Elem &el) |
217 | { |
218 | set_dynamic(&array, &el, idx); |
219 | } |
220 | |
221 | bool resize(size_t new_size, Elem default_val) |
222 | { |
223 | size_t old_size= elements(); |
224 | if (unlikely(allocate_dynamic(&array, (uint)new_size))) |
225 | return true; |
226 | |
227 | if (new_size > old_size) |
228 | { |
229 | set_dynamic(&array, (uchar*)&default_val, (uint)(new_size - 1)); |
230 | /*for (size_t i= old_size; i != new_size; i++) |
231 | { |
232 | at(i)= default_val; |
233 | }*/ |
234 | } |
235 | return false; |
236 | } |
237 | |
238 | ~Dynamic_array() |
239 | { |
240 | delete_dynamic(&array); |
241 | } |
242 | |
243 | void free_memory() |
244 | { |
245 | delete_dynamic(&array); |
246 | } |
247 | |
248 | typedef int (*CMP_FUNC)(const Elem *el1, const Elem *el2); |
249 | |
250 | void sort(CMP_FUNC cmp_func) |
251 | { |
252 | my_qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func); |
253 | } |
254 | |
255 | typedef int (*CMP_FUNC2)(const Elem *el1, const Elem *el2, void *); |
256 | void sort(CMP_FUNC2 cmp_func, void *data) |
257 | { |
258 | my_qsort2(array.buffer, array.elements, sizeof(Elem), (qsort2_cmp)cmp_func, data); |
259 | } |
260 | }; |
261 | |
262 | typedef Bounds_checked_array<Item*> Ref_ptr_array; |
263 | |
264 | #endif /* SQL_ARRAY_INCLUDED */ |
265 | |