Squashed 'external/gainput/' content from commit 2be0a50
git-subtree-dir: external/gainput git-subtree-split: 2be0a50089eafcc6fccb66142180082e48f27f4c
This commit is contained in:
508
lib/include/gainput/GainputContainers.h
Normal file
508
lib/include/gainput/GainputContainers.h
Normal file
@@ -0,0 +1,508 @@
|
||||
|
||||
#ifndef GAINPUTCONTAINERS_H_
|
||||
#define GAINPUTCONTAINERS_H_
|
||||
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
|
||||
// -- MurmurHash3 begin --
|
||||
// http://code.google.com/p/smhasher/wiki/MurmurHash3
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
|
||||
inline uint32_t rotl32(uint32_t x, int8_t r)
|
||||
{
|
||||
return (x << r) | (x >> (32 - r));
|
||||
}
|
||||
|
||||
inline uint32_t getblock(const uint32_t * p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
|
||||
inline uint32_t fmix(uint32_t h)
|
||||
{
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/// Calculates MurmurHash3 for the given key.
|
||||
/**
|
||||
* \param key The key to calculate the hash of.
|
||||
* \param len Length of the key in bytes.
|
||||
* \param seed Seed for the hash.
|
||||
* \param[out] out The hash value, a uint32_t in this case.
|
||||
*/
|
||||
inline void MurmurHash3_x86_32(const void * key, int len, uint32_t seed, void * out)
|
||||
{
|
||||
const uint8_t * data = (const uint8_t*)key;
|
||||
const int nblocks = len / 4;
|
||||
|
||||
uint32_t h1 = seed;
|
||||
|
||||
const uint32_t c1 = 0xcc9e2d51;
|
||||
const uint32_t c2 = 0x1b873593;
|
||||
|
||||
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
|
||||
|
||||
for(int i = -nblocks; i; i++)
|
||||
{
|
||||
uint32_t k1 = getblock(blocks,i);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = rotl32(k1,15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = rotl32(h1,13);
|
||||
h1 = h1*5+0xe6546b64;
|
||||
}
|
||||
|
||||
const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
|
||||
|
||||
uint32_t k1 = 0;
|
||||
|
||||
switch(len & 3)
|
||||
{
|
||||
case 3: k1 ^= tail[2] << 16;
|
||||
case 2: k1 ^= tail[1] << 8;
|
||||
case 1: k1 ^= tail[0];
|
||||
k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1;
|
||||
};
|
||||
|
||||
h1 ^= len;
|
||||
|
||||
h1 = fmix(h1);
|
||||
|
||||
*(uint32_t*)out = h1;
|
||||
}
|
||||
|
||||
// -- MurmurHash3 end --
|
||||
|
||||
|
||||
/// A std::vector-like data container for POD-types.
|
||||
/**
|
||||
* \tparam T A POD-type to hold in this container.
|
||||
*/
|
||||
template<class T>
|
||||
class GAINPUT_LIBEXPORT Array
|
||||
{
|
||||
public:
|
||||
static const size_t DefaultCapacity = 8;
|
||||
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
typedef T value_type;
|
||||
|
||||
Array(Allocator& allocator, size_t capacity = DefaultCapacity) :
|
||||
allocator_(allocator),
|
||||
size_(0),
|
||||
capacity_(capacity)
|
||||
{
|
||||
data_ = static_cast<T*>(allocator_.Allocate(sizeof(T)*capacity_));
|
||||
}
|
||||
|
||||
~Array()
|
||||
{
|
||||
allocator_.Delete(data_);
|
||||
}
|
||||
|
||||
iterator begin() { return data_; }
|
||||
const_iterator begin() const { return data_; }
|
||||
iterator end() { return data_ + size_; }
|
||||
const_iterator end() const { return data_ + size_; }
|
||||
|
||||
T& operator[] (size_t i)
|
||||
{
|
||||
GAINPUT_ASSERT(i < size_);
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
const T& operator[] (size_t i) const
|
||||
{
|
||||
GAINPUT_ASSERT(i < size_);
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
void push_back(const value_type& val)
|
||||
{
|
||||
if (size_ + 1 > capacity_)
|
||||
{
|
||||
reserve(size_ + 1);
|
||||
}
|
||||
data_[size_++] = val;
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
if (size_ > 0)
|
||||
--size_;
|
||||
}
|
||||
|
||||
void reserve(size_t capacity)
|
||||
{
|
||||
if (capacity <= capacity_)
|
||||
return;
|
||||
capacity = (capacity_*2) < capacity ? capacity : (capacity_*2);
|
||||
T* newData = static_cast<T*>(allocator_.Allocate(sizeof(T)*capacity));
|
||||
memcpy(newData, data_, sizeof(T)*capacity_);
|
||||
allocator_.Deallocate(data_);
|
||||
data_ = newData;
|
||||
capacity_ = capacity;
|
||||
}
|
||||
|
||||
void swap(Array<T>& x)
|
||||
{
|
||||
GAINPUT_ASSERT(&allocator_ == &x.allocator_);
|
||||
|
||||
const size_t thisSize = size_;
|
||||
const size_t capacity = capacity_;
|
||||
T* data = data_;
|
||||
|
||||
size_ = x.size_;
|
||||
capacity_ = x.capacity_;
|
||||
data_ = x.data_;
|
||||
|
||||
x.size_ = thisSize;
|
||||
x.capacity_ = capacity;
|
||||
x.data_ = data;
|
||||
}
|
||||
|
||||
iterator erase(iterator pos)
|
||||
{
|
||||
if (size_ == 0)
|
||||
return end();
|
||||
GAINPUT_ASSERT(pos >= begin() && pos < end());
|
||||
memcpy(pos, pos+1, sizeof(T)*(end()-(pos+1)));
|
||||
--size_;
|
||||
return pos;
|
||||
}
|
||||
|
||||
void clear() { size_ = 0; }
|
||||
|
||||
bool empty() const { return size_ == 0; }
|
||||
size_t size() const { return size_; }
|
||||
|
||||
iterator find(const value_type& val)
|
||||
{
|
||||
for (size_t i = 0; i < size_; ++i)
|
||||
{
|
||||
if (data_[i] == val)
|
||||
{
|
||||
return data_ + i;
|
||||
}
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
const_iterator find(const value_type& val) const
|
||||
{
|
||||
for (size_t i = 0; i < size_; ++i)
|
||||
{
|
||||
if (data_[i] == val)
|
||||
{
|
||||
return data_ + i;
|
||||
}
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
private:
|
||||
Allocator& allocator_;
|
||||
size_t size_;
|
||||
size_t capacity_;
|
||||
T* data_;
|
||||
};
|
||||
|
||||
|
||||
/// A hash table mapping keys to POD-type values.
|
||||
/**
|
||||
* \tparam K The key pointing to a value.
|
||||
* \tparam V POD-type being stored in the table.
|
||||
*/
|
||||
template<class K, class V>
|
||||
class GAINPUT_LIBEXPORT HashMap
|
||||
{
|
||||
public:
|
||||
static const unsigned Seed = 329856235;
|
||||
enum { InvalidKey = unsigned(-1) };
|
||||
|
||||
/// An element of the hash table.
|
||||
struct Node
|
||||
{
|
||||
K first; ///< The element's key.
|
||||
V second; ///< The element's value.
|
||||
uint32_t next; ///< The index of the next element with the same (wrapped) hash; Do not use.
|
||||
};
|
||||
|
||||
typedef Node* iterator;
|
||||
typedef const Node* const_iterator;
|
||||
|
||||
|
||||
HashMap(Allocator& allocator = GetDefaultAllocator()) :
|
||||
allocator_(allocator),
|
||||
keys_(allocator_),
|
||||
values_(allocator_),
|
||||
size_(0)
|
||||
{ }
|
||||
|
||||
iterator begin() { return values_.begin(); }
|
||||
const_iterator begin() const { return values_.begin(); }
|
||||
iterator end() { return values_.begin() + values_.size(); }
|
||||
const_iterator end() const { return values_.begin() + values_.size(); }
|
||||
|
||||
size_t size() const { return size_; }
|
||||
bool empty() const { return size_ == 0; }
|
||||
|
||||
size_t count(const K& k) const
|
||||
{
|
||||
return find(k) != end() ? 1 : 0;
|
||||
}
|
||||
|
||||
iterator find(const K& k)
|
||||
{
|
||||
if (keys_.empty() || values_.empty())
|
||||
return end();
|
||||
uint32_t h;
|
||||
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
|
||||
const uint32_t ha = h % keys_.size();
|
||||
volatile uint32_t vi = keys_[ha];
|
||||
while (vi != InvalidKey)
|
||||
{
|
||||
if (values_[vi].first == k)
|
||||
{
|
||||
return &values_[vi];
|
||||
}
|
||||
vi = values_[vi].next;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
const_iterator find(const K& k) const
|
||||
{
|
||||
if (keys_.empty() || values_.empty())
|
||||
return end();
|
||||
uint32_t h;
|
||||
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
|
||||
const uint32_t ha = h % keys_.size();
|
||||
volatile uint32_t vi = keys_[ha];
|
||||
while (vi != InvalidKey)
|
||||
{
|
||||
if (values_[vi].first == k)
|
||||
{
|
||||
return &values_[vi];
|
||||
}
|
||||
vi = values_[vi].next;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
iterator insert(const K& k, const V& v)
|
||||
{
|
||||
if (values_.size() >= 0.6f*keys_.size())
|
||||
{
|
||||
Rehash(values_.size()*2 + 10);
|
||||
}
|
||||
|
||||
uint32_t h;
|
||||
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
|
||||
const uint32_t ha = h % keys_.size();
|
||||
uint32_t vi = keys_[ha];
|
||||
|
||||
if (vi == InvalidKey)
|
||||
{
|
||||
keys_[ha] = values_.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (values_[vi].next == InvalidKey)
|
||||
{
|
||||
values_[vi].next = values_.size();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
vi = values_[vi].next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Node node;
|
||||
node.first = k;
|
||||
node.second = v;
|
||||
node.next = InvalidKey;
|
||||
values_.push_back(node);
|
||||
|
||||
++size_;
|
||||
|
||||
return &values_[values_.size()-1];
|
||||
}
|
||||
|
||||
V& operator[] (const K& k)
|
||||
{
|
||||
iterator it = find(k);
|
||||
if (it == end())
|
||||
{
|
||||
return insert(k, V())->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
size_t erase(const K& k)
|
||||
{
|
||||
if (keys_.empty())
|
||||
return 0;
|
||||
uint32_t h;
|
||||
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
|
||||
const uint32_t ha = h % keys_.size();
|
||||
uint32_t vi = keys_[ha];
|
||||
uint32_t prevVi = InvalidKey;
|
||||
while (vi != InvalidKey)
|
||||
{
|
||||
if (values_[vi].first == k)
|
||||
{
|
||||
if (prevVi == InvalidKey)
|
||||
{
|
||||
keys_[ha] = values_[vi].next;
|
||||
}
|
||||
else
|
||||
{
|
||||
values_[prevVi].next = values_[vi].next;
|
||||
}
|
||||
|
||||
--size_;
|
||||
if (vi == values_.size() - 1)
|
||||
{
|
||||
values_.pop_back();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t lastVi = values_.size()-1;
|
||||
values_[vi] = values_[lastVi];
|
||||
values_.pop_back();
|
||||
|
||||
for (typename Array<uint32_t>::iterator it = keys_.begin(); it != keys_.end(); ++it)
|
||||
{
|
||||
if (*it == lastVi)
|
||||
{
|
||||
*it = vi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (typename Array<Node>::iterator it = values_.begin(); it != values_.end(); ++it)
|
||||
{
|
||||
if (it->next == lastVi)
|
||||
{
|
||||
it->next = vi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
prevVi = vi;
|
||||
vi = values_[vi].next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
keys_.clear();
|
||||
values_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
Allocator& allocator_;
|
||||
Array<uint32_t> keys_;
|
||||
Array<Node> values_;
|
||||
size_t size_;
|
||||
|
||||
void Rehash(size_t newSize)
|
||||
{
|
||||
Array<uint32_t> keys(allocator_, newSize);
|
||||
Array<Node> values(allocator_, values_.size());
|
||||
|
||||
for (size_t i = 0; i < newSize; ++i)
|
||||
keys.push_back(InvalidKey);
|
||||
|
||||
keys_.swap(keys);
|
||||
values_.swap(values);
|
||||
size_ = 0;
|
||||
|
||||
for (typename Array<Node>::const_iterator it = values.begin();
|
||||
it != values.end();
|
||||
++it)
|
||||
{
|
||||
insert(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// A ring buffer.
|
||||
/**
|
||||
* \tparam N The number of elements that can be stored in the ring buffer.
|
||||
* \tparam T Type of the elements stored in the ring buffer.
|
||||
*/
|
||||
template<int N, class T>
|
||||
class GAINPUT_LIBEXPORT RingBuffer
|
||||
{
|
||||
public:
|
||||
RingBuffer() :
|
||||
nextRead_(0),
|
||||
nextWrite_(0)
|
||||
{ }
|
||||
|
||||
|
||||
bool CanGet() const
|
||||
{
|
||||
return nextRead_ < nextWrite_;
|
||||
}
|
||||
|
||||
size_t GetCount() const
|
||||
{
|
||||
const size_t d = nextWrite_ - nextRead_;
|
||||
return d > N ? N : d;
|
||||
}
|
||||
|
||||
T Get()
|
||||
{
|
||||
return buf_[(nextRead_++) % N];
|
||||
}
|
||||
|
||||
void Put(T d)
|
||||
{
|
||||
buf_[(nextWrite_++) % N] = d;
|
||||
while (nextRead_ + N < nextWrite_)
|
||||
++nextRead_;
|
||||
}
|
||||
|
||||
private:
|
||||
T buf_[N];
|
||||
size_t nextRead_;
|
||||
size_t nextWrite_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user