From 83f6fd406a3837443441081b62939371e52b9f59 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Wed, 23 Oct 2024 18:39:56 -0400 Subject: [PATCH] Add Bimap, a basic bi-directional map --- CMakeLists.txt | 2 +- lib/core/CMakeLists.txt | 2 + lib/core/include/qx/core/qx-bimap.h | 394 ++++++++++++++++ lib/core/src/qx-bimap.dox | 703 ++++++++++++++++++++++++++++ 4 files changed, 1100 insertions(+), 1 deletion(-) create mode 100644 lib/core/include/qx/core/qx-bimap.h create mode 100644 lib/core/src/qx-bimap.dox diff --git a/CMakeLists.txt b/CMakeLists.txt index fdd96290..2fa62573 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ project(Qx # Get helper scripts include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/FetchOBCMake.cmake) -fetch_ob_cmake("e7e1e091fd3b95dcd33e168f7faffa9d33d3b2a7") +fetch_ob_cmake("19d33b5bb1752b50767f78ca3e17796868354ac3") # Initialize project according to standard rules include(OB/Project) diff --git a/lib/core/CMakeLists.txt b/lib/core/CMakeLists.txt index 5d382754..772f0543 100644 --- a/lib/core/CMakeLists.txt +++ b/lib/core/CMakeLists.txt @@ -5,6 +5,7 @@ qx_add_component("Core" qx-algorithm.h qx-array.h qx-base85.h + qx-bimap.h qx-bitarray.h qx-bytearray.h qx-char.h @@ -74,6 +75,7 @@ qx_add_component("Core" __private/qx-processwaiter_linux.h __private/qx-processwaiter_linux.cpp DOC_ONLY + qx-bimap.dox qx-regularexpression.dox qx-bytearray.dox qx-exclusiveaccess.dox diff --git a/lib/core/include/qx/core/qx-bimap.h b/lib/core/include/qx/core/qx-bimap.h new file mode 100644 index 00000000..11f880fd --- /dev/null +++ b/lib/core/include/qx/core/qx-bimap.h @@ -0,0 +1,394 @@ +#ifndef QX_BIMAP_H +#define QX_BIMAP_H + +#include + +// Qt Includes +#include + +// Extra-component Includes +#include + +namespace Qx +{ + +template +class Bimap; + +template +concept asymmetric_bimap = !std::same_as; + +template +concept bimap_iterator_predicate = defines_call_for_s::const_iterator>; + +template +concept bimap_pair_predicate = defines_call_for_s>; + +template +concept bimap_predicate = bimap_iterator_predicate || bimap_pair_predicate; + +} + +/*! @cond */ +namespace _QxBimapPrivate +{ + +template +qsizetype _erase_if(Qx::Bimap& bm, Predicate& pred) +{ + // This could be moved to a private file and made more generic for any other container types if needed + using ConstIterator = Qx::Bimap::const_iterator; + + qsizetype result = 0; + + ConstIterator it = bm.cbegin(); + const ConstIterator end = bm.cend(); + while (it != end) + { + if constexpr(Qx::bimap_iterator_predicate) + { + if(pred(it)) + { + it = bm.erase(it); + result++; + } + else + it++; + } + else if constexpr(Qx::bimap_pair_predicate) + { + if (pred(std::move(*it))) + { + it = bm.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::Bimap) == 0, "Invalid Predicate"); + } + } + + return result; +} + +} +/*! @endcond */ + +namespace Qx +{ + +template +class Bimap +{ +//-Inner Classes---------------------------------------------------------------------------------------------------- +public: + //class iterator; Would cause internal iterator invalidation with no way to recover AFAICT, with current impl. + class const_iterator + { + friend class Bimap; + //-Aliases------------------------------------------------------------------------------------------------------ + private: + using PIterator = QHash::const_iterator; + + //-Instance Variables------------------------------------------------------------------------------------------- + private: + PIterator mPItr; + + //-Constructor-------------------------------------------------------------------------------------------------- + private: + const_iterator(const PIterator& pitr) : mPItr(pitr) {} + + public: + const_iterator() {} + + //-Instance Functions------------------------------------------------------------------------------------------- + public: + const Left& left() const { return mPItr.key(); } + const Right& right() const { return *mPItr.value(); } + + //-Operators--------------------------------------------------------------------------------------------- + public: + bool operator==(const const_iterator& other) const = default; + std::pair operator*() const { return std::pair(left(), right()); } + const_iterator& operator++() { mPItr++; return *this; } + + const_iterator operator++(int) + { + auto cur = *this; + mPItr++; + return cur; + } + }; + +//-Aliases------------------------------------------------------------------------------------------------------ +public: + using left_type = Left; + using right_type = Right; + using ConstIterator = const_iterator; + +//-Instance Variables------------------------------------------------------------------------------------------- +private: + QHash mL2R; + QHash mR2L; + +//-Constructor-------------------------------------------------------------------------------------------------- +public: + Bimap() {} + + Bimap(std::initializer_list> list) + { + reserve(list.size()); + for(auto it = list.begin(); it != list.end(); ++it) + insert(it->first, it->second); + } + +//-Class Functions------------------------------------------------------------------------------------------- +private: + template + void removeCrossReference(AMap& am, BMap& bm, const V& v) + { + if constexpr(std::same_as) + Q_ASSERT(&am != &bm); // Ensure different maps are used if the types are the same + + if(am.contains(v)) + bm.remove(*am[v]); + } + + template + bool remove(AMap& am, BMap& bm, const V& v) + { + if(!am.contains(v)) + return false; + + bm.remove(*am[v]); + am.remove(v); + return true; + } + +//-Instance Functions------------------------------------------------------------------------------------------- +private: + const_iterator existingRelation(const Left& l, const Right& r) const + { + auto itr = mL2R.constFind(l); + return (itr != mL2R.cend() && *itr.value() == r) ? const_iterator(itr) : const_iterator(); + } + + void removeCrossReferences(const Left& l, const Right& r) + { + // Remove to-be stale relations + removeCrossReference(mL2R, mR2L, l); + removeCrossReference(mR2L, mL2R, r); + } + + const_iterator addOrUpdateRelation(const Left& l, const Right& r) + { + auto lItr = mL2R.insert(l, nullptr); + auto rItr = mR2L.insert(r, nullptr); + lItr.value() = &rItr.key(); + rItr.value() = &lItr.key(); + return const_iterator(lItr); + } + +public: + const_iterator begin() const { return constBegin(); } + const_iterator cbegin() const { return constBegin(); } + const_iterator constBegin() const { return const_iterator(mL2R.cbegin()); } + const_iterator end() const { return constEnd(); } + const_iterator cend() const { return constEnd(); } + const_iterator constEnd() const { return const_iterator(mL2R.cend()); } + const_iterator constFind(const Left& l) const requires asymmetric_bimap { return constFindLeft(l); } + const_iterator constFind(const Right& r) const requires asymmetric_bimap { return constFindRight(r); } + const_iterator constFindLeft(const Left& l) const { return const_iterator(mL2R.constFind(l)); } + + const_iterator constFindRight(const Right& r) const + { + auto rItr = mR2L.constFind(r); + return const_iterator(rItr != mR2L.cend() ? mL2R.constFind(*(*rItr)) : mL2R.cend()); + } + + const_iterator find(const Left& l) const requires asymmetric_bimap { return findLeft(l); } + const_iterator find(const Right& r) const requires asymmetric_bimap { return findRight(r); } + const_iterator findLeft(const Left& l) const { return const_iterator(constFindLeft(l)); } + const_iterator findRight(const Right& r) const { return const_iterator(constFindRight(r)); } + + const_iterator erase(const_iterator pos) + { + auto lItr = pos.mPItr; + auto rItr = mR2L.constFind(pos.right()); + mR2L.erase(rItr); + return const_iterator(mL2R.erase(lItr)); + } + + void insert(const Bimap& other) + { + if(this == &other) + return; + + for(auto it = other.begin(); it != other.end(); it++) + insert(it.left(), it.right()); + } + + const_iterator insert(const Left& l, const Right& r) + { + if(auto itr = existingRelation(l, r); itr != cend()) + return itr; + + removeCrossReferences(l, r); + return addOrUpdateRelation(l, r); + } + + bool containsLeft(const Left& l) const { return mL2R.contains(l); } + bool containsRight(const Right& r) const { return mR2L.contains(r); } + + Right fromLeft(const Left& l) const + { + return mL2R.contains(l) ? *mL2R[l] : Right(); + } + + Right fromLeft(const Left& l, const Right& defaultValue) const + { + return mL2R.contains(l) ? *mL2R[l] : defaultValue; + } + + Left fromRight(const Right& l) const + { + return mR2L.contains(l) ? *mR2L[l] : Left(); + } + + Left fromRight(const Right& l, const Left& defaultValue) const + { + return mR2L.contains(l) ? *mR2L[l] : defaultValue; + } + + Right from(const Left& l) const requires asymmetric_bimap { return fromLeft(l); } + Right from(const Left& l, const Right& defaultValue) const requires asymmetric_bimap { return fromLeft(l, defaultValue); } + Left from(const Right& r) const requires asymmetric_bimap { return fromRight(r); } + Left from(const Right& r, const Left& defaultValue) const requires asymmetric_bimap { return fromRight(r, defaultValue); } + + Left toLeft(const Right& r) const { return fromRight(r); } + Left toLeft(const Right& r, const Left& defaultValue) const { return fromRight(r, defaultValue); } + Right toRight(const Left& l) const { return fromLeft(l); } + Right toRight(const Left& l, const Right& defaultValue) const { return fromLeft(l, defaultValue); } + Left to(const Right& r) const { return toLeft(r); } + Left to(const Right& r, const Left& defaultValue) const { return toLeft(r, defaultValue); } + Right to(const Left& l) const { return toRight(l); } + Right to(const Left& l, const Right& defaultValue) const { return toRight(l, defaultValue); } + + bool remove(const Left& l) { removeLeft(l); } + bool remove(const Right& r) { removeRight(r); } + bool removeLeft(const Left& l) { return remove(mL2R, mR2L, l); } + bool removeRight(const Right& r) { return remove(mR2L, mL2R, r); } + + template + requires bimap_predicate + qsizetype removeIf(Predicate pred) { return _QxBimapPrivate::_erase_if(*this, pred); } + + Right takeRight(const Left& l) + { + Right r = fromLeft(l); + removeLeft(l); + return r; + } + + Left takeLeft(const Right& r) + { + Left l = fromRight(r); + removeRight(r); + return l; + } + + Right take(const Left& l) requires asymmetric_bimap { return takeRight(l); } + Left take(const Right& r) requires asymmetric_bimap { return takeLeft(r); } + + void swap(Bimap& other) + { + mL2R.swap(other.mL2R); + mR2L.swap(other.mR2L); + } + + qsizetype size() const { return mL2R.size(); } + qsizetype count() const { return size(); } + bool isEmpty() const { return size() == 0; } + bool empty() const { return isEmpty(); } + float load_factor() const { return mL2R.load_factor(); } + + qsizetype capacity() const { return mL2R.capacity(); } + void clear() { mL2R.clear(); mR2L.clear(); } + void reserve(qsizetype size) { mL2R.reserve(size); mR2L.reserve(size); } + void squeeze() { mL2R.squeeze(); mR2L.squeeze(); } + + QList lefts() const { return mL2R.keys(); } + QList rights() const { return mR2L.keys(); } + + // Doc'ed here cause doxygen struggles with this one being separate + /*! + * Returns a list containing all of relationships in the bimap, in an arbitrary 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 lefts() and rights(). + */ + QList> relationships() const + { + QList> rel; + for(auto [k, v] : mL2R.asKeyValueRange()) + rel.append(std::make_pair(k, *v)); + } + +//-Operators--------------------------------------------------------------------------------------------- +public: + /* TODO: Having non-const versions of these that return a reference would require + * const_cast<>'ing away the constness of the key of the "other" map, and I'm not + * sure if modifying that reference directly instead of using QHash's methods would + * break the hash or not. + */ + Right operator[](const Left& l) const requires asymmetric_bimap + { + /* Alternatively these [] operators could insert a default constructed pair opposite if the + * key is not found, like QHash::operator[]() does by using our insert function (to handle + * both maps), but for now we do this. + */ + if(!mL2R.contains(l)) + throw std::invalid_argument("Access into bimap with a value it does not contain!"); + return *mL2R[l]; + } + + Left operator[](const Right& r) const requires asymmetric_bimap + { + if(!mR2L.contains(r)) + throw std::invalid_argument("Access into bimap with a value it does not contain!"); + return *mR2L[r]; + } + + bool operator==(const Bimap& other) const + { + const auto& oL2R = other.mL2R; + for (auto [l, rp] : mL2R.asKeyValueRange()) + if(!oL2R.contains(l) || *rp != *oL2R[l]) + return false; + + return true; + } + + bool operator!=(const Bimap& 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 bimap. + * + * The function supports predicates which take either an argument of type Bimap::const_iterator, + * or an argument of type std::pair. + * + * Returns the number of elements removed, if any. + */ +template +qsizetype erase_if(Bimap& bimap, Predicate pred) { return _QxBimapPrivate::_erase_if(bimap, pred); } + +} + +#endif // QX_BIMAP_H diff --git a/lib/core/src/qx-bimap.dox b/lib/core/src/qx-bimap.dox new file mode 100644 index 00000000..8ac35363 --- /dev/null +++ b/lib/core/src/qx-bimap.dox @@ -0,0 +1,703 @@ +namespace Qx +{ + +/*! + * @concept asymmetric_bimap + * @brief Specifies that a bimap has different Left and Right types. + * + * Satisfied if @c Left is not the same as @c Right. + */ + +/*! + * @concept bimap_iterator_predicate + * @brief Specifies that a predicate is a valid, iterator based predicate for a bimap. + * + * Satisfied if the predicate takes a Qx::Bimap::const_iterator and returns @c bool. + */ + +/*! + * @concept bimap_pair_predicate + * @brief Specifies that a predicate is a valid, pair based predicate for a bimap. + * + * Satisfied if the predicate takes a std::pair and returns @c bool. + */ + +/*! + * @concept bimap_predicate + * @brief Specifies that a predicate is a valid predicate for a bimap. + * + * Satisfied if the predicate satisfies bimap_iterator_predicate or bimap_pair_predicate. + */ + +//=============================================================================================================== +// Bimap +//=============================================================================================================== + +/*! + * @class Bimap qx/core/qx-bimap.h + * @ingroup qx-core + * + * @brief The Bimap template class offers a rudimentary bi-directional associative map. + * + * Qx::Bimap is like QHash, except that instead of Key and Value there is + * Left and Right, meaning that no neither type in any specialization of the container is more + * significant than the other. Lookup of one of the "side's" values using the other is possible + * via fromLeft(), fromRight(), and other similarly named functions. + * + * Both the Left and Right types must provide operator==() and a global qHash() overload. + */ + +//-Aliases-------------------------------------------------------------------------------------------------- +//Public: +/*! + * @typedef Bimap::left_type + * + * Typedef for Left. + */ + +/*! + * @typedef Bimap::right_type + * + * Typedef for Right. + */ + +/*! + * @typedef Bimap::ConstIterator + * + * Qt-style synonym for Bimap::const_iterator. + */ + +//-Constructor---------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn Bimap::Bimap() + * + * Creates an empty bimap. + * + * @sa clear(). + */ + +/*! + * @fn Bimap::Bimap(std::initializer_list> list) + * + * Creates a bimap with a copy of each of the elements in the initializer list @a list. + */ + +//-Instance Functions---------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn const_iterator Bimap::begin() const + * + * Same as constBegin(). + */ + +/*! + * @fn const_iterator Bimap::cbegin() const + * + * Same as constBegin(). + */ + +/*! + * @fn const_iterator Bimap::constBegin() const + * + * Returns an STL-style iterator pointing to the first relationship in the bimap. + * + * @warning Returned iterators/references should be considered invalidated the next time you call + * a non-const function on the bimap, or when the bimap is destroyed. + * + * @sa constEnd(). + */ + +/*! + * @fn const_iterator Bimap::end() const + * + * Same as constEnd(). + */ + +/*! + * @fn const_iterator Bimap::cend() const + * + * Same as constEnd(). + */ + +/*! + * @fn const_iterator Bimap::constEnd() const + * + * Returns an STL-style iterator pointing to the first relationship in the bimap. + * + * @warning Returned iterators/references should be considered invalidated the next time you call + * a non-const function on the bimap, or when the bimap is destroyed. + * + * @sa constBegin(). + */ + +/*! + * @fn const_iterator Bimap::constFind(const Left& l) const + * + * Same as constFindLeft(). + */ + +/*! + * @fn const_iterator Bimap::constFind(const Right& l) const + * + * Same as constFindRight(). + */ + +/*! + * @fn const_iterator Bimap::constFindLeft(const Left& l) const + * + * Returns an iterator pointing to the relationship with the Left value @a l in the bimap. + * + * If the bimaps contains no relationship with the Left value, the function returns constEnd(). + * + * @warning Returned iterators/references should be considered invalidated the next time you call + * a non-const function on the bimap, or when the bimap is destroyed. + */ + +/*! + * @fn const_iterator Bimap::constFindRight(const Left& l) const + * + * Returns an iterator pointing to the relationship with the Right value @a r in the bimap. + * + * If the bimaps contains no relationship with the Right value, the function returns constEnd(). + * + * @warning Returned iterators/references should be considered invalidated the next time you call + * a non-const function on the bimap, or when the bimap is destroyed. + */ + +/*! + * @fn const_iterator Bimap::find(const Left& l) const + * + * Same as constFindLeft(). + */ + +/*! + * @fn const_iterator Bimap::find(const Right& l) const + * + * Same as constFindRight(). + */ + +/*! + * @fn const_iterator Bimap::findLeft(const Left& l) const + * + * Same as constFindLeft(). + */ + +/*! + * @fn const_iterator Bimap::findRight(const Right& l) const + * + * Same as constFindRight(). + */ + +/*! + * @fn const_iterator Bimap::erase(const_iterator pos) + * + * Removes the (Left, Right) pair associated with the iterator @a pos from the bimap, + * and returns an iterator to the next relationship in the bimap. + * + * @warning Returned iterators/references should be considered invalidated the next time you call + * a non-const function on the bimap, or when the bimap is destroyed. + * + * @sa remove(), take() and find(). + */ + +/*! + * @fn void Bimap::insert(const Bimap& other) + * + * Inserts all the relationships in the other bimap into this bimap. + * + * If a Left or Right value from any relationship is common to both bimaps, the relationship containing + * then will be replaced with the relation that contains said value(s) stored in other. + */ + +/*! + * @fn const_iterator Bimap::insert(const Left& l, const Right& r) + * + * Inserts a new relationship between the Left value @a l and Right value @a r. + * + * If there is already a relationship for either value, that relationship is + * removed, effectively replacing it with the new relationship. + * + * Returns an iterator pointing to the new relationship. + * + * @warning Returned iterators/references should be considered invalidated the next time you call + * a non-const function on the bimap, or when the bimap is destroyed. + */ + +/*! + * @fn bool Bimap::containsLeft(const Left& l) const + * + * Returns @c true if the bimap contains a relationship with the Left value @a l; otherwise, + * returns @c false. + * + * @sa containsRight() and count(). + */ + +/*! + * @fn bool Bimap::containsRight(const Right& r) const + * + * Returns @c true if the bimap contains a relationship with the Right value @a r; otherwise, + * returns @c false. + * + * @sa containsLeft() and count(). + */ + +/*! + * @fn Right Bimap::fromLeft(const Left& l) const + * + * Returns the Right value associated with Left value @a l. + * + * If the bimap does not contain a relationship with @a l, a default constructed Right + * value is returned. + * + * @sa fromRight(). + */ + +/*! + * @fn Right Bimap::fromLeft(const Left& l, const Right& defaultValue) const + * + * @overload + * + * Returns the Right value associated with Left value @a l. + * + * If the bimap does not contain a relationship with @a l, @a defaultValue is returned. + */ + +/*! + * @fn Left Bimap::fromRight(const Right& r) const + * + * Returns the Left value associated with Right value @a r. + * + * If the bimap does not contain a relationship with @a r, a default constructed Left + * value is returned. + * + * @sa fromLeft(). + */ + +/*! + * @fn Left Bimap::fromRight(const Right& r, const Left& defaultValue) const + * + * @overload + * + * Returns the Left value associated with Right value @a r. + * + * If the bimap does not contain a relationship with @a r, @a defaultValue is returned. + */ + +/*! + * @fn Right Bimap::from(const Left& l) const + * + * Same as fromLeft(). + */ + +/*! + * @fn Right Bimap::from(const Left& l, const Right& defaultValue) const + * + * Same as fromLeft(const Left&, const Right&). + */ + +/*! + * @fn Left Bimap::from(const Right& r) const + * + * Same as fromRight(). + */ + +/*! + * @fn Left Bimap::from(const Right& r, const Left& defaultValue) const + * + * Same as fromLeft(const Right&, const Left&). + */ + +/*! + * @fn Left Bimap::toLeft(const Right& r) const + * + * Same as fromRight(). + * + * @sa toRight(). + */ + +/*! + * @fn Left Bimap::toLeft(const Right& r, const Left& defaultValue) const + * + * @overload + */ + +/*! + * @fn Right Bimap::toRight(const Left& l) const + * + * Same as fromLeft(). + * + * @sa toLeft(). + */ + +/*! + * @fn Right Bimap::toRight(const Left& l, const Right& defaultValue) const + * + * @overload + */ + +/*! + * @fn Left Bimap::to(const Right& r) const + * + * Same as toLeft(). + * + * @sa toRight(). + */ + +/*! + * @fn Left Bimap::to(const Right& r, const Left& defaultValue) const + * + * @overload + */ + +/*! + * @fn Right Bimap::to(const Left& l) const + * + * Same as toRight(). + * + * @sa toLeft(). + */ + +/*! + * @fn Right Bimap::to(const Left& l, const Right& defaultValue) const + * + * @overload + */ + +/*! + * @fn bool Bimap::remove(const Left& l) + * + * Same as removeLeft(). + */ + +/*! + * @fn bool Bimap::remove(const Right& r) + * + * Same as removeRight(). + */ + +/*! + * @fn bool Bimap::removeLeft(const Left& l) + * + * Removes the relationship containing the Left value @a l from the bimap if present and + * returns @c true; otherwise, returns @c false. + * + * @sa removeRight() and clear(). + */ + +/*! + * @fn bool Bimap::removeRight(const Right& r) + * + * Removes the relationship containing the Right value @a r from the bimap if present and + * returns @c true; otherwise, returns @c false. + * + * @sa removeLeft() and clear(). + */ + +/*! + * @fn qsizetype Bimap::removeIf(Predicate pred) + * + * Removes all elements for which the predicate pred returns true from the bimap. + * + * The function supports predicates which take either an argument of type Bimap::const_iterator, + * or an argument of type std::pair. + * + * Returns the number of elements removed, if any. + * + * @sa clear() and take(). + */ + +/*! + * @fn Right Bimap::takeRight(const Left& l) + * + * Removes the relationship with the Left value @a l from the bimap and returns the Right value + * associated with it. + * + * If such a relationship does not exist in the bimap, the function simply returns a default-constructed value + * + * If you don't use the return value, remove() is more efficient. + * + * @sa remove(). + */ + +/*! + * @fn Left Bimap::takeLeft(const Right& r) + * + * Removes the relationship with the Right value @a r from the bimap and returns the Left value + * associated with it. + * + * If such a relationship does not exist in the bimap, the function simply returns a default-constructed value + * + * If you don't use the return value, remove() is more efficient. + * + * @sa remove(). + */ + +/*! + * @fn Right Bimap::take(const Left& l) + * + * Same as takeRight(). + */ + +/*! + * @fn Left Bimap::take(const Right& r) + * + * Same as takeLeft(). + */ + + +/*! + * @fn void Bimap::swap(Bimap& other) + * + * Swaps bimap @a other with this bimap. This operation is very fast and never fails. + */ + +/*! + * @fn qsizetype Bimap::size() const + * + * Returns the number of relations in the bimap. + * + * @sa isEmpty() and count(). + */ + +/*! + * @fn qsizetype Bimap::count() const + * + * Same as size(). + */ + +/*! + * @fn bool Bimap::isEmpty() const + * + * Returns @c true if the bimap contains no relations; otherwise, returns @c false. + * + * @sa size(). + */ + +/*! + * @fn bool Bimap::empty() const + * + * Same as isEmpty(). + */ + +/*! + * @fn float Bimap::load_factor() const + * + * Returns the current load factor of the Bimap's internal table. This is the same as + * capacity()/size(). The implementation used will aim to keep the load factor + * between 0.25 and 0.5. This avoids having too many table collisions that would + * degrade performance. + * + * Even with a low load factor, the implementation of the bimap table has a very low memory overhead. + * + * This method purely exists for diagnostic purposes and you should rarely need to call it yourself. + * + * @sa reserve() and squeeze(). + */ + +/*! + * @fn qsizetype Bimap::capacity() const + * + * Returns the number of buckets in the bimap's internal table. + * + * The sole purpose of this function is to provide a means of fine tuning Bimap's memory + * usage. In general, you will rarely ever need to call this function. If you want to know + * how many items are in the bimap, call size(). + * + * @sa reserve() and squeeze(). + */ + +/*! + * @fn void Bimap::clear() + * + * Removes all relations from the bimap and frees up all memory used by it. + * + * @sa remove(). + */ + +/*! + * @fn void Bimap::reserve() + * + * Ensures that the bimap's internal table has space to store at least @a size items without + * having to grow the table. + * + * This function is useful for code that needs to build a huge bimap and wants to avoid repeated + * reallocation. + * + * In general, you will rarely ever need to call this function. Bimap's internal table + * automatically grows to provide good performance without wasting too much memory. + * + * @sa squeeze() and capacity(). + */ + +/*! + * @fn void Bimap::squeeze() + * + * Reduces the size of the Bimap's internal table to save memory. + * + * The sole purpose of this function is to provide a means of fine tuning Bimap's memory usage. + * In general, you will rarely ever need to call this function. + * + * @sa reserve() and capacity(). + */ + +/*! + * @fn QList Bimap::lefts() const + * + * Returns a list containing all of the Left values in the bimap, in an arbitrary 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 rights() and fromRight(). + */ + +/*! + * @fn QList Bimap::rights() const + * + * Returns a list containing all of the Right values in the bimap, in an arbitrary 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 lefts() and fromLeft(). + */ + +//-Operators--------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn Right Bimap::operator[](const Left& l) const + * + * Returns the Right value associated with the Left value @a l. + * + * Throws `std::invalid_argument()` if the bimap does not contain a relationship with the Left value @a l. + * + * @sa fromLeft() and fromRight(). + */ + +/*! + * @fn Left Bimap::operator[](const Right& r) const + * + * Returns the Left value associated with the Right value @a r. + * + * Throws `std::invalid_argument()` if the bimap does not contain a relationship with the Right value @a r. + * + * @sa fromLeft() and fromRight(). + */ + +/*! + * @fn bool Bimap::operator==(const Bimap& other) const + * + * Returns @c true if @a other is equal to this bimap; otherwise, returns @c false. + * + * Two bimap's are considered equal if they contain the same (right, left) relationships. + * + * This function requires the Right and Left types to implement operator==(). + * + * @sa operator!=(). + */ + +/*! + * @fn bool Bimap::operator!=(const Bimap& other) const + * + * Returns @c true if @a other is not equal to this bimap; otherwise, returns @c false. + * + * Two bimap's are considered equal if they contain the same (right, left) relationships. + * + * This function requires the Right and Left types to implement operator==(). + * + * @sa operator==(). + */ + +//=============================================================================================================== +// Bimap::const_iterator +//=============================================================================================================== + +/*! + * @class Bimap::const_iterator qx/core/qx-bimap.h + * @ingroup qx-core + * + * @brief The Bimap::const_iterator class provides an STL-style const iterator for Bimap. + * + * Bimap::const_iterator allows you to iterate over a Bimap. + * + * The default Bimap::const_iterator constructor creates an uninitialized iterator. You must initialize it using + * a Bimap function like Bimap::cbegin(), Bimap::cend(), or Bimap::constFind() before you can start iterating. + * + * Bimap stores its relationships in an arbitrary order. + * + * Multiple iterators can be used on the same bimap. However, be aware that any modification performed directly on + * the Bimap (inserting and removing items) can cause the iterators to become invalid. + * + * Inserting relationships into the bimap or calling methods such as Bimap::reserve() or Bimap::squeeze() can + * invalidate all iterators pointing into the bimap. Iterators are guaranteed to stay valid only as long as the + * Bimap doesn't have to grow/shrink its internal table. Using any iterator after a rehashing operation has + * occurred will lead to undefined behavior. + * + * You can however safely use iterators to remove entries from the bimap using the Bimap::erase() method. + * This function can safely be called while iterating, and won't affect the order of items in the bimap. + * + * @warning Iterators on this container do not work exactly like STL-iterators. You should avoid copying a bimap + * while iterators are active on it. For more information, read Qt's "Implicit sharing iterator problem". + */ + +//-Constructor---------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn Bimap::const_iterator::const_iterator() + * + * Constructs an uninitialized iterator. + * + * Functions like left(), right(), and operator++() must not be called on an uninitialized iterator. + * Use operator=() to assign a value to it before using it. + * + * @sa Bimap::constBegin() and Bimap::constEnd(). + */ + +//-Instance Functions---------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn const Left& Bimap::const_iterator::left() const + * + * Returns the current relationship's Left value. + */ + +/*! + * @fn const Right& Bimap::const_iterator::right() const + * + * Returns the current relationship's Right value. + */ + +//-Operators--------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn bool Right& Bimap::const_iterator::operator==(const const_iterator& other) const + * + * Returns @c true if @a other points to the same relationship as this iterator; otherwise, returns @c false. + */ + +/*! + * @fn std::pair Bimap::const_iterator::operator*() const + * + * Returns the current relationship. + */ + +/*! + * @fn const_iterator Bimap::const_iterator::operator++() + * + * The prefix @c ++ operator @c (++i) advances the iterator to the next relationship in the bimap and + * returns an iterator to the new current relationship. + * + * Calling this function on Bimap::constEnd() leads to undefined results. + */ + +/*! + * @fn const_iterator Bimap::const_iterator::operator++(int) + * + * The postfix @c ++ operator @c (i++) advances the iterator to the next relationship in the bimap and + * returns an iterator to the previously current relationship. + * + * Calling this function on Bimap::constEnd() leads to undefined results. + */ + +}