StringMap.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /**
  2. * Copyright (c) 2006-2020 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #ifndef LOVE_STRING_MAP_H
  21. #define LOVE_STRING_MAP_H
  22. #include "Exception.h"
  23. #include <string>
  24. #include <vector>
  25. // As StringMap instantiates std::vector<std::string> for instances that use
  26. // getNames(), we end up with multiple copies in the object files. This
  27. // declaration means we only emit it once (in StringMap.cpp).
  28. extern template class std::vector<std::string>;
  29. namespace love
  30. {
  31. template<typename T, unsigned int SIZE>
  32. class StringMap
  33. {
  34. public:
  35. struct Entry
  36. {
  37. const char *key;
  38. T value;
  39. };
  40. StringMap(const Entry *entries, unsigned int num)
  41. {
  42. for (unsigned int i = 0; i < SIZE; ++i)
  43. reverse[i] = nullptr;
  44. unsigned int n = num / sizeof(Entry);
  45. for (unsigned int i = 0; i < n; ++i)
  46. add(entries[i].key, entries[i].value);
  47. }
  48. bool streq(const char *a, const char *b)
  49. {
  50. while (*a != 0 && *b != 0)
  51. {
  52. if (*a != *b)
  53. return false;
  54. ++a;
  55. ++b;
  56. }
  57. return (*a == 0 && *b == 0);
  58. }
  59. bool find(const char *key, T &t)
  60. {
  61. unsigned int str_hash = djb2(key);
  62. for (unsigned int i = 0; i < MAX; ++i)
  63. {
  64. unsigned int str_i = (str_hash + i) % MAX;
  65. if (!records[str_i].set)
  66. return false;
  67. if (streq(records[str_i].key, key))
  68. {
  69. t = records[str_i].value;
  70. return true;
  71. }
  72. }
  73. return false;
  74. }
  75. bool find(T key, const char *&str)
  76. {
  77. unsigned int index = (unsigned int) key;
  78. if (index >= SIZE)
  79. return false;
  80. if (reverse[index] != nullptr)
  81. {
  82. str = reverse[index];
  83. return true;
  84. }
  85. else
  86. {
  87. return false;
  88. }
  89. }
  90. bool add(const char *key, T value)
  91. {
  92. unsigned int str_hash = djb2(key);
  93. bool inserted = false;
  94. for (unsigned int i = 0; i < MAX; ++i)
  95. {
  96. unsigned int str_i = (str_hash + i) % MAX;
  97. if (!records[str_i].set)
  98. {
  99. inserted = true;
  100. records[str_i].set = true;
  101. records[str_i].key = key;
  102. records[str_i].value = value;
  103. break;
  104. }
  105. }
  106. unsigned int index = (unsigned int) value;
  107. if (index >= SIZE)
  108. {
  109. printf("Constant %s out of bounds with %u!\n", key, index);
  110. return false;
  111. }
  112. reverse[index] = key;
  113. return inserted;
  114. }
  115. unsigned int djb2(const char *key)
  116. {
  117. unsigned int hash = 5381;
  118. int c;
  119. while ((c = *key++))
  120. hash = ((hash << 5) + hash) + c;
  121. return hash;
  122. }
  123. std::vector<std::string> getNames() const
  124. {
  125. std::vector<std::string> names;
  126. names.reserve(SIZE);
  127. for (unsigned int i = 0; i < SIZE; ++i)
  128. if (reverse[i] != nullptr)
  129. names.emplace_back(reverse[i]);
  130. return names;
  131. }
  132. private:
  133. struct Record
  134. {
  135. const char *key;
  136. T value;
  137. bool set;
  138. Record() : set(false) {}
  139. };
  140. static const unsigned int MAX = SIZE * 2;
  141. Record records[MAX];
  142. const char *reverse[SIZE];
  143. }; // StringMap
  144. #define STRINGMAP_DECLARE(type) \
  145. bool getConstant(const char *in, type &out); \
  146. bool getConstant(type in, const char *&out); \
  147. std::vector<std::string> getConstants(type); \
  148. #define STRINGMAP_BEGIN(type, count, name) \
  149. static StringMap<type, count>::Entry name##Entries[] =
  150. #define STRINGMAP_END(type, count, name) \
  151. ; \
  152. static StringMap<type, count> name##s(name##Entries, sizeof(name##Entries)); \
  153. bool getConstant(const char *in, type &out) { return name##s.find(in, out); } \
  154. bool getConstant(type in, const char *&out) { return name##s.find(in, out); } \
  155. std::vector<std::string> getConstants(type) { return name##s.getNames(); }
  156. } // love
  157. #endif // LOVE_STRING_MAP_H