1/*****************************************************************************
2
3Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License, version 2.0,
7as published by the Free Software Foundation.
8
9This program is also distributed with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation.  The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have included with MySQL.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License, version 2.0, for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25*****************************************************************************/
26
27/**************************************************//**
28@file include/dyn0dyn.ic
29The dynamically allocated array
30
31Created 2/5/1996 Heikki Tuuri
32*******************************************************/
33
34/** Value of dyn_block_t::magic_n */
35#define DYN_BLOCK_MAGIC_N	375767
36/** Flag for dyn_block_t::used that indicates a full block */
37#define DYN_BLOCK_FULL_FLAG	0x1000000UL
38
39/************************************************************//**
40Adds a new block to a dyn array.
41@return	created block */
42UNIV_INTERN
43dyn_block_t*
44dyn_array_add_block(
45/*================*/
46	dyn_array_t*	arr)	/*!< in/out: dyn array */
47	MY_ATTRIBUTE((nonnull, warn_unused_result));
48
49/********************************************************************//**
50Gets the number of used bytes in a dyn array block.
51@return	number of bytes used */
52UNIV_INLINE
53ulint
54dyn_block_get_used(
55/*===============*/
56	const dyn_block_t*	block)	/*!< in: dyn array block */
57{
58	ut_ad(block);
59
60	return((block->used) & ~DYN_BLOCK_FULL_FLAG);
61}
62
63/********************************************************************//**
64Gets pointer to the start of data in a dyn array block.
65@return	pointer to data */
66UNIV_INLINE
67byte*
68dyn_block_get_data(
69/*===============*/
70	const dyn_block_t*	block)	/*!< in: dyn array block */
71{
72	ut_ad(block);
73
74	return(const_cast<byte*>(block->data));
75}
76
77/*********************************************************************//**
78Initializes a dynamic array.
79@return	initialized dyn array */
80UNIV_INLINE
81dyn_array_t*
82dyn_array_create(
83/*=============*/
84	dyn_array_t*	arr)	/*!< in/out: memory buffer of
85				size sizeof(dyn_array_t) */
86{
87	ut_ad(arr);
88#if DYN_ARRAY_DATA_SIZE >= DYN_BLOCK_FULL_FLAG
89# error "DYN_ARRAY_DATA_SIZE >= DYN_BLOCK_FULL_FLAG"
90#endif
91
92	arr->heap = NULL;
93	arr->used = 0;
94
95	ut_d(arr->buf_end = 0);
96	ut_d(arr->magic_n = DYN_BLOCK_MAGIC_N);
97
98	return(arr);
99}
100
101/************************************************************//**
102Frees a dynamic array. */
103UNIV_INLINE
104void
105dyn_array_free(
106/*===========*/
107	dyn_array_t*	arr)	/*!< in: dyn array */
108{
109	if (arr->heap != NULL) {
110		mem_heap_free(arr->heap);
111	}
112
113	ut_d(arr->magic_n = 0);
114}
115
116/*********************************************************************//**
117Makes room on top of a dyn array and returns a pointer to the added element.
118The caller must copy the element to the pointer returned.
119@return	pointer to the element */
120UNIV_INLINE
121void*
122dyn_array_push(
123/*===========*/
124	dyn_array_t*	arr,	/*!< in/out: dynamic array */
125	ulint		size)	/*!< in: size in bytes of the element */
126{
127	dyn_block_t*	block;
128	ulint		used;
129
130	ut_ad(arr);
131	ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
132	ut_ad(size <= DYN_ARRAY_DATA_SIZE);
133	ut_ad(size);
134
135	block = arr;
136
137	if (block->used + size > DYN_ARRAY_DATA_SIZE) {
138		/* Get the last array block */
139
140		block = dyn_array_get_last_block(arr);
141
142		if (block->used + size > DYN_ARRAY_DATA_SIZE) {
143			block = dyn_array_add_block(arr);
144		}
145	}
146
147	used = block->used;
148
149	block->used = used + size;
150	ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
151
152	return(block->data + used);
153}
154
155/*********************************************************************//**
156Makes room on top of a dyn array and returns a pointer to a buffer in it.
157After copying the elements, the caller must close the buffer using
158dyn_array_close.
159@return	pointer to the buffer */
160UNIV_INLINE
161byte*
162dyn_array_open(
163/*===========*/
164	dyn_array_t*	arr,	/*!< in: dynamic array */
165	ulint		size)	/*!< in: size in bytes of the buffer; MUST be
166				smaller than DYN_ARRAY_DATA_SIZE! */
167{
168	dyn_block_t*	block;
169
170	ut_ad(arr);
171	ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
172	ut_ad(size <= DYN_ARRAY_DATA_SIZE);
173	ut_ad(size);
174
175	block = arr;
176
177	if (block->used + size > DYN_ARRAY_DATA_SIZE) {
178		/* Get the last array block */
179
180		block = dyn_array_get_last_block(arr);
181
182		if (block->used + size > DYN_ARRAY_DATA_SIZE) {
183			block = dyn_array_add_block(arr);
184			ut_a(size <= DYN_ARRAY_DATA_SIZE);
185		}
186	}
187
188	ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
189	ut_ad(arr->buf_end == 0);
190	ut_d(arr->buf_end = block->used + size);
191
192	return(block->data + block->used);
193}
194
195/*********************************************************************//**
196Closes the buffer returned by dyn_array_open. */
197UNIV_INLINE
198void
199dyn_array_close(
200/*============*/
201	dyn_array_t*	arr,	/*!< in/out: dynamic array */
202	const byte*	ptr)	/*!< in: end of used space */
203{
204	dyn_block_t*	block;
205
206	ut_ad(arr);
207	ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
208
209	block = dyn_array_get_last_block(arr);
210
211	ut_ad(arr->buf_end + block->data >= ptr);
212
213	block->used = ptr - block->data;
214
215	ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
216
217	ut_d(arr->buf_end = 0);
218}
219
220/************************************************************//**
221Returns pointer to an element in dyn array.
222@return	pointer to element */
223UNIV_INLINE
224void*
225dyn_array_get_element(
226/*==================*/
227	const dyn_array_t*	arr,	/*!< in: dyn array */
228	ulint			pos)	/*!< in: position of element
229					in bytes from array start */
230{
231	const dyn_block_t*	block;
232
233	ut_ad(arr);
234	ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
235
236	/* Get the first array block */
237	block = dyn_array_get_first_block(arr);
238
239	if (arr->heap != NULL) {
240		for (;;) {
241			ulint	used = dyn_block_get_used(block);
242
243			if (pos < used) {
244				break;
245			}
246
247			pos -= used;
248			block = UT_LIST_GET_NEXT(list, block);
249			ut_ad(block);
250		}
251	}
252
253	ut_ad(block);
254	ut_ad(dyn_block_get_used(block) >= pos);
255
256	return(const_cast<byte*>(block->data) + pos);
257}
258
259/************************************************************//**
260Returns the size of stored data in a dyn array.
261@return	data size in bytes */
262UNIV_INLINE
263ulint
264dyn_array_get_data_size(
265/*====================*/
266	const dyn_array_t*	arr)	/*!< in: dyn array */
267{
268	const dyn_block_t*	block;
269	ulint			sum	= 0;
270
271	ut_ad(arr);
272	ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
273
274	if (arr->heap == NULL) {
275
276		return(arr->used);
277	}
278
279	/* Get the first array block */
280	block = dyn_array_get_first_block(arr);
281
282	while (block != NULL) {
283		sum += dyn_block_get_used(block);
284		block = dyn_array_get_next_block(arr, block);
285	}
286
287	return(sum);
288}
289
290/********************************************************//**
291Pushes n bytes to a dyn array. */
292UNIV_INLINE
293void
294dyn_push_string(
295/*============*/
296	dyn_array_t*	arr,	/*!< in/out: dyn array */
297	const byte*	str,	/*!< in: string to write */
298	ulint		len)	/*!< in: string length */
299{
300	ulint	n_copied;
301
302	while (len > 0) {
303		if (len > DYN_ARRAY_DATA_SIZE) {
304			n_copied = DYN_ARRAY_DATA_SIZE;
305		} else {
306			n_copied = len;
307		}
308
309		memcpy(dyn_array_push(arr, n_copied), str, n_copied);
310
311		str += n_copied;
312		len -= n_copied;
313	}
314}
315