added qse_arr_setheapposoffset()
This commit is contained in:
		| @ -149,6 +149,8 @@ struct qse_arr_t | ||||
| 	qse_arr_keeper_t keeper; /* data keeper */ | ||||
| 	qse_arr_sizer_t  sizer;  /* size calculator */ | ||||
| 	qse_byte_t       scale;  /* scale factor */ | ||||
| 	qse_size_t       heap_pos_offset; /* offset in the data element where position  | ||||
| 	                                   * is stored when heap operation is performed. */ | ||||
| 	qse_size_t       size;   /* number of items */ | ||||
| 	qse_size_t       capa;   /* capacity */ | ||||
| 	qse_arr_slot_t** slot; | ||||
| @ -446,6 +448,36 @@ QSE_EXPORT qse_size_t qse_arr_updateheap ( | ||||
| 	qse_size_t dlen | ||||
| ); | ||||
|  | ||||
| QSE_EXPORT qse_size_t qse_arr_getheapposoffset ( | ||||
| 	qse_arr_t* arr | ||||
| ); | ||||
|  | ||||
| /** | ||||
|  * The qse_arr_setheapposoffset() function sets the offset to a position holding  | ||||
|  * field within a data element. It assumes that the field is of the qse_size_t type. | ||||
|  * | ||||
|  * \code | ||||
|  * struct data_t | ||||
|  * { | ||||
|  *    int v; | ||||
|  *    qse_size_t pos; | ||||
|  * }; | ||||
|  * struct data_t d; | ||||
|  * qse_arr_setheapposoffset (arr, QSE_OFFSETOF(struct data_t, pos));  | ||||
|  * d.v = 20; | ||||
|  * qse_arr_pushheap (arr, &d, 1); | ||||
|  * \endcode | ||||
|  *  | ||||
|  * In the code above, the 'pos' field of the first element in the array must be 0. | ||||
|  *  | ||||
|  * If it's set to QSE_ARR_NIL, position is not updated when heapification is  | ||||
|  * performed.   | ||||
|  */ | ||||
| QSE_EXPORT void qse_arr_setheapposoffset ( | ||||
| 	qse_arr_t* arr, | ||||
| 	qse_size_t offset | ||||
| ); | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -135,6 +135,7 @@ int qse_arr_init (arr_t* arr, mmgr_t* mmgr, size_t capa) | ||||
| 	arr->capa = 0; | ||||
| 	arr->slot = QSE_NULL; | ||||
| 	arr->scale = 1; | ||||
| 	arr->heap_pos_offset = QSE_ARR_NIL; | ||||
|  | ||||
| 	arr->copier = QSE_ARR_COPIER_SIMPLE; | ||||
| 	arr->comper = default_comparator; | ||||
| @ -608,13 +609,20 @@ void qse_arr_popstack (arr_t* arr) | ||||
| #define HEAP_LEFT(x)   ((x)*2 + 1) | ||||
| #define HEAP_RIGHT(x)  ((x)*2 + 2) | ||||
|  | ||||
| size_t sift_up (arr_t* arr, size_t index) | ||||
| #define HEAP_UPDATE_POS(arr, index) \ | ||||
| 	do { \ | ||||
| 		if (arr->heap_pos_offset != QSE_ARR_NIL) \ | ||||
| 			*(qse_size_t*)((qse_byte_t*)DPTR(arr->slot[index]) + arr->heap_pos_offset) = index; \ | ||||
| 	} while(0) | ||||
|  | ||||
| qse_size_t sift_up (arr_t* arr, qse_size_t index) | ||||
| { | ||||
| 	size_t parent; | ||||
| 	int n; | ||||
| 	qse_size_t parent; | ||||
|  | ||||
| 	if (index > 0) | ||||
| 	{ | ||||
| 		int n; | ||||
|  | ||||
| 		parent = HEAP_PARENT(index); | ||||
| 		n = arr->comper (arr, | ||||
| 			DPTR(arr->slot[index]), DLEN(arr->slot[index]), | ||||
| @ -628,6 +636,7 @@ size_t sift_up (arr_t* arr, size_t index) | ||||
| 			while (1) | ||||
| 			{ | ||||
| 				arr->slot[index] = arr->slot[parent]; | ||||
| 				HEAP_UPDATE_POS (arr, index); | ||||
|  | ||||
| 				index = parent; | ||||
| 				parent = HEAP_PARENT(parent); | ||||
| @ -641,6 +650,7 @@ size_t sift_up (arr_t* arr, size_t index) | ||||
| 			}  | ||||
|  | ||||
| 			arr->slot[index] = tmp; | ||||
| 			HEAP_UPDATE_POS (arr, index); | ||||
| 		} | ||||
| 	} | ||||
| 	return index; | ||||
| @ -684,11 +694,13 @@ size_t sift_down (arr_t* arr, size_t index) | ||||
| 			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; | ||||
| @ -701,6 +713,7 @@ size_t qse_arr_pushheap (arr_t* arr, void* dptr, size_t dlen) | ||||
| 	/* add a value at the back of the array  */ | ||||
| 	index = arr->size; | ||||
| 	if (qse_arr_insert (arr, index, dptr, dlen) == QSE_ARR_NIL) return QSE_ARR_NIL; | ||||
| 	HEAP_UPDATE_POS (arr, index); | ||||
|  | ||||
| 	QSE_ASSERT (arr->size == index + 1); | ||||
|  | ||||
| @ -715,7 +728,7 @@ void qse_arr_popheap (arr_t* arr) | ||||
| 	qse_arr_deleteheap (arr, 0); | ||||
| } | ||||
|  | ||||
| void qse_arr_deleteheap (arr_t* arr, size_t index) | ||||
| void qse_arr_deleteheap (arr_t* arr, qse_size_t index) | ||||
| { | ||||
| 	slot_t* tmp; | ||||
|  | ||||
| @ -732,6 +745,7 @@ void qse_arr_deleteheap (arr_t* arr, size_t index) | ||||
|  | ||||
| 		/* 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. */ | ||||
| @ -750,7 +764,7 @@ void qse_arr_deleteheap (arr_t* arr, size_t index) | ||||
| 	arr->slot[arr->size] = QSE_NULL; | ||||
| } | ||||
|  | ||||
| size_t qse_arr_updateheap (qse_arr_t* arr, qse_size_t index, void* dptr, qse_size_t dlen) | ||||
| qse_size_t qse_arr_updateheap (qse_arr_t* arr, qse_size_t index, void* dptr, qse_size_t dlen) | ||||
| { | ||||
| 	slot_t* tmp; | ||||
| 	int n; | ||||
| @ -762,9 +776,21 @@ size_t qse_arr_updateheap (qse_arr_t* arr, qse_size_t index, void* dptr, qse_siz | ||||
| 	if (n) | ||||
| 	{ | ||||
| 		if (qse_arr_update (arr, index, dptr, dlen) == QSE_ARR_NIL) return QSE_ARR_NIL; | ||||
| 		HEAP_UPDATE_POS (arr, index); | ||||
|  | ||||
| 		if (n > 0) sift_up (arr, index); | ||||
| 		else sift_down (arr, index); | ||||
| 	} | ||||
|  | ||||
| 	return index; | ||||
| } | ||||
|  | ||||
| qse_size_t qse_arr_getheapposoffset (qse_arr_t* arr) | ||||
| { | ||||
| 	return arr->heap_pos_offset; | ||||
| } | ||||
|  | ||||
| void qse_arr_setheapposoffset (qse_arr_t* arr, qse_size_t offset) | ||||
| { | ||||
| 	arr->heap_pos_offset = offset; | ||||
| } | ||||
|  | ||||
| @ -19,20 +19,20 @@ void keeper1 (qse_arr_t* arr, void* dptr, qse_size_t dlen) | ||||
| qse_arr_walk_t walker1 (qse_arr_t* arr, qse_size_t index, void* arg) | ||||
| { | ||||
| 	qse_printf (QSE_T("%d => [%.*s]\n"),  | ||||
| 		index, (int)QSE_ARR_DLEN(arr,index), QSE_ARR_DPTR(arr,index)); | ||||
| 		(int)index, (int)QSE_ARR_DLEN(arr,index), QSE_ARR_DPTR(arr,index)); | ||||
| 	return QSE_ARR_WALK_FORWARD; | ||||
| } | ||||
| qse_arr_walk_t rwalker1 (qse_arr_t* arr, qse_size_t index, void* arg) | ||||
| { | ||||
| 	qse_printf (QSE_T("%d => [%.*s]\n"),  | ||||
| 		index, (int)QSE_ARR_DLEN(arr,index), QSE_ARR_DPTR(arr,index)); | ||||
| 		(int)index, (int)QSE_ARR_DLEN(arr,index), QSE_ARR_DPTR(arr,index)); | ||||
| 	return QSE_ARR_WALK_BACKWARD; | ||||
| } | ||||
|  | ||||
| qse_arr_walk_t walker3 (qse_arr_t* arr, qse_size_t index, void* arg) | ||||
| { | ||||
| 	qse_printf (QSE_T("%d => [%d]\n"),  | ||||
| 		index, *(int*)QSE_ARR_DPTR(arr,index)); | ||||
| 		(int)index, *(int*)QSE_ARR_DPTR(arr,index)); | ||||
| 	return QSE_ARR_WALK_FORWARD; | ||||
| } | ||||
|  | ||||
| @ -476,6 +476,113 @@ static int test5 () | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| struct test6_data_t | ||||
| { | ||||
| 	int v; | ||||
| 	qse_size_t pos;	 | ||||
| }; | ||||
| typedef struct test6_data_t test6_data_t; | ||||
|  | ||||
| static int test6_comparator (qse_arr_t* arr, | ||||
|         const void* dptr1, size_t dlen1, | ||||
|         const void* dptr2, size_t dlen2) | ||||
| { | ||||
| 	return ((test6_data_t*)dptr1)->v > ((test6_data_t*)dptr2)->v? 1: | ||||
| 	       ((test6_data_t*)dptr1)->v < ((test6_data_t*)dptr2)->v? -1: 0; | ||||
| } | ||||
|  | ||||
| qse_arr_walk_t test6_walker (qse_arr_t* arr, qse_size_t index, void* arg) | ||||
| { | ||||
| 	test6_data_t* x; | ||||
|  | ||||
| 	x = QSE_ARR_DPTR(arr,index); | ||||
| 	qse_printf (QSE_T("%d => [%d] pos=%d\n"), (int)index, (int)x->v, (int)x->pos); | ||||
| 	QSE_ASSERT (index == x->pos); | ||||
| 	return QSE_ARR_WALK_FORWARD; | ||||
| } | ||||
|  | ||||
| static int test6 () | ||||
| { | ||||
| 	qse_arr_t* s1; | ||||
| 	int i, oldv, newv; | ||||
| 	test6_data_t j; | ||||
|  | ||||
| 	s1 = qse_arr_open (QSE_MMGR_GETDFL(), 0, 3); | ||||
| 	if (s1 == QSE_NULL) | ||||
| 	{ | ||||
| 		qse_printf (QSE_T("cannot open an array\n")); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	qse_arr_setcopier (s1, QSE_ARR_COPIER_INLINE); | ||||
| 	qse_arr_setscale (s1, QSE_SIZEOF(j)); | ||||
| 	qse_arr_setcomper (s1, test6_comparator); | ||||
| 	qse_arr_setheapposoffset (s1, QSE_OFFSETOF(test6_data_t, pos)); | ||||
|  | ||||
| 	for (i = 0; i < 100; i++) | ||||
| 	{ | ||||
| 		j.v = rand () % 65535; | ||||
| 		qse_arr_pushheap (s1, &j, 1); | ||||
| 	} | ||||
|  | ||||
| 	j.v = 88888888; | ||||
| 	qse_arr_updateheap (s1, QSE_ARR_SIZE(s1) / 2, &j, 1); | ||||
| 	j.v = -123; | ||||
| 	qse_arr_updateheap (s1, QSE_ARR_SIZE(s1) / 2, &j, 1); | ||||
|  | ||||
| 	qse_printf (QSE_T("arr size => %lu\n"), QSE_ARR_SIZE(s1)); | ||||
| 	qse_arr_walk (s1, test6_walker, QSE_NULL); | ||||
|  | ||||
| 	oldv = 99999999; | ||||
| 	while (QSE_ARR_SIZE(s1) > 50) | ||||
| 	{ | ||||
| 		newv = ((test6_data_t*)QSE_ARR_DPTR(s1,0))->v; | ||||
| 		qse_printf (QSE_T("top => %d prevtop => %d\n"), newv, oldv); | ||||
| 		QSE_ASSERT (newv <= oldv); | ||||
| 		qse_arr_popheap (s1); | ||||
| 		oldv = newv; | ||||
| 	} | ||||
|  | ||||
| 	qse_printf (QSE_T("arr size => %lu\n"), QSE_ARR_SIZE(s1)); | ||||
| 	qse_arr_walk (s1, test6_walker, QSE_NULL); | ||||
|  | ||||
| 	while (QSE_ARR_SIZE(s1) > 10) | ||||
| 	{ | ||||
| 		newv = ((test6_data_t*)QSE_ARR_DPTR(s1,0))->v; | ||||
| 		qse_printf (QSE_T("top => %d prevtop => %d\n"), newv, oldv); | ||||
| 		QSE_ASSERT (newv <= oldv); | ||||
| 		qse_arr_popheap (s1); | ||||
| 		oldv = newv; | ||||
| 	} | ||||
|  | ||||
| 	qse_printf (QSE_T("arr size => %lu\n"), QSE_ARR_SIZE(s1)); | ||||
| 	qse_arr_walk (s1, test6_walker, QSE_NULL); | ||||
|  | ||||
| 	while (QSE_ARR_SIZE(s1) > 1) | ||||
| 	{ | ||||
| 		newv = ((test6_data_t*)QSE_ARR_DPTR(s1,0))->v; | ||||
| 		qse_printf (QSE_T("top => %d prevtop => %d\n"), newv, oldv); | ||||
| 		QSE_ASSERT (newv <= oldv); | ||||
| 		qse_arr_popheap (s1); | ||||
| 		oldv = newv; | ||||
| 	} | ||||
|  | ||||
| 	qse_printf (QSE_T("arr size => %lu\n"), QSE_ARR_SIZE(s1)); | ||||
| 	qse_arr_walk (s1, test6_walker, QSE_NULL); | ||||
|  | ||||
| 	while (QSE_ARR_SIZE(s1) > 0) | ||||
| 	{ | ||||
| 		newv = ((test6_data_t*)QSE_ARR_DPTR(s1,0))->v; | ||||
| 		qse_printf (QSE_T("top => %d prevtop => %d\n"), newv, oldv); | ||||
| 		QSE_ASSERT (newv <= oldv); | ||||
| 		qse_arr_popheap (s1); | ||||
| 		oldv = newv; | ||||
| 	} | ||||
|  | ||||
| 	qse_arr_close (s1); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int main () | ||||
| { | ||||
| 	qse_openstdsios (); | ||||
| @ -484,6 +591,7 @@ int main () | ||||
| 	R (test3); | ||||
| 	R (test4); | ||||
| 	R (test5); | ||||
| 	R (test6); | ||||
| 	qse_closestdsios (); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user