Gainput  v1.0.0
GainputContainers.h
1 
2 #ifndef GAINPUTCONTAINERS_H_
3 #define GAINPUTCONTAINERS_H_
4 
5 
6 namespace gainput
7 {
8 
9 
10 // -- MurmurHash3 begin --
11 // http://code.google.com/p/smhasher/wiki/MurmurHash3
12 // MurmurHash3 was written by Austin Appleby, and is placed in the public
13 // domain. The author hereby disclaims copyright to this source code.
14 
15 inline uint32_t rotl32(uint32_t x, int8_t r)
16 {
17  return (x << r) | (x >> (32 - r));
18 }
19 
20 inline uint32_t getblock(const uint32_t * p, int i)
21 {
22  return p[i];
23 }
24 
25 
26 inline uint32_t fmix(uint32_t h)
27 {
28  h ^= h >> 16;
29  h *= 0x85ebca6b;
30  h ^= h >> 13;
31  h *= 0xc2b2ae35;
32  h ^= h >> 16;
33 
34  return h;
35 }
36 
38 
44 inline void MurmurHash3_x86_32(const void * key, int len, uint32_t seed, void * out)
45 {
46  const uint8_t * data = (const uint8_t*)key;
47  const int nblocks = len / 4;
48 
49  uint32_t h1 = seed;
50 
51  const uint32_t c1 = 0xcc9e2d51;
52  const uint32_t c2 = 0x1b873593;
53 
54  const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
55 
56  for(int i = -nblocks; i; i++)
57  {
58  uint32_t k1 = getblock(blocks,i);
59 
60  k1 *= c1;
61  k1 = rotl32(k1,15);
62  k1 *= c2;
63 
64  h1 ^= k1;
65  h1 = rotl32(h1,13);
66  h1 = h1*5+0xe6546b64;
67  }
68 
69  const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
70 
71  uint32_t k1 = 0;
72 
73  switch(len & 3)
74  {
75  case 3: k1 ^= tail[2] << 16;
76  case 2: k1 ^= tail[1] << 8;
77  case 1: k1 ^= tail[0];
78  k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1;
79  };
80 
81  h1 ^= len;
82 
83  h1 = fmix(h1);
84 
85  *(uint32_t*)out = h1;
86 }
87 
88 // -- MurmurHash3 end --
89 
90 
92 
95 template<class T>
96 class GAINPUT_LIBEXPORT Array
97 {
98 public:
99  static const size_t DefaultCapacity = 8;
100 
101  typedef T* iterator;
102  typedef const T* const_iterator;
103  typedef T value_type;
104 
105  Array(Allocator& allocator, size_t capacity = DefaultCapacity) :
106  allocator_(allocator),
107  size_(0),
108  capacity_(capacity)
109  {
110  data_ = static_cast<T*>(allocator_.Allocate(sizeof(T)*capacity_));
111  }
112 
113  ~Array()
114  {
115  allocator_.Delete(data_);
116  }
117 
118  iterator begin() { return data_; }
119  const_iterator begin() const { return data_; }
120  iterator end() { return data_ + size_; }
121  const_iterator end() const { return data_ + size_; }
122 
123  T& operator[] (size_t i)
124  {
125  GAINPUT_ASSERT(i < size_);
126  return data_[i];
127  }
128 
129  const T& operator[] (size_t i) const
130  {
131  GAINPUT_ASSERT(i < size_);
132  return data_[i];
133  }
134 
135  void push_back(const value_type& val)
136  {
137  if (size_ + 1 > capacity_)
138  {
139  reserve(size_ + 1);
140  }
141  data_[size_++] = val;
142  }
143 
144  void pop_back()
145  {
146  if (size_ > 0)
147  --size_;
148  }
149 
150  void reserve(size_t capacity)
151  {
152  if (capacity <= capacity_)
153  return;
154  capacity = (capacity_*2) < capacity ? capacity : (capacity_*2);
155  T* newData = static_cast<T*>(allocator_.Allocate(sizeof(T)*capacity));
156  memcpy(newData, data_, sizeof(T)*capacity_);
157  allocator_.Deallocate(data_);
158  data_ = newData;
159  capacity_ = capacity;
160  }
161 
162  void swap(Array<T>& x)
163  {
164  GAINPUT_ASSERT(&allocator_ == &x.allocator_);
165 
166  const size_t thisSize = size_;
167  const size_t capacity = capacity_;
168  T* data = data_;
169 
170  size_ = x.size_;
171  capacity_ = x.capacity_;
172  data_ = x.data_;
173 
174  x.size_ = thisSize;
175  x.capacity_ = capacity;
176  x.data_ = data;
177  }
178 
179  iterator erase(iterator pos)
180  {
181  if (size_ == 0)
182  return end();
183  GAINPUT_ASSERT(pos >= begin() && pos < end());
184  memcpy(pos, pos+1, sizeof(T)*(end()-(pos+1)));
185  --size_;
186  return pos;
187  }
188 
189  void clear() { size_ = 0; }
190 
191  bool empty() const { return size_ == 0; }
192  size_t size() const { return size_; }
193 
194  iterator find(const value_type& val)
195  {
196  for (size_t i = 0; i < size_; ++i)
197  {
198  if (data_[i] == val)
199  {
200  return data_ + i;
201  }
202  }
203  return end();
204  }
205 
206  const_iterator find(const value_type& val) const
207  {
208  for (size_t i = 0; i < size_; ++i)
209  {
210  if (data_[i] == val)
211  {
212  return data_ + i;
213  }
214  }
215  return end();
216  }
217 
218 private:
219  Allocator& allocator_;
220  size_t size_;
221  size_t capacity_;
222  T* data_;
223 };
224 
225 
227 
231 template<class K, class V>
232 class GAINPUT_LIBEXPORT HashMap
233 {
234 public:
235  static const unsigned Seed = 329856235;
236  enum { InvalidKey = unsigned(-1) };
237 
239  struct Node
240  {
241  K first;
242  V second;
243  uint32_t next;
244  };
245 
246  typedef Node* iterator;
247  typedef const Node* const_iterator;
248 
249 
250  HashMap(Allocator& allocator = GetDefaultAllocator()) :
251  allocator_(allocator),
252  keys_(allocator_),
253  values_(allocator_),
254  size_(0)
255  { }
256 
257  iterator begin() { return values_.begin(); }
258  const_iterator begin() const { return values_.begin(); }
259  iterator end() { return values_.begin() + values_.size(); }
260  const_iterator end() const { return values_.begin() + values_.size(); }
261 
262  size_t size() const { return size_; }
263  bool empty() const { return size_ == 0; }
264 
265  size_t count(const K& k) const
266  {
267  return find(k) != end() ? 1 : 0;
268  }
269 
270  iterator find(const K& k)
271  {
272  if (keys_.empty() || values_.empty())
273  return end();
274  uint32_t h;
275  MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
276  const uint32_t ha = h % keys_.size();
277  volatile uint32_t vi = keys_[ha];
278  while (vi != InvalidKey)
279  {
280  if (values_[vi].first == k)
281  {
282  return &values_[vi];
283  }
284  vi = values_[vi].next;
285  }
286  return end();
287  }
288 
289  const_iterator find(const K& k) const
290  {
291  if (keys_.empty() || values_.empty())
292  return end();
293  uint32_t h;
294  MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
295  const uint32_t ha = h % keys_.size();
296  volatile uint32_t vi = keys_[ha];
297  while (vi != InvalidKey)
298  {
299  if (values_[vi].first == k)
300  {
301  return &values_[vi];
302  }
303  vi = values_[vi].next;
304  }
305  return end();
306  }
307 
308  iterator insert(const K& k, const V& v)
309  {
310  if (values_.size() >= 0.6f*keys_.size())
311  {
312  Rehash(values_.size()*2 + 10);
313  }
314 
315  uint32_t h;
316  MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
317  const uint32_t ha = h % keys_.size();
318  uint32_t vi = keys_[ha];
319 
320  if (vi == InvalidKey)
321  {
322  keys_[ha] = values_.size();
323  }
324  else
325  {
326  for (;;)
327  {
328  if (values_[vi].next == InvalidKey)
329  {
330  values_[vi].next = values_.size();
331  break;
332  }
333  else
334  {
335  vi = values_[vi].next;
336  }
337  }
338  }
339 
340  Node node;
341  node.first = k;
342  node.second = v;
343  node.next = InvalidKey;
344  values_.push_back(node);
345 
346  ++size_;
347 
348  return &values_[values_.size()-1];
349  }
350 
351  V& operator[] (const K& k)
352  {
353  iterator it = find(k);
354  if (it == end())
355  {
356  return insert(k, V())->second;
357  }
358  else
359  {
360  return it->second;
361  }
362  }
363 
364  size_t erase(const K& k)
365  {
366  if (keys_.empty())
367  return 0;
368  uint32_t h;
369  MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
370  const uint32_t ha = h % keys_.size();
371  uint32_t vi = keys_[ha];
372  uint32_t prevVi = InvalidKey;
373  while (vi != InvalidKey)
374  {
375  if (values_[vi].first == k)
376  {
377  if (prevVi == InvalidKey)
378  {
379  keys_[ha] = values_[vi].next;
380  }
381  else
382  {
383  values_[prevVi].next = values_[vi].next;
384  }
385 
386  --size_;
387  if (vi == values_.size() - 1)
388  {
389  values_.pop_back();
390  return 1;
391  }
392  else
393  {
394  size_t lastVi = values_.size()-1;
395  values_[vi] = values_[lastVi];
396  values_.pop_back();
397 
398  for (typename Array<uint32_t>::iterator it = keys_.begin(); it != keys_.end(); ++it)
399  {
400  if (*it == lastVi)
401  {
402  *it = vi;
403  break;
404  }
405  }
406  for (typename Array<Node>::iterator it = values_.begin(); it != values_.end(); ++it)
407  {
408  if (it->next == lastVi)
409  {
410  it->next = vi;
411  break;
412  }
413  }
414  return 1;
415  }
416  }
417  prevVi = vi;
418  vi = values_[vi].next;
419  }
420  return 0;
421  }
422 
423  void clear()
424  {
425  keys_.clear();
426  values_.clear();
427  }
428 
429 private:
430  Allocator& allocator_;
431  Array<uint32_t> keys_;
432  Array<Node> values_;
433  size_t size_;
434 
435  void Rehash(size_t newSize)
436  {
437  Array<uint32_t> keys(allocator_, newSize);
438  Array<Node> values(allocator_, values_.size());
439 
440  for (size_t i = 0; i < newSize; ++i)
441  keys.push_back(InvalidKey);
442 
443  keys_.swap(keys);
444  values_.swap(values);
445  size_ = 0;
446 
447  for (typename Array<Node>::const_iterator it = values.begin();
448  it != values.end();
449  ++it)
450  {
451  insert(it->first, it->second);
452  }
453  }
454 
455 };
456 
457 
458 
460 
464 template<int N, class T>
465 class GAINPUT_LIBEXPORT RingBuffer
466 {
467 public:
468  RingBuffer() :
469  nextRead_(0),
470  nextWrite_(0)
471  { }
472 
473 
474  bool CanGet() const
475  {
476  return nextRead_ < nextWrite_;
477  }
478 
479  size_t GetCount() const
480  {
481  const size_t d = nextWrite_ - nextRead_;
482  return d > N ? N : d;
483  }
484 
485  T Get()
486  {
487  return buf_[(nextRead_++) % N];
488  }
489 
490  void Put(T d)
491  {
492  buf_[(nextWrite_++) % N] = d;
493  while (nextRead_ + N < nextWrite_)
494  ++nextRead_;
495  }
496 
497 private:
498  T buf_[N];
499  size_t nextRead_;
500  size_t nextWrite_;
501 };
502 
503 
504 
505 }
506 
507 #endif
508 
A std::vector-like data container for POD-types.
Definition: GainputContainers.h:96
uint32_t next
The index of the next element with the same (wrapped) hash; Do not use.
Definition: GainputContainers.h:243
K first
The element&#39;s key.
Definition: GainputContainers.h:241
GAINPUT_LIBEXPORT DefaultAllocator & GetDefaultAllocator()
Returns the default instance of the default allocator.
V second
The element&#39;s value.
Definition: GainputContainers.h:242
A hash table mapping keys to POD-type values.
Definition: GainputContainers.h:232
A ring buffer.
Definition: GainputContainers.h:465
void MurmurHash3_x86_32(const void *key, int len, uint32_t seed, void *out)
Calculates MurmurHash3 for the given key.
Definition: GainputContainers.h:44
An element of the hash table.
Definition: GainputContainers.h:239
Interface used to pass custom allocators to the library.
Definition: GainputAllocator.h:16
Contains all Gainput related classes, types, and functions.
Definition: gainput.h:103