stringmap.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
  3. * Copyright (c) 2009 Joseph Adams (joeyadams3.14159@gmail.com).
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. The name of the author may not be used to endorse or promote products
  15. * derived from this software without specific prior written permission
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. /* This is a heavily modified version of the Patricia tree implementation
  29. in PCC at http://pcc.zentus.com/cgi-bin/cvsweb.cgi/cc/cpp/cpp.c?rev=1.96 */
  30. #include "stringmap.h"
  31. #if 0
  32. #include <assert.h>
  33. #else
  34. #define assert(...) do {} while(0)
  35. #endif
  36. #define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
  37. #define LEFT_IS_LEAF 0x80000000
  38. #define RIGHT_IS_LEAF 0x40000000
  39. #define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0)
  40. #define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0)
  41. #define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1
  42. #define CHECKBITS 8
  43. struct T {
  44. char *str;
  45. };
  46. static void *T_new(struct block_pool *bp, const char *key, size_t T_size) {
  47. struct T *leaf = block_pool_alloc(bp, T_size);
  48. memset(leaf, 0, T_size);
  49. leaf->str = block_pool_strdup(bp, key);
  50. return leaf;
  51. }
  52. void *stringmap_lookup_real(struct stringmap *t, const char *key, int enterf, const size_t T_size) {
  53. struct T *sp;
  54. struct stringmap_node *w, *new, *last;
  55. int len, cix, bit, fbit, svbit, ix, bitno;
  56. const char *k, *m, *sm;
  57. if (!t->root) {
  58. if (!enterf)
  59. return NULL;
  60. t->bp = block_pool_new(t->bp);
  61. t->root = T_new(t->bp, key, T_size);
  62. t->count = 1;
  63. return t->root;
  64. }
  65. /* Count full string length */
  66. for (k = key, len = 0; *k; k++, len++)
  67. ;
  68. if (t->count == 1) {
  69. w = t->root;
  70. svbit = 0;
  71. } else {
  72. w = t->root;
  73. bitno = len * CHECKBITS;
  74. for (;;) {
  75. bit = BITNO(w->bitno);
  76. fbit = bit > bitno ? 0 : P_BIT(key, bit);
  77. svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
  78. IS_LEFT_LEAF(w->bitno);
  79. w = w->lr[fbit];
  80. if (svbit)
  81. break;
  82. }
  83. }
  84. sp = (struct T *)w;
  85. sm = m = sp->str;
  86. k = key;
  87. /* Check for correct string and return */
  88. for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
  89. ;
  90. if (*m == 0 && *k == 0) {
  91. //if (!enterf && sp->value == NULL)
  92. // return NULL;
  93. return sp;
  94. }
  95. if (!enterf)
  96. return NULL; /* no string found and do not enter */
  97. ix = *m ^ *k;
  98. while ((ix & 1) == 0)
  99. ix >>= 1, cix++;
  100. /* Create new node */
  101. new = block_pool_alloc(t->bp, sizeof *new);
  102. bit = P_BIT(key, cix);
  103. new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
  104. new->lr[bit] = T_new(t->bp, key, T_size);
  105. if (t->count++ == 1) {
  106. new->lr[!bit] = t->root;
  107. new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
  108. t->root = new;
  109. return (struct T *)new->lr[bit];
  110. }
  111. w = t->root;
  112. last = NULL;
  113. for (;;) {
  114. fbit = w->bitno;
  115. bitno = BITNO(w->bitno);
  116. assert(bitno != cix);
  117. if (bitno > cix)
  118. break;
  119. svbit = P_BIT(key, bitno);
  120. last = w;
  121. w = w->lr[svbit];
  122. if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
  123. break;
  124. }
  125. new->lr[!bit] = w;
  126. if (last == NULL) {
  127. t->root = new;
  128. } else {
  129. last->lr[svbit] = new;
  130. last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
  131. }
  132. if (bitno < cix)
  133. new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
  134. return (struct T *)new->lr[bit];
  135. }