/***************************************************************************** Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *****************************************************************************/ /**************************************************//** @file include/dyn0dyn.ic The dynamically allocated array Created 2/5/1996 Heikki Tuuri *******************************************************/ /** Value of dyn_block_struct::magic_n */ #define DYN_BLOCK_MAGIC_N 375767 /** Flag for dyn_block_struct::used that indicates a full block */ #define DYN_BLOCK_FULL_FLAG 0x1000000UL /************************************************************//** Adds a new block to a dyn array. @return created block */ UNIV_INTERN dyn_block_t* dyn_array_add_block( /*================*/ dyn_array_t* arr) /*!< in/out: dyn array */ __attribute__((nonnull, warn_unused_result)); /********************************************************************//** Gets the number of used bytes in a dyn array block. @return number of bytes used */ UNIV_INLINE ulint dyn_block_get_used( /*===============*/ const dyn_block_t* block) /*!< in: dyn array block */ { return((block->used) & ~DYN_BLOCK_FULL_FLAG); } /********************************************************************//** Gets pointer to the start of data in a dyn array block. @return pointer to data */ UNIV_INLINE byte* dyn_block_get_data( /*===============*/ const dyn_block_t* block) /*!< in: dyn array block */ { return((byte*) block->data); } /*********************************************************************//** Initializes a dynamic array. @return initialized dyn array */ UNIV_INLINE dyn_array_t* dyn_array_create( /*=============*/ dyn_array_t* arr) /*!< in/out: memory buffer of size sizeof(dyn_array_t) */ { #if DYN_ARRAY_DATA_SIZE >= DYN_BLOCK_FULL_FLAG # error "DYN_ARRAY_DATA_SIZE >= DYN_BLOCK_FULL_FLAG" #endif arr->heap = NULL; arr->used = 0; ut_d(arr->buf_end = 0); ut_d(arr->magic_n = DYN_BLOCK_MAGIC_N); return(arr); } /************************************************************//** Frees a dynamic array. */ UNIV_INLINE void dyn_array_free( /*===========*/ dyn_array_t* arr) /*!< in: dyn array */ { if (arr->heap != NULL) { mem_heap_free(arr->heap); } ut_d(arr->magic_n = 0); } /*********************************************************************//** Makes room on top of a dyn array and returns a pointer to the added element. The caller must copy the element to the pointer returned. @return pointer to the element */ UNIV_INLINE void* dyn_array_push( /*===========*/ dyn_array_t* arr, /*!< in/out: dynamic array */ ulint size) /*!< in: size in bytes of the element */ { dyn_block_t* block; ulint used; ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); ut_ad(size <= DYN_ARRAY_DATA_SIZE); ut_ad(size); block = arr; if (block->used + size > DYN_ARRAY_DATA_SIZE) { /* Get the last array block */ block = dyn_array_get_last_block(arr); if (block->used + size > DYN_ARRAY_DATA_SIZE) { block = dyn_array_add_block(arr); } } used = block->used; block->used = used + size; ut_ad(block->used <= DYN_ARRAY_DATA_SIZE); return(block->data + used); } /*********************************************************************//** Makes room on top of a dyn array and returns a pointer to a buffer in it. After copying the elements, the caller must close the buffer using dyn_array_close. @return pointer to the buffer */ UNIV_INLINE byte* dyn_array_open( /*===========*/ dyn_array_t* arr, /*!< in: dynamic array */ ulint size) /*!< in: size in bytes of the buffer; MUST be smaller than DYN_ARRAY_DATA_SIZE! */ { dyn_block_t* block; ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); ut_ad(size <= DYN_ARRAY_DATA_SIZE); ut_ad(size); block = arr; if (block->used + size > DYN_ARRAY_DATA_SIZE) { /* Get the last array block */ block = dyn_array_get_last_block(arr); if (block->used + size > DYN_ARRAY_DATA_SIZE) { block = dyn_array_add_block(arr); ut_a(size <= DYN_ARRAY_DATA_SIZE); } } ut_ad(block->used <= DYN_ARRAY_DATA_SIZE); ut_ad(arr->buf_end == 0); ut_d(arr->buf_end = block->used + size); return(block->data + block->used); } /*********************************************************************//** Closes the buffer returned by dyn_array_open. */ UNIV_INLINE void dyn_array_close( /*============*/ dyn_array_t* arr, /*!< in/out: dynamic array */ const byte* ptr) /*!< in: end of used space */ { dyn_block_t* block; ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); block = dyn_array_get_last_block(arr); ut_ad(arr->buf_end + block->data >= ptr); block->used = ptr - block->data; ut_ad(block->used <= DYN_ARRAY_DATA_SIZE); ut_d(arr->buf_end = 0); } /************************************************************//** Returns pointer to an element in dyn array. @return pointer to element */ UNIV_INLINE void* dyn_array_get_element( /*==================*/ const dyn_array_t* arr, /*!< in: dyn array */ ulint pos) /*!< in: position of element in bytes from array start */ { const dyn_block_t* block; ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); /* Get the first array block */ block = dyn_array_get_first_block(arr); if (arr->heap != NULL) { for (;;) { ulint used = dyn_block_get_used(block); if (pos < used) { break; } pos -= used; block = UT_LIST_GET_NEXT(list, block); ut_ad(block); } } ut_ad(block); ut_ad(dyn_block_get_used(block) >= pos); return((byte*) block->data + pos); } /************************************************************//** Returns the size of stored data in a dyn array. @return data size in bytes */ UNIV_INLINE ulint dyn_array_get_data_size( /*====================*/ const dyn_array_t* arr) /*!< in: dyn array */ { const dyn_block_t* block; ulint sum = 0; ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); if (arr->heap == NULL) { return(arr->used); } /* Get the first array block */ block = dyn_array_get_first_block(arr); while (block != NULL) { sum += dyn_block_get_used(block); block = dyn_array_get_next_block(arr, block); } return(sum); } /********************************************************//** Pushes n bytes to a dyn array. */ UNIV_INLINE void dyn_push_string( /*============*/ dyn_array_t* arr, /*!< in/out: dyn array */ const byte* str, /*!< in: string to write */ ulint len) /*!< in: string length */ { ulint n_copied; while (len > 0) { if (len > DYN_ARRAY_DATA_SIZE) { n_copied = DYN_ARRAY_DATA_SIZE; } else { n_copied = len; } memcpy(dyn_array_push(arr, n_copied), str, n_copied); str += n_copied; len -= n_copied; } }