mirror of https://github.com/MariaDB/server
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							306 lines
						
					
					
						
							7.2 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							306 lines
						
					
					
						
							7.2 KiB
						
					
					
				
								/*****************************************************************************
							 | 
						|
								
							 | 
						|
								Copyright (c) 1996, 2016, 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, Suite 500, Boston, MA 02110-1335 USA
							 | 
						|
								
							 | 
						|
								*****************************************************************************/
							 | 
						|
								
							 | 
						|
								/**************************************************//**
							 | 
						|
								@file include/dyn0dyn.ic
							 | 
						|
								The dynamically allocated array
							 | 
						|
								
							 | 
						|
								Created 2/5/1996 Heikki Tuuri
							 | 
						|
								*******************************************************/
							 | 
						|
								
							 | 
						|
								/** Value of dyn_block_t::magic_n */
							 | 
						|
								#define DYN_BLOCK_MAGIC_N	375767
							 | 
						|
								/** Flag for dyn_block_t::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 */
							 | 
						|
									MY_ATTRIBUTE((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 */
							 | 
						|
								{
							 | 
						|
									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(
							 | 
						|
								/*===============*/
							 | 
						|
									const dyn_block_t*	block)	/*!< in: dyn array block */
							 | 
						|
								{
							 | 
						|
									ut_ad(block);
							 | 
						|
								
							 | 
						|
									return(const_cast<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) */
							 | 
						|
								{
							 | 
						|
									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;
							 | 
						|
								
							 | 
						|
									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);
							 | 
						|
									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);
							 | 
						|
									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);
							 | 
						|
									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);
							 | 
						|
									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(const_cast<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);
							 | 
						|
									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;
							 | 
						|
									}
							 | 
						|
								}
							 |