// // ListMap.h // // Library: Foundation // Package: Core // Module: ListMap // // Definition of the ListMap class. // // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // #ifndef Foundation_ListMap_INCLUDED #define Foundation_ListMap_INCLUDED #include "Poco/Foundation.h" #include "Poco/String.h" #include "Poco/Exception.h" #include #include namespace Poco { template >, bool CaseSensitive = false> class ListMap /// 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 performance and it is not recommended for /// use with large datasets. The main purpose within POCO is for Internet /// messages (email message, http headers etc), to prevent automatic /// header entry reordering. { public: using KeyType = Key; using MappedType = Mapped; using Reference = Mapped&; using ConstReference = const Mapped&; using Pointer = Mapped*; using ConstPointer = const Mapped*; using ValueType = typename Container::value_type; using SizeType = typename Container::size_type; using Iterator = typename Container::iterator; using ConstIterator = typename Container::const_iterator; ListMap() /// Creates an empty ListMap. { } explicit ListMap(std::size_t initialReserve): _container(initialReserve) /// Creates the ListMap with room for initialReserve entries. { } ListMap(const ListMap& other): _container(other._container) { } ListMap(ListMap&& other) noexcept: _container(std::move(other._container)) { } ListMap& operator = (const ListMap& map) /// Assigns another ListMap. { ListMap tmp(map); swap(tmp); return *this; } ListMap& operator = (ListMap&& map) noexcept /// Assigns another ListMap. { _container = std::move(map._container); return *this; } void swap(ListMap& map) /// Swaps the ListMap with another one. { _container.swap(map._container); } ConstIterator begin() const /// Returns the beginning of the map. { return _container.begin(); } ConstIterator end() const /// Returns the end of the map. { return _container.end(); } Iterator begin() /// Returns the beginning of the map. { return _container.begin(); } Iterator end() /// Returns the end of the map. { return _container.end(); } ConstIterator find(const KeyType& key) const /// Finds the first occurrence of the key and /// returns iterator pointing to the found entry /// or iterator pointing to the end if entry is /// not found. { typename Container::const_iterator it = _container.begin(); typename Container::const_iterator itEnd = _container.end(); for(; it != itEnd; ++it) { if (isEqual(it->first, key)) return it; } return itEnd; } Iterator find(const KeyType& key) /// Finds the first occurrence of the key and /// returns iterator pointing to the found entry /// or iterator pointing to the end if entry is /// not found. { typename Container::iterator it = _container.begin(); typename Container::iterator itEnd = _container.end(); for(; it != itEnd; ++it) { if (isEqual(it->first, key)) return it; } return itEnd; } 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 { Iterator it = find(val.first); while (it != _container.end() && isEqual(it->first, val.first)) ++it; return _container.insert(it, val); } void erase(Iterator it) { _container.erase(it); } SizeType erase(const KeyType& key) { SizeType count = 0; Iterator it = find(key); bool removed = false; while (it != _container.end()) { if (isEqual(it->first, key)) { ++count; it = _container.erase(it); removed = true; } else { if (removed) return count; ++it; } } return count; } void clear() { _container.clear(); } std::size_t size() const { return _container.size(); } bool empty() const { return _container.empty(); } ConstReference operator [] (const KeyType& key) const { ConstIterator it = find(key); if (it != _container.end()) return it->second; else throw NotFoundException(); } Reference operator [] (const KeyType& key) { Iterator it = find(key); if (it != _container.end()) { return it->second; } else { ValueType value(key, Mapped()); Iterator itInsert = insert(value); return itInsert->second; } } private: template bool isEqual(T1 val1, T2 val2) const { return val1 == val2; } bool isEqual(const std::string& s1, const std::string& s2) const { 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 _container; }; } // namespace Poco #endif // Foundation_ListMap_INCLUDED