Landtiger LPC1768 C BigLib 1
A self made, custom C library for the LandTiger board.
 
Loading...
Searching...
No Matches
cl_prioqueue.c File Reference
#include "cl_prioqueue.h"
#include <alloca.h>
#include <stdlib.h>
#include <string.h>

Go to the source code of this file.

Classes

struct  __PQueue
 

Macros

#define RESZ_FACTOR   2
 
#define BASE_CAPACITY   10
 
#define PARENT(i)   ((i - 1) / 2)
 
#define LEFT(i)   (2 * i + 1)
 
#define RIGHT(i)   (2 * i + 2)
 

Functions

_PRIVATE void pSwap (void *const a, void *const b, u32 size)
 
_PRIVATE void bubble_up_leaf (CL_PQueue *const pq)
 
_PRIVATE void bubble_down_root (CL_PQueue *const pq)
 
_PRIVATE void * realloc_data (CL_PQueue *const pq, u32 new_capacity)
 
CL_PQueueCL_PQueueAllocWithCapacity (MEM_Allocator *const alloc, u32 capacity, u32 elem_sz, CL_PQueueCompareFn compare_fn)
 Initializes a priority queue with the allocated memory provided by the user.
 
CL_PQueueCL_PQueueAlloc (MEM_Allocator *const alloc, u32 elem_sz, CL_PQueueCompareFn compare_fn)
 Initializes a priority queue with a default capacity.
 
void CL_PQueueFree (CL_PQueue *const pq)
 Frees the memory previously assigned to the priority queue.
 
CL_Error CL_PQueueEnqueue (CL_PQueue *const pq, const void *const elem)
 Adds an element to the priority queue.
 
CL_Error CL_PQueueDequeue (CL_PQueue *const pq, void *out_elem)
 Removes the element with the highest priority from the priority queue.
 
CL_Error CL_PQueuePeek (const CL_PQueue *const pq, void *out_elem)
 Gets the element with the highest priority from the priority queue without removing it.
 
u32 CL_PQueueSize (const CL_PQueue *const pq)
 Gets the number of elements in the priority queue.
 
bool CL_PQueueIsEmpty (const CL_PQueue *const pq)
 Checks if the priority queue is empty.
 

Macro Definition Documentation

◆ BASE_CAPACITY

#define BASE_CAPACITY   10

Definition at line 18 of file cl_prioqueue.c.

◆ LEFT

#define LEFT (   i)    (2 * i + 1)

Definition at line 26 of file cl_prioqueue.c.

◆ PARENT

#define PARENT (   i)    ((i - 1) / 2)

Definition at line 25 of file cl_prioqueue.c.

◆ RESZ_FACTOR

#define RESZ_FACTOR   2

Definition at line 17 of file cl_prioqueue.c.

◆ RIGHT

#define RIGHT (   i)    (2 * i + 2)

Definition at line 27 of file cl_prioqueue.c.

Function Documentation

◆ bubble_down_root()

_PRIVATE void bubble_down_root ( CL_PQueue *const  pq)

Definition at line 61 of file cl_prioqueue.c.

62{
63 if (!pq)
64 return;
65
66 u32 idx = 0, smallest_idx = 0;
67 u8 *root_elem, *left_elem, *smallest_elem;
68
69 // Comparing the root with its children. If the root has a lower priority
70 // than one of its children, we need to swap them and continue bubbling down.
71 // The parent node is the first element of the array, i.e. at index 0. The left
72 // one follows at index 1, and the right one at index 2, etc. We iterate until
73 // we reach the leaf nodes (i.e. the last level of the tree). Leaf nodes DO NOT
74 // have children, so LEFT (and RIGHT) will be out of bounds. Since LEFT is lower
75 // than RIGHT, we use it as stopping condition.
76 while (LEFT(idx) < pq->size)
77 {
78 root_elem = (u8 *)(pq->data) + (idx * pq->elem_size);
79 left_elem = (u8 *)(pq->data) + (LEFT(idx) * pq->elem_size);
80 smallest_idx = idx;
81
82 // If the left child has a higher priority than the root
83 if (pq->compare_fn(left_elem, root_elem) < 0)
84 smallest_idx = LEFT(idx);
85
86 // Comparing the current smallest (could be the root or the left child) with the right child.
87 if (RIGHT(idx) < pq->size && pq->compare_fn((u8 *)(pq->data) + (RIGHT(idx) * pq->elem_size),
88 (u8 *)(pq->data) + (smallest_idx * pq->elem_size)) < 0)
89 smallest_idx = RIGHT(idx);
90
91 // If the root has a higher priority than both children
92 if (smallest_idx == idx)
93 break; // We're done.
94
95 // Swapping the root with the child that has a higher priority.
96 smallest_elem = (u8 *)(pq->data) + (smallest_idx * pq->elem_size);
97 pSwap(root_elem, smallest_elem, pq->elem_size);
98 idx = smallest_idx; // Moving down the tree.
99 }
100}
#define RIGHT(i)
#define LEFT(i)
_PRIVATE void pSwap(void *const a, void *const b, u32 size)
void * data
CL_PQueueCompareFn compare_fn
The comparison function.
u32 elem_size
uint8_t u8
Definition types.h:8
uint32_t u32
Definition types.h:6

◆ bubble_up_leaf()

_PRIVATE void bubble_up_leaf ( CL_PQueue *const  pq)

Definition at line 40 of file cl_prioqueue.c.

41{
42 if (!pq)
43 return;
44
45 u32 new_idx = pq->size - 1;
46 u8 *parent_elem, *new_elem;
47 while (new_idx > 0)
48 {
49 parent_elem = (u8 *)(pq->data) + (PARENT(new_idx) * pq->elem_size);
50 new_elem = (u8 *)(pq->data) + (new_idx * pq->elem_size);
51 if (pq->compare_fn(new_elem, parent_elem) < 0)
52 pSwap(parent_elem, new_elem, pq->elem_size);
53
54 new_idx = PARENT(new_idx); // Moving up the tree.
55 }
56}
#define PARENT(i)

◆ CL_PQueueAlloc()

CL_PQueue * CL_PQueueAlloc ( MEM_Allocator *const  alloc,
u32  elem_sz,
CL_PQueueCompareFn  compare_fn 
)

Initializes a priority queue with a default capacity.

Parameters
allocThe memory allocator to use.
elem_szThe size of each element.
compare_fnThe comparison function to use for handling priorities.
Returns
Pointer to the new priority queue or NULL on error.

Definition at line 143 of file cl_prioqueue.c.

144{
145 return CL_PQueueAllocWithCapacity(alloc, BASE_CAPACITY, elem_sz, compare_fn);
146}
#define BASE_CAPACITY
CL_PQueue * CL_PQueueAllocWithCapacity(MEM_Allocator *const alloc, u32 capacity, u32 elem_sz, CL_PQueueCompareFn compare_fn)
Initializes a priority queue with the allocated memory provided by the user.

◆ CL_PQueueAllocWithCapacity()

CL_PQueue * CL_PQueueAllocWithCapacity ( MEM_Allocator *const  alloc,
u32  capacity,
u32  elem_sz,
CL_PQueueCompareFn  compare_fn 
)

Initializes a priority queue with the allocated memory provided by the user.

Parameters
allocatorThe memory allocator to use.
capacityThe initial capacity of the priority queue.
elem_szThe size of each element.
compare_fnThe comparison function to use for handling priorities.
Returns
Pointer to the new priority queue or NULL on error.

Definition at line 115 of file cl_prioqueue.c.

117{
118 if (!alloc || !capacity || !elem_sz || !compare_fn)
119 return NULL;
120
121 CL_PQueue *const pq = MEM_Alloc(alloc, sizeof(CL_PQueue));
122 if (!pq)
123 return NULL;
124
125 *pq = (CL_PQueue){
126 .data = MEM_Alloc(alloc, capacity * elem_sz),
127 .size = 0,
128 .capacity = capacity,
129 .elem_size = elem_sz,
130 .compare_fn = compare_fn,
131 .allocator = alloc,
132 };
133
134 if (!pq->data)
135 {
136 MEM_Free(alloc, pq);
137 return NULL;
138 }
139
140 return pq;
141}
void MEM_Free(MEM_Allocator *ma, void *ptr)
Free a previously allocated block.
Definition allocator.c:98
void * MEM_Alloc(MEM_Allocator *ma, u32 size)
Allocate a block of memory from the pool with at least 'size' bytes.
Definition allocator.c:52
struct __PQueue CL_PQueue

◆ CL_PQueueDequeue()

CL_Error CL_PQueueDequeue ( CL_PQueue *const  pq,
void *  out_elem 
)

Removes the element with the highest priority from the priority queue.

Parameters
pqThe priority queue to remove the element from.
out_elem[OUTPUT] The element with the highest priority.
Returns
CL_Error The error code.

Definition at line 179 of file cl_prioqueue.c.

180{
181 if (!pq || !out_elem)
183
184 if (!pq->size)
185 return CL_ERR_EMPTY;
186
187 // Getting the element with the highest priority (i.e. the root of the tree).
188 memcpy(out_elem, pq->data, pq->elem_size);
189 pq->size--;
190
191 // Moving the last element to the root and bubbling it down.
192 const u32 last_elem_offset = pq->size * pq->elem_size;
193 memcpy(pq->data, (u8 *)(pq->data) + last_elem_offset, pq->elem_size);
195 return CL_ERR_OK;
196}
_PRIVATE void bubble_down_root(CL_PQueue *const pq)
@ CL_ERR_EMPTY
Empty collection.
Definition cl_types.h:41
@ CL_ERR_INVALID_PARAMS
Invalid arguments.
Definition cl_types.h:29
@ CL_ERR_OK
No error.
Definition cl_types.h:26

◆ CL_PQueueEnqueue()

CL_Error CL_PQueueEnqueue ( CL_PQueue *const  pq,
const void *const  elem 
)

Adds an element to the priority queue.

Parameters
pqThe priority queue to add the element to.
elemThe element to add.
Returns
CL_Error The error code.

Definition at line 157 of file cl_prioqueue.c.

158{
159 if (!pq || !elem)
161
162 if (pq->size >= pq->capacity)
163 {
164 const u32 new_capacity = pq->capacity * RESZ_FACTOR;
165 if (!realloc_data(pq, new_capacity))
166 return CL_ERR_NO_MEMORY;
167 }
168
169 // Adding the element at the end (queues are FIFO)
170 const u32 offset = pq->size * pq->elem_size;
171 memcpy((u8 *)(pq->data) + offset, elem, pq->elem_size);
172 pq->size++;
173
174 // Bubbling up the new element to its correct position.
175 bubble_up_leaf(pq);
176 return CL_ERR_OK;
177}
_PRIVATE void bubble_up_leaf(CL_PQueue *const pq)
_PRIVATE void * realloc_data(CL_PQueue *const pq, u32 new_capacity)
#define RESZ_FACTOR
@ CL_ERR_NO_MEMORY
No memory available.
Definition cl_types.h:35

◆ CL_PQueueFree()

void CL_PQueueFree ( CL_PQueue *const  pq)

Frees the memory previously assigned to the priority queue.

Parameters
pqThe priority queue to release the memory of.
Note
CL_PQueue does not take ownership of the elements, so it's the user's responsibility to free them.

Definition at line 148 of file cl_prioqueue.c.

149{
150 if (!pq)
151 return;
152
153 MEM_Free(pq->allocator, pq->data);
154 MEM_Free(pq->allocator, pq);
155}
MEM_Allocator * allocator
The memory allocator.

◆ CL_PQueueIsEmpty()

bool CL_PQueueIsEmpty ( const CL_PQueue *const  pq)

Checks if the priority queue is empty.

Parameters
pqThe priority queue to check.
Returns
Whether the priority queue is empty.

Definition at line 216 of file cl_prioqueue.c.

217{
218 return pq ? pq->size == 0 : true;
219}

◆ CL_PQueuePeek()

CL_Error CL_PQueuePeek ( const CL_PQueue *const  pq,
void *  out_elem 
)

Gets the element with the highest priority from the priority queue without removing it.

Parameters
pqThe priority queue to get the element from.
out_elem[OUTPUT] The element with the highest priority.
Returns
CL_Error The error code.

Definition at line 198 of file cl_prioqueue.c.

199{
200 if (!pq || !out_elem)
202
203 if (!pq->size)
204 return CL_ERR_EMPTY;
205
206 // Getting the element with the highest priority (i.e. the root of the tree).
207 memcpy(out_elem, pq->data, pq->elem_size);
208 return CL_ERR_OK;
209}

◆ CL_PQueueSize()

u32 CL_PQueueSize ( const CL_PQueue *const  pq)

Gets the number of elements in the priority queue.

Parameters
pqThe priority queue to get the number of elements from.
Returns
The number of elements in the priority queue.

Definition at line 211 of file cl_prioqueue.c.

212{
213 return pq ? pq->size : 0;
214}

◆ pSwap()

_PRIVATE void pSwap ( void *const  a,
void *const  b,
u32  size 
)
inline

Definition at line 29 of file cl_prioqueue.c.

30{
31 void *temp = alloca(size);
32 memcpy(temp, a, size);
33 memcpy(a, b, size);
34 memcpy(b, temp, size);
35}

◆ realloc_data()

_PRIVATE void * realloc_data ( CL_PQueue *const  pq,
u32  new_capacity 
)
inline

Definition at line 102 of file cl_prioqueue.c.

103{
104 void *new_data = MEM_Realloc(pq->allocator, pq->data, new_capacity * pq->elem_size);
105 if (!new_data)
106 return NULL;
107
108 pq->data = new_data;
109 pq->capacity = new_capacity;
110 return new_data;
111}
void * MEM_Realloc(MEM_Allocator *ma, void *ptr, u32 new_size)
Reallocate a previously allocated block to a new size.
Definition allocator.c:131