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