iodine 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +4 -4
  4. data/SPEC-Websocket-Draft.md +3 -6
  5. data/bin/mustache.rb +128 -0
  6. data/examples/test_template.mustache +16 -0
  7. data/ext/iodine/fio.c +9397 -0
  8. data/ext/iodine/fio.h +4723 -0
  9. data/ext/iodine/fio_ary.h +353 -54
  10. data/ext/iodine/fio_cli.c +351 -361
  11. data/ext/iodine/fio_cli.h +84 -105
  12. data/ext/iodine/fio_hashmap.h +70 -16
  13. data/ext/iodine/fio_json_parser.h +35 -24
  14. data/ext/iodine/fio_siphash.c +104 -4
  15. data/ext/iodine/fio_siphash.h +18 -2
  16. data/ext/iodine/fio_str.h +1218 -0
  17. data/ext/iodine/fio_tmpfile.h +1 -1
  18. data/ext/iodine/fiobj.h +13 -8
  19. data/ext/iodine/fiobj4sock.h +6 -8
  20. data/ext/iodine/fiobj_ary.c +107 -17
  21. data/ext/iodine/fiobj_ary.h +36 -4
  22. data/ext/iodine/fiobj_data.c +146 -127
  23. data/ext/iodine/fiobj_data.h +25 -23
  24. data/ext/iodine/fiobj_hash.c +7 -7
  25. data/ext/iodine/fiobj_hash.h +6 -5
  26. data/ext/iodine/fiobj_json.c +20 -17
  27. data/ext/iodine/fiobj_json.h +5 -5
  28. data/ext/iodine/fiobj_mem.h +71 -0
  29. data/ext/iodine/fiobj_mustache.c +310 -0
  30. data/ext/iodine/fiobj_mustache.h +40 -0
  31. data/ext/iodine/fiobj_numbers.c +199 -94
  32. data/ext/iodine/fiobj_numbers.h +7 -7
  33. data/ext/iodine/fiobj_str.c +142 -333
  34. data/ext/iodine/fiobj_str.h +65 -55
  35. data/ext/iodine/fiobject.c +49 -11
  36. data/ext/iodine/fiobject.h +40 -39
  37. data/ext/iodine/http.c +382 -190
  38. data/ext/iodine/http.h +124 -80
  39. data/ext/iodine/http1.c +99 -127
  40. data/ext/iodine/http1.h +5 -5
  41. data/ext/iodine/http1_parser.c +3 -2
  42. data/ext/iodine/http1_parser.h +2 -2
  43. data/ext/iodine/http_internal.c +14 -12
  44. data/ext/iodine/http_internal.h +25 -19
  45. data/ext/iodine/iodine.c +37 -18
  46. data/ext/iodine/iodine.h +4 -0
  47. data/ext/iodine/iodine_caller.c +9 -2
  48. data/ext/iodine/iodine_caller.h +2 -0
  49. data/ext/iodine/iodine_connection.c +82 -117
  50. data/ext/iodine/iodine_defer.c +57 -50
  51. data/ext/iodine/iodine_defer.h +0 -1
  52. data/ext/iodine/iodine_fiobj2rb.h +4 -2
  53. data/ext/iodine/iodine_helpers.c +4 -4
  54. data/ext/iodine/iodine_http.c +25 -32
  55. data/ext/iodine/iodine_json.c +2 -1
  56. data/ext/iodine/iodine_mustache.c +423 -0
  57. data/ext/iodine/iodine_mustache.h +6 -0
  58. data/ext/iodine/iodine_pubsub.c +48 -153
  59. data/ext/iodine/iodine_pubsub.h +5 -4
  60. data/ext/iodine/iodine_rack_io.c +7 -5
  61. data/ext/iodine/iodine_store.c +16 -13
  62. data/ext/iodine/iodine_tcp.c +26 -34
  63. data/ext/iodine/mustache_parser.h +1085 -0
  64. data/ext/iodine/redis_engine.c +740 -646
  65. data/ext/iodine/redis_engine.h +13 -15
  66. data/ext/iodine/resp_parser.h +11 -5
  67. data/ext/iodine/websocket_parser.h +13 -13
  68. data/ext/iodine/websockets.c +240 -393
  69. data/ext/iodine/websockets.h +52 -113
  70. data/lib/iodine.rb +1 -1
  71. data/lib/iodine/mustache.rb +140 -0
  72. data/lib/iodine/version.rb +1 -1
  73. metadata +15 -28
  74. data/ext/iodine/defer.c +0 -566
  75. data/ext/iodine/defer.h +0 -148
  76. data/ext/iodine/evio.c +0 -26
  77. data/ext/iodine/evio.h +0 -161
  78. data/ext/iodine/evio_callbacks.c +0 -26
  79. data/ext/iodine/evio_epoll.c +0 -251
  80. data/ext/iodine/evio_kqueue.c +0 -194
  81. data/ext/iodine/facil.c +0 -2325
  82. data/ext/iodine/facil.h +0 -616
  83. data/ext/iodine/fio_base64.c +0 -277
  84. data/ext/iodine/fio_base64.h +0 -71
  85. data/ext/iodine/fio_llist.h +0 -257
  86. data/ext/iodine/fio_mem.c +0 -675
  87. data/ext/iodine/fio_mem.h +0 -143
  88. data/ext/iodine/fio_random.c +0 -248
  89. data/ext/iodine/fio_random.h +0 -45
  90. data/ext/iodine/fio_sha1.c +0 -362
  91. data/ext/iodine/fio_sha1.h +0 -107
  92. data/ext/iodine/fio_sha2.c +0 -842
  93. data/ext/iodine/fio_sha2.h +0 -169
  94. data/ext/iodine/pubsub.c +0 -867
  95. data/ext/iodine/pubsub.h +0 -221
  96. data/ext/iodine/sock.c +0 -1366
  97. data/ext/iodine/sock.h +0 -566
  98. data/ext/iodine/spnlock.inc +0 -111
@@ -0,0 +1,4723 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2018
3
+ License: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #ifndef H_FACIL_IO_H
8
+ /**
9
+ "facil.h" is the main header for the facil.io server platform.
10
+ */
11
+ #define H_FACIL_IO_H
12
+
13
+ /* *****************************************************************************
14
+ Table of contents:
15
+ =================
16
+ * Version and helper macros
17
+ * Helper String Information Type
18
+ * Memory pool / custom allocator for short lived objects
19
+ *
20
+ * Connection Callback (Protocol) Management
21
+ * Listening to Incoming Connections
22
+ * Connecting to remote servers as a client
23
+ * Starting the IO reactor and reviewing it's state
24
+ * Socket / Connection Functions
25
+ * Connection Read / Write Hooks, for overriding the system calls
26
+ * Concurrency overridable functions
27
+ * Connection Task scheduling
28
+ * Event / Task scheduling
29
+ * Startup / State Callbacks (fork, start up, idle, etc')
30
+ * Lower Level API - for special circumstances, use with care under
31
+ *
32
+ * Pub/Sub / Cluster Messages API
33
+ * Cluster Messages and Pub/Sub
34
+ * Cluster / Pub/Sub Middleware and Extensions ("Engines")
35
+ *
36
+ * Atomic Operations and Spin Locking Helper Functions
37
+ * Byte Swapping and Network Order
38
+ *
39
+ * Converting Numbers to Strings (and back)
40
+ * Strings to Numbers
41
+ * Numbers to Strings* Random Generator Functions
42
+ *
43
+ * SipHash
44
+ * SHA-1
45
+ * SHA-2
46
+ * Base64 (URL) encoding
47
+ *
48
+ * Memory Allocator Details
49
+ *
50
+ * Spin locking Implementation
51
+ *
52
+ ******** facil.io Data Types (String, Set / Hash Map, Linked Lists, etc')
53
+ *
54
+ * These types can be included by defining the macros and (re)including fio.h.
55
+ *
56
+ *
57
+ *
58
+ * #ifdef FIO_INCLUDE_LINKED_LIST
59
+ *
60
+ * Linked List Helpers
61
+ * Independent Linked List API
62
+ * Embedded Linked List API* Independent Linked List Implementation
63
+ * Embeded Linked List Implementation
64
+ *
65
+ *
66
+ *
67
+ * #ifdef FIO_INCLUDE_STR
68
+ *
69
+ * String Helpers
70
+ * String API - Initialization and Destruction
71
+ * String API - String state (data pointers, length, capacity, etc')
72
+ * String API - Memory management
73
+ * String API - UTF-8 State
74
+ * String Implementation - state (data pointers, length, capacity, etc')
75
+ * String Implementation - Memory management
76
+ * String Implementation - UTF-8 State
77
+ * String Implementation - Content Manipulation and Review
78
+ *
79
+ *
80
+ *
81
+ * #ifdef FIO_SET_NAME - can be included more than once
82
+ *
83
+ * Set / Hash Map Data-Store
84
+ * Set / Hash Map API
85
+ * Set / Hash Map Internal Data Structures
86
+ * Set / Hash Map Internal Helpers
87
+ * Set / Hash Map Implementation
88
+ *
89
+ ***************************************************************************** */
90
+
91
+ /* *****************************************************************************
92
+ Version and helper macros
93
+ ***************************************************************************** */
94
+
95
+ #define FIO_VERSION_MAJOR 0
96
+ #define FIO_VERSION_MINOR 7
97
+ #define FIO_VERSION_PATCH 0
98
+
99
+ /* Automatically convert version data to a string constant - ignore these two */
100
+ #define FIO_MACRO2STR_STEP2(macro) #macro
101
+ #define FIO_MACRO2STR(macro) FIO_MACRO2STR_STEP2(macro)
102
+
103
+ /** The facil.io version as a String literal */
104
+ #define FIO_VERSION_STRING \
105
+ FIO_MACRO2STR(FIO_VERSION_MAJOR) \
106
+ "." FIO_MACRO2STR(FIO_VERSION_MINOR) "." FIO_MACRO2STR(FIO_VERSION_PATCH)
107
+
108
+ #ifndef FIO_MAX_SOCK_CAPACITY
109
+ /**
110
+ * The maximum number of connections per worker process.
111
+ */
112
+ #define FIO_MAX_SOCK_CAPACITY 131072
113
+ #endif
114
+
115
+ #ifndef FIO_CPU_CORES_LIMIT
116
+ /**
117
+ * If facil.io detects more CPU cores than the number of cores stated in the
118
+ * FIO_CPU_CORES_LIMIT, it will assume an error and cap the number of cores
119
+ * detected to the assigned limit.
120
+ *
121
+ * This is only relevant to automated values, when running facil.io with zero
122
+ * threads and processes, which invokes a large matrix of workers and threads
123
+ * (see {facil_run})
124
+ *
125
+ * The default auto-detection cap is set at 8 cores. The number is arbitrary
126
+ * (historically the number 7 was used after testing `malloc` race conditions on
127
+ * a MacBook Pro).
128
+ *
129
+ * This does NOT effect manually set (non-zero) worker/thread values.
130
+ */
131
+ #define FIO_CPU_CORES_LIMIT 8
132
+ #endif
133
+
134
+ #ifndef FIO_DEFER_THROTTLE_PROGRESSIVE
135
+ /**
136
+ * The progressive throttling model makes concurrency and parallelism more
137
+ * likely.
138
+ *
139
+ * Otherwise threads are assumed to be intended for "fallback" in case of slow
140
+ * user code, where a single thread should be active most of the time and other
141
+ * threads are activated only when that single thread is slow to perform.
142
+ */
143
+ #define FIO_DEFER_THROTTLE_PROGRESSIVE 1
144
+ #endif
145
+
146
+ #ifndef FIO_PRINT_STATE
147
+ /**
148
+ * Prints some state massages to stderr (startup / shutdown / etc').
149
+ */
150
+ #define FIO_PRINT_STATE 1
151
+ #endif
152
+
153
+ #ifndef FIO_PUBSUB_SUPPORT
154
+ /**
155
+ * If true (1), compiles the facil.io pub/sub API.
156
+ */
157
+ #define FIO_PUBSUB_SUPPORT 1
158
+ #endif
159
+
160
+ #ifndef FIO_IGNORE_MACRO
161
+ /**
162
+ * This is used internally to ignor macros that shadow functions (avoiding named
163
+ * arguments when required.
164
+ */
165
+ #define FIO_IGNORE_MACRO
166
+ #endif
167
+
168
+ #ifndef _GNU_SOURCE
169
+ #define _GNU_SOURCE
170
+ #endif
171
+
172
+ #include <errno.h>
173
+ #include <limits.h>
174
+ #include <signal.h>
175
+ #include <stdarg.h>
176
+ #include <stdint.h>
177
+ #include <stdio.h>
178
+ #include <stdlib.h>
179
+ #include <string.h>
180
+ #include <strings.h>
181
+ #include <time.h>
182
+
183
+ #include <fcntl.h>
184
+ #include <sys/stat.h>
185
+ #include <sys/time.h>
186
+ #include <unistd.h>
187
+
188
+ #if !defined(__GNUC__) && !defined(__clang__) && !defined(FIO_GNUC_BYPASS)
189
+ #define __attribute__(...)
190
+ #define __has_include(...) 0
191
+ #define __has_builtin(...) 0
192
+ #define FIO_GNUC_BYPASS 1
193
+ #elif !defined(__clang__) && __GNUC__ < 5
194
+ #define __has_builtin(...) 0
195
+ #define FIO_GNUC_BYPASS 1
196
+ #endif
197
+
198
+ #ifndef FIO_FUNC
199
+ #define FIO_FUNC static __attribute__((unused))
200
+ #endif
201
+
202
+ #ifndef FIO_ASSERT_ALLOC
203
+ /** Tests for an allocation failure. The behavior can be overridden. */
204
+ #define FIO_ASSERT_ALLOC(ptr) \
205
+ if (!(ptr)) { \
206
+ fprintf(stderr, \
207
+ "FATAL ERROR: memory allocation error "__FILE__ \
208
+ ":%d\n", \
209
+ __LINE__); \
210
+ perror(" Error details (errno)"); \
211
+ kill(0, SIGINT); \
212
+ exit(errno); \
213
+ }
214
+ #endif
215
+
216
+ #if defined(__FreeBSD__)
217
+ #include <netinet/in.h>
218
+ #include <sys/socket.h>
219
+ #endif
220
+
221
+ #if FIO_PRINT_STATE
222
+ #define FIO_LOG_STATE(...) fprintf(stderr, __VA_ARGS__)
223
+ #else
224
+ #define FIO_LOG_STATE(...)
225
+ #endif
226
+
227
+ #if DEBUG
228
+ #define FIO_LOG_DEBUG(...) FIO_LOG_STATE("INFO [DEBUG]: " __VA_ARGS__)
229
+ // #define FIO_ASSERT(cond, ...) \
230
+ // if (!(cond)) { \
231
+ // fprintf(stderr, "FATAL [DEBUG] (" __FILE__ \
232
+ // ":" FIO_MACRO2STR(__LINE__) "): " __VA_ARGS__); \
233
+ // exit(-1); \
234
+ // }
235
+ #define FIO_ASSERT(cond, ...) \
236
+ if (!(cond)) { \
237
+ fprintf(stderr, "FATAL [DEBUG] (" __FILE__ \
238
+ ":" FIO_MACRO2STR(__LINE__) "): " __VA_ARGS__); \
239
+ exit(-1); \
240
+ }
241
+ #else
242
+ #define FIO_LOG_DEBUG(...)
243
+ #define FIO_ASSERT(...)
244
+ #endif
245
+
246
+ /* *****************************************************************************
247
+ C++ extern start
248
+ ***************************************************************************** */
249
+ /* support C++ */
250
+ #ifdef __cplusplus
251
+ extern "C" {
252
+ #endif
253
+
254
+ /* *****************************************************************************
255
+ Helper String Information Type
256
+ ***************************************************************************** */
257
+
258
+ #ifndef FIO_STR_INFO_TYPE
259
+ /** A string information type, reports information about a C string. */
260
+ typedef struct fio_str_info_s {
261
+ size_t capa; /* Buffer capacity, if the string is writable. */
262
+ size_t len; /* String length. */
263
+ char *data; /* String's first byte. */
264
+ } fio_str_info_s;
265
+ #define FIO_STR_INFO_TYPE
266
+ #endif
267
+
268
+ /* *****************************************************************************
269
+ Memory pool / custom allocator for short lived objects
270
+ ***************************************************************************** */
271
+
272
+ /**
273
+ * Allocates memory using a per-CPU core block memory pool.
274
+ * Memory is zeroed out.
275
+ *
276
+ * Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (12,288 bytes when using 32Kb
277
+ * blocks) will be redirected to `mmap`, as if `fio_mmap` was called.
278
+ */
279
+ void *fio_malloc(size_t size);
280
+
281
+ /**
282
+ * same as calling `fio_malloc(size_per_unit * unit_count)`;
283
+ *
284
+ * Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (12,288 bytes when using 32Kb
285
+ * blocks) will be redirected to `mmap`, as if `fio_mmap` was called.
286
+ */
287
+ void *fio_calloc(size_t size_per_unit, size_t unit_count);
288
+
289
+ /** Frees memory that was allocated using this library. */
290
+ void fio_free(void *ptr);
291
+
292
+ /**
293
+ * Re-allocates memory. An attempt to avoid copying the data is made only for
294
+ * big memory allocations (larger than FIO_MEMORY_BLOCK_ALLOC_LIMIT).
295
+ */
296
+ void *fio_realloc(void *ptr, size_t new_size);
297
+
298
+ /**
299
+ * Re-allocates memory. An attempt to avoid copying the data is made only for
300
+ * big memory allocations (larger than FIO_MEMORY_BLOCK_ALLOC_LIMIT).
301
+ *
302
+ * This variation is slightly faster as it might copy less data.
303
+ */
304
+ void *fio_realloc2(void *ptr, size_t new_size, size_t copy_length);
305
+
306
+ /**
307
+ * Allocates memory directly using `mmap`, this is prefered for objects that
308
+ * both require almost a page of memory (or more) and expect a long lifetime.
309
+ *
310
+ * However, since this allocation will invoke the system call (`mmap`), it will
311
+ * be inherently slower.
312
+ *
313
+ * `fio_free` can be used for deallocating the memory.
314
+ */
315
+ void *fio_mmap(size_t size);
316
+
317
+ #if FIO_FORCE_MALLOC
318
+ #define fio_malloc malloc
319
+ #define fio_calloc calloc
320
+ #define fio_mmap malloc
321
+ #define fio_free free
322
+ #define fio_realloc realloc
323
+ #define fio_realloc2(ptr, new_size, old_data_len) realloc((ptr), (new_size))
324
+ #define fio_malloc_test()
325
+ #define fio_malloc_after_fork()
326
+ #endif
327
+
328
+ /* *****************************************************************************
329
+
330
+
331
+
332
+
333
+
334
+
335
+
336
+
337
+
338
+
339
+
340
+
341
+ Connection Callback (Protocol) Management
342
+
343
+
344
+
345
+
346
+
347
+
348
+
349
+
350
+
351
+
352
+
353
+
354
+ ***************************************************************************** */
355
+
356
+ typedef struct fio_protocol_s fio_protocol_s;
357
+ /**************************************************************************/ /**
358
+ * The Protocol
359
+
360
+ The Protocol struct defines the callbacks used for the connection and sets it's
361
+ behaviour. The Protocol struct is part of facil.io's core design.
362
+
363
+ For concurrency reasons, a protocol instance SHOULD be unique to each
364
+ connections. Different connections shouldn't share a single protocol object
365
+ (callbacks and data can obviously be shared).
366
+
367
+ All the callbacks receive a unique connection ID (a localized UUID) that can be
368
+ converted to the original file descriptor when in need.
369
+
370
+ This allows facil.io to prevent old connection handles from sending data
371
+ to new connections after a file descriptor is "recycled" by the OS.
372
+ */
373
+ struct fio_protocol_s {
374
+ /** Called when a data is available, but will not run concurrently */
375
+ void (*on_data)(intptr_t uuid, fio_protocol_s *protocol);
376
+ /** called once all pending `fio_write` calls are finished. */
377
+ void (*on_ready)(intptr_t uuid, fio_protocol_s *protocol);
378
+ /**
379
+ * Called when the server is shutting down, immediately before closing the
380
+ * connection.
381
+ *
382
+ * The callback runs within a {FIO_PR_LOCK_TASK} lock, so it will never run
383
+ * concurrently with {on_data} or other connection specific tasks.
384
+ *
385
+ * The `on_shutdown` callback should return 0 to close the socket or a number
386
+ * between 1..254 to delay the socket closure by that amount of time.
387
+ *
388
+ * Once the socket wass marked for closure, facil.io will allow 8 seconds for
389
+ * all the data to be sent before forcfully closing the socket (regardless of
390
+ * state).
391
+ *
392
+ * If the `on_shutdown` returns 255, the socket is ignored and it will be
393
+ * abruptly terminated when all other sockets have finished their graceful
394
+ * shutdown procedure.
395
+ */
396
+ uint8_t (*on_shutdown)(intptr_t uuid, fio_protocol_s *protocol);
397
+ /** Called when the connection was closed, but will not run concurrently */
398
+ void (*on_close)(intptr_t uuid, fio_protocol_s *protocol);
399
+ /** called when a connection's timeout was reached */
400
+ void (*ping)(intptr_t uuid, fio_protocol_s *protocol);
401
+ /** private metadata used by facil. */
402
+ size_t rsv;
403
+ };
404
+
405
+ /**
406
+ * Attaches (or updates) a protocol object to a socket UUID.
407
+ *
408
+ * The new protocol object can be NULL, which will detach ("hijack"), the
409
+ * socket .
410
+ *
411
+ * The old protocol's `on_close` (if any) will be scheduled.
412
+ *
413
+ * On error, the new protocol's `on_close` callback will be called immediately.
414
+ */
415
+ void fio_attach(intptr_t uuid, fio_protocol_s *protocol);
416
+
417
+ /**
418
+ * Attaches (or updates) a protocol object to a file descriptor (fd).
419
+ *
420
+ * The new protocol object can be NULL, which will detach ("hijack"), the
421
+ * socket and the `fd` can be one created outside of facil.io.
422
+ *
423
+ * The old protocol's `on_close` (if any) will be scheduled.
424
+ *
425
+ * On error, the new protocol's `on_close` callback will be called immediately.
426
+ */
427
+ void fio_attach_fd(int fd, fio_protocol_s *protocol);
428
+
429
+ /**
430
+ * Returns the maximum number of open files facil.io can handle per worker
431
+ * process.
432
+ *
433
+ * Total OS limits might apply as well but aren't shown.
434
+ *
435
+ * The value of 0 indicates either that the facil.io library wasn't initialized
436
+ * yet or that it's resources were released.
437
+ */
438
+ size_t fio_capa(void);
439
+
440
+ /** Sets a timeout for a specific connection (only when running and valid). */
441
+ void fio_timeout_set(intptr_t uuid, uint8_t timeout);
442
+
443
+ /** Gets a timeout for a specific connection. Returns 0 if none. */
444
+ uint8_t fio_timeout_get(intptr_t uuid);
445
+
446
+ /**
447
+ * "Touches" a socket connection, resetting it's timeout counter.
448
+ */
449
+ void fio_touch(intptr_t uuid);
450
+
451
+ enum fio_io_event {
452
+ FIO_EVENT_ON_DATA,
453
+ FIO_EVENT_ON_READY,
454
+ FIO_EVENT_ON_TIMEOUT
455
+ };
456
+ /** Schedules an IO event, even if it did not occur. */
457
+ void fio_force_event(intptr_t uuid, enum fio_io_event);
458
+
459
+ /**
460
+ * Temporarily prevents `on_data` events from firing.
461
+ *
462
+ * The `on_data` event will be automatically rescheduled when (if) the socket's
463
+ * outgoing buffer fills up or when `fio_force_event` is called with
464
+ * `FIO_EVENT_ON_DATA`.
465
+ *
466
+ * Note: the function will work as expected when called within the protocol's
467
+ * `on_data` callback and the `uuid` refers to a valid socket. Otherwise the
468
+ * function might quietly fail.
469
+ */
470
+ void fio_suspend(intptr_t uuid);
471
+
472
+ /* *****************************************************************************
473
+ Listening to Incoming Connections
474
+ ***************************************************************************** */
475
+
476
+ /* Arguments for the fio_listen function */
477
+ struct fio_listen_args {
478
+ /**
479
+ * Called whenever a new connection is accepted.
480
+ *
481
+ * Should either call `fio_attach` or close the connection.
482
+ */
483
+ void (*on_open)(intptr_t uuid, void *udata);
484
+ /** The network service / port. Defaults to "3000". */
485
+ const char *port;
486
+ /** The socket binding address. Defaults to the recommended NULL. */
487
+ const char *address;
488
+ /** Opaque user data. */
489
+ void *udata;
490
+ /**
491
+ * Called when the server starts (or a worker process is respawned), allowing
492
+ * for further initialization, such as timed event scheduling or VM
493
+ * initialization.
494
+ *
495
+ * This will be called separately for every worker process whenever it is
496
+ * spawned.
497
+ */
498
+ void (*on_start)(intptr_t uuid, void *udata);
499
+ /**
500
+ * Called when the server is done, usable for cleanup.
501
+ *
502
+ * This will be called separately for every process. */
503
+ void (*on_finish)(intptr_t uuid, void *udata);
504
+ };
505
+
506
+ /**
507
+ * Sets up a network service on a listening socket.
508
+ *
509
+ * Returns the listening socket's uuid or -1 (on error).
510
+ *
511
+ * See the `fio_listen` Macro for details.
512
+ */
513
+ intptr_t fio_listen(struct fio_listen_args args);
514
+
515
+ /************************************************************************ */ /**
516
+ Listening to Incoming Connections
517
+ ===
518
+
519
+ Listening to incoming connections is pretty straight forward.
520
+
521
+ After a new connection is accepted, the `on_open` callback is called. `on_open`
522
+ should allocate the new connection's protocol and call `fio_attach` to attach
523
+ the protocol to the connection's uuid.
524
+
525
+ The protocol's `on_close` callback is expected to handle any cleanup required.
526
+
527
+ The following is an example echo server using facil.io:
528
+
529
+ ```c
530
+ #include <fio.h>
531
+
532
+ // A callback to be called whenever data is available on the socket
533
+ static void echo_on_data(intptr_t uuid, fio_protocol_s *prt) {
534
+ (void)prt; // we can ignore the unused argument
535
+ // echo buffer
536
+ char buffer[1024] = {'E', 'c', 'h', 'o', ':', ' '};
537
+ ssize_t len;
538
+ // Read to the buffer, starting after the "Echo: "
539
+ while ((len = fio_read(uuid, buffer + 6, 1018)) > 0) {
540
+ fprintf(stderr, "Read: %.*s", (int)len, buffer + 6);
541
+ // Write back the message
542
+ fio_write(uuid, buffer, len + 6);
543
+ // Handle goodbye
544
+ if ((buffer[6] | 32) == 'b' && (buffer[7] | 32) == 'y' &&
545
+ (buffer[8] | 32) == 'e') {
546
+ fio_write(uuid, "Goodbye.\n", 9);
547
+ fio_close(uuid);
548
+ return;
549
+ }
550
+ }
551
+ }
552
+
553
+ // A callback called whenever a timeout is reach
554
+ static void echo_ping(intptr_t uuid, fio_protocol_s *prt) {
555
+ (void)prt; // we can ignore the unused argument
556
+ fio_write(uuid, "Server: Are you there?\n", 23);
557
+ }
558
+
559
+ // A callback called if the server is shutting down...
560
+ // ... while the connection is still open
561
+ static uint8_t echo_on_shutdown(intptr_t uuid, fio_protocol_s *prt) {
562
+ (void)prt; // we can ignore the unused argument
563
+ fio_write(uuid, "Echo server shutting down\nGoodbye.\n", 35);
564
+ return 0;
565
+ }
566
+
567
+ static void echo_on_close(intptr_t uuid, fio_protocol_s *proto) {
568
+ fprintf(stderr, "Connection %p closed.\n", (void *)proto);
569
+ free(proto);
570
+ (void)uuid;
571
+ }
572
+
573
+ // A callback called for new connections
574
+ static void echo_on_open(intptr_t uuid, void *udata) {
575
+ (void)udata; // ignore this
576
+ // Protocol objects MUST be dynamically allocated when multi-threading.
577
+ fio_protocol_s *echo_proto = malloc(sizeof(*echo_proto));
578
+ *echo_proto = (fio_protocol_s){.service = "echo",
579
+ .on_data = echo_on_data,
580
+ .on_shutdown = echo_on_shutdown,
581
+ .on_close = echo_on_close,
582
+ .ping = echo_ping};
583
+ fprintf(stderr, "New Connection %p received from %s\n", (void *)echo_proto,
584
+ fio_peer_addr(uuid).data);
585
+ fio_attach(uuid, echo_proto);
586
+ fio_write2(uuid, .data.buffer = "Echo Service: Welcome\n", .length = 22,
587
+ .after.dealloc = FIO_DEALLOC_NOOP);
588
+ fio_timeout_set(uuid, 5);
589
+ }
590
+
591
+ int main() {
592
+ // Setup a listening socket
593
+ if (fio_listen(.port = "3000", .on_open = echo_on_open) == -1) {
594
+ perror("No listening socket available on port 3000");
595
+ exit(-1);
596
+ }
597
+ // Run the server and hang until a stop signal is received.
598
+ fio_start(.threads = 4, .workers = 1);
599
+ }
600
+ ```
601
+ */
602
+ #define fio_listen(...) fio_listen((struct fio_listen_args){__VA_ARGS__})
603
+
604
+ /* *****************************************************************************
605
+ Connecting to remote servers as a client
606
+ ***************************************************************************** */
607
+
608
+ /**
609
+ Named arguments for the `fio_connect` function, that allows non-blocking
610
+ connections to be established.
611
+ */
612
+ struct fio_connect_args {
613
+ /** The address of the server we are connecting to. */
614
+ const char *address;
615
+ /** The port on the server we are connecting to. */
616
+ const char *port;
617
+ /**
618
+ * The `on_connect` callback should return a pointer to a protocol object
619
+ * that will handle any connection related events.
620
+ *
621
+ * Should either call `fio_attach` or close the connection.
622
+ */
623
+ void (*on_connect)(intptr_t uuid, void *udata);
624
+ /**
625
+ * The `on_fail` is called when a socket fails to connect. The old sock UUID
626
+ * is passed along.
627
+ */
628
+ void (*on_fail)(intptr_t uuid, void *udata);
629
+ /** Opaque user data. */
630
+ void *udata;
631
+ /** A non-system timeout after which connection is assumed to have failed. */
632
+ uint8_t timeout;
633
+ };
634
+
635
+ /**
636
+ Creates a client connection (in addition or instead of the server).
637
+
638
+ See the `struct fio_connect_args` details for any possible named arguments.
639
+
640
+ * `.address` should be the address of the server.
641
+
642
+ * `.port` the server's port.
643
+
644
+ * `.udata`opaque user data.
645
+
646
+ * `.on_connect` called once a connection was established.
647
+
648
+ Should return a pointer to a `fio_protocol_s` object, to handle connection
649
+ callbacks.
650
+
651
+ * `.on_fail` called if a connection failed to establish.
652
+
653
+ (experimental: untested)
654
+ */
655
+ intptr_t fio_connect(struct fio_connect_args);
656
+ #define fio_connect(...) fio_connect((struct fio_connect_args){__VA_ARGS__})
657
+
658
+ /* *****************************************************************************
659
+ Starting the IO reactor and reviewing it's state
660
+ ***************************************************************************** */
661
+
662
+ struct fio_start_args {
663
+ /**
664
+ * The number of threads to run in the thread pool. Has "smart" defaults.
665
+ *
666
+ *
667
+ * A positive value will indicate a set number of threads (or workers).
668
+ *
669
+ * Zeros and negative values are fun and include an interesting shorthand:
670
+ *
671
+ * * Negative values indicate a fraction of the number of CPU cores. i.e.
672
+ * -2 will normally indicate "half" (1/2) the number of cores.
673
+ *
674
+ * * If the other option (i.e. `.workers` when setting `.threads`) is zero,
675
+ * it will be automatically updated to reflect the option's absolute value.
676
+ * i.e.:
677
+ * if .threads == -2 and .workers == 0,
678
+ * than facil.io will run 2 worker processes with (cores/2) threads per
679
+ * process.
680
+ */
681
+ int16_t threads;
682
+ /** The number of worker processes to run. See `threads`. */
683
+ int16_t workers;
684
+ };
685
+
686
+ /**
687
+ * Starts the facil.io event loop. This function will return after facil.io is
688
+ * done (after shutdown).
689
+ *
690
+ * See the `struct fio_start_args` details for any possible named arguments.
691
+ *
692
+ * This method blocks the current thread until the server is stopped (when a
693
+ * SIGINT/SIGTERM is received).
694
+ */
695
+ void fio_start(struct fio_start_args args);
696
+ #define fio_start(...) fio_start((struct fio_start_args){__VA_ARGS__})
697
+
698
+ /**
699
+ * Attempts to stop the facil.io application. This only works within the Root
700
+ * process. A worker process will simply respawn itself.
701
+ */
702
+ void fio_stop(void);
703
+
704
+ /**
705
+ * Returns the number of expected threads / processes to be used by facil.io.
706
+ *
707
+ * The pointers should start with valid values that match the expected threads /
708
+ * processes values passed to `fio_start`.
709
+ *
710
+ * The data in the pointers will be overwritten with the result.
711
+ */
712
+ void fio_expected_concurrency(int16_t *threads, int16_t *workers);
713
+
714
+ /**
715
+ * Returns the number of worker processes if facil.io is running.
716
+ *
717
+ * (1 is returned when in single process mode, otherwise the number of workers)
718
+ */
719
+ int16_t fio_is_running(void);
720
+
721
+ /**
722
+ * Returns 1 if the current process is a worker process or a single process.
723
+ *
724
+ * Otherwise returns 0.
725
+ *
726
+ * NOTE: When cluster mode is off, the root process is also the worker process.
727
+ * This means that single process instances don't automatically respawn
728
+ * after critical errors.
729
+ */
730
+ int fio_is_worker(void);
731
+
732
+ /**
733
+ * Returns 1 if the current process is the master (root) process.
734
+ *
735
+ * Otherwise returns 0.
736
+ */
737
+ int fio_is_master(void);
738
+
739
+ /** Returns facil.io's parent (root) process pid. */
740
+ pid_t fio_parent_pid(void);
741
+
742
+ /**
743
+ * Initializes zombie reaping for the process. Call before `fio_start` to enable
744
+ * global zombie reaping.
745
+ */
746
+ void fio_reap_children(void);
747
+
748
+ /**
749
+ * Returns the last time the server reviewed any pending IO events.
750
+ */
751
+ struct timespec fio_last_tick(void);
752
+
753
+ /**
754
+ * Returns a C string detailing the IO engine selected during compilation.
755
+ *
756
+ * Valid values are "kqueue", "epoll" and "poll".
757
+ */
758
+ char const *fio_engine(void);
759
+
760
+ /* *****************************************************************************
761
+ Socket / Connection Functions
762
+ ***************************************************************************** */
763
+
764
+ /**
765
+ * Creates a Unix or a TCP/IP socket and returns it's unique identifier.
766
+ *
767
+ * For TCP/IP server sockets (`is_server` is `1`), a NULL `address` variable is
768
+ * recommended. Use "localhost" or "127.0.0.1" to limit access to the server
769
+ * application.
770
+ *
771
+ * For TCP/IP client sockets (`is_server` is `0`), a remote `address` and `port`
772
+ * combination will be required
773
+ *
774
+ * For Unix server or client sockets, set the `port` variable to NULL or `0`.
775
+ *
776
+ * Returns -1 on error. Any other value is a valid unique identifier.
777
+ *
778
+ * Note: facil.io uses unique identifiers to protect sockets from collisions.
779
+ * However these identifiers can be converted to the underlying file
780
+ * descriptor using the `fio_uuid2fd` macro.
781
+ */
782
+ intptr_t fio_socket(const char *address, const char *port, uint8_t is_server);
783
+
784
+ /**
785
+ * `fio_accept` accepts a new socket connection from a server socket - see the
786
+ * server flag on `fio_socket`.
787
+ *
788
+ * NOTE: this function does NOT attach the socket to the IO reactor - see
789
+ * `fio_attach`.
790
+ */
791
+ intptr_t fio_accept(intptr_t srv_uuid);
792
+
793
+ /**
794
+ * Returns 1 if the uuid refers to a valid and open, socket.
795
+ *
796
+ * Returns 0 if not.
797
+ */
798
+ int fio_is_valid(intptr_t uuid);
799
+
800
+ /**
801
+ * Returns 1 if the uuid is invalid or the socket is flagged to be closed.
802
+ *
803
+ * Returns 0 if the socket is valid, open and isn't flagged to be closed.
804
+ */
805
+ int fio_is_closed(intptr_t uuid);
806
+
807
+ /**
808
+ * `fio_close` marks the connection for disconnection once all the data was
809
+ * sent. The actual disconnection will be managed by the `fio_flush` function.
810
+ *
811
+ * `fio_flash` will be automatically scheduled.
812
+ */
813
+ void fio_close(intptr_t uuid);
814
+
815
+ /**
816
+ * `fio_force_close` closes the connection immediately, without adhering to any
817
+ * protocol restrictions and without sending any remaining data in the
818
+ * connection buffer.
819
+ */
820
+ void fio_force_close(intptr_t uuid);
821
+
822
+ /**
823
+ * Returns the information available about the socket's peer address.
824
+ *
825
+ * If no information is available, the struct will be initialized with zero
826
+ * (`addr == NULL`).
827
+ * The information is only available when the socket was accepted using
828
+ * `fio_accept` or opened using `fio_connect`.
829
+ */
830
+ fio_str_info_s fio_peer_addr(intptr_t uuid);
831
+
832
+ /**
833
+ * `fio_read` attempts to read up to count bytes from the socket into the
834
+ * buffer starting at `buffer`.
835
+ *
836
+ * `fio_read`'s return values are wildly different then the native return
837
+ * values and they aim at making far simpler sense.
838
+ *
839
+ * `fio_read` returns the number of bytes read (0 is a valid return value which
840
+ * simply means that no bytes were read from the buffer).
841
+ *
842
+ * On a fatal connection error that leads to the connection being closed (or if
843
+ * the connection is already closed), `fio_read` returns -1.
844
+ *
845
+ * The value 0 is the valid value indicating no data was read.
846
+ *
847
+ * Data might be available in the kernel's buffer while it is not available to
848
+ * be read using `fio_read` (i.e., when using a transport layer, such as TLS).
849
+ */
850
+ ssize_t fio_read(intptr_t uuid, void *buffer, size_t count);
851
+
852
+ /** The following structure is used for `fio_write2_fn` function arguments. */
853
+ typedef struct {
854
+ union {
855
+ /** The in-memory data to be sent. */
856
+ const void *buffer;
857
+ /** The data to be sent, if this is a file. */
858
+ const intptr_t fd;
859
+ } data;
860
+ union {
861
+ /**
862
+ * This deallocation callback will be called when the packet is finished
863
+ * with the buffer.
864
+ *
865
+ * If no deallocation callback is set, `free` (or `close`) will be used.
866
+ *
867
+ * Note: socket library functions MUST NEVER be called by a callback, or a
868
+ * deadlock might occur.
869
+ */
870
+ void (*dealloc)(void *buffer);
871
+ /**
872
+ * This is an alternative deallocation callback accessor (same memory space
873
+ * as `dealloc`) for conveniently setting the file `close` callback.
874
+ *
875
+ * Note: `sock` library functions MUST NEVER be called by a callback, or a
876
+ * deadlock might occur.
877
+ */
878
+ void (*close)(intptr_t fd);
879
+ } after;
880
+ /** The length (size) of the buffer, or the amount of data to be sent from the
881
+ * file descriptor.
882
+ */
883
+ uintptr_t length;
884
+ /** Starting point offset from the buffer or file descriptor's beginning. */
885
+ uintptr_t offset;
886
+ /** The packet will be sent as soon as possible. */
887
+ unsigned urgent : 1;
888
+ /**
889
+ * The data union contains the value of a file descriptor (`int`). i.e.:
890
+ * `.data.fd = fd` or `.data.buffer = (void*)fd;`
891
+ */
892
+ unsigned is_fd : 1;
893
+ /** for internal use */
894
+ unsigned rsv : 1;
895
+ /** for internal use */
896
+ unsigned rsv2 : 1;
897
+ } fio_write_args_s;
898
+
899
+ /**
900
+ * `fio_write2_fn` is the actual function behind the macro `fio_write2`.
901
+ */
902
+ ssize_t fio_write2_fn(intptr_t uuid, fio_write_args_s options);
903
+
904
+ /**
905
+ * Schedules data to be written to the socket.
906
+ *
907
+ * `fio_write2` is similar to `fio_write`, except that it allows far more
908
+ * flexibility.
909
+ *
910
+ * On error, -1 will be returned. Otherwise returns 0.
911
+ *
912
+ * See the `fio_write_args_s` structure for details.
913
+ *
914
+ * NOTE: The data is "moved" to the ownership of the socket, not copied. The
915
+ * data will be deallocated according to the `.after.dealloc` function.
916
+ */
917
+ #define fio_write2(uuid, ...) \
918
+ fio_write2_fn(uuid, (fio_write_args_s){__VA_ARGS__})
919
+
920
+ /** A noop function for fio_write2 in cases not deallocation is required. */
921
+ void FIO_DEALLOC_NOOP(void *arg);
922
+ #define FIO_CLOSE_NOOP ((void (*)(intptr_t))FIO_DEALLOC_NOOP)
923
+
924
+ /**
925
+ * `fio_write` copies `legnth` data from the buffer and schedules the data to
926
+ * be sent over the socket.
927
+ *
928
+ * The data isn't necessarily written to the socket. The actual writing to the
929
+ * socket is handled by the IO reactor.
930
+ *
931
+ * On error, -1 will be returned. Otherwise returns 0.
932
+ *
933
+ * Returns the same values as `fio_write2`.
934
+ */
935
+ // ssize_t fio_write(uintptr_t uuid, void *buffer, size_t legnth);
936
+ inline FIO_FUNC ssize_t fio_write(const intptr_t uuid, const void *buffer,
937
+ const size_t length) {
938
+ if (!length || !buffer)
939
+ return 0;
940
+ void *cpy = fio_malloc(length);
941
+ if (!cpy)
942
+ return -1;
943
+ memcpy(cpy, buffer, length);
944
+ return fio_write2(uuid, .data.buffer = cpy, .length = length,
945
+ .after.dealloc = fio_free);
946
+ }
947
+
948
+ /**
949
+ * Sends data from a file as if it were a single atomic packet (sends up to
950
+ * length bytes or until EOF is reached).
951
+ *
952
+ * Once the file was sent, the `source_fd` will be closed using `close`.
953
+ *
954
+ * The file will be buffered to the socket chunk by chunk, so that memory
955
+ * consumption is capped. The system's `sendfile` might be used if conditions
956
+ * permit.
957
+ *
958
+ * `offset` dictates the starting point for the data to be sent and length sets
959
+ * the maximum amount of data to be sent.
960
+ *
961
+ * Returns -1 and closes the file on error. Returns 0 on success.
962
+ */
963
+ inline FIO_FUNC ssize_t fio_sendfile(intptr_t uuid, intptr_t source_fd,
964
+ off_t offset, size_t length) {
965
+ return fio_write2(uuid, .data.fd = source_fd, .length = length, .is_fd = 1,
966
+ .offset = offset);
967
+ }
968
+
969
+ /**
970
+ * Returns the number of `fio_write` calls that are waiting in the socket's
971
+ * queue and haven't been processed.
972
+ */
973
+ size_t fio_pending(intptr_t uuid);
974
+
975
+ /**
976
+ * `fio_flush` attempts to write any remaining data in the internal buffer to
977
+ * the underlying file descriptor and closes the underlying file descriptor once
978
+ * if it's marked for closure (and all the data was sent).
979
+ *
980
+ * Return values: 1 will be returned if data remains in the buffer. 0
981
+ * will be returned if the buffer was fully drained. -1 will be returned on an
982
+ * error or when the connection is closed.
983
+ *
984
+ * errno will be set to EWOULDBLOCK if the socket's lock is busy.
985
+ */
986
+ ssize_t fio_flush(intptr_t uuid);
987
+
988
+ /** Blocks until all the data was flushed from the buffer */
989
+ #define fio_flush_strong(uuid) \
990
+ do { \
991
+ errno = 0; \
992
+ } while (fio_flush(uuid) > 0 || errno == EWOULDBLOCK)
993
+
994
+ /** `fio_flush_all` attempts flush all the open connections. */
995
+ void fio_flush_all(void);
996
+
997
+ /**
998
+ * Convert between a facil.io connection's identifier (uuid) and system's fd.
999
+ */
1000
+ #define fio_uuid2fd(uuid) ((int)((uintptr_t)uuid >> 8))
1001
+
1002
+ /**
1003
+ * `fio_fd2uuid` takes an existing file decriptor `fd` and returns it's active
1004
+ * `uuid`.
1005
+ *
1006
+ * If the file descriptor was closed, __it will be registered as open__.
1007
+ *
1008
+ * If the file descriptor was closed directly (not using `fio_close`) or the
1009
+ * closure event hadn't been processed, a false positive will be possible. This
1010
+ * is not an issue, since the use of an invalid fd will result in the registry
1011
+ * being updated and the fd being closed.
1012
+ *
1013
+ * Returns -1 on error. Returns a valid socket (non-random) UUID.
1014
+ */
1015
+ intptr_t fio_fd2uuid(int fd);
1016
+
1017
+ /**
1018
+ * `fio_fd2uuid` takes an existing file decriptor `fd` and returns it's active
1019
+ * `uuid`.
1020
+ *
1021
+ * If the file descriptor is marked as closed (wasn't opened / registered with
1022
+ * facil.io) the function returns -1;
1023
+ *
1024
+ * If the file descriptor was closed directly (not using `fio_close`) or the
1025
+ * closure event hadn't been processed, a false positive will be possible. This
1026
+ * is not an issue, since the use of an invalid fd will result in the registry
1027
+ * being updated and the fd being closed.
1028
+ *
1029
+ * Returns -1 on error. Returns a valid socket (non-random) UUID.
1030
+ */
1031
+ intptr_t fio_fd2uuid(int fd);
1032
+
1033
+ /* *****************************************************************************
1034
+ Connection Object Links
1035
+ ***************************************************************************** */
1036
+
1037
+ /**
1038
+ * Links an object to a connection's lifetime, calling the `on_close` callback
1039
+ * once the connection has died.
1040
+ *
1041
+ * If the `uuid` is invalid, the `on_close` callback will be called immediately.
1042
+ *
1043
+ * NOTE: the `on_close` callback will be called with high priority. Long tasks
1044
+ * should be deferred.
1045
+ */
1046
+ void fio_uuid_link(intptr_t uuid, void *obj, void (*on_close)(void *obj));
1047
+
1048
+ /**
1049
+ * Un-links an object from the connection's lifetime, so it's `on_close`
1050
+ * callback will NOT be called.
1051
+ *
1052
+ * Returns 0 on success and -1 if the object couldn't be found, setting `errno`
1053
+ * to `EBADF` if the `uuid` was invalid and `ENOTCONN` if the object wasn't
1054
+ * found (wasn't linked).
1055
+ *
1056
+ * NOTICE: a failure likely means that the object's `on_close` callback was
1057
+ * already called!
1058
+ */
1059
+ int fio_uuid_unlink(intptr_t uuid, void *obj);
1060
+
1061
+ /* *****************************************************************************
1062
+ Connection Read / Write Hooks, for overriding the system calls
1063
+ ***************************************************************************** */
1064
+
1065
+ /**
1066
+ * The following struct is used for setting a the read/write hooks that will
1067
+ * replace the default system calls to `recv` and `write`.
1068
+ *
1069
+ * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
1070
+ * deadlock might occur.
1071
+ */
1072
+ typedef struct fio_rw_hook_s {
1073
+ /**
1074
+ * Implement reading from a file descriptor. Should behave like the file
1075
+ * system `read` call, including the setup or errno to EAGAIN / EWOULDBLOCK.
1076
+ *
1077
+ * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
1078
+ * deadlock might occur.
1079
+ */
1080
+ ssize_t (*read)(intptr_t uuid, void *udata, void *buf, size_t count);
1081
+ /**
1082
+ * Implement writing to a file descriptor. Should behave like the file system
1083
+ * `write` call.
1084
+ *
1085
+ * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
1086
+ * deadlock might occur.
1087
+ */
1088
+ ssize_t (*write)(intptr_t uuid, void *udata, const void *buf, size_t count);
1089
+ /**
1090
+ * The `close` callback should close the underlying socket / file descriptor.
1091
+ * It should also be used to release any resources associated with the
1092
+ * connection's read/write hooks.
1093
+ *
1094
+ * If the function returns a non-zero value, it will be called again after an
1095
+ * attempt to flush the socket and any pending outgoing buffer.
1096
+ *
1097
+ * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
1098
+ * deadlock might occur.
1099
+ * */
1100
+ ssize_t (*close)(intptr_t uuid, void *udata);
1101
+ /**
1102
+ * When implemented, this function will be called to flush any data remaining
1103
+ * in the internal buffer.
1104
+ *
1105
+ * The function should return the number of bytes remaining in the internal
1106
+ * buffer (0 is a valid response) or -1 (on error).
1107
+ *
1108
+ * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
1109
+ * deadlock might occur.
1110
+ */
1111
+ ssize_t (*flush)(intptr_t uuid, void *udata);
1112
+ } fio_rw_hook_s;
1113
+
1114
+ /** Sets a socket hook state (a pointer to the struct). */
1115
+ int fio_rw_hook_set(intptr_t uuid, fio_rw_hook_s *rw_hooks, void *udata);
1116
+
1117
+ /** The default Read/Write hooks used for system Read/Write (udata == NULL). */
1118
+ extern const fio_rw_hook_s FIO_DEFAULT_RW_HOOKS;
1119
+
1120
+ /* *****************************************************************************
1121
+ Concurrency overridable functions
1122
+
1123
+ These functions can be overridden so as to adjust for different environments.
1124
+ ***************************************************************************** */
1125
+
1126
+ /**
1127
+ OVERRIDE THIS to replace the default `fork` implementation.
1128
+
1129
+ Behaves like the system's `fork`.
1130
+ */
1131
+ int fio_fork(void);
1132
+
1133
+ /**
1134
+ * OVERRIDE THIS to replace the default pthread implementation.
1135
+ *
1136
+ * Accepts a pointer to a function and a single argument that should be executed
1137
+ * within a new thread.
1138
+ *
1139
+ * The function should allocate memory for the thread object and return a
1140
+ * pointer to the allocated memory that identifies the thread.
1141
+ *
1142
+ * On error NULL should be returned.
1143
+ */
1144
+ void *fio_thread_new(void *(*thread_func)(void *), void *arg);
1145
+
1146
+ /**
1147
+ * OVERRIDE THIS to replace the default pthread implementation.
1148
+ *
1149
+ * Frees the memory associated with a thread identifier (allows the thread to
1150
+ * run it's course, just the identifier is freed).
1151
+ */
1152
+ void fio_thread_free(void *p_thr);
1153
+
1154
+ /**
1155
+ * OVERRIDE THIS to replace the default pthread implementation.
1156
+ *
1157
+ * Accepts a pointer returned from `fio_thread_new` (should also free any
1158
+ * allocated memory) and joins the associated thread.
1159
+ *
1160
+ * Return value is ignored.
1161
+ */
1162
+ int fio_thread_join(void *p_thr);
1163
+
1164
+ /* *****************************************************************************
1165
+ Connection Task scheduling
1166
+ ***************************************************************************** */
1167
+
1168
+ /**
1169
+ * This is used to lock the protocol againste concurrency collisions and
1170
+ * concurrent memory deallocation.
1171
+ *
1172
+ * However, there are three levels of protection that allow non-coliding tasks
1173
+ * to protect the protocol object from being deallocated while in use:
1174
+ *
1175
+ * * `FIO_PR_LOCK_TASK` - a task lock locks might change data owned by the
1176
+ * protocol object. This task is used for tasks such as `on_data`.
1177
+ *
1178
+ * * `FIO_PR_LOCK_WRITE` - a lock that promises only to use static data (data
1179
+ * that tasks never changes) in order to write to the underlying socket.
1180
+ * This lock is used for tasks such as `on_ready` and `ping`
1181
+ *
1182
+ * * `FIO_PR_LOCK_STATE` - a lock that promises only to retrieve static data
1183
+ * (data that tasks never changes), performing no actions. This usually
1184
+ * isn't used for client side code (used internally by facil) and is only
1185
+ * meant for very short locks.
1186
+ */
1187
+ enum fio_protocol_lock_e {
1188
+ FIO_PR_LOCK_TASK = 0,
1189
+ FIO_PR_LOCK_WRITE = 1,
1190
+ FIO_PR_LOCK_STATE = 2
1191
+ };
1192
+
1193
+ /** Named arguments for the `fio_defer` function. */
1194
+ typedef struct {
1195
+ /** The type of task to be performed. Defaults to `FIO_PR_LOCK_TASK` but could
1196
+ * also be seto to `FIO_PR_LOCK_WRITE`. */
1197
+ enum fio_protocol_lock_e type;
1198
+ /** The task (function) to be performed. This is required. */
1199
+ void (*task)(intptr_t uuid, fio_protocol_s *, void *udata);
1200
+ /** An opaque user data that will be passed along to the task. */
1201
+ void *udata;
1202
+ /** A fallback task, in case the connection was lost. Good for cleanup. */
1203
+ void (*fallback)(intptr_t uuid, void *udata);
1204
+ } fio_defer_iotask_args_s;
1205
+
1206
+ /**
1207
+ * Schedules a protected connection task. The task will run within the
1208
+ * connection's lock.
1209
+ *
1210
+ * If an error ocuurs or the connection is closed before the task can run, the
1211
+ * `fallback` task wil be called instead, allowing for resource cleanup.
1212
+ */
1213
+ void fio_defer_io_task(intptr_t uuid, fio_defer_iotask_args_s args);
1214
+ #define fio_defer_io_task(uuid, ...) \
1215
+ fio_defer_io_task((uuid), (fio_defer_iotask_args_s){__VA_ARGS__})
1216
+
1217
+ /* *****************************************************************************
1218
+ Event / Task scheduling
1219
+ ***************************************************************************** */
1220
+
1221
+ /**
1222
+ * Defers a task's execution.
1223
+ *
1224
+ * Tasks are functions of the type `void task(void *, void *)`, they return
1225
+ * nothing (void) and accept two opaque `void *` pointers, user-data 1
1226
+ * (`udata1`) and user-data 2 (`udata2`).
1227
+ *
1228
+ * Returns -1 or error, 0 on success.
1229
+ */
1230
+ int fio_defer(void (*task)(void *, void *), void *udata1, void *udata2);
1231
+
1232
+ /**
1233
+ * Creates a timer to run a task at the specified interval.
1234
+ *
1235
+ * The task will repeat `repetitions` times. If `repetitions` is set to 0, task
1236
+ * will repeat forever.
1237
+ *
1238
+ * Returns -1 on error.
1239
+ *
1240
+ * The `on_finish` handler is always called (even on error).
1241
+ */
1242
+ int fio_run_every(size_t milliseconds, size_t repetitions, void (*task)(void *),
1243
+ void *arg, void (*on_finish)(void *));
1244
+
1245
+ /**
1246
+ * Performs all deferred tasks.
1247
+ */
1248
+ void fio_defer_perform(void);
1249
+
1250
+ /** Returns true if there are deferred functions waiting for execution. */
1251
+ int fio_defer_has_queue(void);
1252
+
1253
+ /* *****************************************************************************
1254
+ Startup / State Callbacks (fork, start up, idle, etc')
1255
+ ***************************************************************************** */
1256
+
1257
+ /** a callback type signifier */
1258
+ typedef enum {
1259
+ /** Called once during library initialization. */
1260
+ FIO_CALL_ON_INITIALIZE,
1261
+ /** Called once before starting up the IO reactor. */
1262
+ FIO_CALL_PRE_START,
1263
+ /** Called before each time the IO reactor forks a new worker. */
1264
+ FIO_CALL_BEFORE_FORK,
1265
+ /** Called after each fork (both in parent and workers). */
1266
+ FIO_CALL_AFTER_FORK,
1267
+ /** Called by a worker process right after forking. */
1268
+ FIO_CALL_IN_CHILD,
1269
+ /** Called every time a *Worker* proceess starts. */
1270
+ FIO_CALL_ON_START,
1271
+ /** Called when facil.io enters idling mode. */
1272
+ FIO_CALL_ON_IDLE,
1273
+ /** Called before starting the shutdown sequence. */
1274
+ FIO_CALL_ON_SHUTDOWN,
1275
+ /** Called just before finishing up (both on chlid and parent processes). */
1276
+ FIO_CALL_ON_FINISH,
1277
+ /** Called by each worker the moment it detects the master process crashed. */
1278
+ FIO_CALL_ON_PARENT_CRUSH,
1279
+ /** Called by the parent (master) after a worker process crashed. */
1280
+ FIO_CALL_ON_CHILD_CRUSH,
1281
+ /** An alternative to the system's at_exit. */
1282
+ FIO_CALL_AT_EXIT,
1283
+ /** used for testing. */
1284
+ FIO_CALL_NEVER
1285
+ } callback_type_e;
1286
+
1287
+ /** Adds a callback to the list of callbacks to be called for the event. */
1288
+ void fio_state_callback_add(callback_type_e, void (*func)(void *), void *arg);
1289
+
1290
+ /** Removes a callback from the list of callbacks to be called for the event. */
1291
+ int fio_state_callback_remove(callback_type_e, void (*func)(void *), void *arg);
1292
+
1293
+ /**
1294
+ * Forces all the existing callbacks to run, as if the event occurred.
1295
+ *
1296
+ * Callbacks are called from last to first (last callback executes first).
1297
+ *
1298
+ * During an event, changes to the callback list are ignored (callbacks can't
1299
+ * remove other callbacks for the same event).
1300
+ */
1301
+ void fio_state_callback_force(callback_type_e);
1302
+
1303
+ /** Clears all the existing callbacks for the event. */
1304
+ void fio_state_callback_clear(callback_type_e);
1305
+
1306
+ /* *****************************************************************************
1307
+ Lower Level API - for special circumstances, use with care.
1308
+ ***************************************************************************** */
1309
+
1310
+ /**
1311
+ * This function allows out-of-task access to a connection's `fio_protocol_s`
1312
+ * object by attempting to acquire a locked pointer.
1313
+ *
1314
+ * CAREFUL: mostly, the protocol object will be locked and a pointer will be
1315
+ * sent to the connection event's callback. However, if you need access to the
1316
+ * protocol object from outside a running connection task, you might need to
1317
+ * lock the protocol to prevent it from being closed / freed in the background.
1318
+ *
1319
+ * facil.io uses three different locks:
1320
+ *
1321
+ * * FIO_PR_LOCK_TASK locks the protocol for normal tasks (i.e. `on_data`,
1322
+ * `fio_defer`, `fio_every`).
1323
+ *
1324
+ * * FIO_PR_LOCK_WRITE locks the protocol for high priority `fio_write`
1325
+ * oriented tasks (i.e. `ping`, `on_ready`).
1326
+ *
1327
+ * * FIO_PR_LOCK_STATE locks the protocol for quick operations that need to copy
1328
+ * data from the protocol's data structure.
1329
+ *
1330
+ * IMPORTANT: Remember to call `fio_protocol_unlock` using the same lock type.
1331
+ *
1332
+ * Returns NULL on error (lock busy == EWOULDBLOCK, connection invalid == EBADF)
1333
+ * and a pointer to a protocol object on success.
1334
+ *
1335
+ * On error, consider calling `fio_defer` or `defer` instead of busy waiting.
1336
+ * Busy waiting SHOULD be avoided whenever possible.
1337
+ */
1338
+ fio_protocol_s *fio_protocol_try_lock(intptr_t uuid, enum fio_protocol_lock_e);
1339
+ /** Don't unlock what you don't own... see `fio_protocol_try_lock` for
1340
+ * details. */
1341
+ void fio_protocol_unlock(fio_protocol_s *pr, enum fio_protocol_lock_e);
1342
+
1343
+ /**
1344
+ Sets a socket to non blocking state.
1345
+
1346
+ This function is called automatically for the new socket, when using
1347
+ `fio_accept` or `fio_connect`.
1348
+ */
1349
+ int fio_set_non_block(int fd);
1350
+
1351
+ /* *****************************************************************************
1352
+ * Pub/Sub / Cluster Messages API
1353
+ *
1354
+ * Facil supports a message oriented API for use for Inter Process Communication
1355
+ * (IPC), publish/subscribe patterns, horizontal scaling and similar use-cases.
1356
+ *
1357
+ **************************************************************************** */
1358
+ #if FIO_PUBSUB_SUPPORT
1359
+
1360
+ /* *****************************************************************************
1361
+ * Cluster Messages and Pub/Sub
1362
+ **************************************************************************** */
1363
+
1364
+ /** An opaque subscription type. */
1365
+ typedef struct subscription_s subscription_s;
1366
+
1367
+ /** A pub/sub engine data structure. See details later on. */
1368
+ typedef struct fio_pubsub_engine_s fio_pubsub_engine_s;
1369
+
1370
+ /** The default engine (settable). Initial default is FIO_PUBSUB_CLUSTER. */
1371
+ extern fio_pubsub_engine_s *FIO_PUBSUB_DEFAULT;
1372
+ /** Used to publish the message to all clients in the cluster. */
1373
+ #define FIO_PUBSUB_CLUSTER ((fio_pubsub_engine_s *)1)
1374
+ /** Used to publish the message only within the current process. */
1375
+ #define FIO_PUBSUB_PROCESS ((fio_pubsub_engine_s *)2)
1376
+ /** Used to publish the message except within the current process. */
1377
+ #define FIO_PUBSUB_SIBLINGS ((fio_pubsub_engine_s *)3)
1378
+ /** Used to publish the message exclusively to the root / master process. */
1379
+ #define FIO_PUBSUB_ROOT ((fio_pubsub_engine_s *)4)
1380
+
1381
+ /** Message structure, with an integer filter as well as a channel filter. */
1382
+ typedef struct fio_msg_s {
1383
+ /** A unique message type. Negative values are reserved, 0 == pub/sub. */
1384
+ int32_t filter;
1385
+ /**
1386
+ * A channel name, allowing for pub/sub patterns.
1387
+ *
1388
+ * NOTE: the channel and msg strings should be considered immutable. The .capa
1389
+ * field might be used for internal data.
1390
+ */
1391
+ fio_str_info_s channel;
1392
+ /**
1393
+ * The actual message.
1394
+ *
1395
+ * NOTE: the channel and msg strings should be considered immutable. The .capa
1396
+ *field might be used for internal data.
1397
+ **/
1398
+ fio_str_info_s msg;
1399
+ /** The `udata1` argument associated with the subscription. */
1400
+ void *udata1;
1401
+ /** The `udata1` argument associated with the subscription. */
1402
+ void *udata2;
1403
+ /** flag indicating if the message is JSON data or binary/text. */
1404
+ uint8_t is_json;
1405
+ } fio_msg_s;
1406
+
1407
+ /**
1408
+ * Pattern matching callback type - should return 0 unless channel matches
1409
+ * pattern.
1410
+ */
1411
+ typedef int (*fio_match_fn)(fio_str_info_s pattern, fio_str_info_s channel);
1412
+
1413
+ extern fio_match_fn FIO_MATCH_GLOB;
1414
+
1415
+ /**
1416
+ * Possible arguments for the fio_subscribe method.
1417
+ *
1418
+ * NOTICE: passing protocol objects to the `udata` is not safe. This is because
1419
+ * protocol objects might be destroyed or invalidated according to both network
1420
+ * events (socket closure) and internal changes (i.e., `fio_attach` being
1421
+ * called). The preferred way is to add the `uuid` to the `udata` field and call
1422
+ * `fio_protocol_try_lock`.
1423
+ */
1424
+ typedef struct {
1425
+ /**
1426
+ * If `filter` is set, all messages that match the filter's numerical value
1427
+ * will be forwarded to the subscription's callback.
1428
+ *
1429
+ * Subscriptions can either require a match by filter or match by channel.
1430
+ * This will match the subscription by filter.
1431
+ */
1432
+ int32_t filter;
1433
+ /**
1434
+ * If `channel` is set, all messages where `filter == 0` and the channel is an
1435
+ * exact match will be forwarded to the subscription's callback.
1436
+ *
1437
+ * Subscriptions can either require a match by filter or match by channel.
1438
+ * This will match the subscription by channel (only messages with no `filter`
1439
+ * will be received.
1440
+ */
1441
+ fio_str_info_s channel;
1442
+ /**
1443
+ * The the `match` function allows pattern matching for channel names.
1444
+ *
1445
+ * When using a match function, the channel name is considered to be a pattern
1446
+ * and each pub/sub message (a message where filter == 0) will be tested
1447
+ * against that pattern.
1448
+ *
1449
+ * Using pattern subscriptions extensively could become a performance concern,
1450
+ * since channel names are tested against each distinct pattern rather than
1451
+ * leveraging a hashmap for possible name matching.
1452
+ */
1453
+ fio_match_fn match;
1454
+ /**
1455
+ * The callback will be called for each message forwarded to the subscription.
1456
+ */
1457
+ void (*on_message)(fio_msg_s *msg);
1458
+ /** An optional callback for when a subscription is fully canceled. */
1459
+ void (*on_unsubscribe)(void *udata1, void *udata2);
1460
+ /** The udata values are ignored and made available to the callback. */
1461
+ void *udata1;
1462
+ /** The udata values are ignored and made available to the callback. */
1463
+ void *udata2;
1464
+ } subscribe_args_s;
1465
+
1466
+ /** Publishing and on_message callback arguments. */
1467
+ typedef struct fio_publish_args_s {
1468
+ /** The pub/sub engine that should be used to forward this message. */
1469
+ fio_pubsub_engine_s const *engine;
1470
+ /** A unique message type. Negative values are reserved, 0 == pub/sub. */
1471
+ int32_t filter;
1472
+ /** The pub/sub target channnel. */
1473
+ fio_str_info_s channel;
1474
+ /** The pub/sub message. */
1475
+ fio_str_info_s message;
1476
+ /** flag indicating if the message is JSON data or binary/text. */
1477
+ uint8_t is_json;
1478
+ } fio_publish_args_s;
1479
+
1480
+ /**
1481
+ * Subscribes to either a filter OR a channel (never both).
1482
+ *
1483
+ * Returns a subscription pointer on success or NULL on failure.
1484
+ *
1485
+ * See `subscribe_args_s` for details.
1486
+ */
1487
+ subscription_s *fio_subscribe(subscribe_args_s args);
1488
+ /**
1489
+ * Subscribes to either a filter OR a channel (never both).
1490
+ *
1491
+ * Returns a subscription pointer on success or NULL on failure.
1492
+ *
1493
+ * See `subscribe_args_s` for details.
1494
+ */
1495
+ #define fio_subscribe(...) fio_subscribe((subscribe_args_s){__VA_ARGS__})
1496
+
1497
+ /**
1498
+ * Cancels an existing subscriptions - actual effects might be delayed, for
1499
+ * example, if the subscription's callback is running in another thread.
1500
+ */
1501
+ void fio_unsubscribe(subscription_s *subscription);
1502
+
1503
+ /**
1504
+ * This helper returns a temporary String with the subscription's channel (or a
1505
+ * string representing the filter).
1506
+ *
1507
+ * To keep the string beyond the lifetime of the subscription, copy the string.
1508
+ */
1509
+ fio_str_info_s fio_subscription_channel(subscription_s *subscription);
1510
+
1511
+ /**
1512
+ * Publishes a message to the relevant subscribers (if any).
1513
+ *
1514
+ * See `fio_publish_args_s` for details.
1515
+ *
1516
+ * By default the message is sent using the FIO_PUBSUB_CLUSTER engine (all
1517
+ * processes, including the calling process).
1518
+ *
1519
+ * To limit the message only to other processes (exclude the calling process),
1520
+ * use the FIO_PUBSUB_SIBLINGS engine.
1521
+ *
1522
+ * To limit the message only to the calling process, use the
1523
+ * FIO_PUBSUB_PROCESS engine.
1524
+ *
1525
+ * To publish messages to the pub/sub layer, the `.filter` argument MUST be
1526
+ * equal to 0 or missing.
1527
+ */
1528
+ void fio_publish(fio_publish_args_s args);
1529
+ /**
1530
+ * Publishes a message to the relevant subscribers (if any).
1531
+ *
1532
+ * See `fio_publish_args_s` for details.
1533
+ *
1534
+ * By default the message is sent using the FIO_PUBSUB_CLUSTER engine (all
1535
+ * processes, including the calling process).
1536
+ *
1537
+ * To limit the message only to other processes (exclude the calling process),
1538
+ * use the FIO_PUBSUB_SIBLINGS engine.
1539
+ *
1540
+ * To limit the message only to the calling process, use the
1541
+ * FIO_PUBSUB_PROCESS engine.
1542
+ *
1543
+ * To publish messages to the pub/sub layer, the `.filter` argument MUST be
1544
+ * equal to 0 or missing.
1545
+ */
1546
+ #define fio_publish(...) fio_publish((fio_publish_args_s){__VA_ARGS__})
1547
+ /** for backwards compatibility */
1548
+ #define pubsub_publish fio_publish
1549
+
1550
+ /** Finds the message's metadata by it's type ID. Returns the data or NULL. */
1551
+ void *fio_message_metadata(fio_msg_s *msg, intptr_t type_id);
1552
+
1553
+ /**
1554
+ * Defers the current callback, so it will be called again for the message.
1555
+ */
1556
+ void fio_message_defer(fio_msg_s *msg);
1557
+
1558
+ /* *****************************************************************************
1559
+ * Cluster / Pub/Sub Middleware and Extensions ("Engines")
1560
+ **************************************************************************** */
1561
+
1562
+ /** Contains message metadata, set by message extensions. */
1563
+ typedef struct fio_msg_metadata_s fio_msg_metadata_s;
1564
+ struct fio_msg_metadata_s {
1565
+ /**
1566
+ * The type ID should be used to identify the metadata's actual structure.
1567
+ *
1568
+ * Negative ID values are reserved for internal use.
1569
+ */
1570
+ intptr_t type_id;
1571
+ /**
1572
+ * This method will be called by facil.io to cleanup the metadata resources.
1573
+ *
1574
+ * Don't alter / call this method, this data is reserved.
1575
+ */
1576
+ void (*on_finish)(fio_msg_s *msg, void *metadata);
1577
+ /** The pointer to be disclosed to the `fio_message_metadata` function. */
1578
+ void *metadata;
1579
+ /** RESERVED for internal use (Metadata linked list). */
1580
+ fio_msg_metadata_s *next;
1581
+ };
1582
+
1583
+ /**
1584
+ * Pub/Sub Metadata callback type.
1585
+ */
1586
+ typedef fio_msg_metadata_s (*fio_msg_metadata_fn)(fio_str_info_s ch,
1587
+ fio_str_info_s msg,
1588
+ uint8_t is_json);
1589
+
1590
+ /**
1591
+ * It's possible to attach metadata to facil.io pub/sub messages (filter == 0)
1592
+ * before they are published.
1593
+ *
1594
+ * This allows, for example, messages to be encoded as network packets for
1595
+ * outgoing protocols (i.e., encoding for WebSocket transmissions), improving
1596
+ * performance in large network based broadcasting.
1597
+ *
1598
+ * The callback should return a valid metadata object. If the `.metadata` field
1599
+ * returned is NULL than the result will be ignored.
1600
+ *
1601
+ * To remove a callback, set the `enable` flag to false (`0`).
1602
+ *
1603
+ * The cluster messaging system allows some messages to be flagged as JSON and
1604
+ * this flag is available to the metadata callback.
1605
+ */
1606
+ void fio_message_metadata_callback_set(fio_msg_metadata_fn callback,
1607
+ int enable);
1608
+
1609
+ /**
1610
+ * facil.io can be linked with external Pub/Sub services using "engines".
1611
+ *
1612
+ * Only unfiltered messages and subscriptions (where filter == 0) will be
1613
+ * forwarded to external Pub/Sub services.
1614
+ *
1615
+ * Engines MUST provide the listed function pointers and should be attached
1616
+ * using the `fio_pubsub_attach` function.
1617
+ *
1618
+ * Engines should disconnect / detach, before being destroyed, by using the
1619
+ * `fio_pubsub_detach` function.
1620
+ *
1621
+ * When an engine received a message to publish, it should call the
1622
+ * `pubsub_publish` function with the engine to which the message is forwarded.
1623
+ * i.e.:
1624
+ *
1625
+ * pubsub_publish(
1626
+ * .engine = FIO_PROCESS_ENGINE,
1627
+ * .channel = channel_name,
1628
+ * .message = msg_body );
1629
+ *
1630
+ * IMPORTANT: The `subscribe` and `unsubscribe` callbacks are called from within
1631
+ * an internal lock. They MUST NEVER call pub/sub functions except by
1632
+ * exiting the lock using `fio_defer`.
1633
+ */
1634
+ struct fio_pubsub_engine_s {
1635
+ /** Should subscribe channel. Failures are ignored. */
1636
+ void (*subscribe)(const fio_pubsub_engine_s *eng, fio_str_info_s channel,
1637
+ fio_match_fn match);
1638
+ /** Should unsubscribe channel. Failures are ignored. */
1639
+ void (*unsubscribe)(const fio_pubsub_engine_s *eng, fio_str_info_s channel,
1640
+ fio_match_fn match);
1641
+ /** Should publish a message through the engine. Failures are ignored. */
1642
+ void (*publish)(const fio_pubsub_engine_s *eng, fio_str_info_s channel,
1643
+ fio_str_info_s msg, uint8_t is_json);
1644
+ };
1645
+
1646
+ /**
1647
+ * Attaches an engine, so it's callback can be called by facil.io.
1648
+ *
1649
+ * The `subscribe` callback will be called for every existing channel.
1650
+ *
1651
+ * NOTE: the root (master) process will call `subscribe` for any channel in any
1652
+ * process, while all the other processes will call `subscribe` only for their
1653
+ * own channels. This allows engines to use the root (master) process as an
1654
+ * exclusive subscription process.
1655
+ */
1656
+ void fio_pubsub_attach(fio_pubsub_engine_s *engine);
1657
+
1658
+ /** Detaches an engine, so it could be safely destroyed. */
1659
+ void fio_pubsub_detach(fio_pubsub_engine_s *engine);
1660
+
1661
+ /**
1662
+ * Engines can ask facil.io to call the `subscribe` callback for all active
1663
+ * channels.
1664
+ *
1665
+ * This allows engines that lost their connection to their Pub/Sub service to
1666
+ * resubscribe all the currently active channels with the new connection.
1667
+ *
1668
+ * CAUTION: This is an evented task... try not to free the engine's memory while
1669
+ * resubscriptions are under way...
1670
+ *
1671
+ * NOTE: the root (master) process will call `subscribe` for any channel in any
1672
+ * process, while all the other processes will call `subscribe` only for their
1673
+ * own channels. This allows engines to use the root (master) process as an
1674
+ * exclusive subscription process.
1675
+ */
1676
+ void fio_pubsub_reattach(fio_pubsub_engine_s *eng);
1677
+
1678
+ /** Returns true (1) if the engine is attached to the system. */
1679
+ int fio_pubsub_is_attached(fio_pubsub_engine_s *engine);
1680
+
1681
+ #endif /* FIO_PUBSUB_SUPPORT */
1682
+
1683
+ /* *****************************************************************************
1684
+
1685
+
1686
+
1687
+
1688
+
1689
+
1690
+
1691
+
1692
+
1693
+
1694
+
1695
+ Atomic Operations and Spin Locking Helper Functions
1696
+
1697
+
1698
+
1699
+
1700
+
1701
+
1702
+
1703
+
1704
+
1705
+
1706
+
1707
+ ***************************************************************************** */
1708
+
1709
+ /* C11 Atomics are defined? */
1710
+ #if defined(__ATOMIC_RELAXED)
1711
+ /** An atomic exchange operation, returns previous value */
1712
+ #define fio_atomic_xchange(p_obj, value) \
1713
+ __atomic_exchange_n((p_obj), (value), __ATOMIC_SEQ_CST)
1714
+ /** An atomic addition operation */
1715
+ #define fio_atomic_add(p_obj, value) \
1716
+ __atomic_add_fetch((p_obj), (value), __ATOMIC_SEQ_CST)
1717
+ /** An atomic subtraction operation */
1718
+ #define fio_atomic_sub(p_obj, value) \
1719
+ __atomic_sub_fetch((p_obj), (value), __ATOMIC_SEQ_CST)
1720
+ /* Note: __ATOMIC_SEQ_CST is probably safer and __ATOMIC_ACQ_REL may be faster
1721
+ */
1722
+
1723
+ /* Select the correct compiler builtin method. */
1724
+ #elif __has_builtin(__sync_add_and_fetch)
1725
+ /** An atomic exchange operation, ruturns previous value */
1726
+ #define fio_atomic_xchange(p_obj, value) __sync_fetch_and_or((p_obj), (value))
1727
+ /** An atomic addition operation */
1728
+ #define fio_atomic_add(p_obj, value) __sync_add_and_fetch((p_obj), (value))
1729
+ /** An atomic subtraction operation */
1730
+ #define fio_atomic_sub(p_obj, value) __sync_sub_and_fetch((p_obj), (value))
1731
+
1732
+ #elif __GNUC__ > 3
1733
+ /** An atomic exchange operation, ruturns previous value */
1734
+ #define fio_atomic_xchange(p_obj, value) __sync_fetch_and_or((p_obj), (value))
1735
+ /** An atomic addition operation */
1736
+ #define fio_atomic_add(p_obj, value) __sync_add_and_fetch((p_obj), (value))
1737
+ /** An atomic subtraction operation */
1738
+ #define fio_atomic_sub(p_obj, value) __sync_sub_and_fetch((p_obj), (value))
1739
+
1740
+ #else
1741
+ #error Required builtin "__sync_add_and_fetch" not found.
1742
+ #endif
1743
+
1744
+ /** An atomic based spinlock. */
1745
+ typedef uint8_t volatile fio_lock_i;
1746
+
1747
+ /** The initail value of an unlocked spinlock. */
1748
+ #define FIO_LOCK_INIT 0
1749
+
1750
+ /** returns 0 if the lock was acquired and -1 on failure. */
1751
+ FIO_FUNC inline int fio_trylock(fio_lock_i *lock);
1752
+
1753
+ /** Releases a spinlock. Releasing an unacquired lock will break it. */
1754
+ FIO_FUNC inline void fio_unlock(fio_lock_i *lock);
1755
+
1756
+ /** Returns a spinlock's state (non 0 == Busy). */
1757
+ FIO_FUNC inline int fio_is_locked(fio_lock_i *lock);
1758
+
1759
+ /** Busy waits for the spinlock (CAREFUL). */
1760
+ FIO_FUNC inline void fio_lock(fio_lock_i *lock);
1761
+
1762
+ /**
1763
+ * Nanosleep seems to be the most effective and efficient thread rescheduler.
1764
+ */
1765
+ FIO_FUNC inline void fio_reschedule_thread(void);
1766
+
1767
+ /** Nanosleep the thread - a blocking throttle. */
1768
+ FIO_FUNC inline void fio_throttle_thread(size_t nano_sec);
1769
+
1770
+ /* *****************************************************************************
1771
+
1772
+
1773
+
1774
+
1775
+
1776
+
1777
+
1778
+
1779
+
1780
+
1781
+ Byte Swapping and Network Order
1782
+ (Big Endian v.s Little Endian etc')
1783
+
1784
+
1785
+
1786
+
1787
+
1788
+
1789
+
1790
+
1791
+
1792
+
1793
+
1794
+ ***************************************************************************** */
1795
+
1796
+ /** inplace byte swap 16 bit integer */
1797
+ #if __has_builtin(__builtin_bswap16)
1798
+ #define fio_bswap16(i) __builtin_bswap16((uint16_t)(i))
1799
+ #else
1800
+ #define fio_bswap16(i) ((((i)&0xFFU) << 8) | (((i)&0xFF00U) >> 8))
1801
+ #endif
1802
+ /** inplace byte swap 32 bit integer */
1803
+ #if __has_builtin(__builtin_bswap32)
1804
+ #define fio_bswap32(i) __builtin_bswap32((uint32_t)(i));
1805
+ #else
1806
+ #define fio_bswap32(i) \
1807
+ ((((i)&0xFFUL) << 24) | (((i)&0xFF00UL) << 8) | (((i)&0xFF0000UL) >> 8) | \
1808
+ (((i)&0xFF000000UL) >> 24))
1809
+ #endif
1810
+ /** inplace byte swap 64 bit integer */
1811
+ #if __has_builtin(__builtin_bswap64)
1812
+ #define fio_bswap64(i) __builtin_bswap64((uint64_t)(i));
1813
+ #else
1814
+ #define fio_bswap64(i) \
1815
+ ((((i)&0xFFULL) << 56) | (((i)&0xFF00ULL) << 40) | \
1816
+ (((i)&0xFF0000ULL) << 24) | (((i)&0xFF000000ULL) << 8) | \
1817
+ (((i)&0xFF00000000ULL) >> 8) | (((i)&0xFF0000000000ULL) >> 24) | \
1818
+ (((i)&0xFF000000000000ULL) >> 40) | (((i)&0xFF00000000000000ULL) >> 56))
1819
+ #endif
1820
+
1821
+ /* Note: using BIG_ENDIAN invokes false positives on some systems */
1822
+ #if (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__) || \
1823
+ (defined(__LITTLE_ENDIAN__) && !__LITTLE_ENDIAN__) || \
1824
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
1825
+ #define __BIG_ENDIAN__ 1
1826
+ #elif !defined(__BIG_ENDIAN__) && !defined(__BYTE_ORDER__) && \
1827
+ !defined(__LITTLE_ENDIAN__)
1828
+ #error Could not detect byte order on this system.
1829
+ #endif
1830
+
1831
+ #if __BIG_ENDIAN__
1832
+
1833
+ /** Local byte order to Network byte order, 16 bit integer */
1834
+ #define fio_lton16(i) (i)
1835
+ /** Local byte order to Network byte order, 32 bit integer */
1836
+ #define fio_lton32(i) (i)
1837
+ /** Local byte order to Network byte order, 62 bit integer */
1838
+ #define fio_lton64(i) (i)
1839
+
1840
+ /** Network byte order to Local byte order, 16 bit integer */
1841
+ #define fio_ntol16(i) (i)
1842
+ /** Network byte order to Local byte order, 32 bit integer */
1843
+ #define fio_ntol32(i) (i)
1844
+ /** Network byte order to Local byte order, 62 bit integer */
1845
+ #define fio_ntol64(i) (i)
1846
+
1847
+ /** Converts an unaligned network ordered byte stream to a 16 bit number. */
1848
+ #define fio_str2u16(c) \
1849
+ ((uint16_t)((((uint16_t)0 + ((uint8_t *)(c))[1]) << 8) | \
1850
+ ((uint16_t)0 + ((uint8_t *)(c))[0])))
1851
+ /** Converts an unaligned network ordered byte stream to a 32 bit number. */
1852
+ #define fio_str2u32(c) \
1853
+ ((uint32_t)((((uint32_t)0 + ((uint8_t *)(c))[3]) << 24) | \
1854
+ (((uint32_t)0 + ((uint8_t *)(c))[2]) << 16) | \
1855
+ (((uint32_t)0 + ((uint8_t *)(c))[1]) << 8) | \
1856
+ ((uint32_t)0 + ((uint8_t *)(c))[0])))
1857
+ /** Converts an unaligned network ordered byte stream to a 64 bit number. */
1858
+ #define fio_str2u64(c) \
1859
+ ((uint64_t)((((uint64_t)0 + ((uint8_t *)(c))[7]) << 56) | \
1860
+ (((uint64_t)0 + ((uint8_t *)(c))[6]) << 48) | \
1861
+ (((uint64_t)0 + ((uint8_t *)(c))[5]) << 40) | \
1862
+ (((uint64_t)0 + ((uint8_t *)(c))[4]) << 32) | \
1863
+ (((uint64_t)0 + ((uint8_t *)(c))[3]) << 24) | \
1864
+ (((uint64_t)0 + ((uint8_t *)(c))[2]) << 16) | \
1865
+ (((uint64_t)0 + ((uint8_t *)(c))[1]) << 8) | \
1866
+ ((uint64_t)0 + ((uint8_t *)(c))[0])))
1867
+
1868
+ #else /* Little Endian */
1869
+
1870
+ /** Local byte order to Network byte order, 16 bit integer */
1871
+ #define fio_lton16(i) fio_bswap16((i))
1872
+ /** Local byte order to Network byte order, 32 bit integer */
1873
+ #define fio_lton32(i) fio_bswap32((i))
1874
+ /** Local byte order to Network byte order, 62 bit integer */
1875
+ #define fio_lton64(i) fio_bswap64((i))
1876
+
1877
+ /** Network byte order to Local byte order, 16 bit integer */
1878
+ #define fio_ntol16(i) fio_bswap16((i))
1879
+ /** Network byte order to Local byte order, 32 bit integer */
1880
+ #define fio_ntol32(i) fio_bswap32((i))
1881
+ /** Network byte order to Local byte order, 62 bit integer */
1882
+ #define fio_ntol64(i) fio_bswap64((i))
1883
+
1884
+ /** Converts an unaligned network ordered byte stream to a 16 bit number. */
1885
+ #define fio_str2u16(c) \
1886
+ ((uint16_t)((((uint16_t)0 + ((uint8_t *)(c))[0]) << 8) | \
1887
+ ((uint16_t)0 + ((uint8_t *)(c))[1])))
1888
+ /** Converts an unaligned network ordered byte stream to a 32 bit number. */
1889
+ #define fio_str2u32(c) \
1890
+ ((uint32_t)((((uint32_t)0 + ((uint8_t *)(c))[0]) << 24) | \
1891
+ (((uint32_t)0 + ((uint8_t *)(c))[1]) << 16) | \
1892
+ (((uint32_t)0 + ((uint8_t *)(c))[2]) << 8) | \
1893
+ ((uint32_t)0 + ((uint8_t *)(c))[3])))
1894
+ /** Converts an unaligned network ordered byte stream to a 64 bit number. */
1895
+ #define fio_str2u64(c) \
1896
+ ((uint64_t)((((uint64_t)0 + ((uint8_t *)(c))[0]) << 56) | \
1897
+ (((uint64_t)0 + ((uint8_t *)(c))[1]) << 48) | \
1898
+ (((uint64_t)0 + ((uint8_t *)(c))[2]) << 40) | \
1899
+ (((uint64_t)0 + ((uint8_t *)(c))[3]) << 32) | \
1900
+ (((uint64_t)0 + ((uint8_t *)(c))[4]) << 24) | \
1901
+ (((uint64_t)0 + ((uint8_t *)(c))[5]) << 16) | \
1902
+ (((uint64_t)0 + ((uint8_t *)(c))[6]) << 8) | \
1903
+ ((uint64_t)0 + ((uint8_t *)(c))[7])))
1904
+ #endif
1905
+
1906
+ /** Writes a local 16 bit number to an unaligned buffer in network order. */
1907
+ #define fio_u2str16(buffer, i) \
1908
+ do { \
1909
+ ((uint8_t *)(buffer))[0] = ((uint16_t)(i) >> 8) & 0xFF; \
1910
+ ((uint8_t *)(buffer))[1] = ((uint16_t)(i)) & 0xFF; \
1911
+ } while (0);
1912
+
1913
+ /** Writes a local 32 bit number to an unaligned buffer in network order. */
1914
+ #define fio_u2str32(buffer, i) \
1915
+ do { \
1916
+ ((uint8_t *)(buffer))[0] = ((uint32_t)(i) >> 24) & 0xFF; \
1917
+ ((uint8_t *)(buffer))[1] = ((uint32_t)(i) >> 16) & 0xFF; \
1918
+ ((uint8_t *)(buffer))[2] = ((uint32_t)(i) >> 8) & 0xFF; \
1919
+ ((uint8_t *)(buffer))[3] = ((uint32_t)(i)) & 0xFF; \
1920
+ } while (0);
1921
+
1922
+ /** Writes a local 64 bit number to an unaligned buffer in network order. */
1923
+ #define fio_u2str64(buffer, i) \
1924
+ do { \
1925
+ ((uint8_t *)(buffer))[0] = ((uint64_t)(i) >> 56) & 0xFF; \
1926
+ ((uint8_t *)(buffer))[1] = ((uint64_t)(i) >> 48) & 0xFF; \
1927
+ ((uint8_t *)(buffer))[2] = ((uint64_t)(i) >> 40) & 0xFF; \
1928
+ ((uint8_t *)(buffer))[3] = ((uint64_t)(i) >> 32) & 0xFF; \
1929
+ ((uint8_t *)(buffer))[4] = ((uint64_t)(i) >> 24) & 0xFF; \
1930
+ ((uint8_t *)(buffer))[5] = ((uint64_t)(i) >> 16) & 0xFF; \
1931
+ ((uint8_t *)(buffer))[6] = ((uint64_t)(i) >> 8) & 0xFF; \
1932
+ ((uint8_t *)(buffer))[7] = ((uint64_t)(i)) & 0xFF; \
1933
+ } while (0);
1934
+
1935
+ /* *****************************************************************************
1936
+
1937
+
1938
+
1939
+
1940
+
1941
+
1942
+
1943
+
1944
+
1945
+
1946
+ Converting Numbers to Strings (and back)
1947
+
1948
+
1949
+
1950
+
1951
+
1952
+
1953
+
1954
+
1955
+
1956
+
1957
+
1958
+ ***************************************************************************** */
1959
+
1960
+ /* *****************************************************************************
1961
+ Strings to Numbers
1962
+ ***************************************************************************** */
1963
+
1964
+ /**
1965
+ * A helper function that converts between String data to a signed int64_t.
1966
+ *
1967
+ * Numbers are assumed to be in base 10. Octal (`0###`), Hex (`0x##`/`x##`) and
1968
+ * binary (`0b##`/ `b##`) are recognized as well. For binary Most Significant
1969
+ * Bit must come first.
1970
+ *
1971
+ * The most significant difference between this function and `strtol` (aside of
1972
+ * API design), is the added support for binary representations.
1973
+ */
1974
+ int64_t fio_atol(char **pstr);
1975
+
1976
+ /** A helper function that converts between String data to a signed double. */
1977
+ double fio_atof(char **pstr);
1978
+
1979
+ /* *****************************************************************************
1980
+ Numbers to Strings
1981
+ ***************************************************************************** */
1982
+
1983
+ /**
1984
+ * A helper function that writes a signed int64_t to a string.
1985
+ *
1986
+ * No overflow guard is provided, make sure there's at least 68 bytes
1987
+ * available (for base 2).
1988
+ *
1989
+ * Offers special support for base 2 (binary), base 8 (octal), base 10 and base
1990
+ * 16 (hex). An unsupported base will silently default to base 10. Prefixes
1991
+ * aren't added (i.e., no "0x" or "0b" at the beginning of the string).
1992
+ *
1993
+ * Returns the number of bytes actually written (excluding the NUL
1994
+ * terminator).
1995
+ */
1996
+ size_t fio_ltoa(char *dest, int64_t num, uint8_t base);
1997
+
1998
+ /**
1999
+ * A helper function that converts between a double to a string.
2000
+ *
2001
+ * No overflow guard is provided, make sure there's at least 130 bytes
2002
+ * available (for base 2).
2003
+ *
2004
+ * Supports base 2, base 10 and base 16. An unsupported base will silently
2005
+ * default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the
2006
+ * beginning of the string).
2007
+ *
2008
+ * Returns the number of bytes actually written (excluding the NUL
2009
+ * terminator).
2010
+ */
2011
+ size_t fio_ftoa(char *dest, double num, uint8_t base);
2012
+
2013
+ /* *****************************************************************************
2014
+
2015
+
2016
+
2017
+
2018
+
2019
+
2020
+
2021
+ Random Generator Functions
2022
+
2023
+ Probably not cryptographically safe
2024
+
2025
+
2026
+
2027
+
2028
+
2029
+
2030
+
2031
+ ***************************************************************************** */
2032
+
2033
+ /** Returns 64 psedo-random bits. Probably not cryptographically safe. */
2034
+ uint64_t fio_rand64(void);
2035
+
2036
+ /** Writes `length` bytes of psedo-random bits to the target buffer. */
2037
+ void fio_rand_bytes(void *target, size_t length);
2038
+
2039
+ /* *****************************************************************************
2040
+
2041
+
2042
+
2043
+
2044
+
2045
+
2046
+
2047
+ Hash Functions and Friends
2048
+
2049
+
2050
+
2051
+
2052
+
2053
+
2054
+
2055
+ ***************************************************************************** */
2056
+
2057
+ /* *****************************************************************************
2058
+ SipHash
2059
+ ***************************************************************************** */
2060
+
2061
+ /**
2062
+ * A SipHash variation (2-4).
2063
+ */
2064
+ uint64_t fio_siphash24(const void *data, size_t len);
2065
+
2066
+ /**
2067
+ * A SipHash 1-3 variation.
2068
+ */
2069
+ uint64_t fio_siphash13(const void *data, size_t len);
2070
+
2071
+ /**
2072
+ * The Hashing function used by dynamic facil.io objects.
2073
+ *
2074
+ * Currently implemented using SipHash 1-3.
2075
+ */
2076
+ #define fio_siphash(data, length) fio_siphash13((data), (length))
2077
+
2078
+ /* *****************************************************************************
2079
+ SHA-1
2080
+ ***************************************************************************** */
2081
+
2082
+ /**
2083
+ SHA-1 hashing container - you should ignore the contents of this struct.
2084
+
2085
+ The `sha1_s` type will contain all the sha1 data required to perform the
2086
+ hashing, managing it's encoding. If it's stack allocated, no freeing will be
2087
+ required.
2088
+
2089
+ Use, for example:
2090
+
2091
+ fio_sha1_s sha1;
2092
+ fio_sha1_init(&sha1);
2093
+ fio_sha1_write(&sha1,
2094
+ "The quick brown fox jumps over the lazy dog", 43);
2095
+ char *hashed_result = fio_sha1_result(&sha1);
2096
+ */
2097
+ typedef struct {
2098
+ uint64_t length;
2099
+ uint8_t buffer[64];
2100
+ union {
2101
+ uint32_t i[5];
2102
+ unsigned char str[21];
2103
+ } digest;
2104
+ } fio_sha1_s;
2105
+
2106
+ /**
2107
+ Initialize or reset the `sha1` object. This must be performed before hashing
2108
+ data using sha1.
2109
+ */
2110
+ fio_sha1_s fio_sha1_init(void);
2111
+ /**
2112
+ Writes data to the sha1 buffer.
2113
+ */
2114
+ void fio_sha1_write(fio_sha1_s *s, const void *data, size_t len);
2115
+ /**
2116
+ Finalizes the SHA1 hash, returning the Hashed data.
2117
+
2118
+ `fio_sha1_result` can be called for the same object multiple times, but the
2119
+ finalization will only be performed the first time this function is called.
2120
+ */
2121
+ char *fio_sha1_result(fio_sha1_s *s);
2122
+
2123
+ /**
2124
+ An SHA1 helper function that performs initialiation, writing and finalizing.
2125
+ */
2126
+ inline FIO_FUNC char *fio_sha1(fio_sha1_s *s, const void *data, size_t len) {
2127
+ *s = fio_sha1_init();
2128
+ fio_sha1_write(s, data, len);
2129
+ return fio_sha1_result(s);
2130
+ }
2131
+
2132
+ /* *****************************************************************************
2133
+ SHA-2
2134
+ ***************************************************************************** */
2135
+
2136
+ /**
2137
+ SHA-2 function variants.
2138
+
2139
+ This enum states the different SHA-2 function variants. placing SHA_512 at the
2140
+ beginning is meant to set this variant as the default (in case a 0 is passed).
2141
+ */
2142
+ typedef enum {
2143
+ SHA_512 = 1,
2144
+ SHA_512_256 = 3,
2145
+ SHA_512_224 = 5,
2146
+ SHA_384 = 7,
2147
+ SHA_256 = 2,
2148
+ SHA_224 = 4,
2149
+ } fio_sha2_variant_e;
2150
+
2151
+ /**
2152
+ SHA-2 hashing container - you should ignore the contents of this struct.
2153
+
2154
+ The `sha2_s` type will contain all the SHA-2 data required to perform the
2155
+ hashing, managing it's encoding. If it's stack allocated, no freeing will be
2156
+ required.
2157
+
2158
+ Use, for example:
2159
+
2160
+ fio_sha2_s sha2;
2161
+ fio_sha2_init(&sha2, SHA_512);
2162
+ fio_sha2_write(&sha2,
2163
+ "The quick brown fox jumps over the lazy dog", 43);
2164
+ char *hashed_result = fio_sha2_result(&sha2);
2165
+
2166
+ */
2167
+ typedef struct {
2168
+ /* notice: we're counting bits, not bytes. max length: 2^128 bits */
2169
+ union {
2170
+ uint8_t bytes[16];
2171
+ uint8_t matrix[4][4];
2172
+ uint32_t words_small[4];
2173
+ uint64_t words[2];
2174
+ #if defined(__SIZEOF_INT128__)
2175
+ __uint128_t i;
2176
+ #endif
2177
+ } length;
2178
+ uint8_t buffer[128];
2179
+ union {
2180
+ uint32_t i32[16];
2181
+ uint64_t i64[8];
2182
+ uint8_t str[65]; /* added 64+1 for the NULL byte.*/
2183
+ } digest;
2184
+ fio_sha2_variant_e type;
2185
+ } fio_sha2_s;
2186
+
2187
+ /**
2188
+ Initialize/reset the SHA-2 object.
2189
+
2190
+ SHA-2 is actually a family of functions with different variants. When
2191
+ initializing the SHA-2 container, you must select the variant you intend to
2192
+ apply. The following are valid options (see the sha2_variant enum):
2193
+
2194
+ - SHA_512 (== 0)
2195
+ - SHA_384
2196
+ - SHA_512_224
2197
+ - SHA_512_256
2198
+ - SHA_256
2199
+ - SHA_224
2200
+
2201
+ */
2202
+ fio_sha2_s fio_sha2_init(fio_sha2_variant_e variant);
2203
+ /**
2204
+ Writes data to the SHA-2 buffer.
2205
+ */
2206
+ void fio_sha2_write(fio_sha2_s *s, const void *data, size_t len);
2207
+ /**
2208
+ Finalizes the SHA-2 hash, returning the Hashed data.
2209
+
2210
+ `sha2_result` can be called for the same object multiple times, but the
2211
+ finalization will only be performed the first time this function is called.
2212
+ */
2213
+ char *fio_sha2_result(fio_sha2_s *s);
2214
+
2215
+ /**
2216
+ An SHA2 helper function that performs initialiation, writing and finalizing.
2217
+ Uses the SHA2 512 variant.
2218
+ */
2219
+ inline FIO_FUNC char *fio_sha2_512(fio_sha2_s *s, const void *data,
2220
+ size_t len) {
2221
+ *s = fio_sha2_init(SHA_512);
2222
+ fio_sha2_write(s, data, len);
2223
+ return fio_sha2_result(s);
2224
+ }
2225
+
2226
+ /**
2227
+ An SHA2 helper function that performs initialiation, writing and finalizing.
2228
+ Uses the SHA2 256 variant.
2229
+ */
2230
+ inline FIO_FUNC char *fio_sha2_256(fio_sha2_s *s, const void *data,
2231
+ size_t len) {
2232
+ *s = fio_sha2_init(SHA_256);
2233
+ fio_sha2_write(s, data, len);
2234
+ return fio_sha2_result(s);
2235
+ }
2236
+
2237
+ /**
2238
+ An SHA2 helper function that performs initialiation, writing and finalizing.
2239
+ Uses the SHA2 384 variant.
2240
+ */
2241
+ inline FIO_FUNC char *fio_sha2_384(fio_sha2_s *s, const void *data,
2242
+ size_t len) {
2243
+ *s = fio_sha2_init(SHA_384);
2244
+ fio_sha2_write(s, data, len);
2245
+ return fio_sha2_result(s);
2246
+ }
2247
+
2248
+ /* *****************************************************************************
2249
+ Base64 (URL) encoding
2250
+ ***************************************************************************** */
2251
+
2252
+ /**
2253
+ This will encode a byte array (data) of a specified length (len) and
2254
+ place the encoded data into the target byte buffer (target). The target buffer
2255
+ MUST have enough room for the expected data.
2256
+
2257
+ Base64 encoding always requires 4 bytes for each 3 bytes. Padding is added if
2258
+ the raw data's length isn't devisable by 3.
2259
+
2260
+ Always assume the target buffer should have room enough for (len*4/3 + 4)
2261
+ bytes.
2262
+
2263
+ Returns the number of bytes actually written to the target buffer
2264
+ (including the Base64 required padding and excluding a NULL terminator).
2265
+
2266
+ A NULL terminator char is NOT written to the target buffer.
2267
+ */
2268
+ int fio_base64_encode(char *target, const char *data, int len);
2269
+
2270
+ /**
2271
+ Same as fio_base64_encode, but using Base64URL encoding.
2272
+ */
2273
+ int fio_base64url_encode(char *target, const char *data, int len);
2274
+
2275
+ /**
2276
+ This will decode a Base64 encoded string of a specified length (len) and
2277
+ place the decoded data into the target byte buffer (target).
2278
+
2279
+ The target buffer MUST have enough room for 2 bytes in addition to the expected
2280
+ data (NUL byte + padding test).
2281
+
2282
+ A NUL byte will be appended to the target buffer. The function will return
2283
+ the number of bytes written to the target buffer (excluding the NUL byte).
2284
+
2285
+ If the target buffer is NUL, the encoded string will be destructively edited
2286
+ and the decoded data will be placed in the original string's buffer.
2287
+
2288
+ Base64 encoding always requires 4 bytes for each 3 bytes. Padding is added if
2289
+ the raw data's length isn't devisable by 3. Hence, the target buffer should
2290
+ be, at least, `base64_len/4*3 + 3` long.
2291
+
2292
+ Returns the number of bytes actually written to the target buffer (excluding
2293
+ the NUL terminator byte).
2294
+
2295
+ Note:
2296
+ ====
2297
+
2298
+ The decoder is variation agnostic (will decode Base64, Base64 URL and Base64 XML
2299
+ variations) and will attempt it's best to ignore invalid data, (in order to
2300
+ support the MIME Base64 variation in RFC 2045).
2301
+
2302
+ This comes at the cost of error
2303
+ checking, so the encoding isn't validated and invalid input might produce
2304
+ surprising results.
2305
+ */
2306
+ int fio_base64_decode(char *target, char *encoded, int base64_len);
2307
+
2308
+ /* *****************************************************************************
2309
+ Testing
2310
+ ***************************************************************************** */
2311
+
2312
+ #if DEBUG
2313
+ void fio_test(void);
2314
+ #else
2315
+ #define fio_test()
2316
+ #endif
2317
+
2318
+ /* *****************************************************************************
2319
+ C++ extern end
2320
+ ***************************************************************************** */
2321
+ #ifdef __cplusplus
2322
+ } /* extern "C" */
2323
+ #endif
2324
+
2325
+ /* *****************************************************************************
2326
+
2327
+
2328
+
2329
+
2330
+
2331
+
2332
+
2333
+
2334
+ Memory Allocator Details
2335
+
2336
+
2337
+
2338
+
2339
+
2340
+
2341
+
2342
+
2343
+ ***************************************************************************** */
2344
+
2345
+ /**
2346
+ * This is a custom memory allocator the utilizes memory pools to allow for
2347
+ * concurrent memory allocations across threads.
2348
+ *
2349
+ * Allocated memory is always zeroed out and aligned on a 16 byte boundary.
2350
+ *
2351
+ * Reallocated memory is always aligned on a 16 byte boundary but it might be
2352
+ * filled with junk data after the valid data (this is true also for
2353
+ * `fio_realloc2`).
2354
+ *
2355
+ * The memory allocator assumes multiple concurrent allocation/deallocation,
2356
+ * short life spans (memory is freed shortly, but not immediately, after it was
2357
+ * allocated) as well as small allocations (realloc almost always copies data).
2358
+ *
2359
+ * These assumptions allow the allocator to avoid lock contention by ignoring
2360
+ * fragmentation within a memory "block" and waiting for the whole "block" to be
2361
+ * freed before it's memory is recycled (no per-allocation "free list").
2362
+ *
2363
+ * An "arena" is allocated per-CPU core during initialization - there's no
2364
+ * dynamic allocation of arenas. This allows threads to minimize lock contention
2365
+ * by cycling through the arenas until a free arena is detected.
2366
+ *
2367
+ * There should be a free arena at any given time (statistically speaking) and
2368
+ * the thread will only be deferred in the unlikely event in which there's no
2369
+ * available arena.
2370
+ *
2371
+ * By avoiding the "free-list", the need for allocation "headers" is also
2372
+ * avoided and allocations are performed with practically zero overhead (about
2373
+ * 32 bytes overhead per 32KB memory, that's 1 bit per 1Kb).
2374
+ *
2375
+ * However, the lack of a "free list" means that memory "leaks" are more
2376
+ * expensive and small long-life allocations could cause fragmentation if
2377
+ * performed periodically (rather than performed during startup).
2378
+ *
2379
+ * This allocator should NOT be used for objects with a long life-span, because
2380
+ * even a single persistent object will prevent the re-use of the whole memory
2381
+ * block from which it was allocated (see FIO_MEMORY_BLOCK_SIZE for size).
2382
+ *
2383
+ * Some more details:
2384
+ *
2385
+ * Allocation and deallocations and (usually) managed by "blocks".
2386
+ *
2387
+ * A memory "block" can include any number of memory pages that are a multiple
2388
+ * of 2 (up to 1Mb of memory). However, the default value, set by the value of
2389
+ * FIO_MEMORY_BLOCK_SIZE_LOG, is 32Kb (see value at the end of this header).
2390
+ *
2391
+ * Each block includes a 32 byte header that uses reference counters and
2392
+ * position markers (24 bytes are required padding).
2393
+ *
2394
+ * The block's position marker (`pos`) marks the next available byte (counted in
2395
+ * multiples of 16 bytes).
2396
+ *
2397
+ * The block's reference counter (`ref`) counts how many allocations reference
2398
+ * memory in the block (including the "arena" that "owns" the block).
2399
+ *
2400
+ * Except for the position marker (`pos`) that acts the same as `sbrk`, there's
2401
+ * no way to know which "slices" are allocated and which "slices" are available.
2402
+ *
2403
+ * The allocator uses `mmap` when requesting memory from the system and for
2404
+ * allocations bigger than MEMORY_BLOCK_ALLOC_LIMIT (37.5% of the block).
2405
+ *
2406
+ * Small allocations are differentiated from big allocations by their memory
2407
+ * alignment.
2408
+ *
2409
+ * If a memory allocation is placed 16 bytes after whole block alignment (within
2410
+ * a block's padding zone), the memory was allocated directly using `mmap` as a
2411
+ * "big allocation". The 16 bytes include an 8 byte header and an 8 byte
2412
+ * padding.
2413
+ *
2414
+ * To replace the system's `malloc` function family compile with the
2415
+ * `FIO_OVERRIDE_MALLOC` defined (`-DFIO_OVERRIDE_MALLOC`).
2416
+ *
2417
+ * When using tcmalloc or jemalloc, it's possible to define `FIO_FORCE_MALLOC`
2418
+ * to prevent the facil.io allocator from compiling (`-DFIO_FORCE_MALLOC`).
2419
+ */
2420
+ #define H_FIO_MEM_H /* prevent fiobj conflicts */
2421
+
2422
+ /** Allocator default settings. */
2423
+
2424
+ /** The logarithmic value for a memory block, 15 == 32Kb, 16 == 64Kb, etc' */
2425
+ #ifndef FIO_MEMORY_BLOCK_SIZE_LOG
2426
+ #define FIO_MEMORY_BLOCK_SIZE_LOG (15)
2427
+ #endif
2428
+
2429
+ /* dounb't change these - they are derived from FIO_MEMORY_BLOCK_SIZE_LOG */
2430
+ #undef FIO_MEMORY_BLOCK_SIZE
2431
+ #undef FIO_MEMORY_BLOCK_MASK
2432
+ #undef FIO_MEMORY_BLOCK_SLICES
2433
+ #define FIO_MEMORY_BLOCK_MASK (FIO_MEMORY_BLOCK_SIZE - 1) /* 0b111... */
2434
+ #define FIO_MEMORY_BLOCK_SLICES (FIO_MEMORY_BLOCK_SIZE >> 4) /* 16B slices */
2435
+ #define FIO_MEMORY_BLOCK_SIZE ((uintptr_t)1 << FIO_MEMORY_BLOCK_SIZE_LOG)
2436
+
2437
+ #ifndef FIO_MEMORY_BLOCK_ALLOC_LIMIT
2438
+ /* defaults to 37.5% of the block, after which `mmap` is used instead */
2439
+ #define FIO_MEMORY_BLOCK_ALLOC_LIMIT \
2440
+ ((FIO_MEMORY_BLOCK_SIZE >> 2) + (FIO_MEMORY_BLOCK_SIZE >> 3))
2441
+ #endif
2442
+
2443
+ #ifndef FIO_MEM_MAX_BLOCKS_PER_CORE
2444
+ /**
2445
+ * The maximum number of available memory blocks that will be pooled before
2446
+ * memory is returned to the system.
2447
+ */
2448
+ #define FIO_MEM_MAX_BLOCKS_PER_CORE \
2449
+ (1 << (22 - FIO_MEMORY_BLOCK_SIZE_LOG)) /* 22 == 4Mb per CPU core (1<<22) */
2450
+ #endif
2451
+
2452
+ /* *****************************************************************************
2453
+
2454
+
2455
+
2456
+
2457
+
2458
+
2459
+
2460
+
2461
+
2462
+ Spin locking Implementation
2463
+
2464
+
2465
+
2466
+
2467
+
2468
+
2469
+
2470
+
2471
+
2472
+ ***************************************************************************** */
2473
+
2474
+ /**
2475
+ * Nanosleep seems to be the most effective and efficient thread rescheduler.
2476
+ */
2477
+ FIO_FUNC inline void fio_reschedule_thread(void) {
2478
+ const struct timespec tm = {.tv_nsec = 1};
2479
+ nanosleep(&tm, NULL);
2480
+ }
2481
+
2482
+ /** Nanosleep the thread - a blocking throttle. */
2483
+ FIO_FUNC inline void fio_throttle_thread(size_t nano_sec) {
2484
+ const struct timespec tm = {.tv_nsec = (nano_sec % 1000000000),
2485
+ .tv_sec = (nano_sec / 1000000000)};
2486
+ nanosleep(&tm, NULL);
2487
+ }
2488
+
2489
+ /** returns 0 if the lock was acquired and -1 on failure. */
2490
+ FIO_FUNC inline int fio_trylock(fio_lock_i *lock) {
2491
+ __asm__ volatile("" ::: "memory");
2492
+ fio_lock_i ret = fio_atomic_xchange(lock, 1);
2493
+ __asm__ volatile("" ::: "memory");
2494
+ return ret;
2495
+ }
2496
+
2497
+ /** Releases a spinlock. Releasing an unacquired lock will break it. */
2498
+ FIO_FUNC inline void fio_unlock(fio_lock_i *lock) {
2499
+ __asm__ volatile("" ::: "memory");
2500
+ fio_atomic_xchange(lock, 0);
2501
+ }
2502
+
2503
+ /** Returns a spinlock's state (non 0 == Busy). */
2504
+ FIO_FUNC inline int fio_is_locked(fio_lock_i *lock) {
2505
+ __asm__ volatile("" ::: "memory");
2506
+ return *lock;
2507
+ }
2508
+
2509
+ /** Busy waits for the spinlock (CAREFUL). */
2510
+ FIO_FUNC inline void fio_lock(fio_lock_i *lock) {
2511
+ while (fio_trylock(lock)) {
2512
+ fio_reschedule_thread();
2513
+ }
2514
+ }
2515
+
2516
+ #if DEBUG_SPINLOCK
2517
+ /** Busy waits for a lock, reports contention. */
2518
+ FIO_FUNC inline void fio_lock_dbg(fio_lock_i *lock, const char *file,
2519
+ int line) {
2520
+ size_t lock_cycle_count = 0;
2521
+ while (fio_trylock(lock)) {
2522
+ if (lock_cycle_count >= 8 &&
2523
+ (lock_cycle_count == 8 || !(lock_cycle_count & 511)))
2524
+ fprintf(stderr, "INFO: fio-spinlock spin %s:%d round %zu\n", file, line,
2525
+ lock_cycle_count);
2526
+ ++lock_cycle_count;
2527
+ fio_reschedule_thread();
2528
+ }
2529
+ if (lock_cycle_count >= 8)
2530
+ fprintf(stderr, "INFO: fio-spinlock spin %s:%d total = %zu\n", file, line,
2531
+ lock_cycle_count);
2532
+ }
2533
+ #define fio_lock(lock) fio_lock_dbg((lock), __FILE__, __LINE__)
2534
+
2535
+ FIO_FUNC inline int fio_trylock_dbg(fio_lock_i *lock, const char *file,
2536
+ int line) {
2537
+ static int last_line = 0;
2538
+ static size_t count = 0;
2539
+ int result = fio_trylock(lock);
2540
+ if (!result) {
2541
+ count = 0;
2542
+ last_line = 0;
2543
+ } else if (line == last_line) {
2544
+ ++count;
2545
+ if (count >= 2)
2546
+ fprintf(stderr, "INFO: trying fio-spinlock %s:%d attempt %zu\n", file,
2547
+ line, count);
2548
+ } else {
2549
+ count = 0;
2550
+ last_line = line;
2551
+ }
2552
+ return result;
2553
+ }
2554
+ #define fio_trylock(lock) fio_trylock_dbg((lock), __FILE__, __LINE__)
2555
+ #endif /* DEBUG_SPINLOCK */
2556
+
2557
+ #endif /* H_FACIL_IO_H */
2558
+
2559
+ /* *****************************************************************************
2560
+
2561
+
2562
+
2563
+
2564
+
2565
+
2566
+ Linked List Helpers
2567
+
2568
+ exposes internally used inline helpers for linked lists
2569
+
2570
+
2571
+
2572
+
2573
+
2574
+
2575
+ ***************************************************************************** */
2576
+
2577
+ #if !defined(H_FIO_LINKED_LIST_H) && defined(FIO_INCLUDE_LINKED_LIST)
2578
+
2579
+ #define H_FIO_LINKED_LIST_H
2580
+ #undef FIO_INCLUDE_LINKED_LIST
2581
+ /* *****************************************************************************
2582
+ Data Structure and Initialization.
2583
+ ***************************************************************************** */
2584
+
2585
+ /** an embeded linked list. */
2586
+ typedef struct fio_ls_embd_s {
2587
+ struct fio_ls_embd_s *prev;
2588
+ struct fio_ls_embd_s *next;
2589
+ } fio_ls_embd_s;
2590
+
2591
+ /** an independent linked list. */
2592
+ typedef struct fio_ls_s {
2593
+ struct fio_ls_s *prev;
2594
+ struct fio_ls_s *next;
2595
+ const void *obj;
2596
+ } fio_ls_s;
2597
+
2598
+ #define FIO_LS_INIT(name) \
2599
+ { .next = &(name), .prev = &(name) }
2600
+
2601
+ /* *****************************************************************************
2602
+ Embedded Linked List API
2603
+ ***************************************************************************** */
2604
+
2605
+ /** Adds a node to the list's head. */
2606
+ FIO_FUNC inline void fio_ls_embd_push(fio_ls_embd_s *dest, fio_ls_embd_s *node);
2607
+
2608
+ /** Adds a node to the list's tail. */
2609
+ FIO_FUNC inline void fio_ls_embd_unshift(fio_ls_embd_s *dest,
2610
+ fio_ls_embd_s *node);
2611
+
2612
+ /** Removes a node from the list's head. */
2613
+ FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_pop(fio_ls_embd_s *list);
2614
+
2615
+ /** Removes a node from the list's tail. */
2616
+ FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_shift(fio_ls_embd_s *list);
2617
+
2618
+ /** Removes a node from the containing node. */
2619
+ FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_remove(fio_ls_embd_s *node);
2620
+
2621
+ /** Tests if the list is empty. */
2622
+ FIO_FUNC inline int fio_ls_embd_is_empty(fio_ls_embd_s *list);
2623
+
2624
+ /** Tests if the list is NOT empty (contains any nodes). */
2625
+ FIO_FUNC inline int fio_ls_embd_any(fio_ls_embd_s *list);
2626
+
2627
+ /**
2628
+ * Iterates through the list using a `for` loop.
2629
+ *
2630
+ * Access the data with `pos->obj` (`pos` can be named however you please).
2631
+ */
2632
+ #define FIO_LS_EMBD_FOR(list, node)
2633
+
2634
+ /**
2635
+ * Takes a list pointer `plist` and returns a pointer to it's container.
2636
+ *
2637
+ * This uses pointer offset calculations and can be used to calculate any
2638
+ * struct's pointer (not just list containers) as an offset from a pointer of
2639
+ * one of it's members.
2640
+ *
2641
+ * Very useful.
2642
+ */
2643
+ #define FIO_LS_EMBD_OBJ(type, member, plist) \
2644
+ ((type *)((uintptr_t)(plist) - (uintptr_t)(&(((type *)0)->member))))
2645
+
2646
+ /* *****************************************************************************
2647
+ Independent Linked List API
2648
+ ***************************************************************************** */
2649
+
2650
+ /** Adds an object to the list's head. */
2651
+ FIO_FUNC inline void fio_ls_push(fio_ls_s *pos, const void *obj);
2652
+
2653
+ /** Adds an object to the list's tail. */
2654
+ FIO_FUNC inline void fio_ls_unshift(fio_ls_s *pos, const void *obj);
2655
+
2656
+ /** Removes an object from the list's head. */
2657
+ FIO_FUNC inline void *fio_ls_pop(fio_ls_s *list);
2658
+
2659
+ /** Removes an object from the list's tail. */
2660
+ FIO_FUNC inline void *fio_ls_shift(fio_ls_s *list);
2661
+
2662
+ /** Removes a node from the list, returning the contained object. */
2663
+ FIO_FUNC inline void *fio_ls_remove(fio_ls_s *node);
2664
+
2665
+ /** Tests if the list is empty. */
2666
+ FIO_FUNC inline int fio_ls_is_empty(fio_ls_s *list);
2667
+
2668
+ /** Tests if the list is NOT empty (contains any nodes). */
2669
+ FIO_FUNC inline int fio_ls_any(fio_ls_s *list);
2670
+
2671
+ /**
2672
+ * Iterates through the list using a `for` loop.
2673
+ *
2674
+ * Access the data with `pos->obj` (`pos` can be named however you please).
2675
+ */
2676
+ #define FIO_LS_FOR(list, pos)
2677
+
2678
+ /* *****************************************************************************
2679
+
2680
+
2681
+ Linked List Helpers
2682
+
2683
+ IMPLEMENTATION
2684
+
2685
+
2686
+ ***************************************************************************** */
2687
+
2688
+ /* *****************************************************************************
2689
+ Embeded Linked List Implementation
2690
+ ***************************************************************************** */
2691
+
2692
+ /** Removes a node from the containing node. */
2693
+ FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_remove(fio_ls_embd_s *node) {
2694
+ if (node->next == node) {
2695
+ /* never remove the list's head */
2696
+ return NULL;
2697
+ }
2698
+ node->next->prev = node->prev;
2699
+ node->prev->next = node->next;
2700
+ return node;
2701
+ }
2702
+
2703
+ /** Adds a node to the list's head. */
2704
+ FIO_FUNC inline void fio_ls_embd_push(fio_ls_embd_s *dest,
2705
+ fio_ls_embd_s *node) {
2706
+ node->prev = dest->prev;
2707
+ node->next = dest;
2708
+ dest->prev->next = node;
2709
+ dest->prev = node;
2710
+ }
2711
+
2712
+ /** Adds a node to the list's tail. */
2713
+ FIO_FUNC inline void fio_ls_embd_unshift(fio_ls_embd_s *dest,
2714
+ fio_ls_embd_s *node) {
2715
+ fio_ls_embd_push(dest->next, node);
2716
+ }
2717
+
2718
+ /** Removes a node from the list's head. */
2719
+ FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_pop(fio_ls_embd_s *list) {
2720
+ return fio_ls_embd_remove(list->prev);
2721
+ }
2722
+
2723
+ /** Removes a node from the list's tail. */
2724
+ FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_shift(fio_ls_embd_s *list) {
2725
+ return fio_ls_embd_remove(list->next);
2726
+ }
2727
+
2728
+ /** Tests if the list is empty. */
2729
+ FIO_FUNC inline int fio_ls_embd_is_empty(fio_ls_embd_s *list) {
2730
+ return list->next == list;
2731
+ }
2732
+
2733
+ /** Tests if the list is NOT empty (contains any nodes). */
2734
+ FIO_FUNC inline int fio_ls_embd_any(fio_ls_embd_s *list) {
2735
+ return list->next != list;
2736
+ }
2737
+
2738
+ #undef FIO_LS_EMBD_FOR
2739
+ #define FIO_LS_EMBD_FOR(list, node) \
2740
+ for (fio_ls_embd_s *node = (list)->next; node != (list); node = node->next)
2741
+
2742
+ /* *****************************************************************************
2743
+ Independent Linked List Implementation
2744
+ ***************************************************************************** */
2745
+
2746
+ /** Removes an object from the containing node. */
2747
+ FIO_FUNC inline void *fio_ls_remove(fio_ls_s *node) {
2748
+ if (node->next == node) {
2749
+ /* never remove the list's head */
2750
+ return NULL;
2751
+ }
2752
+ const void *ret = node->obj;
2753
+ node->next->prev = node->prev;
2754
+ node->prev->next = node->next;
2755
+ free(node);
2756
+ return (void *)ret;
2757
+ }
2758
+
2759
+ /** Adds an object to the list's head. */
2760
+ FIO_FUNC inline void fio_ls_push(fio_ls_s *pos, const void *obj) {
2761
+ /* prepare item */
2762
+ fio_ls_s *item = (fio_ls_s *)malloc(sizeof(*item));
2763
+ if (!item) {
2764
+ perror("ERROR: simple list couldn't allocate memory");
2765
+ exit(errno);
2766
+ }
2767
+ *item = (fio_ls_s){.prev = pos->prev, .next = pos, .obj = obj};
2768
+ /* inject item */
2769
+ pos->prev->next = item;
2770
+ pos->prev = item;
2771
+ }
2772
+
2773
+ /** Adds an object to the list's tail. */
2774
+ FIO_FUNC inline void fio_ls_unshift(fio_ls_s *pos, const void *obj) {
2775
+ fio_ls_push(pos->next, obj);
2776
+ }
2777
+
2778
+ /** Removes an object from the list's head. */
2779
+ FIO_FUNC inline void *fio_ls_pop(fio_ls_s *list) {
2780
+ return fio_ls_remove(list->prev);
2781
+ }
2782
+
2783
+ /** Removes an object from the list's tail. */
2784
+ FIO_FUNC inline void *fio_ls_shift(fio_ls_s *list) {
2785
+ return fio_ls_remove(list->next);
2786
+ }
2787
+
2788
+ /** Tests if the list is empty. */
2789
+ FIO_FUNC inline int fio_ls_is_empty(fio_ls_s *list) {
2790
+ return list->next == list;
2791
+ }
2792
+
2793
+ /** Tests if the list is NOT empty (contains any nodes). */
2794
+ FIO_FUNC inline int fio_ls_any(fio_ls_s *list) { return list->next != list; }
2795
+
2796
+ #undef FIO_LS_FOR
2797
+ #define FIO_LS_FOR(list, pos) \
2798
+ for (fio_ls_s *pos = (list)->next; pos != (list); pos = pos->next)
2799
+
2800
+ #endif /* FIO_INCLUDE_LINKED_LIST */
2801
+
2802
+ /* *****************************************************************************
2803
+
2804
+
2805
+
2806
+
2807
+
2808
+
2809
+
2810
+ String Helpers
2811
+
2812
+ exposes internally used inline helpers for binary Strings
2813
+
2814
+
2815
+
2816
+
2817
+
2818
+
2819
+
2820
+ ***************************************************************************** */
2821
+
2822
+ #if !defined(H_FIO_STR_H) && defined(FIO_INCLUDE_STR)
2823
+
2824
+ #define H_FIO_STR_H
2825
+ #undef FIO_INCLUDE_STR
2826
+
2827
+ /* *****************************************************************************
2828
+ String API - Initialization and Destruction
2829
+ ***************************************************************************** */
2830
+
2831
+ /**
2832
+ * The `fio_str_s` type should be considered opaque.
2833
+ *
2834
+ * The type's attributes should be accessed ONLY through the accessor functions:
2835
+ * `fio_str_info`, `fio_str_len`, `fio_str_data`, `fio_str_capa`, etc'.
2836
+ *
2837
+ * Note: when the `small` flag is present, the structure is ignored and used as
2838
+ * raw memory for a small String (no additional allocation). This changes the
2839
+ * String's behavior drastically and requires that the accessor functions be
2840
+ * used.
2841
+ */
2842
+ typedef struct {
2843
+ volatile uint32_t ref; /* reference counter for fio_str_dup */
2844
+ uint8_t small; /* Flag indicating the String is small and self-contained */
2845
+ uint8_t frozen; /* Flag indicating the String is frozen (don't edit) */
2846
+ uint8_t reserved[10]; /* Align struct on 16 byte allocator boundary */
2847
+ uint64_t capa; /* Known capacity for longer Strings */
2848
+ uint64_t len; /* String length for longer Strings */
2849
+ void (*dealloc)(void *); /* Data deallocation function (NULL for static) */
2850
+ char *data; /* Data for longer Strings */
2851
+ #if UINTPTR_MAX != UINT64_MAX
2852
+ uint8_t padding[2 * (sizeof(uint64_t) -
2853
+ sizeof(void *))]; /* 16 byte boundary for 32bit OS */
2854
+ #endif
2855
+ } fio_str_s;
2856
+
2857
+ /**
2858
+ * This value should be used for initialization. For example:
2859
+ *
2860
+ * // on the stack
2861
+ * fio_str_s str = FIO_STR_INIT;
2862
+ *
2863
+ * // or on the heap
2864
+ * fio_str_s *str = malloc(sizeof(*str);
2865
+ * *str = FIO_STR_INIT;
2866
+ *
2867
+ * Remember to cleanup:
2868
+ *
2869
+ * // on the stack
2870
+ * fio_str_free(&str);
2871
+ *
2872
+ * // or on the heap
2873
+ * fio_str_free(str);
2874
+ * free(str);
2875
+ */
2876
+ #define FIO_STR_INIT ((fio_str_s){.data = NULL, .small = 1})
2877
+
2878
+ /**
2879
+ * This macro allows the container to be initialized with existing data, as long
2880
+ * as it's memory was allocated using `fio_malloc`.
2881
+ *
2882
+ * The `capacity` value should exclude the NUL character (if exists).
2883
+ */
2884
+ #define FIO_STR_INIT_EXISTING(buffer, length, capacity) \
2885
+ ((fio_str_s){.data = (buffer), \
2886
+ .len = (length), \
2887
+ .capa = (capacity), \
2888
+ .dealloc = fio_free})
2889
+
2890
+ /**
2891
+ * This macro allows the container to be initialized with existing data, as long
2892
+ * as it's memory was allocated using `fio_malloc`.
2893
+ *
2894
+ * The `capacity` value should exclude the NUL character (if exists).
2895
+ */
2896
+ #define FIO_STR_INIT_STATIC(buffer) \
2897
+ ((fio_str_s){.data = (buffer), .len = strlen((buffer)), .dealloc = NULL})
2898
+
2899
+ /**
2900
+ * Allocates a new fio_str_s object on the heap and initializes it.
2901
+ *
2902
+ * Use `fio_str_free2` to free both the String data and the container.
2903
+ *
2904
+ * NOTE: This makes the allocation and reference counting logic more intuitive.
2905
+ */
2906
+ inline FIO_FUNC fio_str_s *fio_str_new2(void);
2907
+
2908
+ /**
2909
+ * Allocates a new fio_str_s object on the heap, initializes it and copies the
2910
+ * original (`src`) string into the new string.
2911
+ *
2912
+ * Use `fio_str_free2` to free the new string's data and it's container.
2913
+ */
2914
+ inline FIO_FUNC fio_str_s *fio_str_new_copy2(fio_str_s *src);
2915
+
2916
+ /**
2917
+ * Adds a references to the current String object and returns itself.
2918
+ *
2919
+ * NOTE: Nothing is copied, reference Strings are referencing the same String.
2920
+ * Editing one reference will effect the other.
2921
+ *
2922
+ * The original's String's container should remain in scope (if on the
2923
+ * stack) or remain allocated (if on the heap) until all the references
2924
+ * were freed using `fio_str_free` / `fio_str_free2` or discarded.
2925
+ */
2926
+ inline FIO_FUNC fio_str_s *fio_str_dup(fio_str_s *s);
2927
+
2928
+ /**
2929
+ * Frees the String's resources and reinitializes the container.
2930
+ *
2931
+ * Note: if the container isn't allocated on the stack, it should be freed
2932
+ * separately using `free(s)`.
2933
+ *
2934
+ * Returns 0 if the data was freed and -1 if the String is NULL or has un-freed
2935
+ * references (see fio_str_dup).
2936
+ */
2937
+ inline FIO_FUNC int fio_str_free(fio_str_s *s);
2938
+
2939
+ /**
2940
+ * Frees the String's resources AS WELL AS the container.
2941
+ *
2942
+ * Note: the container is freed using `fio_free`, make sure `fio_malloc` was
2943
+ * used to allocate it.
2944
+ */
2945
+ FIO_FUNC void fio_str_free2(fio_str_s *s);
2946
+
2947
+ /**
2948
+ * `fio_str_send_free2` sends the fio_str_s using `fio_write2`, freeing both the
2949
+ * String and the container once the data was sent
2950
+ *
2951
+ * As the naming indicates, the String is assumed to have been allocated using
2952
+ * `fio_str_new2` or `fio_malloc`.
2953
+ */
2954
+ inline FIO_FUNC ssize_t fio_str_send_free2(const intptr_t uuid,
2955
+ const fio_str_s *str);
2956
+
2957
+ /* *****************************************************************************
2958
+ String API - String state (data pointers, length, capacity, etc')
2959
+ ***************************************************************************** */
2960
+
2961
+ /*
2962
+ * String state information, defined above as:
2963
+ typedef struct {
2964
+ size_t capa;
2965
+ size_t len;
2966
+ char *data;
2967
+ } fio_str_info_s;
2968
+ */
2969
+
2970
+ /** Returns the String's complete state (capacity, length and pointer). */
2971
+ inline FIO_FUNC fio_str_info_s fio_str_info(const fio_str_s *s);
2972
+
2973
+ /** Returns the String's length in bytes. */
2974
+ inline FIO_FUNC size_t fio_str_len(fio_str_s *s);
2975
+
2976
+ /** Returns a pointer (`char *`) to the String's content. */
2977
+ inline FIO_FUNC char *fio_str_data(fio_str_s *s);
2978
+
2979
+ /** Returns a byte pointer (`uint8_t *`) to the String's unsigned content. */
2980
+ #define fio_str_bytes(s) ((uint8_t *)fio_str_data((s)))
2981
+
2982
+ /** Returns the String's existing capacity (total used & available memory). */
2983
+ inline FIO_FUNC size_t fio_str_capa(fio_str_s *s);
2984
+
2985
+ /**
2986
+ * Sets the new String size without reallocating any memory (limited by
2987
+ * existing capacity).
2988
+ *
2989
+ * Returns the updated state of the String.
2990
+ *
2991
+ * Note: When shrinking, any existing data beyond the new size may be corrupted.
2992
+ */
2993
+ inline FIO_FUNC fio_str_info_s fio_str_resize(fio_str_s *s, size_t size);
2994
+
2995
+ /**
2996
+ * Clears the string (retaining the existing capacity).
2997
+ */
2998
+ #define fio_str_clear(s) fio_str_resize((s), 0)
2999
+
3000
+ /**
3001
+ * Returns the string's siphash value (Uses SipHash 1-3).
3002
+ */
3003
+ inline FIO_FUNC uint64_t fio_str_hash(const fio_str_s *s);
3004
+
3005
+ /* *****************************************************************************
3006
+ String API - Memory management
3007
+ ***************************************************************************** */
3008
+
3009
+ /**
3010
+ * Performs a best attempt at minimizing memory consumption.
3011
+ *
3012
+ * Actual effects depend on the underlying memory allocator and it's
3013
+ * implementation. Not all allocators will free any memory.
3014
+ */
3015
+ FIO_FUNC void fio_str_compact(fio_str_s *s);
3016
+
3017
+ /**
3018
+ * Requires the String to have at least `needed` capacity. Returns the current
3019
+ * state of the String.
3020
+ */
3021
+ FIO_FUNC fio_str_info_s fio_str_capa_assert(fio_str_s *s, size_t needed);
3022
+
3023
+ /* *****************************************************************************
3024
+ String API - UTF-8 State
3025
+ ***************************************************************************** */
3026
+
3027
+ /** Returns 1 if the String is UTF-8 valid and 0 if not. */
3028
+ FIO_FUNC size_t fio_str_utf8_valid(fio_str_s *s);
3029
+
3030
+ /** Returns the String's length in UTF-8 characters. */
3031
+ FIO_FUNC size_t fio_str_utf8_len(fio_str_s *s);
3032
+
3033
+ /**
3034
+ * Takes a UTF-8 character selection information (UTF-8 position and length) and
3035
+ * updates the same variables so they reference the raw byte slice information.
3036
+ *
3037
+ * If the String isn't UTF-8 valid up to the requested selection, than `pos`
3038
+ * will be updated to `-1` otherwise values are always positive.
3039
+ *
3040
+ * The returned `len` value may be shorter than the original if there wasn't
3041
+ * enough data left to accomodate the requested length. When a `len` value of
3042
+ * `0` is returned, this means that `pos` marks the end of the String.
3043
+ *
3044
+ * Returns -1 on error and 0 on success.
3045
+ */
3046
+ FIO_FUNC int fio_str_utf8_select(fio_str_s *s, intptr_t *pos, size_t *len);
3047
+
3048
+ /**
3049
+ * Advances the `ptr` by one utf-8 character, placing the value of the UTF-8
3050
+ * character into the i32 variable (which must be a signed integer with 32bits
3051
+ * or more). On error, `i32` will be equal to `-1` and `ptr` will not step
3052
+ * forwards.
3053
+ *
3054
+ * The `end` value is only used for overflow protection.
3055
+ *
3056
+ * This helper macro is used internally but left exposed for external use.
3057
+ */
3058
+ #define FIO_STR_UTF8_CODE_POINT(ptr, end, i32)
3059
+
3060
+ /* *****************************************************************************
3061
+ String API - Content Manipulation and Review
3062
+ ***************************************************************************** */
3063
+
3064
+ /**
3065
+ * Writes data at the end of the String (similar to `fio_str_insert` with the
3066
+ * argument `pos == -1`).
3067
+ */
3068
+ inline FIO_FUNC fio_str_info_s fio_str_write(fio_str_s *s, const void *src,
3069
+ size_t src_len);
3070
+
3071
+ /**
3072
+ * Writes a number at the end of the String using normal base 10 notation.
3073
+ */
3074
+ inline FIO_FUNC fio_str_info_s fio_str_write_i(fio_str_s *s, int64_t num);
3075
+
3076
+ /**
3077
+ * Appens the `src` String to the end of the `dest` String.
3078
+ *
3079
+ * If `dest` is empty, the resulting Strings will be equal.
3080
+ */
3081
+ inline FIO_FUNC fio_str_info_s fio_str_concat(fio_str_s *dest,
3082
+ fio_str_s const *src);
3083
+
3084
+ /** Alias for fio_str_concat */
3085
+ #define fio_str_join(dest, src) fio_str_concat((dest), (src))
3086
+
3087
+ /**
3088
+ * Replaces the data in the String - replacing `old_len` bytes starting at
3089
+ * `start_pos`, with the data at `src` (`src_len` bytes long).
3090
+ *
3091
+ * Negative `start_pos` values are calculated backwards, `-1` == end of String.
3092
+ *
3093
+ * When `old_len` is zero, the function will insert the data at `start_pos`.
3094
+ *
3095
+ * If `src_len == 0` than `src` will be ignored and the data marked for
3096
+ * replacement will be erased.
3097
+ */
3098
+ FIO_FUNC fio_str_info_s fio_str_replace(fio_str_s *s, intptr_t start_pos,
3099
+ size_t old_len, const void *src,
3100
+ size_t src_len);
3101
+
3102
+ /**
3103
+ * Writes to the String using a vprintf like interface.
3104
+ *
3105
+ * Data is written to the end of the String.
3106
+ */
3107
+ FIO_FUNC fio_str_info_s fio_str_vprintf(fio_str_s *s, const char *format,
3108
+ va_list argv);
3109
+
3110
+ /**
3111
+ * Writes to the String using a printf like interface.
3112
+ *
3113
+ * Data is written to the end of the String.
3114
+ */
3115
+ FIO_FUNC fio_str_info_s fio_str_printf(fio_str_s *s, const char *format, ...);
3116
+
3117
+ /**
3118
+ * Opens the file `filename` and pastes it's contents (or a slice ot it) at the
3119
+ * end of the String. If `limit == 0`, than the data will be read until EOF.
3120
+ *
3121
+ * If the file can't be located, opened or read, or if `start_at` is beyond
3122
+ * the EOF position, NULL is returned in the state's `data` field.
3123
+ *
3124
+ * Works on POSIX only.
3125
+ */
3126
+ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
3127
+ intptr_t start_at, intptr_t limit);
3128
+
3129
+ /**
3130
+ * Prevents further manipulations to the String's content.
3131
+ */
3132
+ inline FIO_FUNC void fio_str_freeze(fio_str_s *s);
3133
+
3134
+ /**
3135
+ * Binary comparison returns `1` if both strings are equal and `0` if not.
3136
+ */
3137
+ inline FIO_FUNC int fio_str_iseq(const fio_str_s *str1, const fio_str_s *str2);
3138
+
3139
+ /* *****************************************************************************
3140
+
3141
+
3142
+ String Implementation
3143
+
3144
+ IMPLEMENTATION
3145
+
3146
+
3147
+ ***************************************************************************** */
3148
+
3149
+ /* *****************************************************************************
3150
+ String Implementation - state (data pointers, length, capacity, etc')
3151
+ ***************************************************************************** */
3152
+
3153
+ typedef struct {
3154
+ volatile uint32_t ref; /* reference counter for fio_str_dup */
3155
+ uint8_t small; /* Flag indicating the String is small and self-contained */
3156
+ uint8_t frozen; /* Flag indicating the String is frozen (don't edit) */
3157
+ } fio_str__small_s;
3158
+
3159
+ #define FIO_STR_SMALL_DATA(s) ((char *)((&(s)->frozen) + 1))
3160
+
3161
+ /* the capacity when the string is stored in the container itself */
3162
+ #define FIO_STR_SMALL_CAPA \
3163
+ (sizeof(fio_str_s) - (size_t)((&((fio_str_s *)0)->frozen) + 1))
3164
+
3165
+ /** Returns the String's state (capacity, length and pointer). */
3166
+ inline FIO_FUNC fio_str_info_s fio_str_info(const fio_str_s *s) {
3167
+ if (!s)
3168
+ return (fio_str_info_s){.len = 0};
3169
+ return (s->small || !s->data)
3170
+ ? (fio_str_info_s){.capa =
3171
+ (s->frozen ? 0 : (FIO_STR_SMALL_CAPA - 1)),
3172
+ .len = (size_t)(s->small >> 1),
3173
+ .data = FIO_STR_SMALL_DATA(s)}
3174
+ : (fio_str_info_s){.capa = (s->frozen ? 0 : s->capa),
3175
+ .len = s->len,
3176
+ .data = s->data};
3177
+ }
3178
+
3179
+ /**
3180
+ * Allocates a new fio_str_s object on the heap and initializes it.
3181
+ *
3182
+ * Use `fio_str_free2` to free both the String data and the container.
3183
+ *
3184
+ * NOTE: This makes the allocation and reference counting logic more intuitive.
3185
+ */
3186
+ inline FIO_FUNC fio_str_s *fio_str_new2(void) {
3187
+ fio_str_s *str = fio_malloc(sizeof(*str));
3188
+ FIO_ASSERT_ALLOC(str);
3189
+ *str = FIO_STR_INIT;
3190
+ return str;
3191
+ }
3192
+
3193
+ /**
3194
+ * Allocates a new fio_str_s object on the heap, initializes it and copies the
3195
+ * original (`src`) string into the new string.
3196
+ *
3197
+ * Use `fio_str_free2` to free the new string's data and it's container.
3198
+ */
3199
+ inline FIO_FUNC fio_str_s *fio_str_new_copy2(fio_str_s *src) {
3200
+ fio_str_s *cpy = fio_str_new2();
3201
+ fio_str_concat(cpy, src);
3202
+ return cpy;
3203
+ }
3204
+
3205
+ /**
3206
+ * Adds a references to the current String object and returns itself.
3207
+ *
3208
+ * NOTE: Nothing is copied, reference Strings are referencing the same String.
3209
+ * Editing one reference will effect the other.
3210
+ *
3211
+ * The original's String's container should remain in scope (if on the
3212
+ * stack) or remain allocated (if on the heap) until all the references
3213
+ * were freed using `fio_str_free` / `fio_str_free2` or discarded.
3214
+ */
3215
+ inline FIO_FUNC fio_str_s *fio_str_dup(fio_str_s *s) {
3216
+ if (s)
3217
+ fio_atomic_add(&s->ref, 1);
3218
+ return s;
3219
+ }
3220
+
3221
+ /**
3222
+ * Frees the String's resources and reinitializes the container.
3223
+ *
3224
+ * Note: if the container isn't allocated on the stack, it should be freed
3225
+ * separately using `free(s)`.
3226
+ *
3227
+ * Returns 0 if the data was freed and -1 if the String is NULL or has un-freed
3228
+ * references (see fio_str_dup).
3229
+ */
3230
+ inline FIO_FUNC int fio_str_free(fio_str_s *s) {
3231
+ if (s && fio_atomic_sub(&s->ref, 1) == (uint32_t)-1) {
3232
+ if (!s->small && s->dealloc)
3233
+ s->dealloc(s->data);
3234
+ *s = FIO_STR_INIT;
3235
+ return 0;
3236
+ }
3237
+ return -1;
3238
+ }
3239
+
3240
+ /**
3241
+ * Frees the String's resources as well as the container.
3242
+ *
3243
+ * Note: the container is freed using `free`, make sure `malloc` was used to
3244
+ * allocate it.
3245
+ */
3246
+ FIO_FUNC void fio_str_free2(fio_str_s *s) {
3247
+ if (fio_str_free(s)) {
3248
+ return;
3249
+ }
3250
+ fio_free(s);
3251
+ }
3252
+
3253
+ /** Returns the String's length in bytes. */
3254
+ inline FIO_FUNC size_t fio_str_len(fio_str_s *s) {
3255
+ return (s->small || !s->data) ? (s->small >> 1) : s->len;
3256
+ }
3257
+
3258
+ /** Returns a pointer (`char *`) to the String's content. */
3259
+ inline FIO_FUNC char *fio_str_data(fio_str_s *s) {
3260
+ return (s->small || !s->data) ? FIO_STR_SMALL_DATA(s) : s->data;
3261
+ }
3262
+
3263
+ /** Returns the String's existing capacity (allocated memory). */
3264
+ inline FIO_FUNC size_t fio_str_capa(fio_str_s *s) {
3265
+ if (s->frozen)
3266
+ return 0;
3267
+ return (s->small || !s->data) ? (FIO_STR_SMALL_CAPA - 1) : s->capa;
3268
+ }
3269
+
3270
+ /**
3271
+ * Sets the new String size without reallocating any memory (limited by
3272
+ * existing capacity).
3273
+ *
3274
+ * Returns the updated state of the String.
3275
+ *
3276
+ * Note: When shrinking, any existing data beyond the new size may be corrupted.
3277
+ */
3278
+ inline FIO_FUNC fio_str_info_s fio_str_resize(fio_str_s *s, size_t size) {
3279
+ if (!s || s->frozen) {
3280
+ return fio_str_info(s);
3281
+ }
3282
+ fio_str_capa_assert(s, size);
3283
+ if (s->small || !s->data) {
3284
+ s->small = (uint8_t)(((size << 1) | 1) & 0xFF);
3285
+ FIO_STR_SMALL_DATA(s)[size] = 0;
3286
+ return (fio_str_info_s){.capa = (FIO_STR_SMALL_CAPA - 1),
3287
+ .len = size,
3288
+ .data = FIO_STR_SMALL_DATA(s)};
3289
+ }
3290
+ s->len = size;
3291
+ s->data[size] = 0;
3292
+ return (fio_str_info_s){.capa = s->capa, .len = size, .data = s->data};
3293
+ }
3294
+
3295
+ /**
3296
+ * Returns the string's siphash value (Uses SipHash 1-3).
3297
+ */
3298
+ /** Returns the String's complete state (capacity, length and pointer). */
3299
+ inline FIO_FUNC uint64_t fio_str_hash(const fio_str_s *s) {
3300
+ fio_str_info_s state = fio_str_info(s);
3301
+ return fio_siphash(state.data, state.len);
3302
+ }
3303
+
3304
+ /* *****************************************************************************
3305
+ String Implementation - Memory management
3306
+ ***************************************************************************** */
3307
+
3308
+ /**
3309
+ * Rounds up allocated capacity to the closest 2 words byte boundary (leaving 1
3310
+ * byte space for the NUL byte).
3311
+ *
3312
+ * This shouldn't effect actual allocation size and should only minimize the
3313
+ * effects of the memory allocator's alignment rounding scheme.
3314
+ *
3315
+ * To clarify:
3316
+ *
3317
+ * Memory allocators are required to allocate memory on the minimal alignment
3318
+ * required by the largest type (`long double`), which usually results in memory
3319
+ * allocations using this alignment as a minimal spacing.
3320
+ *
3321
+ * For example, on 64 bit architectures, it's likely that `malloc(18)` will
3322
+ * allocate the same amount of memory as `malloc(32)` due to alignment concerns.
3323
+ *
3324
+ * In fact, with some allocators (i.e., jemalloc), spacing increases for larger
3325
+ * allocations - meaning the allocator will round up to more than 16 bytes, as
3326
+ * noted here: http://jemalloc.net/jemalloc.3.html#size_classes
3327
+ *
3328
+ * Note that this increased spacing, doesn't occure with facil.io's allocator,
3329
+ * since it uses 16 byte alignment right up until allocations are routed
3330
+ * directly to `mmap` (due to their size, usually over 12KB).
3331
+ */
3332
+ #define ROUND_UP_CAPA_2WORDS(num) \
3333
+ (((num + 1) & (sizeof(long double) - 1)) \
3334
+ ? ((num + 1) | (sizeof(long double) - 1)) \
3335
+ : (num))
3336
+ /**
3337
+ * Requires the String to have at least `needed` capacity. Returns the current
3338
+ * state of the String.
3339
+ */
3340
+ FIO_FUNC fio_str_info_s fio_str_capa_assert(fio_str_s *s, size_t needed) {
3341
+ if (!s)
3342
+ return (fio_str_info_s){.capa = 0};
3343
+ char *tmp;
3344
+ if (s->small || !s->data) {
3345
+ goto is_small;
3346
+ }
3347
+ if (needed > s->capa) {
3348
+ needed = ROUND_UP_CAPA_2WORDS(needed);
3349
+ if (s->dealloc == fio_free) {
3350
+ tmp = (char *)fio_realloc2(s->data, needed + 1, s->len);
3351
+ FIO_ASSERT_ALLOC(tmp);
3352
+ } else {
3353
+ tmp = (char *)fio_malloc(needed + 1);
3354
+ FIO_ASSERT_ALLOC(tmp);
3355
+ memcpy(tmp, s->data, s->len);
3356
+ if (s->dealloc)
3357
+ s->dealloc(s->data);
3358
+ }
3359
+ s->capa = needed;
3360
+ s->data = tmp;
3361
+ s->data[needed] = 0;
3362
+ }
3363
+ return (fio_str_info_s){
3364
+ .capa = (s->frozen ? 0 : s->capa), .len = s->len, .data = s->data};
3365
+
3366
+ is_small:
3367
+ /* small string (string data is within the container) */
3368
+ if (needed < FIO_STR_SMALL_CAPA) {
3369
+ return (fio_str_info_s){.capa = (s->frozen ? 0 : (FIO_STR_SMALL_CAPA - 1)),
3370
+ .len = (size_t)(s->small >> 1),
3371
+ .data = FIO_STR_SMALL_DATA(s)};
3372
+ }
3373
+ needed = ROUND_UP_CAPA_2WORDS(needed);
3374
+ tmp = (char *)fio_malloc(needed + 1);
3375
+ FIO_ASSERT_ALLOC(tmp);
3376
+ const size_t existing_len = (size_t)((s->small >> 1) & 0xFF);
3377
+ if (existing_len) {
3378
+ memcpy(tmp, FIO_STR_SMALL_DATA(s), existing_len + 1);
3379
+ } else {
3380
+ tmp[0] = 0;
3381
+ }
3382
+ *s = (fio_str_s){
3383
+ .ref = s->ref,
3384
+ .small = 0,
3385
+ .capa = needed,
3386
+ .len = existing_len,
3387
+ .dealloc = fio_free,
3388
+ .data = tmp,
3389
+ };
3390
+ return (fio_str_info_s){
3391
+ .capa = (s->frozen ? 0 : needed), .len = existing_len, .data = s->data};
3392
+ }
3393
+
3394
+ /** Performs a best attempt at minimizing memory consumption. */
3395
+ FIO_FUNC void fio_str_compact(fio_str_s *s) {
3396
+ if (!s || (s->small || !s->data))
3397
+ return;
3398
+ char *tmp;
3399
+ if (s->len < FIO_STR_SMALL_CAPA)
3400
+ goto shrink2small;
3401
+ tmp = fio_realloc(s->data, s->len + 1);
3402
+ FIO_ASSERT_ALLOC(tmp);
3403
+ s->data = tmp;
3404
+ s->capa = s->len;
3405
+ return;
3406
+
3407
+ shrink2small:
3408
+ /* move the string into the container */
3409
+ tmp = s->data;
3410
+ size_t len = s->len;
3411
+ *s = (fio_str_s){.small = (uint8_t)(((len << 1) | 1) & 0xFF),
3412
+ .frozen = s->frozen};
3413
+ if (len) {
3414
+ memcpy(FIO_STR_SMALL_DATA(s), tmp, len + 1);
3415
+ }
3416
+ fio_free(tmp);
3417
+ }
3418
+
3419
+ /* *****************************************************************************
3420
+ String Implementation - UTF-8 State
3421
+ ***************************************************************************** */
3422
+
3423
+ /**
3424
+ * Maps the last 5 bits in a byte (0b11111xxx) to a UTF-8 codepoint length.
3425
+ *
3426
+ * Codepoint length 0 == error.
3427
+ *
3428
+ * The first valid length can be any value between 1 to 4.
3429
+ *
3430
+ * An intermidiate (second, third or forth) valid length must be 5.
3431
+ *
3432
+ * To map was populated using the following Ruby script:
3433
+ *
3434
+ * map = []; 32.times { map << 0 }; (0..0b1111).each {|i| map[i] = 1} ;
3435
+ * (0b10000..0b10111).each {|i| map[i] = 5} ;
3436
+ * (0b11000..0b11011).each {|i| map[i] = 2} ;
3437
+ * (0b11100..0b11101).each {|i| map[i] = 3} ;
3438
+ * map[0b11110] = 4; map;
3439
+ */
3440
+ static uint8_t fio_str_utf8_map[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3441
+ 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5,
3442
+ 5, 5, 2, 2, 2, 2, 3, 3, 4, 0};
3443
+
3444
+ #undef FIO_STR_UTF8_CODE_POINT
3445
+ /**
3446
+ * Advances the `ptr` by one utf-8 character, placing the value of the UTF-8
3447
+ * character into the i32 variable (which must be a signed integer with 32bits
3448
+ * or more). On error, `i32` will be equal to `-1` and `ptr` will not step
3449
+ * forwards.
3450
+ *
3451
+ * The `end` value is only used for overflow protection.
3452
+ */
3453
+ #define FIO_STR_UTF8_CODE_POINT(ptr, end, i32) \
3454
+ do { \
3455
+ switch (fio_str_utf8_map[((uint8_t *)(ptr))[0] >> 3]) { \
3456
+ case 1: \
3457
+ (i32) = ((uint8_t *)(ptr))[0]; \
3458
+ ++(ptr); \
3459
+ break; \
3460
+ case 2: \
3461
+ if (((ptr) + 2 > (end)) || \
3462
+ fio_str_utf8_map[((uint8_t *)(ptr))[1] >> 3] != 5) { \
3463
+ (i32) = -1; \
3464
+ break; \
3465
+ } \
3466
+ (i32) = \
3467
+ ((((uint8_t *)(ptr))[0] & 31) << 6) | (((uint8_t *)(ptr))[1] & 63); \
3468
+ (ptr) += 2; \
3469
+ break; \
3470
+ case 3: \
3471
+ if (((ptr) + 3 > (end)) || \
3472
+ fio_str_utf8_map[((uint8_t *)(ptr))[1] >> 3] != 5 || \
3473
+ fio_str_utf8_map[((uint8_t *)(ptr))[2] >> 3] != 5) { \
3474
+ (i32) = -1; \
3475
+ break; \
3476
+ } \
3477
+ (i32) = ((((uint8_t *)(ptr))[0] & 15) << 12) | \
3478
+ ((((uint8_t *)(ptr))[1] & 63) << 6) | \
3479
+ (((uint8_t *)(ptr))[2] & 63); \
3480
+ (ptr) += 3; \
3481
+ break; \
3482
+ case 4: \
3483
+ if (((ptr) + 4 > (end)) || \
3484
+ fio_str_utf8_map[((uint8_t *)(ptr))[1] >> 3] != 5 || \
3485
+ fio_str_utf8_map[((uint8_t *)(ptr))[2] >> 3] != 5 || \
3486
+ fio_str_utf8_map[((uint8_t *)(ptr))[3] >> 3] != 5) { \
3487
+ (i32) = -1; \
3488
+ break; \
3489
+ } \
3490
+ (i32) = ((((uint8_t *)(ptr))[0] & 7) << 18) | \
3491
+ ((((uint8_t *)(ptr))[1] & 63) << 12) | \
3492
+ ((((uint8_t *)(ptr))[2] & 63) << 6) | \
3493
+ (((uint8_t *)(ptr))[3] & 63); \
3494
+ (ptr) += 4; \
3495
+ break; \
3496
+ default: \
3497
+ (i32) = -1; \
3498
+ break; \
3499
+ } \
3500
+ } while (0);
3501
+
3502
+ /** Returns 1 if the String is UTF-8 valid and 0 if not. */
3503
+ FIO_FUNC size_t fio_str_utf8_valid(fio_str_s *s) {
3504
+ if (!s)
3505
+ return 0;
3506
+ fio_str_info_s state = fio_str_info(s);
3507
+ if (!state.len)
3508
+ return 1;
3509
+ char *const end = state.data + state.len;
3510
+ int32_t c = 0;
3511
+ do {
3512
+ FIO_STR_UTF8_CODE_POINT(state.data, end, c);
3513
+ } while (c > 0 && state.data < end);
3514
+ return state.data == end && c >= 0;
3515
+ }
3516
+
3517
+ /** Returns the String's length in UTF-8 characters. */
3518
+ FIO_FUNC size_t fio_str_utf8_len(fio_str_s *s) {
3519
+ fio_str_info_s state = fio_str_info(s);
3520
+ if (!state.len)
3521
+ return 0;
3522
+ char *end = state.data + state.len;
3523
+ size_t utf8len = 0;
3524
+ int32_t c = 0;
3525
+ do {
3526
+ ++utf8len;
3527
+ FIO_STR_UTF8_CODE_POINT(state.data, end, c);
3528
+ } while (c > 0 && state.data < end);
3529
+ if (state.data != end || c == -1) {
3530
+ /* invalid */
3531
+ return 0;
3532
+ }
3533
+ return utf8len;
3534
+ }
3535
+
3536
+ /**
3537
+ * Takes a UTF-8 character selection information (UTF-8 position and length) and
3538
+ * updates the same variables so they reference the raw byte slice information.
3539
+ *
3540
+ * If the String isn't UTF-8 valid up to the requested selection, than `pos`
3541
+ * will be updated to `-1` otherwise values are always positive.
3542
+ *
3543
+ * The returned `len` value may be shorter than the original if there wasn't
3544
+ * enough data left to accomodate the requested length. When a `len` value of
3545
+ * `0` is returned, this means that `pos` marks the end of the String.
3546
+ *
3547
+ * Returns -1 on error and 0 on success.
3548
+ */
3549
+ FIO_FUNC int fio_str_utf8_select(fio_str_s *s, intptr_t *pos, size_t *len) {
3550
+ fio_str_info_s state = fio_str_info(s);
3551
+ if (!state.data)
3552
+ goto error;
3553
+ if (!state.len || *pos == -1)
3554
+ goto at_end;
3555
+
3556
+ int32_t c = 0;
3557
+ char *p = state.data;
3558
+ char *const end = state.data + state.len;
3559
+ size_t start;
3560
+
3561
+ if (*pos) {
3562
+ if ((*pos) > 0) {
3563
+ start = *pos;
3564
+ while (start && p < end && c >= 0) {
3565
+ FIO_STR_UTF8_CODE_POINT(p, end, c);
3566
+ --start;
3567
+ }
3568
+ if (c == -1)
3569
+ goto error;
3570
+ if (start || p >= end)
3571
+ goto at_end;
3572
+ *pos = p - state.data;
3573
+ } else {
3574
+ /* walk backwards */
3575
+ p = state.data + state.len - 1;
3576
+ c = 0;
3577
+ ++*pos;
3578
+ do {
3579
+ switch (fio_str_utf8_map[((uint8_t *)p)[0] >> 3]) {
3580
+ case 5:
3581
+ ++c;
3582
+ break;
3583
+ case 4:
3584
+ if (c != 3)
3585
+ goto error;
3586
+ c = 0;
3587
+ ++(*pos);
3588
+ break;
3589
+ case 3:
3590
+ if (c != 2)
3591
+ goto error;
3592
+ c = 0;
3593
+ ++(*pos);
3594
+ break;
3595
+ case 2:
3596
+ if (c != 1)
3597
+ goto error;
3598
+ c = 0;
3599
+ ++(*pos);
3600
+ break;
3601
+ case 1:
3602
+ if (c)
3603
+ goto error;
3604
+ ++(*pos);
3605
+ break;
3606
+ default:
3607
+ goto error;
3608
+ }
3609
+ --p;
3610
+ } while (p > state.data && *pos);
3611
+ if (c)
3612
+ goto error;
3613
+ ++p; /* There's always an extra back-step */
3614
+ *pos = (p - state.data);
3615
+ }
3616
+ }
3617
+
3618
+ /* find end */
3619
+ start = *len;
3620
+ while (start && p < end && c >= 0) {
3621
+ FIO_STR_UTF8_CODE_POINT(p, end, c);
3622
+ --start;
3623
+ }
3624
+ if (c == -1 || p > end)
3625
+ goto error;
3626
+ *len = p - (state.data + (*pos));
3627
+ return 0;
3628
+
3629
+ at_end:
3630
+ *pos = state.len;
3631
+ *len = 0;
3632
+ return 0;
3633
+ error:
3634
+ *pos = -1;
3635
+ *len = 0;
3636
+ return -1;
3637
+ }
3638
+
3639
+ /* *****************************************************************************
3640
+ String Implementation - Content Manipulation and Review
3641
+ ***************************************************************************** */
3642
+
3643
+ /**
3644
+ * Writes data at the end of the String (similar to `fio_str_insert` with the
3645
+ * argument `pos == -1`).
3646
+ */
3647
+ inline FIO_FUNC fio_str_info_s fio_str_write(fio_str_s *s, const void *src,
3648
+ size_t src_len) {
3649
+ if (!s || !src_len || !src || s->frozen)
3650
+ return fio_str_info(s);
3651
+ fio_str_info_s state = fio_str_resize(s, src_len + fio_str_len(s));
3652
+ memcpy(state.data + (state.len - src_len), src, src_len);
3653
+ return state;
3654
+ }
3655
+
3656
+ /**
3657
+ * Writes a number at the end of the String using normal base 10 notation.
3658
+ */
3659
+ inline FIO_FUNC fio_str_info_s fio_str_write_i(fio_str_s *s, int64_t num) {
3660
+ if (!s || s->frozen)
3661
+ return fio_str_info(s);
3662
+ fio_str_info_s i;
3663
+ if (!num)
3664
+ goto zero;
3665
+ char buf[22];
3666
+ uint64_t l = 0;
3667
+ uint8_t neg;
3668
+ if ((neg = (num < 0))) {
3669
+ num = 0 - num;
3670
+ neg = 1;
3671
+ }
3672
+ while (num) {
3673
+ uint64_t t = num / 10;
3674
+ buf[l++] = '0' + (num - (t * 10));
3675
+ num = t;
3676
+ }
3677
+ if (neg) {
3678
+ buf[l++] = '-';
3679
+ }
3680
+ i = fio_str_resize(s, fio_str_len(s) + l);
3681
+
3682
+ while (l) {
3683
+ --l;
3684
+ i.data[i.len - (l + 1)] = buf[l];
3685
+ }
3686
+ return i;
3687
+ zero:
3688
+ i = fio_str_resize(s, fio_str_len(s) + 1);
3689
+ i.data[i.len - 1] = '0';
3690
+ return i;
3691
+ }
3692
+
3693
+ /**
3694
+ * Appens the `src` String to the end of the `dest` String.
3695
+ */
3696
+ inline FIO_FUNC fio_str_info_s fio_str_concat(fio_str_s *dest,
3697
+ fio_str_s const *src) {
3698
+ if (!dest || !src || dest->frozen)
3699
+ return fio_str_info(dest);
3700
+ fio_str_info_s src_state = fio_str_info(src);
3701
+ if (!src_state.len)
3702
+ return fio_str_info(dest);
3703
+ fio_str_info_s state =
3704
+ fio_str_resize(dest, src_state.len + fio_str_len(dest));
3705
+ memcpy(state.data + state.len - src_state.len, src_state.data, src_state.len);
3706
+ return state;
3707
+ }
3708
+
3709
+ /**
3710
+ * Replaces the data in the String - replacing `old_len` bytes starting at
3711
+ * `start_pos`, with the data at `src` (`src_len` bytes long).
3712
+ *
3713
+ * Negative `start_pos` values are calculated backwards, `-1` == end of String.
3714
+ *
3715
+ * When `old_len` is zero, the function will insert the data at `start_pos`.
3716
+ *
3717
+ * If `src_len == 0` than `src` will be ignored and the data marked for
3718
+ * replacement will be erased.
3719
+ */
3720
+ FIO_FUNC fio_str_info_s fio_str_replace(fio_str_s *s, intptr_t start_pos,
3721
+ size_t old_len, const void *src,
3722
+ size_t src_len) {
3723
+ fio_str_info_s state = fio_str_info(s);
3724
+ if (!s || s->frozen || (!old_len && !src_len))
3725
+ return state;
3726
+
3727
+ if (start_pos < 0) {
3728
+ /* backwards position indexing */
3729
+ start_pos += s->len + 1;
3730
+ if (start_pos < 0)
3731
+ start_pos = 0;
3732
+ }
3733
+
3734
+ if (start_pos + old_len >= state.len) {
3735
+ /* old_len overflows the end of the String */
3736
+ if (s->small || !s->data) {
3737
+ s->small = 1 | ((size_t)((start_pos << 1) & 0xFF));
3738
+ } else {
3739
+ s->len = start_pos;
3740
+ }
3741
+ return fio_str_write(s, src, src_len);
3742
+ }
3743
+
3744
+ /* data replacement is now always in the middle (or start) of the String */
3745
+ const size_t new_size = state.len + (src_len - old_len);
3746
+
3747
+ if (old_len != src_len) {
3748
+ /* there's an offset requiring an adjustment */
3749
+ if (old_len < src_len) {
3750
+ /* make room for new data */
3751
+ const size_t offset = src_len - old_len;
3752
+ state = fio_str_resize(s, state.len + offset);
3753
+ }
3754
+ memmove(state.data + start_pos + src_len, state.data + start_pos + old_len,
3755
+ (state.len - start_pos) - old_len);
3756
+ }
3757
+ if (src_len) {
3758
+ memcpy(state.data + start_pos, src, src_len);
3759
+ }
3760
+
3761
+ return fio_str_resize(s, new_size);
3762
+ }
3763
+
3764
+ /** Writes to the String using a vprintf like interface. */
3765
+ FIO_FUNC __attribute__((format(printf, 2, 0))) fio_str_info_s
3766
+ fio_str_vprintf(fio_str_s *s, const char *format, va_list argv) {
3767
+ va_list argv_cpy;
3768
+ va_copy(argv_cpy, argv);
3769
+ int len = vsnprintf(NULL, 0, format, argv_cpy);
3770
+ va_end(argv_cpy);
3771
+ if (len <= 0)
3772
+ return fio_str_info(s);
3773
+ fio_str_info_s state = fio_str_resize(s, len + fio_str_len(s));
3774
+ vsnprintf(state.data + (state.len - len), len + 1, format, argv);
3775
+ return state;
3776
+ }
3777
+
3778
+ /** Writes to the String using a printf like interface. */
3779
+ FIO_FUNC __attribute__((format(printf, 2, 3))) fio_str_info_s
3780
+ fio_str_printf(fio_str_s *s, const char *format, ...) {
3781
+ va_list argv;
3782
+ va_start(argv, format);
3783
+ fio_str_info_s state = fio_str_vprintf(s, format, argv);
3784
+ va_end(argv);
3785
+ return state;
3786
+ }
3787
+
3788
+ /**
3789
+ * Opens the file `filename` and pastes it's contents (or a slice ot it) at the
3790
+ * end of the String. If `limit == 0`, than the data will be read until EOF.
3791
+ *
3792
+ * If the file can't be located, opened or read, or if `start_at` is beyond
3793
+ * the EOF position, NULL is returned in the state's `data` field.
3794
+ */
3795
+ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
3796
+ intptr_t start_at, intptr_t limit) {
3797
+ fio_str_info_s state = {.data = NULL};
3798
+ #if defined(__unix__) || defined(__linux__) || defined(__APPLE__) || \
3799
+ defined(__CYGWIN__)
3800
+ /* POSIX implementations. */
3801
+ if (filename == NULL)
3802
+ return state;
3803
+ struct stat f_data;
3804
+ int file = -1;
3805
+ char *path = NULL;
3806
+ size_t path_len = 0;
3807
+
3808
+ if (filename[0] == '~' && (filename[1] == '/' || filename[1] == '\\')) {
3809
+ char *home = getenv("HOME");
3810
+ if (home) {
3811
+ size_t filename_len = strlen(filename);
3812
+ size_t home_len = strlen(home);
3813
+ if ((home_len + filename_len) >= (1 << 16)) {
3814
+ /* too long */
3815
+ return state;
3816
+ }
3817
+ if (home[home_len - 1] == '/' || home[home_len - 1] == '\\')
3818
+ --home_len;
3819
+ path_len = home_len + filename_len - 1;
3820
+ path = fio_malloc(path_len + 1);
3821
+ FIO_ASSERT_ALLOC(path);
3822
+ memcpy(path, home, home_len);
3823
+ memcpy(path + home_len, filename + 1, filename_len);
3824
+ path[path_len] = 0;
3825
+ filename = path;
3826
+ }
3827
+ }
3828
+
3829
+ if (stat(filename, &f_data)) {
3830
+ goto finish;
3831
+ }
3832
+
3833
+ if (f_data.st_size <= 0 || start_at >= f_data.st_size) {
3834
+ state = fio_str_info(s);
3835
+ goto finish;
3836
+ }
3837
+
3838
+ file = open(filename, O_RDONLY);
3839
+ if (-1 == file)
3840
+ goto finish;
3841
+
3842
+ if (start_at < 0) {
3843
+ start_at = f_data.st_size + start_at;
3844
+ if (start_at < 0)
3845
+ start_at = 0;
3846
+ }
3847
+
3848
+ if (limit <= 0 || f_data.st_size < (limit + start_at))
3849
+ limit = f_data.st_size - start_at;
3850
+
3851
+ const size_t org_len = fio_str_len(s);
3852
+ state = fio_str_resize(s, org_len + limit);
3853
+ if (pread(file, state.data + org_len, limit, start_at) != (ssize_t)limit) {
3854
+ close(file);
3855
+ fio_str_resize(s, org_len);
3856
+ state.data = NULL;
3857
+ state.len = state.capa = 0;
3858
+ goto finish;
3859
+ }
3860
+ close(file);
3861
+ finish:
3862
+ fio_free(path);
3863
+ return state;
3864
+ #else
3865
+ /* TODO: consider adding non POSIX implementations. */
3866
+ fprintf(stderr, "ERROR: File reading requires a posix system (ignored!).\n");
3867
+ return state;
3868
+ #endif
3869
+ }
3870
+
3871
+ /**
3872
+ * Prevents further manipulations to the String's content.
3873
+ */
3874
+ inline FIO_FUNC void fio_str_freeze(fio_str_s *s) {
3875
+ if (!s)
3876
+ return;
3877
+ s->frozen = 1;
3878
+ }
3879
+
3880
+ /**
3881
+ * Binary comparison returns `1` if both strings are equal and `0` if not.
3882
+ */
3883
+ inline FIO_FUNC int fio_str_iseq(const fio_str_s *str1, const fio_str_s *str2) {
3884
+ if (str1 == str2)
3885
+ return 1;
3886
+ if (!str1 || !str2)
3887
+ return 0;
3888
+ fio_str_info_s s1 = fio_str_info(str1);
3889
+ fio_str_info_s s2 = fio_str_info(str2);
3890
+ return (s1.len == s2.len && !memcmp(s1.data, s2.data, s1.len));
3891
+ }
3892
+
3893
+ /**
3894
+ * `fio_str_send_free2` sends the fio_str_s using `fio_write2`, freeing the
3895
+ * String once the data was sent
3896
+ *
3897
+ * As the naming indicates, the String is assumed to have been allocated using
3898
+ * `fio_str_new2` or `fio_malloc`.
3899
+ */
3900
+ inline FIO_FUNC ssize_t fio_str_send_free2(const intptr_t uuid,
3901
+ const fio_str_s *str) {
3902
+ if (!str)
3903
+ return 0;
3904
+ fio_str_info_s state = fio_str_info(str);
3905
+ return fio_write2(uuid, .data.buffer = str, .length = state.len,
3906
+ .offset = ((uintptr_t)state.data - (uintptr_t)str),
3907
+ .after.dealloc = (void (*)(void *))fio_str_free2);
3908
+ }
3909
+
3910
+ #undef ROUND_UP_CAPA_2WORDS
3911
+ #undef FIO_STR_SMALL_DATA
3912
+
3913
+ #endif /* H_FIO_STR_H */
3914
+ /* *****************************************************************************
3915
+
3916
+
3917
+
3918
+
3919
+
3920
+
3921
+
3922
+
3923
+
3924
+
3925
+
3926
+ Set / Hash Map Data-Store
3927
+
3928
+
3929
+
3930
+
3931
+
3932
+
3933
+
3934
+
3935
+
3936
+
3937
+
3938
+ ***************************************************************************** */
3939
+
3940
+ #ifdef FIO_SET_NAME
3941
+
3942
+ /**
3943
+ * A simple ordered Set / Hash Map implementation, with a minimal API.
3944
+ *
3945
+ * A Set is basically a Hash Map where the keys are also the values, it's often
3946
+ * used for caching objects.
3947
+ *
3948
+ * The Set's object type and behavior is controlled by the FIO_SET_OBJ_* marcos.
3949
+ *
3950
+ * A Hash Map is basically a set where the objects in the Set are key-value
3951
+ * couplets and only the keys are tested when searching the Set.
3952
+ *
3953
+ * To create a Set or a Hash Map, the macro FIO_SET_NAME must be defined. i.e.:
3954
+ *
3955
+ * #define FIO_SET_NAME fio_cstr_set
3956
+ * #define FIO_SET_OBJ_TYPE char *
3957
+ * #define FIO_SET_OBJ_COMPARE(k1, k2) (!strcmp((k1), (k2)))
3958
+ * #include <fio.h>
3959
+ *
3960
+ * To create a Hash Map, rather than a pure Set, the macro FIO_SET_KET_TYPE must
3961
+ * be defined. i.e.:
3962
+ *
3963
+ * #define FIO_SET_KEY_TYPE char *
3964
+ *
3965
+ * This allows the FIO_SET_KEY_* macros to be defined as well. For example:
3966
+ *
3967
+ * #define FIO_SET_KEY_TYPE char *
3968
+ * #define FIO_SET_KEY_COMPARE(k1, k2) (!strcmp((k1), (k2)))
3969
+ * #define FIO_SET_OBJ_TYPE char *
3970
+ * #include <fio.h>
3971
+ *
3972
+ * It's possible to create a number of Set or HasMap types by reincluding the
3973
+ * fio.h header. i.e.:
3974
+ *
3975
+ *
3976
+ * #define FIO_INCLUDE_STR
3977
+ * #include <fio.h> // adds the fio_str_s types and functions
3978
+ *
3979
+ * #define FIO_SET_NAME fio_str_set
3980
+ * #define FIO_SET_KEY_TYPE fio_str_s *
3981
+ * #include <fio.h> // creates the fio_str_set_s Set and functions
3982
+ *
3983
+ * #define FIO_SET_NAME fio_str_hash
3984
+ * #define FIO_SET_KEY_TYPE fio_str_s *
3985
+ * #define FIO_SET_KEY_COMPARE(k1, k2) (fio_str_iseq((k1), (k2)))
3986
+ * #define FIO_SET_KEY_COPY(key) fio_str_dup((key))
3987
+ * #define FIO_SET_KEY_DESTROY(key) fio_str_free2((key))
3988
+ * #define FIO_SET_OBJ_TYPE fio_str_s *
3989
+ * #define FIO_SET_OBJ_COMPARE(k1, k2) (fio_str_iseq((k1), (k2)))
3990
+ * #define FIO_SET_OBJ_COPY(key) fio_str_dup((key))
3991
+ * #define FIO_SET_OBJ_DESTROY(key) fio_str_free2((key))
3992
+ * #include <fio.h> // creates the fio_str_hash_s Hash Map and functions
3993
+ *
3994
+ * The default integer Hash used is a pointer length type (uintptr_t). This can
3995
+ * be changed by defining ALL of the following macros:
3996
+ * * FIO_SET_HASH_TYPE - the type of the hash value.
3997
+ * * FIO_SET_HASH2UINTPTR(hash) - converts the hash value to a uintptr_t.
3998
+ * * FIO_SET_HASH_COMPARE(h1, h2) - compares two hash values (1 == equal).
3999
+ * * FIO_SET_HASH_INVALID - an invalid Hash value, all bytes are 0.
4000
+ *
4001
+ *
4002
+ * Note: FIO_SET_HASH_TYPE should, normaly be left alone (uintptr_t is
4003
+ * enough). Also, the hash value 0 is reserved to indicate an empty slot.
4004
+ *
4005
+ * Note: the FIO_SET_OBJ_COMPARE for Sets or the FIO_SET_KEY_COMPARE will be
4006
+ * used to compare against invalid as well as valid objects. Invalid
4007
+ * objects have their bytes all zero. FIO_SET_*_DESTROY should somehow
4008
+ * mark them as invalid.
4009
+ *
4010
+ * Note: Before freeing the Set, FIO_SET_OBJ_DESTROY will be automatically
4011
+ * called for every existing object.
4012
+ */
4013
+
4014
+ /* Used for naming functions and types, prefixing FIO_SET_NAME to the name */
4015
+ #define FIO_NAME_FROM_MACRO_STEP2(name, postfix) name##_##postfix
4016
+ #define FIO_NAME_FROM_MACRO_STEP1(name, postfix) \
4017
+ FIO_NAME_FROM_MACRO_STEP2(name, postfix)
4018
+
4019
+ #define FIO_NAME(postfix) FIO_NAME_FROM_MACRO_STEP1(FIO_SET_NAME, postfix)
4020
+
4021
+ /* The default Set object / value type is `void *` */
4022
+ #if !defined(FIO_SET_OBJ_TYPE)
4023
+ #define FIO_SET_OBJ_TYPE void *
4024
+ #elif !defined(FIO_SET_NO_TEST)
4025
+ #define FIO_SET_NO_TEST 1
4026
+ #endif
4027
+
4028
+ /* The default Set has opaque objects that can't be compared */
4029
+ #if !defined(FIO_SET_OBJ_COMPARE)
4030
+ #define FIO_SET_OBJ_COMPARE(o1, o2) (1)
4031
+ #endif
4032
+
4033
+ /** object copy required? */
4034
+ #ifndef FIO_SET_OBJ_COPY
4035
+ #define FIO_SET_OBJ_COPY(dest, obj) ((dest) = (obj))
4036
+ #endif
4037
+
4038
+ /** object destruction required? */
4039
+ #ifndef FIO_SET_OBJ_DESTROY
4040
+ #define FIO_SET_OBJ_DESTROY(obj) ((void)0)
4041
+ #endif
4042
+
4043
+ /** test for a pre-defined hash value type */
4044
+ #ifndef FIO_SET_HASH_TYPE
4045
+ #define FIO_SET_HASH_TYPE uintptr_t
4046
+ #endif
4047
+
4048
+ /** test for a pre-defined hash to integer conversion */
4049
+ #ifndef FIO_SET_HASH2UINTPTR
4050
+ #define FIO_SET_HASH2UINTPTR(hash) ((uintptr_t)(hash))
4051
+ #endif
4052
+
4053
+ /** test for a pre-defined invalid hash value (all bytes are 0) */
4054
+ #ifndef FIO_SET_HASH_INVALID
4055
+ #define FIO_SET_HASH_INVALID ((FIO_SET_HASH_TYPE)0)
4056
+ #endif
4057
+
4058
+ /** test for a pre-defined hash comparison */
4059
+ #ifndef FIO_SET_HASH_COMPARE
4060
+ #define FIO_SET_HASH_COMPARE(h1, h2) ((h1) == (h2))
4061
+ #endif
4062
+
4063
+ /* Customizable memory management */
4064
+ #ifndef FIO_SET_REALLOC /* NULL ptr indicates new allocation */
4065
+ #define FIO_SET_REALLOC(ptr, original_size, new_size, valid_data_length) \
4066
+ realloc((ptr), (new_size))
4067
+ #endif
4068
+ #ifndef FIO_SET_CALLOC
4069
+ #define FIO_SET_CALLOC(size, count) calloc((size), (count))
4070
+ #endif
4071
+ #ifndef FIO_SET_FREE
4072
+ #define FIO_SET_FREE(ptr, size) free((ptr))
4073
+ #endif
4074
+
4075
+ /* The maximum number of bins to rotate when partial collisions occure */
4076
+ #ifndef FIO_SET_MAX_MAP_SEEK
4077
+ #define FIO_SET_MAX_MAP_SEEK (96)
4078
+ #endif
4079
+
4080
+ /* Prime numbers are better */
4081
+ #ifndef FIO_SET_CUCKOO_STEPS
4082
+ #define FIO_SET_CUCKOO_STEPS 11
4083
+ #endif
4084
+
4085
+ #ifdef FIO_SET_KEY_TYPE
4086
+ typedef struct {
4087
+ FIO_SET_KEY_TYPE key;
4088
+ FIO_SET_OBJ_TYPE obj;
4089
+ } FIO_NAME(_couplet_s);
4090
+
4091
+ #define FIO_SET_TYPE FIO_NAME(_couplet_s)
4092
+
4093
+ /** key copy required? */
4094
+ #ifndef FIO_SET_KEY_COPY
4095
+ #define FIO_SET_KEY_COPY(dest, obj) ((dest) = (obj))
4096
+ #endif
4097
+
4098
+ /** key destruction required? */
4099
+ #ifndef FIO_SET_KEY_DESTROY
4100
+ #define FIO_SET_KEY_DESTROY(obj) ((void)0)
4101
+ #endif
4102
+
4103
+ /* The default Hash Map-Set has will use straight euqality operators */
4104
+ #if !defined(FIO_SET_KEY_COMPARE)
4105
+ #define FIO_SET_KEY_COMPARE(o1, o2) ((o1) == (o2))
4106
+ #endif
4107
+
4108
+ /** Internal macros for object actions in Hash mode */
4109
+ #define FIO_SET_COMPARE(o1, o2) FIO_SET_KEY_COMPARE((o1).key, (o2).key)
4110
+ #define FIO_SET_COPY(dest, org) \
4111
+ do { \
4112
+ FIO_SET_OBJ_COPY((dest).obj, (org).obj); \
4113
+ FIO_SET_KEY_COPY((dest).key, (org).key); \
4114
+ } while (0);
4115
+ #define FIO_SET_DESTROY(couplet) \
4116
+ do { \
4117
+ FIO_SET_KEY_DESTROY((couplet).key); \
4118
+ FIO_SET_OBJ_DESTROY((couplet).obj); \
4119
+ } while (0);
4120
+
4121
+ #else /* a pure Set, not a Hash Map*/
4122
+ /** Internal macros for object actions in Set mode */
4123
+ #define FIO_SET_COMPARE(o1, o2) FIO_SET_OBJ_COMPARE((o1), (o2))
4124
+ #define FIO_SET_COPY(dest, obj) FIO_SET_OBJ_COPY((dest), (obj))
4125
+ #define FIO_SET_DESTROY(obj) FIO_SET_OBJ_DESTROY((obj))
4126
+ #define FIO_SET_TYPE FIO_SET_OBJ_TYPE
4127
+ #endif
4128
+
4129
+ /* *****************************************************************************
4130
+ Set / Hash Map API
4131
+ ***************************************************************************** */
4132
+
4133
+ /** The Set container type. By default: fio_ptr_set_s */
4134
+ typedef struct FIO_NAME(s) FIO_NAME(s);
4135
+
4136
+ #ifndef FIO_SET_INIT
4137
+ /** Initializes the set */
4138
+ #define FIO_SET_INIT \
4139
+ { .capa = 0 }
4140
+ #endif
4141
+
4142
+ /** Deallocates any internal resources. Doesn't free any objects! */
4143
+ FIO_FUNC void FIO_NAME(free)(FIO_NAME(s) * set);
4144
+
4145
+ #ifdef FIO_SET_KEY_TYPE
4146
+
4147
+ /**
4148
+ *Locates an object in the Set, if it exists.
4149
+ *
4150
+ * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4151
+ */
4152
+ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4153
+ FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4154
+ FIO_SET_KEY_TYPE key);
4155
+
4156
+ /**
4157
+ * Inserts an object to the Set only if it's missing, rehashing if required,
4158
+ * returning the new (or old) object's pointer.
4159
+ *
4160
+ * If the object already exists in the set, no action is performed (the old
4161
+ * object is returned).
4162
+ *
4163
+ * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4164
+ */
4165
+ FIO_FUNC inline void FIO_NAME(insert)(FIO_NAME(s) * set,
4166
+ const FIO_SET_HASH_TYPE hash_value,
4167
+ FIO_SET_KEY_TYPE key,
4168
+ FIO_SET_OBJ_TYPE obj);
4169
+
4170
+ /**
4171
+ * Removes an object from the Set, rehashing if required.
4172
+ *
4173
+ * Returns 0 on success and -1 if the object wasn't found.
4174
+ *
4175
+ * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4176
+ */
4177
+ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4178
+ const FIO_SET_HASH_TYPE hash_value,
4179
+ FIO_SET_KEY_TYPE key);
4180
+
4181
+ #else
4182
+
4183
+ /**
4184
+ * Locates an object in the Set, if it exists.
4185
+ *
4186
+ * NOTE: This is the function's pure Set variant (no FIO_SET_KEY_TYPE).
4187
+ */
4188
+ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4189
+ FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4190
+ FIO_SET_OBJ_TYPE obj);
4191
+
4192
+ /**
4193
+ * Inserts an object to the Set only if it's missing, rehashing if required,
4194
+ * returning the new (or old) object's pointer.
4195
+ *
4196
+ *
4197
+ * If the object already exists in the set, than the new object will be
4198
+ * destroyed and the old object's address will be returned.
4199
+ *
4200
+ * NOTE: This is the function's pure Set variant (no FIO_SET_KEY_TYPE).
4201
+ */
4202
+ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4203
+ FIO_NAME(insert)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4204
+ FIO_SET_OBJ_TYPE obj);
4205
+
4206
+ /**
4207
+ * Inserts an object to the Set, rehashing if required, returning the new
4208
+ * object's pointer.
4209
+ *
4210
+ * If the object already exists in the set, it will be destroyed and
4211
+ * overwritten.
4212
+ *
4213
+ * NOTE: This function doesn't exist when FIO_SET_KEY_TYPE is defined.
4214
+ */
4215
+ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4216
+ FIO_NAME(overwrite)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4217
+ FIO_SET_OBJ_TYPE obj);
4218
+
4219
+ /**
4220
+ * Removes an object from the Set, rehashing if required.
4221
+ *
4222
+ * Returns 0 on success and -1 if the object wasn't found.
4223
+ *
4224
+ * NOTE: This is the function's pure Set variant (no FIO_SET_KEY_TYPE).
4225
+ */
4226
+ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4227
+ const FIO_SET_HASH_TYPE hash_value,
4228
+ FIO_SET_OBJ_TYPE obj);
4229
+
4230
+ #endif
4231
+ /**
4232
+ * Allows a peak at the Set's last element.
4233
+ *
4234
+ * Remember that objects might be destroyed if the Set is altered
4235
+ * (`FIO_SET_OBJ_DESTROY` / `FIO_SET_KEY_DESTROY`).
4236
+ */
4237
+ FIO_FUNC inline FIO_SET_TYPE *FIO_NAME(last)(FIO_NAME(s) * set);
4238
+
4239
+ /**
4240
+ * Allows the Hash to be momentarily used as a stack, destroying the last
4241
+ * object added (`FIO_SET_OBJ_DESTROY` / `FIO_SET_KEY_DESTROY`).
4242
+ */
4243
+ FIO_FUNC inline void FIO_NAME(pop)(FIO_NAME(s) * set);
4244
+
4245
+ /** Returns the number of object currently in the Set. */
4246
+ FIO_FUNC inline size_t FIO_NAME(count)(const FIO_NAME(s) * set);
4247
+
4248
+ /**
4249
+ * Returns a temporary theoretical Set capacity.
4250
+ * This could be used for testing performance and memory consumption.
4251
+ */
4252
+ FIO_FUNC inline size_t FIO_NAME(capa)(const FIO_NAME(s) * set);
4253
+
4254
+ /**
4255
+ * Requires that a Set contains the minimal requested theoretical capacity.
4256
+ *
4257
+ * Returns the actual (temporary) theoretical capacity.
4258
+ */
4259
+ FIO_FUNC inline size_t FIO_NAME(capa_require)(FIO_NAME(s) * set,
4260
+ size_t min_capa);
4261
+
4262
+ /**
4263
+ * Returns non-zero if the Set is fragmented (more than 50% holes).
4264
+ */
4265
+ FIO_FUNC inline size_t FIO_NAME(is_fragmented)(const FIO_NAME(s) * set);
4266
+
4267
+ /**
4268
+ * Attempts to minimize memory usage by removing empty spaces caused by deleted
4269
+ * items and rehashing the Set.
4270
+ *
4271
+ * Returns the updated Set capacity.
4272
+ */
4273
+ FIO_FUNC inline size_t FIO_NAME(compact)(FIO_NAME(s) * set);
4274
+
4275
+ /** Forces a rehashing of the Set. */
4276
+ FIO_FUNC void FIO_NAME(rehash)(FIO_NAME(s) * set);
4277
+
4278
+ #ifndef FIO_SET_FOR_LOOP
4279
+ /**
4280
+ * A macro for a `for` loop that iterates over all the Set's objects (in
4281
+ * order).
4282
+ *
4283
+ * `set` is a pointer to the Set variable and `pos` is a temporary variable
4284
+ * name to be created for iteration.
4285
+ *
4286
+ * `pos->hash` is the hashing value and `pos->obj` is the object's data.
4287
+ *
4288
+ * NOTICE: Since the Set might have "holes" (objects that were removed), it is
4289
+ * important to skip any `pos->hash == 0` or the equivalent of
4290
+ * `FIO_SET_HASH_COMPARE(pos->hash, FIO_SET_HASH_INVALID)`.
4291
+ */
4292
+ #define FIO_SET_FOR_LOOP(set, pos)
4293
+ #endif
4294
+
4295
+ /* *****************************************************************************
4296
+ Set / Hash Map Internal Data Structures
4297
+ ***************************************************************************** */
4298
+
4299
+ typedef struct FIO_NAME(_ordered_s_) {
4300
+ FIO_SET_HASH_TYPE hash;
4301
+ FIO_SET_TYPE obj;
4302
+ } FIO_NAME(_ordered_s_);
4303
+
4304
+ typedef struct FIO_NAME(_map_s_) {
4305
+ FIO_SET_HASH_TYPE hash; /* another copy for memory cache locality */
4306
+ FIO_NAME(_ordered_s_) * pos;
4307
+ } FIO_NAME(_map_s_);
4308
+
4309
+ /* the information in the Hash Map structure should be considered READ ONLY. */
4310
+ struct FIO_NAME(s) {
4311
+ uintptr_t count;
4312
+ uintptr_t capa;
4313
+ uintptr_t pos;
4314
+ uintptr_t mask;
4315
+ FIO_NAME(_ordered_s_) * ordered;
4316
+ FIO_NAME(_map_s_) * map;
4317
+ uint8_t has_collisions;
4318
+ };
4319
+
4320
+ #undef FIO_SET_FOR_LOOP
4321
+ #define FIO_SET_FOR_LOOP(set, container) \
4322
+ for (__typeof__((set)->ordered) container = (set)->ordered; \
4323
+ container && (container < ((set)->ordered + (set)->pos)); ++container)
4324
+
4325
+ /* *****************************************************************************
4326
+ Set / Hash Map Internal Helpers
4327
+ ***************************************************************************** */
4328
+
4329
+ /** Locates an object's map position in the Set, if it exists. */
4330
+ FIO_FUNC inline FIO_NAME(_map_s_) *
4331
+ FIO_NAME(_find_map_pos_)(FIO_NAME(s) * set,
4332
+ const FIO_SET_HASH_TYPE hash_value,
4333
+ FIO_SET_TYPE obj) {
4334
+ if (set->map) {
4335
+ /* make sure collisions don't effect seeking */
4336
+ if (set->has_collisions && set->pos != set->count) {
4337
+ FIO_NAME(rehash)(set);
4338
+ }
4339
+
4340
+ /* O(1) access to object */
4341
+ FIO_NAME(_map_s_) *pos =
4342
+ set->map + (FIO_SET_HASH2UINTPTR(hash_value) & set->mask);
4343
+ if (FIO_SET_HASH_COMPARE(FIO_SET_HASH_INVALID, pos->hash))
4344
+ return pos;
4345
+ if (FIO_SET_HASH_COMPARE(pos->hash, hash_value)) {
4346
+ if (!pos->pos || FIO_SET_OBJ_COMPARE(pos->pos->obj, obj))
4347
+ return pos;
4348
+ set->has_collisions = 1;
4349
+ }
4350
+
4351
+ /* Handle partial / full collisions with cuckoo steps O(x) access time */
4352
+ uintptr_t i = FIO_SET_CUCKOO_STEPS;
4353
+ const uintptr_t limit =
4354
+ FIO_SET_CUCKOO_STEPS * (set->capa > (FIO_SET_MAX_MAP_SEEK << 2)
4355
+ ? FIO_SET_MAX_MAP_SEEK
4356
+ : (set->capa >> 2));
4357
+ while (i < limit) {
4358
+ pos = set->map + ((FIO_SET_HASH2UINTPTR(hash_value) + i) & set->mask);
4359
+ if (FIO_SET_HASH_COMPARE(FIO_SET_HASH_INVALID, pos->hash))
4360
+ return pos;
4361
+ if (FIO_SET_HASH_COMPARE(pos->hash, hash_value)) {
4362
+ if (!pos->pos || FIO_SET_OBJ_COMPARE(pos->pos->obj, obj))
4363
+ return pos;
4364
+ set->has_collisions = 1;
4365
+ }
4366
+ i += FIO_SET_CUCKOO_STEPS;
4367
+ }
4368
+ }
4369
+ return NULL;
4370
+ (void)obj; /* in cases where FIO_SET_OBJ_COMPARE does nothing */
4371
+ }
4372
+ #undef FIO_SET_CUCKOO_STEPS
4373
+
4374
+ /** Removes "holes" from the Set's internal Array - MUST re-hash afterwards.
4375
+ */
4376
+ FIO_FUNC inline void FIO_NAME(_compact_ordered_array_)(FIO_NAME(s) * set) {
4377
+ if (set->count == set->pos)
4378
+ return;
4379
+ FIO_NAME(_ordered_s_) *reader = set->ordered;
4380
+ FIO_NAME(_ordered_s_) *writer = set->ordered;
4381
+ const FIO_NAME(_ordered_s_) *end = set->ordered + set->pos;
4382
+ for (; reader && (reader < end); ++reader) {
4383
+ if (FIO_SET_HASH_COMPARE(reader->hash, FIO_SET_HASH_INVALID)) {
4384
+ continue;
4385
+ }
4386
+ *writer = *reader;
4387
+ ++writer;
4388
+ }
4389
+ /* fix any possible counting errors as well as resetting position */
4390
+ set->pos = set->count = (writer - set->ordered);
4391
+ }
4392
+
4393
+ /** (Re)allocates the set's internal, invalidatint the mapping (must rehash) */
4394
+ FIO_FUNC inline void FIO_NAME(_reallocate_set_mem_)(FIO_NAME(s) * set) {
4395
+ FIO_SET_FREE(set->map, set->capa * sizeof(*set->map));
4396
+ set->map =
4397
+ (FIO_NAME(_map_s_) *)FIO_SET_CALLOC(sizeof(*set->map), (set->mask + 1));
4398
+ set->ordered = (FIO_NAME(_ordered_s_) *)FIO_SET_REALLOC(
4399
+ set->ordered, (set->capa * sizeof(*set->ordered)),
4400
+ ((set->mask + 1) * sizeof(*set->ordered)),
4401
+ (set->pos * sizeof(*set->ordered)));
4402
+ if (!set->map || !set->ordered) {
4403
+ perror("FATAL ERROR: couldn't allocate memory for Set data");
4404
+ exit(errno);
4405
+ }
4406
+ set->capa = set->mask + 1;
4407
+ }
4408
+
4409
+ /**
4410
+ * Inserts an object to the Set, rehashing if required, returning the new
4411
+ * object's pointer.
4412
+ *
4413
+ * If the object already exists in the set, it will be destroyed and
4414
+ * overwritten.
4415
+ */
4416
+ FIO_FUNC inline FIO_SET_TYPE *
4417
+ FIO_NAME(_insert_or_overwrite_)(FIO_NAME(s) * set,
4418
+ const FIO_SET_HASH_TYPE hash_value,
4419
+ FIO_SET_TYPE obj, int overwrite) {
4420
+ if (FIO_SET_HASH_COMPARE(hash_value, FIO_SET_HASH_INVALID))
4421
+ return NULL;
4422
+
4423
+ /* automatic fragmentation protection */
4424
+ if (FIO_NAME(is_fragmented)(set))
4425
+ FIO_NAME(rehash)(set);
4426
+
4427
+ /* locate future position, rehashing until a position is available */
4428
+ FIO_NAME(_map_s_) *pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
4429
+
4430
+ while (!pos) {
4431
+ set->mask = (set->mask << 1) | 1;
4432
+ FIO_NAME(rehash)(set);
4433
+ pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
4434
+ }
4435
+
4436
+ /* overwriting / new */
4437
+ if (pos->pos) {
4438
+ /* overwrite existing object */
4439
+ if (!overwrite) {
4440
+ FIO_SET_DESTROY(obj);
4441
+ return &pos->pos->obj;
4442
+ }
4443
+ #ifdef FIO_SET_KEY_TYPE
4444
+ /* no need to recreate the key object, just the value object */
4445
+ FIO_SET_OBJ_DESTROY(pos->pos->obj.obj);
4446
+ FIO_SET_OBJ_COPY(pos->pos->obj.obj, obj.obj);
4447
+ return &pos->pos->obj;
4448
+ #else
4449
+ FIO_SET_DESTROY(pos->pos->obj);
4450
+ #endif
4451
+ } else {
4452
+ /* insert into new slot */
4453
+ pos->pos = set->ordered + set->pos;
4454
+ ++set->pos;
4455
+ ++set->count;
4456
+ }
4457
+ /* store object at position */
4458
+ pos->hash = hash_value;
4459
+ pos->pos->hash = hash_value;
4460
+ FIO_SET_COPY(pos->pos->obj, obj);
4461
+
4462
+ return &pos->pos->obj;
4463
+ }
4464
+
4465
+ /* *****************************************************************************
4466
+ Set / Hash Map Implementation
4467
+ ***************************************************************************** */
4468
+
4469
+ /** Deallocates any internal resources. Doesn't free any objects! */
4470
+ FIO_FUNC void FIO_NAME(free)(FIO_NAME(s) * s) {
4471
+ /* destroy existing valid objects */
4472
+ const FIO_NAME(_ordered_s_) *const end = s->ordered + s->pos;
4473
+ if (s->ordered && s->ordered != end) {
4474
+ for (FIO_NAME(_ordered_s_) *pos = s->ordered; pos < end; ++pos) {
4475
+ if (!FIO_SET_HASH_COMPARE(FIO_SET_HASH_INVALID, pos->hash)) {
4476
+ FIO_SET_DESTROY(pos->obj);
4477
+ }
4478
+ }
4479
+ }
4480
+ /* free ordered array and hash mapping */
4481
+ FIO_SET_FREE(s->map, s->capa * sizeof(*s->map));
4482
+ FIO_SET_FREE(s->ordered, s->capa * sizeof(*s->ordered));
4483
+ *s = (FIO_NAME(s)){.map = NULL};
4484
+ }
4485
+
4486
+ #ifdef FIO_SET_KEY_TYPE
4487
+
4488
+ /**
4489
+ * Locates an object in the Set, if it exists.
4490
+ *
4491
+ * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4492
+ */
4493
+ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4494
+ FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4495
+ FIO_SET_KEY_TYPE key) {
4496
+ FIO_NAME(_map_s_) *pos =
4497
+ FIO_NAME(_find_map_pos_)(set, hash_value, (FIO_SET_TYPE){.key = key});
4498
+ if (!pos || !pos->pos)
4499
+ return NULL;
4500
+ return &pos->pos->obj.obj;
4501
+ }
4502
+
4503
+ /**
4504
+ * Inserts an object to the Set only if it's missing, rehashing if required,
4505
+ * returning the new (or old) object's pointer.
4506
+ *
4507
+ * If the object already exists in the set, no action is performed (the old
4508
+ * object is returned).
4509
+ *
4510
+ * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4511
+ */
4512
+ FIO_FUNC inline void FIO_NAME(insert)(FIO_NAME(s) * set,
4513
+ const FIO_SET_HASH_TYPE hash_value,
4514
+ FIO_SET_KEY_TYPE key,
4515
+ FIO_SET_OBJ_TYPE obj) {
4516
+ FIO_NAME(_insert_or_overwrite_)
4517
+ (set, hash_value, (FIO_SET_TYPE){.key = key, .obj = obj}, 1);
4518
+ }
4519
+
4520
+ #else
4521
+
4522
+ /** Locates an object in the Set, if it exists. */
4523
+ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4524
+ FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4525
+ FIO_SET_OBJ_TYPE obj) {
4526
+ FIO_NAME(_map_s_) *pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
4527
+ if (!pos || !pos->pos)
4528
+ return NULL;
4529
+ return &pos->pos->obj;
4530
+ }
4531
+
4532
+ /**
4533
+ * Inserts an object to the Set, rehashing if required, returning the new
4534
+ * object's pointer.
4535
+ *
4536
+ * If the object already exists in the set, than the new object will be
4537
+ * destroyed and the old object's address will be returned.
4538
+ */
4539
+ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4540
+ FIO_NAME(insert)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4541
+ FIO_SET_OBJ_TYPE obj) {
4542
+ return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 0);
4543
+ }
4544
+
4545
+ /**
4546
+ * Inserts an object to the Set, rehashing if required, returning the new
4547
+ * object's pointer.
4548
+ *
4549
+ * If the object already exists in the set, it will be destroyed and
4550
+ * overwritten.
4551
+ */
4552
+ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4553
+ FIO_NAME(overwrite)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4554
+ FIO_SET_OBJ_TYPE obj) {
4555
+ return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 1);
4556
+ }
4557
+
4558
+ #endif
4559
+
4560
+ /**
4561
+ * Removes an object from the Set, rehashing if required.
4562
+ */
4563
+ #ifdef FIO_SET_KEY_TYPE
4564
+
4565
+ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4566
+ const FIO_SET_HASH_TYPE hash_value,
4567
+ FIO_SET_KEY_TYPE key) {
4568
+ #else
4569
+ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4570
+ const FIO_SET_HASH_TYPE hash_value,
4571
+ FIO_SET_OBJ_TYPE obj) {
4572
+ #endif
4573
+ if (FIO_SET_HASH_COMPARE(hash_value, FIO_SET_HASH_INVALID))
4574
+ return -1;
4575
+ #ifdef FIO_SET_KEY_TYPE
4576
+ FIO_NAME(_map_s_) *pos =
4577
+ FIO_NAME(_find_map_pos_)(set, hash_value, (FIO_SET_TYPE){.key = key});
4578
+ #else
4579
+ FIO_NAME(_map_s_) *pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
4580
+ #endif
4581
+ if (!pos || !pos->pos)
4582
+ return -1;
4583
+ FIO_SET_DESTROY(pos->pos->obj);
4584
+ --set->count;
4585
+ pos->pos->hash = FIO_SET_HASH_INVALID;
4586
+ if (pos->pos == set->pos + set->ordered - 1) {
4587
+ do {
4588
+ --set->pos;
4589
+ } while (set->pos && FIO_SET_HASH_COMPARE(set->ordered[set->pos - 1].hash,
4590
+ FIO_SET_HASH_INVALID));
4591
+ }
4592
+ pos->pos = NULL; /* leave pos->hash set to mark "hole" */
4593
+ return 0;
4594
+ }
4595
+
4596
+ /**
4597
+ * Allows a peak at the Set's last element.
4598
+ *
4599
+ * Remember that objects might be destroyed if the Set is altered
4600
+ * (`FIO_SET_OBJ_DESTROY` / `FIO_SET_KEY_DESTROY`).
4601
+ */
4602
+ FIO_FUNC inline FIO_SET_TYPE *FIO_NAME(last)(FIO_NAME(s) * set) {
4603
+ if (!set->ordered || !set->pos)
4604
+ return NULL;
4605
+ return &set->ordered[set->pos - 1].obj;
4606
+ }
4607
+
4608
+ /**
4609
+ * Allows the Hash to be momentarily used as a stack, destroying the last
4610
+ * object added (`FIO_SET_OBJ_DESTROY` / `FIO_SET_KEY_DESTROY`).
4611
+ */
4612
+ FIO_FUNC void FIO_NAME(pop)(FIO_NAME(s) * set) {
4613
+ if (!set->ordered || !set->pos)
4614
+ return;
4615
+ FIO_SET_DESTROY(set->ordered[set->pos - 1].obj);
4616
+ set->ordered[set->pos - 1].hash = FIO_SET_HASH_INVALID;
4617
+ --(set->count);
4618
+ do {
4619
+ --(set->pos);
4620
+ } while (set->pos && FIO_SET_HASH_COMPARE(set->ordered[set->pos - 1].hash,
4621
+ FIO_SET_HASH_INVALID));
4622
+ }
4623
+
4624
+ /** Returns the number of objects currently in the Set. */
4625
+ FIO_FUNC inline size_t FIO_NAME(count)(const FIO_NAME(s) * set) {
4626
+ return (size_t)set->count;
4627
+ }
4628
+
4629
+ /**
4630
+ * Returns a temporary theoretical Set capacity.
4631
+ * This could be used for testing performance and memory consumption.
4632
+ */
4633
+ FIO_FUNC inline size_t FIO_NAME(capa)(const FIO_NAME(s) * set) {
4634
+ return (size_t)set->capa;
4635
+ }
4636
+
4637
+ /**
4638
+ * Requires that a Set contains the minimal requested theoretical capacity.
4639
+ *
4640
+ * Returns the actual (temporary) theoretical capacity.
4641
+ */
4642
+ FIO_FUNC inline size_t FIO_NAME(capa_require)(FIO_NAME(s) * set,
4643
+ size_t min_capa) {
4644
+ if (min_capa <= FIO_NAME(capa)(set))
4645
+ return FIO_NAME(capa)(set);
4646
+ set->mask = 1;
4647
+ while (min_capa >= set->mask) {
4648
+ set->mask = (set->mask << 1) | 1;
4649
+ }
4650
+ FIO_NAME(rehash)(set);
4651
+ return FIO_NAME(capa)(set);
4652
+ }
4653
+
4654
+ /**
4655
+ * Returns non-zero if the Set is fragmented (more than 50% holes).
4656
+ */
4657
+ FIO_FUNC inline size_t FIO_NAME(is_fragmented)(const FIO_NAME(s) * set) {
4658
+ return ((set->pos - set->count) > (set->count >> 1));
4659
+ }
4660
+
4661
+ /**
4662
+ * Attempts to minimize memory usage by removing empty spaces caused by deleted
4663
+ * items and rehashing the Set.
4664
+ *
4665
+ * Returns the updated Set capacity.
4666
+ */
4667
+ FIO_FUNC inline size_t FIO_NAME(compact)(FIO_NAME(s) * set) {
4668
+ FIO_NAME(_compact_ordered_array_)(set);
4669
+ set->mask = 1;
4670
+ while (set->count >= set->mask) {
4671
+ set->mask = (set->mask << 1) | 1;
4672
+ }
4673
+ FIO_NAME(rehash)(set);
4674
+ return FIO_NAME(capa)(set);
4675
+ }
4676
+
4677
+ /** Forces a rehashing of the Set. */
4678
+ FIO_FUNC void FIO_NAME(rehash)(FIO_NAME(s) * set) {
4679
+ FIO_NAME(_compact_ordered_array_)(set);
4680
+ set->has_collisions = 0;
4681
+ restart:
4682
+ FIO_NAME(_reallocate_set_mem_)(set);
4683
+ {
4684
+ FIO_NAME(_ordered_s_) const *const end = set->ordered + set->pos;
4685
+ for (FIO_NAME(_ordered_s_) *pos = set->ordered; pos < end; ++pos) {
4686
+ FIO_NAME(_map_s_) *mp =
4687
+ FIO_NAME(_find_map_pos_)(set, pos->hash, pos->obj);
4688
+ if (!mp) {
4689
+ set->mask = (set->mask << 1) | 1;
4690
+ goto restart;
4691
+ }
4692
+ mp->pos = pos;
4693
+ mp->hash = pos->hash;
4694
+ }
4695
+ }
4696
+ }
4697
+
4698
+ #undef FIO_SET_OBJ_TYPE
4699
+ #undef FIO_SET_OBJ_COMPARE
4700
+ #undef FIO_SET_OBJ_COPY
4701
+ #undef FIO_SET_OBJ_DESTROY
4702
+ #undef FIO_SET_HASH_TYPE
4703
+ #undef FIO_SET_HASH2UINTPTR
4704
+ #undef FIO_SET_HASH_COMPARE
4705
+ #undef FIO_SET_HASH_INVALID
4706
+ #undef FIO_SET_KEY_TYPE
4707
+ #undef FIO_SET_KEY_COPY
4708
+ #undef FIO_SET_KEY_DESTROY
4709
+ #undef FIO_SET_KEY_COMPARE
4710
+ #undef FIO_SET_TYPE
4711
+ #undef FIO_SET_COMPARE
4712
+ #undef FIO_SET_COPY
4713
+ #undef FIO_SET_DESTROY
4714
+ #undef FIO_SET_MAX_MAP_SEEK
4715
+ #undef FIO_SET_REALLOC
4716
+ #undef FIO_SET_CALLOC
4717
+ #undef FIO_SET_FREE
4718
+ #undef FIO_NAME
4719
+ #undef FIO_NAME_FROM_MACRO_STEP2
4720
+ #undef FIO_NAME_FROM_MACRO_STEP1
4721
+ #undef FIO_SET_NAME
4722
+
4723
+ #endif