/****************************************************** The dynamically allocated array (c) 1996 Innobase Oy Created 2/5/1996 Heikki Tuuri *******************************************************/ #define DYN_BLOCK_MAGIC_N 375767 #define DYN_BLOCK_FULL_FLAG 0x1000000UL /**************************************************************** Adds a new block to a dyn array. */ dyn_block_t* dyn_array_add_block( /*================*/ /* out: created block */ dyn_array_t* arr); /* in: dyn array */ /**************************************************************** Gets the first block in a dyn array. */ UNIV_INLINE dyn_block_t* dyn_array_get_first_block( /*======================*/ dyn_array_t* arr) /* in: dyn array */ { return(arr); } /**************************************************************** Gets the last block in a dyn array. */ UNIV_INLINE dyn_block_t* dyn_array_get_last_block( /*=====================*/ dyn_array_t* arr) /* in: dyn array */ { if (arr->heap == NULL) { return(arr); } return(UT_LIST_GET_LAST(arr->base)); } /************************************************************************ Gets the next block in a dyn array. */ UNIV_INLINE dyn_block_t* dyn_array_get_next_block( /*=====================*/ /* out: pointer to next, NULL if end of list */ dyn_array_t* arr, /* in: dyn array */ dyn_block_t* block) /* in: dyn array block */ { ut_ad(arr && block); if (arr->heap == NULL) { ut_ad(arr == block); return(NULL); } return(UT_LIST_GET_NEXT(list, block)); } /************************************************************************ Gets the number of used bytes in a dyn array block. */ UNIV_INLINE ulint dyn_block_get_used( /*===============*/ /* out: number of bytes used */ dyn_block_t* block) /* in: dyn array block */ { ut_ad(block); return((block->used) & ~DYN_BLOCK_FULL_FLAG); } /************************************************************************ Gets pointer to the start of data in a dyn array block. */ UNIV_INLINE byte* dyn_block_get_data( /*===============*/ /* out: pointer to data */ dyn_block_t* block) /* in: dyn array block */ { ut_ad(block); return(block->data); } /************************************************************************* Initializes a dynamic array. */ UNIV_INLINE dyn_array_t* dyn_array_create( /*=============*/ /* out: initialized dyn array */ dyn_array_t* arr) /* in: pointer to a memory buffer of size sizeof(dyn_array_t) */ { ut_ad(arr); ut_ad(DYN_ARRAY_DATA_SIZE < DYN_BLOCK_FULL_FLAG); arr->heap = NULL; arr->used = 0; #ifdef UNIV_DEBUG arr->buf_end = 0; arr->magic_n = DYN_BLOCK_MAGIC_N; #endif 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); } #ifdef UNIV_DEBUG arr->magic_n = 0; #endif } /************************************************************************* 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. */ UNIV_INLINE void* dyn_array_push( /*===========*/ /* out: pointer to the element */ dyn_array_t* arr, /* in: dynamic array */ ulint size) /* in: size in bytes of the element */ { dyn_block_t* block; ulint used; ut_ad(arr); ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); ut_ad(size <= DYN_ARRAY_DATA_SIZE); ut_ad(size); block = arr; used = block->used; if (used + size > DYN_ARRAY_DATA_SIZE) { /* Get the last array block */ block = dyn_array_get_last_block(arr); used = block->used; if (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. */ UNIV_INLINE byte* dyn_array_open( /*===========*/ /* out: pointer to the buffer */ 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; ulint used; ut_ad(arr); ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); ut_ad(size <= DYN_ARRAY_DATA_SIZE); ut_ad(size); block = arr; used = block->used; if (used + size > DYN_ARRAY_DATA_SIZE) { /* Get the last array block */ block = dyn_array_get_last_block(arr); used = block->used; if (used + size > DYN_ARRAY_DATA_SIZE) { block = dyn_array_add_block(arr); used = block->used; ut_a(size <= DYN_ARRAY_DATA_SIZE); } } ut_ad(block->used <= DYN_ARRAY_DATA_SIZE); #ifdef UNIV_DEBUG ut_ad(arr->buf_end == 0); arr->buf_end = used + size; #endif return((block->data) + used); } /************************************************************************* Closes the buffer returned by dyn_array_open. */ UNIV_INLINE void dyn_array_close( /*============*/ dyn_array_t* arr, /* in: dynamic array */ byte* ptr) /* in: buffer space from ptr up was not used */ { dyn_block_t* block; ut_ad(arr); 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); #ifdef UNIV_DEBUG arr->buf_end = 0; #endif } /**************************************************************** Returns pointer to an element in dyn array. */ UNIV_INLINE void* dyn_array_get_element( /*==================*/ /* out: pointer to element */ dyn_array_t* arr, /* in: dyn array */ ulint pos) /* in: position of element as bytes from array start */ { dyn_block_t* block; ulint used; ut_ad(arr); 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) { used = dyn_block_get_used(block); while (pos >= used) { pos -= used; block = UT_LIST_GET_NEXT(list, block); ut_ad(block); used = dyn_block_get_used(block); } } ut_ad(block); ut_ad(dyn_block_get_used(block) >= pos); return(block->data + pos); } /**************************************************************** Returns the size of stored data in a dyn array. */ UNIV_INLINE ulint dyn_array_get_data_size( /*====================*/ /* out: data size in bytes */ dyn_array_t* arr) /* in: dyn array */ { dyn_block_t* block; ulint sum = 0; ut_ad(arr); 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: 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; } }