as_symboltable.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2012 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. BEGIN_AS_NAMESPACE
  39. // TODO: cleanup: This should be in its own header. It is only here because it is
  40. // needed for the template and cannot be resolved with a forward declaration
  41. struct asSNameSpace
  42. {
  43. asCString name;
  44. // TODO: namespace: A namespace should have access masks. The application should be
  45. // able to restrict specific namespaces from access to specific modules
  46. };
  47. // Interface to avoid nested templates which is not well supported by older compilers, e.g. MSVC6
  48. struct asIFilter
  49. {
  50. virtual bool operator()(const void*) const = 0;
  51. };
  52. // forward declaration
  53. template<class T>
  54. class asCSymbolTable;
  55. // Iterator that allows iterating in index order
  56. template<class T, class T2 = T>
  57. class asCSymbolTableIterator
  58. {
  59. public:
  60. T2* operator*() const;
  61. T2* operator->() const;
  62. asCSymbolTableIterator<T, T2>& operator++(int);
  63. asCSymbolTableIterator<T, T2>& operator--(int);
  64. operator bool() const;
  65. int GetIndex() const { return m_idx; }
  66. private:
  67. friend class asCSymbolTable<T>;
  68. asCSymbolTableIterator<T, T2>(asCSymbolTable<T> *table);
  69. void Next();
  70. void Previous();
  71. asCSymbolTable<T>* m_table;
  72. unsigned int m_idx;
  73. };
  74. // Symbol table mapping namespace + name to symbols
  75. template<class T>
  76. class asCSymbolTable
  77. {
  78. public:
  79. typedef asCSymbolTableIterator<T, T> iterator;
  80. typedef asCSymbolTableIterator<T, const T> const_iterator;
  81. asCSymbolTable(unsigned int initialCapacity = 0);
  82. int GetFirstIndex(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
  83. int GetFirstIndex(const asSNameSpace *ns, const asCString &name) const;
  84. int GetLastIndex() const;
  85. int GetIndex(const T*) const;
  86. T* GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
  87. T* GetFirst(const asSNameSpace *ns, const asCString &name);
  88. const T* GetFirst(const asSNameSpace *ns, const asCString &name) const;
  89. T* Get(unsigned int index);
  90. const T* Get(unsigned int index) const;
  91. T* GetLast();
  92. const T* GetLast() const;
  93. const asCArray<unsigned int> &GetIndexes(const asSNameSpace *ns, const asCString &name) const;
  94. int Put(T* entry);
  95. unsigned int GetSize() const;
  96. void SwapWith(asCSymbolTable<T> &other);
  97. void Clear();
  98. bool Erase(unsigned int idx);
  99. void Allocate(unsigned int elem_cnt, bool keep_data);
  100. iterator List();
  101. const_iterator List() const;
  102. private:
  103. // Don't allow assignment
  104. asCSymbolTable<T>& operator=(const asCSymbolTable<T> &other) { return *this; }
  105. friend class asCSymbolTableIterator<T, T>;
  106. friend class asCSymbolTableIterator<T, const T>;
  107. void GetKey(const T *entry, asCString &key) const;
  108. void BuildKey(const asSNameSpace *ns, const asCString &name, asCString &key) const;
  109. bool CheckIdx(unsigned idx) const;
  110. asCMap<asCString, asCArray<unsigned int> > m_map;
  111. asCArray<T*> m_entries;
  112. unsigned int m_size;
  113. };
  114. template<class T>
  115. void asCSymbolTable<T>::SwapWith(asCSymbolTable<T> &other)
  116. {
  117. m_map.SwapWith(other.m_map);
  118. m_entries.SwapWith(other.m_entries);
  119. unsigned int tmp = m_size;
  120. m_size = other.m_size;
  121. other.m_size = tmp;
  122. }
  123. // Constructor
  124. // initialCapacity gives the number of entries to allocate in advance
  125. template<class T>
  126. asCSymbolTable<T>::asCSymbolTable(unsigned initialCapacity) : m_entries(initialCapacity)
  127. {
  128. m_size = 0;
  129. }
  130. template<class T>
  131. int asCSymbolTable<T>::GetFirstIndex(
  132. const asSNameSpace *ns,
  133. const asCString &name,
  134. const asIFilter &filter) const
  135. {
  136. asCString key;
  137. BuildKey(ns, name, key);
  138. asSMapNode<asCString, asCArray<unsigned int> > *cursor;
  139. if( m_map.MoveTo(&cursor, key) )
  140. {
  141. const asCArray<unsigned int> &arr = m_map.GetValue(cursor);
  142. for( unsigned int n = 0; n < arr.GetLength(); n++ )
  143. {
  144. T *entry = m_entries[arr[n]];
  145. if( entry && filter(entry) )
  146. return arr[n];
  147. }
  148. }
  149. return -1;
  150. }
  151. template<class T>
  152. const asCArray<unsigned int> &asCSymbolTable<T>::GetIndexes(const asSNameSpace *ns, const asCString &name) const
  153. {
  154. asCString key;
  155. BuildKey(ns, name, key);
  156. asSMapNode<asCString, asCArray<unsigned int> > *cursor;
  157. if( m_map.MoveTo(&cursor, key) )
  158. return m_map.GetValue(cursor);
  159. static asCArray<unsigned int> dummy;
  160. return dummy;
  161. }
  162. template<class T>
  163. T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comp) const
  164. {
  165. int idx = GetFirstIndex(ns, name, comp);
  166. if (idx != -1) return m_entries[idx];
  167. return 0;
  168. }
  169. template<class T>
  170. int asCSymbolTable<T>::GetFirstIndex(const asSNameSpace *ns, const asCString &name) const
  171. {
  172. asCString key;
  173. BuildKey(ns, name, key);
  174. asSMapNode<asCString, asCArray<unsigned int> > *cursor;
  175. if( m_map.MoveTo(&cursor, key) )
  176. return m_map.GetValue(cursor)[0];
  177. return -1;
  178. }
  179. // Find the index of a certain symbol
  180. // ATTENTION: this function has linear runtime complexity O(n)!!
  181. template<class T>
  182. int asCSymbolTable<T>::GetIndex(const T* entry) const
  183. {
  184. for( unsigned int n = 0; n < m_entries.GetLength(); n++ )
  185. if( m_entries[n] == entry )
  186. return n;
  187. return -1;
  188. }
  189. template<class T>
  190. T* asCSymbolTable<T>::Get(unsigned idx)
  191. {
  192. if( !CheckIdx(idx) )
  193. return 0;
  194. return m_entries[idx];
  195. }
  196. template<class T>
  197. const T* asCSymbolTable<T>::Get(unsigned idx) const
  198. {
  199. return const_cast< asCSymbolTable<T>* >(this)->Get(idx);
  200. }
  201. template<class T>
  202. T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name)
  203. {
  204. int idx = GetFirstIndex(ns, name);
  205. return Get(idx);
  206. }
  207. template<class T>
  208. const T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name) const
  209. {
  210. return const_cast< asCSymbolTable<T>* >(this)->GetFirst(ns, name);
  211. }
  212. template<class T>
  213. T* asCSymbolTable<T>::GetLast()
  214. {
  215. return Get(GetLastIndex());
  216. }
  217. template<class T>
  218. const T* asCSymbolTable<T>::GetLast() const
  219. {
  220. return const_cast< asCSymbolTable<T>* >(this)->GetLast();
  221. }
  222. // Clear the symbol table
  223. // ATTENTION: The contained symbols are not rleased. This is up to the client
  224. template<class T>
  225. void asCSymbolTable<T>::Clear()
  226. {
  227. m_entries.SetLength(0);
  228. m_map.EraseAll();
  229. m_size = 0;
  230. }
  231. // Pre-allocate slots for elemCnt entries
  232. template<class T>
  233. void asCSymbolTable<T>::Allocate(unsigned elemCnt, bool keepData)
  234. {
  235. asASSERT( elemCnt >= m_entries.GetLength() );
  236. m_entries.Allocate(elemCnt, keepData);
  237. if( !keepData )
  238. m_map.EraseAll();
  239. }
  240. template<class T>
  241. bool asCSymbolTable<T>::Erase(unsigned idx)
  242. {
  243. if( !CheckIdx(idx) )
  244. {
  245. asASSERT(false);
  246. return false;
  247. }
  248. T *entry = m_entries[idx];
  249. asASSERT(entry);
  250. if( !entry )
  251. return false;
  252. if( idx == m_entries.GetLength() - 1 )
  253. {
  254. m_entries.PopLast();
  255. // TODO: Should remove all trailing empty slots
  256. }
  257. else
  258. m_entries[idx] = 0;
  259. m_size--;
  260. asCString key;
  261. GetKey(entry, key);
  262. asSMapNode<asCString, asCArray<unsigned int> > *cursor;
  263. if( m_map.MoveTo(&cursor, key) )
  264. {
  265. asCArray<unsigned int> &arr = m_map.GetValue(cursor);
  266. arr.RemoveValue(idx);
  267. if( arr.GetLength() == 0 )
  268. m_map.Erase(cursor);
  269. }
  270. else
  271. asASSERT(false);
  272. return true;
  273. }
  274. template<class T>
  275. int asCSymbolTable<T>::Put(T *entry)
  276. {
  277. unsigned int idx = (unsigned int)(m_entries.GetLength());
  278. asCString key;
  279. GetKey(entry, key);
  280. asSMapNode<asCString, asCArray<unsigned int> > *cursor;
  281. if( m_map.MoveTo(&cursor, key) )
  282. m_map.GetValue(cursor).PushLast(idx);
  283. else
  284. {
  285. asCArray<unsigned int> arr(1);
  286. arr.PushLast(idx);
  287. m_map.Insert(key, arr);
  288. }
  289. m_entries.PushLast(entry);
  290. m_size++;
  291. return idx;
  292. }
  293. template<class T>
  294. void asCSymbolTable<T>::BuildKey(const asSNameSpace *ns, const asCString &name, asCString &key) const
  295. {
  296. // TODO: optimize: The key shouldn't be just an asCString. It should keep the
  297. // namespace as a pointer, so it can be compared as pointer.
  298. // Which should be compared first, the namespace or the name? There is likely
  299. // going to be many symbols with the same namespace, so it is probably best to
  300. // compare the name first
  301. key = ns->name + "::" + name;
  302. }
  303. // Return key for specified symbol (namespace and name are used to generate the key)
  304. template<class T>
  305. void asCSymbolTable<T>::GetKey(const T *entry, asCString &key) const
  306. {
  307. BuildKey(entry->nameSpace, entry->name, key);
  308. }
  309. template<class T>
  310. unsigned int asCSymbolTable<T>::GetSize() const
  311. {
  312. return m_size;
  313. }
  314. template<class T>
  315. bool asCSymbolTable<T>::CheckIdx(unsigned int idx) const
  316. {
  317. return idx < m_entries.GetLength();
  318. }
  319. template<class T>
  320. int asCSymbolTable<T>::GetLastIndex() const
  321. {
  322. unsigned int idx = (unsigned int)(m_entries.GetLength()) - 1;
  323. asASSERT( idx == asUINT(-1) || m_entries[idx] );
  324. return int(idx);
  325. }
  326. template<class T>
  327. asCSymbolTableIterator<T, T> asCSymbolTable<T>::List()
  328. {
  329. return asCSymbolTableIterator<T, T>(this);
  330. }
  331. template<class T>
  332. typename asCSymbolTable<T>::const_iterator asCSymbolTable<T>::List() const
  333. {
  334. return asCSymbolTableIterator<T, const T>(const_cast< asCSymbolTable<T> *>(this));
  335. }
  336. /////////////////////////////////////////////////////////////////////////////////////////////////
  337. // Iterator
  338. template<class T, class T2>
  339. asCSymbolTableIterator<T, T2>::asCSymbolTableIterator(asCSymbolTable<T> *table) : m_table(table), m_idx(0)
  340. {
  341. unsigned int sz = (unsigned int)(m_table->m_entries.GetLength());
  342. while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
  343. 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. T2* asCSymbolTableIterator<T, T2>::operator->() const
  353. {
  354. asASSERT(m_table->CheckIdx(m_idx));
  355. return m_table->m_entries[m_idx];
  356. }
  357. template<class T, class T2>
  358. asCSymbolTableIterator<T, T2>& asCSymbolTableIterator<T, T2>::operator++(int)
  359. {
  360. Next();
  361. return *this;
  362. }
  363. // Return true if more elements are following
  364. // ATTENTION: When deleting the object currently pointed to by this iterator this
  365. // method returns false even though there might be more elements in the list
  366. template<class T, class T2>
  367. asCSymbolTableIterator<T, T2>::operator bool() const
  368. {
  369. return m_idx < m_table->m_entries.GetLength() && m_table->m_entries[m_idx] != 0;
  370. }
  371. template<class T, class T2>
  372. void asCSymbolTableIterator<T, T2>::Next()
  373. {
  374. unsigned int sz = (unsigned int)(m_table->m_entries.GetLength());
  375. m_idx++;
  376. while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
  377. m_idx++;
  378. }
  379. template<class T, class T2>
  380. void asCSymbolTableIterator<T, T2>::Previous()
  381. {
  382. // overflow on stepping over first element
  383. unsigned int sz = (unsigned int)(m_table->m_entries.GetLength());
  384. m_idx--;
  385. while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
  386. m_idx--;
  387. }
  388. template<class T, class T2>
  389. asCSymbolTableIterator<T, T2>& asCSymbolTableIterator<T, T2>::operator--(int)
  390. {
  391. Previous();
  392. return *this;
  393. }
  394. END_AS_NAMESPACE
  395. #endif // AS_SYMBOLTABLE_H