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:
David Anderson
2013-08-29 10:09:02 -07:00
parent 88fdec6dd5
commit b261dde858
11 changed files with 758 additions and 250 deletions
+34 -2
View File
@@ -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();
}
+34 -8
View File
@@ -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_;
}
+66
View File
@@ -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_
+7
View File
@@ -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]) {
+2 -1
View File
@@ -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_);
+37 -4
View File
@@ -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_;