-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathscl_stack.c
353 lines (295 loc) · 10.1 KB
/
scl_stack.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
/**
* @file scl_stack.c
* @author Mihai Negru (determinant289@gmail.com)
* @version 1.0.0
* @date 2022-06-21
*
* @copyright Copyright (C) 2022-2023 Mihai Negru <determinant289@gmail.com>
* This file is part of C-language-Data-Structures.
*
* C-language-Data-Structures is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* C-language-Data-Structures 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with C-language-Data-Structures. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "./include/scl_stack.h"
/**
* @brief Create a stack object. Allocation may fail
* if there is not enough memory on heap, in this case
* an exception will be thrown
*
* @param frd pointer to a function to free content of one data
* @param data_size length in bytes of the data data type
* @return sstack_t* a new allocated stack object or `NULL` (if function failed)
*/
sstack_t* create_stack(free_func frd, size_t data_size) {
if (0 == data_size) {
return NULL;
}
/* Allocate a new stack on the heap */
sstack_t *new_stack = malloc(sizeof(*new_stack));
/* Check if stack allocation went right */
if (NULL != new_stack) {
/* Set function pointers */
new_stack->frd = frd;
/* Set top and size of an empty stack */
new_stack->top = NULL;
new_stack->data_size = data_size;
new_stack->size = 0;
} else {
errno = ENOMEM;
perror("Not enough memory for stack allocation");
}
/* Return a new allocated stack or `NULL` */
return new_stack;
}
/**
* @brief Create a stack node object. Allocation of a new node
* may fail if address of data is not valid or if not enough
* memory is left on heap, in this case function will return `NULL`
* and an exception will be thrown
*
* @param stack an allocated stack object
* @param data pointer to an address of a generic data
* @return stack_node_t* new allocated stack node object or `NULL`
*/
static stack_node_t* create_stack_node(const sstack_t * const __restrict__ stack, const void * __restrict__ data) {
/* Check if data address is valid */
if (NULL == data) {
return NULL;
}
/* Allocate a new node on the heap */
stack_node_t *new_node = malloc(sizeof(*new_node));
/* Check if node allocation went successfully */
if (NULL != new_node) {
/* Set default next pointer */
new_node->next = NULL;
/* Allocate heap memory for data */
new_node->data = malloc(stack->data_size);
/* Check if memory allocation went right */
if (NULL != new_node->data) {
/* Copy all bytes from data address to new node's data */
memcpy(new_node->data, data, stack->data_size);
} else {
free(new_node);
new_node = NULL;
errno = ENOMEM;
perror("Not enough memory for data node stack allocation");
}
} else {
errno = ENOMEM;
perror("Not enough memory for stack node allocation");
}
/* Return a new stack node object or `NULL` */
return new_node;
}
/**
* @brief Function to free every byte of memory allocated for a specific
* stack object. The function will iterate through all nodes and will
* free the data content according to frd function provided by user at
* creation of stack, however if no free function was provided it means
* that data pointer does not contain any dinamically allocated elements.
*
* @param stack an allocated stack object
* @return scl_error_t enum object for handling errors
*/
scl_error_t free_stack(sstack_t * const __restrict__ stack) {
/* Check if stack needs to be freed */
if (NULL != stack) {
/* Iterate through every node from stack */
while (NULL != stack->top) {
stack_node_t *iterator = stack->top;
/* Update new top of the stack */
stack->top = stack->top->next;
/* Free content of data if necessary */
if ((NULL != stack->frd) && (NULL != iterator->data)) {
stack->frd(iterator->data);
}
/* Free node pointer to data */
if (NULL != iterator->data) {
free(iterator->data);
}
/* Set node pointer to data as `NULL` */
iterator->data = NULL;
/* Free node pointer */
if (NULL != iterator) {
free(iterator);
}
/* Set node pointer as `NULL` */
iterator = NULL;
}
/* Free stack object */
free(stack);
return SCL_OK;
}
return SCL_NULL_STACK;
}
/**
* @brief Function prints all elements within the
* given stack according to printData function. Function
* may fail if list is not allocated in this case function
* will not print anywith on output. In case if list is empty
* then a set of paired square brakets will be printed on output.
*
* @param stack a stack object
* @param print a pointer to a function to print content of data pointer
* @return scl_error_t enum object for handling errors
*/
scl_error_t print_stack(const sstack_t * const __restrict__ stack, action_func print) {
/* Check if input data is valid */
if (NULL == stack) {
return SCL_NULL_STACK;
}
if (NULL == print) {
return SCL_NULL_ACTION_FUNC;
}
/* Stack is empty, print [] */
if (NULL == stack->top) {
printf("[ ]");
} else {
const stack_node_t *iterator = stack->top;
/*
* Print every node according
* to print function
*/
while (NULL != iterator) {
print(iterator->data);
iterator = iterator->next;
}
}
return SCL_OK;
}
/**
* @brief Function to check if a stack object
* is empty or not. The function tests if top of stack
* is `NULL` in that case function will return true, otherwise
* it will return false. A `NULL` stack is also considered as an
* empty stack
*
* @param stack a stack object
* @return uint8_t 1(True) if stack is not allocated or empty and 0(False) otherwise
*/
uint8_t is_stack_empty(const sstack_t * const __restrict__ stack) {
if ((NULL == stack) || (NULL == stack->top)) {
return 1;
}
return 0;
}
/**
* @brief Get the stack size object. If stack is not
* allocated then function will return SIZE_MAX value.
*
* @param stack a stack object
* @return size_t SIZE_MAX if stack is not allocated or
* stack size
*/
size_t get_stack_size(const sstack_t * const __restrict__ stack) {
if (NULL == stack) {
return SIZE_MAX;
}
return stack->size;
}
/**
* @brief Function to return a pointer to data of the
* top node. If stack is not allocated or stack is empty
* then `NULL` will be returned, otherwise a pointer to the actual
* data memory location will be returned
*
* @param stack a stack object
* @return const void* a pointer to top element data
*/
const void* stack_top(const sstack_t * const __restrict__ stack) {
if ((NULL == stack) || (NULL == stack->top)) {
return NULL;
}
return stack->top->data;
}
/**
* @brief Function to push one generic data to a stack.
* Function may fail if stack or data is not valid (have
* address `NULL`) or not enough heap memory is left.
*
* @param stack a stack object
* @param data pointer to an address of a generic data type
* @return scl_error_t enum object for handling errors
*/
scl_error_t stack_push(sstack_t * const __restrict__ stack, const void * __restrict__ data) {
/* Check if stack and data addresses are valid */
if (NULL == stack) {
return SCL_NULL_STACK;
}
if (NULL == data) {
return SCL_INVALID_DATA;
}
/* Create a new stack node */
stack_node_t *new_node = create_stack_node(stack, data);
/* Check if new node was allocated */
if (NULL == new_node) {
return SCL_NOT_ENOUGHT_MEM_FOR_NODE;
}
/* Insert node into stack */
if (NULL == stack->top) {
/* Stack is empty */
stack->top = new_node;
} else {
/* Update top links */
new_node->next = stack->top;
stack->top = new_node;
}
/* Increase stack size */
++(stack->size);
/* Pushing went successfully */
return SCL_OK;
}
/**
* @brief Function to pop one genric data from a stack.
* Function may fail if stack or data is not valid (have
* address `NULL`). Function will remove the top element from the stack
* and will clear the content of the data accroding to frd
* function provided by the user at creation of the stack.
*
* @param stack a stack object
* @return scl_error_t enum object for handling errors
*/
scl_error_t stack_pop(sstack_t * const __restrict__ stack) {
/* Check if stack is allocated and it is not empty */
if (NULL == stack) {
return SCL_NULL_STACK;
}
if ((NULL == stack->top) || (0 == stack->size)) {
return SCL_DELETE_FROM_EMPTY_OBJECT;
}
/* Pointer to current wipe node */
stack_node_t *delete_node = stack->top;
/* Update the top pointer of the stack */
stack->top = stack->top->next;
/* Decrease stack size */
--(stack->size);
/* Free content of the data if necessary */
if ((NULL != stack->frd) && (NULL != delete_node->data)) {
stack->frd(delete_node->data);
}
/* Free pointer to data memory location */
if (NULL != delete_node->data) {
free(delete_node->data);
}
/* Set data pointer to default value */
delete_node->data = NULL;
/* Free node memory */
if (NULL != delete_node) {
free(delete_node);
}
/* Set node poiner to default value */
delete_node = NULL;
/* Popping went successfully */
return SCL_OK;
}