mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-26 23:13:35 +08:00
Optimized Map<>
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user