|
| 1 | +/* |
| 2 | +------------------------------------------------------------------------------ |
| 3 | + Licensing information can be found at the end of the file. |
| 4 | +------------------------------------------------------------------------------ |
| 5 | +
|
| 6 | +array.h - v0.1 - Dynamic array library for C/C++. |
| 7 | +
|
| 8 | +Do this: |
| 9 | + #define ARRAY_IMPLEMENTATION |
| 10 | +before you include this file in *one* C/C++ file to create the implementation. |
| 11 | +*/ |
| 12 | + |
| 13 | +#ifndef array_h |
| 14 | +#define array_h |
| 15 | + |
| 16 | +#ifndef ARRAY_BOOL_T |
| 17 | + #define _CRT_NONSTDC_NO_DEPRECATE |
| 18 | + #define _CRT_SECURE_NO_WARNINGS |
| 19 | + #include <stdbool.h> |
| 20 | + #define ARRAY_BOOL_T bool |
| 21 | +#endif |
| 22 | + |
| 23 | +#define array_t( type ) struct { int count; type* items; } |
| 24 | +#define array_param_t( type ) void |
| 25 | +#define array_create( type ) ARRAY_CAST( (void*)internal_array_create( sizeof( type ), NULL ) ) |
| 26 | +#define array_create_memctx( type, memctx ) ARRAY_CAST( (void*)internal_array_create( sizeof( type ), (memctx) ) ) |
| 27 | +#define array_destroy( array ) internal_array_destroy( (struct internal_array_t*) (array) ) |
| 28 | +#define array_add( array, item ) ARRAY_CAST( internal_array_add( (struct internal_array_t*) (array), (void*) (item) ) ) |
| 29 | +#define array_remove( array, index ) internal_array_remove( (struct internal_array_t*) (array), (index) ) |
| 30 | +#define array_remove_ordered( array, index ) internal_array_remove_ordered( (struct internal_array_t*) (array), (index) ) |
| 31 | +#define array_get( array, index, item ) internal_array_get( (struct internal_array_t*) (array), (index), (void*) (item) ) |
| 32 | +#define array_set( array, index, item ) internal_array_set( (struct internal_array_t*) (array), (index), (void*) (item) ) |
| 33 | +#define array_count( array ) internal_array_count( (struct internal_array_t*) (array) ) |
| 34 | +#define array_sort( array, compare ) internal_array_sort( (struct internal_array_t*) (array), (compare) ) |
| 35 | +#define array_bsearch( array, key, compare ) internal_array_bsearch( (struct internal_array_t*) (array), (void*) (key), (compare) ) |
| 36 | +#define array_find( array, item ) internal_array_find( (struct internal_array_t*) (array), (void*) (item) ) |
| 37 | +#define array_item( array, index ) ARRAY_CAST( internal_array_item( (struct internal_array_t*) (array), (index) ) ) |
| 38 | + |
| 39 | + |
| 40 | +// In C, a void* can be implicitly cast to any other kind of pointer, while in C++ you need an explicit cast. In most |
| 41 | +// cases, the explicit cast works for both C and C++, but if we consider the case where we have nested structs, then |
| 42 | +// the way you refer to them differs between C and C++ (in C++, `parent_type::nested_type`, in C just `nested_type`). |
| 43 | +// In addition, with the automatic cast in C, it is possible to use unnamed nested structs and still dynamically |
| 44 | +// allocate arrays of that type - this would be desirable when the code is compiled from C++ as well. |
| 45 | +// This VOID_CAST macro allows for automatic cast from void* in C++. In C, it does nothing, but for C++ it uses a |
| 46 | +// simple template function to define a cast-to-anything operator. |
| 47 | +// Use like this: |
| 48 | +// struct { |
| 49 | +// struct { |
| 50 | +// int x; |
| 51 | +// } *nested; |
| 52 | +// } parent; |
| 53 | +// parent.nested = VOID_CAST( malloc( sizeof( *parent.nested ) * count ) ); |
| 54 | +// |
| 55 | +#ifndef ARRAY_CAST |
| 56 | + #ifdef __cplusplus |
| 57 | + struct array_cast { |
| 58 | + inline array_cast( void* x_ ) : x( x_ ) { } |
| 59 | + inline array_cast( void const* x_ ) : x( (void*) x_ ) { } |
| 60 | + template< typename T > inline operator T() { return (T)x; } // cast to whatever requested |
| 61 | + void* x; |
| 62 | + }; |
| 63 | + #define ARRAY_CAST( x ) array_cast( x ) |
| 64 | + #else |
| 65 | + #define ARRAY_CAST( x ) x |
| 66 | + #endif |
| 67 | +#endif |
| 68 | + |
| 69 | + |
| 70 | +struct internal_array_t; |
| 71 | + |
| 72 | +struct internal_array_t* internal_array_create( int item_size, void* memctx ); |
| 73 | +void internal_array_destroy( struct internal_array_t* array ); |
| 74 | +void* internal_array_add( struct internal_array_t* array, void* item ); |
| 75 | +void internal_array_remove( struct internal_array_t* array, int index ); |
| 76 | +void internal_array_remove_ordered( struct internal_array_t* array, int index ); |
| 77 | +ARRAY_BOOL_T internal_array_get( struct internal_array_t* array, int index, void* item ); |
| 78 | +ARRAY_BOOL_T internal_array_set( struct internal_array_t* array, int index, void const* item ); |
| 79 | +int internal_array_count( struct internal_array_t* array ); |
| 80 | +void internal_array_sort( struct internal_array_t* array, int (*compare)( void const*, void const* ) ); |
| 81 | +int internal_array_bsearch( struct internal_array_t* array, void* key, int (*compare)( void const*, void const* ) ); |
| 82 | +int internal_array_find( struct internal_array_t* array, void* item ); |
| 83 | +void* internal_array_item( struct internal_array_t* array, int index ); |
| 84 | + |
| 85 | +#endif /* array_h */ |
| 86 | + |
| 87 | + |
| 88 | +/* |
| 89 | +---------------------- |
| 90 | + IMPLEMENTATION |
| 91 | +---------------------- |
| 92 | +*/ |
| 93 | + |
| 94 | +#ifdef ARRAY_IMPLEMENTATION |
| 95 | +#undef ARRAY_IMPLEMENTATION |
| 96 | + |
| 97 | + |
| 98 | +#ifndef ARRAY_MALLOC |
| 99 | + #define _CRT_NONSTDC_NO_DEPRECATE |
| 100 | + #define _CRT_SECURE_NO_WARNINGS |
| 101 | + #include <stdlib.h> |
| 102 | + #define ARRAY_MALLOC( ctx, size ) ( malloc( size ) ) |
| 103 | + #define ARRAY_FREE( ctx, ptr ) ( free( ptr ) ) |
| 104 | +#endif |
| 105 | + |
| 106 | +#ifndef ARRAY_MEMCPY |
| 107 | + #define _CRT_NONSTDC_NO_DEPRECATE |
| 108 | + #define _CRT_SECURE_NO_WARNINGS |
| 109 | + #include <string.h> |
| 110 | + #define ARRAY_MEMCPY( dst, src, cnt ) ( memcpy( (dst), (src), (cnt) ) ) |
| 111 | +#endif |
| 112 | + |
| 113 | +#ifndef ARRAY_MEMMOVE |
| 114 | + #define _CRT_NONSTDC_NO_DEPRECATE |
| 115 | + #define _CRT_SECURE_NO_WARNINGS |
| 116 | + #include <string.h> |
| 117 | + #define ARRAY_MEMMOVE( dst, src, cnt ) ( memcpy( (dst), (src), (cnt) ) ) |
| 118 | +#endif |
| 119 | + |
| 120 | +#ifndef ARRAY_MEMCMP |
| 121 | + #define _CRT_NONSTDC_NO_DEPRECATE |
| 122 | + #define _CRT_SECURE_NO_WARNINGS |
| 123 | + #include <string.h> |
| 124 | + #define ARRAY_MEMCMP( a, b, cnt ) ( memcmp( (a), (b), (cnt) ) ) |
| 125 | +#endif |
| 126 | + |
| 127 | +#ifndef ARRAY_QSORT |
| 128 | + #define _CRT_NONSTDC_NO_DEPRECATE |
| 129 | + #define _CRT_SECURE_NO_WARNINGS |
| 130 | + #include <stdlib.h> |
| 131 | + #define ARRAY_QSORT( base, num, size, cmp ) ( qsort( (base), (num), (size), (cmp) ) ) |
| 132 | +#endif |
| 133 | + |
| 134 | +#ifndef ARRAY_BSEARCH |
| 135 | + #define _CRT_NONSTDC_NO_DEPRECATE |
| 136 | + #define _CRT_SECURE_NO_WARNINGS |
| 137 | + #include <stdlib.h> |
| 138 | + #define ARRAY_BSEARCH( key, base, num, size, cmp ) ( bsearch( (key), (base), (num), (size), (cmp) ) ) |
| 139 | +#endif |
| 140 | + |
| 141 | + |
| 142 | +struct internal_array_t { |
| 143 | + int count; |
| 144 | + void* items; |
| 145 | + void* memctx; |
| 146 | + int item_size; |
| 147 | + int capacity; |
| 148 | +}; |
| 149 | + |
| 150 | + |
| 151 | +struct internal_array_t* internal_array_create( int item_size, void* memctx ) { |
| 152 | + struct internal_array_t* array = (struct internal_array_t*) ARRAY_MALLOC( memctx, sizeof( struct internal_array_t ) ); |
| 153 | + array->memctx = memctx; |
| 154 | + array->item_size = item_size; |
| 155 | + array->capacity = 256; |
| 156 | + array->count = 0; |
| 157 | + array->items = ARRAY_MALLOC( memctx, (size_t) array->capacity * item_size ); |
| 158 | + return array; |
| 159 | +} |
| 160 | + |
| 161 | + |
| 162 | +void internal_array_destroy( struct internal_array_t* array ) { |
| 163 | + ARRAY_FREE( array->memctx, array->items ); |
| 164 | + ARRAY_FREE( array->memctx, array ); |
| 165 | +} |
| 166 | + |
| 167 | + |
| 168 | +void* internal_array_add( struct internal_array_t* array, void* item ) { |
| 169 | + if( array->count >= array->capacity ) { |
| 170 | + array->capacity *= 2; |
| 171 | + void* items = array->items; |
| 172 | + array->items = ARRAY_MALLOC( array->memctx, (size_t) array->capacity * array->item_size ); |
| 173 | + ARRAY_MEMCPY( array->items, items, (size_t)array->count * array->item_size ); |
| 174 | + ARRAY_FREE( array->memctx, items ); |
| 175 | + } |
| 176 | + ARRAY_MEMCPY( (void*)( ( (uintptr_t) array->items ) + array->count * array->item_size ), item, |
| 177 | + (size_t)array->item_size ); |
| 178 | + ++array->count; |
| 179 | + return (void*)( ( (uintptr_t) array->items ) + ( array->count - 1 ) * array->item_size ); |
| 180 | +} |
| 181 | + |
| 182 | + |
| 183 | +void internal_array_remove( struct internal_array_t* array, int index ) { |
| 184 | + if( index >= 0 && index < array->count ) { |
| 185 | + --array->count; |
| 186 | + ARRAY_MEMMOVE( (void*)( ( (uintptr_t) array->items ) + index * array->item_size ), |
| 187 | + (void*)( ( (uintptr_t) array->items ) + array->count * array->item_size ), (size_t) array->item_size ); |
| 188 | + } |
| 189 | +} |
| 190 | + |
| 191 | +void internal_array_remove_ordered( struct internal_array_t* array, int index ) { |
| 192 | + if( index >= 0 && index < array->count ) { |
| 193 | + --array->count; |
| 194 | + ARRAY_MEMMOVE( (void*)( ( (uintptr_t) array->items ) + index * array->item_size ), |
| 195 | + (void*)( ( (uintptr_t) array->items ) + ( index + 1 ) * array->item_size ), |
| 196 | + (size_t)array->item_size * ( array->count - index ) ); |
| 197 | + } |
| 198 | +} |
| 199 | + |
| 200 | +ARRAY_BOOL_T internal_array_get( struct internal_array_t* array, int index, void* item ) { |
| 201 | + ARRAY_BOOL_T result = index >= 0 && index < array->count; |
| 202 | + if( result ) { |
| 203 | + ARRAY_MEMCPY( item, (void*)( ( (uintptr_t) array->items ) + index * array->item_size ), |
| 204 | + (size_t) array->item_size ); |
| 205 | + } |
| 206 | + return result; |
| 207 | +} |
| 208 | + |
| 209 | +ARRAY_BOOL_T internal_array_set( struct internal_array_t* array, int index, void const* item ) { |
| 210 | + ARRAY_BOOL_T result = index >= 0 && index < array->count; |
| 211 | + if( result ) { |
| 212 | + ARRAY_MEMCPY( (void*)( ( (uintptr_t) array->items ) + index * array->item_size ), item, |
| 213 | + (size_t) array->item_size ); |
| 214 | + } |
| 215 | + return result; |
| 216 | +} |
| 217 | + |
| 218 | +int internal_array_count( struct internal_array_t* array ) { |
| 219 | + int count = array->count; |
| 220 | + return count; |
| 221 | +} |
| 222 | + |
| 223 | + |
| 224 | +void internal_array_sort( struct internal_array_t* array, int (*compare)( void const*, void const* ) ) { |
| 225 | + ARRAY_QSORT( array->items, (size_t) array->count, (size_t) array->item_size, compare ); |
| 226 | +} |
| 227 | + |
| 228 | + |
| 229 | +int internal_array_bsearch( struct internal_array_t* array, void* key, int (*compare)( void const*, void const* ) ) { |
| 230 | + void* item = ARRAY_BSEARCH( key, array->items, (size_t) array->count, (size_t) array->item_size, compare ); |
| 231 | + int result = -1; |
| 232 | + if( item ) { |
| 233 | + result = (int)( ( ((uintptr_t)item) - ((uintptr_t)array->items) ) / array->item_size ); |
| 234 | + } |
| 235 | + return result; |
| 236 | +} |
| 237 | + |
| 238 | + |
| 239 | +int internal_array_find( struct internal_array_t* array, void* item ) { |
| 240 | + for( int i = 0; i < array->count; ++i ) { |
| 241 | + if( ARRAY_MEMCMP( (void*)( ( (uintptr_t) array->items ) + i * array->item_size ), item, |
| 242 | + (size_t) array->item_size) == 0 ) { |
| 243 | + |
| 244 | + return i; |
| 245 | + } |
| 246 | + } |
| 247 | + return -1; |
| 248 | +} |
| 249 | + |
| 250 | + |
| 251 | +void* internal_array_item( struct internal_array_t* array, int index ) { |
| 252 | + if( index >= 0 && index < array->count ) { |
| 253 | + return (void*)( ( (uintptr_t) array->items ) + index * array->item_size ); |
| 254 | + } else { |
| 255 | + return NULL; |
| 256 | + } |
| 257 | +} |
| 258 | + |
| 259 | +#endif /* ARRAY_IMPLEMENTATION */ |
| 260 | + |
| 261 | +/* |
| 262 | +------------------------------------------------------------------------------ |
| 263 | +
|
| 264 | +This software is available under 2 licenses - you may choose the one you like. |
| 265 | +
|
| 266 | +------------------------------------------------------------------------------ |
| 267 | +
|
| 268 | +ALTERNATIVE A - MIT License |
| 269 | +
|
| 270 | +Copyright (c) 2022 Mattias Gustavsson |
| 271 | +
|
| 272 | +Permission is hereby granted, free of charge, to any person obtaining a copy of |
| 273 | +this software and associated documentation files (the "Software"), to deal in |
| 274 | +the Software without restriction, including without limitation the rights to |
| 275 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
| 276 | +of the Software, and to permit persons to whom the Software is furnished to do |
| 277 | +so, subject to the following conditions: |
| 278 | +
|
| 279 | +The above copyright notice and this permission notice shall be included in all |
| 280 | +copies or substantial portions of the Software. |
| 281 | +
|
| 282 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 283 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 284 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 285 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 286 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 287 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 288 | +SOFTWARE. |
| 289 | +
|
| 290 | +------------------------------------------------------------------------------ |
| 291 | +
|
| 292 | +ALTERNATIVE B - Public Domain (www.unlicense.org) |
| 293 | +
|
| 294 | +This is free and unencumbered software released into the public domain. |
| 295 | +
|
| 296 | +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this |
| 297 | +software, either in source code form or as a compiled binary, for any purpose, |
| 298 | +commercial or non-commercial, and by any means. |
| 299 | +
|
| 300 | +In jurisdictions that recognize copyright laws, the author or authors of this |
| 301 | +software dedicate any and all copyright interest in the software to the public |
| 302 | +domain. We make this dedication for the benefit of the public at large and to |
| 303 | +the detriment of our heirs and successors. We intend this dedication to be an |
| 304 | +overt act of relinquishment in perpetuity of all present and future rights to |
| 305 | +this software under copyright law. |
| 306 | +
|
| 307 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 308 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 309 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 310 | +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| 311 | +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 312 | +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 313 | +
|
| 314 | +------------------------------------------------------------------------------ |
| 315 | +*/ |
0 commit comments