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
269buff_t nyx_buffer_ndup(BUFF_t b, size_t n)
270{
271 if(b != NULL)
272 {
273 buff_t buff = nyx_memory_alloc(n);
274
275 memcpy(buff, b, n);
276
277 return buff;
278 }
279
280 return NULL;
281}
282
283/*--------------------------------------------------------------------------------------------------------------------*/
284/*--------------------------------------------------------------------------------------------------------------------*/
285
286nyx_str_t nyx_str_s(STR_t s)
287{
288 nyx_str_t str = {(str_t) /* NOSONAR */ s, s == NULL ? 0x0000000 : strlen(s)};
289
290 return str;
291}
292
293/*--------------------------------------------------------------------------------------------------------------------*/
294/* OBJECT */
295/*--------------------------------------------------------------------------------------------------------------------*/
296
297__NYX_INLINE__ void _object_free(nyx_object_t *object)
298{
299 switch(object->type)
300 {
301 case NYX_TYPE_NULL:
302 nyx_null_free((nyx_null_t *) object);
303 break;
304
305 case NYX_TYPE_NUMBER:
306 nyx_number_free((nyx_number_t *) object);
307 break;
308
309 case NYX_TYPE_BOOLEAN:
310 nyx_boolean_free((nyx_boolean_t *) object);
311 break;
312
313 case NYX_TYPE_STRING:
314 nyx_string_free((nyx_string_t *) object);
315 break;
316
317 case NYX_TYPE_LIST:
318 nyx_list_free((nyx_list_t *) object);
319 break;
320
321 case NYX_TYPE_DICT:
322 nyx_dict_free((nyx_dict_t *) object);
323 break;
324
325 default:
326 NYX_LOG_FATAL("Invalid object type");
327 }
328}
329
330/*--------------------------------------------------------------------------------------------------------------------*/
331
332nyx_object_t *nyx_object_ref(void *object)
333{
334 /*----------------------------------------------------------------------------------------------------------------*/
335
336 if(object == NULL)
337 {
338 return NULL;
339 }
340
341 if(!NYX_OBJECT_CHECK_MAGIC(object))
342 {
343 NYX_LOG_FATAL("Invalid object");
344 }
345
346 /*----------------------------------------------------------------------------------------------------------------*/
347
348 if(((nyx_object_t *) object)->ref <= 0)
349 {
350 ((nyx_object_t *) object)->ref = 1;
351
352 /* always returns the input object */
353 }
354 else
355 {
356 ((nyx_object_t *) object)->ref++;
357 }
358
359 /*----------------------------------------------------------------------------------------------------------------*/
360
361 return object;
362}
363
364/*--------------------------------------------------------------------------------------------------------------------*/
365
366nyx_object_t *nyx_object_unref(void *object)
367{
368 /*----------------------------------------------------------------------------------------------------------------*/
369
370 if(object == NULL)
371 {
372 return NULL;
373 }
374
375 if(!NYX_OBJECT_CHECK_MAGIC(object))
376 {
377 NYX_LOG_FATAL("Invalid object");
378 }
379
380 /*----------------------------------------------------------------------------------------------------------------*/
381
382 if(((nyx_object_t *) object)->ref <= 1)
383 {
384 ((nyx_object_t *) object)->ref = 0;
385
386 _object_free(object); object = NULL;
387 }
388 else
389 {
390 ((nyx_object_t *) object)->ref--;
391 }
392
393 /*----------------------------------------------------------------------------------------------------------------*/
394
395 return object;
396}
397
398/*--------------------------------------------------------------------------------------------------------------------*/
399
400nyx_type_t nyx_object_get_type(const nyx_object_t *object)
401{
402 return object != NULL ? object->type : 0x00;
403}
404
405/*--------------------------------------------------------------------------------------------------------------------*/
406
407bool nyx_object_notify(const nyx_object_t *object)
408{
409 for(; object != NULL; object = object->parent)
410 {
411 if(internal_notify(object))
412 {
413 return true;
414 }
415 }
416
417 return false;
418}
419
420/*--------------------------------------------------------------------------------------------------------------------*/
421
422bool nyx_object_equal(const nyx_object_t *object1, const nyx_object_t *object2)
423{
424 if(object1 == NULL || object2 == NULL)
425 {
426 return false;
427 }
428
429 if(!NYX_OBJECT_CHECK_MAGIC(object1) || !NYX_OBJECT_CHECK_MAGIC(object2))
430 {
431 NYX_LOG_FATAL("Invalid object");
432 }
433
434 /*----------------------------------------------------------------------------------------------------------------*/
435
436 if(object1 == object2)
437 {
438 return true;
439 }
440
441 if(object1->type != object2->type)
442 {
443 return false;
444 }
445
446 /*----------------------------------------------------------------------------------------------------------------*/
447
448 switch(object1->type)
449 {
450 case NYX_TYPE_NULL:
451 return true;
452
453 case NYX_TYPE_NUMBER:
454 return ((const nyx_number_t *) object1)->value == ((const nyx_number_t *) object2)->value;
455
456 case NYX_TYPE_BOOLEAN:
457 return ((const nyx_boolean_t *) object1)->value == ((const nyx_boolean_t *) object2)->value;
458
459 case NYX_TYPE_STRING:
460 return strcmp(((const nyx_string_t *) object1)->value, ((const nyx_string_t *) object2)->value) == 0;
461
462 case NYX_TYPE_LIST:
463 case NYX_TYPE_DICT:
464 {
465 str_t s1 = nyx_object_to_string(object1);
466 str_t s2 = nyx_object_to_string(object2);
467
468 bool equal = strcmp(s1, s2) == 0;
469
470 nyx_memory_free(s1);
471 nyx_memory_free(s2);
472
473 return equal;
474 }
475
476 default:
477 NYX_LOG_FATAL("Invalid object type");
478 }
479
480 /*----------------------------------------------------------------------------------------------------------------*/
481}
482
483/*--------------------------------------------------------------------------------------------------------------------*/
484
485str_t nyx_object_to_string(const nyx_object_t *object)
486{
487 if(object == NULL)
488 {
489 return NULL;
490 }
491
492 if(!NYX_OBJECT_CHECK_MAGIC(object))
493 {
494 NYX_LOG_FATAL("Invalid object");
495 }
496
497 /*----------------------------------------------------------------------------------------------------------------*/
498
499 switch(object->type)
500 {
501 case NYX_TYPE_NULL:
502 return nyx_null_to_string((const nyx_null_t *) object);
503
504 case NYX_TYPE_NUMBER:
505 return nyx_number_to_string((const nyx_number_t *) object);
506
507 case NYX_TYPE_BOOLEAN:
508 return nyx_boolean_to_string((const nyx_boolean_t *) object);
509
510 case NYX_TYPE_STRING:
511 return nyx_string_to_string((const nyx_string_t *) object);
512
513 case NYX_TYPE_LIST:
514 return nyx_list_to_string((const nyx_list_t *) object);
515
516 case NYX_TYPE_DICT:
517 return nyx_dict_to_string((const nyx_dict_t *) object);
518
519 default:
520 NYX_LOG_FATAL("Invalid object type");
521 }
522
523 /*----------------------------------------------------------------------------------------------------------------*/
524}
525
526/*--------------------------------------------------------------------------------------------------------------------*/
527
528str_t nyx_object_to_cstring(const nyx_object_t *object)
529{
530 if(object == NULL)
531 {
532 return NULL;
533 }
534
535 if(!NYX_OBJECT_CHECK_MAGIC(object))
536 {
537 NYX_LOG_FATAL("Invalid object");
538 }
539
540 /*----------------------------------------------------------------------------------------------------------------*/
541
542 switch(object->type)
543 {
544 case NYX_TYPE_NULL:
545 return nyx_null_to_string((const nyx_null_t *) object);
546
547 case NYX_TYPE_NUMBER:
548 return nyx_number_to_string((const nyx_number_t *) object);
549
550 case NYX_TYPE_BOOLEAN:
551 return nyx_boolean_to_string((const nyx_boolean_t *) object);
552
553 case NYX_TYPE_STRING:
554 return nyx_string_to_cstring((const nyx_string_t *) object);
555
556 case NYX_TYPE_LIST:
557 return nyx_list_to_string((const nyx_list_t *) object);
558
559 case NYX_TYPE_DICT:
560 return nyx_dict_to_string((const nyx_dict_t *) object);
561
562 default:
563 NYX_LOG_FATAL("Invalid object type");
564 }
565
566 /*----------------------------------------------------------------------------------------------------------------*/
567}
568
569/*--------------------------------------------------------------------------------------------------------------------*/
Struct describing a JSON boolean object.
Definition nyx_node.h:821
Struct describing a JSON dict object.
Struct describing a JSON list object.
#define NYX_LOG_FATAL(fmt,...)
Logs a fatal message.
Definition nyx_node.h:208
#define NYX_LOG_ERROR(fmt,...)
Logs an error message.
Definition nyx_node.h:219
#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
#define BUFF_t
Alias for const void *.
Definition nyx_node.h:68
void nyx_memory_initialize(void)
Initializes the memory subsystem.
Definition object.c:37
bool nyx_memory_finalize(void)
Finalizes 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
Struct describing a JSON null object.
Definition nyx_node.h:680
Struct describing a JSON number object.
Definition nyx_node.h:726
nyx_type_t
JSON object types.
Definition nyx_node.h:433
@ NYX_TYPE_DICT
Dict object.
Definition nyx_node.h:438
@ NYX_TYPE_LIST
List object.
Definition nyx_node.h:439
@ NYX_TYPE_BOOLEAN
Boolean object.
Definition nyx_node.h:435
@ NYX_TYPE_NUMBER
Number object.
Definition nyx_node.h:436
@ NYX_TYPE_NULL
Null object.
Definition nyx_node.h:434
@ NYX_TYPE_STRING
String object.
Definition nyx_node.h:437
Struct describing a JSON object.
Struct describing a JSON string object.
Definition nyx_node.h:914