hashtab.c 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * hashtab.c
  3. *
  4. * Copyright (C) 2019 Alex A. <coderain@sdf.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "hashtab.h"
  20. void *hash_table_search(hash_table_t *ht, void *entry, int auto_add)
  21. {
  22. size_t bucket = ht->hash(entry);
  23. if (ht->lengths[bucket] > 0)
  24. {
  25. void **array = ht->buckets[bucket];
  26. int low = 0, high = ht->lengths[bucket] - 1;
  27. while (low <= high)
  28. {
  29. int mid = (low + high) / 2;
  30. int comp = ht->compare(array[mid], entry);
  31. if (comp < 0) low = mid + 1;
  32. else if (comp > 0) high = mid - 1;
  33. else return array[mid];
  34. }
  35. if (!auto_add || ht->lengths[bucket] == DUPLICATES) return NULL;
  36. if (low < ht->lengths[bucket])
  37. {
  38. /* Maintain the ascending order by moving all the bigger ones right */
  39. memmove(&array[low + 1], &array[low], (ht->lengths[bucket] - low) * sizeof(void*));
  40. }
  41. array[low] = entry;
  42. ht->lengths[bucket]++;
  43. }
  44. else
  45. {
  46. if (!auto_add) return NULL;
  47. ht->buckets[bucket][0] = entry;
  48. ht->lengths[bucket] = 1;
  49. }
  50. return entry;
  51. }
  52. void hash_table_delete(hash_table_t *ht, const void *entry)
  53. {
  54. size_t bucket = ht->hash(entry);
  55. void **array = ht->buckets[bucket];
  56. if (!array) return;
  57. int low = 0;
  58. int high = ht->lengths[bucket] - 1;
  59. int mid;
  60. while (low <= high)
  61. {
  62. mid = (low + high) / 2;
  63. int comp = ht->compare(array[mid], entry);
  64. if (comp < 0) low = mid + 1;
  65. else if (comp > 0) high = mid - 1;
  66. else break;
  67. }
  68. if (low <= high) memmove(&array[mid], &array[mid + 1], (--ht->lengths[bucket] - mid) * sizeof(void*));
  69. }
  70. void **hash_table_enum(hash_table_t *ht, void **current)
  71. {
  72. size_t bucket = current ? ht->hash(*current) : 0;
  73. if (current)
  74. {
  75. size_t index = current - ht->buckets[bucket] + 1;
  76. if (index < ht->lengths[bucket]) return &ht->buckets[bucket][index];
  77. }
  78. while (++bucket < BUCKETS) if (ht->lengths[bucket] > 0) return ht->buckets[bucket];
  79. return NULL;
  80. }