Map<>::getByIndex()

This commit is contained in:
Pavel Kirienko
2015-03-23 04:27:59 +03:00
parent 2d7e20b885
commit ab4c5f54a6
2 changed files with 94 additions and 5 deletions
+66 -4
View File
@@ -36,6 +36,7 @@ class UAVCAN_EXPORT MapBase : Noncopyable
template <typename, typename, unsigned> friend class Map;
UAVCAN_PACKED_BEGIN
public:
struct KVPair
{
Key key;
@@ -48,6 +49,7 @@ class UAVCAN_EXPORT MapBase : Noncopyable
bool match(const Key& rhs) const { return rhs == key; }
};
private:
struct KVGroup : LinkedListNode<KVGroup>
{
enum { NumKV = (MemPoolBlockSize - sizeof(LinkedListNode<KVGroup>)) / sizeof(KVPair) };
@@ -166,12 +168,22 @@ public:
void removeAll();
/**
* Returns a key-value pair located at the specified position from the beginning.
* Note that any insertion or deletion may greatly disturb internal ordering, so use with care.
* If index is greater than or equal the number of pairs, null pointer will be returned.
*/
KVPair* getByIndex(unsigned index);
const KVPair* getByIndex(unsigned index) const;
bool isEmpty() const;
/// For testing
unsigned getNumStaticPairs() const;
unsigned getSize() const;
/// For testing
/**
* For testing, do not use directly.
*/
unsigned getNumStaticPairs() const;
unsigned getNumDynamicPairs() const;
};
@@ -458,10 +470,60 @@ void MapBase<Key, Value>::removeAll()
removeWhere(YesPredicate());
}
template <typename Key, typename Value>
typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::getByIndex(unsigned index)
{
// Checking the static storage
for (unsigned i = 0; i < num_static_entries_; i++)
{
if (!static_[i].match(Key()))
{
if (index == 0)
{
return static_ + i;
}
index--;
}
}
// Slowly crawling through the dynamic storage
KVGroup* p = list_.get();
while (p)
{
for (int i = 0; i < KVGroup::NumKV; i++)
{
KVPair* const kv = p->kvs + i;
if (!kv->match(Key()))
{
if (index == 0)
{
return kv;
}
index--;
}
}
p = p->getNextListNode();
}
return NULL;
}
template <typename Key, typename Value>
const typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::getByIndex(unsigned index) const
{
return const_cast<MapBase<Key, Value>*>(this)->getByIndex(index);
}
template <typename Key, typename Value>
bool MapBase<Key, Value>::isEmpty() const
{
return (getNumStaticPairs() == 0) && (getNumDynamicPairs() == 0);
return getSize() == 0;
}
template <typename Key, typename Value>
unsigned MapBase<Key, Value>::getSize() const
{
return getNumStaticPairs() + getNumDynamicPairs();
}
template <typename Key, typename Value>
+28 -1
View File
@@ -55,6 +55,9 @@ TEST(Map, Basic)
ASSERT_FALSE(map->access("hi"));
map->remove("foo");
ASSERT_EQ(0, pool.getNumUsedBlocks());
ASSERT_FALSE(map->getByIndex(0));
ASSERT_FALSE(map->getByIndex(1));
ASSERT_FALSE(map->getByIndex(10000));
// Static insertion
ASSERT_EQ("a", *map->insert("1", "a"));
@@ -63,6 +66,10 @@ TEST(Map, Basic)
ASSERT_EQ(2, map->getNumStaticPairs());
ASSERT_EQ(0, map->getNumDynamicPairs());
// Ordering
ASSERT_TRUE(map->getByIndex(0)->match("1"));
ASSERT_TRUE(map->getByIndex(1)->match("2"));
// Dynamic insertion
ASSERT_EQ("c", *map->insert("3", "c"));
ASSERT_EQ(1, pool.getNumUsedBlocks());
@@ -79,6 +86,14 @@ TEST(Map, Basic)
ASSERT_EQ("d", *map->access("4"));
ASSERT_FALSE(map->access("hi"));
// Ordering
ASSERT_TRUE(map->getByIndex(0)->match("1"));
ASSERT_TRUE(map->getByIndex(1)->match("2"));
ASSERT_TRUE(map->getByIndex(2)->match("3"));
ASSERT_TRUE(map->getByIndex(3)->match("4"));
ASSERT_FALSE(map->getByIndex(4));
ASSERT_FALSE(map->getByIndex(1000));
// Modifying existing entries
*map->access("1") = "A";
*map->access("2") = "B";
@@ -115,6 +130,11 @@ TEST(Map, Basic)
ASSERT_EQ("C", *map->access("3"));
ASSERT_EQ("D", *map->access("4"));
// Ordering has not changed - first dynamic entry has moved to the first static slot
ASSERT_TRUE(map->getByIndex(0)->match("3"));
ASSERT_TRUE(map->getByIndex(1)->match("2"));
ASSERT_TRUE(map->getByIndex(2)->match("4"));
// Removing another static
map->remove("2");
ASSERT_EQ(2, map->getNumStaticPairs());
@@ -198,11 +218,18 @@ TEST(Map, NoStatic)
ASSERT_FALSE(map->access("hi"));
map->remove("foo");
ASSERT_EQ(0, pool.getNumUsedBlocks());
ASSERT_FALSE(map->getByIndex(0));
// Static insertion
// 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());
// Ordering
ASSERT_TRUE(map->getByIndex(0)->match("1"));
ASSERT_TRUE(map->getByIndex(1)->match("2"));
ASSERT_FALSE(map->getByIndex(3));
ASSERT_FALSE(map->getByIndex(1000));
}