strcache.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /* ----- strcache.c ----- */
  2. typedef unsigned long hash_t;
  3. hash_t strhash(char* str) {
  4. unsigned long h = 0;
  5. int c;
  6. while(c = *str++) {
  7. h = c + (h << 6) + (h << 16) - h;
  8. }
  9. return h;
  10. }
  11. hash_t strnhash(char* str, size_t n) {
  12. unsigned long h = 0;
  13. int c;
  14. while((c = *str++) && n--) {
  15. h = c + (h << 6) + (h << 16) - h;
  16. }
  17. return h;
  18. }
  19. typedef struct {
  20. hash_t hash;
  21. char* str;
  22. unsigned int len;
  23. int refs;
  24. } string_cache_bucket;
  25. typedef struct {
  26. int fill;
  27. int alloc;
  28. string_cache_bucket* buckets;
  29. } string_cache_t;
  30. string_cache_t string_cache;
  31. void string_cache_init(int alloc) {
  32. string_cache.fill = 0;
  33. string_cache.alloc = alloc ? alloc : 1024;
  34. string_cache.buckets = calloc(1, string_cache.alloc * sizeof(*string_cache.buckets));
  35. }
  36. int string_cache_find_bucket(string_cache_t* ht, hash_t hash, char* key) {
  37. int b = hash % ht->alloc;
  38. for(int i = 0; i < ht->alloc; i++) {
  39. // empty bucket
  40. if(ht->buckets[b].str == NULL) return b;
  41. // full bucket
  42. if(ht->buckets[b].hash == hash) {
  43. if(0 == strcmp(key, ht->buckets[b].str)) {
  44. return b;
  45. }
  46. }
  47. // probe forward on collisions
  48. b = (b + 1) % ht->alloc;
  49. }
  50. // should never reach here
  51. printf("oops. -1 bucket \n");
  52. return -1;
  53. }
  54. void string_cache_expand(string_cache_t* ht) {
  55. int old_alloc = ht->alloc;
  56. ht->alloc *= 2;
  57. string_cache_bucket* old = ht->buckets;
  58. ht->buckets = calloc(1, ht->alloc * sizeof(*ht->buckets));
  59. for(int i = 0, f = 0; i < old_alloc && f < ht->fill; i++) {
  60. if(!old[i].str) continue;
  61. int b = string_cache_find_bucket(ht, old[i].hash, old[i].str);
  62. ht->buckets[b] = old[i];
  63. f++;
  64. }
  65. free(old);
  66. }
  67. char* strcache(char* in) {
  68. hash_t hash = strhash(in);
  69. int b = string_cache_find_bucket(&string_cache, hash, in);
  70. if(!string_cache.buckets[b].str) {
  71. if(string_cache.fill > string_cache.alloc * .80) {
  72. string_cache_expand(&string_cache);
  73. // the bucket location has changed
  74. b = string_cache_find_bucket(&string_cache, hash, in);
  75. }
  76. string_cache.fill++;
  77. string_cache.buckets[b].str = strdup(in);
  78. string_cache.buckets[b].hash = hash;
  79. string_cache.buckets[b].refs = 1;
  80. string_cache.buckets[b].len = strlen(in);
  81. }
  82. else {
  83. string_cache.buckets[b].refs++;
  84. }
  85. return string_cache.buckets[b].str;
  86. }
  87. char* strncache(char* in, size_t n) {
  88. hash_t hash = strnhash(in, n);
  89. int b = string_cache_find_bucket(&string_cache, hash, in);
  90. if(!string_cache.buckets[b].str) {
  91. if(string_cache.fill > string_cache.alloc * .80) {
  92. string_cache_expand(&string_cache);
  93. // the bucket location has changed
  94. b = string_cache_find_bucket(&string_cache, hash, in);
  95. }
  96. string_cache.fill++;
  97. string_cache.buckets[b].str = strndup(in, n);
  98. string_cache.buckets[b].hash = hash;
  99. string_cache.buckets[b].refs = 1;
  100. string_cache.buckets[b].len = n;
  101. }
  102. else {
  103. string_cache.buckets[b].refs++;
  104. }
  105. return string_cache.buckets[b].str;
  106. }
  107. void struncache(char* in) {
  108. hash_t hash = strhash(in);
  109. int b = string_cache_find_bucket(&string_cache, hash, in);
  110. if(!string_cache.buckets[b].str) {
  111. // normal string, free it
  112. free(in);
  113. return;
  114. }
  115. string_cache.buckets[b].refs--;
  116. if(string_cache.buckets[b].refs == 0) {
  117. // just do nothing for now. deletion is a pain.
  118. }
  119. }
  120. /* -END- strcache.c ----- */