Refactor Trie natives to use HashMap instead of KTrie; add iteration API (bug 5892, r=ds).
--HG-- extra : rebase_source : a5bcf64a45d6734a97d78b4f4ea9aea48d17bb8b
This commit is contained in:
@@ -60,12 +60,28 @@ class HashMap : public AllocPolicy
|
||||
Entry()
|
||||
{
|
||||
}
|
||||
Entry(Moveable<Entry> other)
|
||||
: key(Moveable<K>(other->key)),
|
||||
value(Moveable<V>(other->value))
|
||||
{
|
||||
}
|
||||
|
||||
Entry(const K &aKey, const V &aValue)
|
||||
: key(aKey),
|
||||
value(aValue)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
Entry(const K &aKey, Moveable<V> aValue)
|
||||
: key(aKey),
|
||||
value(aValue)
|
||||
{ }
|
||||
Entry(Moveable<K> aKey, const V &aValue)
|
||||
: key(aKey),
|
||||
value(aValue)
|
||||
{ }
|
||||
Entry(Moveable<K> aKey, Moveable<V> aValue)
|
||||
: key(aKey),
|
||||
value(aValue)
|
||||
{ }
|
||||
};
|
||||
|
||||
struct Policy
|
||||
@@ -124,6 +140,18 @@ class HashMap : public AllocPolicy
|
||||
bool add(Insert &i, const K &key, const V &value) {
|
||||
return table_.add(i, Entry(key, value));
|
||||
}
|
||||
bool add(Insert &i, Moveable<K> key, const V &value) {
|
||||
return table_.add(i, Entry(key, value));
|
||||
}
|
||||
bool add(Insert &i, const K &key, Moveable<V> value) {
|
||||
return table_.add(i, Entry(key, value));
|
||||
}
|
||||
bool add(Insert &i, Moveable<K> key, Moveable<V> value) {
|
||||
return table_.add(i, Entry(key, value));
|
||||
}
|
||||
bool add(Insert &i, Moveable<K> key) {
|
||||
return table_.add(i, Entry(key, V()));
|
||||
}
|
||||
|
||||
// This can be used to avoid compiler constructed temporaries, since AMTL
|
||||
// does not yet support move semantics. If you use this, the key and value
|
||||
@@ -140,6 +168,10 @@ class HashMap : public AllocPolicy
|
||||
table_.clear();
|
||||
}
|
||||
|
||||
size_t elements() const {
|
||||
return table_.elements();
|
||||
}
|
||||
|
||||
size_t estimateMemoryUse() const {
|
||||
return table_.estimateMemoryUse();
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "am-allocator-policies.h"
|
||||
#include "am-utility.h"
|
||||
#include "am-moveable.h"
|
||||
|
||||
namespace ke {
|
||||
|
||||
@@ -50,8 +51,16 @@ namespace detail {
|
||||
static const uint32_t kRemovedHash = 1;
|
||||
|
||||
public:
|
||||
void setHash(uint32_t hash, const T &t) {
|
||||
void setHash(uint32_t hash) {
|
||||
hash_ = hash;
|
||||
}
|
||||
void construct() {
|
||||
new (&t_) T();
|
||||
}
|
||||
void construct(const T &t) {
|
||||
new (&t_) T(t);
|
||||
}
|
||||
void construct(Moveable<T> t) {
|
||||
new (&t_) T(t);
|
||||
}
|
||||
uint32_t hash() const {
|
||||
@@ -257,7 +266,8 @@ class HashTable : public AllocPolicy
|
||||
Entry &oldEntry = oldTable[i];
|
||||
if (oldEntry.isLive()) {
|
||||
Insert p = insertUnique(oldEntry.hash());
|
||||
p.entry().setHash(p.hash(), oldEntry.payload());
|
||||
p.entry().setHash(p.hash());
|
||||
p.entry().construct(Moveable<Payload>(oldEntry.payload()));
|
||||
}
|
||||
oldEntry.destruct();
|
||||
}
|
||||
@@ -290,8 +300,8 @@ class HashTable : public AllocPolicy
|
||||
if (e->free())
|
||||
break;
|
||||
if (e->isLive() &&
|
||||
e->sameHash(hash) &&
|
||||
HashPolicy::matches(key, e->payload()))
|
||||
e->sameHash(hash) &&
|
||||
HashPolicy::matches(key, e->payload()))
|
||||
{
|
||||
return Result(e);
|
||||
}
|
||||
@@ -318,7 +328,7 @@ class HashTable : public AllocPolicy
|
||||
return Insert(e, hash);
|
||||
}
|
||||
|
||||
bool internalAdd(Insert &i, const Payload &payload) {
|
||||
bool internalAdd(Insert &i) {
|
||||
assert(!i.found());
|
||||
|
||||
// If the entry is deleted, just re-use the slot.
|
||||
@@ -345,8 +355,8 @@ class HashTable : public AllocPolicy
|
||||
i = insertUnique(i.hash());
|
||||
}
|
||||
|
||||
i.entry().setHash(i.hash(), payload);
|
||||
nelements_++;
|
||||
i.entry().setHash(i.hash());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -423,10 +433,22 @@ class HashTable : public AllocPolicy
|
||||
// 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);
|
||||
if (!internalAdd(i))
|
||||
return false;
|
||||
i.entry().construct(payload);
|
||||
return true;
|
||||
}
|
||||
bool add(Insert &i, Moveable<Payload> payload) {
|
||||
if (!internalAdd(i))
|
||||
return false;
|
||||
i.entry().construct(payload);
|
||||
return true;
|
||||
}
|
||||
bool add(Insert &i) {
|
||||
return internalAdd(i, Payload());
|
||||
if (!internalAdd(i))
|
||||
return false;
|
||||
i.entry().construct();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkDensity() {
|
||||
@@ -445,6 +467,10 @@ class HashTable : public AllocPolicy
|
||||
nelements_ = 0;
|
||||
}
|
||||
|
||||
size_t elements() const {
|
||||
return nelements_;
|
||||
}
|
||||
|
||||
size_t estimateMemoryUse() const {
|
||||
return sizeof(Entry) * capacity_;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// 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_moveable_h_
|
||||
#define _include_amtl_moveable_h_
|
||||
|
||||
namespace ke {
|
||||
|
||||
// This is a feature in C++11, but since AM projects do not have access to
|
||||
// C++11 yet, we provide templates to implement move semantics. A class can
|
||||
// provide a constructor for (ke::Moveable<T> t) which containers will try
|
||||
// to use.
|
||||
//
|
||||
// When implementing a constructor that takes a Moveable, the object being
|
||||
// moved should be left in a state that is safe, since its destructor will
|
||||
// be called even though it has been moved.
|
||||
|
||||
template <typename T>
|
||||
struct Moveable
|
||||
{
|
||||
public:
|
||||
explicit Moveable(T &t)
|
||||
: t_(t)
|
||||
{
|
||||
}
|
||||
|
||||
T *operator ->() {
|
||||
return &t_;
|
||||
}
|
||||
operator T &() {
|
||||
return t_;
|
||||
}
|
||||
|
||||
private:
|
||||
T &t_;
|
||||
};
|
||||
|
||||
} // namespace ke
|
||||
|
||||
#endif // _include_amtl_moveable_h_
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <am-utility.h>
|
||||
#include <am-moveable.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
@@ -54,6 +55,12 @@ class AString
|
||||
if (other.length_)
|
||||
set(other.chars_, other.length_);
|
||||
}
|
||||
AString(Moveable<AString> other)
|
||||
: chars_(other->chars_.take()),
|
||||
length_(other->length_)
|
||||
{
|
||||
other->length_ = 0;
|
||||
}
|
||||
|
||||
AString &operator =(const char *str) {
|
||||
if (str && str[0]) {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <am-allocator-policies.h>
|
||||
#include <am-utility.h>
|
||||
#include <am-moveable.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
@@ -163,7 +164,7 @@ class Vector : public AllocPolicy
|
||||
if (newdata == NULL)
|
||||
return false;
|
||||
for (size_t i = 0; i < nitems_; i++) {
|
||||
new (&newdata[i]) T(data_[i]);
|
||||
new (&newdata[i]) T(Moveable<T>(data_[i]));
|
||||
data_[i].~T();
|
||||
}
|
||||
this->free(data_);
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <am-allocator-policies.h>
|
||||
#include <am-hashmap.h>
|
||||
#include <am-string.h>
|
||||
#include <am-moveable.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace SourceMod
|
||||
@@ -113,6 +114,7 @@ public:
|
||||
}
|
||||
|
||||
typedef typename Internal::Result Result;
|
||||
typedef typename Internal::Insert Insert;
|
||||
typedef typename Internal::iterator iterator;
|
||||
|
||||
// Some KTrie-like helper functions.
|
||||
@@ -143,7 +145,7 @@ public:
|
||||
bool replace(const char *aKey, const T &value)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
typename Internal::Insert i = internal_.findForAdd(key);
|
||||
Insert i = internal_.findForAdd(key);
|
||||
if (!i.found())
|
||||
{
|
||||
memory_used_ += key.length() + 1;
|
||||
@@ -158,7 +160,7 @@ public:
|
||||
bool insert(const char *aKey, const T &value)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
typename Internal::Insert i = internal_.findForAdd(key);
|
||||
Insert i = internal_.findForAdd(key);
|
||||
if (i.found())
|
||||
return false;
|
||||
if (!internal_.add(i))
|
||||
@@ -190,14 +192,45 @@ public:
|
||||
internal_.clear();
|
||||
}
|
||||
|
||||
iterator iter() {
|
||||
iterator iter()
|
||||
{
|
||||
return internal_.iter();
|
||||
}
|
||||
|
||||
size_t mem_usage() const {
|
||||
size_t mem_usage() const
|
||||
{
|
||||
return internal_.estimateMemoryUse() + memory_used_;
|
||||
}
|
||||
|
||||
size_t elements() const
|
||||
{
|
||||
return internal_.elements();
|
||||
}
|
||||
|
||||
|
||||
Insert findForAdd(const char *aKey)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
return internal_.findForAdd(key);
|
||||
}
|
||||
|
||||
// Note that |i->key| must be set after calling this, and the key must
|
||||
// be the same as used with findForAdd(). It is best to avoid these two
|
||||
// functions as the combined variants above are safer.
|
||||
bool add(Insert &i)
|
||||
{
|
||||
return internal_.add(i);
|
||||
}
|
||||
|
||||
// Only value needs to be set after.
|
||||
bool add(Insert &i, const char *aKey)
|
||||
{
|
||||
if (!internal_.add(i))
|
||||
return false;
|
||||
i->key = aKey;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Internal internal_;
|
||||
size_t memory_used_;
|
||||
|
||||
Reference in New Issue
Block a user