iodine 0.7.1 → 0.7.2

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.

@@ -11,82 +11,84 @@ Feel free to copy, use and enjoy according to the license provided.
11
11
  #define H_FACIL_IO_H
12
12
 
13
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
- ***************************************************************************** */
14
+ * Table of contents (find by subject):
15
+ * =================
16
+ * Version and helper macros
17
+ * Helper String Information Type
18
+ * Memory pool / custom allocator for short lived objects
19
+ * Logging and testing helpers
20
+ *
21
+ * Connection Callback (Protocol) Management
22
+ * Listening to Incoming Connections
23
+ * Connecting to remote servers as a client
24
+ * Starting the IO reactor and reviewing it's state
25
+ * Socket / Connection Functions
26
+ * Connection Read / Write Hooks, for overriding the system calls
27
+ * Concurrency overridable functions
28
+ * Connection Task scheduling
29
+ * Event / Task scheduling
30
+ * Startup / State Callbacks (fork, start up, idle, etc')
31
+ * Lower Level API - for special circumstances, use with care under
32
+ *
33
+ * Pub/Sub / Cluster Messages API
34
+ * Cluster Messages and Pub/Sub
35
+ * Cluster / Pub/Sub Middleware and Extensions ("Engines")
36
+ *
37
+ * Atomic Operations and Spin Locking Helper Functions
38
+ * Byte Swapping and Network Order
39
+ *
40
+ * Converting Numbers to Strings (and back)
41
+ * Strings to Numbers
42
+ * Numbers to Strings* Random Generator Functions
43
+ *
44
+ * SipHash
45
+ * SHA-1
46
+ * SHA-2
47
+ * Base64 (URL) encoding
48
+ *
49
+ * Memory Allocator Details
50
+ *
51
+ * Spin locking Implementation
52
+ *
53
+ ******** facil.io Data Types (String, Set / Hash Map, Linked Lists, etc')
54
+ *
55
+ * These types can be included by defining the macros and (re)including fio.h.
56
+ *
57
+ *
58
+ *
59
+ * #ifdef FIO_INCLUDE_LINKED_LIST
60
+ *
61
+ * Linked List Helpers
62
+ * Independent Linked List API
63
+ * Embedded Linked List API* Independent Linked List Implementation
64
+ * Embeded Linked List Implementation
65
+ *
66
+ *
67
+ *
68
+ * #ifdef FIO_INCLUDE_STR
69
+ *
70
+ * String Helpers
71
+ * String API - Initialization and Destruction
72
+ * String API - String state (data pointers, length, capacity, etc')
73
+ * String API - Memory management
74
+ * String API - UTF-8 State
75
+ * String Implementation - state (data pointers, length, capacity, etc')
76
+ * String Implementation - Memory management
77
+ * String Implementation - UTF-8 State
78
+ * String Implementation - Content Manipulation and Review
79
+ *
80
+ *
81
+ *
82
+ * #ifdef FIO_SET_NAME - can be included more than once
83
+ *
84
+ * Set / Hash Map Data-Store
85
+ * Set / Hash Map API
86
+ * Set / Hash Map Internal Data Structures
87
+ * Set / Hash Map Internal Helpers
88
+ * Set / Hash Map Implementation
89
+ *
90
+ *****************************************************************************
91
+ */
90
92
 
91
93
  /* *****************************************************************************
92
94
  Version and helper macros
@@ -199,44 +201,11 @@ Version and helper macros
199
201
  #define FIO_FUNC static __attribute__((unused))
200
202
  #endif
201
203
 
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
204
  #if defined(__FreeBSD__)
217
205
  #include <netinet/in.h>
218
206
  #include <sys/socket.h>
219
207
  #endif
220
208
 
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
- #else
236
- #define FIO_LOG_DEBUG(...)
237
- #define FIO_ASSERT(...)
238
- #endif
239
-
240
209
  /* *****************************************************************************
241
210
  C++ extern start
242
211
  ***************************************************************************** */
@@ -260,7 +229,31 @@ typedef struct fio_str_info_s {
260
229
  #endif
261
230
 
262
231
  /* *****************************************************************************
232
+
233
+
234
+
235
+
236
+
237
+
238
+
239
+
240
+
241
+
242
+
243
+
263
244
  Memory pool / custom allocator for short lived objects
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+
253
+
254
+
255
+
256
+
264
257
  ***************************************************************************** */
265
258
 
266
259
  /**
@@ -308,10 +301,16 @@ void *fio_realloc2(void *ptr, size_t new_size, size_t copy_length);
308
301
  */
309
302
  void *fio_mmap(size_t size);
310
303
 
304
+ /**
305
+ * When forking is called manually, call this function to reset the facil.io
306
+ * memory allocator's locks.
307
+ */
308
+ void fio_malloc_after_fork(void);
309
+
311
310
  #if FIO_FORCE_MALLOC
312
- #define fio_malloc malloc
311
+ #define fio_malloc(size) calloc(size, 1)
313
312
  #define fio_calloc calloc
314
- #define fio_mmap malloc
313
+ #define fio_mmap(size) calloc(size, 1)
315
314
  #define fio_free free
316
315
  #define fio_realloc realloc
317
316
  #define fio_realloc2(ptr, new_size, old_data_len) realloc((ptr), (new_size))
@@ -332,6 +331,100 @@ void *fio_mmap(size_t size);
332
331
 
333
332
 
334
333
 
334
+ Logging and testing helpers
335
+
336
+
337
+
338
+
339
+
340
+
341
+
342
+
343
+
344
+
345
+
346
+
347
+ ***************************************************************************** */
348
+
349
+ /** Logging level of zero (no logging). */
350
+ #define FIO_LOG_LEVEL_NONE 0
351
+ /** Log fatal errors. */
352
+ #define FIO_LOG_LEVEL_FATAL 1
353
+ /** Log errors and fatal errors. */
354
+ #define FIO_LOG_LEVEL_ERROR 2
355
+ /** Log warnings, errors and fatal errors. */
356
+ #define FIO_LOG_LEVEL_WARNING 3
357
+ /** Log every message (info, warnings, errors and fatal errors). */
358
+ #define FIO_LOG_LEVEL_INFO 4
359
+ /** Log everything, including debug messages. */
360
+ #define FIO_LOG_LEVEL_DEBUG 5
361
+
362
+ /** The logging level */
363
+ extern size_t FIO_LOG_LEVEL;
364
+
365
+ #ifndef FIO_LOG_PRINT
366
+ #define FIO_LOG_PRINT(level, ...) \
367
+ do { \
368
+ if (level <= FIO_LOG_LEVEL) \
369
+ fprintf(stderr, "\n" __VA_ARGS__); \
370
+ } while (0)
371
+ #define FIO_LOG_DEBUG(...) \
372
+ FIO_LOG_PRINT(FIO_LOG_LEVEL_DEBUG, \
373
+ "[DEBUG ("__FILE__ \
374
+ ":" FIO_MACRO2STR(__LINE__) ")] " __VA_ARGS__)
375
+ #define FIO_LOG_INFO(...) \
376
+ FIO_LOG_PRINT(FIO_LOG_LEVEL_INFO, "[INFO] " __VA_ARGS__)
377
+ #define FIO_LOG_WARNING(...) \
378
+ FIO_LOG_PRINT(FIO_LOG_LEVEL_WARNING, "[WARNING] " __VA_ARGS__)
379
+ #define FIO_LOG_ERROR(...) \
380
+ FIO_LOG_PRINT(FIO_LOG_LEVEL_ERROR, "[ERROR] " __VA_ARGS__)
381
+ #define FIO_LOG_FATAL(...) \
382
+ FIO_LOG_PRINT(FIO_LOG_LEVEL_FATAL, "[FATAL] " __VA_ARGS__)
383
+ #endif
384
+
385
+ #if FIO_PRINT_STATE
386
+ #define FIO_LOG_STATE(...) fprintf(stderr, "\n" __VA_ARGS__)
387
+ #else
388
+ #define FIO_LOG_STATE(...)
389
+ #endif
390
+
391
+ #if DEBUG
392
+ #define FIO_ASSERT(cond, ...) \
393
+ if (!(cond)) { \
394
+ FIO_LOG_DEBUG(__VA_ARGS__); \
395
+ exit(-1); \
396
+ }
397
+ #else
398
+ #define FIO_ASSERT(...)
399
+ #endif
400
+
401
+ #ifndef FIO_ASSERT_ALLOC
402
+ /** Tests for an allocation failure. The behavior can be overridden. */
403
+ #define FIO_ASSERT_ALLOC(ptr) \
404
+ if (!(ptr)) { \
405
+ fprintf(stderr, \
406
+ "FATAL ERROR: memory allocation error "__FILE__ \
407
+ ":%d\n", \
408
+ __LINE__); \
409
+ perror(" Error details (errno)"); \
410
+ kill(0, SIGINT); \
411
+ exit(errno); \
412
+ }
413
+ #endif
414
+
415
+ /* *****************************************************************************
416
+
417
+
418
+
419
+
420
+
421
+
422
+
423
+
424
+
425
+
426
+
427
+
335
428
  Connection Callback (Protocol) Management
336
429
 
337
430
 
@@ -1082,8 +1175,6 @@ typedef struct fio_rw_hook_s {
1082
1175
  ssize_t (*write)(intptr_t uuid, void *udata, const void *buf, size_t count);
1083
1176
  /**
1084
1177
  * The `close` callback should close the underlying socket / file descriptor.
1085
- * It should also be used to release any resources associated with the
1086
- * connection's read/write hooks.
1087
1178
  *
1088
1179
  * If the function returns a non-zero value, it will be called again after an
1089
1180
  * attempt to flush the socket and any pending outgoing buffer.
@@ -1103,6 +1194,10 @@ typedef struct fio_rw_hook_s {
1103
1194
  * deadlock might occur.
1104
1195
  */
1105
1196
  ssize_t (*flush)(intptr_t uuid, void *udata);
1197
+ /**
1198
+ * Called to perform cleanup after the socket was closed.
1199
+ * */
1200
+ void (*cleanup)(void *udata);
1106
1201
  } fio_rw_hook_s;
1107
1202
 
1108
1203
  /** Sets a socket hook state (a pointer to the struct). */
@@ -1260,6 +1355,8 @@ typedef enum {
1260
1355
  FIO_CALL_AFTER_FORK,
1261
1356
  /** Called by a worker process right after forking. */
1262
1357
  FIO_CALL_IN_CHILD,
1358
+ /** Called by the master process after spawning a worker (after forking). */
1359
+ FIO_CALL_IN_MASTER,
1263
1360
  /** Called every time a *Worker* proceess starts. */
1264
1361
  FIO_CALL_ON_START,
1265
1362
  /** Called when facil.io enters idling mode. */
@@ -2424,9 +2521,9 @@ C++ extern end
2424
2521
  #undef FIO_MEMORY_BLOCK_SIZE
2425
2522
  #undef FIO_MEMORY_BLOCK_MASK
2426
2523
  #undef FIO_MEMORY_BLOCK_SLICES
2427
- #define FIO_MEMORY_BLOCK_MASK (FIO_MEMORY_BLOCK_SIZE - 1) /* 0b111... */
2428
- #define FIO_MEMORY_BLOCK_SLICES (FIO_MEMORY_BLOCK_SIZE >> 4) /* 16B slices */
2429
2524
  #define FIO_MEMORY_BLOCK_SIZE ((uintptr_t)1 << FIO_MEMORY_BLOCK_SIZE_LOG)
2525
+ #define FIO_MEMORY_BLOCK_MASK (FIO_MEMORY_BLOCK_SIZE - 1) /* 0b0...1... */
2526
+ #define FIO_MEMORY_BLOCK_SLICES (FIO_MEMORY_BLOCK_SIZE >> 4) /* 16B slices */
2430
2527
 
2431
2528
  #ifndef FIO_MEMORY_BLOCK_ALLOC_LIMIT
2432
2529
  /* defaults to 37.5% of the block, after which `mmap` is used instead */
@@ -2515,13 +2612,13 @@ FIO_FUNC inline void fio_lock_dbg(fio_lock_i *lock, const char *file,
2515
2612
  while (fio_trylock(lock)) {
2516
2613
  if (lock_cycle_count >= 8 &&
2517
2614
  (lock_cycle_count == 8 || !(lock_cycle_count & 511)))
2518
- fprintf(stderr, "INFO: fio-spinlock spin %s:%d round %zu\n", file, line,
2615
+ fprintf(stderr, "[DEBUG] fio-spinlock spin %s:%d round %zu\n", file, line,
2519
2616
  lock_cycle_count);
2520
2617
  ++lock_cycle_count;
2521
2618
  fio_reschedule_thread();
2522
2619
  }
2523
2620
  if (lock_cycle_count >= 8)
2524
- fprintf(stderr, "INFO: fio-spinlock spin %s:%d total = %zu\n", file, line,
2621
+ fprintf(stderr, "[DEBUG] fio-spinlock spin %s:%d total = %zu\n", file, line,
2525
2622
  lock_cycle_count);
2526
2623
  }
2527
2624
  #define fio_lock(lock) fio_lock_dbg((lock), __FILE__, __LINE__)
@@ -2537,7 +2634,7 @@ FIO_FUNC inline int fio_trylock_dbg(fio_lock_i *lock, const char *file,
2537
2634
  } else if (line == last_line) {
2538
2635
  ++count;
2539
2636
  if (count >= 2)
2540
- fprintf(stderr, "INFO: trying fio-spinlock %s:%d attempt %zu\n", file,
2637
+ fprintf(stderr, "[DEBUG] trying fio-spinlock %s:%d attempt %zu\n", file,
2541
2638
  line, count);
2542
2639
  } else {
2543
2640
  count = 0;
@@ -2834,10 +2931,16 @@ String API - Initialization and Destruction
2834
2931
  * used.
2835
2932
  */
2836
2933
  typedef struct {
2934
+ #ifndef FIO_STR_NO_REF
2837
2935
  volatile uint32_t ref; /* reference counter for fio_str_dup */
2936
+ #endif
2838
2937
  uint8_t small; /* Flag indicating the String is small and self-contained */
2839
2938
  uint8_t frozen; /* Flag indicating the String is frozen (don't edit) */
2840
- uint8_t reserved[10]; /* Align struct on 16 byte allocator boundary */
2939
+ #ifdef FIO_STR_NO_REF
2940
+ uint8_t reserved[14]; /* Align struct on 16 byte allocator boundary */
2941
+ #else
2942
+ uint8_t reserved[10]; /* Align struct on 16 byte allocator boundary */
2943
+ #endif
2841
2944
  uint64_t capa; /* Known capacity for longer Strings */
2842
2945
  uint64_t len; /* String length for longer Strings */
2843
2946
  void (*dealloc)(void *); /* Data deallocation function (NULL for static) */
@@ -2910,6 +3013,9 @@ inline FIO_FUNC fio_str_s *fio_str_new_copy2(fio_str_s *src);
2910
3013
  /**
2911
3014
  * Adds a references to the current String object and returns itself.
2912
3015
  *
3016
+ * If refecrence counting was disabled (FIO_STR_NO_REF was defined), returns a
3017
+ * copy of the String (free with `fio_str_free2`).
3018
+ *
2913
3019
  * NOTE: Nothing is copied, reference Strings are referencing the same String.
2914
3020
  * Editing one reference will effect the other.
2915
3021
  *
@@ -3145,7 +3251,9 @@ String Implementation - state (data pointers, length, capacity, etc')
3145
3251
  ***************************************************************************** */
3146
3252
 
3147
3253
  typedef struct {
3254
+ #ifndef FIO_STR_NO_REF
3148
3255
  volatile uint32_t ref; /* reference counter for fio_str_dup */
3256
+ #endif
3149
3257
  uint8_t small; /* Flag indicating the String is small and self-contained */
3150
3258
  uint8_t frozen; /* Flag indicating the String is frozen (don't edit) */
3151
3259
  } fio_str__small_s;
@@ -3199,6 +3307,9 @@ inline FIO_FUNC fio_str_s *fio_str_new_copy2(fio_str_s *src) {
3199
3307
  /**
3200
3308
  * Adds a references to the current String object and returns itself.
3201
3309
  *
3310
+ * If refecrence counting was disabled (FIO_STR_NO_REF was defined), returns a
3311
+ * copy of the String (free with `fio_str_free2`).
3312
+ *
3202
3313
  * NOTE: Nothing is copied, reference Strings are referencing the same String.
3203
3314
  * Editing one reference will effect the other.
3204
3315
  *
@@ -3207,9 +3318,15 @@ inline FIO_FUNC fio_str_s *fio_str_new_copy2(fio_str_s *src) {
3207
3318
  * were freed using `fio_str_free` / `fio_str_free2` or discarded.
3208
3319
  */
3209
3320
  inline FIO_FUNC fio_str_s *fio_str_dup(fio_str_s *s) {
3321
+ #ifdef FIO_STR_NO_REF
3322
+ fio_str_s *s2 = fio_str_new2();
3323
+ fio_str_concat(s2, s);
3324
+ return s2;
3325
+ #else
3210
3326
  if (s)
3211
3327
  fio_atomic_add(&s->ref, 1);
3212
3328
  return s;
3329
+ #endif
3213
3330
  }
3214
3331
 
3215
3332
  /**
@@ -3222,13 +3339,14 @@ inline FIO_FUNC fio_str_s *fio_str_dup(fio_str_s *s) {
3222
3339
  * references (see fio_str_dup).
3223
3340
  */
3224
3341
  inline FIO_FUNC int fio_str_free(fio_str_s *s) {
3225
- if (s && fio_atomic_sub(&s->ref, 1) == (uint32_t)-1) {
3226
- if (!s->small && s->dealloc)
3227
- s->dealloc(s->data);
3228
- *s = FIO_STR_INIT;
3229
- return 0;
3230
- }
3231
- return -1;
3342
+ #ifndef FIO_STR_NO_REF
3343
+ if (!s || fio_atomic_sub(&s->ref, 1) != (uint32_t)-1)
3344
+ return -1;
3345
+ #endif
3346
+ if (!s->small && s->dealloc)
3347
+ s->dealloc(s->data);
3348
+ *s = FIO_STR_INIT;
3349
+ return 0;
3232
3350
  }
3233
3351
 
3234
3352
  /**
@@ -3323,7 +3441,7 @@ String Implementation - Memory management
3323
3441
  * since it uses 16 byte alignment right up until allocations are routed
3324
3442
  * directly to `mmap` (due to their size, usually over 12KB).
3325
3443
  */
3326
- #define ROUND_UP_CAPA_2WORDS(num) \
3444
+ #define ROUND_UP_CAPA2WORDS(num) \
3327
3445
  (((num + 1) & (sizeof(long double) - 1)) \
3328
3446
  ? ((num + 1) | (sizeof(long double) - 1)) \
3329
3447
  : (num))
@@ -3339,7 +3457,7 @@ FIO_FUNC fio_str_info_s fio_str_capa_assert(fio_str_s *s, size_t needed) {
3339
3457
  goto is_small;
3340
3458
  }
3341
3459
  if (needed > s->capa) {
3342
- needed = ROUND_UP_CAPA_2WORDS(needed);
3460
+ needed = ROUND_UP_CAPA2WORDS(needed);
3343
3461
  if (s->dealloc == fio_free) {
3344
3462
  tmp = (char *)fio_realloc2(s->data, needed + 1, s->len);
3345
3463
  FIO_ASSERT_ALLOC(tmp);
@@ -3364,7 +3482,7 @@ is_small:
3364
3482
  .len = (size_t)(s->small >> 1),
3365
3483
  .data = FIO_STR_SMALL_DATA(s)};
3366
3484
  }
3367
- needed = ROUND_UP_CAPA_2WORDS(needed);
3485
+ needed = ROUND_UP_CAPA2WORDS(needed);
3368
3486
  tmp = (char *)fio_malloc(needed + 1);
3369
3487
  FIO_ASSERT_ALLOC(tmp);
3370
3488
  const size_t existing_len = (size_t)((s->small >> 1) & 0xFF);
@@ -3373,6 +3491,15 @@ is_small:
3373
3491
  } else {
3374
3492
  tmp[0] = 0;
3375
3493
  }
3494
+ #ifdef FIO_STR_NO_REF
3495
+ *s = (fio_str_s){
3496
+ .small = 0,
3497
+ .capa = needed,
3498
+ .len = existing_len,
3499
+ .dealloc = fio_free,
3500
+ .data = tmp,
3501
+ };
3502
+ #else
3376
3503
  *s = (fio_str_s){
3377
3504
  .ref = s->ref,
3378
3505
  .small = 0,
@@ -3381,6 +3508,7 @@ is_small:
3381
3508
  .dealloc = fio_free,
3382
3509
  .data = tmp,
3383
3510
  };
3511
+ #endif
3384
3512
  return (fio_str_info_s){
3385
3513
  .capa = (s->frozen ? 0 : needed), .len = existing_len, .data = s->data};
3386
3514
  }
@@ -3845,11 +3973,9 @@ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
3845
3973
  const size_t org_len = fio_str_len(s);
3846
3974
  state = fio_str_resize(s, org_len + limit);
3847
3975
  if (pread(file, state.data + org_len, limit, start_at) != (ssize_t)limit) {
3848
- close(file);
3849
3976
  fio_str_resize(s, org_len);
3850
3977
  state.data = NULL;
3851
3978
  state.len = state.capa = 0;
3852
- goto finish;
3853
3979
  }
3854
3980
  close(file);
3855
3981
  finish:
@@ -3857,7 +3983,7 @@ finish:
3857
3983
  return state;
3858
3984
  #else
3859
3985
  /* TODO: consider adding non POSIX implementations. */
3860
- fprintf(stderr, "ERROR: File reading requires a posix system (ignored!).\n");
3986
+ FIO_LOG_ERROR("File reading requires a posix system (ignored!).\n");
3861
3987
  return state;
3862
3988
  #endif
3863
3989
  }
@@ -3901,8 +4027,9 @@ inline FIO_FUNC ssize_t fio_str_send_free2(const intptr_t uuid,
3901
4027
  .after.dealloc = (void (*)(void *))fio_str_free2);
3902
4028
  }
3903
4029
 
3904
- #undef ROUND_UP_CAPA_2WORDS
4030
+ #undef ROUND_UP_CAPA2WORDS
3905
4031
  #undef FIO_STR_SMALL_DATA
4032
+ #undef FIO_STR_NO_REF
3906
4033
 
3907
4034
  #endif /* H_FIO_STR_H */
3908
4035
  /* *****************************************************************************
@@ -4139,7 +4266,7 @@ FIO_FUNC void FIO_NAME(free)(FIO_NAME(s) * set);
4139
4266
  #ifdef FIO_SET_KEY_TYPE
4140
4267
 
4141
4268
  /**
4142
- *Locates an object in the Set, if it exists.
4269
+ * Locates an object in the Hash Map, if it exists.
4143
4270
  *
4144
4271
  * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4145
4272
  */
@@ -4148,13 +4275,15 @@ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4148
4275
  FIO_SET_KEY_TYPE key);
4149
4276
 
4150
4277
  /**
4151
- * Inserts an object to the Set only if it's missing, rehashing if required,
4152
- * returning the new (or old) object's pointer.
4278
+ * Inserts an object to the Hash Map, rehashing if required, returning the new
4279
+ * object's location using a pointer.
4153
4280
  *
4154
- * If the object already exists in the set, no action is performed (the old
4155
- * object is returned).
4281
+ * If an object already exists in the Hash Map with the same key, it will be
4282
+ * destroyed.
4156
4283
  *
4157
- * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4284
+ * NOTE 1: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4285
+ *
4286
+ * NOTE 2: This is equivelant to calling the `insert2` with `old` set to NULL.
4158
4287
  */
4159
4288
  FIO_FUNC inline void FIO_NAME(insert)(FIO_NAME(s) * set,
4160
4289
  const FIO_SET_HASH_TYPE hash_value,
@@ -4162,7 +4291,24 @@ FIO_FUNC inline void FIO_NAME(insert)(FIO_NAME(s) * set,
4162
4291
  FIO_SET_OBJ_TYPE obj);
4163
4292
 
4164
4293
  /**
4165
- * Removes an object from the Set, rehashing if required.
4294
+ * Inserts an object to the Hash Map, rehashing if required, returning the new
4295
+ * object's location using a pointer.
4296
+ *
4297
+ * If an object already exists in the Hash Map, it will be destroyed.
4298
+ *
4299
+ * If `old` is set, the existing object (if any) will be copied to the location
4300
+ * pointed to by `old` before it is destroyed.
4301
+ *
4302
+ * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4303
+ */
4304
+ FIO_FUNC inline void FIO_NAME(insert2)(FIO_NAME(s) * set,
4305
+ const FIO_SET_HASH_TYPE hash_value,
4306
+ FIO_SET_KEY_TYPE key,
4307
+ FIO_SET_OBJ_TYPE obj,
4308
+ FIO_SET_OBJ_TYPE *old);
4309
+
4310
+ /**
4311
+ * Removes an object from the Hash Map, rehashing if required.
4166
4312
  *
4167
4313
  * Returns 0 on success and -1 if the object wasn't found.
4168
4314
  *
@@ -4172,6 +4318,21 @@ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4172
4318
  const FIO_SET_HASH_TYPE hash_value,
4173
4319
  FIO_SET_KEY_TYPE key);
4174
4320
 
4321
+ /**
4322
+ * Removes an object from the Hash Map, rehashing if required.
4323
+ *
4324
+ * Returns 0 on success and -1 if the object wasn't found.
4325
+ *
4326
+ * If `old` is set, the existing object (if any) will be copied to the location
4327
+ * pointed to by `old`.
4328
+ *
4329
+ * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4330
+ */
4331
+ FIO_FUNC inline int FIO_NAME(remove2)(FIO_NAME(s) * set,
4332
+ const FIO_SET_HASH_TYPE hash_value,
4333
+ FIO_SET_KEY_TYPE key,
4334
+ FIO_SET_OBJ_TYPE *old);
4335
+
4175
4336
  #else
4176
4337
 
4177
4338
  /**
@@ -4210,6 +4371,17 @@ FIO_FUNC inline FIO_SET_OBJ_TYPE *
4210
4371
  FIO_NAME(overwrite)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4211
4372
  FIO_SET_OBJ_TYPE obj);
4212
4373
 
4374
+ /**
4375
+ * The same as `overwrite`, only it copies the old object (if any) to the
4376
+ * location pointed to by `old`.
4377
+ *
4378
+ * When setting `old` to NULL, the function behaves the same as `overwrite`.
4379
+ */
4380
+ FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(replace)(FIO_NAME(s) * set,
4381
+ const FIO_SET_HASH_TYPE hash_value,
4382
+ FIO_SET_OBJ_TYPE obj,
4383
+ FIO_SET_OBJ_TYPE *old);
4384
+
4213
4385
  /**
4214
4386
  * Removes an object from the Set, rehashing if required.
4215
4387
  *
@@ -4337,7 +4509,7 @@ FIO_FUNC inline FIO_NAME(_map_s_) *
4337
4509
  if (FIO_SET_HASH_COMPARE(FIO_SET_HASH_INVALID, pos->hash))
4338
4510
  return pos;
4339
4511
  if (FIO_SET_HASH_COMPARE(pos->hash, hash_value)) {
4340
- if (!pos->pos || FIO_SET_OBJ_COMPARE(pos->pos->obj, obj))
4512
+ if (!pos->pos || FIO_SET_COMPARE(pos->pos->obj, obj))
4341
4513
  return pos;
4342
4514
  set->has_collisions = 1;
4343
4515
  }
@@ -4353,7 +4525,7 @@ FIO_FUNC inline FIO_NAME(_map_s_) *
4353
4525
  if (FIO_SET_HASH_COMPARE(FIO_SET_HASH_INVALID, pos->hash))
4354
4526
  return pos;
4355
4527
  if (FIO_SET_HASH_COMPARE(pos->hash, hash_value)) {
4356
- if (!pos->pos || FIO_SET_OBJ_COMPARE(pos->pos->obj, obj))
4528
+ if (!pos->pos || FIO_SET_COMPARE(pos->pos->obj, obj))
4357
4529
  return pos;
4358
4530
  set->has_collisions = 1;
4359
4531
  }
@@ -4407,10 +4579,9 @@ FIO_FUNC inline void FIO_NAME(_reallocate_set_mem_)(FIO_NAME(s) * set) {
4407
4579
  * If the object already exists in the set, it will be destroyed and
4408
4580
  * overwritten.
4409
4581
  */
4410
- FIO_FUNC inline FIO_SET_TYPE *
4411
- FIO_NAME(_insert_or_overwrite_)(FIO_NAME(s) * set,
4412
- const FIO_SET_HASH_TYPE hash_value,
4413
- FIO_SET_TYPE obj, int overwrite) {
4582
+ FIO_FUNC inline FIO_SET_TYPE *FIO_NAME(_insert_or_overwrite_)(
4583
+ FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value, FIO_SET_TYPE obj,
4584
+ int overwrite, FIO_SET_OBJ_TYPE *old) {
4414
4585
  if (FIO_SET_HASH_COMPARE(hash_value, FIO_SET_HASH_INVALID))
4415
4586
  return NULL;
4416
4587
 
@@ -4435,11 +4606,17 @@ FIO_NAME(_insert_or_overwrite_)(FIO_NAME(s) * set,
4435
4606
  return &pos->pos->obj;
4436
4607
  }
4437
4608
  #ifdef FIO_SET_KEY_TYPE
4609
+ if (old) {
4610
+ FIO_SET_OBJ_COPY((*old), pos->pos->obj.obj);
4611
+ }
4438
4612
  /* no need to recreate the key object, just the value object */
4439
4613
  FIO_SET_OBJ_DESTROY(pos->pos->obj.obj);
4440
4614
  FIO_SET_OBJ_COPY(pos->pos->obj.obj, obj.obj);
4441
4615
  return &pos->pos->obj;
4442
4616
  #else
4617
+ if (old) {
4618
+ FIO_SET_COPY((*old), pos->pos->obj);
4619
+ }
4443
4620
  FIO_SET_DESTROY(pos->pos->obj);
4444
4621
  #endif
4445
4622
  } else {
@@ -4484,9 +4661,9 @@ FIO_FUNC void FIO_NAME(free)(FIO_NAME(s) * s) {
4484
4661
  *
4485
4662
  * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4486
4663
  */
4487
- FIO_FUNC inline FIO_SET_OBJ_TYPE *
4488
- FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4489
- FIO_SET_KEY_TYPE key) {
4664
+ FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(find)(FIO_NAME(s) * set,
4665
+ const FIO_SET_HASH_TYPE hash_value,
4666
+ FIO_SET_KEY_TYPE key) {
4490
4667
  FIO_NAME(_map_s_) *pos =
4491
4668
  FIO_NAME(_find_map_pos_)(set, hash_value, (FIO_SET_TYPE){.key = key});
4492
4669
  if (!pos || !pos->pos)
@@ -4495,28 +4672,86 @@ FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4495
4672
  }
4496
4673
 
4497
4674
  /**
4498
- * Inserts an object to the Set only if it's missing, rehashing if required,
4499
- * returning the new (or old) object's pointer.
4675
+ * Inserts an object to the Hash Map, rehashing if required, returning the new
4676
+ * object's location using a pointer.
4500
4677
  *
4501
- * If the object already exists in the set, no action is performed (the old
4502
- * object is returned).
4678
+ * If the object already exists in the set, it will be destroyed.
4503
4679
  *
4504
4680
  * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4505
4681
  */
4506
- FIO_FUNC inline void FIO_NAME(insert)(FIO_NAME(s) * set,
4682
+ FIO_FUNC void FIO_NAME(insert)(FIO_NAME(s) * set,
4683
+ const FIO_SET_HASH_TYPE hash_value,
4684
+ FIO_SET_KEY_TYPE key, FIO_SET_OBJ_TYPE obj) {
4685
+ FIO_NAME(_insert_or_overwrite_)
4686
+ (set, hash_value, (FIO_SET_TYPE){.key = key, .obj = obj}, 1, NULL);
4687
+ }
4688
+
4689
+ /**
4690
+ * Inserts an object to the Hash Map, rehashing if required, returning the new
4691
+ * object's location using a pointer.
4692
+ *
4693
+ * If an object already exists in the Hash Map, it will be destroyed.
4694
+ *
4695
+ * If `old` is set, the existing object (if any) will be copied to the location
4696
+ * pointed to by `old` before it is destroyed.
4697
+ *
4698
+ * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4699
+ */
4700
+ FIO_FUNC void FIO_NAME(insert2)(FIO_NAME(s) * set,
4701
+ const FIO_SET_HASH_TYPE hash_value,
4702
+ FIO_SET_KEY_TYPE key, FIO_SET_OBJ_TYPE obj,
4703
+ FIO_SET_OBJ_TYPE *old) {
4704
+ FIO_NAME(_insert_or_overwrite_)
4705
+ (set, hash_value, (FIO_SET_TYPE){.key = key, .obj = obj}, 1, old);
4706
+ }
4707
+
4708
+ /**
4709
+ * Removes an object from the Hash Map, rehashing if required.
4710
+ *
4711
+ * Returns 0 on success and -1 if the object wasn't found.
4712
+ *
4713
+ * If `old` is set, the existing object (if any) will be copied to the location
4714
+ * pointed to by `old`.
4715
+ *
4716
+ * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4717
+ */
4718
+ FIO_FUNC inline int FIO_NAME(remove2)(FIO_NAME(s) * set,
4507
4719
  const FIO_SET_HASH_TYPE hash_value,
4508
4720
  FIO_SET_KEY_TYPE key,
4509
- FIO_SET_OBJ_TYPE obj) {
4510
- FIO_NAME(_insert_or_overwrite_)
4511
- (set, hash_value, (FIO_SET_TYPE){.key = key, .obj = obj}, 1);
4721
+ FIO_SET_OBJ_TYPE *old) {
4722
+ if (FIO_SET_HASH_COMPARE(hash_value, FIO_SET_HASH_INVALID))
4723
+ return -1;
4724
+ FIO_NAME(_map_s_) *pos =
4725
+ FIO_NAME(_find_map_pos_)(set, hash_value, (FIO_SET_TYPE){.key = key});
4726
+ if (!pos || !pos->pos)
4727
+ return -1;
4728
+ if (old)
4729
+ FIO_SET_OBJ_COPY((*old), pos->pos->obj.obj);
4730
+ FIO_SET_DESTROY(pos->pos->obj);
4731
+ --set->count;
4732
+ pos->pos->hash = FIO_SET_HASH_INVALID;
4733
+ if (pos->pos == set->pos + set->ordered - 1) {
4734
+ do {
4735
+ --set->pos;
4736
+ } while (set->pos && FIO_SET_HASH_COMPARE(set->ordered[set->pos - 1].hash,
4737
+ FIO_SET_HASH_INVALID));
4738
+ }
4739
+ pos->pos = NULL; /* leave pos->hash set to mark "hole" */
4740
+ return 0;
4741
+ }
4742
+
4743
+ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4744
+ const FIO_SET_HASH_TYPE hash_value,
4745
+ FIO_SET_KEY_TYPE key) {
4746
+ return FIO_NAME(remove2)(set, hash_value, key, NULL);
4512
4747
  }
4513
4748
 
4514
4749
  #else
4515
4750
 
4516
4751
  /** Locates an object in the Set, if it exists. */
4517
- FIO_FUNC inline FIO_SET_OBJ_TYPE *
4518
- FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4519
- FIO_SET_OBJ_TYPE obj) {
4752
+ FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(find)(FIO_NAME(s) * set,
4753
+ const FIO_SET_HASH_TYPE hash_value,
4754
+ FIO_SET_OBJ_TYPE obj) {
4520
4755
  FIO_NAME(_map_s_) *pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
4521
4756
  if (!pos || !pos->pos)
4522
4757
  return NULL;
@@ -4530,10 +4765,10 @@ FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4530
4765
  * If the object already exists in the set, than the new object will be
4531
4766
  * destroyed and the old object's address will be returned.
4532
4767
  */
4533
- FIO_FUNC inline FIO_SET_OBJ_TYPE *
4534
- FIO_NAME(insert)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4535
- FIO_SET_OBJ_TYPE obj) {
4536
- return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 0);
4768
+ FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(insert)(FIO_NAME(s) * set,
4769
+ const FIO_SET_HASH_TYPE hash_value,
4770
+ FIO_SET_OBJ_TYPE obj) {
4771
+ return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 0, NULL);
4537
4772
  }
4538
4773
 
4539
4774
  /**
@@ -4543,35 +4778,34 @@ FIO_NAME(insert)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4543
4778
  * If the object already exists in the set, it will be destroyed and
4544
4779
  * overwritten.
4545
4780
  */
4546
- FIO_FUNC inline FIO_SET_OBJ_TYPE *
4781
+ FIO_FUNC FIO_SET_OBJ_TYPE *
4547
4782
  FIO_NAME(overwrite)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4548
4783
  FIO_SET_OBJ_TYPE obj) {
4549
- return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 1);
4784
+ return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 1, NULL);
4550
4785
  }
4551
4786
 
4552
- #endif
4787
+ /**
4788
+ * The same as `overwrite`, only it copies the old object (if any) to the
4789
+ * location pointed to by `old`.
4790
+ *
4791
+ * When setting `old` to NULL, the function behaves the same as `overwrite`.
4792
+ */
4793
+ FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(replace)(FIO_NAME(s) * set,
4794
+ const FIO_SET_HASH_TYPE hash_value,
4795
+ FIO_SET_OBJ_TYPE obj,
4796
+ FIO_SET_OBJ_TYPE *old) {
4797
+ return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 1, old);
4798
+ }
4553
4799
 
4554
4800
  /**
4555
4801
  * Removes an object from the Set, rehashing if required.
4556
4802
  */
4557
- #ifdef FIO_SET_KEY_TYPE
4558
-
4559
- FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4560
- const FIO_SET_HASH_TYPE hash_value,
4561
- FIO_SET_KEY_TYPE key) {
4562
- #else
4563
- FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4564
- const FIO_SET_HASH_TYPE hash_value,
4565
- FIO_SET_OBJ_TYPE obj) {
4566
- #endif
4803
+ FIO_FUNC int FIO_NAME(remove)(FIO_NAME(s) * set,
4804
+ const FIO_SET_HASH_TYPE hash_value,
4805
+ FIO_SET_OBJ_TYPE obj) {
4567
4806
  if (FIO_SET_HASH_COMPARE(hash_value, FIO_SET_HASH_INVALID))
4568
4807
  return -1;
4569
- #ifdef FIO_SET_KEY_TYPE
4570
- FIO_NAME(_map_s_) *pos =
4571
- FIO_NAME(_find_map_pos_)(set, hash_value, (FIO_SET_TYPE){.key = key});
4572
- #else
4573
4808
  FIO_NAME(_map_s_) *pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
4574
- #endif
4575
4809
  if (!pos || !pos->pos)
4576
4810
  return -1;
4577
4811
  FIO_SET_DESTROY(pos->pos->obj);
@@ -4587,6 +4821,8 @@ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4587
4821
  return 0;
4588
4822
  }
4589
4823
 
4824
+ #endif
4825
+
4590
4826
  /**
4591
4827
  * Allows a peak at the Set's last element.
4592
4828
  *
@@ -4638,7 +4874,7 @@ FIO_FUNC inline size_t FIO_NAME(capa_require)(FIO_NAME(s) * set,
4638
4874
  if (min_capa <= FIO_NAME(capa)(set))
4639
4875
  return FIO_NAME(capa)(set);
4640
4876
  set->mask = 1;
4641
- while (min_capa >= set->mask) {
4877
+ while (min_capa > set->mask) {
4642
4878
  set->mask = (set->mask << 1) | 1;
4643
4879
  }
4644
4880
  FIO_NAME(rehash)(set);