ptable.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // -*- C++ -*-
  2. // Ptable-related definitions, see libgroff/ptable.cc.
  3. #include <assert.h>
  4. #include <string.h>
  5. #ifdef TRADITIONAL_CPP
  6. #define name2(a,b) a/**/b
  7. #else /* not TRADITIONAL_CPP */
  8. #define name2(a,b) name2x(a,b)
  9. #define name2x(a,b) a ## b
  10. #endif /* not TRADITIONAL_CPP */
  11. #define PTABLE(T) name2(T,_ptable)
  12. #define PASSOC(T) name2(T,_passoc)
  13. #define PTABLE_ITERATOR(T) name2(T,_ptable_iterator)
  14. extern unsigned next_ptable_size(unsigned);
  15. extern unsigned long hash_string(const char *);
  16. #define declare_ptable(T) \
  17. \
  18. struct PASSOC(T) { \
  19. char *key; \
  20. T *val; \
  21. PASSOC(T)(); \
  22. }; \
  23. \
  24. struct PTABLE(T); \
  25. \
  26. class PTABLE_ITERATOR(T) { \
  27. PTABLE(T) *p; \
  28. unsigned i; \
  29. public: \
  30. PTABLE_ITERATOR(T)(PTABLE(T) *); \
  31. int next(const char **, T **); \
  32. }; \
  33. \
  34. class PTABLE(T) { \
  35. PASSOC(T) *v; \
  36. unsigned size; \
  37. unsigned used; \
  38. enum { FULL_NUM = 2, FULL_DEN = 3, INITIAL_SIZE = 17 }; \
  39. public: \
  40. PTABLE(T)(); \
  41. ~PTABLE(T)(); \
  42. void define(const char *, T *); \
  43. T *lookup(const char *); \
  44. friend class PTABLE_ITERATOR(T); \
  45. };
  46. #define implement_ptable(T) \
  47. \
  48. PASSOC(T)::PASSOC(T)() \
  49. : key(0), val(0) \
  50. { \
  51. } \
  52. \
  53. PTABLE(T)::PTABLE(T)() \
  54. { \
  55. v = new PASSOC(T)[size = INITIAL_SIZE]; \
  56. used = 0; \
  57. } \
  58. \
  59. PTABLE(T)::~PTABLE(T)() \
  60. { \
  61. for (unsigned i = 0; i < size; i++) { \
  62. a_delete v[i].key; \
  63. delete v[i].val; \
  64. } \
  65. a_delete v; \
  66. } \
  67. \
  68. void PTABLE(T)::define(const char *key, T *val) \
  69. { \
  70. assert(key != 0); \
  71. unsigned long h = hash_string(key); \
  72. unsigned n; \
  73. for (n = unsigned(h % size); \
  74. v[n].key != 0; \
  75. n = (n == 0 ? size - 1 : n - 1)) \
  76. if (strcmp(v[n].key, key) == 0) { \
  77. delete v[n].val; \
  78. v[n].val = val; \
  79. return; \
  80. } \
  81. if (val == 0) \
  82. return; \
  83. if (used*FULL_DEN >= size*FULL_NUM) { \
  84. PASSOC(T) *oldv = v; \
  85. unsigned old_size = size; \
  86. size = next_ptable_size(size); \
  87. v = new PASSOC(T)[size]; \
  88. for (unsigned i = 0; i < old_size; i++) \
  89. if (oldv[i].key != 0) { \
  90. if (oldv[i].val == 0) \
  91. a_delete oldv[i].key; \
  92. else { \
  93. unsigned j; \
  94. for (j = unsigned(hash_string(oldv[i].key) % size); \
  95. v[j].key != 0; \
  96. j = (j == 0 ? size - 1 : j - 1)) \
  97. ; \
  98. v[j].key = oldv[i].key; \
  99. v[j].val = oldv[i].val; \
  100. } \
  101. } \
  102. for (n = unsigned(h % size); \
  103. v[n].key != 0; \
  104. n = (n == 0 ? size - 1 : n - 1)) \
  105. ; \
  106. a_delete oldv; \
  107. } \
  108. char *temp = new char[strlen(key)+1]; \
  109. strcpy(temp, key); \
  110. v[n].key = temp; \
  111. v[n].val = val; \
  112. used++; \
  113. } \
  114. \
  115. T *PTABLE(T)::lookup(const char *key) \
  116. { \
  117. assert(key != 0); \
  118. for (unsigned n = unsigned(hash_string(key) % size); \
  119. v[n].key != 0; \
  120. n = (n == 0 ? size - 1 : n - 1)) \
  121. if (strcmp(v[n].key, key) == 0) \
  122. return v[n].val; \
  123. return 0; \
  124. } \
  125. \
  126. PTABLE_ITERATOR(T)::PTABLE_ITERATOR(T)(PTABLE(T) *t) \
  127. : p(t), i(0) \
  128. { \
  129. } \
  130. \
  131. int PTABLE_ITERATOR(T)::next(const char **keyp, T **valp) \
  132. { \
  133. unsigned size = p->size; \
  134. PASSOC(T) *v = p->v; \
  135. for (; i < size; i++) \
  136. if (v[i].key != 0) { \
  137. *keyp = v[i].key; \
  138. *valp = v[i].val; \
  139. i++; \
  140. return 1; \
  141. } \
  142. return 0; \
  143. }