mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-15 15:16:49 +02:00
multimap-like functionality
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
|
||||
|
||||
#include "Poco/Foundation.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <list>
|
||||
#include <utility>
|
||||
@@ -49,17 +50,15 @@
|
||||
namespace Poco {
|
||||
|
||||
|
||||
template <class Key, class Mapped, class Container = std::list<std::pair<Key, Mapped> > >
|
||||
template <class Key, class Mapped, class Container = std::list<std::pair<Key, Mapped> >, bool CaseSensitive = false >
|
||||
class ListMap
|
||||
/// This class implements a map in terms of a sequential container.
|
||||
/// This class implements a multimap in terms of a sequential container.
|
||||
/// The use for this type of associative container is wherever automatic
|
||||
/// ordering of elements is not desirable. Naturally, this container will
|
||||
/// have inferior data retrieval perofrmance and it is not recommended for
|
||||
/// have inferior data retrieval performance and it is not recommended for
|
||||
/// use with large datasets. The main purpose within POCO is for Internet
|
||||
/// messages (email in particular), in order to prevent autmomatic header
|
||||
/// reordering.
|
||||
///
|
||||
/// A ListMap can be used just like a std::map.
|
||||
/// messages (email message, http headers etc), to prevent autmomatic
|
||||
/// header entry reordering.
|
||||
{
|
||||
public:
|
||||
typedef Key KeyType;
|
||||
@@ -100,26 +99,34 @@ public:
|
||||
}
|
||||
|
||||
ConstIterator begin() const
|
||||
/// Returns the beginning of the map.
|
||||
{
|
||||
return _list.begin();
|
||||
}
|
||||
|
||||
ConstIterator end() const
|
||||
/// Returns the end of the map.
|
||||
{
|
||||
return _list.end();
|
||||
}
|
||||
|
||||
Iterator begin()
|
||||
/// Returns the beginning of the map.
|
||||
{
|
||||
return _list.begin();
|
||||
}
|
||||
|
||||
Iterator end()
|
||||
/// Returns the end of the map.
|
||||
{
|
||||
return _list.end();
|
||||
}
|
||||
|
||||
ConstIterator find(const KeyType& key) const
|
||||
/// Finds the first occurence of the key and
|
||||
/// returns iterator pointing to the found entry
|
||||
/// or iterator pointing to the end if entry is
|
||||
/// not found.
|
||||
{
|
||||
Container::const_iterator it = _list.begin();
|
||||
Container::const_iterator end = _list.end();
|
||||
@@ -131,6 +138,10 @@ public:
|
||||
}
|
||||
|
||||
Iterator find(const KeyType& key)
|
||||
/// Finds the first occurence of the key and
|
||||
/// returns iterator pointing to the found entry
|
||||
/// or iterator pointing to the end if entry is
|
||||
/// not found.
|
||||
{
|
||||
Container::iterator it = _list.begin();
|
||||
Container::iterator end = _list.end();
|
||||
@@ -141,12 +152,27 @@ public:
|
||||
return end;
|
||||
}
|
||||
|
||||
std::pair<Iterator, bool> insert(const ValueType& val)
|
||||
Iterator insert(const ValueType& val)
|
||||
/// Inserts the value into the map. If one or more values
|
||||
/// already exist, new value is inserted at the end of the
|
||||
/// block. Thus, all the equal value entries are located
|
||||
/// sequentially at all times.
|
||||
/// Returns iterator pointing to the newly inserted value
|
||||
{
|
||||
_list.push_back(val);
|
||||
Iterator it = _list.end();
|
||||
std::pair<Iterator, bool> p(--it, true);
|
||||
return p;
|
||||
Iterator it = find(val.first);
|
||||
|
||||
if (it == _list.end())
|
||||
{
|
||||
_list.push_back(val);
|
||||
it = _list.end();
|
||||
--it;
|
||||
}
|
||||
else
|
||||
{
|
||||
_list.insert(it, 1, val);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
void erase(Iterator it)
|
||||
@@ -158,10 +184,20 @@ public:
|
||||
{
|
||||
SizeType count = 0;
|
||||
Iterator it = find(key);
|
||||
bool removed = false;
|
||||
while (it != _list.end())
|
||||
{
|
||||
++count;
|
||||
it = _list.erase(it);
|
||||
if (isEqual(it->first, key))
|
||||
{
|
||||
++count;
|
||||
it = _list.erase(it);
|
||||
removed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (removed) return count;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -197,8 +233,8 @@ public:
|
||||
return it->second;
|
||||
else
|
||||
{
|
||||
_list.push_back(ValueType(key, KeyType()));
|
||||
it = find(key);
|
||||
ValueType value(key, Mapped());
|
||||
Iterator it = insert(value);
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
@@ -210,10 +246,27 @@ private:
|
||||
return val1 == val2;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool isEqual(const std::string& s1, const std::string& s2) const
|
||||
{
|
||||
return Poco::icompare(s1, s2) == 0;
|
||||
if (!CaseSensitive)
|
||||
return Poco::icompare(s1, s2) == 0;
|
||||
else
|
||||
return s1 == s2;
|
||||
}
|
||||
|
||||
bool isEqual(const std::string& s1, const char* s2) const
|
||||
{
|
||||
return isEqual(s1, std::string(s2));
|
||||
}
|
||||
|
||||
bool isEqual(const char* s1, const std::string& s2) const
|
||||
{
|
||||
return isEqual(std::string(s1), s2);
|
||||
}
|
||||
|
||||
bool isEqual(const char* s1, const char* s2) const
|
||||
{
|
||||
return isEqual(std::string(s1), std::string(s2));
|
||||
}
|
||||
|
||||
Container _list;
|
||||
|
@@ -62,10 +62,9 @@ void ListMapTest::testInsert()
|
||||
|
||||
for (int i = 0; i < N; ++i)
|
||||
{
|
||||
std::pair<IntMap::Iterator, bool> res = hm.insert(IntMap::ValueType(i, i*2));
|
||||
assert (res.first->first == i);
|
||||
assert (res.first->second == i*2);
|
||||
assert (res.second);
|
||||
IntMap::Iterator res = hm.insert(IntMap::ValueType(i, i*2));
|
||||
assert (res->first == i);
|
||||
assert (res->second == i*2);
|
||||
IntMap::Iterator it = hm.find(i);
|
||||
assert (it != hm.end());
|
||||
assert (it->first == i);
|
||||
@@ -83,11 +82,12 @@ void ListMapTest::testInsert()
|
||||
assert (it->second == i*2);
|
||||
}
|
||||
|
||||
hm.clear();
|
||||
for (int i = 0; i < N; ++i)
|
||||
{
|
||||
std::pair<IntMap::Iterator, bool> res = hm.insert(IntMap::ValueType(i, 0));
|
||||
assert (res.first->first == i);
|
||||
assert (res.first->second == 0);
|
||||
IntMap::Iterator res = hm.insert(IntMap::ValueType(i, 0));
|
||||
assert (res->first == i);
|
||||
assert (res->second == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ void ListMapTest::testConstIterator()
|
||||
}
|
||||
|
||||
|
||||
void ListMapTest::testIndex()
|
||||
void ListMapTest::testIntIndex()
|
||||
{
|
||||
typedef ListMap<int, int> IntMap;
|
||||
IntMap hm;
|
||||
@@ -218,6 +218,32 @@ void ListMapTest::testIndex()
|
||||
}
|
||||
|
||||
|
||||
void ListMapTest::testStringIndex()
|
||||
{
|
||||
typedef ListMap<const char*, std::string> StringMap;
|
||||
StringMap hm;
|
||||
|
||||
hm["index1"] = "value2";
|
||||
hm["index2"] = "value4";
|
||||
hm["index3"] = "value6";
|
||||
|
||||
assert (hm.size() == 3);
|
||||
assert (hm["index1"] == "value2");
|
||||
assert (hm["Index2"] == "value4");
|
||||
assert (hm["inDeX3"] == "value6");
|
||||
|
||||
try
|
||||
{
|
||||
const StringMap& im = hm;
|
||||
std::string x = im["index4"];
|
||||
fail("no such key - must throw");
|
||||
}
|
||||
catch (Poco::NotFoundException&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ListMapTest::setUp()
|
||||
{
|
||||
}
|
||||
@@ -236,7 +262,8 @@ CppUnit::Test* ListMapTest::suite()
|
||||
CppUnit_addTest(pSuite, ListMapTest, testErase);
|
||||
CppUnit_addTest(pSuite, ListMapTest, testIterator);
|
||||
CppUnit_addTest(pSuite, ListMapTest, testConstIterator);
|
||||
CppUnit_addTest(pSuite, ListMapTest, testIndex);
|
||||
CppUnit_addTest(pSuite, ListMapTest, testIntIndex);
|
||||
CppUnit_addTest(pSuite, ListMapTest, testStringIndex);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@@ -50,7 +50,8 @@ public:
|
||||
void testErase();
|
||||
void testIterator();
|
||||
void testConstIterator();
|
||||
void testIndex();
|
||||
void testIntIndex();
|
||||
void testStringIndex();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
Reference in New Issue
Block a user