PikaScript
QuickVars.h
1 
41 #ifndef QuickVars_h
42 #define QuickVars_h
43 
44 #if !defined(PikaScriptImpl_h)
45 #include "PikaScriptImpl.h"
46 #endif
47 
48 namespace Pika {
49 
50 // TODO : documentation with use example
51 // TODO : I think this one could be based on an arbitrary variables class and use assign, lookup etc of the super-class instead of accessing vars directly. The question is if it would affect performance?
52 template<class Super, unsigned int CACHE_SIZE = 11> class QuickVars : public Super {
53  public: typedef typename Super::ForScript::String String;
54  public: typedef typename Super::ForScript::Value Value;
55  public: typedef std::pair<String, Value> CacheEntry;
56 
57  public: unsigned int hash(const String& s) {
58  unsigned int l = static_cast<unsigned int>(s.size());
59  if (s.size() == 1 && s[0] >= 'a' && s[0] <= 'z') return (s[0] - 'a') % CACHE_SIZE;
60  if (s.size() == 2 && s[0] == '$' && s[1] >= '0' && s[1] <= '9') return s[1] - '0';
61  return (s[0] * 1733 + s[l >> 2] * 2069 + s[l >> 1] * 2377 + s[l - 1] * 2851) % CACHE_SIZE;
62  }
63 
64  public: virtual bool assign(const String& identifier, const Value& value) {
65  if (identifier.empty()) return false;
66  unsigned int i = hash(identifier);
67  if (cache[i].first == identifier) { cache[i] = CacheEntry(identifier, value); return true; }
68  if (!cache[i].first.empty()) Super::vars[cache[i].first] = cache[i].second;
69  cache[i] = CacheEntry(identifier, value);
70  return true;
71  }
72 
73  public: virtual bool erase(const String& identifier) {
74  bool erased = (Super::vars.erase(identifier) != 0);
75  unsigned int i = hash(identifier);
76  if (cache[i].first == identifier) { cache[i] = std::pair<const String, Value>(); erased = true; }
77  return erased;
78  }
79 
80  public: virtual bool lookup(const String& identifier, Value& result) {
81  if (identifier.empty()) return false;
82  unsigned int i = hash(identifier);
83  if (cache[i].first == identifier) { result = cache[i].second; return true; }
84  typename Super::VariableMap::const_iterator it = Super::vars.find(identifier);
85  if (it == Super::vars.end()) return false;
86  if (!cache[i].first.empty()) Super::vars[cache[i].first] = cache[i].second;
87  cache[i] = CacheEntry(identifier, it->second);
88  result = it->second;
89  return true;
90  }
91 
92  public: virtual void list(const String& key, typename Super::ForScript::Variables::VarList& list) {
93  for (unsigned int i = 0; i < CACHE_SIZE; ++i)
94  if (!cache[i].first.empty()) Super::vars[cache[i].first] = cache[i].second;
95  for (typename Super::VariableMap::const_iterator it = Super::vars.lower_bound(key)
96  ; it != Super::vars.end() && it->first.substr(0, key.size()) == key; ++it)
97  list.push_back(*it);
98  }
99 
100  protected: CacheEntry cache[CACHE_SIZE];
101 };
102 
103 } // namespace Pika
104 
105 #endif