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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -2
- data/ext/iodine/fio.c +319 -46
- data/ext/iodine/fio.h +851 -37
- data/ext/iodine/fio_cli.c +17 -16
- data/ext/iodine/fio_json_parser.h +28 -3
- data/ext/iodine/fiobj_ary.c +44 -46
- data/ext/iodine/fiobj_data.c +12 -13
- data/ext/iodine/fiobj_hash.c +28 -27
- data/ext/iodine/fiobj_json.c +40 -33
- data/ext/iodine/fiobj_numbers.c +2 -304
- data/ext/iodine/fiobj_str.c +0 -1
- data/ext/iodine/fiobject.c +268 -38
- data/ext/iodine/iodine_json.c +13 -14
- data/ext/iodine/iodine_store.c +33 -29
- data/iodine.gemspec +1 -3
- data/lib/iodine.rb +2 -2
- data/lib/iodine/json.rb +3 -1
- data/lib/iodine/version.rb +1 -1
- metadata +5 -4
- data/ext/iodine/fio_ary.h +0 -717
data/ext/iodine/fio.h
CHANGED
@@ -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
|
-
"
|
374
|
-
":" FIO_MACRO2STR(__LINE__) ")
|
374
|
+
"DEBUG ("__FILE__ \
|
375
|
+
":" FIO_MACRO2STR(__LINE__) "): " __VA_ARGS__)
|
375
376
|
#define FIO_LOG_INFO(...) \
|
376
|
-
FIO_LOG_PRINT(FIO_LOG_LEVEL_INFO, "
|
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, "
|
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, "
|
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, "
|
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
|
-
|
406
|
-
|
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
|
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
|
-
*
|
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
|
-
|
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)
|
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)
|
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
|
-
/**
|
4263
|
-
FIO_FUNC void
|
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
|
-
|
4560
|
-
|
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
|
-
|
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
|
-
/**
|
4605
|
-
FIO_FUNC void
|
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) |
|
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 =
|
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) |
|
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
|