efl
468 строк · 11.1 Кб
1#ifdef HAVE_CONFIG_H2# include <config.h>3#endif4
5#include <stdlib.h>6#include <string.h>7#include <stdint.h>8
9#include "Ecore_Data.h"10
11#define HEAP_INCREMENT 409612
13#define PARENT(i) (i / 2)14#define LEFT(i) (2 * i)15#define RIGHT(i) (2 * i + 1)16
17static void _ecore_sheap_heapify(Ecore_Sheap *heap, int i);18static void _ecore_sheap_update_data(Ecore_Sheap *heap);19
20/**
21* Allocate and initialize a new binary heap
22* @param compare The function for comparing keys, NULL for direct comparison
23* @param size The number of elements to allow in the heap
24* @return A pointer to the newly allocated binary heap on success, NULL on
25* failure.
26*/
27EAPI Ecore_Sheap *28ecore_sheap_new(Ecore_Compare_Cb compare, int size)29{
30Ecore_Sheap *heap = NULL;31
32heap = (Ecore_Sheap *)malloc(sizeof(Ecore_Sheap));33if (!heap)34return NULL;35
36memset(heap, 0, sizeof(Ecore_Sheap));37
38if (!ecore_sheap_init(heap, compare, size))39{40FREE(heap);41return NULL;42}43
44return heap;45}
46
47/**
48* Initialize a binary heap to default values
49* @param heap The heap to initialize
50* @param compare The function for comparing keys, NULL for direct comparison
51* @param size The number of elements to allow in the heap
52* @return TRUE on success, FALSE on failure
53*/
54EAPI int55ecore_sheap_init(Ecore_Sheap *heap, Ecore_Compare_Cb compare, int size)56{
57CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);58
59heap->space = size;60if (!compare)61heap->compare = ecore_direct_compare;62else63heap->compare = compare;64
65heap->order = ECORE_SORT_MIN;66
67heap->data = (void **)malloc(heap->space * sizeof(void *));68if (!heap->data)69return FALSE;70
71memset(heap->data, 0, heap->space * sizeof(void *));72
73return TRUE;74}
75
76/**
77* Free up the memory used by the heap
78*
79* Frees the memory used by @a heap, calls the destroy function on each data
80* item if necessary.
81*
82* @param heap The heap to be freed
83*/
84EAPI void85ecore_sheap_destroy(Ecore_Sheap *heap)86{
87int i;88
89CHECK_PARAM_POINTER("heap", heap);90
91/*92* Free data in heap
93*/
94if (heap->free_func)95for (i = 0; i < heap->size; i++)96heap->free_func(heap->data[i]);97
98FREE(heap->data);99
100FREE(heap);101}
102
103/**
104* Set the function for freeing data.
105* @param heap The heap that will use this function when nodes are
106* destroyed.
107* @param free_func The function that will free the key data.
108* @return @c TRUE on successful set, @c FALSE otherwise.
109*/
110EAPI int111ecore_sheap_free_cb_set(Ecore_Sheap *heap, Ecore_Free_Cb free_func)112{
113CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);114
115heap->free_func = free_func;116
117return TRUE;118}
119
120/**
121* Insert new data into the heap.
122* @param heap The heap to insert @a data.
123* @param data The data to add to @a heap.
124* @return TRUE on success, NULL on failure. Increases the size of the heap if
125* it becomes larger than available space.
126*/
127EAPI int128ecore_sheap_insert(Ecore_Sheap *heap, void *data)129{
130int i;131void *temp;132int parent;133int position;134
135CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);136
137/*138* Increase the size of the allocated data area if there isn't enough
139* space available to add this data
140*/
141if (heap->size >= heap->space)142return FALSE;143
144heap->sorted = FALSE;145
146/*147* Place the data at the end of the heap initially. Then determine the
148* parent and position in the array of it's parent.
149*/
150heap->data[heap->size] = data;151position = heap->size;152heap->size++;153i = heap->size;154parent = PARENT(i) - 1;155
156/*157* Check the order of the heap to decide where to place the inserted
158* data. The loop is placed inside the if statement to reduce the
159* number of branching decisions that must be predicted.
160*/
161if (heap->order == ECORE_SORT_MIN)162while ((position > 0) && heap->compare(heap->data[parent],163heap->data[position]) > 0)164{165
166/*167* Swap the data with it's parents to move it up in
168* the heap.
169*/
170temp = heap->data[position];171heap->data[position] = heap->data[parent];172heap->data[parent] = temp;173
174/*175* Now determine the new position for the next
176* iteration of the loop, as well as it's parents
177* position.
178*/
179i = PARENT(i);180position = i - 1;181parent = PARENT(i) - 1;182}183else184while ((position > 0) && heap->compare(heap->data[parent],185heap->data[position]) < 0)186{187
188/*189* Swap the data with it's parents to move it up in
190* the heap.
191*/
192temp = heap->data[position];193heap->data[position] = heap->data[PARENT(i) - 1];194heap->data[PARENT(i) - 1] = temp;195
196/*197* Now determine the new position for the next
198* iteration of the loop, as well as it's parents
199* position.
200*/
201i = PARENT(i);202position = i - 1;203parent = PARENT(i) - 1;204}205
206return TRUE;207}
208
209/**
210* Extract the item at the top of the heap
211* @param heap The heap to remove the top item
212* @return The top item of the heap on success, NULL on failure.
213* @note The extract function maintains the heap properties after the
214* extract.
215*/
216EAPI void *217ecore_sheap_extract(Ecore_Sheap *heap)218{
219void *extreme;220
221if (heap->size < 1)222return NULL;223
224heap->sorted = FALSE;225
226extreme = heap->data[0];227heap->size--;228heap->data[0] = heap->data[heap->size];229
230_ecore_sheap_heapify(heap, 1);231
232return extreme;233}
234
235/**
236* Examine the item at the top of the heap
237* @param heap The heap to examine the top item
238* @return The top item of the heap on success, NULL on failure.
239* @note The function does not alter the heap.
240*/
241EAPI void *242ecore_sheap_extreme(Ecore_Sheap *heap)243{
244if (heap->size < 1)245return NULL;246
247return heap->data[0];248}
249
250/**
251* Change the value of the specified item in the heap
252* @param heap The heap to search for the item to change
253* @param item The item in the heap to change
254* @param newval The new value assigned to the item in the heap
255* @return TRUE on success, FALSE on failure.
256* @note The heap does not free the old data since it must be passed
257* in, so the caller can perform the free if desired.
258*/
259EAPI int260ecore_sheap_change(Ecore_Sheap *heap, void *item, void *newval)261{
262int i;263
264CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);265
266for (i = 0; i < heap->size && heap->compare(heap->data[i], item); i++) ;267
268if (i < heap->size)269heap->data[i] = newval;270else271return FALSE;272
273/*274* FIXME: This is not the correct procedure when a change occurs.
275*/
276_ecore_sheap_heapify(heap, 1);277
278return TRUE;279}
280
281/**
282* Change the comparison function for the heap
283* @param heap The heap to change comparison function
284* @param compare The new function for comparing nodes
285* @return TRUE on success, FALSE on failure.
286*
287* The comparison function is changed to @compare and the heap is heapified
288* by the new comparison.
289*/
290EAPI int291ecore_sheap_compare_set(Ecore_Sheap *heap, Ecore_Compare_Cb compare)292{
293CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);294
295if (!compare)296heap->compare = ecore_direct_compare;297else298heap->compare = compare;299
300_ecore_sheap_update_data(heap);301
302return TRUE;303}
304
305/**
306* Change the order of the heap
307* @param heap The heap to change the order
308* @param order The new order of the heap
309*
310* Changes the heap order of @heap and re-heapifies the data to this new
311* order. The default order is a min heap.
312*/
313EAPI void314ecore_sheap_order_set(Ecore_Sheap *heap, char order)315{
316CHECK_PARAM_POINTER("heap", heap);317
318heap->order = order;319
320_ecore_sheap_update_data(heap);321}
322
323/**
324* Sort the data in the heap
325* @param heap The heap to be sorted
326*
327* Sorts the data in the heap into the order that is used for the heap's
328* data.
329*/
330EAPI void331ecore_sheap_sort(Ecore_Sheap *heap)332{
333int i = 0;334void **new_data;335
336CHECK_PARAM_POINTER("heap", heap);337
338new_data = (void **)malloc(heap->size * sizeof(void *));339
340/*341* Extract the heap and insert into the new data array in order.
342*/
343while (heap->size > 0)344new_data[i++] = ecore_sheap_extract(heap);345
346/*347* Free the old data array and update the heap with the new data, also
348* mark as sorted.
349*/
350FREE(heap->data);351heap->data = new_data;352heap->size = i;353heap->sorted = TRUE;354}
355
356/*
357* Access the item at the ith position in the heap
358* @param heap The heap to access the internal data
359* @param i The index of the data within the heap
360* @return The data located at the ith position within @heap on success,
361* NULL on failure.
362* @note The data is guaranteed to be in sorted order.
363*/
364EAPI inline void *365ecore_sheap_item(Ecore_Sheap *heap, int i)366{
367if (i >= heap->size)368return NULL;369
370/*371* Make sure the data is sorted so we return the correct value.
372*/
373if (!heap->sorted)374ecore_sheap_sort(heap);375
376return heap->data[i];377}
378
379/*
380* Regain the heap properties starting at position i
381* @param heap The heap to regain heap properties
382* @param i The position to start heapifying
383*/
384static void385_ecore_sheap_heapify(Ecore_Sheap *heap, int i)386{
387int extreme;388int left = LEFT(i);389int right = RIGHT(i);390
391if (heap->order == ECORE_SORT_MIN)392{393if (left <= heap->size && heap->compare(heap->data[left - 1],394heap->data[i - 1]) < 0)395extreme = left;396else397extreme = i;398
399if (right <= heap->size && heap->compare(heap->data[right - 1],400heap->data[extreme - 1]) < 0)401extreme = right;402}403else404{405if (left <= heap->size && heap->compare(heap->data[left - 1],406heap->data[i - 1]) > 0)407extreme = left;408else409extreme = i;410
411if (right <= heap->size && heap->compare(heap->data[right - 1],412heap->data[extreme - 1]) > 0)413extreme = right;414}415
416/*417* If the data needs to be swapped down the heap, recurse on
418* heapifying it's new placement.
419*/
420if (extreme != i)421{422void *temp;423
424temp = heap->data[extreme - 1];425heap->data[extreme - 1] = heap->data[i - 1];426heap->data[i - 1] = temp;427
428_ecore_sheap_heapify(heap, extreme);429}430}
431
432static void433_ecore_sheap_update_data(Ecore_Sheap *heap)434{
435int i, old_size;436void **data;437
438/*439* Track the old values from the heap
440*/
441old_size = heap->size;442data = heap->data;443
444heap->size = 0;445heap->data = malloc(heap->space * sizeof(void *));446
447for (i = 0; i < old_size; i++)448ecore_sheap_insert(heap, data[i]);449
450FREE(data);451}
452
453int
454ecore_direct_compare(const void *key1, const void *key2)455{
456uintptr_t k1, k2;457
458k1 = (uintptr_t)key1;459k2 = (uintptr_t)key2;460
461if (k1 > k2)462return 1;463
464if (k1 < k2)465return -1;466
467return 0;468}
469