ScummVM API documentation
as_symboltable.h
1 /*
2  AngelCode Scripting Library
3  Copyright (c) 2012-2021 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  virtual bool operator()(const void *) const = 0;
61  virtual ~asIFilter() {};
62 };
63 
64 
65 
66 
67 // forward declaration
68 template<class T>
70 
71 
72 
73 
74 // Iterator that allows iterating in index order
75 template<class T, class T2 = T>
77 public:
78  T2 *operator*() const;
79  T2 *operator->() const;
80  asCSymbolTableIterator<T, T2> &operator++(int);
81  asCSymbolTableIterator<T, T2> &operator--(int);
82  operator bool() const;
83  int GetIndex() const {
84  return m_idx;
85  }
86 
87 private:
88  friend class asCSymbolTable<T>;
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 public:
107  typedef asCSymbolTableIterator<T, T> iterator;
108  typedef asCSymbolTableIterator<T, const T> const_iterator;
109 
110  asCSymbolTable(asUINT initialCapacity = 0);
111 
112  int GetFirstIndex(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
113  int GetFirstIndex(const asSNameSpace *ns, const asCString &name) const;
114  int GetLastIndex() const;
115 
116  int GetIndex(const T *) const;
117 
118  T *GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
119  T *GetFirst(const asSNameSpace *ns, const asCString &name);
120  const T *GetFirst(const asSNameSpace *ns, const asCString &name) const;
121  T *Get(asUINT index);
122  const T *Get(asUINT index) const;
123  T *GetLast();
124  const T *GetLast() const;
125 
126  const asCArray<asUINT> &GetIndexes(const asSNameSpace *ns, const asCString &name) const;
127 
128  asUINT Put(T *entry);
129 
130  asUINT GetSize() const;
131 
132  void SwapWith(asCSymbolTable<T> &other);
133 
134  void Clear();
135  bool Erase(asUINT idx);
136  void Allocate(asUINT elem_cnt, bool keep_data);
137 
138  iterator List();
139  const_iterator List() const;
140 
141 private:
142  // Don't allow assignment
143  asCSymbolTable<T> &operator=(const asCSymbolTable<T> &other) {
144  return *this;
145  }
146 
147  friend class asCSymbolTableIterator<T, T>;
148  friend class asCSymbolTableIterator<T, const T>;
149 
150  void GetKey(const T *entry, asSNameSpaceNamePair &key) const;
151  bool CheckIdx(asUINT idx) const;
152 
154  asCArray<T *> m_entries;
155  unsigned int m_size;
156 };
157 
158 
159 
160 
161 template<class T>
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>
177 asCSymbolTable<T>::asCSymbolTable(asUINT initialCapacity) : m_entries(initialCapacity) {
178  m_size = 0;
179 }
180 
181 
182 
183 template<class T>
185  const asSNameSpace *ns,
186  const asCString &name,
187  const asIFilter &filter) const {
188  asSNameSpaceNamePair key(ns, name);
189 
191  if (m_map.MoveTo(&cursor, key)) {
192  const asCArray<asUINT> &arr = m_map.GetValue(cursor);
193  for (asUINT n = 0; n < arr.GetLength(); n++) {
194  T *entry = m_entries[arr[n]];
195  if (entry && filter(entry))
196  return arr[n];
197  }
198  }
199 
200  return -1;
201 }
202 
203 
204 
205 template<class T>
206 const asCArray<asUINT> &asCSymbolTable<T>::GetIndexes(const asSNameSpace *ns, const asCString &name) const {
207  asSNameSpaceNamePair key(ns, name);
208 
210  if (m_map.MoveTo(&cursor, key))
211  return m_map.GetValue(cursor);
212 
213  static asCArray<asUINT> dummy;
214  return dummy;
215 }
216 
217 
218 
219 
220 template<class T>
221 T *asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comp) const {
222  int idx = GetFirstIndex(ns, name, comp);
223  if (idx != -1) return m_entries[idx];
224  return 0;
225 }
226 
227 
228 
229 
230 template<class T>
231 int asCSymbolTable<T>::GetFirstIndex(const asSNameSpace *ns, const asCString &name) const {
232  asSNameSpaceNamePair key(ns, name);
233 
235  if (m_map.MoveTo(&cursor, key))
236  return m_map.GetValue(cursor)[0];
237 
238  return -1;
239 }
240 
241 
242 
243 
244 // Find the index of a certain symbol
245 // ATTENTION: this function has linear runtime complexity O(n)!!
246 template<class T>
247 int asCSymbolTable<T>::GetIndex(const T *entry) const {
248  for (asUINT n = 0; n < m_entries.GetLength(); n++)
249  if (m_entries[n] == entry)
250  return n;
251 
252  return -1;
253 }
254 
255 
256 
257 
258 
259 
260 template<class T>
261 T *asCSymbolTable<T>::Get(asUINT idx) {
262  if (!CheckIdx(idx))
263  return 0;
264 
265  return m_entries[idx];
266 }
267 
268 template<class T>
269 const T *asCSymbolTable<T>::Get(asUINT idx) const {
270  return const_cast< asCSymbolTable<T>* >(this)->Get(idx);
271 }
272 
273 
274 
275 
276 
277 template<class T>
278 T *asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name) {
279  int idx = GetFirstIndex(ns, name);
280  return Get(idx);
281 }
282 
283 template<class T>
284 const T *asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name) const {
285  return const_cast< asCSymbolTable<T>* >(this)->GetFirst(ns, name);
286 }
287 
288 
289 
290 
291 
292 template<class T>
294  return Get(GetLastIndex());
295 }
296 
297 template<class T>
298 const T *asCSymbolTable<T>::GetLast() const {
299  return const_cast< asCSymbolTable<T>* >(this)->GetLast();
300 }
301 
302 
303 
304 
305 
306 // Clear the symbol table
307 // ATTENTION: The contained symbols are not rleased. This is up to the client
308 template<class T>
310  m_entries.SetLength(0);
311  m_map.EraseAll();
312  m_size = 0;
313 }
314 
315 
316 
317 
318 // Pre-allocate slots for elemCnt entries
319 template<class T>
320 void asCSymbolTable<T>::Allocate(asUINT elemCnt, bool keepData) {
321  asASSERT(elemCnt >= m_entries.GetLength());
322  m_entries.Allocate(elemCnt, keepData);
323  if (!keepData)
324  m_map.EraseAll();
325 }
326 
327 
328 
329 template<class T>
330 bool asCSymbolTable<T>::Erase(asUINT idx) {
331  if (!CheckIdx(idx)) {
332  asASSERT(false);
333  return false;
334  }
335 
336  T *entry = m_entries[idx];
337  asASSERT(entry);
338  if (!entry)
339  return false;
340 
341  // Remove the symbol from the lookup map
343  GetKey(entry, key);
344 
346  if (m_map.MoveTo(&cursor, key)) {
347  asCArray<asUINT> &arr = m_map.GetValue(cursor);
348  arr.RemoveValue(idx);
349  if (arr.GetLength() == 0)
350  m_map.Erase(cursor);
351  } else
352  asASSERT(false);
353 
354  // Remove the symbol from the indexed array
355  if (idx == m_entries.GetLength() - 1)
356  m_entries.PopLast();
357  else {
358  // Must keep the array packed
359  int prevIdx = int(m_entries.GetLength() - 1);
360  m_entries[idx] = m_entries.PopLast();
361 
362  // Update the index in the lookup map
363  entry = m_entries[idx];
364  GetKey(entry, key);
365  if (m_map.MoveTo(&cursor, key)) {
366  asCArray<asUINT> &arr = m_map.GetValue(cursor);
367  arr[arr.IndexOf(prevIdx)] = idx;
368  } else
369  asASSERT(false);
370  }
371  m_size--;
372 
373  return true;
374 }
375 
376 
377 
378 
379 template<class T>
380 asUINT asCSymbolTable<T>::Put(T *entry) {
381  asUINT idx = m_entries.GetLength();
383  GetKey(entry, key);
384 
386  if (m_map.MoveTo(&cursor, key))
387  m_map.GetValue(cursor).PushLast(idx);
388  else {
389  asCArray<asUINT> arr(1);
390  arr.PushLast(idx);
391  m_map.Insert(key, arr);
392  }
393 
394  m_entries.PushLast(entry);
395  m_size++;
396  return idx;
397 }
398 
399 
400 
401 
402 // Return key for specified symbol (namespace and name are used to generate the key)
403 template<class T>
404 void asCSymbolTable<T>::GetKey(const T *entry, asSNameSpaceNamePair &key) const {
405  key = asSNameSpaceNamePair(entry->nameSpace, entry->name);
406 }
407 
408 
409 
410 
411 template<class T>
412 asUINT asCSymbolTable<T>::GetSize() const {
413  return m_size;
414 }
415 
416 
417 
418 
419 template<class T>
420 bool asCSymbolTable<T>::CheckIdx(asUINT idx) const {
421  return idx < m_entries.GetLength();
422 }
423 
424 
425 
426 
427 template<class T>
429  int idx = int(m_entries.GetLength()) - 1;
430  asASSERT(idx == -1 || m_entries[idx]);
431  return idx;
432 }
433 
434 
435 
436 
437 template<class T>
439  return asCSymbolTableIterator<T, T>(this);
440 }
441 
442 
443 
444 
445 template<class T>
447  return asCSymbolTableIterator<T, const T>(const_cast< asCSymbolTable<T> *>(this));
448 }
449 
450 
452 // Iterator
453 
454 
455 template<class T, class T2>
457  asUINT sz = m_table->m_entries.GetLength();
458  while (m_idx < sz && m_table->m_entries[m_idx] == 0)
459  m_idx++;
460 }
461 
462 
463 
464 template<class T, class T2>
466  asASSERT(m_table->CheckIdx(m_idx));
467  return m_table->m_entries[m_idx];
468 }
469 
470 
471 
472 template<class T, class T2>
474  asASSERT(m_table->CheckIdx(m_idx));
475  return m_table->m_entries[m_idx];
476 }
477 
478 
479 
480 template<class T, class T2>
482  Next();
483  return *this;
484 }
485 
486 
487 
488 // Return true if more elements are following
489 // ATTENTION: When deleting the object currently pointed to by this iterator this
490 // method returns false even though there might be more elements in the list
491 template<class T, class T2>
493  return m_idx < m_table->m_entries.GetLength() && m_table->m_entries[m_idx] != 0;
494 }
495 
496 
497 
498 template<class T, class T2>
500  asUINT sz = m_table->m_entries.GetLength();
501  m_idx++;
502  while (m_idx < sz && m_table->m_entries[m_idx] == 0)
503  m_idx++;
504 }
505 
506 
507 
508 template<class T, class T2>
510  // overflow on stepping over first element
511  asUINT sz = m_table->m_entries.GetLength();
512  m_idx--;
513  while (m_idx < sz && m_table->m_entries[m_idx] == 0)
514  m_idx--;
515 }
516 
517 
518 
519 template<class T, class T2>
521  Previous();
522  return *this;
523 }
524 
525 
526 END_AS_NAMESPACE
527 
528 #endif // AS_SYMBOLTABLE_H
Definition: as_symboltable.h:76
Definition: as_namespace.h:39
Definition: as_map.h:44
Definition: as_symboltable.h:59
Definition: as_namespace.h:47
Definition: as_map.h:42
Definition: as_symboltable.h:69
Definition: as_string.h:41