All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			changed multiple open functions to accept hawk_errinfo_t* instead of hawk_errnum_t*
		
			
				
	
	
		
			743 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			743 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
    Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
						|
 | 
						|
    Redistribution and use in source and binary forms, with or without
 | 
						|
    modification, are permitted provided that the following conditions
 | 
						|
    are met:
 | 
						|
    1. Redistributions of source code must retain the above copyright
 | 
						|
       notice, this list of conditions and the following disclaimer.
 | 
						|
    2. Redistributions in binary form must reproduce the above copyright
 | 
						|
       notice, this list of conditions and the following disclaimer in the
 | 
						|
       documentation and/or other materials provided with the distribution.
 | 
						|
 | 
						|
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | 
						|
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
						|
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
						|
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
						|
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
						|
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
						|
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
#include <hawk-arr.h>
 | 
						|
#include "hawk-prv.h"
 | 
						|
 | 
						|
#define slot_t   hawk_arr_slot_t
 | 
						|
#define copier_t hawk_arr_copier_t
 | 
						|
#define freeer_t hawk_arr_freeer_t
 | 
						|
#define comper_t hawk_arr_comper_t
 | 
						|
#define sizer_t  hawk_arr_sizer_t
 | 
						|
#define keeper_t hawk_arr_keeper_t
 | 
						|
#define walker_t hawk_arr_walker_t
 | 
						|
 | 
						|
 | 
						|
#define TOB(arr,len) ((len)*(arr)->scale)
 | 
						|
#define DPTR(slot)   ((slot)->val.ptr)
 | 
						|
#define DLEN(slot)   ((slot)->val.len)
 | 
						|
 | 
						|
/* the default comparator is not proper for number comparision.
 | 
						|
 * the first different byte decides whice side is greater */
 | 
						|
int hawk_arr_dflcomp (hawk_arr_t* arr, const void* dptr1, hawk_oow_t dlen1, const void* dptr2, hawk_oow_t dlen2)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	if (dlen1 == dlen2) return HAWK_MEMCMP(dptr1, dptr2, TOB(arr,dlen1));
 | 
						|
	return 1;
 | 
						|
	*/
 | 
						|
 | 
						|
	int n;
 | 
						|
	hawk_oow_t min;
 | 
						|
 | 
						|
	min = (dlen1 < dlen2)? dlen1: dlen2;
 | 
						|
	n = HAWK_MEMCMP(dptr1, dptr2, TOB(arr,min));
 | 
						|
	if (n == 0 && dlen1 != dlen2)
 | 
						|
	{
 | 
						|
		n = (dlen1 > dlen2)? 1: -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE slot_t* alloc_slot (hawk_arr_t* arr, void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	slot_t* n;
 | 
						|
 | 
						|
	if (arr->style->copier == HAWK_ARR_COPIER_SIMPLE)
 | 
						|
	{
 | 
						|
		n = (slot_t*)hawk_gem_allocmem(arr->gem, HAWK_SIZEOF(slot_t));
 | 
						|
		if (HAWK_UNLIKELY(!n)) return HAWK_NULL;
 | 
						|
		DPTR(n) = dptr; /* store the pointer */
 | 
						|
	}
 | 
						|
	else if (arr->style->copier == HAWK_ARR_COPIER_INLINE)
 | 
						|
	{
 | 
						|
		n = (slot_t*)hawk_gem_allocmem(arr->gem, HAWK_SIZEOF(slot_t) + TOB(arr,dlen));
 | 
						|
		if (HAWK_UNLIKELY(!n)) return HAWK_NULL;
 | 
						|
 | 
						|
		HAWK_MEMCPY (n + 1, dptr, TOB(arr,dlen)); /* copy data contents */
 | 
						|
		DPTR(n) = n + 1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		n = (slot_t*)hawk_gem_allocmem(arr->gem, HAWK_SIZEOF(slot_t));
 | 
						|
		if (HAWK_UNLIKELY(!n)) return HAWK_NULL;
 | 
						|
		DPTR(n) = arr->style->copier(arr, dptr, dlen); /* call the custom copier */
 | 
						|
		if (HAWK_UNLIKELY(!DPTR(n)))
 | 
						|
		{
 | 
						|
			hawk_gem_freemem(arr->gem, n);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	DLEN(n) = dlen;
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
hawk_arr_t* hawk_arr_open (hawk_gem_t* gem, hawk_oow_t xtnsize, hawk_oow_t capa)
 | 
						|
{
 | 
						|
	hawk_arr_t* arr;
 | 
						|
 | 
						|
	arr = (hawk_arr_t*)hawk_gem_allocmem(gem, HAWK_SIZEOF(hawk_arr_t) + xtnsize);
 | 
						|
	if (HAWK_UNLIKELY(!arr)) return HAWK_NULL;
 | 
						|
 | 
						|
	if (hawk_arr_init(arr, gem, capa) <= -1)
 | 
						|
	{
 | 
						|
		hawk_gem_freemem (gem, arr);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	HAWK_MEMSET (arr + 1, 0, xtnsize);
 | 
						|
	return arr;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_arr_close (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	hawk_arr_fini (arr);
 | 
						|
	hawk_gem_freemem(arr->gem, arr);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static hawk_arr_style_t style[] =
 | 
						|
{
 | 
						|
	{
 | 
						|
		HAWK_ARR_COPIER_DEFAULT,
 | 
						|
		HAWK_ARR_FREEER_DEFAULT,
 | 
						|
		HAWK_ARR_COMPER_DEFAULT,
 | 
						|
		HAWK_ARR_KEEPER_DEFAULT,
 | 
						|
		HAWK_ARR_SIZER_DEFAULT
 | 
						|
	},
 | 
						|
 | 
						|
	{
 | 
						|
		HAWK_ARR_COPIER_INLINE,
 | 
						|
		HAWK_ARR_FREEER_DEFAULT,
 | 
						|
		HAWK_ARR_COMPER_DEFAULT,
 | 
						|
		HAWK_ARR_KEEPER_DEFAULT,
 | 
						|
		HAWK_ARR_SIZER_DEFAULT
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
const hawk_arr_style_t* hawk_get_arr_style (hawk_arr_style_kind_t kind)
 | 
						|
{
 | 
						|
	return &style[kind];
 | 
						|
}
 | 
						|
 | 
						|
int hawk_arr_init (hawk_arr_t* arr, hawk_gem_t* gem, hawk_oow_t capa)
 | 
						|
{
 | 
						|
	HAWK_MEMSET(arr, 0, HAWK_SIZEOF(*arr));
 | 
						|
 | 
						|
	arr->gem = gem;
 | 
						|
	arr->size = 0;
 | 
						|
	arr->tally = 0;
 | 
						|
	arr->capa = 0;
 | 
						|
	arr->slot = HAWK_NULL;
 | 
						|
	arr->scale = 1;
 | 
						|
	arr->heap_pos_offset = HAWK_ARR_NIL;
 | 
						|
	arr->style = &style[0];
 | 
						|
 | 
						|
	return (hawk_arr_setcapa(arr, capa) == HAWK_NULL)? -1: 0;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_arr_fini (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	hawk_arr_clear (arr);
 | 
						|
 | 
						|
	if (arr->slot)
 | 
						|
	{
 | 
						|
		hawk_gem_freemem(arr->gem, arr->slot);
 | 
						|
		arr->slot = HAWK_NULL;
 | 
						|
		arr->capa = 0;
 | 
						|
		arr->size = 0 ;
 | 
						|
		arr->tally = 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int hawk_arr_getscale (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	return arr->scale;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_arr_setscale (hawk_arr_t* arr, int scale)
 | 
						|
{
 | 
						|
	/* The scale should be larger than 0 and less than or equal to the
 | 
						|
	 * maximum value that the hawk_uint8_t type can hold */
 | 
						|
	HAWK_ASSERT (scale > 0 && scale <= HAWK_TYPE_MAX(hawk_uint8_t));
 | 
						|
 | 
						|
	if (scale <= 0) scale = 1;
 | 
						|
	if (scale > HAWK_TYPE_MAX(hawk_uint8_t)) scale = HAWK_TYPE_MAX(hawk_uint8_t);
 | 
						|
 | 
						|
	arr->scale = scale;
 | 
						|
}
 | 
						|
 | 
						|
const hawk_arr_style_t* hawk_arr_getstyle (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	return arr->style;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_arr_setstyle (hawk_arr_t* arr, const hawk_arr_style_t* style)
 | 
						|
{
 | 
						|
	HAWK_ASSERT (style != HAWK_NULL);
 | 
						|
	arr->style = style;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_getsize (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	return arr->size;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_getcapa (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	return arr->capa;
 | 
						|
}
 | 
						|
 | 
						|
hawk_arr_t* hawk_arr_setcapa (hawk_arr_t* arr, hawk_oow_t capa)
 | 
						|
{
 | 
						|
	void* tmp;
 | 
						|
 | 
						|
	if (capa == arr->capa) return arr;
 | 
						|
 | 
						|
	if (capa < arr->size)
 | 
						|
	{
 | 
						|
		/* to trigger freeers on the items truncated */
 | 
						|
		hawk_arr_delete(arr, capa, arr->size - capa);
 | 
						|
		HAWK_ASSERT(arr->size <= capa);
 | 
						|
	}
 | 
						|
 | 
						|
	if (capa > 0)
 | 
						|
	{
 | 
						|
		tmp = (slot_t**)hawk_gem_reallocmem(arr->gem, arr->slot, HAWK_SIZEOF(*arr->slot) * capa);
 | 
						|
		if (HAWK_UNLIKELY(!tmp)) return HAWK_NULL;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (arr->slot)
 | 
						|
		{
 | 
						|
			hawk_arr_clear(arr);
 | 
						|
			hawk_gem_freemem(arr->gem, arr->slot);
 | 
						|
		}
 | 
						|
 | 
						|
		tmp = HAWK_NULL;
 | 
						|
 | 
						|
		HAWK_ASSERT (arr->size == 0);
 | 
						|
		HAWK_ASSERT (arr->tally == 0);
 | 
						|
	}
 | 
						|
 | 
						|
	arr->slot = tmp;
 | 
						|
	arr->capa = capa;
 | 
						|
 | 
						|
	return arr;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_search (hawk_arr_t* arr, hawk_oow_t pos, const void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
 | 
						|
	for (i = pos; i < arr->size; i++)
 | 
						|
	{
 | 
						|
		if (arr->slot[i] == HAWK_NULL) continue;
 | 
						|
		if (arr->style->comper(arr, DPTR(arr->slot[i]), DLEN(arr->slot[i]), dptr, dlen) == 0) return i;
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_gem_seterrnum (arr->gem, HAWK_NULL, HAWK_ENOENT);
 | 
						|
	return HAWK_ARR_NIL;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_rsearch (hawk_arr_t* arr, hawk_oow_t pos, const void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
 | 
						|
	if (arr->size > 0)
 | 
						|
	{
 | 
						|
		if (pos >= arr->size) pos = arr->size - 1;
 | 
						|
 | 
						|
		for (i = pos + 1; i-- > 0; )
 | 
						|
		{
 | 
						|
			if (arr->slot[i] == HAWK_NULL) continue;
 | 
						|
			if (arr->style->comper(arr, DPTR(arr->slot[i]), DLEN(arr->slot[i]), dptr, dlen) == 0) return i;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_gem_seterrnum (arr->gem, HAWK_NULL, HAWK_ENOENT);
 | 
						|
	return HAWK_ARR_NIL;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_upsert (hawk_arr_t* arr, hawk_oow_t pos, void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	if (pos < arr->size) return hawk_arr_update(arr, pos, dptr, dlen);
 | 
						|
	return hawk_arr_insert(arr, pos, dptr, dlen);
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_insert (hawk_arr_t* arr, hawk_oow_t pos, void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
	slot_t* slot;
 | 
						|
 | 
						|
	/* allocate the slot first */
 | 
						|
	slot = alloc_slot(arr, dptr, dlen);
 | 
						|
	if (HAWK_UNLIKELY(!slot)) return HAWK_ARR_NIL;
 | 
						|
 | 
						|
	/* do resizeing if necessary.
 | 
						|
	 * resizing is performed after slot allocation because that way, it
 | 
						|
	 * doesn't modify arr on any errors */
 | 
						|
	if (pos >= arr->capa || arr->size >= arr->capa)
 | 
						|
	{
 | 
						|
		hawk_oow_t capa, mincapa;
 | 
						|
 | 
						|
		/* get the minimum capacity needed */
 | 
						|
		mincapa = (pos >= arr->size)? (pos + 1): (arr->size + 1);
 | 
						|
 | 
						|
		if (arr->style->sizer)
 | 
						|
		{
 | 
						|
			capa = arr->style->sizer(arr, mincapa);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (arr->capa <= 0)
 | 
						|
			{
 | 
						|
				HAWK_ASSERT (arr->size <= 0);
 | 
						|
				capa = HAWK_ALIGN_POW2(pos + 1, 64);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				hawk_oow_t bound = (pos >= arr->size)? pos: arr->size;
 | 
						|
				capa = HAWK_ALIGN_POW2(bound + 1, 64);
 | 
						|
				do { capa = arr->capa * 2; } while (capa <= bound);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		do
 | 
						|
		{
 | 
						|
			if (hawk_arr_setcapa(arr, capa) != HAWK_NULL) break;
 | 
						|
 | 
						|
			if (capa <= mincapa)
 | 
						|
			{
 | 
						|
				if (arr->style->freeer) arr->style->freeer(arr, DPTR(slot), DLEN(slot));
 | 
						|
				hawk_gem_freemem(arr->gem, slot);
 | 
						|
				return HAWK_ARR_NIL;
 | 
						|
			}
 | 
						|
 | 
						|
			capa--; /* let it retry after lowering the capacity */
 | 
						|
		}
 | 
						|
		while (1);
 | 
						|
 | 
						|
		if (pos >= arr->capa || arr->size >= arr->capa)  /* can happen if the sizer() callback isn't good enough */
 | 
						|
		{
 | 
						|
			/* the buffer is not still enough after resizing */
 | 
						|
			if (arr->style->freeer) arr->style->freeer(arr, DPTR(slot), DLEN(slot));
 | 
						|
			hawk_gem_freemem(arr->gem, slot);
 | 
						|
			hawk_gem_seterrnum (arr->gem, HAWK_NULL, HAWK_EBUFFULL);
 | 
						|
			return HAWK_ARR_NIL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* fill in the gap with HAWK_NULL */
 | 
						|
	for (i = arr->size; i < pos; i++) arr->slot[i] = HAWK_NULL;
 | 
						|
 | 
						|
	/* shift values to the next cell */
 | 
						|
	for (i = arr->size; i > pos; i--) arr->slot[i] = arr->slot[i-1];
 | 
						|
 | 
						|
	/*  set the value */
 | 
						|
	arr->slot[pos] = slot;
 | 
						|
 | 
						|
	if (pos > arr->size) arr->size = pos + 1;
 | 
						|
	else arr->size++;
 | 
						|
	arr->tally++;
 | 
						|
 | 
						|
	return pos;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_update (hawk_arr_t* arr, hawk_oow_t pos, void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	slot_t* c;
 | 
						|
 | 
						|
	if (pos >= arr->size)
 | 
						|
	{
 | 
						|
		hawk_gem_seterrnum (arr->gem, HAWK_NULL, HAWK_EINVAL);
 | 
						|
		return HAWK_ARR_NIL;
 | 
						|
	}
 | 
						|
 | 
						|
	c = arr->slot[pos];
 | 
						|
	if (c == HAWK_NULL)
 | 
						|
	{
 | 
						|
		/* no previous data */
 | 
						|
		arr->slot[pos] = alloc_slot(arr, dptr, dlen);
 | 
						|
		if (arr->slot[pos] == HAWK_NULL) return HAWK_ARR_NIL;
 | 
						|
		arr->tally++;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (dptr == DPTR(c) && dlen == DLEN(c))
 | 
						|
		{
 | 
						|
			/* updated to the same data */
 | 
						|
			if (arr->style->keeper) arr->style->keeper(arr, dptr, dlen);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			/* updated to different data */
 | 
						|
			slot_t* slot = alloc_slot(arr, dptr, dlen);
 | 
						|
			if (HAWK_UNLIKELY(!slot)) return HAWK_ARR_NIL;
 | 
						|
 | 
						|
			if (arr->style->freeer) arr->style->freeer(arr, DPTR(c), DLEN(c));
 | 
						|
			hawk_gem_freemem(arr->gem, c);
 | 
						|
 | 
						|
			arr->slot[pos] = slot;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return pos;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_delete (hawk_arr_t* arr, hawk_oow_t index, hawk_oow_t count)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
 | 
						|
	if (index >= arr->size) return 0;
 | 
						|
	if (count > arr->size - index) count = arr->size - index;
 | 
						|
 | 
						|
	i = index;
 | 
						|
 | 
						|
	for (i = index; i < index + count; i++)
 | 
						|
	{
 | 
						|
		slot_t* c = arr->slot[i];
 | 
						|
		if (c)
 | 
						|
		{
 | 
						|
			if (arr->style->freeer) arr->style->freeer(arr, DPTR(c), DLEN(c));
 | 
						|
			hawk_gem_freemem(arr->gem, c);
 | 
						|
			arr->slot[i] = HAWK_NULL;
 | 
						|
			arr->tally--;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = index + count; i < arr->size; i++)
 | 
						|
	{
 | 
						|
		arr->slot[i - count] = arr->slot[i];
 | 
						|
	}
 | 
						|
	arr->slot[arr->size - 1] = HAWK_NULL;
 | 
						|
 | 
						|
	arr->size -= count;
 | 
						|
	return count;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_uplete (hawk_arr_t* arr, hawk_oow_t index, hawk_oow_t count)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
 | 
						|
	if (index >= arr->size) return 0;
 | 
						|
	if (count > arr->size - index) count = arr->size - index;
 | 
						|
 | 
						|
	i = index;
 | 
						|
 | 
						|
	for (i = index; i < index + count; i++)
 | 
						|
	{
 | 
						|
		slot_t* c = arr->slot[i];
 | 
						|
		if (c)
 | 
						|
		{
 | 
						|
			if (arr->style->freeer) arr->style->freeer(arr, DPTR(c), DLEN(c));
 | 
						|
			hawk_gem_freemem(arr->gem, c);
 | 
						|
			arr->slot[i] = HAWK_NULL;
 | 
						|
			arr->tally--;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return count;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_arr_clear (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
 | 
						|
	for (i = 0; i < arr->size; i++)
 | 
						|
	{
 | 
						|
		slot_t* c = arr->slot[i];
 | 
						|
		if (c != HAWK_NULL)
 | 
						|
		{
 | 
						|
			if (arr->style->freeer) arr->style->freeer(arr, DPTR(c), DLEN(c));
 | 
						|
			hawk_gem_freemem(arr->gem, c);
 | 
						|
			arr->slot[i] = HAWK_NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	arr->size = 0;
 | 
						|
	arr->tally = 0;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_walk (hawk_arr_t* arr, walker_t walker, void* ctx)
 | 
						|
{
 | 
						|
	hawk_arr_walk_t w = HAWK_ARR_WALK_FORWARD;
 | 
						|
	hawk_oow_t i = 0, nwalks = 0;
 | 
						|
 | 
						|
	if (arr->size <= 0) return 0;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (arr->slot[i])
 | 
						|
		{
 | 
						|
			w = walker(arr, i, ctx);
 | 
						|
			nwalks++;
 | 
						|
		}
 | 
						|
 | 
						|
		if (w == HAWK_ARR_WALK_STOP) break;
 | 
						|
 | 
						|
		if (w == HAWK_ARR_WALK_FORWARD)
 | 
						|
		{
 | 
						|
			i++;
 | 
						|
			if (i >= arr->size) break;
 | 
						|
		}
 | 
						|
		if (w == HAWK_ARR_WALK_BACKWARD)
 | 
						|
		{
 | 
						|
			if (i <= 0) break;
 | 
						|
			i--;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nwalks;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_rwalk (hawk_arr_t* arr, walker_t walker, void* ctx)
 | 
						|
{
 | 
						|
	hawk_arr_walk_t w = HAWK_ARR_WALK_BACKWARD;
 | 
						|
	hawk_oow_t i, nwalks = 0;
 | 
						|
 | 
						|
	if (arr->size <= 0) return 0;
 | 
						|
	i = arr->size - 1;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (arr->slot[i])
 | 
						|
		{
 | 
						|
			w = walker(arr, i, ctx);
 | 
						|
			nwalks++;
 | 
						|
		}
 | 
						|
 | 
						|
		if (w == HAWK_ARR_WALK_STOP) break;
 | 
						|
 | 
						|
		if (w == HAWK_ARR_WALK_FORWARD)
 | 
						|
		{
 | 
						|
			i++;
 | 
						|
			if (i >= arr->size) break;
 | 
						|
		}
 | 
						|
		if (w == HAWK_ARR_WALK_BACKWARD)
 | 
						|
		{
 | 
						|
			if (i <= 0) break;
 | 
						|
			i--;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nwalks;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_pushstack (hawk_arr_t* arr, void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	return hawk_arr_insert(arr, arr->size, dptr, dlen);
 | 
						|
}
 | 
						|
 | 
						|
void hawk_arr_popstack (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	HAWK_ASSERT(arr->size > 0);
 | 
						|
	hawk_arr_delete(arr, arr->size - 1, 1);
 | 
						|
}
 | 
						|
 | 
						|
#define HEAP_PARENT(x) (((x)-1) / 2)
 | 
						|
#define HEAP_LEFT(x)   ((x)*2 + 1)
 | 
						|
#define HEAP_RIGHT(x)  ((x)*2 + 2)
 | 
						|
 | 
						|
#define HEAP_UPDATE_POS(arr, index) \
 | 
						|
	do { \
 | 
						|
		if (arr->heap_pos_offset != HAWK_ARR_NIL) \
 | 
						|
			*(hawk_oow_t*)((hawk_uint8_t*)DPTR(arr->slot[index]) + arr->heap_pos_offset) = index; \
 | 
						|
	} while(0)
 | 
						|
 | 
						|
static hawk_oow_t sift_up (hawk_arr_t* arr, hawk_oow_t index)
 | 
						|
{
 | 
						|
	hawk_oow_t parent;
 | 
						|
 | 
						|
	if (index > 0)
 | 
						|
	{
 | 
						|
		int n;
 | 
						|
 | 
						|
		parent = HEAP_PARENT(index);
 | 
						|
		n = arr->style->comper(arr, DPTR(arr->slot[index]), DLEN(arr->slot[index]), DPTR(arr->slot[parent]), DLEN(arr->slot[parent]));
 | 
						|
		if (n > 0)
 | 
						|
		{
 | 
						|
			slot_t* tmp;
 | 
						|
 | 
						|
			tmp = arr->slot[index];
 | 
						|
 | 
						|
			while (1)
 | 
						|
			{
 | 
						|
				arr->slot[index] = arr->slot[parent];
 | 
						|
				HEAP_UPDATE_POS(arr, index);
 | 
						|
 | 
						|
				index = parent;
 | 
						|
				parent = HEAP_PARENT(parent);
 | 
						|
 | 
						|
				if (index <= 0) break;
 | 
						|
 | 
						|
				n = arr->style->comper(arr, DPTR(tmp), DLEN(tmp), DPTR(arr->slot[parent]), DLEN(arr->slot[parent]));
 | 
						|
				if (n <= 0) break;
 | 
						|
			}
 | 
						|
 | 
						|
			arr->slot[index] = tmp;
 | 
						|
			HEAP_UPDATE_POS(arr, index);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return index;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_oow_t sift_down (hawk_arr_t* arr, hawk_oow_t index)
 | 
						|
{
 | 
						|
	hawk_oow_t base;
 | 
						|
 | 
						|
	base = arr->size / 2;
 | 
						|
 | 
						|
	if (index < base) /* at least 1 child is under the 'index' position */
 | 
						|
	{
 | 
						|
		slot_t* tmp;
 | 
						|
 | 
						|
		tmp = arr->slot[index];
 | 
						|
 | 
						|
		do
 | 
						|
		{
 | 
						|
			hawk_oow_t left, right, child;
 | 
						|
			int n;
 | 
						|
 | 
						|
			left= HEAP_LEFT(index);
 | 
						|
			right = HEAP_RIGHT(index);
 | 
						|
 | 
						|
			if (right < arr->size)
 | 
						|
			{
 | 
						|
				n = arr->style->comper(arr,
 | 
						|
					DPTR(arr->slot[right]), DLEN(arr->slot[right]),
 | 
						|
					DPTR(arr->slot[left]), DLEN(arr->slot[left]));
 | 
						|
				child = (n > 0)? right: left;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				child = left;
 | 
						|
			}
 | 
						|
 | 
						|
			n = arr->style->comper(arr, DPTR(tmp), DLEN(tmp), DPTR(arr->slot[child]), DLEN(arr->slot[child]));
 | 
						|
			if (n > 0) break;
 | 
						|
 | 
						|
			arr->slot[index] = arr->slot[child];
 | 
						|
			HEAP_UPDATE_POS(arr, index);
 | 
						|
			index = child;
 | 
						|
		}
 | 
						|
		while (index < base);
 | 
						|
 | 
						|
		arr->slot[index] = tmp;
 | 
						|
		HEAP_UPDATE_POS(arr, index);
 | 
						|
	}
 | 
						|
 | 
						|
	return index;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_pushheap (hawk_arr_t* arr, void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	hawk_oow_t index;
 | 
						|
 | 
						|
	/* add a value at the back of the array  */
 | 
						|
	index = arr->size;
 | 
						|
	if (hawk_arr_insert(arr, index, dptr, dlen) == HAWK_ARR_NIL) return HAWK_ARR_NIL;
 | 
						|
	HEAP_UPDATE_POS(arr, index);
 | 
						|
 | 
						|
	HAWK_ASSERT (arr->size == index + 1);
 | 
						|
 | 
						|
	/* move the item upto the top if it's greater than the parent items */
 | 
						|
	sift_up(arr, index);
 | 
						|
	return arr->size;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_arr_popheap (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	HAWK_ASSERT (arr->size > 0);
 | 
						|
	hawk_arr_deleteheap(arr, 0);
 | 
						|
}
 | 
						|
 | 
						|
void hawk_arr_deleteheap (hawk_arr_t* arr, hawk_oow_t index)
 | 
						|
{
 | 
						|
	slot_t* tmp;
 | 
						|
 | 
						|
	HAWK_ASSERT (arr->size > 0);
 | 
						|
	HAWK_ASSERT (index < arr->size);
 | 
						|
 | 
						|
	/* remember the item to destroy */
 | 
						|
	tmp = arr->slot[index];
 | 
						|
 | 
						|
	arr->size = arr->size - 1;
 | 
						|
	if (arr->size > 0 && index != arr->size)
 | 
						|
	{
 | 
						|
		int n;
 | 
						|
 | 
						|
		/* move the last item to the deleting position */
 | 
						|
		arr->slot[index] = arr->slot[arr->size];
 | 
						|
		HEAP_UPDATE_POS(arr, index);
 | 
						|
 | 
						|
		/* move it up if the last item is greater than the item to be deleted,
 | 
						|
		 * move it down otherwise. */
 | 
						|
		n = arr->style->comper(arr, DPTR(arr->slot[index]), DLEN(arr->slot[index]), DPTR(tmp), DLEN(tmp));
 | 
						|
		if (n > 0) sift_up(arr, index);
 | 
						|
		else if (n < 0) sift_down(arr, index);
 | 
						|
	}
 | 
						|
 | 
						|
	/* destroy the actual item */
 | 
						|
	if (arr->style->freeer) arr->style->freeer(arr, DPTR(tmp), DLEN(tmp));
 | 
						|
	hawk_gem_freemem(arr->gem, tmp);
 | 
						|
 | 
						|
	/* empty the last slot */
 | 
						|
	arr->slot[arr->size] = HAWK_NULL;
 | 
						|
	arr->tally--;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_updateheap (hawk_arr_t* arr, hawk_oow_t index, void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	slot_t* tmp;
 | 
						|
	int n;
 | 
						|
 | 
						|
	tmp = arr->slot[index];
 | 
						|
	HAWK_ASSERT (tmp != HAWK_NULL);
 | 
						|
 | 
						|
	n = arr->style->comper(arr, dptr, dlen, DPTR(tmp), DLEN(tmp));
 | 
						|
	if (n)
 | 
						|
	{
 | 
						|
		if (hawk_arr_update(arr, index, dptr, dlen) == HAWK_ARR_NIL) return HAWK_ARR_NIL;
 | 
						|
		HEAP_UPDATE_POS(arr, index);
 | 
						|
 | 
						|
		if (n > 0) sift_up(arr, index);
 | 
						|
		else sift_down(arr, index);
 | 
						|
	}
 | 
						|
 | 
						|
	return index;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_arr_getheapposoffset (hawk_arr_t* arr)
 | 
						|
{
 | 
						|
	return arr->heap_pos_offset;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_arr_setheapposoffset (hawk_arr_t* arr, hawk_oow_t offset)
 | 
						|
{
 | 
						|
	arr->heap_pos_offset = offset;
 | 
						|
}
 |