From efeea769c8f966233d27cd3d833c65059082ae53 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sun, 15 Dec 2024 15:23:29 -0500 Subject: [PATCH] Add Lopmap, a more value-centric map Sorts keys by value instead of themselves (i.e. iterating the map will be in order of value). Functions that normally return a range of iterators (i.e. equal_range) are based on the positions of values instead of keys. Has reverse iterators, allows for custom comparator. --- lib/core/CMakeLists.txt | 2 + lib/core/include/qx/core/qx-lopmap.h | 468 ++++++++++++++++++ lib/core/src/qx-lopmap.dox | 691 +++++++++++++++++++++++++++ 3 files changed, 1161 insertions(+) create mode 100644 lib/core/include/qx/core/qx-lopmap.h create mode 100644 lib/core/src/qx-lopmap.dox diff --git a/lib/core/CMakeLists.txt b/lib/core/CMakeLists.txt index 0e935ece..030eb821 100644 --- a/lib/core/CMakeLists.txt +++ b/lib/core/CMakeLists.txt @@ -23,6 +23,7 @@ qx_add_component("Core" qx-iostream.h qx-json.h qx-list.h + qx-lopmap.h qx-processbider.h qx-progressgroup.h qx-table.h @@ -93,6 +94,7 @@ qx_add_component("Core" qx-index.dox qx-iostream.dox qx-list.dox + qx-lopmap.dox qx-traverser.dox qx-cumulation.dox qx-array.dox diff --git a/lib/core/include/qx/core/qx-lopmap.h b/lib/core/include/qx/core/qx-lopmap.h new file mode 100644 index 00000000..ae568df4 --- /dev/null +++ b/lib/core/include/qx/core/qx-lopmap.h @@ -0,0 +1,468 @@ +#ifndef QX_LOPMAP_H +#define QX_LOPMAP_H + +// Standard Library Includes +#include +#include + +// Extra-component Includes +#include + +namespace Qx +{ + +template> + requires std::predicate +class Lopmap; + +template +concept lopmap_iterator_predicate = defines_call_for_s::const_iterator>; + +template +concept lopmap_pair_predicate = defines_call_for_s>; + +template +concept lopmap_predicate = lopmap_iterator_predicate || lopmap_pair_predicate; + +} + +/*! @cond */ +namespace _QxPrivate +{ + +template +qsizetype _erase_if(Qx::Lopmap& lm, Predicate& pred) +{ + // This could be moved to a private file and made more generic for any other container types if needed, + // though its tricky since here for the pair predicate we pass a const T + using Iterator = typename Qx::Lopmap::iterator; + + typename Qx::Lopmap::size_type result = 0; + + Iterator it = lm.cbegin(); + const Iterator end = lm.cend(); + while(it != end) + { + if constexpr(Qx::lopmap_iterator_predicate) + { + if(pred(it)) + { + it = lm.erase(it); + result++; + } + else + it++; + } + else if constexpr(Qx::lopmap_pair_predicate) + { + if(pred(std::move(*it))) + { + it = lm.erase(it); + result++; + } + else + it++; + } + else + { + // Delayed evaluation trick to prevent immediate static_assert failure for older compilers from before the resolution of CWG 2518 + static_assert(sizeof(Qx::Lopmap) == 0, "Invalid Predicate"); + } + } + + return result; +} + +} +/*! @endcond */ + +namespace Qx +{ + +template + requires std::predicate +class Lopmap +{ +//-Inner Classes---------------------------------------------------------------------------------------------------- +private: + struct Data + { + Key key; + T value; + }; + + struct DataCompare + { + Compare cmp; + bool operator()(const Data& lhs, const Data& rhs) const { return cmp(lhs.value, rhs.value); } + }; + +//-Aliases---------------------------------------------------------------------------------------------------------- +private: + using StorageContainer = std::set; + using LookupContainer = std::unordered_map; + +public: + class const_iterator + { + friend class Lopmap; + //-Aliases------------------------------------------------------------------------------------------------------ + private: + using StorageItr = typename StorageContainer::const_iterator; + + public: + using iterator_category = typename StorageItr::iterator_category; + + //-Instance Variables------------------------------------------------------------------------------------------- + private: + StorageItr mStorageItr; + + //-Constructor-------------------------------------------------------------------------------------------------- + private: + const_iterator(const StorageItr& sItr) : mStorageItr(sItr) {} + + public: + const_iterator() {} + + //-Instance Functions------------------------------------------------------------------------------------------- + public: + const Key& key() const { return mStorageItr->key; } + const T& value() const { return mStorageItr->value; } + + //-Operators--------------------------------------------------------------------------------------------- + public: + bool operator==(const const_iterator& other) const = default; + const T& operator*() const { return value(); } + const_iterator& operator++() { mStorageItr++; return *this; } + + const_iterator operator++(int) + { + auto cur = *this; + mStorageItr++; + return cur; + } + + const_iterator& operator--() { mStorageItr--; return *this; } + + const_iterator operator--(int) + { + auto cur = *this; + mStorageItr--; + return cur; + } + + const T* operator->() const { return &mStorageItr->value; } + }; + + // Could be greatly simplified with the above by using a base type, but that makes documentation hard... + class const_reverse_iterator + { +/*! @cond */ + friend class Lopmap; + //-Aliases------------------------------------------------------------------------------------------------------ + private: + using StorageItr = typename StorageContainer::const_reverse_iterator; + + //-Instance Variables------------------------------------------------------------------------------------------- + private: + StorageItr mStorageItr; + + //-Constructor-------------------------------------------------------------------------------------------------- + private: + const_reverse_iterator(const StorageItr& sItr) : mStorageItr(sItr) {} + + public: + const_reverse_iterator() {} + + //-Instance Functions------------------------------------------------------------------------------------------- + public: + const Key& key() const { return mStorageItr->key; } + const T& value() const { return mStorageItr->value; } + + //-Operators--------------------------------------------------------------------------------------------- + public: + bool operator==(const const_reverse_iterator& other) const = default; + const T& operator*() const { return value(); } + const_reverse_iterator& operator++() { mStorageItr++; return *this; } + + const_reverse_iterator operator++(int) + { + auto cur = *this; + mStorageItr++; + return cur; + } + + const_reverse_iterator& operator--() { mStorageItr--; return *this; } + + const_reverse_iterator operator--(int) + { + auto cur = *this; + mStorageItr--; + return cur; + } + + const T* operator->() const { return &mStorageItr->value; } +/*! @endcond */ + }; + +//-Aliases (cont.)------------------------------------------------------------------------------------------------- +public: + using iterator = const_iterator; + using ConstIterator = const_iterator; + using Iterator = iterator; + using reverse_iterator = const_reverse_iterator; + using ConstReverseIterator = const_reverse_iterator; + using ReverseIterator = reverse_iterator; + using difference_type = typename StorageContainer::difference_type; + using key_type = Key; + using mapped_Type = T; + using size_type = typename StorageContainer::size_type; + using value_compare = Compare; + +//-Instance Variables------------------------------------------------------------------------------------------- +private: + StorageContainer mStorage; + LookupContainer mLookup; + +//-Constructor-------------------------------------------------------------------------------------------------- +public: + Lopmap() {} + + Lopmap(std::initializer_list> list) + { + reserve(list.size()); + for(auto it = list.begin(); it != list.end(); ++it) + insert(it->first, it->second); + } + +//-Instance Functions------------------------------------------------------------------------------------------- +public: + iterator begin() { return iterator(mStorage.begin()); } + const_iterator begin() const { return constBegin(); } + const_iterator cbegin() const { return constBegin(); } + const_iterator constBegin() const { return const_iterator(mStorage.cbegin()); } + iterator end() { return iterator(mStorage.end()); } + const_iterator end() const { return constEnd(); } + const_iterator cend() const { return constEnd(); } + const_iterator constEnd() const { return const_iterator(mStorage.cend()); } + reverse_iterator rbegin() { return reverse_iterator(mStorage.rbegin()); } + const_reverse_iterator rbegin() const { return constReverseBegin(); } + const_reverse_iterator crbegin() const { return constReverseBegin(); } + const_reverse_iterator constReverseBegin() const { return const_reverse_iterator(mStorage.crbegin()); } + reverse_iterator rend() { return reverse_iterator(mStorage.rend()); } + const_reverse_iterator rend() const { return constEnd(); } + const_reverse_iterator crend() const { return constEnd(); } + const_reverse_iterator constReverseEnd() const { return const_reverse_iterator(mStorage.crend()); } + + iterator find(const Key& key) + { + auto lItr = mLookup.find(key); // Lookup iterator + return lItr == mLookup.end() ? iterator() : + iterator(*lItr); // Convert to storage iterator to construct our iterator + } + + const_iterator find(const Key& key) const { return constFind(key); } + + const_iterator constFind(const Key& key) const + { + auto lItr = mLookup.find(key); // Lookup iterator + return lItr == mLookup.cend() ? const_iterator() : + const_iterator(*lItr); // Convert to storage iterator to construct our iterator + } + + iterator lowerBound(const T& value) { return std::as_const(this)->lowerBound(value); } + + const_iterator lowerBound(const T& value) const + { + // Use dummy key since only value is used for ordering + return const_iterator(mStorage.lower_bound(Data{{}, value})); + } + + iterator upperBound(const T& value) { return std::as_const(this)->upperBound(value); } + + const_iterator upperBound(const T& value) const + { + // Use dummy key since only value is used for ordering + return const_iterator(mStorage.upper_bound(Data{{}, value})); + } + + std::pair equal_range(const T& value) { return std::as_const(this)->equal_range(value); } + + std::pair equal_range(const T& value) const + { + // Use dummy key since only value is used for ordering + auto sItrPair = mStorage.equal_range(Data{{}, value}); + return std::make_pair(sItrPair.first, sItrPair.second); + } + + const T& first() const { Q_ASSERT(!mStorage.empty()); mStorage.cbegin()->value; } + const Key& firstKey() const { Q_ASSERT(!mStorage.empty()); mStorage.cbegin()->key; } + + const T& last() const { Q_ASSERT(!mStorage.empty()); mStorage.cend()->value; } + const Key& lastKey() const { Q_ASSERT(!mStorage.empty()); mStorage.cend()->key; } + + Key key(const T& value, const Key& defaultKey = Key()) const + { + for(const auto& data : std::as_const(mStorage)) + if(data.value == value) + return data.key; + + return defaultKey; + } + + iterator erase(const_iterator pos) + { + Q_ASSERT(pos != constEnd()); + mLookup.erase(pos.key()); + return iterator(mStorage.erase(pos.mStorageItr)); + } + + iterator erase(const_iterator first, const_iterator last) + { + Q_ASSERT(first != constEnd() && last != constEnd()); + mLookup.erase(mLookup.find(first.key()), mLookup.find(last.key())); + return iterator(mStorage.erase(first.mStorageItr, last.mStorageItr)); + } + + void insert(Lopmap&& other) + { + // Have to copy due to underlying iterator being const, but original container is emptied + insert(std::as_const(other)); + + other.mStorage.clear(); + other.mLookup.clear(); + } + + void insert(const Lopmap& other) + { + if(this == &other) + return; + + for(auto itr = other.mStorage.begin(); itr != other.mStorage.end(); itr++) + insert(itr->key, itr->value); + } + + iterator insert(const Key& key, const T& value) + { + // The value will not match the storage value (since it's of type Data), so we have to remove it explicitly + auto oldLItr = mLookup.find(key); + if(oldLItr != mLookup.end()) + mStorage.erase(*oldLItr); // Convert to storage itr and purge + + auto newItr = mStorage.insert(Data{key, value}); + mLookup[key] = newItr; // This will replace existing keys correctly + } + + iterator insert(const_iterator pos, const Key& key, const T& value) + { + // The value will not match the storage value (since it's of type Data), so we have to remove it explicitly + auto oldLItr = mLookup.find(key); + if(oldLItr != mLookup.end()) + mStorage.erase(*oldLItr); // Convert to storage itr and purge + + auto newItr = mStorage.insert(pos, Data{key, value}); + mLookup[key] = newItr; // This will replace existing keys correctly + } + + bool contains(const Key& key) const { return mLookup.contains(key); } + + size_type remove(const Key& key) + { + auto lItr = mLookup.find(key); + if(lItr != mLookup.cend()) + { + auto sItr = *lItr; + mLookup.erase(lItr); + mStorage.erase(sItr); + return 1; + } + + return 0; + } + + template + requires lopmap_predicate + qsizetype removeIf(Predicate pred) { return _QxPrivate::_erase_if(*this, pred); } + + T take(const Key& key) + { + auto lItr = mLookup.find(key); + if(lItr != mLookup.cend()) + { + auto sItr = *lItr; + T t = sItr->value; + mLookup.erase(lItr); + mStorage.erase(sItr); + return t; + } + + return T(); + } + + void swap(Lopmap& other) + { + mLookup.swap(other.mLookup); + mStorage.swap(other.mStorage); + } + + qsizetype size() const { return mStorage.size(); } + qsizetype count() const { return size(); } + bool isEmpty() const { return size() == 0; } + bool empty() const { return isEmpty(); } + + void clear() { mLookup.clear(); mStorage.clear(); } + + T value(const Key& key, const T& defaultValue = T()) const + { + auto lItr = mLookup.find(key); + return lItr != mLookup.cend() ? lItr->value : defaultValue; + } + + QList keys() const + { + QList ks; + for(const auto& data : std::as_const(mStorage)) + ks.append(data.key); + return ks; + } + + QList keys(const T& value) const + { + QList ks; + for(const auto& data : std::as_const(mStorage)) + if(data.value == value) + ks.append(data.key); + return ks; + } + + QList values() const + { + QList vs; + for(const auto& data : std::as_const(mStorage)) + vs.append(data.value); + return vs; + } + +//-Operators--------------------------------------------------------------------------------------------- +public: + T operator[](const Key& key) const { return value(key); } + + bool operator==(const Lopmap& other) const { return mStorage == other.mStorage; } + bool operator!=(const Lopmap& other) const = default; +}; + +// Doc'ed here cause doxygen struggles with this one being separate +/*! + * Removes all elements for which the predicate pred returns true from the lopmap. + * + * The function supports predicates which take either an argument of type Lopmap::const_iterator, + * or an argument of type std::pair. + * + * Returns the number of elements removed, if any. + */ +template +qsizetype erase_if(Lopmap& lopmap, Predicate pred) { return _QxPrivate::_erase_if(lopmap, pred); } + +} + +#endif // QX_LOPMMAP_H diff --git a/lib/core/src/qx-lopmap.dox b/lib/core/src/qx-lopmap.dox new file mode 100644 index 00000000..6c7b157a --- /dev/null +++ b/lib/core/src/qx-lopmap.dox @@ -0,0 +1,691 @@ +namespace Qx +{ + +/*! + * @concept lopmap_iterator_predicate + * @brief Specifies that a predicate is a valid, iterator based predicate for a lopmap. + * + * Satisfied if the predicate takes a Qx::Lopmap>::const_iterator and returns @c bool. + */ + +/*! + * @concept lopmap_pair_predicate + * @brief Specifies that a predicate is a valid, pair based predicate for a lopmap. + * + * Satisfied if the predicate takes a std::pair and returns @c bool. + */ + +/*! + * @concept lopmap_predicate + * @brief Specifies that a predicate is a valid predicate for a lopmap. + * + * Satisfied if the predicate satisfies lopmap_iterator_predicate or lopmap_pair_predicate. + */ + +//=============================================================================================================== +// Lopmap +//=============================================================================================================== + +/*! + * @class Lopmap qx/core/qx-lopmap.h + * @ingroup qx-core + * + * @brief The Lopmap class is a template class that provides an "lopsided" associative array. + * + * Qx::Lopmap is like QMap, except that values in the map are sorted + * by value instead of key, with an order dictated by Compare. + * + * Unlike QMap, iterator is simply an alias for const_iterator as values cannot be modified through lopmap iterators + * since that would affect ordering. Additionally, some methods that would traditional take Key as an argument, + * instead take T. + * + * The value type of Lopmap must provide operator<(), or a custom Compare object must be + * provided specifying a total order. + */ + +//-Aliases-------------------------------------------------------------------------------------------------- +//Public: +/*! + * @typedef Lopmap::iterator + * Typedef for const_iterator. + * + * @typedef Lopmap::ConstIterator + * Qt-style synonym for Lopmap::const_iterator. + * + * @typedef Lopmap::Iterator + * Qt-style synonym for Lopmap::iterator. + * + * @typedef Lopmap::reverse_iterator + * Typedef for const_reverse_iterator. + * + * @typedef Lopmap::ConstReverseIterator + * Qt-style synonym for const_reverse_iterator. + * + * @typedef Lopmap::ReverseIterator + * Qt-style synonym for reverse_iterator. + * + * @typedef Lopmap::difference_type + * Typedef for the container's difference type, usually std::ptrdiff_t. + * + * @typedef Lopmap::key_type + * Typedef for Key. + * + * @typedef Lopmap::mapped_Type + * Typedef for T. + * + * @typedef Lopmap::size_type + * Typedef for the container's size_type, usually std::size_t. + * + * @typedef Lopmap::value_compare + * Typedef for Compare. + */ + +//-Constructor---------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn Lopmap::Lopmap() + * + * Creates an empty lopmap. + * + * @sa clear(). + */ + +/*! + * @fn Lopmap::Lopmap(std::initializer_list> list) + * + * Creates a lopmap with a copy of each of the elements in the initializer list @a list. + */ + +//-Instance Functions---------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn iterator Lopmap::begin() + * + * Same as constBegin(). + */ + +/*! + * @fn iterator Lopmap::begin() const + * + * @overload + */ + +/*! + * @fn const_iterator Lopmap::cbegin() const + * + * Same as constBegin(). + */ + +/*! + * @fn const_iterator Lopmap::constBegin() const + * + * Returns an STL-style iterator pointing to the first item in the lopmap. + * + * @sa constEnd(). + */ + +/*! + * @fn iterator Lopmap::end() + * + * Same as constEnd(). + */ + +/*! + * @fn const_iterator Lopmap::end() const + * + * @overload + */ + +/*! + * @fn const_iterator Lopmap::cend() const + * + * Same as constEnd(). + */ + +/*! + * @fn const_iterator Lopmap::constEnd() const + * + * Returns an STL-style iterator pointing to the imaginary item after the last item in the lopmap. + * + * @sa constBegin(). + */ + +/*! + * @fn reverse_iterator Lopmap::rbegin() + * + * Same as constReverseBegin(). + */ + +/*! + * @fn const_reverse_iterator Lopmap::rbegin() const + * + * @overload + */ + +/*! + * @fn const_reverse_iterator Lopmap::crbegin() const + * + * Same as constReverseBegin(). + */ + +/*! + * @fn const_reverse_iterator Lopmap::constReverseBegin() const + * + * Returns an STL-style iterator pointing to the last item in the lopmap. + * + * @sa constReverseEnd(). + */ + +/*! + * @fn reverse_iterator Lopmap::rend() + * + * Same as constReverseEnd(). + */ + +/*! + * @fn const_reverse_iterator Lopmap::rend() const + * + * @overload + */ + +/*! + * @fn const_reverse_iterator Lopmap::crend() const + * + * Same as constReverseEnd(). + */ + +/*! + * @fn const_reverse_iterator Lopmap::constReverseEnd() const + * + * Returns an STL-style iterator pointing to the imaginary item after the first item in the lopmap. + * + * @sa constReverseBegin(). + */ + +/*! + * @fn iterator Lopmap::find(const Key& key) + * + * Same as constFind(). + */ + +/*! + * @fn const_iterator Lopmap::find(const Key& key) const + * + * @overload + */ + +/*! + * @fn const_iterator Lopmap::constFind(const Key& key) const + * + * Returns an iterator pointing to the item with the key @a key in the lopmap. + * + * If the lopmaps contains no item with the key @a key, the function returns constEnd(). + */ + +/*! + * @fn iterator Lopmap::lowerBound(const T& value) + * + * Returns an iterator pointing to the first item with value @a value in the lopmap. If the map contains no + * item with value @a value, the function returns an iterator to the nearest item with a greater value, + * or constEnd() if there is none. + * + * @sa upperBound() and find(). + */ + +/*! + * @fn const_iterator Lopmap::lowerBound(const T& value) const + * + * @overload + */ + +/*! + * @fn iterator Lopmap::upperBound(const T& value) + * + * Returns an iterator pointing to the item that immediately follows the last item with value @a value in the + * lopmap. If the map contains no item with value @a value, the function returns an iterator to the nearest + * item with a greater value, or constEnd() if there is none. + * + * @sa lowerBound() and find(). + */ + +/*! + * @fn const_iterator Lopmap::upperBound(const T& value) const + * + * @overload + */ + +/*! + * @fn std::pair Lopmap::equal_range(const T& value) + * + * Returns a pair of iterators delimiting the range of values [first, second), that are stored with @a value. + */ + +/*! + * @fn std::pair Lopmap::equal_range(const T& value) const + * + * @overload + */ + +/*! + * @fn const T& Lopmap::first() const + * + * Returns a reference to the first value in the lopmap. + * + * This function assumes that the map is not empty. + * + * @sa last(), firstKey(), and isEmpty(). + */ + +/*! + * @fn const Key& Lopmap::firstKey() const + * + * Returns a reference to the first key in the lopmap. + * + * This function assumes that the map is not empty. + * + * @sa lastKey(), first(), and isEmpty(). + */ + +/*! + * @fn const T& Lopmap::last() const + * + * Returns a reference to the last value in the lopmap. + * + * This function assumes that the map is not empty. + * + * @sa last(), firstKey(), and isEmpty(). + */ + +/*! + * @fn const Key& Lopmap::lastKey() const + * + * Returns a reference to the last key in the lopmap. + * + * This function assumes that the map is not empty. + * + * @sa lastKey(), first(), and isEmpty(). + */ + +/*! + * @fn Key Lopmap::key(const T& value, const Key& defaultKey) const + * + * Returns the key with value @a value, or @a defaultKey if the lopmap contains no item with @a value. If no + * @a defaultKey is provided the functionr returns a default-constructed key. + * + * This function can be slow, because Lopmap's internal data structure is optimized for fast lookup by key, + * not by value. + * + * @sa value(), and keys(). + */ + +/*! + * @fn iterator Lopmap::erase(const_iterator pos) + * + * Removes the (key, value) pair pointed to by the iterator @a pos from the lopmap, and returns an + * iterator to the next item in the map. + * + * @note The iterator @a pos @e must be valid and dereferenceable. + * + * @sa remove(), and take(). + */ + +/*! + * @fn iterator Lopmap::erase(const_iterator first, const_iterator last) + * + * Removes the (key, value) pairs pointed to by the iterator range [first, last) from the lopmap, + * and returns an iterator to the item in the map following the last removed element. + * + * @note The range @c [first, @c last) @e must be a valid range in @c *this. + * + * @sa remove(), and take(). + */ + +/*! + * @fn void Lopmap::insert(Lopmap&& other) + * + * Moves all the items from @a other into this lopmap. + * + * If a key is common to both maps, its value with be replaced with the value stored in @a other. + */ + +/*! + * @fn void Lopmap::insert(const Lopmap& other) + * + * Inserts all the items in the @a other lopmap into this lopmap. + * + * If a key is common to both maps, its value with be replaced with the value stored in @a other. + */ + +/*! + * @fn iterator Lopmap::insert(const Key& key, const T& value) + * + * Inserts a new item with the key @a key and value of @a value. + * + * If there is already an item with the key @a key, that item's value is replaced with @a value. + * + * Returns an iterator pointing to the new/updated element. + */ + +/*! + * @fn iterator Lopmap::insert(const_iterator pos, const Key& key, const T& value) + * + * Inserts a new item with the key @a key and value @a value and with hint @a pos suggesting where to do + * the insert. + * + * If constBegin() is used as hint it indicates that the @a key is less than any key in the map while + * constEnd() suggests that the @a key is (strictly) larger than any key in the map. Otherwise the hint + * should meet the condition (pos - 1).key() < key <= pos.key(). If the hint pos is wrong it is ignored + * and a regular insert is done. + * + * If there is already an item with the key @a key, that item's value is replaced with @a value. + * + * If the hint is correct, the insert executes in amortized constant time. + * + * When creating a map from sorted data inserting the largest key first with constBegin() is faster than + * inserting in sorted order with constEnd(), since constEnd() - 1 (which is needed to check if the hint + * is valid) needs logarithmic time. + * + * Returns an iterator pointing to the new/updated element. + */ + +/*! + * @fn bool Lopmap::contains(const Key& key) const + * + * Returns @c true if the lopmap contains an item with the key @a key; otherwise, + * returns @c false. + * + * @sa count(). + */ + +/*! + * @fn size_type Lopmap::remove(const Key& key) + * + * Remove the item with key @a key from the map if it exists and returns @c 1; otherwise, returns @c 0. + * + * @sa clear() and take(). + */ + +/*! + * @fn qsizetype Lopmap::removeIf(Predicate pred) + * + * Removes all elements for which the predicate @a pred returns true from the lopmap. + * + * The function supports predicates which take either an argument of type Lopmap::const_iterator, + * or an argument of type std::pair. + * + * Returns the number of elements removed, if any. + * + * @sa clear() and take(). + */ + +/*! + * @fn T Lopmap::take(const Key& key) + * + * Removes the item with the key @a key from the lopmap and returns the value + * associated with it. + * + * If this item does not exist in the lopmap, the function simply returns a default-constructed value + * + * If you don't use the return value, remove() is more efficient. + * + * @sa remove(). + */ + +/*! + * @fn void Lopmap::swap(Lopmap& other) + * + * Swaps lopmap @a other with this lopmap. This operation is very fast and never fails. + */ + +/*! + * @fn qsizetype Lopmap::size() const + * + * Returns the number of items in the lopmap. + * + * @sa isEmpty() and count(). + */ + +/*! + * @fn qsizetype Lopmap::count() const + * + * Same as size(). + */ + +/*! + * @fn bool Lopmap::isEmpty() const + * + * Returns @c true if the lopmap contains no items; otherwise, returns @c false. + * + * @sa size(). + */ + +/*! + * @fn bool Lopmap::empty() const + * + * Same as isEmpty(). + */ + +/*! + * @fn void Lopmap::clear() + * + * Removes all items from the lopmap. + * + * @sa remove(). + */ + +/*! + * @fn T Lopmap::value(const Key& key, const T& defaultValue) const + * + * Returns the value associated with the key @a key. + * + * If the lopmap contains no item with key @a key, the function returns @a defaultValue. + * If no @a defaultValue is specified, the function returns a default-constructed value. + * + * @sa key(), values(), contains(), and operator[](). + */ + +/*! + * @fn QList Lopmap::keys() const + * + * Returns a list containing all of the keys in the lopmap in order of their associated values. + * + * The order is guaranteed to be the same as that used by values(). + * + * This function creates a new list, in linear time. + * + * @sa values() and key(). + */ + +/*! + * @fn QList Lopmap::keys(const T& values) const + * + * Returns a list containing all of the keys associated with the value @a value in order of their + * associated values. + * + * This function creates a new list, in linear time. + */ + +/*! + * @fn QList Lopmap::values() const + * + * Returns a list containing all of the values in the lopmap in order. + * + * This function creates a new list, in linear time. The time and memory use that entails can be + * avoided by iterating from begin() to end(). + * + * @sa keys() and value(). + */ + +//-Operators--------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn T Lopmap::operator[](const Key& key) const + * + * Same as value(). + */ + +/*! + * @fn bool Lopmap::operator==(const Lopmap& other) const + * + * Returns @c true if @a other is equal to this lopmap; otherwise, returns @c false. + * + * Two lopmap's are considered equal if they contain the same (key, value) pairs. + * + * This function requires the key and the value types to implement @c operator==(). + * + * @sa operator!=(). + */ + +/*! + * @fn bool Lopmap::operator!=(const Lopmap& other) const + * + * Returns @c true if @a other is not equal to this lopmap; otherwise, returns @c false. + * + * Two lopmap's are considered equal if they contain the same (key, value) pairs. + * + * This function requires the key and the value types to implement @c operator==(). + * + * @sa operator==(). + */ + +//=============================================================================================================== +// Lopmap::const_iterator +//=============================================================================================================== + +/*! + * @class Lopmap::const_iterator qx/core/qx-lopmap.h + * @ingroup qx-core + * + * @brief The Lopmap::const_iterator class provides an STL-style const iterator for Lopmap. + * + * Lopmap::const_iterator allows you to iterate over a Lopmap. + * + * The default Lopmap::const_iterator constructor creates an uninitialized iterator. You must initialize it using + * a Lopmap function like Lopmap::cbegin(), Lopmap::cend(), or Lopmap::constFind() before you can start iterating. + * + * Lopmap stores its items ordered according to Compare. + * + * Multiple iterators can be used on the same map. If you add items to the map, existing iterators will remain + * valid. If you remove items from the map, iterators that point to the removed items will become dangling iterators. + * + * Inserting relationships into the lopmap or calling methods such as Lopmap::reserve() or Lopmap::squeeze() can + * invalidate all iterators pointing into the lopmap. Iterators are guaranteed to stay valid only as long as the + * Lopmap doesn't have to grow/shrink its internal table. Using any iterator after a rehashing operation has + * occurred will lead to undefined behavior + */ + +//-Aliases---------------------------------------------------------------------------------------------- +//Public: +/*! + * @typedef Lopmap::const_iterator::iterator_category + * A synonym for std::bidirectional_iterator_tag indicating this iterator is a bidirectional iterator. + */ +//-Constructor---------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn Lopmap::const_iterator::const_iterator() + * + * Constructs an uninitialized iterator. + * + * Functions like key(), value(), and operator++() must not be called on an uninitialized iterator. + * Use operator=() to assign a value to it before using it. + * + * @sa Lopmap::constBegin() and Lopmap::constEnd(). + */ + +//-Instance Functions---------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn const Key& Lopmap::const_iterator::key() const + * + * Returns the current item's key. + * + * @sa value() and operator*(). + */ + +/*! + * @fn const T& Lopmap::const_iterator::value() const + * + * Returns the current item's value. + * + * @sa key(). + */ + +//-Operators--------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn bool Lopmap::const_iterator::operator==(const const_iterator& other) const + * + * Returns @c true if @a other points to the same item as this iterator; otherwise, returns @c false. + */ + +/*! + * @fn const T& Lopmap::const_iterator::operator*() const + * + * Returns the current item's value. + * + * @sa key(). + */ + +/*! + * @fn const_iterator Lopmap::const_iterator::operator++() + * + * The prefix @c ++ operator @c (++i) advances the iterator to the next item in the lopmap and + * returns an iterator to the new item relationship. + * + * Calling this function on Lopmap::constEnd() leads to undefined results. + * + * @sa operator--(). + */ + +/*! + * @fn const_iterator Lopmap::const_iterator::operator++(int) + * + * The postfix @c ++ operator @c (i++) advances the iterator to the next item in the lopmap and + * returns an iterator to the previously current item. + * + * Calling this function on Lopmap::constEnd() leads to undefined results. + */ + +/*! + * @fn const_iterator Lopmap::const_iterator::operator--() + * + * The prefix @c -- operator @c (--i) makes the preceding item current and + * returns an iterator to the new current item. + * + * Calling this function on Lopmap::constBegin() leads to undefined results. + * + * @sa operator++(). + */ + +/*! + * @fn const_iterator Lopmap::const_iterator::operator--(int) + * + * The postfix @c -- operator @c (--i) makes the preceding item current and + * returns an iterator to the previously current item. + * + * Calling this function on Lopmap::constEnd() leads to undefined results. + */ + +/*! + * @fn const T* Lopmap::const_iterator::operator->() const + * + * Returns a pointer to the current item's value. + * + * @sa value(). + */ + +//=============================================================================================================== +// Lopmap::const_reverse_iterator +//=============================================================================================================== + +/*! + * @class Lopmap::const_reverse_iterator qx/core/qx-lopmap.h + * @ingroup qx-core + * + * @brief The Lopmap::const_reverse_iterator class provides an STL-style const reverse iterator for Lopmap. + * + * Same as Lopmap::const_iterator, except that it works in the opposite direction. + */ + +}