iodine 0.7.3 → 0.7.4

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.

@@ -4,6 +4,7 @@ License: MIT
4
4
 
5
5
  Feel free to copy, use and enjoy according to the license provided.
6
6
  */
7
+
7
8
  #ifndef H_FACIL_IO_H
8
9
  /**
9
10
  "facil.h" is the main header for the facil.io server platform.
@@ -79,6 +80,17 @@ Feel free to copy, use and enjoy according to the license provided.
79
80
  *
80
81
  *
81
82
  *
83
+ * #ifdef FIO_ARY_NAME - can be included more than once
84
+ *
85
+ * Dynamic Array Data-Store
86
+ * Array API
87
+ * Array Type
88
+ * Array Memory Management
89
+ * Array API implementation
90
+ * Array Testing
91
+ *
92
+ *
93
+ *
82
94
  * #ifdef FIO_SET_NAME - can be included more than once
83
95
  *
84
96
  * Set / Hash Map Data-Store
@@ -307,17 +319,6 @@ void *fio_mmap(size_t size);
307
319
  */
308
320
  void fio_malloc_after_fork(void);
309
321
 
310
- #if FIO_FORCE_MALLOC
311
- #define fio_malloc(size) calloc(size, 1)
312
- #define fio_calloc calloc
313
- #define fio_mmap(size) calloc(size, 1)
314
- #define fio_free free
315
- #define fio_realloc realloc
316
- #define fio_realloc2(ptr, new_size, old_data_len) realloc((ptr), (new_size))
317
- #define fio_malloc_test()
318
- #define fio_malloc_after_fork()
319
- #endif
320
-
321
322
  /* *****************************************************************************
322
323
 
323
324
 
@@ -370,16 +371,16 @@ extern size_t FIO_LOG_LEVEL;
370
371
  } while (0)
371
372
  #define FIO_LOG_DEBUG(...) \
372
373
  FIO_LOG_PRINT(FIO_LOG_LEVEL_DEBUG, \
373
- "[DEBUG ("__FILE__ \
374
- ":" FIO_MACRO2STR(__LINE__) ")] " __VA_ARGS__)
374
+ "DEBUG ("__FILE__ \
375
+ ":" FIO_MACRO2STR(__LINE__) "): " __VA_ARGS__)
375
376
  #define FIO_LOG_INFO(...) \
376
- FIO_LOG_PRINT(FIO_LOG_LEVEL_INFO, "[INFO] " __VA_ARGS__)
377
+ FIO_LOG_PRINT(FIO_LOG_LEVEL_INFO, "INFO: " __VA_ARGS__)
377
378
  #define FIO_LOG_WARNING(...) \
378
- FIO_LOG_PRINT(FIO_LOG_LEVEL_WARNING, "[WARNING] " __VA_ARGS__)
379
+ FIO_LOG_PRINT(FIO_LOG_LEVEL_WARNING, "WARNING: " __VA_ARGS__)
379
380
  #define FIO_LOG_ERROR(...) \
380
- FIO_LOG_PRINT(FIO_LOG_LEVEL_ERROR, "[ERROR] " __VA_ARGS__)
381
+ FIO_LOG_PRINT(FIO_LOG_LEVEL_ERROR, "ERROR: " __VA_ARGS__)
381
382
  #define FIO_LOG_FATAL(...) \
382
- FIO_LOG_PRINT(FIO_LOG_LEVEL_FATAL, "[FATAL] " __VA_ARGS__)
383
+ FIO_LOG_PRINT(FIO_LOG_LEVEL_FATAL, "FATAL: " __VA_ARGS__)
383
384
  #endif
384
385
 
385
386
  #if FIO_PRINT_STATE
@@ -402,9 +403,8 @@ extern size_t FIO_LOG_LEVEL;
402
403
  /** Tests for an allocation failure. The behavior can be overridden. */
403
404
  #define FIO_ASSERT_ALLOC(ptr) \
404
405
  if (!(ptr)) { \
405
- fprintf(stderr, "\nFATAL ERROR: memory allocation error "__FILE__ \
406
- ":" FIO_MACRO2STR(__LINE__) "\n"); \
407
- perror(" Error details (errno)"); \
406
+ FIO_LOG_FATAL("memory allocation error "__FILE__ \
407
+ ":" FIO_MACRO2STR(__LINE__)); \
408
408
  kill(0, SIGINT); \
409
409
  exit(errno); \
410
410
  }
@@ -3542,13 +3542,13 @@ String Implementation - UTF-8 State
3542
3542
  ***************************************************************************** */
3543
3543
 
3544
3544
  /**
3545
- * Maps the last 5 bits in a byte (0b11111xxx) to a UTF-8 codepoint length.
3545
+ * Maps the first 5 bits in a byte (0b11111xxx) to a UTF-8 codepoint length.
3546
3546
  *
3547
3547
  * Codepoint length 0 == error.
3548
3548
  *
3549
3549
  * The first valid length can be any value between 1 to 4.
3550
3550
  *
3551
- * An intermidiate (second, third or forth) valid length must be 5.
3551
+ * A continuation byte (second, third or forth) valid length must be 5.
3552
3552
  *
3553
3553
  * To map was populated using the following Ruby script:
3554
3554
  *
@@ -4031,6 +4031,804 @@ inline FIO_FUNC ssize_t fio_str_send_free2(const intptr_t uuid,
4031
4031
  #undef FIO_STR_NO_REF
4032
4032
 
4033
4033
  #endif /* H_FIO_STR_H */
4034
+
4035
+ /* *****************************************************************************
4036
+
4037
+
4038
+
4039
+
4040
+
4041
+
4042
+
4043
+
4044
+
4045
+
4046
+
4047
+ Dynamic Array Data-Store
4048
+
4049
+
4050
+
4051
+
4052
+
4053
+
4054
+
4055
+
4056
+
4057
+
4058
+
4059
+ ***************************************************************************** */
4060
+
4061
+ #ifdef FIO_ARY_NAME
4062
+ /**
4063
+ * A simple typed dynamic array with a minimal API.
4064
+ *
4065
+ * To create an Array type, define the macro FIO_ARY_NAME. i.e.:
4066
+ *
4067
+ * #define FIO_ARY_NAME fio_cstr_ary
4068
+ * #define FIO_ARY_TYPE char *
4069
+ * #define FIO_ARY_COMPARE(k1, k2) (!strcmp((k1), (k2)))
4070
+ * #include <fio.h>
4071
+ *
4072
+ * It's possible to create a number of Array types by reincluding the fio.h
4073
+ * header. i.e.:
4074
+ *
4075
+ *
4076
+ * #define FIO_INCLUDE_STR
4077
+ * #include <fio.h> // adds the fio_str_s types and functions
4078
+ *
4079
+ * #define FIO_ARY_NAME fio_int_ary
4080
+ * #define FIO_ARY_TYPE int
4081
+ * #include <fio.h> // creates the fio_int_ary_s Array and functions
4082
+ *
4083
+ * #define FIO_ARY_NAME fio_str_ary
4084
+ * #define FIO_ARY_TYPE fio_str_s *
4085
+ * #define FIO_ARY_COMPARE(k1, k2) (fio_str_iseq((k1), (k2)))
4086
+ * #define FIO_ARY_COPY(key) fio_str_dup((key))
4087
+ * #define FIO_ARY_DESTROY(key) fio_str_free2((key))
4088
+ * #include <fio.h> // creates the fio_str_ary_s Array and functions
4089
+ *
4090
+ * Note: Before freeing the Array, FIO_ARY_DESTROY will be automatically called
4091
+ * for every existing object, including any invalid objects (if any).
4092
+ */
4093
+
4094
+ /* Used for naming functions and types, prefixing FIO_ARY_NAME to the name */
4095
+ #define FIO_NAME_FROM_MACRO_STEP2(name, postfix) name##_##postfix
4096
+ #define FIO_NAME_FROM_MACRO_STEP1(name, postfix) \
4097
+ FIO_NAME_FROM_MACRO_STEP2(name, postfix)
4098
+ #define FIO_NAME(postfix) FIO_NAME_FROM_MACRO_STEP1(FIO_ARY_NAME, postfix)
4099
+
4100
+ /* Used for naming the `free` function */
4101
+ #define FIO_NAME_FROM_MACRO_STEP4(name) name##_free
4102
+ #define FIO_NAME_FROM_MACRO_STEP3(name) FIO_NAME_FROM_MACRO_STEP4(name)
4103
+ #define FIO_NAME_FREE() FIO_NAME_FROM_MACRO_STEP3(FIO_ARY_NAME)
4104
+
4105
+ /* The default Array object type is `void *` */
4106
+ #if !defined(FIO_ARY_TYPE)
4107
+ #define FIO_ARY_TYPE void *
4108
+ #endif
4109
+
4110
+ /* An invalid object has all bytes set to 0 - a static constant will do. */
4111
+ #if !defined(FIO_ARY_INVALID)
4112
+ static FIO_ARY_TYPE const FIO_NAME(s___const_invalid_object);
4113
+ #define FIO_ARY_INVALID FIO_NAME(s___const_invalid_object)
4114
+ #endif
4115
+
4116
+ /* The default Array comparison assumes a simple type */
4117
+ #if !defined(FIO_ARY_COMPARE)
4118
+ #define FIO_ARY_COMPARE(o1, o2) ((o1) == (o2))
4119
+ #endif
4120
+
4121
+ /** object copy required? */
4122
+ #ifndef FIO_ARY_COPY
4123
+ #define FIO_ARY_COPY(dest, obj) ((dest) = (obj))
4124
+ #endif
4125
+
4126
+ /** object destruction required? */
4127
+ #ifndef FIO_ARY_DESTROY
4128
+ #define FIO_ARY_DESTROY(obj) ((void)0)
4129
+ #endif
4130
+
4131
+ /* Customizable memory management */
4132
+ #ifndef FIO_ARY_MALLOC /* NULL ptr indicates new allocation */
4133
+ #define FIO_ARY_MALLOC(size) fio_malloc((size))
4134
+ #endif
4135
+
4136
+ /* Customizable memory management */
4137
+ #ifndef FIO_ARY_REALLOC /* NULL ptr indicates new allocation */
4138
+ #define FIO_ARY_REALLOC(ptr, original_size, new_size, valid_data_length) \
4139
+ fio_realloc2((ptr), (new_size), (valid_data_length))
4140
+ #endif
4141
+
4142
+ #ifndef FIO_ARY_DEALLOC
4143
+ #define FIO_ARY_DEALLOC(ptr, size) fio_free((ptr))
4144
+ #endif
4145
+
4146
+ /* padding to be assumed for future expansion. */
4147
+ #ifndef FIO_ARY_PADDING
4148
+ #define FIO_ARY_PADDING 4
4149
+ #endif
4150
+
4151
+ /* minimizes allocation "dead space" by alligning allocated length to 16bytes */
4152
+ #undef FIO_ARY_SIZE2WORDS
4153
+ #define FIO_ARY_SIZE2WORDS(size) \
4154
+ ((sizeof(FIO_ARY_TYPE) & 15) ? (((size) & ~(sizeof(FIO_ARY_TYPE) - 1)) + \
4155
+ (16 - (sizeof(FIO_ARY_TYPE) - 1))) \
4156
+ : (size))
4157
+
4158
+ /* *****************************************************************************
4159
+ Array API
4160
+ ***************************************************************************** */
4161
+
4162
+ /** The Array container type. */
4163
+ typedef struct FIO_NAME(s) FIO_NAME(s);
4164
+
4165
+ #ifndef FIO_ARY_INIT
4166
+ /** Initializes the Array */
4167
+ #define FIO_ARY_INIT \
4168
+ { .capa = 0 }
4169
+ #endif
4170
+
4171
+ /** Frees the array's internal data. */
4172
+ FIO_FUNC inline void FIO_NAME_FREE()(FIO_NAME(s) * ary);
4173
+
4174
+ /** Returns the number of elements in the Array. */
4175
+ FIO_FUNC inline size_t FIO_NAME(count)(FIO_NAME(s) * ary);
4176
+
4177
+ /** Returns the current, temporary, array capacity (it's dynamic). */
4178
+ FIO_FUNC inline size_t FIO_NAME(capa)(FIO_NAME(s) * ary);
4179
+
4180
+ /**
4181
+ * Adds all the items in the `src` Array to the end of the `dest` Array.
4182
+ *
4183
+ * The `src` Array remain untouched.
4184
+ */
4185
+ FIO_FUNC inline void FIO_NAME(concat)(FIO_NAME(s) * dest, FIO_NAME(s) * src);
4186
+
4187
+ /**
4188
+ * Sets `index` to the value in `data`.
4189
+ *
4190
+ * If `index` is negative, it will be counted from the end of the Array (-1 ==
4191
+ * last element).
4192
+ *
4193
+ * If `old` isn't NULL, the existing data will be copied to the location pointed
4194
+ * to by `old` before the copy in the Array is destroyed.
4195
+ */
4196
+ FIO_FUNC inline void FIO_NAME(set)(FIO_NAME(s) * ary, intptr_t index,
4197
+ FIO_ARY_TYPE data, FIO_ARY_TYPE *old);
4198
+
4199
+ /**
4200
+ * Returns the value located at `index` (no copying is peformed).
4201
+ *
4202
+ * If `index` is negative, it will be counted from the end of the Array (-1 ==
4203
+ * last element).
4204
+ */
4205
+ FIO_FUNC inline FIO_ARY_TYPE FIO_NAME(get)(FIO_NAME(s) * ary, intptr_t index);
4206
+
4207
+ /**
4208
+ * Returns the index of the object or -1 if the object wasn't found.
4209
+ */
4210
+ FIO_FUNC inline intptr_t FIO_NAME(find)(FIO_NAME(s) * ary, FIO_ARY_TYPE data);
4211
+
4212
+ /**
4213
+ * Removes an object from the array, MOVING all the other objects to prevent
4214
+ * "holes" in the data.
4215
+ *
4216
+ * If `old` is set, the data is copied to the location pointed to by `old`
4217
+ * before the data in the array is destroyed.
4218
+ *
4219
+ * Returns 0 on success and -1 on error.
4220
+ */
4221
+ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * ary, intptr_t index,
4222
+ FIO_ARY_TYPE *old);
4223
+
4224
+ /**
4225
+ * Removes an object from the array, if it exists, MOVING all the other objects
4226
+ * to prevent "holes" in the data.
4227
+ *
4228
+ * Returns -1 if the object wasn't found or 0 if the object was successfully
4229
+ * removed.
4230
+ */
4231
+ FIO_FUNC inline int FIO_NAME(remove2)(FIO_NAME(s) * ary, FIO_ARY_TYPE data,
4232
+ FIO_ARY_TYPE *old);
4233
+
4234
+ /**
4235
+ * Returns a pointer to the C array containing the objects.
4236
+ */
4237
+ FIO_FUNC inline FIO_ARY_TYPE *FIO_NAME(to_a)(FIO_NAME(s) * ary);
4238
+
4239
+ /**
4240
+ * Pushes an object to the end of the Array. Returns -1 on error.
4241
+ */
4242
+ FIO_FUNC inline int FIO_NAME(push)(FIO_NAME(s) * ary, FIO_ARY_TYPE data);
4243
+
4244
+ /**
4245
+ * Removes an object from the end of the Array.
4246
+ *
4247
+ * If `old` is set, the data is copied to the location pointed to by `old`
4248
+ * before the data in the array is destroyed.
4249
+ *
4250
+ * Returns -1 on error (Array is empty) and 0 on success.
4251
+ */
4252
+ FIO_FUNC inline int FIO_NAME(pop)(FIO_NAME(s) * ary, FIO_ARY_TYPE *old);
4253
+
4254
+ /**
4255
+ * Unshifts an object to the beginning of the Array. Returns -1 on error.
4256
+ *
4257
+ * This could be expensive, causing `memmove`.
4258
+ */
4259
+ FIO_FUNC inline int FIO_NAME(unshift)(FIO_NAME(s) * ary, FIO_ARY_TYPE data);
4260
+
4261
+ /**
4262
+ * Removes an object from the beginning of the Array.
4263
+ *
4264
+ * If `old` is set, the data is copied to the location pointed to by `old`
4265
+ * before the data in the array is destroyed.
4266
+ *
4267
+ * Returns -1 on error (Array is empty) and 0 on success.
4268
+ */
4269
+ FIO_FUNC inline int FIO_NAME(shift)(FIO_NAME(s) * ary, FIO_ARY_TYPE *old);
4270
+
4271
+ /**
4272
+ * Iteration using a callback for each entry in the array.
4273
+ *
4274
+ * The callback task function must accept an the entry data as well as an opaque
4275
+ * user pointer.
4276
+ *
4277
+ * If the callback returns -1, the loop is broken. Any other value is ignored.
4278
+ *
4279
+ * Returns the relative "stop" position, i.e., the number of items processed +
4280
+ * the starting point.
4281
+ */
4282
+ FIO_FUNC inline size_t FIO_NAME(each)(FIO_NAME(s) * ary, size_t start_at,
4283
+ int (*task)(FIO_ARY_TYPE pt, void *arg),
4284
+ void *arg);
4285
+ /**
4286
+ * Removes any FIO_ARY_TYPE_INVALID object from an Array (NULL pointers by
4287
+ * default), keeping all other data in the array.
4288
+ *
4289
+ * This action is O(n) where n in the length of the array.
4290
+ * It could get expensive.
4291
+ */
4292
+ FIO_FUNC inline void FIO_NAME(compact)(FIO_NAME(s) * ary);
4293
+
4294
+ /**
4295
+ * Iterates through the list using a `for` loop.
4296
+ *
4297
+ * Access the object with the pointer `pos`. The `pos` variable can be named
4298
+ * however you please.
4299
+ *
4300
+ * Avoid editing the array during a FOR loop, although I hope it's possible, I
4301
+ * wouldn't count on it.
4302
+ */
4303
+ #ifndef FIO_ARY_FOR
4304
+ #define FIO_ARY_FOR(ary, pos) \
4305
+ if ((ary)->arry) \
4306
+ for (__typeof__((ary)->arry) start__tmp__ = (ary)->arry, \
4307
+ pos = ((ary)->arry + (ary)->start); \
4308
+ pos < (ary)->arry + (ary)->end; \
4309
+ (pos = (ary)->arry + (pos - start__tmp__) + 1), \
4310
+ (start__tmp__ = (ary)->arry))
4311
+ #endif
4312
+
4313
+ /* *****************************************************************************
4314
+ Array Type
4315
+ ***************************************************************************** */
4316
+
4317
+ struct FIO_NAME(s) {
4318
+ size_t start; /* first index where data was already written */
4319
+ size_t end; /* next spot to write at tail */
4320
+ size_t capa; /* existing capacity */
4321
+ FIO_ARY_TYPE *arry; /* the actual array's memory, if any */
4322
+ };
4323
+
4324
+ /* *****************************************************************************
4325
+ Array Memory Management
4326
+ ***************************************************************************** */
4327
+
4328
+ FIO_FUNC inline void FIO_NAME_FREE()(FIO_NAME(s) * ary) {
4329
+ if (ary) {
4330
+ const size_t count = ary->end;
4331
+ for (size_t i = ary->start; i < count; ++i) {
4332
+ FIO_ARY_DESTROY((ary->arry[i]));
4333
+ }
4334
+ FIO_ARY_DEALLOC(ary->arry, ary->capa * sizeof(*ary->arry));
4335
+ *ary = (FIO_NAME(s))FIO_ARY_INIT;
4336
+ }
4337
+ }
4338
+
4339
+ /** Converts between a relative index to an absolute index. */
4340
+ FIO_FUNC inline intptr_t FIO_NAME(__rel2absolute)(FIO_NAME(s) * ary,
4341
+ intptr_t index) {
4342
+ if (index >= 0)
4343
+ return index;
4344
+ index += ary->end - ary->start;
4345
+ if (index >= 0)
4346
+ return index;
4347
+ return 0;
4348
+ }
4349
+
4350
+ /** Makes sure that `len` positions are available at the Array's end. */
4351
+ FIO_FUNC void FIO_NAME(__require_on_top)(FIO_NAME(s) * ary, size_t len) {
4352
+ if (ary->end + len < ary->capa)
4353
+ return;
4354
+ len = FIO_ARY_SIZE2WORDS(len + ary->end);
4355
+ /* reallocate enough memory */
4356
+ ary->arry = FIO_ARY_REALLOC(ary->arry, sizeof(*ary->arry) * ary->capa,
4357
+ (len) * sizeof(*ary->arry),
4358
+ ary->end * sizeof(*ary->arry));
4359
+ FIO_ASSERT_ALLOC(ary->arry);
4360
+ ary->capa = len + 1;
4361
+ }
4362
+
4363
+ /** Makes sure that `len` positions are available at the Array's head. */
4364
+ FIO_FUNC void FIO_NAME(__require_on_bottom)(FIO_NAME(s) * ary, size_t len) {
4365
+ if (ary->start >= len)
4366
+ return;
4367
+ FIO_ARY_TYPE *tmp = ary->arry;
4368
+ len = FIO_ARY_SIZE2WORDS((len - ary->start) + ary->end);
4369
+ if (ary->capa <= len) {
4370
+ /* no room - allocate and copy */
4371
+ ary->arry = FIO_ARY_MALLOC(len * sizeof(*ary->arry));
4372
+ FIO_ASSERT_ALLOC(ary->arry);
4373
+ ary->capa = len;
4374
+ }
4375
+ /* move existing data to the end of the existing space */
4376
+ len = ary->end - ary->start;
4377
+ ary->end = ary->capa;
4378
+ if (len)
4379
+ memmove(ary->arry + (ary->capa - len), tmp + ary->start,
4380
+ len * sizeof(*ary->arry));
4381
+ ary->start = ary->end - len;
4382
+ if (tmp != ary->arry) {
4383
+ fio_free(tmp);
4384
+ }
4385
+ }
4386
+
4387
+ /* *****************************************************************************
4388
+ Array API implementation
4389
+ ***************************************************************************** */
4390
+
4391
+ /** Returns the number of elements in the Array. */
4392
+ FIO_FUNC inline size_t FIO_NAME(count)(FIO_NAME(s) * ary) {
4393
+ return ary ? (ary->end - ary->start) : 0;
4394
+ }
4395
+
4396
+ /** Returns the current, temporary, array capacity (it's dynamic). */
4397
+ FIO_FUNC inline size_t FIO_NAME(capa)(FIO_NAME(s) * ary) {
4398
+ return ary ? ary->capa : 0;
4399
+ }
4400
+
4401
+ /**
4402
+ * Returns a pointer to the C array containing the objects.
4403
+ */
4404
+ FIO_FUNC inline FIO_ARY_TYPE *FIO_NAME(to_a)(FIO_NAME(s) * ary) {
4405
+ return ary ? (ary->arry + ary->start) : NULL;
4406
+ }
4407
+
4408
+ /**
4409
+ * Adds all the items in the `src` Array to the end of the `dest` Array.
4410
+ *
4411
+ * The `src` Array remain untouched.
4412
+ */
4413
+ FIO_FUNC inline void FIO_NAME(concat)(FIO_NAME(s) * dest, FIO_NAME(s) * src) {
4414
+ const size_t added = FIO_NAME(count)(src);
4415
+ if (!added || !dest)
4416
+ return;
4417
+ FIO_NAME(__require_on_top)(dest, added);
4418
+ /* don't use memcpy, in case copying has side-effects (see macro) */
4419
+ for (size_t i = 0; i < added; ++i) {
4420
+ FIO_ARY_COPY(((dest->arry + dest->end)[i]), ((src->arry + src->start)[i]));
4421
+ }
4422
+ dest->end += added;
4423
+ }
4424
+
4425
+ /**
4426
+ * Sets `index` to the value in `data`.
4427
+ *
4428
+ * If `index` is negative, it will be counted from the end of the Array (-1 ==
4429
+ * last element).
4430
+ *
4431
+ * If `old` isn't NULL, the existing data will be copied to the location pointed
4432
+ * to by `old` before the copy in the Array is destroyed.
4433
+ */
4434
+ FIO_FUNC inline void FIO_NAME(set)(FIO_NAME(s) * ary, intptr_t index,
4435
+ FIO_ARY_TYPE data, FIO_ARY_TYPE *old) {
4436
+ if (!ary)
4437
+ return;
4438
+ if (ary->start == ary->end) /* reset memory starting point? */
4439
+ ary->start = ary->end = 0;
4440
+
4441
+ index = FIO_NAME(__rel2absolute)(ary, index);
4442
+
4443
+ const intptr_t spaces = index - (ary->end - ary->start);
4444
+ if (spaces < 0) {
4445
+ /* likely */
4446
+ if (old)
4447
+ FIO_ARY_COPY((*old), ((ary->arry + ary->start)[index]));
4448
+ FIO_ARY_DESTROY(((ary->arry + ary->start)[index]));
4449
+ FIO_ARY_COPY(((ary->arry + ary->start)[index]), data);
4450
+ return;
4451
+ }
4452
+
4453
+ /* fill empty spaces with zero */
4454
+ FIO_NAME(__require_on_top)(ary, spaces + 1);
4455
+ if (spaces) {
4456
+ memset(ary->arry + ary->end, 0, sizeof(*ary->arry) * spaces);
4457
+ }
4458
+ FIO_ARY_COPY(((ary->arry + ary->start)[index]), data);
4459
+ ary->end = index + 1;
4460
+ }
4461
+
4462
+ /**
4463
+ * Returns the value located at `index` (no copying is peformed).
4464
+ *
4465
+ * If `index` is negative, it will be counted from the end of the Array (-1 ==
4466
+ * last element).
4467
+ */
4468
+ FIO_FUNC inline FIO_ARY_TYPE FIO_NAME(get)(FIO_NAME(s) * ary, intptr_t index) {
4469
+ if (!ary)
4470
+ return FIO_ARY_INVALID;
4471
+ index = FIO_NAME(__rel2absolute)(ary, index);
4472
+ if ((size_t)index >= ary->end - ary->start)
4473
+ return FIO_ARY_INVALID;
4474
+ return (ary->arry + ary->start)[index];
4475
+ }
4476
+
4477
+ /**
4478
+ * Returns the index of the object or -1 if the object wasn't found.
4479
+ */
4480
+ FIO_FUNC inline intptr_t FIO_NAME(find)(FIO_NAME(s) * ary, FIO_ARY_TYPE data) {
4481
+ const size_t count = FIO_NAME(count)(ary);
4482
+ if (!count) {
4483
+ return -1;
4484
+ }
4485
+ size_t pos = ary->start;
4486
+ register const size_t end = ary->end;
4487
+ while (pos < end && !FIO_ARY_COMPARE(data, ary->arry[pos])) {
4488
+ ++pos;
4489
+ }
4490
+ if (pos == end)
4491
+ return -1;
4492
+ return (pos - ary->start);
4493
+ }
4494
+
4495
+ /**
4496
+ * Removes an object from the array, MOVING all the other objects to prevent
4497
+ * "holes" in the data.
4498
+ *
4499
+ * If `old` is set, the data is copied to the location pointed to by `old`
4500
+ * before the data in the array is destroyed.
4501
+ *
4502
+ * Returns 0 on success and -1 on error.
4503
+ */
4504
+ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * ary, intptr_t index,
4505
+ FIO_ARY_TYPE *old) {
4506
+ index = FIO_NAME(__rel2absolute)(ary, index);
4507
+ const size_t count = FIO_NAME(count)(ary);
4508
+ if (!count || (size_t)index >= count) {
4509
+ return -1;
4510
+ }
4511
+ index += ary->start;
4512
+ if (old)
4513
+ FIO_ARY_COPY((*old), (ary->arry[index]));
4514
+ FIO_ARY_DESTROY((ary->arry[index]));
4515
+ if ((size_t)index == ary->start) {
4516
+ ++ary->start;
4517
+ return 0;
4518
+ }
4519
+ --ary->end;
4520
+ if ((size_t)index < ary->end) {
4521
+ memmove(ary->arry + index, ary->arry + index + 1,
4522
+ (ary->end - index) * sizeof(*ary->arry));
4523
+ }
4524
+ return 0;
4525
+ }
4526
+
4527
+ /**
4528
+ * Removes an object from the array, if it exists, MOVING all the other objects
4529
+ * to prevent "holes" in the data.
4530
+ *
4531
+ * Returns -1 if the object wasn't found or 0 if the object was successfully
4532
+ * removed.
4533
+ */
4534
+ FIO_FUNC inline int FIO_NAME(remove2)(FIO_NAME(s) * ary, FIO_ARY_TYPE data,
4535
+ FIO_ARY_TYPE *old) {
4536
+ intptr_t index = FIO_NAME(find)(ary, data);
4537
+ if (index == -1) {
4538
+ return -1;
4539
+ }
4540
+ return FIO_NAME(remove)(ary, index, old);
4541
+ }
4542
+
4543
+ /**
4544
+ * Pushes an object to the end of the Array. Returns -1 on error.
4545
+ */
4546
+ FIO_FUNC inline int FIO_NAME(push)(FIO_NAME(s) * ary, FIO_ARY_TYPE data) {
4547
+ if (!ary)
4548
+ return -1;
4549
+ if (ary->capa <= ary->end)
4550
+ FIO_NAME(__require_on_top)(ary, 1 + FIO_ARY_PADDING);
4551
+ if (ary->start == ary->end) /* reset memory starting point? */
4552
+ ary->start = ary->end = 0;
4553
+ FIO_ARY_COPY(ary->arry[ary->end], data);
4554
+ ++ary->end;
4555
+ return 0;
4556
+ }
4557
+
4558
+ /**
4559
+ * Removes an object from the end of the Array.
4560
+ *
4561
+ * If `old` is set, the data is copied to the location pointed to by `old`
4562
+ * before the data in the array is destroyed.
4563
+ *
4564
+ * Returns -1 on error (Array is empty) and 0 on success.
4565
+ */
4566
+ FIO_FUNC inline int FIO_NAME(pop)(FIO_NAME(s) * ary, FIO_ARY_TYPE *old) {
4567
+ if (!FIO_NAME(count)(ary))
4568
+ return -1;
4569
+ --ary->end;
4570
+ if (old)
4571
+ FIO_ARY_COPY((*old), (ary->arry[ary->end]));
4572
+ FIO_ARY_DESTROY((ary->arry[ary->end]));
4573
+ return 0;
4574
+ }
4575
+
4576
+ /**
4577
+ * Unshifts an object to the beginning of the Array. Returns -1 on error.
4578
+ *
4579
+ * This could be expensive, causing `memmove`.
4580
+ */
4581
+ FIO_FUNC inline int FIO_NAME(unshift)(FIO_NAME(s) * ary, FIO_ARY_TYPE data) {
4582
+ if (!ary)
4583
+ return -1;
4584
+ if (ary->start == 0)
4585
+ FIO_NAME(__require_on_bottom)(ary, 8);
4586
+ --ary->start;
4587
+ FIO_ARY_COPY(ary->arry[ary->start], data);
4588
+ return 0;
4589
+ }
4590
+
4591
+ /**
4592
+ * Removes an object from the beginning of the Array.
4593
+ *
4594
+ * If `old` is set, the data is copied to the location pointed to by `old`
4595
+ * before the data in the array is destroyed.
4596
+ *
4597
+ * Returns -1 on error (Array is empty) and 0 on success.
4598
+ */
4599
+ FIO_FUNC inline int FIO_NAME(shift)(FIO_NAME(s) * ary, FIO_ARY_TYPE *old) {
4600
+ if (!FIO_NAME(count)(ary))
4601
+ return -1;
4602
+ if (old)
4603
+ FIO_ARY_COPY((*old), (ary->arry[ary->start]));
4604
+ FIO_ARY_DESTROY((ary->arry[ary->start]));
4605
+ ++ary->start;
4606
+ return 0;
4607
+ }
4608
+
4609
+ /**
4610
+ * Iteration using a callback for each entry in the array.
4611
+ *
4612
+ * The callback task function must accept an the entry data as well as an opaque
4613
+ * user pointer.
4614
+ *
4615
+ * If the callback returns -1, the loop is broken. Any other value is ignored.
4616
+ *
4617
+ * Returns the relative "stop" position, i.e., the number of items processed +
4618
+ * the starting point.
4619
+ */
4620
+ FIO_FUNC inline size_t FIO_NAME(each)(FIO_NAME(s) * ary, size_t start_at,
4621
+ int (*task)(FIO_ARY_TYPE pt, void *arg),
4622
+ void *arg) {
4623
+ const size_t count = FIO_NAME(count)(ary);
4624
+ if (!count || start_at >= count) {
4625
+ return count;
4626
+ }
4627
+ while (start_at < count &&
4628
+ task(ary->arry[ary->start + (start_at++)], arg) != -1)
4629
+ ;
4630
+ return start_at;
4631
+ }
4632
+ /**
4633
+ * Removes any FIO_ARY_TYPE_INVALID object from an Array (NULL pointers by
4634
+ * default), keeping all other data in the array.
4635
+ *
4636
+ * This action is O(n) where n in the length of the array.
4637
+ * It could get expensive.
4638
+ */
4639
+ FIO_FUNC inline void FIO_NAME(compact)(FIO_NAME(s) * ary) {
4640
+ const size_t count = FIO_NAME(count)(ary);
4641
+ if (!count)
4642
+ return;
4643
+ register FIO_ARY_TYPE *pos = ary->arry + ary->start;
4644
+ register FIO_ARY_TYPE *reader = ary->arry + ary->start;
4645
+ register FIO_ARY_TYPE *stop = ary->arry + ary->end;
4646
+ while (reader < stop) {
4647
+ if (!FIO_ARY_COMPARE((*reader), FIO_ARY_INVALID)) {
4648
+ *pos = *reader;
4649
+ pos += 1;
4650
+ }
4651
+ reader += 1;
4652
+ }
4653
+ ary->end = (size_t)(pos - ary->arry);
4654
+ }
4655
+
4656
+ /* *****************************************************************************
4657
+ Array Testing
4658
+ ***************************************************************************** */
4659
+
4660
+ #if DEBUG
4661
+ #include <stdio.h>
4662
+ #define TEST_LIMIT 1016
4663
+ /**
4664
+ * Removes any FIO_ARY_TYPE_INVALID *pointers* from an Array, keeping all other
4665
+ * data in the array.
4666
+ *
4667
+ * This action is O(n) where n in the length of the array.
4668
+ * It could get expensive.
4669
+ */
4670
+ FIO_FUNC inline void FIO_NAME(_test)(void) {
4671
+ union {
4672
+ FIO_ARY_TYPE obj;
4673
+ uintptr_t i;
4674
+ } mem;
4675
+ FIO_NAME(s) ary = FIO_ARY_INIT;
4676
+ fprintf(stderr, "=== Testing Core Array features for type " FIO_MACRO2STR(
4677
+ FIO_ARY_TYPE) "\n");
4678
+
4679
+ for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
4680
+ mem.i = i + 1;
4681
+ FIO_NAME(push)(&ary, mem.obj);
4682
+ }
4683
+ fprintf(stderr,
4684
+ "* Array populated using `push` with %zu items,\n"
4685
+ " with capacity limit of %zu and start index %zu\n",
4686
+ (size_t)FIO_NAME(count)(&ary), (size_t)FIO_NAME(capa)(&ary),
4687
+ ary.start);
4688
+ FIO_ASSERT(FIO_NAME(count)(&ary) == TEST_LIMIT,
4689
+ "Wrong object count for array %zu", (size_t)FIO_NAME(count)(&ary));
4690
+ for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
4691
+ FIO_ASSERT(!FIO_NAME(shift)(&ary, &mem.obj), "Array shift failed at %lu.",
4692
+ i);
4693
+ FIO_ASSERT(mem.i == i + 1, "Array shift value error %lu != %lu", mem.i,
4694
+ i + 1);
4695
+ FIO_ARY_DESTROY(mem.obj);
4696
+ }
4697
+
4698
+ FIO_NAME_FREE()(&ary);
4699
+ FIO_ASSERT(!ary.arry, "Array not reset after fio_ary_free");
4700
+
4701
+ for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
4702
+ mem.i = TEST_LIMIT - i;
4703
+ FIO_NAME(unshift)(&ary, mem.obj);
4704
+ }
4705
+ fprintf(stderr,
4706
+ "* Array populated using `unshift` with %zu items,\n"
4707
+ " with capacity limit of %zu and start index %zu\n",
4708
+ (size_t)FIO_NAME(count)(&ary), (size_t)FIO_NAME(capa)(&ary),
4709
+ ary.start);
4710
+
4711
+ FIO_ASSERT(FIO_NAME(count)(&ary) == TEST_LIMIT,
4712
+ "Wrong object count for array %zu", (size_t)FIO_NAME(count)(&ary));
4713
+ for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
4714
+ FIO_NAME(pop)(&ary, &mem.obj);
4715
+ FIO_ASSERT(mem.i == TEST_LIMIT - i, "Array pop value error");
4716
+ FIO_ARY_DESTROY(mem.obj);
4717
+ }
4718
+ FIO_NAME_FREE()(&ary);
4719
+ FIO_ASSERT(!ary.arry, "Array not reset after fio_ary_free");
4720
+
4721
+ for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
4722
+ mem.i = TEST_LIMIT - i;
4723
+ FIO_NAME(unshift)(&ary, mem.obj);
4724
+ }
4725
+
4726
+ for (size_t i = 0; i < TEST_LIMIT; ++i) {
4727
+ mem.i = i + 1;
4728
+ FIO_ASSERT(FIO_NAME(find)(&ary, mem.obj) == (intptr_t)i,
4729
+ "Wrong object index - ary[%zd] != %zu",
4730
+ (ssize_t)FIO_NAME(find)(&ary, mem.obj), (size_t)mem.i);
4731
+ mem.obj = FIO_NAME(get)(&ary, i);
4732
+ FIO_ASSERT(mem.i == (uintptr_t)(i + 1),
4733
+ "Wrong object returned from fio_ary_index - ary[%zu] != %zu", i,
4734
+ i + 1);
4735
+ }
4736
+
4737
+ FIO_ASSERT((FIO_NAME(count)(&ary) == TEST_LIMIT),
4738
+ "Wrong object count before pop %zu",
4739
+ (size_t)FIO_NAME(count)(&ary));
4740
+ FIO_ASSERT(!FIO_NAME(pop)(&ary, &mem.obj), "Couldn't pop element.");
4741
+ FIO_ASSERT(mem.i == TEST_LIMIT, "Element value error (%zu).", (size_t)mem.i);
4742
+ FIO_ASSERT((FIO_NAME(count)(&ary) == TEST_LIMIT - 1),
4743
+ "Wrong object count after pop %zu", (size_t)FIO_NAME(count)(&ary));
4744
+ FIO_ARY_DESTROY(mem.obj);
4745
+
4746
+ mem.i = (TEST_LIMIT >> 1);
4747
+ FIO_ASSERT(!FIO_NAME(remove2)(&ary, mem.obj, NULL),
4748
+ "Couldn't fio_ary_remove2 object from Array (%zu)", (size_t)mem.i);
4749
+ FIO_ASSERT(FIO_NAME(count)(&ary) == TEST_LIMIT - 2,
4750
+ "Wrong object count after remove2 %zu",
4751
+ (size_t)FIO_NAME(count)(&ary));
4752
+ mem.i = (TEST_LIMIT >> 1) + 1;
4753
+ FIO_ASSERT(FIO_NAME(find)(&ary, mem.obj) != (TEST_LIMIT >> 1) + 1,
4754
+ "fio_ary_remove2 didn't clear holes from Array (%zu)",
4755
+ (size_t)FIO_NAME(find)(&ary, mem.obj));
4756
+ FIO_ARY_DESTROY(mem.obj);
4757
+
4758
+ FIO_ASSERT(!FIO_NAME(remove)(&ary, 0, &mem.obj),
4759
+ "fio_ary_remove failed (at %zd)", (ssize_t)mem.i);
4760
+ FIO_ASSERT(mem.i == 1, "Couldn't fio_ary_remove object from Array (%zd)",
4761
+ (ssize_t)mem.i);
4762
+ FIO_ASSERT(FIO_NAME(count)(&ary) == TEST_LIMIT - 3,
4763
+ "Wrong object count after remove %zu != %d",
4764
+ (size_t)FIO_NAME(count)(&ary), TEST_LIMIT - 3);
4765
+ FIO_ASSERT(FIO_NAME(find)(&ary, mem.obj) == -1,
4766
+ "fio_ary_find should have failed after fio_ary_remove (%zd)",
4767
+ (ssize_t)FIO_NAME(find)(&ary, mem.obj));
4768
+ FIO_ARY_DESTROY(mem.obj);
4769
+
4770
+ mem.i = 2;
4771
+ FIO_ASSERT(FIO_NAME(find)(&ary, mem.obj) == 0,
4772
+ "fio_ary_remove didn't clear holes from Array (%zu)",
4773
+ (size_t)FIO_NAME(find)(&ary, mem.obj));
4774
+
4775
+ FIO_NAME_FREE()(&ary);
4776
+
4777
+ FIO_NAME(s) ary2 = FIO_ARY_INIT;
4778
+ for (uintptr_t i = 0; i < (TEST_LIMIT >> 1); ++i) {
4779
+ mem.i = ((TEST_LIMIT >> 1) << 1) - i;
4780
+ FIO_NAME(unshift)(&ary2, mem.obj);
4781
+ mem.i = (TEST_LIMIT >> 1) - i;
4782
+ FIO_NAME(unshift)(&ary, mem.obj);
4783
+ }
4784
+ FIO_NAME(concat)(&ary, &ary2);
4785
+ FIO_NAME_FREE()(&ary2);
4786
+ FIO_ASSERT(FIO_NAME(count)(&ary) == ((TEST_LIMIT >> 1) << 1),
4787
+ "Wrong object count after fio_ary_concat %zu",
4788
+ (size_t)FIO_NAME(count)(&ary));
4789
+ for (int i = 0; i < ((TEST_LIMIT >> 1) << 1); ++i) {
4790
+ mem.obj = FIO_NAME(get)(&ary, i);
4791
+ FIO_ASSERT(
4792
+ mem.i == (uintptr_t)(i + 1),
4793
+ "Wrong object returned from fio_ary_index after concat - ary[%d] != %d",
4794
+ i, i + 1);
4795
+ }
4796
+ mem.i = 0;
4797
+ while (FIO_NAME(pop)(&ary, &mem.obj)) {
4798
+ ++mem.i;
4799
+ FIO_ARY_DESTROY(mem.obj);
4800
+ }
4801
+ FIO_ASSERT(mem.i == ((TEST_LIMIT >> 1) << 1), "fio_ary_pop overflow (%zu)?",
4802
+ (size_t)mem.i);
4803
+ FIO_NAME_FREE()(&ary);
4804
+ }
4805
+ #undef TEST_LIMIT
4806
+ #else
4807
+ FIO_FUNC inline void FIO_NAME(_test)(void);
4808
+ #endif
4809
+
4810
+ /* *****************************************************************************
4811
+ Done
4812
+ ***************************************************************************** */
4813
+
4814
+ #undef FIO_NAME_FROM_MACRO_STEP2
4815
+ #undef FIO_NAME_FROM_MACRO_STEP1
4816
+ #undef FIO_NAME
4817
+ #undef FIO_NAME_FROM_MACRO_STEP4
4818
+ #undef FIO_NAME_FROM_MACRO_STEP3
4819
+ #undef FIO_NAME_FREE
4820
+ #undef FIO_ARY_NAME
4821
+ #undef FIO_ARY_TYPE
4822
+ #undef FIO_ARY_INVALID
4823
+ #undef FIO_ARY_COMPARE
4824
+ #undef FIO_ARY_COPY
4825
+ #undef FIO_ARY_DESTROY
4826
+ #undef FIO_ARY_REALLOC
4827
+ #undef FIO_ARY_DEALLOC
4828
+ #undef FIO_ARY_SIZE2WORDS
4829
+
4830
+ #endif
4831
+
4034
4832
  /* *****************************************************************************
4035
4833
 
4036
4834
 
@@ -4135,9 +4933,13 @@ inline FIO_FUNC ssize_t fio_str_send_free2(const intptr_t uuid,
4135
4933
  #define FIO_NAME_FROM_MACRO_STEP2(name, postfix) name##_##postfix
4136
4934
  #define FIO_NAME_FROM_MACRO_STEP1(name, postfix) \
4137
4935
  FIO_NAME_FROM_MACRO_STEP2(name, postfix)
4138
-
4139
4936
  #define FIO_NAME(postfix) FIO_NAME_FROM_MACRO_STEP1(FIO_SET_NAME, postfix)
4140
4937
 
4938
+ /* Used for naming the `free` function */
4939
+ #define FIO_NAME_FROM_MACRO_STEP4(name) name##_free
4940
+ #define FIO_NAME_FROM_MACRO_STEP3(name) FIO_NAME_FROM_MACRO_STEP4(name)
4941
+ #define FIO_NAME_FREE() FIO_NAME_FROM_MACRO_STEP3(FIO_SET_NAME)
4942
+
4141
4943
  /* The default Set object / value type is `void *` */
4142
4944
  #if !defined(FIO_SET_OBJ_TYPE)
4143
4945
  #define FIO_SET_OBJ_TYPE void *
@@ -4183,13 +4985,13 @@ inline FIO_FUNC ssize_t fio_str_send_free2(const intptr_t uuid,
4183
4985
  /* Customizable memory management */
4184
4986
  #ifndef FIO_SET_REALLOC /* NULL ptr indicates new allocation */
4185
4987
  #define FIO_SET_REALLOC(ptr, original_size, new_size, valid_data_length) \
4186
- realloc((ptr), (new_size))
4988
+ fio_realloc2((ptr), (new_size), (valid_data_length))
4187
4989
  #endif
4188
4990
  #ifndef FIO_SET_CALLOC
4189
- #define FIO_SET_CALLOC(size, count) calloc((size), (count))
4991
+ #define FIO_SET_CALLOC(size, count) fio_calloc((size), (count))
4190
4992
  #endif
4191
4993
  #ifndef FIO_SET_FREE
4192
- #define FIO_SET_FREE(ptr, size) free((ptr))
4994
+ #define FIO_SET_FREE(ptr, size) fio_free((ptr))
4193
4995
  #endif
4194
4996
 
4195
4997
  /* The maximum number of bins to rotate when partial collisions occure */
@@ -4259,8 +5061,8 @@ typedef struct FIO_NAME(s) FIO_NAME(s);
4259
5061
  { .capa = 0 }
4260
5062
  #endif
4261
5063
 
4262
- /** Deallocates any internal resources. Doesn't free any objects! */
4263
- FIO_FUNC void FIO_NAME(free)(FIO_NAME(s) * set);
5064
+ /** Frees all the objects in the set and deallocates any internal resources. */
5065
+ FIO_FUNC void FIO_NAME_FREE()(FIO_NAME(s) * set);
4264
5066
 
4265
5067
  #ifdef FIO_SET_KEY_TYPE
4266
5068
 
@@ -4555,11 +5357,19 @@ FIO_FUNC inline FIO_SET_TYPE FIO_NAME(_insert_or_overwrite_)(
4555
5357
 
4556
5358
  /* locate future position, rehashing until a position is available */
4557
5359
  FIO_NAME(_map_s_) *pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
4558
-
4559
- while (!pos) {
4560
- set->mask = (set->mask << 1) | 1;
5360
+ if (!pos) {
5361
+ /* no pos - so we know that we are inserting an object. */
5362
+ /* Either we are over capacity, or we have too many holes in the map. */
5363
+ if (set->pos >= set->capa) {
5364
+ set->mask = (set->mask << 1) | 3;
5365
+ FIO_NAME(rehash)(set);
5366
+ }
5367
+ FIO_SET_COPY(set->ordered[set->pos].obj, obj);
5368
+ set->ordered[set->pos].hash = hash_value;
5369
+ ++set->pos;
5370
+ ++set->count;
4561
5371
  FIO_NAME(rehash)(set);
4562
- pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
5372
+ return set->ordered[set->pos - 1].obj;
4563
5373
  }
4564
5374
 
4565
5375
  /* overwriting / new */
@@ -4601,8 +5411,8 @@ FIO_FUNC inline FIO_SET_TYPE FIO_NAME(_insert_or_overwrite_)(
4601
5411
  Set / Hash Map Implementation
4602
5412
  ***************************************************************************** */
4603
5413
 
4604
- /** Deallocates any internal resources. Doesn't free any objects! */
4605
- FIO_FUNC void FIO_NAME(free)(FIO_NAME(s) * s) {
5414
+ /** Frees all the objects in the set and deallocates any internal resources. */
5415
+ FIO_FUNC void FIO_NAME_FREE()(FIO_NAME(s) * s) {
4606
5416
  /* destroy existing valid objects */
4607
5417
  const FIO_NAME(_ordered_s_) *const end = s->ordered + s->pos;
4608
5418
  if (s->ordered && s->ordered != end) {
@@ -4683,6 +5493,7 @@ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4683
5493
  --set->count;
4684
5494
  pos->pos->hash = FIO_SET_HASH_INVALID;
4685
5495
  if (pos->pos == set->pos + set->ordered - 1) {
5496
+ pos->hash = FIO_SET_HASH_INVALID; /* no need for a "hole" */
4686
5497
  do {
4687
5498
  --set->pos;
4688
5499
  } while (set->pos && FIO_SET_HASH_COMPARE(set->ordered[set->pos - 1].hash,
@@ -4818,7 +5629,7 @@ FIO_FUNC inline size_t FIO_NAME(capa_require)(FIO_NAME(s) * set,
4818
5629
  return FIO_NAME(capa)(set);
4819
5630
  set->mask = 1;
4820
5631
  while (min_capa > set->mask) {
4821
- set->mask = (set->mask << 1) | 1;
5632
+ set->mask = (set->mask << 1) | 3;
4822
5633
  }
4823
5634
  FIO_NAME(rehash)(set);
4824
5635
  return FIO_NAME(capa)(set);
@@ -4839,7 +5650,7 @@ FIO_FUNC inline size_t FIO_NAME(is_fragmented)(const FIO_NAME(s) * set) {
4839
5650
  */
4840
5651
  FIO_FUNC inline size_t FIO_NAME(compact)(FIO_NAME(s) * set) {
4841
5652
  FIO_NAME(_compact_ordered_array_)(set);
4842
- set->mask = 1;
5653
+ set->mask = 3;
4843
5654
  while (set->count >= set->mask) {
4844
5655
  set->mask = (set->mask << 1) | 1;
4845
5656
  }
@@ -4859,7 +5670,7 @@ restart:
4859
5670
  FIO_NAME(_map_s_) *mp =
4860
5671
  FIO_NAME(_find_map_pos_)(set, pos->hash, pos->obj);
4861
5672
  if (!mp) {
4862
- set->mask = (set->mask << 1) | 1;
5673
+ set->mask = (set->mask << 1) | 3;
4863
5674
  goto restart;
4864
5675
  }
4865
5676
  mp->pos = pos;
@@ -4891,6 +5702,9 @@ restart:
4891
5702
  #undef FIO_NAME
4892
5703
  #undef FIO_NAME_FROM_MACRO_STEP2
4893
5704
  #undef FIO_NAME_FROM_MACRO_STEP1
5705
+ #undef FIO_NAME_FROM_MACRO_STEP4
5706
+ #undef FIO_NAME_FROM_MACRO_STEP3
5707
+ #undef FIO_NAME_FREE
4894
5708
  #undef FIO_SET_NAME
4895
5709
 
4896
5710
  #endif