as_symboltable.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2012-2014 Andreas Jonsson
  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
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. //
  24. // as_symboltable.h
  25. //
  26. // Created on: Jun 19, 2012
  27. // Author: Markus Lenger, a.k.a. mlengerx
  28. //
  29. // This class is used for fast symbol lookups while parsing or loading bytecode
  30. //
  31. #ifndef AS_SYMBOLTABLE_H
  32. #define AS_SYMBOLTABLE_H
  33. #include "as_config.h"
  34. #include "as_memory.h"
  35. #include "as_string.h"
  36. #include "as_map.h"
  37. #include "as_datatype.h"
  38. #include "as_namespace.h"
  39. BEGIN_AS_NAMESPACE
  40. // Interface to avoid nested templates which is not well supported by older compilers, e.g. MSVC6
  41. struct asIFilter
  42. {
  43. virtual bool operator()(const void*) const = 0;
  44. };
  45. // forward declaration
  46. template<class T>
  47. class asCSymbolTable;
  48. // Iterator that allows iterating in index order
  49. template<class T, class T2 = T>
  50. class asCSymbolTableIterator
  51. {
  52. public:
  53. T2* operator*() const;
  54. T2* operator->() const;
  55. asCSymbolTableIterator<T, T2>& operator++(int);
  56. asCSymbolTableIterator<T, T2>& operator--(int);
  57. operator bool() const;
  58. int GetIndex() const { return m_idx; }
  59. private:
  60. friend class asCSymbolTable<T>;
  61. asCSymbolTableIterator<T, T2>(asCSymbolTable<T> *table);
  62. void Next();
  63. void Previous();
  64. asCSymbolTable<T>* m_table;
  65. unsigned int m_idx;
  66. };
  67. // Symbol table mapping namespace + name to symbols
  68. // The structure keeps the entries indexed in an array so the indices will not change
  69. // There is also a map for a quick lookup. The map supports multiple entries with the same name
  70. template<class T>
  71. class asCSymbolTable
  72. {
  73. public:
  74. typedef asCSymbolTableIterator<T, T> iterator;
  75. typedef asCSymbolTableIterator<T, const T> const_iterator;
  76. asCSymbolTable(unsigned int initialCapacity = 0);
  77. int GetFirstIndex(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
  78. int GetFirstIndex(const asSNameSpace *ns, const asCString &name) const;
  79. int GetLastIndex() const;
  80. int GetIndex(const T*) const;
  81. T* GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
  82. T* GetFirst(const asSNameSpace *ns, const asCString &name);
  83. const T* GetFirst(const asSNameSpace *ns, const asCString &name) const;
  84. T* Get(unsigned int index);
  85. const T* Get(unsigned int index) const;
  86. T* GetLast();
  87. const T* GetLast() const;
  88. const asCArray<unsigned int> &GetIndexes(const asSNameSpace *ns, const asCString &name) const;
  89. int Put(T* entry);
  90. unsigned int GetSize() const;
  91. void SwapWith(asCSymbolTable<T> &other);
  92. void Clear();
  93. bool Erase(unsigned int idx);
  94. void Allocate(unsigned int elem_cnt, bool keep_data);
  95. iterator List();
  96. const_iterator List() const;
  97. private:
  98. // Don't allow assignment
  99. asCSymbolTable<T>& operator=(const asCSymbolTable<T> &other) { return *this; }
  100. friend class asCSymbolTableIterator<T, T>;
  101. friend class asCSymbolTableIterator<T, const T>;
  102. void GetKey(const T *entry, asSNameSpaceNamePair &key) const;
  103. bool CheckIdx(unsigned idx) const;
  104. asCMap<asSNameSpaceNamePair, asCArray<unsigned int> > m_map;
  105. asCArray<T*> m_entries;
  106. unsigned int m_size;
  107. };
  108. template<class T>
  109. void asCSymbolTable<T>::SwapWith(asCSymbolTable<T> &other)
  110. {
  111. m_map.SwapWith(other.m_map);
  112. m_entries.SwapWith(other.m_entries);
  113. unsigned int tmp = m_size;
  114. m_size = other.m_size;
  115. other.m_size = tmp;
  116. }
  117. // Constructor
  118. // initialCapacity gives the number of entries to allocate in advance
  119. template<class T>
  120. asCSymbolTable<T>::asCSymbolTable(unsigned initialCapacity) : m_entries(initialCapacity)
  121. {
  122. m_size = 0;
  123. }
  124. template<class T>
  125. int asCSymbolTable<T>::GetFirstIndex(
  126. const asSNameSpace *ns,
  127. const asCString &name,
  128. const asIFilter &filter) const
  129. {
  130. asSNameSpaceNamePair key(ns, name);
  131. asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
  132. if( m_map.MoveTo(&cursor, key) )
  133. {
  134. const asCArray<unsigned int> &arr = m_map.GetValue(cursor);
  135. for( unsigned int n = 0; n < arr.GetLength(); n++ )
  136. {
  137. T *entry = m_entries[arr[n]];
  138. if( entry && filter(entry) )
  139. return arr[n];
  140. }
  141. }
  142. return -1;
  143. }
  144. template<class T>
  145. const asCArray<unsigned int> &asCSymbolTable<T>::GetIndexes(const asSNameSpace *ns, const asCString &name) const
  146. {
  147. asSNameSpaceNamePair key(ns, name);
  148. asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
  149. if( m_map.MoveTo(&cursor, key) )
  150. return m_map.GetValue(cursor);
  151. static asCArray<unsigned int> dummy;
  152. return dummy;
  153. }
  154. template<class T>
  155. T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comp) const
  156. {
  157. int idx = GetFirstIndex(ns, name, comp);
  158. if (idx != -1) return m_entries[idx];
  159. return 0;
  160. }
  161. template<class T>
  162. int asCSymbolTable<T>::GetFirstIndex(const asSNameSpace *ns, const asCString &name) const
  163. {
  164. asSNameSpaceNamePair key(ns, name);
  165. asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
  166. if( m_map.MoveTo(&cursor, key) )
  167. return m_map.GetValue(cursor)[0];
  168. return -1;
  169. }
  170. // Find the index of a certain symbol
  171. // ATTENTION: this function has linear runtime complexity O(n)!!
  172. template<class T>
  173. int asCSymbolTable<T>::GetIndex(const T* entry) const
  174. {
  175. for( unsigned int n = 0; n < m_entries.GetLength(); n++ )
  176. if( m_entries[n] == entry )
  177. return n;
  178. return -1;
  179. }
  180. template<class T>
  181. T* asCSymbolTable<T>::Get(unsigned idx)
  182. {
  183. if( !CheckIdx(idx) )
  184. return 0;
  185. return m_entries[idx];
  186. }
  187. template<class T>
  188. const T* asCSymbolTable<T>::Get(unsigned idx) const
  189. {
  190. return const_cast< asCSymbolTable<T>* >(this)->Get(idx);
  191. }
  192. template<class T>
  193. T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name)
  194. {
  195. int idx = GetFirstIndex(ns, name);
  196. return Get(idx);
  197. }
  198. template<class T>
  199. const T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name) const
  200. {
  201. return const_cast< asCSymbolTable<T>* >(this)->GetFirst(ns, name);
  202. }
  203. template<class T>
  204. T* asCSymbolTable<T>::GetLast()
  205. {
  206. return Get(GetLastIndex());
  207. }
  208. template<class T>
  209. const T* asCSymbolTable<T>::GetLast() const
  210. {
  211. return const_cast< asCSymbolTable<T>* >(this)->GetLast();
  212. }
  213. // Clear the symbol table
  214. // ATTENTION: The contained symbols are not rleased. This is up to the client
  215. template<class T>
  216. void asCSymbolTable<T>::Clear()
  217. {
  218. m_entries.SetLength(0);
  219. m_map.EraseAll();
  220. m_size = 0;
  221. }
  222. // Pre-allocate slots for elemCnt entries
  223. template<class T>
  224. void asCSymbolTable<T>::Allocate(unsigned elemCnt, bool keepData)
  225. {
  226. asASSERT( elemCnt >= m_entries.GetLength() );
  227. m_entries.Allocate(elemCnt, keepData);
  228. if( !keepData )
  229. m_map.EraseAll();
  230. }
  231. template<class T>
  232. bool asCSymbolTable<T>::Erase(unsigned idx)
  233. {
  234. if( !CheckIdx(idx) )
  235. {
  236. asASSERT(false);
  237. return false;
  238. }
  239. T *entry = m_entries[idx];
  240. asASSERT(entry);
  241. if( !entry )
  242. return false;
  243. // Remove the symbol from the lookup map
  244. asSNameSpaceNamePair key;
  245. GetKey(entry, key);
  246. asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
  247. if( m_map.MoveTo(&cursor, key) )
  248. {
  249. asCArray<unsigned int> &arr = m_map.GetValue(cursor);
  250. arr.RemoveValue(idx);
  251. if( arr.GetLength() == 0 )
  252. m_map.Erase(cursor);
  253. }
  254. else
  255. asASSERT(false);
  256. // Remove the symbol from the indexed array
  257. if( idx == m_entries.GetLength() - 1 )
  258. m_entries.PopLast();
  259. else
  260. {
  261. // Must keep the array packed
  262. int prevIdx = int(m_entries.GetLength()-1);
  263. m_entries[idx] = m_entries.PopLast();
  264. // Update the index in the lookup map
  265. entry = m_entries[idx];
  266. GetKey(entry, key);
  267. if( m_map.MoveTo(&cursor, key) )
  268. {
  269. asCArray<unsigned int> &arr = m_map.GetValue(cursor);
  270. arr[arr.IndexOf(prevIdx)] = idx;
  271. }
  272. else
  273. asASSERT(false);
  274. }
  275. m_size--;
  276. return true;
  277. }
  278. template<class T>
  279. int asCSymbolTable<T>::Put(T *entry)
  280. {
  281. unsigned int idx = (unsigned int)(m_entries.GetLength());
  282. asSNameSpaceNamePair key;
  283. GetKey(entry, key);
  284. asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
  285. if( m_map.MoveTo(&cursor, key) )
  286. m_map.GetValue(cursor).PushLast(idx);
  287. else
  288. {
  289. asCArray<unsigned int> arr(1);
  290. arr.PushLast(idx);
  291. m_map.Insert(key, arr);
  292. }
  293. m_entries.PushLast(entry);
  294. m_size++;
  295. return idx;
  296. }
  297. // Return key for specified symbol (namespace and name are used to generate the key)
  298. template<class T>
  299. void asCSymbolTable<T>::GetKey(const T *entry, asSNameSpaceNamePair &key) const
  300. {
  301. key = asSNameSpaceNamePair(entry->nameSpace, entry->name);
  302. }
  303. template<class T>
  304. unsigned int asCSymbolTable<T>::GetSize() const
  305. {
  306. return m_size;
  307. }
  308. template<class T>
  309. bool asCSymbolTable<T>::CheckIdx(unsigned int idx) const
  310. {
  311. return idx < m_entries.GetLength();
  312. }
  313. template<class T>
  314. int asCSymbolTable<T>::GetLastIndex() const
  315. {
  316. unsigned int idx = (unsigned int)(m_entries.GetLength()) - 1;
  317. asASSERT( idx == asUINT(-1) || m_entries[idx] );
  318. return int(idx);
  319. }
  320. template<class T>
  321. asCSymbolTableIterator<T, T> asCSymbolTable<T>::List()
  322. {
  323. return asCSymbolTableIterator<T, T>(this);
  324. }
  325. template<class T>
  326. typename asCSymbolTable<T>::const_iterator asCSymbolTable<T>::List() const
  327. {
  328. return asCSymbolTableIterator<T, const T>(const_cast< asCSymbolTable<T> *>(this));
  329. }
  330. /////////////////////////////////////////////////////////////////////////////////////////////////
  331. // Iterator
  332. template<class T, class T2>
  333. asCSymbolTableIterator<T, T2>::asCSymbolTableIterator(asCSymbolTable<T> *table) : m_table(table), m_idx(0)
  334. {
  335. unsigned int sz = (unsigned int)(m_table->m_entries.GetLength());
  336. while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
  337. m_idx++;
  338. }
  339. template<class T, class T2>
  340. T2* asCSymbolTableIterator<T, T2>::operator*() const
  341. {
  342. asASSERT(m_table->CheckIdx(m_idx));
  343. return m_table->m_entries[m_idx];
  344. }
  345. template<class T, class T2>
  346. T2* asCSymbolTableIterator<T, T2>::operator->() const
  347. {
  348. asASSERT(m_table->CheckIdx(m_idx));
  349. return m_table->m_entries[m_idx];
  350. }
  351. template<class T, class T2>
  352. asCSymbolTableIterator<T, T2>& asCSymbolTableIterator<T, T2>::operator++(int)
  353. {
  354. Next();
  355. return *this;
  356. }
  357. // Return true if more elements are following
  358. // ATTENTION: When deleting the object currently pointed to by this iterator this
  359. // method returns false even though there might be more elements in the list
  360. template<class T, class T2>
  361. asCSymbolTableIterator<T, T2>::operator bool() const
  362. {
  363. return m_idx < m_table->m_entries.GetLength() && m_table->m_entries[m_idx] != 0;
  364. }
  365. template<class T, class T2>
  366. void asCSymbolTableIterator<T, T2>::Next()
  367. {
  368. unsigned int sz = (unsigned int)(m_table->m_entries.GetLength());
  369. m_idx++;
  370. while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
  371. m_idx++;
  372. }
  373. template<class T, class T2>
  374. void asCSymbolTableIterator<T, T2>::Previous()
  375. {
  376. // overflow on stepping over first element
  377. unsigned int sz = (unsigned int)(m_table->m_entries.GetLength());
  378. m_idx--;
  379. while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
  380. m_idx--;
  381. }
  382. template<class T, class T2>
  383. asCSymbolTableIterator<T, T2>& asCSymbolTableIterator<T, T2>::operator--(int)
  384. {
  385. Previous();
  386. return *this;
  387. }
  388. END_AS_NAMESPACE
  389. #endif // AS_SYMBOLTABLE_H