├── LICENSE ├── README.md ├── indexed_array.c ├── indexed_array.h ├── test_main.c └── test_main.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Taymindis Woon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # indexed_array 2 | Index(ed) Array is a struct array for your to add index for struct field member and it can be binary search 3 | When the field been indexed, it will auto sorted while inserting new node, please make sure the field has value pre-allocated memory. 4 | 5 | ## Noted 6 | Every struct have to be pre-allocated and value setted before push into Index(ed) Array. 7 | 8 | ### Target Project 9 | - this lib mostly target for big datatable searching on cache. 10 | 11 | ### Requirement 12 | - gcc/clang/llvm-gcc 13 | 14 | 15 | ### Sample of Testing 16 | - goto root directory 17 | - gcc indexed_array.c main.c -otest 18 | - ./test 19 | 20 | ### API document 21 | ###### idx_array_t *idxarr_create(idxarr_u_int size, idxarr_u_int num_of_index) 22 | * arg0=The size of array 23 | * arg1=number of index will be created 24 | * return idxarr_array (root_array) 25 | 26 | ###### int idxarr_add_{data_type}_index(idx_array_t *a, struct_name, field_member); 27 | * arg0=root_array 28 | * arg1=the struct name 29 | * arg2=the field name 30 | * return 1 if successful, 0 if fail created 31 | 32 | ###### int idxarr_push(idx_array_t *a, void* node); 33 | * arg0=root array 34 | * arg1=pre-allocated node 35 | * return 1 if successful, 0 if fail pushed 36 | 37 | ###### int idxarr_push_n(idx_array_t *a, idxarr_u_char* node, idxarr_u_int num) 38 | * it is push more than 1 elements at one time by given a array node. 39 | * arg0=root array 40 | * arg1=pre-allocated node array 41 | * arg2=number of element does node array have 42 | * return 1 if successful, 0 if fail pushed 43 | 44 | ###### void* idxarr_search_one(idx_array_t *a, struct_name, field_name, key) 45 | * it is binary search if key matched, it direct return the pointer which point to the node(do not free the node). 46 | * arg0=root array 47 | * arg1=struct name 48 | * arg2=field name 49 | * arg3=key for search 50 | * return the pointer pointed to the node 51 | 52 | 53 | ###### idx_array_rs* idxarr_search_eq(idx_array_t *a, struct_name, field_name, key) 54 | * it is binary search if every node matched to the key 55 | * arg0=root array 56 | * arg1=struct name 57 | * arg2=field name 58 | * arg3=key for search 59 | * return the result set(idx_array_rs) and need to be free after use, see demo for details 60 | 61 | 62 | ###### idx_array_rs* idxarr_search_lt(idx_array_t *a, struct_name, field_name, key) 63 | * it is binary search if every node lower than the key 64 | * arg0=root array 65 | * arg1=struct name 66 | * arg2=field name 67 | * arg3=key for search 68 | * return the result set(idx_array_rs) and need to be free after use, see demo for details 69 | 70 | 71 | ###### idx_array_rs* idxarr_search_gt(idx_array_t *a, struct_name, field_name, key) 72 | * it is binary search if every node greater than the key 73 | * arg0=root array 74 | * arg1=struct name 75 | * arg2=field name 76 | * arg3=key for search 77 | * return the result set(idx_array_rs) and need to be free after use, see demo for details 78 | 79 | 80 | ###### idx_array_rs* idxarr_search_multi_eq2(idx_array_t *a, struct_name, field_name, key1, key2) 81 | * it is binary search more than 1 eq, similar to IN query in sql, it so far can up to 10 key search at the same time. 82 | * arg0=root array 83 | * arg1=struct name 84 | * arg2=field name 85 | * arg3=key1 for search 86 | * arg4=key2 for search 87 | * return the result set(idx_array_rs) and need to be free after use, see demo for details 88 | 89 | ###### idx_array_rs* idxarr_union_rs(idx_array_rs *rs1, idx_array_rs *rs2, bool free_after_merge); 90 | * it is union rs1 and rs2, and return the merged result. 91 | * arg0=result set 1 92 | * arg1=result set 2 93 | * arg2=boolean to tell whether want to free rs1 and rs2 after new merged result created 94 | * return the result set(idx_array_rs) and need to be free after use, see demo for details 95 | 96 | 97 | ###### idx_array_rs* idxarr_intersect_rs(idx_array_rs *rs1, idx_array_rs *rs2, bool free_after_merge); 98 | * it is finding the intersection value between rs1 and rs2, and return the merged result. 99 | * arg0=result set 1 100 | * arg1=result set 2 101 | * arg2=boolean to tell whether want to free rs1 and rs2 after new merged result created 102 | * return the result set(idx_array_rs) and need to be free after use, see demo for details 103 | 104 | 105 | ###### idx_array_rs* idxarr_append_rs(idx_array_rs *rs1, idx_array_rs *rs2, bool free_after_merge); 106 | * it is just appending the result, . 107 | * arg0=result set 1 108 | * arg1=result set 2 109 | * arg2=boolean to tell whether want to free rs2 after new merged result created 110 | * return the result set(idx_array_rs) and need to be free after use, see demo for details 111 | 112 | ###### void idxarr_sort_rs_by(idx_array_rs *rs, cmp_func) 113 | * re-sort the result with your customized compare function, . 114 | * arg0=result set 1 115 | * arg1=result set 2 116 | * arg2=boolean to tell whether want to free rs2 after new merged result created 117 | * return nothing 118 | 119 | ###### void idxarr_sort_rs_by_b(idx_array_rs *rs, cmp_func) 120 | * for Apple Compiler, it can be dynamic block function, re-sort the result with your customized compare function, . 121 | * arg0=result set 1 122 | * arg1=result set 2 123 | * arg2=boolean to tell whether want to free rs2 after new merged result created 124 | * return nothing 125 | 126 | ###### void idxarr_free_rs(idx_array_rs *rs) 127 | * free the result set 128 | * arg0=result set 129 | 130 | ###### void idxarr_clear(idx_array_t *a, free_node_fn free_node_fn) 131 | * it is clear all the value but still remaining the array schema and indexed, for the purpose of reload/reset the data. 132 | * arg0=root array 133 | * arg1=free node function, to create a free node function to free the node when destroy array 134 | * return nothing 135 | 136 | ###### void idxarr_destroy(idx_array_t *a, free_node_fn free_node_fn) 137 | * it is destrying the root array 138 | * arg0=root array 139 | * arg1=free node function, to create a free node function to free the node when destroy array 140 | * return nothing 141 | 142 | 143 | ###### void idxarr_safety_swap(idx_array_t **curr, idx_array_t *new_a, free_node_fn free_node_fn, unsigned int buffer_time_mic_sec) 144 | * It is making hazard ptr to swap new array into curr array safety, 145 | * arg0=curr array dereference 146 | * arg1=new array to replace curr array 147 | * arg2=free node function, to create a free node function to free the node when destroy old array 148 | * arg3=the buffer time for old array going to be freed, the purpose for current thread may still using old array with specific of time 149 | * return nothing 150 | 151 | 152 | ### What is pre-allocated value in the readme 153 | * it means the value must allocate memory before push into the array. The buffer will keeping the same value until you destroy the array, it will be freed 154 | 155 | ### Enjoy your Binary Data searching!! -------------------------------------------------------------------------------- /indexed_array.c: -------------------------------------------------------------------------------- 1 | #include "indexed_array.h" 2 | #include 3 | 4 | 5 | void idxarr_insert(idx_array_t *a, idxarr_u_char* node, size_t index_num); 6 | void idxarr_push_idx_ref(idx_array_t *a, void* node); 7 | 8 | void __union__(idx_array_rs *rs1, idx_array_rs *rs2, idx_array_rs *merged_rs, bool free_after_merge); 9 | void __intersection__(idx_array_rs *rs1, idx_array_rs *rs2, idx_array_rs *merged_rs, bool free_after_merge); 10 | 11 | static inline int cmp_idx_rs_uint(const void * a, const void * b) { 12 | return (int)( (*(const idxarr_u_int *)a) - (*(const idxarr_u_int *)b) ); 13 | } 14 | 15 | // #ifndef DISABLE_BA_SWAP 16 | // #include 17 | 18 | // void *destroy_old_array_(void *swp); 19 | // /* this function and struct is run by the thread only */ 20 | // typedef struct { 21 | // idx_array_t *old_a; 22 | // free_node_fn free_node; 23 | // unsigned int secs; 24 | // } ba_swapping_t; 25 | 26 | // void *destroy_old_array_(void *swp) { 27 | // ba_swapping_t *s = (ba_swapping_t*)swp; 28 | // sleep(s->secs); 29 | // idxarr_destroy(s->old_a, s->free_node); 30 | // __idxarr_free_fn(swp); 31 | // pthread_exit(NULL); 32 | // } 33 | // #endif 34 | 35 | /* 36 | * This is reference of bsearch - https://github.com/torvalds/linux/blob/master/lib/bsearch.c 37 | * but return index, passing struct field as comparison 38 | */ 39 | long 40 | basearch_index_eq_(register const void *key, idxarr_u_char **base, size_t num, register idx_cmp_func cmp) { 41 | register int result = 0; 42 | register size_t mid = 0, i = 0; 43 | // size_t ptr_size = sizeof(idxarr_u_char*); 44 | while (num > 0) { 45 | i = mid + (num >> 1); 46 | result = cmp(key, *(base + i)); 47 | 48 | if (result == 0) 49 | return i; 50 | 51 | if (result > 0) { 52 | mid = i + 1; 53 | num--; 54 | } 55 | num >>= 1; 56 | } 57 | 58 | if (result > 0) return i + 1; // If cannot find the index and previous result is bigger, please plus 1 59 | return i; 60 | } 61 | 62 | long 63 | basearch_index_gt_(register const void *key, idxarr_u_char **base, size_t num, register idx_cmp_func cmp) { 64 | register int result = 0; 65 | register size_t mid = 0, i = 0; 66 | while (num > 0) { 67 | i = mid + (num >> 1); 68 | result = cmp(key, *(base + i)); 69 | 70 | if (result >= 0) { 71 | mid = i + 1; 72 | num--; 73 | } 74 | num >>= 1; 75 | } 76 | if (result >= 0) return i + 1; 77 | return i; 78 | } 79 | 80 | long 81 | basearch_index_lt_(register const void *key, idxarr_u_char **base, size_t num, register idx_cmp_func cmp) { 82 | register int result = 0; 83 | register size_t mid = 0, i = 0; 84 | while (num > 0) { 85 | i = mid + (num >> 1); 86 | result = cmp(key, *(base + i)); 87 | 88 | if (result > 0) { 89 | mid = i + 1; 90 | num--; 91 | } 92 | num >>= 1; 93 | } 94 | if (result <= 0) return i - 1; 95 | return i; 96 | } 97 | 98 | 99 | idx_array_rs* 100 | basearch_index_by_func(const char *key, idx_array_t *a, idxarr_u_long offset, idx_cmp_func cmp_func) 101 | { 102 | size_t i; 103 | idxarr_array_idx *arr_idx; 104 | // long index; 105 | long asize; 106 | idx_array_rs *arr_rs = idxarr_rs_create(__DEFAULT_RS_CAPACITY__); 107 | for (i = 0; i < a->num_of_index; i++) { 108 | if (a->_index_arr_[i].cmp_func != NULL && a->_index_arr_[i].offset == offset) { 109 | goto FOUND_INDEX; 110 | } 111 | } 112 | 113 | return arr_rs; 114 | 115 | FOUND_INDEX: 116 | arr_idx = a->_index_arr_ + i ; // * sizeof(idxarr_array_idx); it is not void/char ptr, not need adjust by size 117 | long lt_ind, gt_ind; 118 | asize = a->size; 119 | 120 | __idxarr_args_with_meta__ key_arg; 121 | key_arg.skey = key; 122 | key_arg.klen = strlen(key); 123 | lt_ind = basearch_index_lt_((void*)&key_arg, arr_idx->arr_ref, asize, cmp_func); 124 | gt_ind = basearch_index_gt_((void*)&key_arg, arr_idx->arr_ref, asize, cmp_func); 125 | 126 | if ( lt_ind >= asize || gt_ind <= 0 || gt_ind - lt_ind < 2) { // means none 127 | return arr_rs; 128 | } 129 | 130 | if (lt_ind < 0) 131 | lt_ind = 0; 132 | else lt_ind++; 133 | 134 | if (gt_ind >= asize) 135 | gt_ind = asize; 136 | 137 | // idxarr_u_char **arr_refs = arr_idx->arr_ref; 138 | 139 | idxarr_push_rs_n(arr_rs, lt_ind, gt_ind - lt_ind, arr_idx->arr_ref); 140 | return arr_rs; 141 | } 142 | 143 | idxarr_u_char ** 144 | idxarr_get_index_array(idx_array_t *a, idxarr_u_int index_num) { 145 | if (index_num < a->num_of_index) { 146 | return a->_index_arr_[index_num].arr_ref; 147 | } 148 | return NULL; 149 | } 150 | 151 | // Function to sort an array a[] of size 'n' 152 | void 153 | idxarr_insert(idx_array_t *a, idxarr_u_char* node, size_t index_num) { 154 | idxarr_array_idx *index_arr = a->_index_arr_ + index_num;// * sizeof(idxarr_array_idx); //it is not void ptr, not need adjust by size 155 | if (index_arr->cmp_func) { 156 | long curr_sz = a->size; 157 | long index_ptr; 158 | if (index_arr->dtype == idxarr_hstr_dataType) { 159 | index_ptr = basearch_index_eq_(*(void**)(node + index_arr->offset), index_arr->arr_ref, curr_sz, index_arr->cmp_func); 160 | } else { 161 | index_ptr = basearch_index_eq_(node + index_arr->offset, index_arr->arr_ref, curr_sz, index_arr->cmp_func); 162 | } 163 | /** Memmove for overlap destination **/ 164 | memmove(&index_arr->arr_ref[index_ptr + 1], &index_arr->arr_ref[index_ptr], (curr_sz - index_ptr) * sizeof(idxarr_u_char*)); 165 | 166 | index_arr->arr_ref[index_ptr] = node; 167 | } 168 | } 169 | 170 | idx_array_t * 171 | idxarr_create(idxarr_u_int size, idxarr_u_int num_of_index) 172 | { 173 | idx_array_t *a; 174 | 175 | a = (idx_array_t *) __idxarr_malloc_fn(sizeof(idx_array_t)); 176 | if (a == NULL) { 177 | return NULL; 178 | } 179 | 180 | if (idxarr_array_init(a, size, num_of_index) == 0) { 181 | return NULL; 182 | } 183 | 184 | return a; 185 | } 186 | 187 | void 188 | idxarr_clear(idx_array_t *a, free_node_fn free_node) { 189 | size_t i, j; 190 | if (!free_node) free_node = __idxarr_free_fn; 191 | for (i = 0; i < a->num_of_index; i++) { 192 | idxarr_array_idx *idx_arr = a->_index_arr_ + i;// * sizeof(idxarr_array_idx); it is not void ptr, not need adjust by size 193 | if (idx_arr->cmp_func) { 194 | if (i == 0) { 195 | for (j = 0; j < a->size; j++) 196 | free_node((void*) idx_arr->arr_ref[j]); 197 | } 198 | } 199 | } 200 | a->size = 0; 201 | } 202 | 203 | void 204 | idxarr_destroy(idx_array_t *a, free_node_fn free_node) { 205 | size_t i, j; 206 | if (!free_node) free_node = __idxarr_free_fn; 207 | for (i = 0; i < a->num_of_index; i++) { 208 | idxarr_array_idx *idx_arr = a->_index_arr_ + i;// * sizeof(idxarr_array_idx); it is not void ptr, not need adjust by size 209 | if (idx_arr->cmp_func) { 210 | if (i == 0) { 211 | for (j = 0; j < a->size; j++) 212 | free_node((void*) idx_arr->arr_ref[j]); 213 | } 214 | } 215 | 216 | __idxarr_free_fn(idx_arr->arr_ref); 217 | } 218 | 219 | __idxarr_free_fn(a->_index_arr_); 220 | __idxarr_free_fn(a); 221 | } 222 | 223 | #ifndef DISABLE_BA_SWAP 224 | void 225 | idxarr_safety_swap(idx_array_t **curr, idx_array_t *new_a, free_node_fn free_node_, unsigned int milisecs) { 226 | /***Proceed Hazard Ptr***/ 227 | idx_array_t *old_a = *curr; 228 | 229 | while (!__sync_bool_compare_and_swap(curr, old_a, new_a)) { 230 | old_a = *curr; 231 | } 232 | // *curr = new_a; 233 | 234 | #ifdef __APPLE__ 235 | usleep(milisecs * 1000); 236 | #else 237 | #pragma GCC diagnostic push 238 | #pragma GCC diagnostic ignored "-Wimplicit-function-declaration" 239 | usleep(milisecs * 1000); 240 | #pragma GCC diagnostic pop 241 | #endif 242 | idxarr_destroy(old_a, free_node_); 243 | 244 | } 245 | #endif 246 | 247 | // int idxarr_add_index_(idx_array_t *a, idxarr_u_long offset, idx_cmp_func cmp_func) { 248 | // if (a && a->num_of_index > 0) { 249 | // size_t i; 250 | // for (i = 0; i < a->num_of_index; i++) { 251 | // if (a->_index_arr_[i].cmp_func == NULL) { 252 | // a->_index_arr_[i].offset = offset; 253 | // a->_index_arr_[i].cmp_func = cmp_func; 254 | // return 1; 255 | // } 256 | // } 257 | // goto ERROR; 258 | // } else { 259 | // ERROR: 260 | // fprintf(stderr, "Running out of index\n"); 261 | // return 0; 262 | // } 263 | 264 | // } 265 | 266 | 267 | void 268 | idxarr_push_idx_ref(idx_array_t *a, void* node) { 269 | size_t i; 270 | for (i = 0; i < a->num_of_index; i++) { 271 | idxarr_insert(a, (unsigned char*)node, i); 272 | } 273 | } 274 | 275 | 276 | int 277 | idxarr_push(idx_array_t *a, void* node) { 278 | if (a->size == a->capacity) { 279 | size_t i; 280 | size_t size_of_ptr = sizeof(idxarr_u_char*); 281 | for (i = 0; i < a->num_of_index; i++) { 282 | idxarr_array_idx *idx_array = a->_index_arr_ + i; //* sizeof(idxarr_array_idx); it is not void ptr, not need adjust by size 283 | idxarr_u_char **new_arr = (idxarr_u_char**) __idxarr_realloc_fn(idx_array->arr_ref, (a->capacity * 2) * size_of_ptr); 284 | if (new_arr == NULL) { 285 | fprintf(stderr, "unable to rellocate more space...\n"); 286 | return 0; 287 | } 288 | idx_array->arr_ref = new_arr; 289 | } 290 | a->capacity *= 2; 291 | } 292 | idxarr_push_idx_ref(a, node); 293 | a->size++; 294 | 295 | return 1; 296 | } 297 | 298 | int 299 | idxarr_push_n(idx_array_t *a, idxarr_u_char* node, idxarr_u_int num) { 300 | idxarr_u_int i; 301 | for (i = 0; i < num; i++) { 302 | idxarr_push(a, (void*) (uintptr_t)node[i]); 303 | } 304 | a->size += num; 305 | 306 | return 1; 307 | } 308 | 309 | idx_array_rs* 310 | idxarr_rs_create(size_t capacity) { 311 | idx_array_rs *rs = (idx_array_rs*) __idxarr_malloc_fn(sizeof(idx_array_rs)); 312 | rs->ptrs = (idxarr_u_char**) __idxarr_malloc_fn(capacity * sizeof(idxarr_u_char*)); 313 | rs->capacity = capacity; 314 | rs->size = 0; 315 | return rs; 316 | } 317 | 318 | int 319 | idxarr_push_rs(idx_array_rs *rs, void* data) { 320 | if (rs->size >= rs->capacity) { 321 | idxarr_u_char** new_rs = (idxarr_u_char**) __idxarr_realloc_fn(rs->ptrs , (rs->capacity * 2) * sizeof(idxarr_u_char*)); 322 | if (new_rs == NULL) { 323 | fprintf(stderr, "NO more allocated space\n"); 324 | return 0; 325 | } 326 | rs->ptrs = new_rs; 327 | rs->capacity *= 2; 328 | } 329 | 330 | rs->ptrs[rs->size++] = (idxarr_u_char*) data; 331 | 332 | return 1; 333 | 334 | } 335 | 336 | /* all the way to highest */ 337 | int 338 | idxarr_push_rs_n(idx_array_rs *rs, idxarr_u_int start_ind, idxarr_u_int width, idxarr_u_char **arr_ref) { 339 | size_t total_added_on = rs->size + width; 340 | if (total_added_on > rs->capacity) { 341 | while (total_added_on > rs->capacity) 342 | rs->capacity *= 2; 343 | 344 | idxarr_u_char** new_rs = (idxarr_u_char**) __idxarr_realloc_fn(rs->ptrs , rs->capacity * sizeof(idxarr_u_char*)); 345 | if (new_rs == NULL) { 346 | fprintf(stderr, "No more allocated space\n"); 347 | return 0; 348 | } 349 | rs->ptrs = new_rs; 350 | } 351 | 352 | memcpy(&rs->ptrs[rs->size], &arr_ref[start_ind], width * sizeof(idxarr_u_char*)); 353 | 354 | rs->size += width; 355 | 356 | return 1; 357 | } 358 | 359 | idx_array_rs* 360 | idxarr_append_rs(idx_array_rs *rs1, idx_array_rs *rs2, bool free_after_merge) { 361 | idxarr_push_rs_n(rs1, 0, rs2->size, rs2->ptrs); 362 | 363 | if (free_after_merge) 364 | idxarr_free_rs(rs2); 365 | 366 | return rs1; 367 | } 368 | 369 | 370 | idx_array_rs* 371 | idxarr_rs_rm_dup_by(idx_array_rs *rs, idxarr_cmp_func cmp_func, bool free_after_merge) { 372 | size_t i, j, count = 0, size = rs->size; 373 | idx_array_rs *group_rs = idxarr_rs_create(size); 374 | for (i = 0; i < size; i++) { 375 | for (j = 0; j < count; j++) { 376 | if (cmp_func(rs->ptrs + i, group_rs->ptrs + j) == 0) 377 | break; 378 | } 379 | if (j == count) { 380 | idxarr_push_rs(group_rs, rs->ptrs[i]); 381 | count++; 382 | } 383 | } 384 | if (free_after_merge && rs != NULL) 385 | idxarr_free_rs(rs); 386 | return group_rs; 387 | } 388 | 389 | void 390 | idxarr_free_rs(idx_array_rs *rs) { 391 | if (rs) { 392 | if (rs->ptrs) __idxarr_free_fn(rs->ptrs); 393 | 394 | rs->size = 0; 395 | rs->capacity = 0; 396 | __idxarr_free_fn(rs); 397 | } 398 | rs = NULL; 399 | } 400 | 401 | idx_array_rs* 402 | idxarr_union_rs(idx_array_rs *rs1, idx_array_rs *rs2, bool free_after_merge) { 403 | idx_array_rs *merged_rs = idxarr_rs_create(__DEFAULT_RS_CAPACITY__); 404 | __union__(rs1, rs2, merged_rs, free_after_merge); 405 | 406 | return merged_rs; 407 | } 408 | 409 | idx_array_rs* 410 | idxarr_intersect_rs(idx_array_rs *rs1, idx_array_rs *rs2, bool free_after_merge) { 411 | idx_array_rs *merged_rs = idxarr_rs_create(__DEFAULT_RS_CAPACITY__); 412 | __intersection__(rs1, rs2, merged_rs, free_after_merge); 413 | 414 | return merged_rs; 415 | } 416 | 417 | /** 418 | ** ref http://www.geeksforgeeks.org/union-and-intersection-of-two-sorted-arrays-2/ 419 | **/ 420 | void 421 | __union__(idx_array_rs *rs1, idx_array_rs *rs2, idx_array_rs *merged_rs, bool free_after_merge) { 422 | size_t size1 = rs1->size, size2 = rs2->size; 423 | size_t i = 0, j = 0; 424 | if ((size1 + size2) > __MIN_ON2_THRESHOLD__ ) { 425 | /* If more than on2 method threshold, please using sorting logic */ 426 | qsort(rs1->ptrs, size1, sizeof(idxarr_u_char*), cmp_idx_rs_uint); 427 | qsort(rs2->ptrs, size2, sizeof(idxarr_u_char*), cmp_idx_rs_uint); 428 | idxarr_u_int *uintptrs1 = rs1->_uintptrs_, *uintptrs2 = rs2->_uintptrs_; 429 | 430 | while (i < size1 && j < size2) 431 | { 432 | if (uintptrs1[i] < uintptrs2[j]) 433 | idxarr_push_rs(merged_rs, (void*) uintptrs1[i++]); 434 | else if (uintptrs2[j] < uintptrs1[i]) 435 | idxarr_push_rs(merged_rs, (void*) uintptrs2[j++]); 436 | else 437 | { 438 | idxarr_push_rs(merged_rs, (void*) uintptrs2[j++]); 439 | i++; 440 | } 441 | } 442 | 443 | while (i < size1) 444 | idxarr_push_rs(merged_rs, (void*) uintptrs1[i++]); 445 | while (j < size2) 446 | idxarr_push_rs(merged_rs, (void*) uintptrs2[j++]); 447 | 448 | 449 | if (free_after_merge) { 450 | idxarr_free_rs(rs1); 451 | idxarr_free_rs(rs2); 452 | } 453 | } else { 454 | idxarr_append_rs(merged_rs, rs1, false); // Do not free the rs1 as still need to merge 455 | idxarr_u_int *uintptrs1 = rs1->_uintptrs_, *uintptrs2 = rs2->_uintptrs_; 456 | for (i = 0; i < size2; i++) { 457 | int found = 0; 458 | for (j = 0; j < size1; j++) { 459 | if (uintptrs2[i] == uintptrs1[j]) { 460 | found = 1; 461 | break; 462 | } 463 | } 464 | if (!found)idxarr_push_rs(merged_rs, (void*) uintptrs2[i]); // if rs2 value not present in merged_rs then add it 465 | } 466 | 467 | if (free_after_merge) { 468 | idxarr_free_rs(rs1); 469 | idxarr_free_rs(rs2); 470 | } 471 | } 472 | } 473 | 474 | void 475 | __intersection__(idx_array_rs *rs1, idx_array_rs *rs2, idx_array_rs *merged_rs, bool free_after_merge) { 476 | size_t size1 = rs1->size, size2 = rs2->size; 477 | size_t i = 0, j = 0; 478 | if ((size1 + size2) > __MIN_ON2_THRESHOLD__ ) { 479 | /* If more than on2 method threshold, please using sorting logic */ 480 | qsort(rs1->ptrs, size1, sizeof(idxarr_u_char*), cmp_idx_rs_uint); 481 | qsort(rs2->ptrs, size2, sizeof(idxarr_u_char*), cmp_idx_rs_uint); 482 | idxarr_u_int *uintptrs1 = rs1->_uintptrs_, *uintptrs2 = rs2->_uintptrs_; 483 | 484 | while ((i < size1) && (j < size2)) 485 | { 486 | if (uintptrs1[i] < uintptrs2[j]) { 487 | i++; 488 | } 489 | else if (uintptrs1[i] > uintptrs2[j]) { 490 | j++; 491 | } 492 | else { 493 | idxarr_push_rs(merged_rs, (void*) uintptrs1[i++]); 494 | j++; 495 | } 496 | } 497 | } else { 498 | idxarr_u_int *uintptrs1 = rs1->_uintptrs_, *uintptrs2 = rs2->_uintptrs_; 499 | for (i = 0; i < size1; i++) { 500 | for (j = 0; j < size2; j++) { 501 | if (uintptrs1[i] == uintptrs2[j]) { 502 | idxarr_push_rs(merged_rs, (void*) uintptrs1[i]); 503 | break; 504 | } 505 | } 506 | } 507 | } 508 | 509 | // clean the previous result 510 | if (free_after_merge) { 511 | idxarr_free_rs(rs1); 512 | idxarr_free_rs(rs2); 513 | } 514 | } 515 | 516 | -------------------------------------------------------------------------------- /indexed_array.h: -------------------------------------------------------------------------------- 1 | #ifndef _HEADER_IDX_ARRAY_T_ 2 | #define _HEADER_IDX_ARRAY_T_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define idxarr_u_char unsigned char 18 | #define idxarr_u_long unsigned long 19 | #define idxarr_u_int uintptr_t 20 | 21 | #define __DEFAULT_RS_CAPACITY__ 10 22 | #define __MIN_ON2_THRESHOLD__ 80 23 | 24 | typedef enum { idxarr_eq, idxarr_gt, idxarr_lt } idxarr_condtion; 25 | typedef enum { 26 | idxarr_sstr_dataType, // stack string 27 | idxarr_hstr_dataType, // heap string 28 | idxarr_int_dataType, 29 | idxarr_long_dataType, 30 | idxarr_float_dataType, 31 | idxarr_double_dataType, 32 | idxarr_char_dataType 33 | } idxarr_data_type; 34 | 35 | typedef void* (*idxarr_malloc_fn)(size_t); 36 | typedef void* (*idxarr_realloc_fn)(void*, size_t); 37 | typedef void (*idxarr_free_fn)(void*); 38 | 39 | static idxarr_malloc_fn __idxarr_malloc_fn = malloc; 40 | 41 | __attribute__((unused)) 42 | static idxarr_realloc_fn __idxarr_realloc_fn = realloc; 43 | __attribute__((unused)) 44 | static idxarr_free_fn __idxarr_free_fn = free; 45 | 46 | #define __idx_is_valid_string__(_idx_elt__) ({ sizeof(*_idx_elt__) == sizeof(char)? 1: 0; }) 47 | 48 | typedef int (*idxarr_cmp_func)(const void*, const void*); 49 | 50 | 51 | #ifdef __APPLE__ 52 | typedef int (^idx_cmp_func)(const void*, const void*); 53 | #else 54 | typedef int (*idx_cmp_func)(const void*, const void*); 55 | #endif 56 | 57 | 58 | typedef void (*free_node_fn)(void*); 59 | 60 | 61 | typedef struct { 62 | union { 63 | void *elt; 64 | char ckey; 65 | const char *skey; 66 | int ikey; 67 | long lkey; 68 | float fkey; 69 | double dkey; 70 | }; 71 | size_t klen; 72 | } __idxarr_args_with_meta__; 73 | 74 | typedef struct { 75 | size_t size; 76 | union { 77 | idxarr_u_char **ptrs; 78 | idxarr_u_int *_uintptrs_; // for internal merging 79 | }; 80 | size_t capacity; 81 | } idx_array_rs; 82 | 83 | typedef struct { 84 | union { 85 | idxarr_u_char **arr_ref; 86 | idxarr_u_int *uintptr_arr; 87 | }; 88 | idxarr_u_long offset; 89 | idxarr_data_type dtype; 90 | idx_cmp_func cmp_func; 91 | } idxarr_array_idx; 92 | 93 | typedef struct { 94 | idxarr_u_int size; 95 | idxarr_u_int capacity; 96 | 97 | idxarr_u_int num_of_index; 98 | idxarr_array_idx * _index_arr_; 99 | } idx_array_t; 100 | 101 | idx_array_t *idxarr_create(idxarr_u_int size, idxarr_u_int num_of_index); 102 | void idxarr_clear(idx_array_t *a, free_node_fn free_node); 103 | void idxarr_destroy(idx_array_t *a, free_node_fn free_node); 104 | #ifndef DISABLE_BA_SWAP 105 | void idxarr_safety_swap(idx_array_t **curr, idx_array_t *new_a, free_node_fn free_node, unsigned int buffer_time_sec); 106 | #endif 107 | idxarr_u_char ** idxarr_get_index_array(idx_array_t *a, idxarr_u_int index_num); 108 | 109 | int idxarr_push(idx_array_t *a, void* node); 110 | int idxarr_push_n(idx_array_t *a, idxarr_u_char* node, idxarr_u_int num); 111 | 112 | #ifdef __APPLE__ 113 | #define idxarr_get_int_cmp_func(__struct_type__, __field__)({\ 114 | idx_cmp_func __f__ = ^int(const void* a, const void *b){\ 115 | int __arg__ = *(int*)a;\ 116 | __struct_type__ *__b__ = (__struct_type__*)b;\ 117 | if (__arg__ > __b__->__field__) return 1;\ 118 | if (__arg__ < __b__->__field__) return -1;\ 119 | return 0;\ 120 | };\ 121 | __f__;}) 122 | #define idxarr_get_long_cmp_func(__struct_type__, __field__)({\ 123 | idx_cmp_func __f__ = ^int(const void* a, const void *b){\ 124 | long __arg__ = *(long*)a;\ 125 | __struct_type__ *__b__ = (__struct_type__*)b;\ 126 | if (__arg__ > __b__->__field__) return 1;\ 127 | if (__arg__ < __b__->__field__) return -1;\ 128 | return 0;\ 129 | };\ 130 | __f__;}) 131 | #define idxarr_get_float_cmp_func(__struct_type__, __field__)({\ 132 | idx_cmp_func __f__ = ^int(const void* a, const void *b){\ 133 | float __arg__ = *(float*)a;\ 134 | __struct_type__ *__b__ = (__struct_type__*)b;\ 135 | if (__arg__ > __b__->__field__) return 1;\ 136 | if (__arg__ < __b__->__field__) return -1;\ 137 | return 0;\ 138 | };\ 139 | __f__;}) 140 | #define idxarr_get_double_cmp_func(__struct_type__, __field__)({\ 141 | idx_cmp_func __f__;\ 142 | __f__ = ^int(const void* a, const void *b){\ 143 | double __arg__ = *(double*)a;\ 144 | __struct_type__ *__b__ = (__struct_type__*)b;\ 145 | if (__arg__ > __b__->__field__) return 1;\ 146 | if (__arg__ < __b__->__field__) return -1;\ 147 | return 0;\ 148 | };\ 149 | __f__;}) 150 | #define idxarr_get_char_cmp_func(__struct_type__, __field__)({\ 151 | idx_cmp_func __f__;\ 152 | __f__ = ^int(const void* a, const void *b){\ 153 | char __arg__ = *(char*)a;\ 154 | __struct_type__ *__b__ = (__struct_type__*)b;\ 155 | if (__arg__ > __b__->__field__) return 1;\ 156 | if (__arg__ < __b__->__field__) return -1;\ 157 | return 0;\ 158 | };\ 159 | __f__;}) 160 | #define idxarr_get_str_cmp_func(__struct_type__, __field__)({\ 161 | idx_cmp_func __f__;\ 162 | __f__ = ^int(const void* a, const void *b){\ 163 | const char *__arg__ = (const char *)a;\ 164 | __struct_type__ *__b__ = (__struct_type__*)b;\ 165 | return strcmp(__arg__, __b__->__field__);\ 166 | };\ 167 | __f__;}) 168 | #else 169 | 170 | #ifdef __cplusplus 171 | 172 | #define idxarr_get_int_cmp_func(__struct_type__, __field__)({\ 173 | idx_cmp_func __f__ = [&](const void*a,const void* b) -> int {\ 174 | int __arg__ = *(int*)a;\ 175 | __struct_type__ *__b__ = (__struct_type__*)b;\ 176 | if (__arg__ > __b__->__field__) return 1;\ 177 | if (__arg__ < __b__->__field__) return -1;\ 178 | return 0;\ 179 | };\ 180 | __f__;}) 181 | #define idxarr_get_long_cmp_func(__struct_type__, __field__)({\ 182 | idx_cmp_func __f__ = [&](const void*a,const void* b) -> int {\ 183 | long __arg__ = *(long*)a;\ 184 | __struct_type__ *__b__ = (__struct_type__*)b;\ 185 | if (__arg__ > __b__->__field__) return 1;\ 186 | if (__arg__ < __b__->__field__) return -1;\ 187 | return 0;\ 188 | };\ 189 | __f__;}) 190 | #define idxarr_get_float_cmp_func(__struct_type__, __field__)({\ 191 | idx_cmp_func __f__ = [&](const void*a,const void* b) -> int {\ 192 | float __arg__ = *(float*)a;\ 193 | __struct_type__ *__b__ = (__struct_type__*)b;\ 194 | if (__arg__ > __b__->__field__) return 1;\ 195 | if (__arg__ < __b__->__field__) return -1;\ 196 | return 0;\ 197 | };\ 198 | __f__;}) 199 | #define idxarr_get_double_cmp_func(__struct_type__, __field__)({\ 200 | idx_cmp_func __f__ = [&](const void*a,const void* b) -> int {\ 201 | double __arg__ = *(double*)a;\ 202 | __struct_type__ *__b__ = (__struct_type__*)b;\ 203 | if (__arg__ > __b__->__field__) return 1;\ 204 | if (__arg__ < __b__->__field__) return -1;\ 205 | return 0;\ 206 | };\ 207 | __f__;}) 208 | #define idxarr_get_char_cmp_func(__struct_type__, __field__)({\ 209 | idx_cmp_func __f__ = [&](const void*a,const void* b) -> int {\ 210 | char __arg__ = *(char*)a;\ 211 | __struct_type__ *__b__ = (__struct_type__*)b;\ 212 | if (__arg__ > __b__->__field__) return 1;\ 213 | if (__arg__ < __b__->__field__) return -1;\ 214 | return 0;\ 215 | };\ 216 | __f__;}) 217 | #define idxarr_get_str_cmp_func(__struct_type__, __field__)({\ 218 | idx_cmp_func __f__ = [&](const void*a,const void* b) -> int {\ 219 | const char *__arg__ = (const char *)a;\ 220 | __struct_type__ *__b__ = (__struct_type__*)b;\ 221 | return strcmp(__arg__, __b__->__field__);\ 222 | };\ 223 | __f__;}) 224 | 225 | #else// C compiler 226 | 227 | #define idxarr_get_int_cmp_func(__struct_type__, __field__)({\ 228 | idx_cmp_func __f__;\ 229 | __f__ =\ 230 | ({\ 231 | int __fn__ (const void* a, const void *b) {\ 232 | int __arg__ = *(int*)a;\ 233 | __struct_type__ *__b__ = (__struct_type__*)b;\ 234 | if (__arg__ > __b__->__field__) return 1;\ 235 | if (__arg__ < __b__->__field__) return -1;\ 236 | return 0;\ 237 | }\ 238 | __fn__;\ 239 | });\ 240 | __f__;}) 241 | #define idxarr_get_long_cmp_func(__struct_type__, __field__)({\ 242 | idx_cmp_func __f__;\ 243 | __f__ =\ 244 | ({\ 245 | int __fn__ (const void* a, const void *b) {\ 246 | long __arg__ = *(long*)a;\ 247 | __struct_type__ *__b__ = (__struct_type__*)b;\ 248 | if (__arg__ > __b__->__field__) return 1;\ 249 | if (__arg__ < __b__->__field__) return -1;\ 250 | return 0;\ 251 | }\ 252 | __fn__;\ 253 | });\ 254 | __f__;}) 255 | #define idxarr_get_float_cmp_func(__struct_type__, __field__)({\ 256 | idx_cmp_func __f__;\ 257 | __f__ =\ 258 | ({\ 259 | int __fn__ (const void* a, const void *b) {\ 260 | float __arg__ = *(float*)a;\ 261 | __struct_type__ *__b__ = (__struct_type__*)b;\ 262 | if (__arg__ > __b__->__field__) return 1;\ 263 | if (__arg__ < __b__->__field__) return -1;\ 264 | return 0;\ 265 | }\ 266 | __fn__;\ 267 | });\ 268 | __f__;}) 269 | #define idxarr_get_double_cmp_func(__struct_type__, __field__)({\ 270 | idx_cmp_func __f__;\ 271 | __f__ =\ 272 | ({\ 273 | int __fn__ (const void* a, const void *b) {\ 274 | double __arg__ = *(double*)a;\ 275 | __struct_type__ *__b__ = (__struct_type__*)b;\ 276 | if (__arg__ > __b__->__field__) return 1;\ 277 | if (__arg__ < __b__->__field__) return -1;\ 278 | return 0;\ 279 | }\ 280 | __fn__;\ 281 | });\ 282 | __f__;}) 283 | #define idxarr_get_char_cmp_func(__struct_type__, __field__)({\ 284 | idx_cmp_func __f__;\ 285 | __f__ =\ 286 | ({\ 287 | int __fn__ (const void* a, const void *b) {\ 288 | char __arg__ = *(char*)a;\ 289 | __struct_type__ *__b__ = (__struct_type__*)b;\ 290 | if (__arg__ > __b__->__field__) return 1;\ 291 | if (__arg__ < __b__->__field__) return -1;\ 292 | return 0;\ 293 | }\ 294 | __fn__;\ 295 | });\ 296 | __f__;}) 297 | #define idxarr_get_str_cmp_func(__struct_type__, __field__)({\ 298 | idx_cmp_func __f__;\ 299 | __f__ =\ 300 | ({\ 301 | int __fn__ (const void* a, const void *b) {\ 302 | const char *__arg__ = (const char *)a;\ 303 | __struct_type__ *__b__ = (__struct_type__*)b;\ 304 | return strcmp(__arg__, __b__->__field__);\ 305 | }\ 306 | __fn__;\ 307 | });\ 308 | __f__;}) 309 | #endif 310 | 311 | #endif 312 | 313 | #define idxarr_add_int_index(__a__, __struct_type__, __field_member__)({\ 314 | int status = 0;\ 315 | if(__a__ && __a__->num_of_index > 0) {\ 316 | size_t i;\ 317 | for (i = 0; i < __a__->num_of_index; i++) {\ 318 | if (__a__->_index_arr_[i].cmp_func == NULL) {\ 319 | __a__->_index_arr_[i].offset = offsetof(__struct_type__, __field_member__);\ 320 | __a__->_index_arr_[i].dtype = idxarr_int_dataType;\ 321 | __a__->_index_arr_[i].cmp_func = idxarr_get_int_cmp_func(__struct_type__, __field_member__);\ 322 | status = 1;\ 323 | break;\ 324 | }}}\ 325 | status;}) 326 | #define idxarr_add_long_index(__a__, __struct_type__, __field_member__)({\ 327 | int status = 0;\ 328 | if(__a__ && __a__->num_of_index > 0) {\ 329 | size_t i;\ 330 | for (i = 0; i < __a__->num_of_index; i++) {\ 331 | if (__a__->_index_arr_[i].cmp_func == NULL) {\ 332 | __a__->_index_arr_[i].offset = offsetof(__struct_type__, __field_member__);\ 333 | __a__->_index_arr_[i].dtype = idxarr_long_dataType;\ 334 | __a__->_index_arr_[i].cmp_func = idxarr_get_long_cmp_func(__struct_type__, __field_member__);\ 335 | status = 1;\ 336 | break;\ 337 | }}}\ 338 | status;}) 339 | #define idxarr_add_float_index(__a__, __struct_type__, __field_member__)({\ 340 | int status = 0;\ 341 | if(__a__ && __a__->num_of_index > 0) {\ 342 | size_t i;\ 343 | for (i = 0; i < __a__->num_of_index; i++) {\ 344 | if (__a__->_index_arr_[i].cmp_func == NULL) {\ 345 | __a__->_index_arr_[i].offset = offsetof(__struct_type__, __field_member__);\ 346 | __a__->_index_arr_[i].dtype = idxarr_float_dataType;\ 347 | __a__->_index_arr_[i].cmp_func = idxarr_get_float_cmp_func(__struct_type__, __field_member__);\ 348 | status = 1;\ 349 | break;\ 350 | }}}\ 351 | status;}) 352 | #define idxarr_add_double_index(__a__, __struct_type__, __field_member__)({\ 353 | int status = 0;\ 354 | if(__a__ && __a__->num_of_index > 0) {\ 355 | size_t i;\ 356 | for (i = 0; i < __a__->num_of_index; i++) {\ 357 | if (__a__->_index_arr_[i].cmp_func == NULL) {\ 358 | __a__->_index_arr_[i].offset = offsetof(__struct_type__, __field_member__);\ 359 | __a__->_index_arr_[i].dtype = idxarr_double_dataType;\ 360 | __a__->_index_arr_[i].cmp_func = idxarr_get_double_cmp_func(__struct_type__, __field_member__);\ 361 | status = 1;\ 362 | break;\ 363 | }}}\ 364 | status;}) 365 | #define idxarr_add_char_index(__a__, __struct_type__, __field_member__)({\ 366 | int status = 0;\ 367 | if(__a__ && __a__->num_of_index > 0) {\ 368 | size_t i;\ 369 | for (i = 0; i < __a__->num_of_index; i++) {\ 370 | if (__a__->_index_arr_[i].cmp_func == NULL) {\ 371 | __a__->_index_arr_[i].offset = offsetof(__struct_type__, __field_member__);\ 372 | __a__->_index_arr_[i].dtype = idxarr_char_dataType;\ 373 | __a__->_index_arr_[i].cmp_func = idxarr_get_char_cmp_func(__struct_type__, __field_member__);\ 374 | status = 1;\ 375 | break;\ 376 | }}}\ 377 | status;}) 378 | #define idxarr_add_heap_str_index(__a__, __struct_type__, __field_member__)({\ 379 | int status = 0;\ 380 | if(__a__ && __a__->num_of_index > 0) {\ 381 | size_t i;\ 382 | for (i = 0; i < __a__->num_of_index; i++) {\ 383 | if (__a__->_index_arr_[i].cmp_func == NULL) {\ 384 | __a__->_index_arr_[i].offset = offsetof(__struct_type__, __field_member__);\ 385 | __a__->_index_arr_[i].dtype = idxarr_hstr_dataType;\ 386 | __a__->_index_arr_[i].cmp_func = idxarr_get_str_cmp_func(__struct_type__, __field_member__);\ 387 | status = 1;\ 388 | break;\ 389 | }}}\ 390 | status;}) 391 | #define idxarr_add_stack_str_index(__a__, __struct_type__, __field_member__)({\ 392 | int status = 0;\ 393 | if(__a__ && __a__->num_of_index > 0) {\ 394 | size_t i;\ 395 | for (i = 0; i < __a__->num_of_index; i++) {\ 396 | if (__a__->_index_arr_[i].cmp_func == NULL) {\ 397 | __a__->_index_arr_[i].offset = offsetof(__struct_type__, __field_member__);\ 398 | __a__->_index_arr_[i].dtype = idxarr_sstr_dataType;\ 399 | __a__->_index_arr_[i].cmp_func = idxarr_get_str_cmp_func(__struct_type__, __field_member__);\ 400 | status = 1;\ 401 | break;\ 402 | }}}\ 403 | status;}) 404 | 405 | 406 | #define idxarr_sort_rs_by(__rs__, __cmp_func__) \ 407 | qsort(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __cmp_func__) 408 | 409 | #define idxarr_sort_rs_by_b(__rs__, __cmp_func__) \ 410 | qsort_b(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __cmp_func__) 411 | 412 | /** Algorithm **/ 413 | long basearch_index_eq_(register const void *key, idxarr_u_char **base, size_t num, register idx_cmp_func cmp); 414 | long basearch_index_gt_(register const void *key, idxarr_u_char **base, size_t num, register idx_cmp_func cmp); 415 | long basearch_index_lt_(register const void *key, idxarr_u_char **base, size_t num, register idx_cmp_func cmp); 416 | idx_array_rs* basearch_index_by_func(const char *key, idx_array_t *a, idxarr_u_long offset, idx_cmp_func cmp_func); 417 | 418 | /** Result Merging other result **/ 419 | idx_array_rs* idxarr_rs_create(size_t capacity); 420 | int idxarr_push_rs(idx_array_rs *rs, void* data); 421 | int idxarr_push_rs_n(idx_array_rs *rs, idxarr_u_int start_ind, idxarr_u_int width, idxarr_u_char **arr_ref); 422 | idx_array_rs* idxarr_rs_rm_dup_by(idx_array_rs *rs, idxarr_cmp_func cmp_func, bool free_after_merge); 423 | idx_array_rs* idxarr_union_rs(idx_array_rs *rs1, idx_array_rs *rs2, bool free_after_merge); 424 | idx_array_rs* idxarr_intersect_rs(idx_array_rs *rs1, idx_array_rs *rs2, bool free_after_merge); 425 | idx_array_rs* idxarr_append_rs(idx_array_rs *rs1, idx_array_rs *rs2, bool free_after_merge); 426 | void idxarr_free_rs(idx_array_rs *rs); 427 | 428 | /** Result Sorting Asc and Desc **/ 429 | #ifdef __APPLE__ 430 | #define idxarr_search_str_start_with(__a__, __struct_type__, __field_member__, __key__)({\ 431 | assert(__idx_is_valid_string__(__key__) && "please do not need to dereference your string, it is already a pointer.");\ 432 | idx_cmp_func __f__ = ^int(const void *a, const void *b){\ 433 | __idxarr_args_with_meta__ *key_arg = (__idxarr_args_with_meta__*)a;\ 434 | __struct_type__ *__b__ = (__struct_type__*)b;\ 435 | return strncmp(key_arg->skey, __b__->__field_member__, key_arg->klen);\ 436 | };\ 437 | basearch_index_by_func(__key__, __a__, offsetof(__struct_type__, __field_member__), __f__);\ 438 | }) 439 | #define idxarr_sort_rs(__rs__, __struct_type__, __field__, __is_string_data_type__) ({\ 440 | if(__is_string_data_type__){\ 441 | idx_cmp_func __f__ = ^int(const void *a, const void *b){\ 442 | __struct_type__ *__a__ = *(__struct_type__**)a;\ 443 | __struct_type__ *__b__ = *(__struct_type__**)b;\ 444 | return strcmp((const char*)(uintptr_t)__a__->__field__, (const char*)(uintptr_t)__b__->__field__);\ 445 | };\ 446 | qsort_b(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 447 | }else{\ 448 | idx_cmp_func __f__ = ^int(const void *a, const void *b){\ 449 | __struct_type__ *__a__ = *(__struct_type__**)a;\ 450 | __struct_type__ *__b__ = *(__struct_type__**)b;\ 451 | if (__a__->__field__ > __b__->__field__) return 1;\ 452 | if (__a__->__field__ < __b__->__field__) return -1;\ 453 | return 0;\ 454 | };\ 455 | qsort_b(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 456 | }\ 457 | }) 458 | 459 | #define idxarr_sort_rs_desc(__rs__, __struct_type__, __field__, __is_string_data_type__) ({\ 460 | if(__is_string_data_type__){\ 461 | idx_cmp_func __f__ = ^int(const void *a, const void *b){\ 462 | __struct_type__ *__a__ = *(__struct_type__**)b;\ 463 | __struct_type__ *__b__ = *(__struct_type__**)a;\ 464 | return strcmp((const char*)(uintptr_t)__a__->__field__, (const char*)(uintptr_t)__b__->__field__);\ 465 | };\ 466 | qsort_b(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 467 | }else{\ 468 | idx_cmp_func __f__ = ^int(const void *a, const void *b){\ 469 | __struct_type__ *__a__ = *(__struct_type__**)b;\ 470 | __struct_type__ *__b__ = *(__struct_type__**)a;\ 471 | if (__a__->__field__ > __b__->__field__) return 1;\ 472 | if (__a__->__field__ < __b__->__field__) return -1;\ 473 | return 0;\ 474 | };\ 475 | qsort_b(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 476 | }\ 477 | }) 478 | #else // Linux OS or windows os 479 | #ifdef __cplusplus 480 | 481 | #define idxarr_search_str_start_with(__a__, __struct_type__, __field_member__, __key__)({\ 482 | assert(__idx_is_valid_string__(__key__) && "please do not need to dereference your string, it is already a pointer.");\ 483 | idx_cmp_func __f__ = [&](const void*a, const void*b) -> int {\ 484 | __idxarr_args_with_meta__ *key_arg = (__idxarr_args_with_meta__*)a;\ 485 | __struct_type__ *__b__ = (__struct_type__*)b;\ 486 | return strncmp(key_arg->skey, __b__->__field_member__, key_arg->klen);\ 487 | };\ 488 | basearch_index_by_func(__key__, __a__, offsetof(__struct_type__, __field_member__), __f__);\ 489 | }) 490 | 491 | #define idxarr_sort_rs(__rs__, __struct_type__, __field__, __is_string_data_type__) ({\ 492 | if(__is_string_data_type__){\ 493 | idx_cmp_func __f__ = [&](const void*a, const void*b) -> int {\ 494 | __struct_type__ *__a__ = *(__struct_type__**)a;\ 495 | __struct_type__ *__b__ = *(__struct_type__**)b;\ 496 | return strcmp((const char*)(uintptr_t)__a__->__field__, (const char*)(uintptr_t)__b__->__field__);\ 497 | };\ 498 | qsort(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 499 | }else{\ 500 | idx_cmp_func __f__ = [&](const void*a, const void*b) -> int {\ 501 | __struct_type__ *__a__ = *(__struct_type__**)a;\ 502 | __struct_type__ *__b__ = *(__struct_type__**)b;\ 503 | if (__a__->__field__ > __b__->__field__) return 1;\ 504 | if (__a__->__field__ < __b__->__field__) return -1;\ 505 | return 0;\ 506 | };\ 507 | qsort(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 508 | }\ 509 | }) 510 | 511 | #define idxarr_sort_rs_desc(__rs__, __struct_type__, __field__, __is_string_data_type__) ({\ 512 | if(__is_string_data_type__){\ 513 | idx_cmp_func __f__ = [&](const void*a, const void*b) -> int {\ 514 | __struct_type__ *__a__ = *(__struct_type__**)b;\ 515 | __struct_type__ *__b__ = *(__struct_type__**)a;\ 516 | return strcmp((const char*)(uintptr_t)__a__->__field__, (const char*)(uintptr_t)__b__->__field__);\ 517 | };\ 518 | qsort(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 519 | }else{\ 520 | idx_cmp_func __f__ = [&](const void*a, const void*b) -> int {\ 521 | __struct_type__ *__a__ = *(__struct_type__**)b;\ 522 | __struct_type__ *__b__ = *(__struct_type__**)a;\ 523 | if (__a__->__field__ > __b__->__field__) return 1;\ 524 | if (__a__->__field__ < __b__->__field__) return -1;\ 525 | return 0;\ 526 | };\ 527 | qsort(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 528 | }\ 529 | }) 530 | #else// C compiler 531 | #define idxarr_search_str_start_with(__a__, __struct_type__, __field_member__, __key__)({\ 532 | assert(__idx_is_valid_string__(__key__) && "please do not need to dereference your string, it is already a pointer.");\ 533 | idx_cmp_func __f__ = ({\ 534 | int __fn__ (const void *a, const void *b) {\ 535 | __idxarr_args_with_meta__ *key_arg = (__idxarr_args_with_meta__*)a;\ 536 | __struct_type__ *__b__ = (__struct_type__*)b;\ 537 | return strncmp(key_arg->skey, __b__->__field_member__, key_arg->klen);\ 538 | }\ 539 | __fn__;\ 540 | });\ 541 | basearch_index_by_func(__key__, __a__, offsetof(__struct_type__, __field_member__), __f__);\ 542 | }) 543 | #define idxarr_sort_rs(__rs__, __struct_type__, __field__, __is_string_data_type__) ({\ 544 | if(__is_string_data_type__){\ 545 | idx_cmp_func __f__ =\ 546 | ({\ 547 | int __fn__ (const void *a, const void *b) {\ 548 | __struct_type__ *__a__ = *(__struct_type__**)a;\ 549 | __struct_type__ *__b__ = *(__struct_type__**)b;\ 550 | return strcmp((const char*)(uintptr_t)__a__->__field__, (const char*)(uintptr_t)__b__->__field__);\ 551 | }\ 552 | __fn__;\ 553 | });\ 554 | qsort(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 555 | }else{\ 556 | idx_cmp_func __f__ =\ 557 | ({\ 558 | int __fn__ (const void *a, const void *b) {\ 559 | __struct_type__ *__a__ = *(__struct_type__**)a;\ 560 | __struct_type__ *__b__ = *(__struct_type__**)b;\ 561 | if (__a__->__field__ > __b__->__field__) return 1;\ 562 | if (__a__->__field__ < __b__->__field__) return -1;\ 563 | return 0;\ 564 | }\ 565 | __fn__;\ 566 | });\ 567 | qsort(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 568 | }\ 569 | }) 570 | 571 | #define idxarr_sort_rs_desc(__rs__, __struct_type__, __field__, __is_string_data_type__) ({\ 572 | if(__is_string_data_type__){\ 573 | idx_cmp_func __f__ =\ 574 | ({\ 575 | int __fn__ (const void *a, const void *b) {\ 576 | __struct_type__ *__a__ = *(__struct_type__**)b;\ 577 | __struct_type__ *__b__ = *(__struct_type__**)a;\ 578 | return strcmp((const char*)(uintptr_t)__a__->__field__, (const char*)(uintptr_t)__b__->__field__);\ 579 | }\ 580 | __fn__;\ 581 | });\ 582 | qsort(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 583 | }else{\ 584 | idx_cmp_func __f__ =\ 585 | ({\ 586 | int __fn__ (const void *a, const void *b) {\ 587 | __struct_type__ *__a__ = *(__struct_type__**)b;\ 588 | __struct_type__ *__b__ = *(__struct_type__**)a;\ 589 | if (__a__->__field__ > __b__->__field__) return 1;\ 590 | if (__a__->__field__ < __b__->__field__) return -1;\ 591 | return 0;\ 592 | }\ 593 | __fn__;\ 594 | });\ 595 | qsort(__rs__->ptrs, __rs__->size, sizeof(idxarr_u_char*), __f__);\ 596 | }\ 597 | }) 598 | 599 | #endif 600 | 601 | #endif 602 | /** End Result Sorting Acs And Desc **/ 603 | 604 | #define basearch_direct_one(__key__, __a__, __offset__)({\ 605 | size_t i;\ 606 | void *rt=NULL;\ 607 | idxarr_array_idx *arr_idx;\ 608 | long asize, lt_ind, gt_ind;\ 609 | for (i = 0; i < __a__->num_of_index; i++) {\ 610 | if (__a__->_index_arr_[i].cmp_func != NULL && __a__->_index_arr_[i].offset == __offset__) {\ 611 | arr_idx = __a__->_index_arr_ + i;\ 612 | asize = __a__->size;\ 613 | lt_ind = basearch_index_lt_(__key__, arr_idx->arr_ref, asize, arr_idx->cmp_func);\ 614 | gt_ind = basearch_index_gt_(__key__, arr_idx->arr_ref, asize, arr_idx->cmp_func);\ 615 | if ( lt_ind >= asize || gt_ind <= 0 || gt_ind - lt_ind < 2) {\ 616 | break;\ 617 | }\ 618 | if (lt_ind < 0)\ 619 | lt_ind = 0;\ 620 | else lt_ind++;\ 621 | if (lt_ind >= 0 && lt_ind < asize) {\ 622 | rt = arr_idx->arr_ref[lt_ind];\ 623 | }\ 624 | }\ 625 | }\ 626 | rt;\ 627 | }) 628 | 629 | #define basearch_index(__key__, __a__, __offset__, __cond__)({\ 630 | size_t i;\ 631 | idxarr_array_idx *arr_idx;\ 632 | long asize;\ 633 | idx_array_rs *arr_rs = idxarr_rs_create(__DEFAULT_RS_CAPACITY__);\ 634 | for (i = 0; i < __a__->num_of_index; i++) {\ 635 | if (__a__->_index_arr_[i].cmp_func != NULL && __a__->_index_arr_[i].offset == __offset__) {\ 636 | arr_idx = __a__->_index_arr_ + i;\ 637 | long index, lt_ind, gt_ind;\ 638 | if (arr_idx->dtype == idxarr_hstr_dataType || arr_idx->dtype == idxarr_sstr_dataType) {\ 639 | assert(__idx_is_valid_string__(__key__) && "please do not need to dereference your string, it is already a pointer.");\ 640 | }\ 641 | switch (__cond__) {\ 642 | case idxarr_eq:\ 643 | asize = __a__->size;\ 644 | lt_ind = basearch_index_lt_(__key__, arr_idx->arr_ref, asize, arr_idx->cmp_func);\ 645 | gt_ind = basearch_index_gt_(__key__, arr_idx->arr_ref, asize, arr_idx->cmp_func);\ 646 | if ( lt_ind >= asize || gt_ind <= 0 || gt_ind - lt_ind < 2) {\ 647 | break;\ 648 | }\ 649 | if (lt_ind < 0)\ 650 | lt_ind = 0;\ 651 | else lt_ind++;\ 652 | if (gt_ind >= asize)\ 653 | gt_ind = asize;\ 654 | idxarr_push_rs_n(arr_rs, lt_ind, gt_ind - lt_ind, arr_idx->arr_ref);\ 655 | break;\ 656 | case idxarr_gt:\ 657 | asize = __a__->size;\ 658 | index = basearch_index_gt_(__key__, arr_idx->arr_ref, asize, arr_idx->cmp_func);\ 659 | if (index >= 0 && index < asize) {\ 660 | idxarr_push_rs_n(arr_rs, index, asize - index, arr_idx->arr_ref);\ 661 | }\ 662 | break;\ 663 | case idxarr_lt:\ 664 | asize = __a__->size;\ 665 | index = basearch_index_lt_(__key__, arr_idx->arr_ref, asize, arr_idx->cmp_func);\ 666 | if (index >= 0 && index < asize) {\ 667 | idxarr_push_rs_n(arr_rs, 0, index + 1, arr_idx->arr_ref);\ 668 | }\ 669 | break;\ 670 | default:\ 671 | break;\ 672 | }\ 673 | break;\ 674 | }\ 675 | }\ 676 | arr_rs;\ 677 | }) 678 | 679 | #define idxarr_search_one(__a__, __struct_type__, __field_member__, __key__)\ 680 | basearch_direct_one(__key__, __a__, offsetof(__struct_type__, __field_member__)) 681 | 682 | #define idxarr_search_eq(__a__, __struct_type__, __field_member__, __key__)\ 683 | basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq) 684 | 685 | #define idxarr_search_lt(__a__, __struct_type__, __field_member__, __key__)\ 686 | basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_lt) 687 | 688 | #define idxarr_search_gt(__a__, __struct_type__, __field_member__, __key__)\ 689 | basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_gt) 690 | 691 | 692 | 693 | 694 | /*** For multiple eq query scope ***/ 695 | 696 | #define idxarr_search_multi_eq2(__a__, __struct_type__, __field_member__, __key__, ...) ({\ 697 | idx_array_rs *__rs1__ = basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 698 | idx_array_rs *__rs2__ = basearch_index(__VA_ARGS__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 699 | idx_array_rs *__rs10__ = idxarr_union_rs(__rs1__, __rs2__, true);\ 700 | __rs10__;}) 701 | 702 | #define idxarr_search_multi_eq3(__a__, __struct_type__, __field_member__, __key__, ...) ({\ 703 | idx_array_rs *__rs1__ = basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 704 | idx_array_rs *__rs2__ = idxarr_search_multi_eq2(__a__, __struct_type__, __field_member__, __VA_ARGS__);\ 705 | idx_array_rs *__rs10__ = idxarr_union_rs(__rs1__, __rs2__, true);\ 706 | __rs10__;}) 707 | 708 | 709 | #define idxarr_search_multi_eq4(__a__, __struct_type__, __field_member__, __key__, ...) ({\ 710 | idx_array_rs *__rs1__ = basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 711 | idx_array_rs *__rs2__ = idxarr_search_multi_eq3(__a__, __struct_type__, __field_member__, __VA_ARGS__);\ 712 | idx_array_rs *__rs10__ = idxarr_union_rs(__rs1__, __rs2__, true);\ 713 | __rs10__;}) 714 | 715 | #define idxarr_search_multi_eq5(__a__, __struct_type__, __field_member__, __key__, ...) ({\ 716 | idx_array_rs *__rs1__ = basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 717 | idx_array_rs *__rs2__ = idxarr_search_multi_eq4(__a__, __struct_type__, __field_member__, __VA_ARGS__);\ 718 | idx_array_rs *__rs10__ = idxarr_union_rs(__rs1__, __rs2__, true);\ 719 | __rs10__;}) 720 | 721 | #define idxarr_search_multi_eq6(__a__, __struct_type__, __field_member__, __key__, ...) ({\ 722 | idx_array_rs *__rs1__ = basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 723 | idx_array_rs *__rs2__ = idxarr_search_multi_eq5(__a__, __struct_type__, __field_member__, __VA_ARGS__);\ 724 | idx_array_rs *__rs10__ = idxarr_union_rs(__rs1__, __rs2__, true);\ 725 | __rs10__;}) 726 | 727 | #define idxarr_search_multi_eq7(__a__, __struct_type__, __field_member__, __key__, ...) ({\ 728 | idx_array_rs *__rs1__ = basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 729 | idx_array_rs *__rs2__ = idxarr_search_multi_eq6(__a__, __struct_type__, __field_member__, __VA_ARGS__);\ 730 | idx_array_rs *__rs10__ = idxarr_union_rs(__rs1__, __rs2__, true);\ 731 | __rs10__;}) 732 | 733 | #define idxarr_search_multi_eq8(__a__, __struct_type__, __field_member__, __key__, ...) ({\ 734 | idx_array_rs *__rs1__ = basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 735 | idx_array_rs *__rs2__ = idxarr_search_multi_eq7(__a__, __struct_type__, __field_member__, __VA_ARGS__);\ 736 | idx_array_rs *__rs10__ = idxarr_union_rs(__rs1__, __rs2__, true);\ 737 | __rs10__;}) 738 | 739 | #define idxarr_search_multi_eq9(__a__, __struct_type__, __field_member__, __key__, ...) ({\ 740 | idx_array_rs *__rs1__ = basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 741 | idx_array_rs *__rs2__ = idxarr_search_multi_eq8(__a__, __struct_type__, __field_member__, __VA_ARGS__);\ 742 | idx_array_rs *__rs10__ = idxarr_union_rs(__rs1__, __rs2__, true);\ 743 | __rs10__;}) 744 | 745 | #define idxarr_search_multi_eq10(__a__, __struct_type__, __field_member__, __key__, ...) ({\ 746 | idx_array_rs *__rs1__ = basearch_index(__key__, __a__, offsetof(__struct_type__, __field_member__), idxarr_eq);\ 747 | idx_array_rs *__rs2__ = idxarr_search_multi_eq9(__a__, __struct_type__, __field_member__, __VA_ARGS__);\ 748 | idx_array_rs *__rs10__ = idxarr_union_rs(__rs1__, __rs2__, true);\ 749 | __rs10__;}) 750 | 751 | /*** End for multiple eq query scope ***/ 752 | 753 | static inline int 754 | idxarr_array_init(idx_array_t *array, idxarr_u_int capacity, idxarr_u_int num_of_index) 755 | { 756 | 757 | if (num_of_index == 0) { 758 | perror("at least 1 index"); 759 | return 0; 760 | } 761 | 762 | array->num_of_index = num_of_index; 763 | 764 | array->size = 0; 765 | array->capacity = capacity; 766 | 767 | array->_index_arr_ = (idxarr_array_idx *) __idxarr_malloc_fn(num_of_index * sizeof(idxarr_array_idx)); 768 | size_t i; 769 | for (i = 0; i < num_of_index; i++) { 770 | array->_index_arr_[i].arr_ref = (idxarr_u_char **) __idxarr_malloc_fn(capacity * sizeof(idxarr_u_char *)); 771 | array->_index_arr_[i].cmp_func = NULL; // init 0 until index added 772 | array->_index_arr_[i].offset = -1; // init -1 until index added 773 | if (array->_index_arr_[i].arr_ref == NULL) 774 | return 0; 775 | } 776 | 777 | return 1; 778 | } 779 | 780 | #ifdef __cplusplus 781 | } 782 | #endif 783 | 784 | #endif /* _HEADER_IDX_ARRAY_T_ */ 785 | -------------------------------------------------------------------------------- /test_main.c: -------------------------------------------------------------------------------- 1 | #define idxarr_assert(message, test) do { \ 2 | if (!(test)) { \ 3 | printf("\033[0;31m");\ 4 | printf("TEST FAILED at line numer %d, %s\n", __LINE__, message);\ 5 | printf("\033[0m");\ 6 | return 0; \ 7 | } \ 8 | } while (0) 9 | 10 | #define idxarr_run_test(test) do { \ 11 | idxarr_tests_run++; \ 12 | if(!test()) return 0;\ 13 | printf("\033[0;32m");\ 14 | printf("%s => PASSED\n", #test);\ 15 | printf("\033[0m");\ 16 | } while (0) 17 | 18 | extern int idxarr_tests_run; 19 | 20 | 21 | #include 22 | #include 23 | #include "indexed_array.h" 24 | #include 25 | 26 | /**** 27 | gcc indexed_array.c test_main.c 28 | valgrind ./a.out 29 | or 30 | clang indexed_array.c test_main.c 31 | drmemory -- a.out 32 | * 33 | */ 34 | 35 | typedef struct { 36 | int val; 37 | long val_l; 38 | float val_f; 39 | char *val_cstr; 40 | char val_cstr2[10]; 41 | } my_node; 42 | 43 | int cmp_group_func (const void *a, const void *b) { 44 | return strcmp((*(my_node**)a)->val_cstr, (*(my_node**)b)->val_cstr); 45 | } 46 | 47 | void free_my_node(void *a) { 48 | free(((my_node*)a)->val_cstr); 49 | free(a); 50 | } 51 | 52 | 53 | int idxarr_tests_run = 0; 54 | 55 | /***Uniq variable***/ 56 | idx_array_t *my_indexed_arr; 57 | 58 | 59 | static int setup_test() { 60 | // at first 50 quantity only 61 | int n = 50; 62 | 63 | my_indexed_arr = idxarr_create(n, 5); 64 | 65 | 66 | idxarr_assert("First Start indexed array capacity should be 50", my_indexed_arr->capacity == 50); 67 | 68 | 69 | if (idxarr_add_float_index(my_indexed_arr, my_node, val_f) 70 | && idxarr_add_int_index(my_indexed_arr, my_node, val) 71 | && idxarr_add_heap_str_index(my_indexed_arr, my_node, val_cstr) 72 | && idxarr_add_stack_str_index(my_indexed_arr, my_node, val_cstr2) 73 | && idxarr_add_long_index(my_indexed_arr, my_node, val_l) 74 | ) { 75 | int i; 76 | for (i = 0; i < 100; i++) { 77 | my_node *s = malloc(sizeof(my_node)); 78 | if (i < 10) { 79 | s->val = i; 80 | s->val_l = i * 1L; 81 | s->val_cstr = strdup("Jack Prabas"); 82 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 83 | s->val_f = i * 1.0f; 84 | } 85 | else if (i < 20) { 86 | s->val = i; 87 | s->val_l = i * 1L; 88 | s->val_cstr = strdup("Abbar"); 89 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 90 | s->val_f = i * 1.0f; 91 | } 92 | else if (i < 30) { 93 | s->val = i; 94 | s->val_l = i * 1L; 95 | s->val_cstr = strdup("BETTY"); 96 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 97 | s->val_f = i * 1.0f; 98 | } 99 | else if (i < 40) { 100 | s->val = i; 101 | s->val_l = i * 1L; 102 | s->val_cstr = strdup("Eason"); 103 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 104 | s->val_f = i * 1.0f; 105 | } 106 | else if (i < 50) { 107 | s->val = i; 108 | s->val_l = i * 1L; 109 | s->val_cstr = strdup("Cat"); 110 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 111 | s->val_f = i * 1.0f; 112 | } 113 | else if (i < 60) { 114 | s->val = i; 115 | s->val_l = i * 1L; 116 | s->val_cstr = strdup("Genus Gan"); 117 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 118 | s->val_f = i * 1.0f; 119 | } 120 | else if (i < 70) { 121 | s->val = i; 122 | s->val_l = i * 1L; 123 | s->val_cstr = strdup("Heat Jack"); 124 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 125 | s->val_f = i * 1.0f; 126 | } 127 | else if (i < 80) { 128 | s->val = i; 129 | s->val_l = i * 1L; 130 | s->val_cstr = strdup("Ian Cheng@"); 131 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 132 | s->val_f = i * 1.0f; 133 | } 134 | else if (i < 90) { 135 | s->val = i; 136 | s->val_l = i * 1L; 137 | s->val_cstr = strdup("Finn"); 138 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 139 | s->val_f = i * 1.0f; 140 | } 141 | else { 142 | s->val = i; 143 | s->val_l = i * 1L; 144 | s->val_cstr = strdup("Denny"); 145 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 146 | s->val_f = i * 1.0f; 147 | } 148 | idxarr_push(my_indexed_arr, s); 149 | } 150 | idxarr_assert("indexed array size should become to 100", my_indexed_arr->size == 100); 151 | 152 | } else { 153 | idxarr_assert("indexed array indexing failed", 0); 154 | } 155 | return 1; 156 | } 157 | 158 | static int test_value_had_indexed() { 159 | my_node **ss = (my_node**)idxarr_get_index_array(my_indexed_arr, 2); // val_cstr indexed 160 | int i; 161 | for (i = 0; i < 10; i++) { 162 | idxarr_assert("Abbar should have val 10-19", ss[i]->val >= 10 && ss[i]->val < 20); 163 | } 164 | 165 | 166 | for (i = 10; i < 20; i++) { 167 | idxarr_assert("BETTY should have val 20-29", ss[i]->val >= 20 && ss[i]->val < 30); 168 | } 169 | 170 | for (i = 20; i < 30; i++) { 171 | idxarr_assert("Cat should have val 40-49", ss[i]->val >= 40 && ss[i]->val < 50); 172 | } 173 | 174 | return 1; 175 | } 176 | 177 | static int test_search_algorithm() { 178 | int search_key1 = 10; 179 | int search_key2 = 20; 180 | int search_key3 = 30; 181 | int search_key4 = 40; 182 | int search_key5 = 50; 183 | int search_key6 = 60; 184 | int search_key7 = 70; 185 | int search_key8 = 80; 186 | int search_key9 = 90; 187 | int search_key10 = 200; 188 | char* search_key5c = "Abbar"; 189 | char* search_key6c = "Cat"; 190 | long search_key12 = 12; 191 | 192 | 193 | idx_array_rs *rs = idxarr_search_multi_eq10(my_indexed_arr, my_node, val, &search_key1, 194 | &search_key2, &search_key3, &search_key4, &search_key5, &search_key6, &search_key7, 195 | &search_key8, &search_key9 , &search_key10 ); 196 | 197 | idxarr_assert("result size should be 9", rs->size == 9); 198 | 199 | idxarr_free_rs(rs); 200 | 201 | 202 | rs = idxarr_search_gt(my_indexed_arr, my_node, val_l, &search_key12); 203 | 204 | 205 | idxarr_assert("result size should be 87", rs->size == 87); 206 | 207 | idxarr_free_rs(rs); 208 | 209 | rs = idxarr_search_lt(my_indexed_arr, my_node, val_l, &search_key12); 210 | 211 | idxarr_assert("result size should be 12", rs->size == 12); 212 | 213 | idxarr_free_rs(rs); 214 | 215 | rs = idxarr_search_eq(my_indexed_arr, my_node, val_cstr, search_key5c); 216 | 217 | idxarr_assert("result size should be 10", rs->size == 10); 218 | 219 | idxarr_free_rs(rs); 220 | 221 | idx_array_rs *rs1 = idxarr_search_eq(my_indexed_arr, my_node, val_cstr, search_key5c); 222 | idx_array_rs *rs2 = idxarr_search_eq(my_indexed_arr, my_node, val_cstr2, search_key6c); 223 | 224 | idx_array_rs *rs10 = idxarr_intersect_rs(rs1, rs2, false); // Join and false mean remain rs1 and rs2, true means free the result 225 | 226 | idxarr_assert("result size should be 0 as join is not match", rs10->size == 0); 227 | 228 | idxarr_free_rs(rs10); 229 | 230 | rs10 = idxarr_union_rs(rs1, rs2, false); // Join 231 | 232 | idxarr_assert("result size should be 20 as union ", rs10->size == 20); 233 | 234 | idxarr_free_rs(rs10); 235 | 236 | 237 | // Join more 238 | rs10 = idxarr_intersect_rs(rs1, idxarr_union_rs(rs1, rs2, false), true); 239 | 240 | idxarr_assert("result size should be 10 as join and the union ", rs10->size == 10); 241 | 242 | 243 | 244 | 245 | #ifdef __APPLE__ 246 | idx_cmp_func f = ^int(const void *a, const void *b) { 247 | my_node *anode = *(my_node**)a; 248 | my_node *bnode = *(my_node**)b; 249 | return strcmp((const char*)(uintptr_t)anode->val_cstr, (const char*)(uintptr_t)bnode->val_cstr); 250 | }; 251 | 252 | idxarr_sort_rs_by_b(rs10, f); 253 | #else 254 | idx_cmp_func f = ({ 255 | int __fn__ (const void *a, const void *b) { 256 | my_node *anode = *(my_node**)a; 257 | my_node *bnode = *(my_node**)b; 258 | return strcmp((const char*)(uintptr_t)anode->val_cstr, (const char*)(uintptr_t)bnode->val_cstr); 259 | } 260 | __fn__; 261 | }); 262 | 263 | idxarr_sort_rs_by(rs10, f); 264 | #endif 265 | 266 | // idxarr_free_rs(rs1); // rs1 is already free at above 267 | idxarr_free_rs(rs2); 268 | idxarr_free_rs(rs10); 269 | 270 | 271 | // Test String start with 272 | char* search_keyStartWith = "A"; 273 | idx_array_rs *rs111 = idxarr_search_str_start_with(my_indexed_arr, my_node, val_cstr, search_keyStartWith); 274 | 275 | idxarr_assert("result size should be 10 as Start with A only have 10 result ", rs111->size == 10); 276 | int i; 277 | 278 | for (i = 0; i < rs111->size; i++) { 279 | idxarr_assert("result start with A should be Abbar only ", strcmp(((my_node*) rs111->ptrs[i])->val_cstr, "Abbar") == 0); 280 | } 281 | 282 | idxarr_free_rs(rs111); 283 | 284 | search_keyStartWith = "F"; 285 | 286 | rs111 = idxarr_search_str_start_with(my_indexed_arr, my_node, val_cstr2, search_keyStartWith); 287 | 288 | idxarr_assert("result size should be 10 as Start with F only have 10 result ", rs111->size == 10); 289 | 290 | for (i = 0; i < rs111->size; i++) { 291 | idxarr_assert("result start with F should be Finn only ", strcmp(((my_node*) rs111->ptrs[i])->val_cstr2, "Finn") == 0); 292 | } 293 | 294 | idxarr_free_rs(rs111); 295 | 296 | return 1; 297 | } 298 | 299 | static int test_reload_data() { 300 | // at first 50 quantity only 301 | int n = 50; 302 | 303 | idx_array_t *my_new_indexed_arr = idxarr_create(n, 5); 304 | 305 | idxarr_assert("new indexed array capacity should be 50", my_new_indexed_arr->capacity == 50); 306 | 307 | 308 | if (idxarr_add_float_index(my_new_indexed_arr, my_node, val_f) 309 | && idxarr_add_int_index(my_new_indexed_arr, my_node, val) 310 | && idxarr_add_heap_str_index(my_new_indexed_arr, my_node, val_cstr) 311 | && idxarr_add_stack_str_index(my_new_indexed_arr, my_node, val_cstr2) 312 | && idxarr_add_long_index(my_new_indexed_arr, my_node, val_l) 313 | ) { 314 | int i; 315 | for (i = 0; i < 50; i++) { 316 | my_node *s = malloc(sizeof(my_node)); 317 | if (i < 10) { 318 | s->val = i; 319 | s->val_l = i * 1L; 320 | s->val_cstr = strdup("Jack Prabas"); 321 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 322 | s->val_f = i * 1.0f; 323 | } 324 | else if (i < 20) { 325 | s->val = i; 326 | s->val_l = i * 1L; 327 | s->val_cstr = strdup("Abbar"); 328 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 329 | s->val_f = i * 1.0f; 330 | } 331 | else if (i < 30) { 332 | s->val = i; 333 | s->val_l = i * 1L; 334 | s->val_cstr = strdup("BETTY"); 335 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 336 | s->val_f = i * 1.0f; 337 | } 338 | else if (i < 40) { 339 | s->val = i; 340 | s->val_l = i * 1L; 341 | s->val_cstr = strdup("Eason"); 342 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 343 | s->val_f = i * 1.0f; 344 | } 345 | else { 346 | s->val = i; 347 | s->val_l = i * 1L; 348 | s->val_cstr = strdup("Cat"); 349 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 350 | s->val_f = i * 1.0f; 351 | } 352 | idxarr_push(my_new_indexed_arr, s); 353 | } 354 | } else { 355 | idxarr_assert("new indexed array indexing failed", 0); 356 | } 357 | 358 | unsigned int buffer_milisecs_to_purge_old_array = 500; 359 | 360 | idxarr_safety_swap(&my_indexed_arr, my_new_indexed_arr, free_my_node, buffer_milisecs_to_purge_old_array); 361 | 362 | idxarr_assert("reloaded indexed array size should become to 50", my_indexed_arr->size == 50); 363 | 364 | 365 | return 1; 366 | } 367 | 368 | 369 | static int all_tests() { 370 | 371 | idxarr_run_test(setup_test); 372 | idxarr_run_test(test_value_had_indexed); 373 | idxarr_run_test(test_search_algorithm); 374 | idxarr_run_test(test_reload_data); 375 | 376 | idxarr_destroy(my_indexed_arr, free_my_node); 377 | 378 | // Use Valgrind compile 379 | 380 | return 1; 381 | } 382 | 383 | int main(int argc, char **argv) { 384 | int test_status = all_tests(); 385 | if (test_status) { 386 | printf("ALL TESTS PASSED\n"); 387 | } 388 | printf("Tests run: %d\n", idxarr_tests_run); 389 | 390 | return test_status; 391 | } -------------------------------------------------------------------------------- /test_main.cpp: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" { 3 | #endif 4 | 5 | #define idxarr_assert(message, test) do { \ 6 | if (!(test)) { \ 7 | printf("\033[0;31m");\ 8 | printf("TEST FAILED at line numer %d, %s\n", __LINE__, message);\ 9 | printf("\033[0m");\ 10 | return 0; \ 11 | } \ 12 | } while (0) 13 | 14 | #define idxarr_run_test(test) do { \ 15 | idxarr_tests_run++; \ 16 | if(!test()) return 0;\ 17 | printf("\033[0;32m");\ 18 | printf("%s => PASSED\n", #test);\ 19 | printf("\033[0m");\ 20 | } while (0) 21 | 22 | extern int idxarr_tests_run; 23 | 24 | #include 25 | #include 26 | #include "indexed_array.h" 27 | #include 28 | 29 | /**** 30 | g++ -std=c++11 indexed_array.c test_main.cpp 31 | valgrind ./a.out // if you have valgrind 32 | or 33 | clang++ -std=c++11 indexed_array.c test_main.cpp 34 | drmemory / valgrind to run 35 | * 36 | */ 37 | typedef struct { 38 | int val; 39 | long val_l; 40 | float val_f; 41 | char *val_cstr; 42 | char val_cstr2[10]; 43 | } my_node; 44 | 45 | int cmp_group_func (const void *a, const void *b) { 46 | return strcmp((*(my_node**)a)->val_cstr, (*(my_node**)b)->val_cstr); 47 | } 48 | 49 | void free_my_node(void *a) { 50 | free(((my_node*)a)->val_cstr); 51 | free(a); 52 | } 53 | 54 | 55 | int idxarr_tests_run = 0; 56 | 57 | /***Uniq variable***/ 58 | idx_array_t *my_indexed_arr; 59 | 60 | 61 | static int setup_test() { 62 | // at first 50 quantity only 63 | int n = 50; 64 | 65 | my_indexed_arr = idxarr_create(n, 5); 66 | 67 | 68 | idxarr_assert("First Start indexed array capacity should be 50", my_indexed_arr->capacity == 50); 69 | 70 | 71 | if (idxarr_add_float_index(my_indexed_arr, my_node, val_f) 72 | && idxarr_add_int_index(my_indexed_arr, my_node, val) 73 | && idxarr_add_heap_str_index(my_indexed_arr, my_node, val_cstr) 74 | && idxarr_add_stack_str_index(my_indexed_arr, my_node, val_cstr2) 75 | && idxarr_add_long_index(my_indexed_arr, my_node, val_l) 76 | ) { 77 | int i; 78 | for (i = 0; i < 100; i++) { 79 | my_node *s = (my_node*) malloc(sizeof(my_node)); 80 | if (i < 10) { 81 | s->val = i; 82 | s->val_l = i * 1L; 83 | s->val_cstr = strdup("Jack Prabas"); 84 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 85 | s->val_f = i * 1.0f; 86 | } 87 | else if (i < 20) { 88 | s->val = i; 89 | s->val_l = i * 1L; 90 | s->val_cstr = strdup("Abbar"); 91 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 92 | s->val_f = i * 1.0f; 93 | } 94 | else if (i < 30) { 95 | s->val = i; 96 | s->val_l = i * 1L; 97 | s->val_cstr = strdup("BETTY"); 98 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 99 | s->val_f = i * 1.0f; 100 | } 101 | else if (i < 40) { 102 | s->val = i; 103 | s->val_l = i * 1L; 104 | s->val_cstr = strdup("Eason"); 105 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 106 | s->val_f = i * 1.0f; 107 | } 108 | else if (i < 50) { 109 | s->val = i; 110 | s->val_l = i * 1L; 111 | s->val_cstr = strdup("Cat"); 112 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 113 | s->val_f = i * 1.0f; 114 | } 115 | else if (i < 60) { 116 | s->val = i; 117 | s->val_l = i * 1L; 118 | s->val_cstr = strdup("Genus Gan"); 119 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 120 | s->val_f = i * 1.0f; 121 | } 122 | else if (i < 70) { 123 | s->val = i; 124 | s->val_l = i * 1L; 125 | s->val_cstr = strdup("Heat Jack"); 126 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 127 | s->val_f = i * 1.0f; 128 | } 129 | else if (i < 80) { 130 | s->val = i; 131 | s->val_l = i * 1L; 132 | s->val_cstr = strdup("Ian Cheng@"); 133 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 134 | s->val_f = i * 1.0f; 135 | } 136 | else if (i < 90) { 137 | s->val = i; 138 | s->val_l = i * 1L; 139 | s->val_cstr = strdup("Finn"); 140 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 141 | s->val_f = i * 1.0f; 142 | } 143 | else { 144 | s->val = i; 145 | s->val_l = i * 1L; 146 | s->val_cstr = strdup("Denny"); 147 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 148 | s->val_f = i * 1.0f; 149 | } 150 | idxarr_push(my_indexed_arr, s); 151 | } 152 | idxarr_assert("indexed array size should become to 100", my_indexed_arr->size == 100); 153 | 154 | } else { 155 | idxarr_assert("indexed array indexing failed", 0); 156 | } 157 | return 1; 158 | } 159 | 160 | static int test_value_had_indexed() { 161 | my_node **ss = (my_node**)idxarr_get_index_array(my_indexed_arr, 2); // val_cstr indexed 162 | int i; 163 | for (i = 0; i < 10; i++) { 164 | idxarr_assert("Abbar should have val 10-19", ss[i]->val >= 10 && ss[i]->val < 20); 165 | } 166 | 167 | 168 | for (i = 10; i < 20; i++) { 169 | idxarr_assert("BETTY should have val 20-29", ss[i]->val >= 20 && ss[i]->val < 30); 170 | } 171 | 172 | for (i = 20; i < 30; i++) { 173 | idxarr_assert("Cat should have val 40-49", ss[i]->val >= 40 && ss[i]->val < 50); 174 | } 175 | 176 | 177 | return 1; 178 | } 179 | 180 | static int test_search_algorithm() { 181 | int search_key1 = 10; 182 | int search_key2 = 20; 183 | int search_key3 = 30; 184 | int search_key4 = 40; 185 | int search_key5 = 50; 186 | int search_key6 = 60; 187 | int search_key7 = 70; 188 | int search_key8 = 80; 189 | int search_key9 = 90; 190 | int search_key10 = 200; 191 | char* search_key5c = "Abbar"; 192 | char* search_key6c = "Cat"; 193 | long search_key12 = 12; 194 | 195 | 196 | idx_array_rs *rs = idxarr_search_multi_eq10(my_indexed_arr, my_node, val, &search_key1, 197 | &search_key2, &search_key3, &search_key4, &search_key5, &search_key6, &search_key7, 198 | &search_key8, &search_key9 , &search_key10 ); 199 | 200 | idxarr_assert("result size should be 9", rs->size == 9); 201 | 202 | idxarr_free_rs(rs); 203 | 204 | 205 | rs = idxarr_search_gt(my_indexed_arr, my_node, val_l, &search_key12); 206 | 207 | 208 | idxarr_assert("result size should be 87", rs->size == 87); 209 | 210 | idxarr_free_rs(rs); 211 | 212 | rs = idxarr_search_lt(my_indexed_arr, my_node, val_l, &search_key12); 213 | 214 | idxarr_assert("result size should be 12", rs->size == 12); 215 | 216 | idxarr_free_rs(rs); 217 | 218 | rs = idxarr_search_eq(my_indexed_arr, my_node, val_cstr, search_key5c); 219 | 220 | idxarr_assert("result size should be 10", rs->size == 10); 221 | 222 | idxarr_free_rs(rs); 223 | 224 | idx_array_rs *rs1 = idxarr_search_eq(my_indexed_arr, my_node, val_cstr, search_key5c); 225 | idx_array_rs *rs2 = idxarr_search_eq(my_indexed_arr, my_node, val_cstr2, search_key6c); 226 | 227 | idx_array_rs *rs10 = idxarr_intersect_rs(rs1, rs2, false); // Join and false mean remain rs1 and rs2, true means free the result 228 | 229 | idxarr_assert("result size should be 0 as join is not match", rs10->size == 0); 230 | 231 | idxarr_free_rs(rs10); 232 | 233 | rs10 = idxarr_union_rs(rs1, rs2, false); // Join 234 | 235 | idxarr_assert("result size should be 20 as union ", rs10->size == 20); 236 | 237 | idxarr_free_rs(rs10); 238 | 239 | 240 | // Join more 241 | rs10 = idxarr_intersect_rs(rs1, idxarr_union_rs(rs1, rs2, false), true); 242 | 243 | idxarr_assert("result size should be 10 as join and the union ", rs10->size == 10); 244 | 245 | 246 | 247 | #ifdef __APPLE__ 248 | idx_cmp_func f = ^int(const void *a, const void *b) { 249 | my_node *anode = *(my_node**)a; 250 | my_node *bnode = *(my_node**)b; 251 | return strcmp((const char*)(uintptr_t)anode->val_cstr, (const char*)(uintptr_t)bnode->val_cstr); 252 | }; 253 | 254 | idxarr_sort_rs_by_b(rs10, f); 255 | #else 256 | idxarr_cmp_func f = [&](const void*a, const void*b) -> int { 257 | my_node *anode = *(my_node**)a; 258 | my_node *bnode = *(my_node**)b; 259 | return strcmp((const char*)(uintptr_t)anode->val_cstr, (const char*)(uintptr_t)bnode->val_cstr); 260 | }; 261 | 262 | idxarr_sort_rs_by(rs10, f); 263 | #endif 264 | 265 | 266 | // idxarr_free_rs(rs1); // rs1 is already free at above 267 | idxarr_free_rs(rs2); 268 | idxarr_free_rs(rs10); 269 | 270 | 271 | // Test String start with 272 | char* search_keyStartWith = "A"; 273 | idx_array_rs *rs111 = idxarr_search_str_start_with(my_indexed_arr, my_node, val_cstr, search_keyStartWith); 274 | 275 | idxarr_assert("result size should be 10 as Start with A only have 10 result ", rs111->size == 10); 276 | int i; 277 | 278 | for (i = 0; i < rs111->size; i++) { 279 | idxarr_assert("result start with A should be Abbar only ", strcmp(((my_node*) rs111->ptrs[i])->val_cstr, "Abbar") == 0); 280 | } 281 | 282 | idxarr_free_rs(rs111); 283 | 284 | search_keyStartWith = "F"; 285 | 286 | rs111 = idxarr_search_str_start_with(my_indexed_arr, my_node, val_cstr2, search_keyStartWith); 287 | 288 | idxarr_assert("result size should be 10 as Start with F only have 10 result ", rs111->size == 10); 289 | 290 | for (i = 0; i < rs111->size; i++) { 291 | idxarr_assert("result start with F should be Finn only ", strcmp(((my_node*) rs111->ptrs[i])->val_cstr2, "Finn") == 0); 292 | } 293 | 294 | idxarr_free_rs(rs111); 295 | 296 | return 1; 297 | } 298 | 299 | static int test_reload_data() { 300 | // at first 50 quantity only 301 | int n = 50; 302 | 303 | idx_array_t *my_new_indexed_arr = idxarr_create(n, 5); 304 | 305 | idxarr_assert("new indexed array capacity should be 50", my_new_indexed_arr->capacity == 50); 306 | 307 | 308 | if (idxarr_add_float_index(my_new_indexed_arr, my_node, val_f) 309 | && idxarr_add_int_index(my_new_indexed_arr, my_node, val) 310 | && idxarr_add_heap_str_index(my_new_indexed_arr, my_node, val_cstr) 311 | && idxarr_add_stack_str_index(my_new_indexed_arr, my_node, val_cstr2) 312 | && idxarr_add_long_index(my_new_indexed_arr, my_node, val_l) 313 | ) { 314 | int i; 315 | for (i = 0; i < 50; i++) { 316 | my_node *s = (my_node*) malloc(sizeof(my_node)); 317 | if (i < 10) { 318 | s->val = i; 319 | s->val_l = i * 1L; 320 | s->val_cstr = strdup("Jack Prabas"); 321 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 322 | s->val_f = i * 1.0f; 323 | } 324 | else if (i < 20) { 325 | s->val = i; 326 | s->val_l = i * 1L; 327 | s->val_cstr = strdup("Abbar"); 328 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 329 | s->val_f = i * 1.0f; 330 | } 331 | else if (i < 30) { 332 | s->val = i; 333 | s->val_l = i * 1L; 334 | s->val_cstr = strdup("BETTY"); 335 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 336 | s->val_f = i * 1.0f; 337 | } 338 | else if (i < 40) { 339 | s->val = i; 340 | s->val_l = i * 1L; 341 | s->val_cstr = strdup("Eason"); 342 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 343 | s->val_f = i * 1.0f; 344 | } 345 | else { 346 | s->val = i; 347 | s->val_l = i * 1L; 348 | s->val_cstr = strdup("Cat"); 349 | memcpy(s->val_cstr2, s->val_cstr, strlen(s->val_cstr) + 1); 350 | s->val_f = i * 1.0f; 351 | } 352 | idxarr_push(my_new_indexed_arr, s); 353 | } 354 | } else { 355 | idxarr_assert("new indexed array indexing failed", 0); 356 | } 357 | 358 | unsigned int buffer_milisecs_to_purge_old_array = 500; 359 | 360 | idxarr_safety_swap(&my_indexed_arr, my_new_indexed_arr, free_my_node, buffer_milisecs_to_purge_old_array); 361 | 362 | idxarr_assert("reloaded indexed array size should become to 50", my_indexed_arr->size == 50); 363 | 364 | 365 | return 1; 366 | } 367 | 368 | 369 | static int all_tests() { 370 | 371 | idxarr_run_test(setup_test); 372 | idxarr_run_test(test_value_had_indexed); 373 | idxarr_run_test(test_search_algorithm); 374 | idxarr_run_test(test_reload_data); 375 | 376 | idxarr_destroy(my_indexed_arr, free_my_node); 377 | 378 | // Use Valgrind compile 379 | 380 | return 1; 381 | } 382 | 383 | int main(int argc, char **argv) { 384 | int test_status = all_tests(); 385 | if (test_status) { 386 | printf("ALL TESTS PASSED\n"); 387 | } 388 | printf("Tests run: %d\n", idxarr_tests_run); 389 | 390 | return test_status; 391 | } 392 | 393 | #ifdef __cplusplus 394 | } 395 | #endif 396 | --------------------------------------------------------------------------------