PageRenderTime 25ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/vm/indexed-string-map.h

https://gitlab.com/alvinahmadov2/hhvm
C Header | 253 lines | 155 code | 40 blank | 58 comment | 16 complexity | 6e3b86253d11244d8546b9b8e531f900 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_VM_INDEXED_STRING_MAP_H_
  17. #define incl_HPHP_VM_INDEXED_STRING_MAP_H_
  18. #include "hphp/runtime/base/string-data.h"
  19. #include "hphp/runtime/vm/fixed-string-map.h"
  20. #include <folly/Range.h>
  21. namespace HPHP {
  22. //////////////////////////////////////////////////////////////////////
  23. /*
  24. * Several VM data structures can be accessed with both a string-based
  25. * lookup and by an index. This map supports both types of lookup.
  26. * (The index type is a template parameter in order to allow different
  27. * uses of this map to have different sized indexes).
  28. *
  29. * The number of elements must be fixed after initialization time
  30. * (since we use a FixedStringMap internally).
  31. */
  32. template<class T,
  33. bool CaseSensitive,
  34. class Index,
  35. Index InvalidIndex = Index(-1)>
  36. struct IndexedStringMap {
  37. struct Builder;
  38. explicit IndexedStringMap() {
  39. setSize(0);
  40. }
  41. ~IndexedStringMap() {
  42. clear();
  43. }
  44. IndexedStringMap(const IndexedStringMap&) = delete;
  45. IndexedStringMap& operator=(const IndexedStringMap&) = delete;
  46. void clear() {
  47. m_map.clear();
  48. setSize(0);
  49. }
  50. /*
  51. * Create an IndexedStringMap from the supplied builder. See
  52. * builder below.
  53. */
  54. void create(const Builder& b) {
  55. assert(!size() && "IndexedStringMap::create called more than once");
  56. setSize(b.size());
  57. m_map.init(b.size(), size() * sizeof(T));
  58. if (!b.size()) {
  59. // note that we have to initialize m_map even though its zero
  60. // sized (an empty FixedStringMap isn't quite empty - see
  61. // FixedStringMap::init).
  62. return;
  63. }
  64. std::copy(b.m_list.begin(), b.m_list.end(), mutableAccessList());
  65. for (typename Builder::const_iterator it = b.begin();
  66. it != b.end();
  67. ++it) {
  68. m_map.add(it->first, it->second);
  69. }
  70. }
  71. const T* accessList() const {
  72. return static_cast<const T*>(m_map.extraData());
  73. }
  74. T* mutableAccessList() { return const_cast<T*>(accessList()); }
  75. bool contains(const StringData* k) const { return m_map.find(k); }
  76. Index size() const { return m_map.extra(); }
  77. bool empty() const { return size() == 0; }
  78. // Find the index for an entry by name. Returns InvalidIndex if
  79. // there is no entry with this name.
  80. Index findIndex(const StringData* k) const {
  81. Index* i = m_map.find(k);
  82. if (!i) return InvalidIndex;
  83. return *i;
  84. }
  85. // Lookup entries in the map by string. Returns the entry or the
  86. // supplied default value if it doesn't exist.
  87. T lookupDefault(const StringData* k, T def) const {
  88. Index* i = m_map.find(k);
  89. if (!i) return def;
  90. return accessList()[*i];
  91. }
  92. // Lookup entries by index. Index must be in range or you get
  93. // undefined behavior.
  94. T& operator[](Index index) {
  95. assert(index < size());
  96. return mutableAccessList()[index];
  97. }
  98. const T& operator[](Index index) const {
  99. return (*const_cast<IndexedStringMap*>(this))[index];
  100. }
  101. folly::Range<const T*> range() const {
  102. return folly::range(accessList(), accessList() + size());
  103. }
  104. static constexpr ptrdiff_t vecOff() {
  105. return offsetof(IndexedStringMap, m_map) +
  106. FixedStringMap<Index,CaseSensitive,Index>::tableOff();
  107. }
  108. private:
  109. uint32_t byteSize() const { return size() * sizeof(T); }
  110. void setSize(Index size) { m_map.extra() = size; }
  111. FixedStringMap<Index,CaseSensitive,Index> m_map;
  112. };
  113. //////////////////////////////////////////////////////////////////////
  114. /*
  115. * Builder object for creating IndexedStringMaps. Fill one of these
  116. * up, and then pass it to IndexedStringMap::create.
  117. */
  118. template<class T, bool CaseSensitive, class Index, Index InvalidIndex>
  119. class IndexedStringMap<T,CaseSensitive,Index,InvalidIndex>::Builder {
  120. using EqObject = typename std::conditional<
  121. CaseSensitive,
  122. string_data_same,
  123. string_data_isame
  124. >::type;
  125. using Map = hphp_hash_map<
  126. const StringData*,
  127. Index,
  128. string_data_hash,
  129. EqObject
  130. >;
  131. public:
  132. typedef typename Map::const_iterator const_iterator;
  133. typedef typename Map::iterator iterator;
  134. iterator find(const StringData* key) { return m_map.find(key); }
  135. iterator begin() { return m_map.begin(); }
  136. iterator end() { return m_map.end(); }
  137. Index size() const { return m_list.size(); }
  138. const_iterator find(const StringData* key) const {
  139. return m_map.find(key);
  140. }
  141. const_iterator begin() const { return m_map.begin(); }
  142. const_iterator end() const { return m_map.end(); }
  143. T& operator[](Index idx) {
  144. assert(idx >= 0);
  145. assert(size_t(idx) < m_list.size());
  146. return m_list[idx];
  147. }
  148. const T& operator[](Index idx) const {
  149. return (*const_cast<Builder*>(this))[idx];
  150. }
  151. /*
  152. * Add an object to the position on the end, and allow lookup by
  153. * `name'.
  154. */
  155. void add(const StringData* name, const T& t) {
  156. if (m_list.size() >= size_t(std::numeric_limits<Index>::max())) {
  157. assert(false && "IndexedStringMap::Builder overflowed");
  158. abort();
  159. }
  160. if (!m_map.emplace(name, m_list.size()).second) {
  161. abort();
  162. }
  163. m_list.push_back(t);
  164. }
  165. /*
  166. * Adds objects that occupy indexes but can't be located by name.
  167. */
  168. void addUnnamed(const T& t) {
  169. m_list.push_back(t);
  170. }
  171. /*
  172. * Implement custom separate versions of (de)serialization code to
  173. * be more compact about what we put on disk. (Instead of just
  174. * pumping through our m_list and m_map.)
  175. */
  176. // Deserialization version.
  177. template<class SerDe>
  178. typename std::enable_if<SerDe::deserializing>::type serde(SerDe& sd) {
  179. uint32_t size;
  180. sd(size);
  181. for (uint32_t i = 0; i < size; ++i) {
  182. const StringData* name;
  183. T t;
  184. sd(name)(t);
  185. if (name) {
  186. add(name, t);
  187. } else {
  188. addUnnamed(t);
  189. }
  190. }
  191. }
  192. // Serialization version.
  193. template<class SerDe>
  194. typename std::enable_if<!SerDe::deserializing>::type serde(SerDe& sd) {
  195. std::vector<const StringData*> names(m_list.size());
  196. for (typename Map::const_iterator it = m_map.begin();
  197. it != m_map.end();
  198. ++it) {
  199. names[it->second] = it->first;
  200. }
  201. sd(uint32_t(m_list.size()));
  202. for (uint32_t i = 0; i < m_list.size(); ++i) {
  203. sd(names[i])(m_list[i]);
  204. }
  205. }
  206. private:
  207. friend class IndexedStringMap;
  208. std::vector<T> m_list;
  209. Map m_map;
  210. };
  211. //////////////////////////////////////////////////////////////////////
  212. }
  213. #endif