Optimized Map<>

This commit is contained in:
Pavel Kirienko 2014-04-09 12:24:27 +04:00
parent 2c9572d845
commit 37f78c9261
2 changed files with 94 additions and 39 deletions

View File

@ -21,9 +21,11 @@ namespace uavcan
* Key's default constructor must initialize the object into invalid state.
* Size of Key + Value + padding must not exceed MemPoolBlockSize.
*/
template <typename Key, typename Value, unsigned NumStaticEntries>
class UAVCAN_EXPORT Map : Noncopyable
template <typename Key, typename Value>
class UAVCAN_EXPORT MapBase : Noncopyable
{
template <typename, typename, unsigned> friend class Map;
UAVCAN_PACKED_BEGIN
struct KVPair
{
@ -84,7 +86,8 @@ class UAVCAN_EXPORT Map : Noncopyable
LinkedListRoot<KVGroup> list_;
IAllocator& allocator_;
KVPair static_[NumStaticEntries];
KVPair* const static_;
const unsigned num_static_entries_;
KVPair* find(const Key& key);
@ -97,19 +100,19 @@ class UAVCAN_EXPORT Map : Noncopyable
bool operator()(const Key& k, const Value& v) const { (void)k; (void)v; return true; }
};
// This container is not copyable
Map(const Map&);
bool operator=(const Map&);
protected:
/// Derived class destructor must call removeAll();
~MapBase() { }
public:
Map(IAllocator& allocator)
MapBase(KVPair* static_buf, unsigned num_static_entries, IAllocator& allocator)
: allocator_(allocator)
, static_(static_buf)
, num_static_entries_(num_static_entries)
{
assert(Key() == Key());
}
~Map() { removeAll(); }
Value* access(const Key& key);
/// If entry with the same key already exists, it will be replaced
@ -139,15 +142,41 @@ public:
unsigned getNumDynamicPairs() const;
};
template <typename Key, typename Value, unsigned NumStaticEntries = 0>
class UAVCAN_EXPORT Map : public MapBase<Key, Value>
{
typename MapBase<Key, Value>::KVPair static_[NumStaticEntries];
public:
Map(IAllocator& allocator)
: MapBase<Key, Value>(static_, NumStaticEntries, allocator)
{ }
~Map() { this->removeAll(); }
};
template <typename Key, typename Value>
class UAVCAN_EXPORT Map<Key, Value, 0> : public MapBase<Key, Value>
{
public:
Map(IAllocator& allocator)
: MapBase<Key, Value>(NULL, 0, allocator)
{ }
~Map() { this->removeAll(); }
};
// ----------------------------------------------------------------------------
/*
* Map<>
* MapBase<>
*/
template <typename Key, typename Value, unsigned NumStaticEntries>
typename Map<Key, Value, NumStaticEntries>::KVPair* Map<Key, Value, NumStaticEntries>::find(const Key& key)
template <typename Key, typename Value>
typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::find(const Key& key)
{
for (unsigned i = 0; i < NumStaticEntries; i++)
for (unsigned i = 0; i < num_static_entries_; i++)
{
if (static_[i].match(key))
{
@ -168,14 +197,14 @@ typename Map<Key, Value, NumStaticEntries>::KVPair* Map<Key, Value, NumStaticEnt
return NULL;
}
template <typename Key, typename Value, unsigned NumStaticEntries>
void Map<Key, Value, NumStaticEntries>::optimizeStorage()
template <typename Key, typename Value>
void MapBase<Key, Value>::optimizeStorage()
{
while (true)
{
// Looking for first EMPTY static entry
KVPair* stat = NULL;
for (unsigned i = 0; i < NumStaticEntries; i++)
for (unsigned i = 0; i < num_static_entries_; i++)
{
if (static_[i].match(Key()))
{
@ -220,8 +249,8 @@ void Map<Key, Value, NumStaticEntries>::optimizeStorage()
}
}
template <typename Key, typename Value, unsigned NumStaticEntries>
void Map<Key, Value, NumStaticEntries>::compact()
template <typename Key, typename Value>
void MapBase<Key, Value>::compact()
{
KVGroup* p = list_.get();
while (p)
@ -245,16 +274,16 @@ void Map<Key, Value, NumStaticEntries>::compact()
}
}
template <typename Key, typename Value, unsigned NumStaticEntries>
Value* Map<Key, Value, NumStaticEntries>::access(const Key& key)
template <typename Key, typename Value>
Value* MapBase<Key, Value>::access(const Key& key)
{
assert(!(key == Key()));
KVPair* const kv = find(key);
return kv ? &kv->value : NULL;
}
template <typename Key, typename Value, unsigned NumStaticEntries>
Value* Map<Key, Value, NumStaticEntries>::insert(const Key& key, const Value& value)
template <typename Key, typename Value>
Value* MapBase<Key, Value>::insert(const Key& key, const Value& value)
{
assert(!(key == Key()));
remove(key);
@ -276,8 +305,8 @@ Value* Map<Key, Value, NumStaticEntries>::insert(const Key& key, const Value& va
return &kvg->kvs[0].value;
}
template <typename Key, typename Value, unsigned NumStaticEntries>
void Map<Key, Value, NumStaticEntries>::remove(const Key& key)
template <typename Key, typename Value>
void MapBase<Key, Value>::remove(const Key& key)
{
assert(!(key == Key()));
KVPair* const kv = find(key);
@ -289,13 +318,13 @@ void Map<Key, Value, NumStaticEntries>::remove(const Key& key)
}
}
template <typename Key, typename Value, unsigned NumStaticEntries>
template <typename Key, typename Value>
template <typename Predicate>
void Map<Key, Value, NumStaticEntries>::removeWhere(Predicate predicate)
void MapBase<Key, Value>::removeWhere(Predicate predicate)
{
unsigned num_removed = 0;
for (unsigned i = 0; i < NumStaticEntries; i++)
for (unsigned i = 0; i < num_static_entries_; i++)
{
if (!static_[i].match(Key()))
{
@ -332,11 +361,11 @@ void Map<Key, Value, NumStaticEntries>::removeWhere(Predicate predicate)
}
}
template <typename Key, typename Value, unsigned NumStaticEntries>
template <typename Key, typename Value>
template <typename Predicate>
const Key* Map<Key, Value, NumStaticEntries>::findFirstKey(Predicate predicate) const
const Key* MapBase<Key, Value>::findFirstKey(Predicate predicate) const
{
for (unsigned i = 0; i < NumStaticEntries; i++)
for (unsigned i = 0; i < num_static_entries_; i++)
{
if (!static_[i].match(Key()))
{
@ -366,23 +395,23 @@ const Key* Map<Key, Value, NumStaticEntries>::findFirstKey(Predicate predicate)
return NULL;
}
template <typename Key, typename Value, unsigned NumStaticEntries>
void Map<Key, Value, NumStaticEntries>::removeAll()
template <typename Key, typename Value>
void MapBase<Key, Value>::removeAll()
{
removeWhere(YesPredicate());
}
template <typename Key, typename Value, unsigned NumStaticEntries>
bool Map<Key, Value, NumStaticEntries>::isEmpty() const
template <typename Key, typename Value>
bool MapBase<Key, Value>::isEmpty() const
{
return (getNumStaticPairs() == 0) && (getNumDynamicPairs() == 0);
}
template <typename Key, typename Value, unsigned NumStaticEntries>
unsigned Map<Key, Value, NumStaticEntries>::getNumStaticPairs() const
template <typename Key, typename Value>
unsigned MapBase<Key, Value>::getNumStaticPairs() const
{
unsigned num = 0;
for (unsigned i = 0; i < NumStaticEntries; i++)
for (unsigned i = 0; i < num_static_entries_; i++)
{
if (!static_[i].match(Key()))
{
@ -392,8 +421,8 @@ unsigned Map<Key, Value, NumStaticEntries>::getNumStaticPairs() const
return num;
}
template <typename Key, typename Value, unsigned NumStaticEntries>
unsigned Map<Key, Value, NumStaticEntries>::getNumDynamicPairs() const
template <typename Key, typename Value>
unsigned MapBase<Key, Value>::getNumDynamicPairs() const
{
unsigned num = 0;
KVGroup* p = list_.get();

View File

@ -180,3 +180,29 @@ TEST(Map, Basic)
map.reset();
ASSERT_EQ(0, pool.getNumUsedBlocks());
}
TEST(Map, NoStatic)
{
using uavcan::Map;
static const int POOL_BLOCKS = 3;
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
typedef Map<std::string, std::string> MapType;
std::auto_ptr<MapType> map(new MapType(poolmgr));
// Empty
ASSERT_FALSE(map->access("hi"));
map->remove("foo");
ASSERT_EQ(0, pool.getNumUsedBlocks());
// Static insertion
ASSERT_EQ("a", *map->insert("1", "a"));
ASSERT_EQ("b", *map->insert("2", "b"));
ASSERT_EQ(1, pool.getNumUsedBlocks());
ASSERT_EQ(0, map->getNumStaticPairs());
ASSERT_EQ(2, map->getNumDynamicPairs());
}