diff --git a/libuavcan/include/uavcan/map.hpp b/libuavcan/include/uavcan/map.hpp index fe929678d7..91d3fa7626 100644 --- a/libuavcan/include/uavcan/map.hpp +++ b/libuavcan/include/uavcan/map.hpp @@ -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 -class UAVCAN_EXPORT Map : Noncopyable +template +class UAVCAN_EXPORT MapBase : Noncopyable { + template friend class Map; + UAVCAN_PACKED_BEGIN struct KVPair { @@ -84,7 +86,8 @@ class UAVCAN_EXPORT Map : Noncopyable LinkedListRoot 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 +class UAVCAN_EXPORT Map : public MapBase +{ + typename MapBase::KVPair static_[NumStaticEntries]; + +public: + Map(IAllocator& allocator) + : MapBase(static_, NumStaticEntries, allocator) + { } + + ~Map() { this->removeAll(); } +}; + + +template +class UAVCAN_EXPORT Map : public MapBase +{ +public: + Map(IAllocator& allocator) + : MapBase(NULL, 0, allocator) + { } + + ~Map() { this->removeAll(); } +}; + // ---------------------------------------------------------------------------- /* - * Map<> + * MapBase<> */ -template -typename Map::KVPair* Map::find(const Key& key) +template +typename MapBase::KVPair* MapBase::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::KVPair* Map -void Map::optimizeStorage() +template +void MapBase::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::optimizeStorage() } } -template -void Map::compact() +template +void MapBase::compact() { KVGroup* p = list_.get(); while (p) @@ -245,16 +274,16 @@ void Map::compact() } } -template -Value* Map::access(const Key& key) +template +Value* MapBase::access(const Key& key) { assert(!(key == Key())); KVPair* const kv = find(key); return kv ? &kv->value : NULL; } -template -Value* Map::insert(const Key& key, const Value& value) +template +Value* MapBase::insert(const Key& key, const Value& value) { assert(!(key == Key())); remove(key); @@ -276,8 +305,8 @@ Value* Map::insert(const Key& key, const Value& va return &kvg->kvs[0].value; } -template -void Map::remove(const Key& key) +template +void MapBase::remove(const Key& key) { assert(!(key == Key())); KVPair* const kv = find(key); @@ -289,13 +318,13 @@ void Map::remove(const Key& key) } } -template +template template -void Map::removeWhere(Predicate predicate) +void MapBase::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::removeWhere(Predicate predicate) } } -template +template template -const Key* Map::findFirstKey(Predicate predicate) const +const Key* MapBase::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::findFirstKey(Predicate predicate) return NULL; } -template -void Map::removeAll() +template +void MapBase::removeAll() { removeWhere(YesPredicate()); } -template -bool Map::isEmpty() const +template +bool MapBase::isEmpty() const { return (getNumStaticPairs() == 0) && (getNumDynamicPairs() == 0); } -template -unsigned Map::getNumStaticPairs() const +template +unsigned MapBase::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::getNumStaticPairs() const return num; } -template -unsigned Map::getNumDynamicPairs() const +template +unsigned MapBase::getNumDynamicPairs() const { unsigned num = 0; KVGroup* p = list_.get(); diff --git a/libuavcan/test/map.cpp b/libuavcan/test/map.cpp index 7577e3f5de..38fdfebebc 100644 --- a/libuavcan/test/map.cpp +++ b/libuavcan/test/map.cpp @@ -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 pool; + uavcan::PoolManager<2> poolmgr; + poolmgr.addPool(&pool); + + typedef Map MapType; + std::auto_ptr 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()); +}