diff options
| author | 2019-05-19 00:20:51 +0200 | |
|---|---|---|
| committer | 2019-05-19 00:20:51 +0200 | |
| commit | 08c6143b870167ad29f9c20a298e0f75c986d0ea (patch) | |
| tree | 079c595bf106a0f93add63a77730a2c8dde2ab7a /src | |
| parent | 7e9ecf2f3f902f3e688e68b1d272f9a4b35540c7 (diff) | |
| download | libplist-08c6143b870167ad29f9c20a298e0f75c986d0ea.tar.gz libplist-08c6143b870167ad29f9c20a298e0f75c986d0ea.tar.bz2 | |
Add index lookup table for large PLIST_ARRAY nodes
Diffstat (limited to 'src')
| -rw-r--r-- | src/plist.c | 80 | ||||
| -rw-r--r-- | src/ptrarray.c | 42 | ||||
| -rw-r--r-- | src/ptrarray.h | 13 |
3 files changed, 113 insertions, 22 deletions
diff --git a/src/plist.c b/src/plist.c index 70386bc..f22a8a0 100644 --- a/src/plist.c +++ b/src/plist.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <stdio.h> | 28 | #include <stdio.h> |
| 29 | #include <math.h> | 29 | #include <math.h> |
| 30 | #include <assert.h> | 30 | #include <assert.h> |
| 31 | #include <limits.h> | ||
| 31 | 32 | ||
| 32 | #ifdef WIN32 | 33 | #ifdef WIN32 |
| 33 | #include <windows.h> | 34 | #include <windows.h> |
| @@ -37,6 +38,7 @@ | |||
| 37 | 38 | ||
| 38 | #include <node.h> | 39 | #include <node.h> |
| 39 | #include <hashtable.h> | 40 | #include <hashtable.h> |
| 41 | #include <ptrarray.h> | ||
| 40 | 42 | ||
| 41 | extern void plist_xml_init(void); | 43 | extern void plist_xml_init(void); |
| 42 | extern void plist_xml_deinit(void); | 44 | extern void plist_xml_deinit(void); |
| @@ -190,6 +192,9 @@ void plist_free_data(plist_data_t data) | |||
| 190 | case PLIST_DATA: | 192 | case PLIST_DATA: |
| 191 | free(data->buff); | 193 | free(data->buff); |
| 192 | break; | 194 | break; |
| 195 | case PLIST_ARRAY: | ||
| 196 | ptr_array_free(data->hashtable); | ||
| 197 | break; | ||
| 193 | case PLIST_DICT: | 198 | case PLIST_DICT: |
| 194 | hash_table_destroy(data->hashtable); | 199 | hash_table_destroy(data->hashtable); |
| 195 | break; | 200 | break; |
| @@ -338,6 +343,20 @@ static void plist_copy_node(node_t *node, void *parent_node_ptr) | |||
| 338 | case PLIST_STRING: | 343 | case PLIST_STRING: |
| 339 | newdata->strval = strdup((char *) data->strval); | 344 | newdata->strval = strdup((char *) data->strval); |
| 340 | break; | 345 | break; |
| 346 | case PLIST_ARRAY: | ||
| 347 | if (data->hashtable) { | ||
| 348 | ptrarray_t* pa = ptr_array_new(((ptrarray_t*)data->hashtable)->capacity); | ||
| 349 | assert(pa); | ||
| 350 | plist_t current = NULL; | ||
| 351 | for (current = (plist_t)node_first_child(node); | ||
| 352 | pa && current; | ||
| 353 | current = (plist_t)node_next_sibling(current)) | ||
| 354 | { | ||
| 355 | ptr_array_add(pa, current); | ||
| 356 | } | ||
| 357 | newdata->hashtable = pa; | ||
| 358 | } | ||
| 359 | break; | ||
| 341 | case PLIST_DICT: | 360 | case PLIST_DICT: |
| 342 | if (data->hashtable) { | 361 | if (data->hashtable) { |
| 343 | hashtable_t* ht = hash_table_new(dict_key_hash, dict_key_compare, NULL); | 362 | hashtable_t* ht = hash_table_new(dict_key_hash, dict_key_compare, NULL); |
| @@ -392,9 +411,14 @@ PLIST_API uint32_t plist_array_get_size(plist_t node) | |||
| 392 | PLIST_API plist_t plist_array_get_item(plist_t node, uint32_t n) | 411 | PLIST_API plist_t plist_array_get_item(plist_t node, uint32_t n) |
| 393 | { | 412 | { |
| 394 | plist_t ret = NULL; | 413 | plist_t ret = NULL; |
| 395 | if (node && PLIST_ARRAY == plist_get_node_type(node)) | 414 | if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) |
| 396 | { | 415 | { |
| 397 | ret = (plist_t)node_nth_child(node, n); | 416 | ptrarray_t *pa = ((plist_data_t)((node_t*)node)->data)->hashtable; |
| 417 | if (pa) { | ||
| 418 | ret = (plist_t)ptr_array_index(pa, n); | ||
| 419 | } else { | ||
| 420 | ret = (plist_t)node_nth_child(node, n); | ||
| 421 | } | ||
| 398 | } | 422 | } |
| 399 | return ret; | 423 | return ret; |
| 400 | } | 424 | } |
| @@ -409,19 +433,46 @@ PLIST_API uint32_t plist_array_get_item_index(plist_t node) | |||
| 409 | return 0; | 433 | return 0; |
| 410 | } | 434 | } |
| 411 | 435 | ||
| 436 | static void _plist_array_post_insert(plist_t node, plist_t item, long n) | ||
| 437 | { | ||
| 438 | ptrarray_t *pa = ((plist_data_t)((node_t*)node)->data)->hashtable; | ||
| 439 | if (pa) { | ||
| 440 | /* store pointer to item in array */ | ||
| 441 | ptr_array_insert(pa, item, n); | ||
| 442 | } else { | ||
| 443 | if (((node_t*)node)->count > 100) { | ||
| 444 | /* make new lookup array */ | ||
| 445 | pa = ptr_array_new(128); | ||
| 446 | plist_t current = NULL; | ||
| 447 | for (current = (plist_t)node_first_child(node); | ||
| 448 | pa && current; | ||
| 449 | current = (plist_t)node_next_sibling(current)) | ||
| 450 | { | ||
| 451 | ptr_array_add(pa, current); | ||
| 452 | } | ||
| 453 | ((plist_data_t)((node_t*)node)->data)->hashtable = pa; | ||
| 454 | } | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 412 | PLIST_API void plist_array_set_item(plist_t node, plist_t item, uint32_t n) | 458 | PLIST_API void plist_array_set_item(plist_t node, plist_t item, uint32_t n) |
| 413 | { | 459 | { |
| 414 | if (node && PLIST_ARRAY == plist_get_node_type(node)) | 460 | if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) |
| 415 | { | 461 | { |
| 416 | plist_t old_item = plist_array_get_item(node, n); | 462 | plist_t old_item = plist_array_get_item(node, n); |
| 417 | if (old_item) | 463 | if (old_item) |
| 418 | { | 464 | { |
| 419 | int idx = plist_free_node(old_item); | 465 | int idx = plist_free_node(old_item); |
| 420 | if (idx < 0) { | 466 | assert(idx >= 0); |
| 421 | node_attach(node, item); | 467 | if (idx < 0) { |
| 422 | } else { | 468 | return; |
| 423 | node_insert(node, idx, item); | 469 | } else { |
| 424 | } | 470 | node_insert(node, idx, item); |
| 471 | ptrarray_t* pa = ((plist_data_t)((node_t*)node)->data)->hashtable; | ||
| 472 | if (pa) { | ||
| 473 | ptr_array_set(pa, item, idx); | ||
| 474 | } | ||
| 475 | } | ||
| 425 | } | 476 | } |
| 426 | } | 477 | } |
| 427 | return; | 478 | return; |
| @@ -432,26 +483,32 @@ PLIST_API void plist_array_append_item(plist_t node, plist_t item) | |||
| 432 | if (node && PLIST_ARRAY == plist_get_node_type(node)) | 483 | if (node && PLIST_ARRAY == plist_get_node_type(node)) |
| 433 | { | 484 | { |
| 434 | node_attach(node, item); | 485 | node_attach(node, item); |
| 486 | _plist_array_post_insert(node, item, -1); | ||
| 435 | } | 487 | } |
| 436 | return; | 488 | return; |
| 437 | } | 489 | } |
| 438 | 490 | ||
| 439 | PLIST_API void plist_array_insert_item(plist_t node, plist_t item, uint32_t n) | 491 | PLIST_API void plist_array_insert_item(plist_t node, plist_t item, uint32_t n) |
| 440 | { | 492 | { |
| 441 | if (node && PLIST_ARRAY == plist_get_node_type(node)) | 493 | if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) |
| 442 | { | 494 | { |
| 443 | node_insert(node, n, item); | 495 | node_insert(node, n, item); |
| 496 | _plist_array_post_insert(node, item, (long)n); | ||
| 444 | } | 497 | } |
| 445 | return; | 498 | return; |
| 446 | } | 499 | } |
| 447 | 500 | ||
| 448 | PLIST_API void plist_array_remove_item(plist_t node, uint32_t n) | 501 | PLIST_API void plist_array_remove_item(plist_t node, uint32_t n) |
| 449 | { | 502 | { |
| 450 | if (node && PLIST_ARRAY == plist_get_node_type(node)) | 503 | if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) |
| 451 | { | 504 | { |
| 452 | plist_t old_item = plist_array_get_item(node, n); | 505 | plist_t old_item = plist_array_get_item(node, n); |
| 453 | if (old_item) | 506 | if (old_item) |
| 454 | { | 507 | { |
| 508 | ptrarray_t* pa = ((plist_data_t)((node_t*)node)->data)->hashtable; | ||
| 509 | if (pa) { | ||
| 510 | ptr_array_remove(pa, n); | ||
| 511 | } | ||
| 455 | plist_free(old_item); | 512 | plist_free(old_item); |
| 456 | } | 513 | } |
| 457 | } | 514 | } |
| @@ -586,8 +643,9 @@ PLIST_API void plist_dict_set_item(plist_t node, const char* key, plist_t item) | |||
| 586 | plist_t key_node = NULL; | 643 | plist_t key_node = NULL; |
| 587 | if (old_item) { | 644 | if (old_item) { |
| 588 | int idx = plist_free_node(old_item); | 645 | int idx = plist_free_node(old_item); |
| 646 | assert(idx >= 0); | ||
| 589 | if (idx < 0) { | 647 | if (idx < 0) { |
| 590 | node_attach(node, item); | 648 | return; |
| 591 | } else { | 649 | } else { |
| 592 | node_insert(node, idx, item); | 650 | node_insert(node, idx, item); |
| 593 | } | 651 | } |
diff --git a/src/ptrarray.c b/src/ptrarray.c index eb17d28..bcffb77 100644 --- a/src/ptrarray.c +++ b/src/ptrarray.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * ptrarray.c | 2 | * ptrarray.c |
| 3 | * simple pointer array implementation | 3 | * simple pointer array implementation |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2011 Nikias Bassen, All Rights Reserved. | 5 | * Copyright (c) 2011-2019 Nikias Bassen, All Rights Reserved. |
| 6 | * | 6 | * |
| 7 | * This library is free software; you can redistribute it and/or | 7 | * This library is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU Lesser General Public | 8 | * modify it under the terms of the GNU Lesser General Public |
| @@ -19,6 +19,7 @@ | |||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 20 | */ | 20 | */ |
| 21 | #include "ptrarray.h" | 21 | #include "ptrarray.h" |
| 22 | #include <string.h> | ||
| 22 | 23 | ||
| 23 | ptrarray_t *ptr_array_new(int capacity) | 24 | ptrarray_t *ptr_array_new(int capacity) |
| 24 | { | 25 | { |
| @@ -39,22 +40,51 @@ void ptr_array_free(ptrarray_t *pa) | |||
| 39 | free(pa); | 40 | free(pa); |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | void ptr_array_add(ptrarray_t *pa, void *data) | 43 | void ptr_array_insert(ptrarray_t *pa, void *data, long array_index) |
| 43 | { | 44 | { |
| 44 | if (!pa || !pa->pdata || !data) return; | 45 | if (!pa || !pa->pdata || !data) return; |
| 45 | size_t remaining = pa->capacity-pa->len; | 46 | long remaining = pa->capacity-pa->len; |
| 46 | if (remaining == 0) { | 47 | if (remaining == 0) { |
| 47 | pa->pdata = realloc(pa->pdata, sizeof(void*) * (pa->capacity + pa->capacity_step)); | 48 | pa->pdata = realloc(pa->pdata, sizeof(void*) * (pa->capacity + pa->capacity_step)); |
| 48 | pa->capacity += pa->capacity_step; | 49 | pa->capacity += pa->capacity_step; |
| 49 | } | 50 | } |
| 50 | pa->pdata[pa->len] = data; | 51 | if (array_index < 0 || array_index >= pa->len) { |
| 52 | pa->pdata[pa->len] = data; | ||
| 53 | } else { | ||
| 54 | memmove(&pa->pdata[array_index+1], &pa->pdata[array_index], (pa->len-array_index) * sizeof(void*)); | ||
| 55 | pa->pdata[array_index] = data; | ||
| 56 | } | ||
| 51 | pa->len++; | 57 | pa->len++; |
| 52 | } | 58 | } |
| 53 | 59 | ||
| 54 | void* ptr_array_index(ptrarray_t *pa, size_t array_index) | 60 | void ptr_array_add(ptrarray_t *pa, void *data) |
| 61 | { | ||
| 62 | ptr_array_insert(pa, data, -1); | ||
| 63 | } | ||
| 64 | |||
| 65 | void ptr_array_remove(ptrarray_t *pa, long array_index) | ||
| 66 | { | ||
| 67 | if (!pa || !pa->pdata || array_index < 0) return; | ||
| 68 | if (pa->len == 0 || array_index >= pa->len) return; | ||
| 69 | if (pa->len == 1) { | ||
| 70 | pa->pdata[0] = NULL; | ||
| 71 | } else { | ||
| 72 | memmove(&pa->pdata[array_index], &pa->pdata[array_index+1], (pa->len-array_index-1) * sizeof(void*)); | ||
| 73 | } | ||
| 74 | pa->len--; | ||
| 75 | } | ||
| 76 | |||
| 77 | void ptr_array_set(ptrarray_t *pa, void *data, long array_index) | ||
| 78 | { | ||
| 79 | if (!pa || !pa->pdata || array_index < 0) return; | ||
| 80 | if (pa->len == 0 || array_index >= pa->len) return; | ||
| 81 | pa->pdata[array_index] = data; | ||
| 82 | } | ||
| 83 | |||
| 84 | void* ptr_array_index(ptrarray_t *pa, long array_index) | ||
| 55 | { | 85 | { |
| 56 | if (!pa) return NULL; | 86 | if (!pa) return NULL; |
| 57 | if (array_index >= pa->len) { | 87 | if (array_index < 0 || array_index >= pa->len) { |
| 58 | return NULL; | 88 | return NULL; |
| 59 | } | 89 | } |
| 60 | return pa->pdata[array_index]; | 90 | return pa->pdata[array_index]; |
diff --git a/src/ptrarray.h b/src/ptrarray.h index e8a3c88..2c6136a 100644 --- a/src/ptrarray.h +++ b/src/ptrarray.h | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * ptrarray.h | 2 | * ptrarray.h |
| 3 | * header file for simple pointer array implementation | 3 | * header file for simple pointer array implementation |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2011 Nikias Bassen, All Rights Reserved. | 5 | * Copyright (c) 2011-2019 Nikias Bassen, All Rights Reserved. |
| 6 | * | 6 | * |
| 7 | * This library is free software; you can redistribute it and/or | 7 | * This library is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU Lesser General Public | 8 | * modify it under the terms of the GNU Lesser General Public |
| @@ -24,13 +24,16 @@ | |||
| 24 | 24 | ||
| 25 | typedef struct ptrarray_t { | 25 | typedef struct ptrarray_t { |
| 26 | void **pdata; | 26 | void **pdata; |
| 27 | size_t len; | 27 | long len; |
| 28 | size_t capacity; | 28 | long capacity; |
| 29 | size_t capacity_step; | 29 | long capacity_step; |
| 30 | } ptrarray_t; | 30 | } ptrarray_t; |
| 31 | 31 | ||
| 32 | ptrarray_t *ptr_array_new(int capacity); | 32 | ptrarray_t *ptr_array_new(int capacity); |
| 33 | void ptr_array_free(ptrarray_t *pa); | 33 | void ptr_array_free(ptrarray_t *pa); |
| 34 | void ptr_array_add(ptrarray_t *pa, void *data); | 34 | void ptr_array_add(ptrarray_t *pa, void *data); |
| 35 | void* ptr_array_index(ptrarray_t *pa, size_t index); | 35 | void ptr_array_insert(ptrarray_t *pa, void *data, long index); |
| 36 | void ptr_array_remove(ptrarray_t *pa, long index); | ||
| 37 | void ptr_array_set(ptrarray_t *pa, void *data, long index); | ||
| 38 | void* ptr_array_index(ptrarray_t *pa, long index); | ||
| 36 | #endif | 39 | #endif |
