Update AMTL with a number of changes.
- Introduce HashMap, a key-value map based on HashTable. - Introduce LinkedList, to port from SourceHook::List. - Introduce AString, to port from SourceHook::String. - Introduce KE_OVERRIDE and KE_DELETE helpers for C++11. - HashTable now constructs/destructs only live items. - Fix insert-on-removed-item bug in HashTable. - Fix Vector keeping a new maxsize if allocation fails. - Renamed am-inline-list.h to am-inlinelist.h. --HG-- rename : public/amtl/am-inline-list.h => public/amtl/am-inlinelist.h
This commit is contained in:
parent
da650606e3
commit
90a2d1bb39
@ -38,7 +38,7 @@ namespace ke {
|
||||
// The default system allocator policy will crash on out-of-memory.
|
||||
class SystemAllocatorPolicy
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
void reportOutOfMemory() {
|
||||
fprintf(stderr, "OUT OF MEMORY\n");
|
||||
abort();
|
||||
|
133
public/amtl/am-hashmap.h
Normal file
133
public/amtl/am-hashmap.h
Normal file
@ -0,0 +1,133 @@
|
||||
// vim: set sts=8 ts=2 sw=2 tw=99 et:
|
||||
//
|
||||
// Copyright (C) 2013, David Anderson and AlliedModders LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of AlliedModders LLC nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef _include_amtl_hashmap_h_
|
||||
#define _include_amtl_hashmap_h_
|
||||
|
||||
#include <am-hashtable.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
// Template parameters:
|
||||
//
|
||||
// K - Key type.
|
||||
// V - Value type.
|
||||
// HashPolicy - A struct with a hash and comparator function for each lookup type:
|
||||
// static uint32_t hash(const Type &value);
|
||||
// static bool matches(const Type &value, const K &key);
|
||||
//
|
||||
// All types that match a given key, must compute the same hash.
|
||||
//
|
||||
// Note that like HashTable, a HashMap is not usable until init() has been called.
|
||||
template <typename K,
|
||||
typename V,
|
||||
typename HashPolicy,
|
||||
typename AllocPolicy = SystemAllocatorPolicy>
|
||||
class HashMap : public AllocPolicy
|
||||
{
|
||||
private:
|
||||
struct Entry
|
||||
{
|
||||
K key;
|
||||
V value;
|
||||
|
||||
Entry(const K &aKey, const V &aValue)
|
||||
: key(aKey),
|
||||
value(aValue)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct Policy
|
||||
{
|
||||
typedef Entry Payload;
|
||||
|
||||
template <typename Lookup>
|
||||
static uint32_t hash(const Lookup &key) {
|
||||
return HashPolicy::hash(key);
|
||||
}
|
||||
|
||||
template <typename Lookup>
|
||||
static bool matches(const Lookup &key, const Payload &payload) {
|
||||
return HashPolicy::matches(key, payload.key);
|
||||
}
|
||||
};
|
||||
|
||||
typedef HashTable<Policy, AllocPolicy> Internal;
|
||||
|
||||
public:
|
||||
HashMap(AllocPolicy ap = AllocPolicy())
|
||||
: table_(ap)
|
||||
{
|
||||
}
|
||||
|
||||
// capacity must be a power of two.
|
||||
bool init(size_t capacity = 16) {
|
||||
return table_.init(capacity);
|
||||
}
|
||||
|
||||
typedef typename Internal::Result Result;
|
||||
typedef typename Internal::Insert Insert;
|
||||
|
||||
template <typename Lookup>
|
||||
Result find(const Lookup &key) {
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
template <typename Lookup>
|
||||
Insert findForAdd(const Lookup &key) {
|
||||
return table_.findForAdd(key);
|
||||
}
|
||||
|
||||
template <typename Lookup>
|
||||
void removeIfExists(const Lookup &key) {
|
||||
return table_.remove(key);
|
||||
}
|
||||
|
||||
void remove(Result &r) {
|
||||
table_.remove(r);
|
||||
}
|
||||
|
||||
// The map must not have been mutated in between findForAdd() and add().
|
||||
// The Insert object is still valid after add() returns, however.
|
||||
bool add(Insert &i, const K &key, const V &value) {
|
||||
return table_.add(i, Entry(key, value));
|
||||
}
|
||||
|
||||
size_t estimateMemoryUse() const {
|
||||
return table_.estimateMemoryUse();
|
||||
}
|
||||
|
||||
private:
|
||||
Internal table_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _include_amtl_hashmap_h_
|
586
public/amtl/am-hashtable.h
Normal file
586
public/amtl/am-hashtable.h
Normal file
@ -0,0 +1,586 @@
|
||||
// vim: set sts=8 ts=2 sw=2 tw=99 et:
|
||||
//
|
||||
// Copyright (C) 2013, David Anderson and AlliedModders LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of AlliedModders LLC nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef _INCLUDE_KEIMA_HASHTABLE_H_
|
||||
#define _INCLUDE_KEIMA_HASHTABLE_H_
|
||||
|
||||
#include <new>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include "am-utility.h"
|
||||
|
||||
namespace ke {
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
class HashTableEntry
|
||||
{
|
||||
uint32_t hash_;
|
||||
T t_;
|
||||
|
||||
public:
|
||||
static const uint32_t kFreeHash = 0;
|
||||
static const uint32_t kRemovedHash = 1;
|
||||
|
||||
public:
|
||||
void setHash(uint32_t hash, const T &t) {
|
||||
hash_ = hash;
|
||||
new (&t_) T(t);
|
||||
}
|
||||
uint32_t hash() const {
|
||||
return hash_;
|
||||
}
|
||||
void setRemoved() {
|
||||
destruct();
|
||||
hash_ = kRemovedHash;
|
||||
}
|
||||
void initialize() {
|
||||
hash_ = kFreeHash;
|
||||
}
|
||||
void destruct() {
|
||||
if (isLive())
|
||||
t_.~T();
|
||||
}
|
||||
bool removed() const {
|
||||
return hash_ == kRemovedHash;
|
||||
}
|
||||
bool free() const {
|
||||
return hash_ == kFreeHash;
|
||||
}
|
||||
bool isLive() const {
|
||||
return hash_ > kRemovedHash;
|
||||
}
|
||||
T &payload() {
|
||||
assert(isLive());
|
||||
return t_;
|
||||
}
|
||||
bool sameHash(uint32_t hash) const {
|
||||
return hash_ == hash;
|
||||
}
|
||||
|
||||
private:
|
||||
HashTableEntry(const HashTableEntry &other) KE_DELETE;
|
||||
HashTableEntry &operator =(const HashTableEntry &other) KE_DELETE;
|
||||
};
|
||||
}
|
||||
|
||||
// The HashPolicy for the table must have the following members:
|
||||
//
|
||||
// Payload
|
||||
// static uint32_t hash(const LookupType &key);
|
||||
// static bool matches(const LookupType &key, const Payload &other);
|
||||
//
|
||||
// Payload must be a type, and LookupType is any type that lookups will be
|
||||
// performed with (these functions can be overloaded). Example:
|
||||
//
|
||||
// struct Policy {
|
||||
// typedef KeyValuePair Payload;
|
||||
// static uint32 hash(const Key &key) {
|
||||
// ...
|
||||
// }
|
||||
// static bool matches(const Key &key, const KeyValuePair &pair) {
|
||||
// ...
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// Note that the table is not usable until init() has been called.
|
||||
//
|
||||
template <typename HashPolicy, typename AllocPolicy = SystemAllocatorPolicy>
|
||||
class HashTable : public AllocPolicy
|
||||
{
|
||||
friend class iterator;
|
||||
|
||||
typedef typename HashPolicy::Payload Payload;
|
||||
typedef detail::HashTableEntry<Payload> Entry;
|
||||
|
||||
private:
|
||||
static const uint32_t kMinCapacity = 16;
|
||||
static const uint32_t kMaxCapacity = INT_MAX / sizeof(Entry);
|
||||
|
||||
template <typename Key>
|
||||
uint32_t computeHash(const Key &key) {
|
||||
// Multiply by golden ratio.
|
||||
uint32_t hash = HashPolicy::hash(key) * 0x9E3779B9;
|
||||
if (hash == Entry::kFreeHash || hash == Entry::kRemovedHash)
|
||||
hash += 2;
|
||||
return hash;
|
||||
}
|
||||
|
||||
Entry *createTable(uint32_t capacity) {
|
||||
assert(capacity <= kMaxCapacity);
|
||||
|
||||
Entry *table = (Entry *)this->malloc(capacity * sizeof(Entry));
|
||||
if (!table)
|
||||
return NULL;
|
||||
|
||||
for (size_t i = 0; i < capacity; i++)
|
||||
table[i].initialize();
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
public:
|
||||
class Result
|
||||
{
|
||||
friend class HashTable;
|
||||
|
||||
Entry *entry_;
|
||||
|
||||
Entry &entry() {
|
||||
return *entry_;
|
||||
}
|
||||
|
||||
public:
|
||||
Result(Entry *entry)
|
||||
: entry_(entry)
|
||||
{ }
|
||||
|
||||
Payload * operator ->() {
|
||||
return &entry_->payload();
|
||||
}
|
||||
Payload & operator *() {
|
||||
return entry_->payload();
|
||||
}
|
||||
|
||||
bool found() const {
|
||||
return entry_->isLive();
|
||||
}
|
||||
};
|
||||
|
||||
class Insert : public Result
|
||||
{
|
||||
uint32_t hash_;
|
||||
|
||||
public:
|
||||
Insert(Entry *entry, uint32_t hash)
|
||||
: Result(entry),
|
||||
hash_(hash)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t hash() const {
|
||||
return hash_;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
class Probulator {
|
||||
uint32_t hash_;
|
||||
uint32_t capacity_;
|
||||
|
||||
public:
|
||||
Probulator(uint32_t hash, uint32_t capacity)
|
||||
: hash_(hash),
|
||||
capacity_(capacity)
|
||||
{
|
||||
assert(IsPowerOfTwo(capacity_));
|
||||
}
|
||||
|
||||
uint32_t entry() const {
|
||||
return hash_ & (capacity_ - 1);
|
||||
}
|
||||
uint32_t next() {
|
||||
hash_++;
|
||||
return entry();
|
||||
}
|
||||
};
|
||||
|
||||
bool underloaded() const {
|
||||
// Check if the table is underloaded: < 25% entries used.
|
||||
return (capacity_ > kMinCapacity) && (nelements_ + ndeleted_ < capacity_ / 4);
|
||||
}
|
||||
bool overloaded() const {
|
||||
// Grow if the table is overloaded: > 75% entries used.
|
||||
return (nelements_ + ndeleted_) > ((capacity_ / 2) + (capacity_ / 4));
|
||||
}
|
||||
|
||||
bool shrink() {
|
||||
if ((capacity_ >> 1) < minCapacity_)
|
||||
return true;
|
||||
return changeCapacity(capacity_ >> 1);
|
||||
}
|
||||
|
||||
bool grow() {
|
||||
if (capacity_ >= kMaxCapacity) {
|
||||
this->reportAllocationOverflow();
|
||||
return false;
|
||||
}
|
||||
return changeCapacity(capacity_ << 1);
|
||||
}
|
||||
|
||||
bool changeCapacity(uint32_t newCapacity) {
|
||||
assert(newCapacity <= kMaxCapacity);
|
||||
|
||||
Entry *newTable = createTable(newCapacity);
|
||||
if (!newTable)
|
||||
return false;
|
||||
|
||||
Entry *oldTable = table_;
|
||||
uint32_t oldCapacity = capacity_;
|
||||
|
||||
table_ = newTable;
|
||||
capacity_ = newCapacity;
|
||||
ndeleted_ = 0;
|
||||
|
||||
for (uint32_t i = 0; i < oldCapacity; i++) {
|
||||
Entry &oldEntry = oldTable[i];
|
||||
if (oldEntry.isLive()) {
|
||||
Insert p = insertUnique(oldEntry.hash());
|
||||
p.entry().setHash(p.hash(), oldEntry.payload());
|
||||
}
|
||||
oldEntry.destruct();
|
||||
}
|
||||
this->free(oldTable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// For use when the key is known to be unique.
|
||||
Insert insertUnique(uint32_t hash) {
|
||||
Probulator probulator(hash, capacity_);
|
||||
|
||||
Entry *e = &table_[probulator.entry()];
|
||||
for (;;) {
|
||||
if (e->free() || e->removed())
|
||||
break;
|
||||
e = &table_[probulator.next()];
|
||||
}
|
||||
|
||||
return Insert(e, hash);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
Result lookup(const Key &key) {
|
||||
uint32_t hash = computeHash(key);
|
||||
Probulator probulator(hash, capacity_);
|
||||
|
||||
Entry *e = &table_[probulator.entry()];
|
||||
for (;;) {
|
||||
if (e->free())
|
||||
break;
|
||||
if (e->isLive() &&
|
||||
e->sameHash(hash) &&
|
||||
HashPolicy::matches(key, e->payload()))
|
||||
{
|
||||
return Result(e);
|
||||
}
|
||||
e = &table_[probulator.next()];
|
||||
}
|
||||
|
||||
return Result(e);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
Insert lookupForAdd(const Key &key) {
|
||||
uint32_t hash = computeHash(key);
|
||||
Probulator probulator(hash, capacity_);
|
||||
|
||||
Entry *e = &table_[probulator.entry()];
|
||||
for (;;) {
|
||||
if (!e->isLive())
|
||||
break;
|
||||
if (e->sameHash(hash) && HashPolicy::matches(key, e->payload()))
|
||||
break;
|
||||
e = &table_[probulator.next()];
|
||||
}
|
||||
|
||||
return Insert(e, hash);
|
||||
}
|
||||
|
||||
bool internalAdd(Insert &i, const Payload &payload) {
|
||||
assert(!i.found());
|
||||
|
||||
// If the entry is deleted, just re-use the slot.
|
||||
if (i.entry().removed()) {
|
||||
ndeleted_--;
|
||||
} else {
|
||||
// Otherwise, see if we're at max capacity.
|
||||
if (nelements_ == kMaxCapacity) {
|
||||
this->reportAllocationOverflow();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the table is over or underloaded. The table is always at
|
||||
// least 25% free, so this check is enough to guarantee one free slot.
|
||||
// (Without one free slot, insertion search could infinite loop.)
|
||||
uint32_t oldCapacity = capacity_;
|
||||
if (!checkDensity())
|
||||
return false;
|
||||
|
||||
// If the table changed size, we need to find a new insertion point.
|
||||
// Note that a removed entry is impossible: either we caught it above,
|
||||
// or we just resized and no entries are removed.
|
||||
if (capacity_ != oldCapacity)
|
||||
i = insertUnique(i.hash());
|
||||
}
|
||||
|
||||
i.entry().setHash(i.hash(), payload);
|
||||
nelements_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void removeEntry(Entry &e) {
|
||||
assert(e.isLive());
|
||||
e.setRemoved();
|
||||
ndeleted_++;
|
||||
nelements_--;
|
||||
}
|
||||
|
||||
public:
|
||||
HashTable(AllocPolicy ap)
|
||||
: AllocPolicy(ap),
|
||||
capacity_(0),
|
||||
nelements_(0),
|
||||
ndeleted_(0),
|
||||
table_(NULL),
|
||||
minCapacity_(kMinCapacity)
|
||||
{
|
||||
}
|
||||
|
||||
~HashTable()
|
||||
{
|
||||
for (uint32_t i = 0; i < capacity_; i++)
|
||||
table_[i].destruct();
|
||||
this->free(table_);
|
||||
}
|
||||
|
||||
bool init(uint32_t capacity = 0) {
|
||||
if (capacity < kMinCapacity) {
|
||||
capacity = kMinCapacity;
|
||||
} else if (capacity > kMaxCapacity) {
|
||||
this->reportAllocationOverflow();
|
||||
return false;
|
||||
}
|
||||
|
||||
minCapacity_ = capacity;
|
||||
|
||||
assert(IsPowerOfTwo(capacity));
|
||||
capacity_ = capacity;
|
||||
|
||||
table_ = createTable(capacity_);
|
||||
if (!table_)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// The Result object must not be used past mutating table operations.
|
||||
template <typename Key>
|
||||
Result find(const Key &key) {
|
||||
return lookup(key);
|
||||
}
|
||||
|
||||
// The Insert object must not be used past mutating table operations.
|
||||
template <typename Key>
|
||||
Insert findForAdd(const Key &key) {
|
||||
return lookupForAdd(key);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void removeIfExists(const Key &key) {
|
||||
Result r = find(key);
|
||||
if (!r.found())
|
||||
return;
|
||||
remove(r);
|
||||
}
|
||||
|
||||
void remove(Result &r) {
|
||||
assert(r.found());
|
||||
removeEntry(r.entry());
|
||||
}
|
||||
|
||||
// The table must not have been mutated in between findForAdd() and add().
|
||||
// The Insert object is still valid after add() returns, however.
|
||||
bool add(Insert &i, const Payload &payload) {
|
||||
return internalAdd(i, payload);
|
||||
}
|
||||
|
||||
bool checkDensity() {
|
||||
if (underloaded())
|
||||
return shrink();
|
||||
if (overloaded())
|
||||
return grow();
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t estimateMemoryUse() const {
|
||||
return sizeof(Entry) * capacity_;
|
||||
}
|
||||
|
||||
public:
|
||||
// It is illegal to mutate a HashTable during iteration.
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator(HashTable *table)
|
||||
: table_(table),
|
||||
i_(table->table_),
|
||||
end_(table->table_ + table->capacity_)
|
||||
{
|
||||
while (i_ < end_ && !i_->isLive())
|
||||
i_++;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return i_ == end_;
|
||||
}
|
||||
|
||||
void erase() {
|
||||
assert(!empty());
|
||||
table_->removeEntry(*i_);
|
||||
}
|
||||
|
||||
const Payload &operator *() const {
|
||||
return i_->payload();
|
||||
}
|
||||
|
||||
void next() {
|
||||
do {
|
||||
i_++;
|
||||
} while (i_ < end_ && !i_->isLive());
|
||||
}
|
||||
|
||||
private:
|
||||
HashTable *table_;
|
||||
Entry *i_;
|
||||
Entry *end_;
|
||||
};
|
||||
|
||||
private:
|
||||
HashTable(const HashTable &other) KE_DELETE;
|
||||
HashTable &operator =(const HashTable &other) KE_DELETE;
|
||||
|
||||
private:
|
||||
uint32_t capacity_;
|
||||
uint32_t nelements_;
|
||||
uint32_t ndeleted_;
|
||||
Entry *table_;
|
||||
uint32_t minCapacity_;
|
||||
};
|
||||
|
||||
// Bob Jenkin's one-at-a-time hash function[1].
|
||||
//
|
||||
// [1] http://burtleburtle.net/bob/hash/doobs.html
|
||||
class CharacterStreamHasher
|
||||
{
|
||||
uint32_t hash;
|
||||
|
||||
public:
|
||||
CharacterStreamHasher()
|
||||
: hash(0)
|
||||
{ }
|
||||
|
||||
void add(char c) {
|
||||
hash += c;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
void add(const char *s, size_t length) {
|
||||
for (size_t i = 0; i < length; i++)
|
||||
add(s[i]);
|
||||
}
|
||||
|
||||
uint32_t result() {
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
HashCharSequence(const char *s, size_t length)
|
||||
{
|
||||
CharacterStreamHasher hasher;
|
||||
hasher.add(s, length);
|
||||
return hasher.result();
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
FastHashCharSequence(const char *s, size_t length)
|
||||
{
|
||||
uint32_t hash = 0;
|
||||
for (size_t i = 0; i < length; i++)
|
||||
hash = s[i] + (hash << 6) + (hash << 16) - hash;
|
||||
return hash;
|
||||
}
|
||||
|
||||
// From http://burtleburtle.net/bob/hash/integer.html
|
||||
static inline uint32_t
|
||||
HashInt32(int32_t a)
|
||||
{
|
||||
a = (a ^ 61) ^ (a >> 16);
|
||||
a = a + (a << 3);
|
||||
a = a ^ (a >> 4);
|
||||
a = a * 0x27d4eb2d;
|
||||
a = a ^ (a >> 15);
|
||||
return a;
|
||||
}
|
||||
|
||||
// From http://www.cris.com/~Ttwang/tech/inthash.htm
|
||||
static inline uint32_t
|
||||
HashInt64(int64_t key)
|
||||
{
|
||||
key = (~key) + (key << 18); // key = (key << 18) - key - 1;
|
||||
key = key ^ (uint64(key) >> 31);
|
||||
key = key * 21; // key = (key + (key << 2)) + (key << 4);
|
||||
key = key ^ (uint64(key) >> 11);
|
||||
key = key + (key << 6);
|
||||
key = key ^ (uint64(key) >> 22);
|
||||
return uint32(key);
|
||||
}
|
||||
|
||||
template <size_t Size>
|
||||
static inline uint32_t
|
||||
HashInteger(uintptr_t value);
|
||||
|
||||
template <>
|
||||
inline uint32_t
|
||||
HashInteger<4>(uintptr_t value)
|
||||
{
|
||||
return HashInt32(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint32_t
|
||||
HashInteger<8>(uintptr_t value)
|
||||
{
|
||||
return HashInt64(value);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
HashPointer(void *ptr)
|
||||
{
|
||||
return HashInteger<sizeof(ptr)>(reinterpret_cast<uintptr_t>(ptr));
|
||||
}
|
||||
|
||||
} // namespace ke
|
||||
|
||||
#endif // _INCLUDE_KEIMA_HASHTABLE_H_
|
290
public/amtl/am-linkedlist.h
Normal file
290
public/amtl/am-linkedlist.h
Normal file
@ -0,0 +1,290 @@
|
||||
// vim: set sts=8 ts=2 sw=2 tw=99 et:
|
||||
//
|
||||
// Copyright (C) 2013, David Anderson and AlliedModders LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of AlliedModders LLC nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef _include_amtl_linkedlist_h_
|
||||
#define _include_amtl_linkedlist_h_
|
||||
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
#include <am-allocator-policies.h>
|
||||
#include <am-utility.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
// LinkedList, analagous to std::list or SourceHook::List. Since it performs a
|
||||
// malloc() and free() on every contained node, it should be avoided unless
|
||||
// absolutely necessary, or for when allocation performance is not a factor. It
|
||||
// is provided here to safely port old AlliedModders code to AMTL.
|
||||
//
|
||||
// In order to use a circular chain, LinkedList's allocation size includes
|
||||
// exactly one T. If T is very large, LinkedList should be allocated on the
|
||||
// heap, to avoid using the stack.
|
||||
template <class T, class AllocPolicy = SystemAllocatorPolicy>
|
||||
class LinkedList : public AllocPolicy
|
||||
{
|
||||
public:
|
||||
friend class iterator;
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
Node(const T &o)
|
||||
: obj(o)
|
||||
{
|
||||
}
|
||||
|
||||
T obj;
|
||||
Node *next;
|
||||
Node *prev;
|
||||
};
|
||||
|
||||
public:
|
||||
LinkedList(AllocPolicy = AllocPolicy())
|
||||
: length_(0)
|
||||
{
|
||||
}
|
||||
~LinkedList() {
|
||||
clear();
|
||||
}
|
||||
|
||||
bool append(const T &obj) {
|
||||
Node *node = allocNode(obj);
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
node->prev = head()->prev;
|
||||
node->next = head();
|
||||
head()->prev->next = node;
|
||||
head()->prev = node;
|
||||
|
||||
length_++;
|
||||
}
|
||||
|
||||
bool prepend(const T &obj) {
|
||||
return insert(begin(), obj);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return length_;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Node *node = head()->next;
|
||||
Node *temp;
|
||||
head()->next = head();
|
||||
head()->prev = head();
|
||||
|
||||
// Iterate through the nodes until we find the sentinel again.
|
||||
while (node != head()) {
|
||||
temp = node->next;
|
||||
freeNode(node);
|
||||
node = temp;
|
||||
}
|
||||
length_ = 0;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return (length_ == 0);
|
||||
}
|
||||
|
||||
T &front() {
|
||||
assert(!empty());
|
||||
return head()->next->obj;
|
||||
}
|
||||
T &back() {
|
||||
assert(!empty());
|
||||
return head()->prev->obj;
|
||||
}
|
||||
|
||||
private:
|
||||
const Node *head() const {
|
||||
return sentinel_.address();
|
||||
}
|
||||
Node *head() {
|
||||
return sentinel_.address();
|
||||
}
|
||||
|
||||
Node *allocNode(const T &obj) {
|
||||
Node *node = (Node *)this->malloc(sizeof(Node));
|
||||
if (!node)
|
||||
return NULL;
|
||||
new (node) Node(obj);
|
||||
return node;
|
||||
}
|
||||
|
||||
void freeNode(Node *node) {
|
||||
node->obj.~T();
|
||||
this->free(node);
|
||||
}
|
||||
|
||||
private:
|
||||
StorageBuffer<Node> sentinel_;
|
||||
size_t length_;
|
||||
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
friend class LinkedList;
|
||||
|
||||
public:
|
||||
iterator()
|
||||
: this_(NULL)
|
||||
{
|
||||
}
|
||||
iterator(const LinkedList &src)
|
||||
: this_(src.head())
|
||||
{
|
||||
}
|
||||
iterator(Node *n)
|
||||
: this_(n)
|
||||
{
|
||||
}
|
||||
iterator(const iterator &where)
|
||||
: this_(where.this_)
|
||||
{
|
||||
}
|
||||
|
||||
iterator &operator --() {
|
||||
if (this_)
|
||||
this_ = this_->prev;
|
||||
return *this;
|
||||
}
|
||||
iterator operator --(int) {
|
||||
iterator old(*this);
|
||||
if (this_)
|
||||
this_ = this_->prev;
|
||||
return old;
|
||||
}
|
||||
iterator &operator ++() {
|
||||
if (this_)
|
||||
this_ = this_->next;
|
||||
return *this;
|
||||
}
|
||||
iterator operator ++(int) {
|
||||
iterator old(*this);
|
||||
if (this_)
|
||||
this_ = this_->next;
|
||||
return old;
|
||||
}
|
||||
|
||||
const T &operator * () const {
|
||||
return this_->obj;
|
||||
}
|
||||
T &operator * () {
|
||||
return this_->obj;
|
||||
}
|
||||
T *operator ->() {
|
||||
return &this_->obj;
|
||||
}
|
||||
const T *operator ->() const {
|
||||
return &(this_->obj);
|
||||
}
|
||||
|
||||
bool operator !=(const iterator &where) const {
|
||||
return (this_ != where.this_);
|
||||
}
|
||||
bool operator ==(const iterator &where) const {
|
||||
return (this_ == where.this_);
|
||||
}
|
||||
|
||||
operator bool() {
|
||||
return !!this_;
|
||||
}
|
||||
|
||||
private:
|
||||
Node *this_;
|
||||
};
|
||||
|
||||
public:
|
||||
iterator begin() const {
|
||||
return iterator(head()->next);
|
||||
}
|
||||
iterator end() const {
|
||||
return iterator(head());
|
||||
}
|
||||
iterator erase(iterator &where) {
|
||||
Node *pNode = where.this_;
|
||||
iterator iter(where);
|
||||
iter++;
|
||||
|
||||
pNode->prev->next = pNode->next;
|
||||
pNode->next->prev = pNode->prev;
|
||||
|
||||
freeNode(pNode);
|
||||
length_--;
|
||||
|
||||
return iter;
|
||||
}
|
||||
iterator insert(iterator where, const T &obj) {
|
||||
// Insert obj right before where
|
||||
Node *node = allocNode(obj);
|
||||
if (!node)
|
||||
return where;
|
||||
|
||||
Node *pWhereNode = where.this_;
|
||||
|
||||
pWhereNode->prev->next = node;
|
||||
node->prev = pWhereNode->prev;
|
||||
pWhereNode->prev = node;
|
||||
node->next = pWhereNode;
|
||||
|
||||
length_++;
|
||||
return iterator(node);
|
||||
}
|
||||
|
||||
public:
|
||||
void remove(const T &obj) {
|
||||
for (iterator b = begin(); b != end(); b++) {
|
||||
if (*b == obj) {
|
||||
erase(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
iterator find(const U &equ) const {
|
||||
for (iterator iter = begin(); iter != end(); iter++) {
|
||||
if (*iter == equ)
|
||||
return iter;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// These are disallowed because they basically violate the failure handling
|
||||
// model for AllocPolicies and are also likely to have abysmal performance.
|
||||
LinkedList &operator =(const LinkedList<T> &other) KE_DELETE;
|
||||
LinkedList(const LinkedList<T> &other) KE_DELETE;
|
||||
};
|
||||
|
||||
} // namespace ke
|
||||
|
||||
#endif //_INCLUDE_CSDM_LIST_H
|
101
public/amtl/am-string.h
Normal file
101
public/amtl/am-string.h
Normal file
@ -0,0 +1,101 @@
|
||||
// vim: set sts=8 ts=2 sw=2 tw=99 et:
|
||||
//
|
||||
// Copyright (C) 2013, David Anderson and AlliedModders LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of AlliedModders LLC nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef _include_amtl_string_h_
|
||||
#define _include_amtl_string_h_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <am-utility.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
// ASCII string.
|
||||
class AString
|
||||
{
|
||||
public:
|
||||
AString()
|
||||
: length_(0)
|
||||
{
|
||||
}
|
||||
explicit AString(const char *str) {
|
||||
set(str, strlen(str));
|
||||
}
|
||||
AString(const char *str, size_t length) {
|
||||
set(str, length);
|
||||
}
|
||||
AString(const AString &other) {
|
||||
set(other.chars_, other.length_);
|
||||
}
|
||||
|
||||
AString &operator =(const char *str) {
|
||||
set(str, strlen(str));
|
||||
return *this;
|
||||
}
|
||||
AString &operator =(const AString &other) {
|
||||
set(other.chars_, other.length_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator ==(const AString &other) const {
|
||||
return other.length() == length() &&
|
||||
memcmp(other.chars(), chars(), length()) == 0;
|
||||
}
|
||||
|
||||
char operator [](size_t index) const {
|
||||
assert(index < length());
|
||||
return chars()[index];
|
||||
}
|
||||
|
||||
size_t length() const {
|
||||
return length_;
|
||||
}
|
||||
|
||||
const char *chars() const {
|
||||
if (!chars_)
|
||||
return "";
|
||||
return chars_;
|
||||
}
|
||||
|
||||
private:
|
||||
void set(const char *str, size_t length) {
|
||||
chars_ = new char[length + 1];
|
||||
length_ = length;
|
||||
memcpy(chars_, str, length);
|
||||
chars_[length] = '\0';
|
||||
}
|
||||
|
||||
private:
|
||||
AutoArray<char> chars_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _include_amtl_string_h_
|
@ -57,15 +57,15 @@ class Mutex : public Lockable
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
}
|
||||
|
||||
bool DoTryLock() {
|
||||
bool DoTryLock() KE_OVERRIDE {
|
||||
return pthread_mutex_trylock(&mutex_) == 0;
|
||||
}
|
||||
|
||||
void DoLock() {
|
||||
void DoLock() KE_OVERRIDE {
|
||||
pthread_mutex_lock(&mutex_);
|
||||
}
|
||||
|
||||
void DoUnlock() {
|
||||
void DoUnlock() KE_OVERRIDE {
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
}
|
||||
|
||||
@ -92,13 +92,13 @@ class ConditionVariable : public Lockable
|
||||
pthread_cond_destroy(&cv_);
|
||||
}
|
||||
|
||||
bool DoTryLock() {
|
||||
bool DoTryLock() KE_OVERRIDE {
|
||||
return mutex_.DoTryLock();
|
||||
}
|
||||
void DoLock() {
|
||||
void DoLock() KE_OVERRIDE {
|
||||
mutex_.DoLock();
|
||||
}
|
||||
void DoUnlock() {
|
||||
void DoUnlock() KE_OVERRIDE {
|
||||
mutex_.DoUnlock();
|
||||
}
|
||||
|
||||
|
@ -44,14 +44,14 @@ class CriticalSection : public Lockable
|
||||
DeleteCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
bool DoTryLock() {
|
||||
bool DoTryLock() KE_OVERRIDE {
|
||||
return !!TryEnterCriticalSection(&cs_);
|
||||
}
|
||||
void DoLock() {
|
||||
void DoLock() KE_OVERRIDE {
|
||||
EnterCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
void DoUnlock() {
|
||||
void DoUnlock() KE_OVERRIDE {
|
||||
LeaveCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
@ -72,13 +72,13 @@ class ConditionVariable : public Lockable
|
||||
CloseHandle(event_);
|
||||
}
|
||||
|
||||
bool DoTryLock() {
|
||||
bool DoTryLock() KE_OVERRIDE {
|
||||
return cs_.DoTryLock();
|
||||
}
|
||||
void DoLock() {
|
||||
void DoLock() KE_OVERRIDE {
|
||||
cs_.DoLock();
|
||||
}
|
||||
void DoUnlock() {
|
||||
void DoUnlock() KE_OVERRIDE {
|
||||
cs_.DoUnlock();
|
||||
}
|
||||
|
||||
|
@ -108,80 +108,49 @@ class AutoPtr
|
||||
}
|
||||
};
|
||||
|
||||
// Bob Jenkin's one-at-a-time hash function[1].
|
||||
//
|
||||
// [1] http://burtleburtle.net/bob/hash/doobs.html
|
||||
class CharacterStreamHasher
|
||||
// Wrapper that automatically deletes its contents. The pointer can be taken
|
||||
// to avoid destruction.
|
||||
template <typename T>
|
||||
class AutoArray
|
||||
{
|
||||
uint32 hash;
|
||||
T *t_;
|
||||
|
||||
public:
|
||||
CharacterStreamHasher()
|
||||
: hash(0)
|
||||
{ }
|
||||
|
||||
void add(char c) {
|
||||
hash += c;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
AutoArray()
|
||||
: t_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void add(const char *s, size_t length) {
|
||||
for (size_t i = 0; i < length; i++)
|
||||
add(s[i]);
|
||||
explicit AutoArray(T *t)
|
||||
: t_(t)
|
||||
{
|
||||
}
|
||||
|
||||
uint32 result() {
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return hash;
|
||||
~AutoArray() {
|
||||
delete [] t_;
|
||||
}
|
||||
T *take() {
|
||||
return ReturnAndVoid(t_);
|
||||
}
|
||||
T *operator *() const {
|
||||
return t_;
|
||||
}
|
||||
T &operator [](size_t index) {
|
||||
return t_[index];
|
||||
}
|
||||
const T &operator [](size_t index) const {
|
||||
return t_[index];
|
||||
}
|
||||
operator T *() const {
|
||||
return t_;
|
||||
}
|
||||
void operator =(T *t) {
|
||||
delete [] t_;
|
||||
t_ = t;
|
||||
}
|
||||
bool operator !() const {
|
||||
return !t_;
|
||||
}
|
||||
};
|
||||
|
||||
static inline uint32
|
||||
HashCharSequence(const char *s, size_t length)
|
||||
{
|
||||
CharacterStreamHasher hasher;
|
||||
hasher.add(s, length);
|
||||
return hasher.result();
|
||||
}
|
||||
|
||||
// From http://burtleburtle.net/bob/hash/integer.html
|
||||
static inline uint32
|
||||
HashInt32(int32 a)
|
||||
{
|
||||
a = (a ^ 61) ^ (a >> 16);
|
||||
a = a + (a << 3);
|
||||
a = a ^ (a >> 4);
|
||||
a = a * 0x27d4eb2d;
|
||||
a = a ^ (a >> 15);
|
||||
return a;
|
||||
}
|
||||
|
||||
// From http://www.cris.com/~Ttwang/tech/inthash.htm
|
||||
static inline uint32
|
||||
HashInt64(int64 key)
|
||||
{
|
||||
key = (~key) + (key << 18); // key = (key << 18) - key - 1;
|
||||
key = key ^ (uint64(key) >> 31);
|
||||
key = key * 21; // key = (key + (key << 2)) + (key << 4);
|
||||
key = key ^ (uint64(key) >> 11);
|
||||
key = key + (key << 6);
|
||||
key = key ^ (uint64(key) >> 22);
|
||||
return uint32(key);
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
HashPointer(void *p)
|
||||
{
|
||||
#if defined(KE_32BIT)
|
||||
return HashInt32(reinterpret_cast<int32>(p));
|
||||
#elif defined(KE_64BIT)
|
||||
return HashInt64(reinterpret_cast<int64>(p));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
Log2(size_t number)
|
||||
{
|
||||
@ -317,6 +286,36 @@ Max(const T &t1, const T &t2)
|
||||
return t1 > t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class StorageBuffer
|
||||
{
|
||||
public:
|
||||
T *address() {
|
||||
return reinterpret_cast<T *>(buffer_);
|
||||
}
|
||||
const T *address() const {
|
||||
return reinterpret_cast<const T *>(buffer_);
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
char buffer_[sizeof(T)];
|
||||
uint64_t aligned_;
|
||||
};
|
||||
};
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
# define KE_CXX11
|
||||
#endif
|
||||
|
||||
#if defined(KE_CXX11)
|
||||
# define KE_DELETE delete
|
||||
# define KE_OVERRIDE override
|
||||
#else
|
||||
# define KE_DELETE
|
||||
# define KE_OVERRIDE
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define KE_SIZET_FMT "%Iu"
|
||||
#elif defined(__GNUC__)
|
||||
|
@ -48,8 +48,7 @@ class Vector : public AllocPolicy
|
||||
{
|
||||
}
|
||||
|
||||
~Vector()
|
||||
{
|
||||
~Vector() {
|
||||
zap();
|
||||
}
|
||||
|
||||
@ -124,6 +123,12 @@ class Vector : public AllocPolicy
|
||||
return growIfNeeded(desired - length());
|
||||
}
|
||||
|
||||
private:
|
||||
// These are disallowed because they basically violate the failure handling
|
||||
// model for AllocPolicies and are also likely to have abysmal performance.
|
||||
Vector(const Vector<T> &other) KE_DELETE;
|
||||
Vector &operator =(const Vector<T> &other) KE_DELETE;
|
||||
|
||||
private:
|
||||
void zap() {
|
||||
for (size_t i = 0; i < nitems_; i++)
|
||||
@ -144,16 +149,17 @@ class Vector : public AllocPolicy
|
||||
}
|
||||
if (nitems_ + needed < maxsize_)
|
||||
return true;
|
||||
if (maxsize_ == 0)
|
||||
maxsize_ = 8;
|
||||
while (nitems_ + needed > maxsize_) {
|
||||
if (!IsUintPtrMultiplySafe(maxsize_, 2)) {
|
||||
|
||||
size_t new_maxsize = maxsize_ ? maxsize_ : 8;
|
||||
while (nitems_ + needed > new_maxsize) {
|
||||
if (!IsUintPtrMultiplySafe(new_maxsize, 2)) {
|
||||
this->reportAllocationOverflow();
|
||||
return false;
|
||||
}
|
||||
maxsize_ *= 2;
|
||||
new_maxsize *= 2;
|
||||
}
|
||||
T* newdata = (T*)this->malloc(sizeof(T) * maxsize_);
|
||||
|
||||
T* newdata = (T*)this->malloc(sizeof(T) * new_maxsize);
|
||||
if (newdata == NULL)
|
||||
return false;
|
||||
for (size_t i = 0; i < nitems_; i++) {
|
||||
@ -161,7 +167,9 @@ class Vector : public AllocPolicy
|
||||
data_[i].~T();
|
||||
}
|
||||
this->free(data_);
|
||||
|
||||
data_ = newdata;
|
||||
maxsize_ = new_maxsize;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
#include <am-vector.h>
|
||||
#include <am-inline-list.h>
|
||||
#include <am-inlinelist.h>
|
||||
#include "jit_shared.h"
|
||||
#include "sp_vm_function.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user