mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			366 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			366 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
/*****************************************************************************
 | 
						|
 | 
						|
Copyright (c) 1996, 2009, Innobase Oy. 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., 59 Temple
 | 
						|
Place, Suite 330, Boston, MA 02111-1307 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: 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.
 | 
						|
@return	pointer to next, NULL if end of list */
 | 
						|
UNIV_INLINE
 | 
						|
dyn_block_t*
 | 
						|
dyn_array_get_next_block(
 | 
						|
/*=====================*/
 | 
						|
	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.
 | 
						|
@return	number of bytes used */
 | 
						|
UNIV_INLINE
 | 
						|
ulint
 | 
						|
dyn_block_get_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.
 | 
						|
@return	pointer to data */
 | 
						|
UNIV_INLINE
 | 
						|
byte*
 | 
						|
dyn_block_get_data(
 | 
						|
/*===============*/
 | 
						|
	dyn_block_t*	block)	/*!< in: dyn array block */
 | 
						|
{
 | 
						|
	ut_ad(block);
 | 
						|
 | 
						|
	return(block->data);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Initializes a dynamic array.
 | 
						|
@return	initialized dyn array */
 | 
						|
UNIV_INLINE
 | 
						|
dyn_array_t*
 | 
						|
dyn_array_create(
 | 
						|
/*=============*/
 | 
						|
	dyn_array_t*	arr)	/*!< in: pointer to a memory buffer of
 | 
						|
				size sizeof(dyn_array_t) */
 | 
						|
{
 | 
						|
	ut_ad(arr);
 | 
						|
#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;
 | 
						|
 | 
						|
#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.
 | 
						|
@return	pointer to the element */
 | 
						|
UNIV_INLINE
 | 
						|
void*
 | 
						|
dyn_array_push(
 | 
						|
/*===========*/
 | 
						|
	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.
 | 
						|
@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;
 | 
						|
	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.
 | 
						|
@return	pointer to element */
 | 
						|
UNIV_INLINE
 | 
						|
void*
 | 
						|
dyn_array_get_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.
 | 
						|
@return	data size in bytes */
 | 
						|
UNIV_INLINE
 | 
						|
ulint
 | 
						|
dyn_array_get_data_size(
 | 
						|
/*====================*/
 | 
						|
	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;
 | 
						|
	}
 | 
						|
}
 |