Nyx Node
Loading...
Searching...
No Matches
object.c
1/* NyxNode
2 * Author: Jérôme ODIER <jerome.odier@lpsc.in2p3.fr>
3 * SPDX-License-Identifier: GPL-2.0-only (Mongoose backend) or GPL-3.0+
4 */
5
6/*--------------------------------------------------------------------------------------------------------------------*/
7
8#include <math.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#ifdef HAVE_MALLOC_SIZE
14# include <stdatomic.h>
15
16size_t malloc_size(void *);
17#endif
18
19#ifdef HAVE_MALLOC_USABLE_SIZE
20# include <stdatomic.h>
21
22size_t malloc_usable_size(void *);
23#endif
24
25#include "nyx_node_internal.h"
26
27/*--------------------------------------------------------------------------------------------------------------------*/
28/* MEMORY */
29/*--------------------------------------------------------------------------------------------------------------------*/
30
31#if defined(HAVE_MALLOC_SIZE) || defined(HAVE_MALLOC_USABLE_SIZE)
32static unsigned long used_mem = 0UL;
33#endif
34
35/*--------------------------------------------------------------------------------------------------------------------*/
36
38{
39 /*----------------------------------------------------------------------------------------------------------------*/
40
41 #if defined(HAVE_MALLOC_SIZE) || defined(HAVE_MALLOC_USABLE_SIZE)
42 atomic_store_explicit(&used_mem, 0UL, memory_order_relaxed);
43 #endif
44
45 /*----------------------------------------------------------------------------------------------------------------*/
46}
47
48/*--------------------------------------------------------------------------------------------------------------------*/
49
51{
52 /*----------------------------------------------------------------------------------------------------------------*/
53
54 #if defined(HAVE_MALLOC_SIZE) || defined(HAVE_MALLOC_USABLE_SIZE)
55 unsigned long leaks = atomic_exchange_explicit(&used_mem, 0UL, memory_order_relaxed);
56
57 if(leaks > 0UL)
58 {
59 NYX_LOG_ERROR("Memory leak: %lu bytes", leaks);
60
61 return false;
62 }
63 #endif
64
65 /*----------------------------------------------------------------------------------------------------------------*/
66
67 return true;
68}
69
70/*--------------------------------------------------------------------------------------------------------------------*/
71
72size_t nyx_memory_free(buff_t buff)
73{
74 if(buff == NULL)
75 {
76 return 0x00;
77 }
78
79 /*----------------------------------------------------------------------------------------------------------------*/
80
81 #ifdef HAVE_MALLOC_SIZE
82 size_t result = malloc_size(buff);
83
84 atomic_fetch_sub_explicit(&used_mem, result, memory_order_relaxed);
85 #endif
86
87 /*----------------------------------------------------------------------------------------------------------------*/
88
89 #ifdef HAVE_MALLOC_USABLE_SIZE
90 size_t result = malloc_usable_size(buff);
91
92 atomic_fetch_sub_explicit(&used_mem, result, memory_order_relaxed);
93 #endif
94
95 /*----------------------------------------------------------------------------------------------------------------*/
96
97 free(buff);
98
99 /*----------------------------------------------------------------------------------------------------------------*/
100
101 #if defined(HAVE_MALLOC_SIZE) || defined(HAVE_MALLOC_USABLE_SIZE)
102 return result;
103 #else
104 return 0x0000;
105 #endif
106}
107
108/*--------------------------------------------------------------------------------------------------------------------*/
109
110buff_t nyx_memory_alloc(size_t size)
111{
112 if(size == 0x00)
113 {
114 return NULL;
115 }
116
117 /*----------------------------------------------------------------------------------------------------------------*/
118
119 buff_t result = malloc(size);
120
121 if(result == NULL)
122 {
123 NYX_LOG_FATAL("Out of memory");
124 }
125
126 /*----------------------------------------------------------------------------------------------------------------*/
127
128 #ifdef HAVE_MALLOC_SIZE
129 atomic_fetch_add_explicit(&used_mem, malloc_size(result), memory_order_relaxed);
130 #endif
131
132 /*----------------------------------------------------------------------------------------------------------------*/
133
134 #ifdef HAVE_MALLOC_USABLE_SIZE
135 atomic_fetch_add_explicit(&used_mem, malloc_usable_size(result), memory_order_relaxed);
136 #endif
137
138 /*----------------------------------------------------------------------------------------------------------------*/
139
140 return result;
141}
142
143/*--------------------------------------------------------------------------------------------------------------------*/
144
145buff_t nyx_memory_realloc(buff_t buff, size_t size)
146{
147 if(buff == NULL) {
148 return nyx_memory_alloc(size);
149 }
150
151 if(size == 0x00) {
152 nyx_memory_free(buff); return NULL;
153 }
154
155 /*----------------------------------------------------------------------------------------------------------------*/
156
157 #ifdef HAVE_MALLOC_SIZE
158 atomic_fetch_sub_explicit(&used_mem, malloc_size(buff), memory_order_relaxed);
159 #endif
160
161 /*----------------------------------------------------------------------------------------------------------------*/
162
163 #ifdef HAVE_MALLOC_USABLE_SIZE
164 atomic_fetch_sub_explicit(&used_mem, malloc_usable_size(buff), memory_order_relaxed);
165 #endif
166
167 /*----------------------------------------------------------------------------------------------------------------*/
168
169 buff_t result = realloc(buff, size);
170
171 if(result == NULL)
172 {
173 NYX_LOG_FATAL("Out of memory");
174 }
175
176 /*----------------------------------------------------------------------------------------------------------------*/
177
178 #ifdef HAVE_MALLOC_SIZE
179 atomic_fetch_add_explicit(&used_mem, malloc_size(result), memory_order_relaxed);
180 #endif
181
182 /*----------------------------------------------------------------------------------------------------------------*/
183
184 #ifdef HAVE_MALLOC_USABLE_SIZE
185 atomic_fetch_add_explicit(&used_mem, malloc_usable_size(result), memory_order_relaxed);
186 #endif
187
188 /*----------------------------------------------------------------------------------------------------------------*/
189
190 return result;
191}
192
193/*--------------------------------------------------------------------------------------------------------------------*/
194/* UTILITIES */
195/*--------------------------------------------------------------------------------------------------------------------*/
196
197str_t nyx_bool_dup(bool b)
198{
199 str_t str;
200
201 if(b) {
202 str = strcpy(nyx_memory_alloc(4 + 1), "true");
203 }
204 else {
205 str = strcpy(nyx_memory_alloc(5 + 1), "false");
206 }
207
208 return str;
209}
210
211/*--------------------------------------------------------------------------------------------------------------------*/
212
213str_t nyx_double_dup(double d)
214{
215 if(!isnan(d))
216 {
217 str_t str = nyx_memory_alloc(32 + 1);
218
219 snprintf(str, 32 + 1, "%f", d);
220
221 return str;
222 }
223
224 return NULL;
225}
226
227/*--------------------------------------------------------------------------------------------------------------------*/
228
230{
231 if(s != NULL)
232 {
233 size_t len = strlen(s);
234
235 str_t str = nyx_memory_alloc(len + 1);
236
237 memcpy(str, s, len);
238
239 str[len] = '\0';
240
241 return str;
242 }
243
244 return NULL;
245}
246
247/*--------------------------------------------------------------------------------------------------------------------*/
248
249str_t nyx_string_ndup(STR_t s, size_t n)
250{
251 if(s != NULL)
252 {
253 size_t len = strnlen(s, n);
254
255 str_t str = nyx_memory_alloc(len + 1);
256
257 memcpy(str, s, len);
258
259 str[len] = '\0';
260
261 return str;
262 }
263
264 return NULL;
265}
266
267/*--------------------------------------------------------------------------------------------------------------------*/
268/*--------------------------------------------------------------------------------------------------------------------*/
269
270nyx_str_t nyx_str_s(STR_t s)
271{
272 nyx_str_t str = {(str_t) /* NOSONAR */ s, s == NULL ? 0x0000000 : strlen(s)};
273
274 return str;
275}
276
277/*--------------------------------------------------------------------------------------------------------------------*/
278/* OBJECT */
279/*--------------------------------------------------------------------------------------------------------------------*/
280
281void nyx_object_free(nyx_object_t *object)
282{
283 if(object == NULL)
284 {
285 return;
286 }
287
288 if(object->magic != NYX_OBJECT_MAGIC)
289 {
290 NYX_LOG_FATAL("Invalid object");
291 }
292
293 switch(object->type)
294 {
295 case NYX_TYPE_NULL:
296 nyx_null_free((nyx_null_t *) object);
297 break;
298
299 case NYX_TYPE_NUMBER:
300 nyx_number_free((nyx_number_t *) object);
301 break;
302
303 case NYX_TYPE_BOOLEAN:
304 nyx_boolean_free((nyx_boolean_t *) object);
305 break;
306
307 case NYX_TYPE_STRING:
308 nyx_string_free((nyx_string_t *) object);
309 break;
310
311 case NYX_TYPE_LIST:
312 nyx_list_free((nyx_list_t *) object);
313 break;
314
315 case NYX_TYPE_DICT:
316 nyx_dict_free((nyx_dict_t *) object);
317 break;
318
319 default:
320 NYX_LOG_FATAL("Internal error");
321 }
322}
323
324/*--------------------------------------------------------------------------------------------------------------------*/
325
326bool nyx_object_equal(const nyx_object_t *object1, const nyx_object_t *object2)
327{
328 if(object1 == NULL || object2 == NULL)
329 {
330 return false;
331 }
332
333 if(object1->magic != NYX_OBJECT_MAGIC || object2->magic != NYX_OBJECT_MAGIC)
334 {
335 NYX_LOG_FATAL("Invalid object");
336 }
337
338 /*----------------------------------------------------------------------------------------------------------------*/
339
340 if(object1 == object2)
341 {
342 return true;
343 }
344
345 if(object1->type != object2->type)
346 {
347 return false;
348 }
349
350 /*----------------------------------------------------------------------------------------------------------------*/
351
352 switch(object1->type)
353 {
354 case NYX_TYPE_NULL:
355 return true;
356
357 case NYX_TYPE_NUMBER:
358 return ((const nyx_number_t *) object1)->value == ((const nyx_number_t *) object2)->value;
359
360 case NYX_TYPE_BOOLEAN:
361 return ((const nyx_boolean_t *) object1)->value == ((const nyx_boolean_t *) object2)->value;
362
363 case NYX_TYPE_STRING:
364 return strcmp(((const nyx_string_t *) object1)->value, ((const nyx_string_t *) object2)->value) == 0;
365
366 case NYX_TYPE_LIST:
367 case NYX_TYPE_DICT:
368 {
369 str_t s1 = nyx_object_to_string(object1);
370 str_t s2 = nyx_object_to_string(object2);
371
372 bool equal = strcmp(s1, s2) == 0;
373
374 nyx_memory_free(s1);
375 nyx_memory_free(s2);
376
377 return equal;
378 }
379
380 default:
381 NYX_LOG_FATAL("Internal error");
382 }
383
384 /*----------------------------------------------------------------------------------------------------------------*/
385}
386
387/*--------------------------------------------------------------------------------------------------------------------*/
388
389str_t nyx_object_to_string(const nyx_object_t *object)
390{
391 if(object == NULL)
392 {
393 return NULL;
394 }
395
396 if(object->magic != NYX_OBJECT_MAGIC)
397 {
398 NYX_LOG_FATAL("Invalid object");
399 }
400
401 /*----------------------------------------------------------------------------------------------------------------*/
402
403 switch(object->type)
404 {
405 case NYX_TYPE_NULL:
406 return nyx_null_to_string((const nyx_null_t *) object);
407
408 case NYX_TYPE_NUMBER:
409 return nyx_number_to_string((const nyx_number_t *) object);
410
411 case NYX_TYPE_BOOLEAN:
412 return nyx_boolean_to_string((const nyx_boolean_t *) object);
413
414 case NYX_TYPE_STRING:
415 return nyx_string_to_string((const nyx_string_t *) object);
416
417 case NYX_TYPE_LIST:
418 return nyx_list_to_string((const nyx_list_t *) object);
419
420 case NYX_TYPE_DICT:
421 return nyx_dict_to_string((const nyx_dict_t *) object);
422
423 default:
424 NYX_LOG_FATAL("Internal error");
425 }
426
427 /*----------------------------------------------------------------------------------------------------------------*/
428}
429
430/*--------------------------------------------------------------------------------------------------------------------*/
431
432str_t nyx_object_to_cstring(const nyx_object_t *object)
433{
434 if(object == NULL)
435 {
436 return NULL;
437 }
438
439 if(object->magic != NYX_OBJECT_MAGIC)
440 {
441 NYX_LOG_FATAL("Invalid object");
442 }
443
444 /*----------------------------------------------------------------------------------------------------------------*/
445
446 switch(object->type)
447 {
448 case NYX_TYPE_NULL:
449 return nyx_null_to_string((const nyx_null_t *) object);
450
451 case NYX_TYPE_NUMBER:
452 return nyx_number_to_string((const nyx_number_t *) object);
453
454 case NYX_TYPE_BOOLEAN:
455 return nyx_boolean_to_string((const nyx_boolean_t *) object);
456
457 case NYX_TYPE_STRING:
458 return nyx_string_to_cstring((const nyx_string_t *) object);
459
460 case NYX_TYPE_LIST:
461 return nyx_list_to_string((const nyx_list_t *) object);
462
463 case NYX_TYPE_DICT:
464 return nyx_dict_to_string((const nyx_dict_t *) object);
465
466 default:
467 NYX_LOG_FATAL("Internal error");
468 }
469
470 /*----------------------------------------------------------------------------------------------------------------*/
471}
472
473/*--------------------------------------------------------------------------------------------------------------------*/
#define NYX_LOG_FATAL(fmt,...)
Logs a fatal message.
Definition nyx_node.h:207
#define NYX_LOG_ERROR(fmt,...)
Logs an error message.
Definition nyx_node.h:218
#define STR_t
Alias for const char *.
Definition nyx_node.h:71
__NYX_NULLABLE__ buff_t nyx_memory_alloc(__NYX_ZEROABLE__ size_t size)
Similar to libc malloc except that a memory overflow causes the node to stop.
__NYX_ZEROABLE__ size_t nyx_memory_free(__NYX_NULLABLE__ buff_t buff)
Similar to libc free except that it returns the amount of memory freed.
#define buff_t
Alias for void *.
Definition nyx_node.h:67
void nyx_memory_initialize(void)
Initialize the memory subsystem.
Definition object.c:37
bool nyx_memory_finalize(void)
Finalize the memory subsystem.
Definition object.c:50
__NYX_NULLABLE__ str_t nyx_string_dup(__NYX_NULLABLE__ STR_t s)
Similar to libc strdup.
__NYX_NULLABLE__ str_t nyx_string_ndup(__NYX_NULLABLE__ STR_t s, __NYX_ZEROABLE__ size_t n)
Similar to libc strndup.
__NYX_NULLABLE__ buff_t nyx_memory_realloc(__NYX_NULLABLE__ buff_t buff, __NYX_ZEROABLE__ size_t size)
Similar to libc realloc except that a memory overflow causes the node to stop.
#define str_t
Alias for char *.
Definition nyx_node.h:70
#define NYX_OBJECT_MAGIC
Magic number for identifying JSON objects.
Definition nyx_node.h:401
@ NYX_TYPE_DICT
Dict object.
Definition nyx_node.h:426
@ NYX_TYPE_LIST
List object.
Definition nyx_node.h:427
@ NYX_TYPE_BOOLEAN
Boolean object.
Definition nyx_node.h:423
@ NYX_TYPE_NUMBER
Number object.
Definition nyx_node.h:424
@ NYX_TYPE_NULL
Null object.
Definition nyx_node.h:422
@ NYX_TYPE_STRING
String object.
Definition nyx_node.h:425
str_t nyx_string_to_cstring(const nyx_string_t *object)
Struct describing a JSON boolean object.
Definition nyx_node.h:795
Struct describing a JSON dict object.
Struct describing a JSON list object.
Struct describing a JSON null object.
Definition nyx_node.h:630
Struct describing a JSON number object.
Definition nyx_node.h:688
Struct describing a JSON object.
Struct describing a JSON string object.
Definition nyx_node.h:900