1 /*
2 AngelCode Scripting Library
3 Copyright (c) 2012-2015 Andreas Jonsson
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any
7 damages arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any
10 purpose, including commercial applications, and to alter it and
11 redistribute it freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you
14 must not claim that you wrote the original software. If you use
15 this software in a product, an acknowledgment in the product
16 documentation would be appreciated but is not required.
17
18 2. Altered source versions must be plainly marked as such, and
19 must not be misrepresented as being the original software.
20
21 3. This notice may not be removed or altered from any source
22 distribution.
23
24 The original version of this library can be located at:
25 http://www.angelcode.com/angelscript/
26
27 Andreas Jonsson
28 andreas@angelcode.com
29 */
30
31
32 //
33 // as_symboltable.h
34 //
35 // Created on: Jun 19, 2012
36 // Author: Markus Lenger, a.k.a. mlengerx
37 //
38 // This class is used for fast symbol lookups while parsing or loading bytecode
39 //
40
41 #ifndef AS_SYMBOLTABLE_H
42 #define AS_SYMBOLTABLE_H
43
44 #include "as_config.h"
45 #include "as_memory.h"
46 #include "as_string.h"
47 #include "as_map.h"
48 #include "as_datatype.h"
49 #include "as_namespace.h"
50
51
52 BEGIN_AS_NAMESPACE
53
54
55
56
57
58 // Interface to avoid nested templates which is not well supported by older compilers, e.g. MSVC6
59 struct asIFilter
60 {
61 virtual bool operator()(const void*) const = 0;
~asIFilterasIFilter62 virtual ~asIFilter() {};
63 };
64
65
66
67
68 // forward declaration
69 template<class T>
70 class asCSymbolTable;
71
72
73
74
75 // Iterator that allows iterating in index order
76 template<class T, class T2 = T>
77 class asCSymbolTableIterator
78 {
79 public:
80 T2* operator*() const;
81 T2* operator->() const;
82 asCSymbolTableIterator<T, T2>& operator++(int);
83 asCSymbolTableIterator<T, T2>& operator--(int);
84 operator bool() const;
GetIndex()85 int GetIndex() const { return m_idx; }
86
87 private:
88 friend class asCSymbolTable<T>;
89 asCSymbolTableIterator<T, T2>(asCSymbolTable<T> *table);
90
91 void Next();
92 void Previous();
93
94 asCSymbolTable<T>* m_table;
95 unsigned int m_idx;
96 };
97
98
99
100
101 // Symbol table mapping namespace + name to symbols
102 // The structure keeps the entries indexed in an array so the indices will not change
103 // There is also a map for a quick lookup. The map supports multiple entries with the same name
104 template<class T>
105 class asCSymbolTable
106 {
107 public:
108 typedef asCSymbolTableIterator<T, T> iterator;
109 typedef asCSymbolTableIterator<T, const T> const_iterator;
110
111 asCSymbolTable(asUINT initialCapacity = 0);
112
113 int GetFirstIndex(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
114 int GetFirstIndex(const asSNameSpace *ns, const asCString &name) const;
115 int GetLastIndex() const;
116
117 int GetIndex(const T*) const;
118
119 T* GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
120 T* GetFirst(const asSNameSpace *ns, const asCString &name);
121 const T* GetFirst(const asSNameSpace *ns, const asCString &name) const;
122 T* Get(asUINT index);
123 const T* Get(asUINT index) const;
124 T* GetLast();
125 const T* GetLast() const;
126
127 const asCArray<asUINT> &GetIndexes(const asSNameSpace *ns, const asCString &name) const;
128
129 asUINT Put(T* entry);
130
131 asUINT GetSize() const;
132
133 void SwapWith(asCSymbolTable<T> &other);
134
135 void Clear();
136 bool Erase(asUINT idx);
137 void Allocate(asUINT elem_cnt, bool keep_data);
138
139 iterator List();
140 const_iterator List() const;
141
142 private:
143 // Don't allow assignment
144 asCSymbolTable<T>& operator=(const asCSymbolTable<T> &other) { return *this; }
145
146 friend class asCSymbolTableIterator<T, T>;
147 friend class asCSymbolTableIterator<T, const T>;
148
149 void GetKey(const T *entry, asSNameSpaceNamePair &key) const;
150 bool CheckIdx(asUINT idx) const;
151
152 asCMap<asSNameSpaceNamePair, asCArray<asUINT> > m_map;
153 asCArray<T*> m_entries;
154 unsigned int m_size;
155 };
156
157
158
159
160 template<class T>
SwapWith(asCSymbolTable<T> & other)161 void asCSymbolTable<T>::SwapWith(asCSymbolTable<T> &other)
162 {
163 m_map.SwapWith(other.m_map);
164 m_entries.SwapWith(other.m_entries);
165
166 asUINT tmp = m_size;
167 m_size = other.m_size;
168 other.m_size = tmp;
169 }
170
171
172
173
174 // Constructor
175 // initialCapacity gives the number of entries to allocate in advance
176 template<class T>
asCSymbolTable(asUINT initialCapacity)177 asCSymbolTable<T>::asCSymbolTable(asUINT initialCapacity) : m_entries(initialCapacity)
178 {
179 m_size = 0;
180 }
181
182
183
184 template<class T>
GetFirstIndex(const asSNameSpace * ns,const asCString & name,const asIFilter & filter)185 int asCSymbolTable<T>::GetFirstIndex(
186 const asSNameSpace *ns,
187 const asCString &name,
188 const asIFilter &filter) const
189 {
190 asSNameSpaceNamePair key(ns, name);
191
192 asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
193 if( m_map.MoveTo(&cursor, key) )
194 {
195 const asCArray<asUINT> &arr = m_map.GetValue(cursor);
196 for( asUINT n = 0; n < arr.GetLength(); n++ )
197 {
198 T *entry = m_entries[arr[n]];
199 if( entry && filter(entry) )
200 return arr[n];
201 }
202 }
203
204 return -1;
205 }
206
207
208
209 template<class T>
GetIndexes(const asSNameSpace * ns,const asCString & name)210 const asCArray<asUINT> &asCSymbolTable<T>::GetIndexes(const asSNameSpace *ns, const asCString &name) const
211 {
212 asSNameSpaceNamePair key(ns, name);
213
214 asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
215 if( m_map.MoveTo(&cursor, key) )
216 return m_map.GetValue(cursor);
217
218 static asCArray<asUINT> dummy;
219 return dummy;
220 }
221
222
223
224
225 template<class T>
GetFirst(const asSNameSpace * ns,const asCString & name,const asIFilter & comp)226 T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comp) const
227 {
228 int idx = GetFirstIndex(ns, name, comp);
229 if (idx != -1) return m_entries[idx];
230 return 0;
231 }
232
233
234
235
236 template<class T>
GetFirstIndex(const asSNameSpace * ns,const asCString & name)237 int asCSymbolTable<T>::GetFirstIndex(const asSNameSpace *ns, const asCString &name) const
238 {
239 asSNameSpaceNamePair key(ns, name);
240
241 asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
242 if( m_map.MoveTo(&cursor, key) )
243 return m_map.GetValue(cursor)[0];
244
245 return -1;
246 }
247
248
249
250
251 // Find the index of a certain symbol
252 // ATTENTION: this function has linear runtime complexity O(n)!!
253 template<class T>
GetIndex(const T * entry)254 int asCSymbolTable<T>::GetIndex(const T* entry) const
255 {
256 for( asUINT n = 0; n < m_entries.GetLength(); n++ )
257 if( m_entries[n] == entry )
258 return n;
259
260 return -1;
261 }
262
263
264
265
266
267
268 template<class T>
Get(asUINT idx)269 T* asCSymbolTable<T>::Get(asUINT idx)
270 {
271 if( !CheckIdx(idx) )
272 return 0;
273
274 return m_entries[idx];
275 }
276
277 template<class T>
Get(asUINT idx)278 const T* asCSymbolTable<T>::Get(asUINT idx) const
279 {
280 return const_cast< asCSymbolTable<T>* >(this)->Get(idx);
281 }
282
283
284
285
286
287 template<class T>
GetFirst(const asSNameSpace * ns,const asCString & name)288 T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name)
289 {
290 int idx = GetFirstIndex(ns, name);
291 return Get(idx);
292 }
293
294 template<class T>
GetFirst(const asSNameSpace * ns,const asCString & name)295 const T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name) const
296 {
297 return const_cast< asCSymbolTable<T>* >(this)->GetFirst(ns, name);
298 }
299
300
301
302
303
304 template<class T>
GetLast()305 T* asCSymbolTable<T>::GetLast()
306 {
307 return Get(GetLastIndex());
308 }
309
310 template<class T>
GetLast()311 const T* asCSymbolTable<T>::GetLast() const
312 {
313 return const_cast< asCSymbolTable<T>* >(this)->GetLast();
314 }
315
316
317
318
319
320 // Clear the symbol table
321 // ATTENTION: The contained symbols are not rleased. This is up to the client
322 template<class T>
Clear()323 void asCSymbolTable<T>::Clear()
324 {
325 m_entries.SetLength(0);
326 m_map.EraseAll();
327 m_size = 0;
328 }
329
330
331
332
333 // Pre-allocate slots for elemCnt entries
334 template<class T>
Allocate(asUINT elemCnt,bool keepData)335 void asCSymbolTable<T>::Allocate(asUINT elemCnt, bool keepData)
336 {
337 asASSERT( elemCnt >= m_entries.GetLength() );
338 m_entries.Allocate(elemCnt, keepData);
339 if( !keepData )
340 m_map.EraseAll();
341 }
342
343
344
345 template<class T>
Erase(asUINT idx)346 bool asCSymbolTable<T>::Erase(asUINT idx)
347 {
348 if( !CheckIdx(idx) )
349 {
350 asASSERT(false);
351 return false;
352 }
353
354 T *entry = m_entries[idx];
355 asASSERT(entry);
356 if( !entry )
357 return false;
358
359 // Remove the symbol from the lookup map
360 asSNameSpaceNamePair key;
361 GetKey(entry, key);
362
363 asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
364 if( m_map.MoveTo(&cursor, key) )
365 {
366 asCArray<asUINT> &arr = m_map.GetValue(cursor);
367 arr.RemoveValue(idx);
368 if( arr.GetLength() == 0 )
369 m_map.Erase(cursor);
370 }
371 else
372 asASSERT(false);
373
374 // Remove the symbol from the indexed array
375 if( idx == m_entries.GetLength() - 1 )
376 m_entries.PopLast();
377 else
378 {
379 // Must keep the array packed
380 int prevIdx = int(m_entries.GetLength()-1);
381 m_entries[idx] = m_entries.PopLast();
382
383 // Update the index in the lookup map
384 entry = m_entries[idx];
385 GetKey(entry, key);
386 if( m_map.MoveTo(&cursor, key) )
387 {
388 asCArray<asUINT> &arr = m_map.GetValue(cursor);
389 arr[arr.IndexOf(prevIdx)] = idx;
390 }
391 else
392 asASSERT(false);
393 }
394 m_size--;
395
396 return true;
397 }
398
399
400
401
402 template<class T>
Put(T * entry)403 asUINT asCSymbolTable<T>::Put(T *entry)
404 {
405 asUINT idx = m_entries.GetLength();
406 asSNameSpaceNamePair key;
407 GetKey(entry, key);
408
409 asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
410 if( m_map.MoveTo(&cursor, key) )
411 m_map.GetValue(cursor).PushLast(idx);
412 else
413 {
414 asCArray<asUINT> arr(1);
415 arr.PushLast(idx);
416 m_map.Insert(key, arr);
417 }
418
419 m_entries.PushLast(entry);
420 m_size++;
421 return idx;
422 }
423
424
425
426
427 // Return key for specified symbol (namespace and name are used to generate the key)
428 template<class T>
GetKey(const T * entry,asSNameSpaceNamePair & key)429 void asCSymbolTable<T>::GetKey(const T *entry, asSNameSpaceNamePair &key) const
430 {
431 key = asSNameSpaceNamePair(entry->nameSpace, entry->name);
432 }
433
434
435
436
437 template<class T>
GetSize()438 asUINT asCSymbolTable<T>::GetSize() const
439 {
440 return m_size;
441 }
442
443
444
445
446 template<class T>
CheckIdx(asUINT idx)447 bool asCSymbolTable<T>::CheckIdx(asUINT idx) const
448 {
449 return idx < m_entries.GetLength();
450 }
451
452
453
454
455 template<class T>
GetLastIndex()456 int asCSymbolTable<T>::GetLastIndex() const
457 {
458 int idx = int(m_entries.GetLength()) - 1;
459 asASSERT( idx == -1 || m_entries[idx] );
460 return idx;
461 }
462
463
464
465
466 template<class T>
List()467 asCSymbolTableIterator<T, T> asCSymbolTable<T>::List()
468 {
469 return asCSymbolTableIterator<T, T>(this);
470 }
471
472
473
474
475 template<class T>
List()476 typename asCSymbolTable<T>::const_iterator asCSymbolTable<T>::List() const
477 {
478 return asCSymbolTableIterator<T, const T>(const_cast< asCSymbolTable<T> *>(this));
479 }
480
481
482 /////////////////////////////////////////////////////////////////////////////////////////////////
483 // Iterator
484
485
486 template<class T, class T2>
asCSymbolTableIterator(asCSymbolTable<T> * table)487 asCSymbolTableIterator<T, T2>::asCSymbolTableIterator(asCSymbolTable<T> *table) : m_table(table), m_idx(0)
488 {
489 asUINT sz = m_table->m_entries.GetLength();
490 while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
491 m_idx++;
492 }
493
494
495
496 template<class T, class T2>
497 T2* asCSymbolTableIterator<T, T2>::operator*() const
498 {
499 asASSERT(m_table->CheckIdx(m_idx));
500 return m_table->m_entries[m_idx];
501 }
502
503
504
505 template<class T, class T2>
506 T2* asCSymbolTableIterator<T, T2>::operator->() const
507 {
508 asASSERT(m_table->CheckIdx(m_idx));
509 return m_table->m_entries[m_idx];
510 }
511
512
513
514 template<class T, class T2>
515 asCSymbolTableIterator<T, T2>& asCSymbolTableIterator<T, T2>::operator++(int)
516 {
517 Next();
518 return *this;
519 }
520
521
522
523 // Return true if more elements are following
524 // ATTENTION: When deleting the object currently pointed to by this iterator this
525 // method returns false even though there might be more elements in the list
526 template<class T, class T2>
527 asCSymbolTableIterator<T, T2>::operator bool() const
528 {
529 return m_idx < m_table->m_entries.GetLength() && m_table->m_entries[m_idx] != 0;
530 }
531
532
533
534 template<class T, class T2>
Next()535 void asCSymbolTableIterator<T, T2>::Next()
536 {
537 asUINT sz = m_table->m_entries.GetLength();
538 m_idx++;
539 while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
540 m_idx++;
541 }
542
543
544
545 template<class T, class T2>
Previous()546 void asCSymbolTableIterator<T, T2>::Previous()
547 {
548 // overflow on stepping over first element
549 asUINT sz = m_table->m_entries.GetLength();
550 m_idx--;
551 while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
552 m_idx--;
553 }
554
555
556
557 template<class T, class T2>
558 asCSymbolTableIterator<T, T2>& asCSymbolTableIterator<T, T2>::operator--(int)
559 {
560 Previous();
561 return *this;
562 }
563
564
565 END_AS_NAMESPACE
566
567 #endif // AS_SYMBOLTABLE_H
568