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