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