-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Bimap, a basic bi-directional map
- Loading branch information
1 parent
3ab133c
commit d3c0d87
Showing
3 changed files
with
381 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#ifndef QX_BIMAP_H | ||
#define QX_BIMAP_H | ||
|
||
// Qt Includes | ||
#include <QHash> | ||
|
||
namespace Qx | ||
{ | ||
|
||
template<typename Left, typename Right> | ||
class Bimap | ||
{ | ||
//-Instance Variables------------------------------------------------------------------------------------------- | ||
private: | ||
QHash<Left, Right*> mL2R; | ||
QHash<Right, Left*> mR2L; | ||
|
||
//-Constructor-------------------------------------------------------------------------------------------------- | ||
public: | ||
Bimap() {} | ||
|
||
Bimap(std::initializer_list<std::pair<Left, Right>> list) | ||
{ | ||
reserve(list.size()); | ||
for(auto it = list.cbegin(); it != list.cend(); ++it) | ||
insert(it->first, it->second); | ||
} | ||
|
||
//-Class Functions------------------------------------------------------------------------------------------- | ||
private: | ||
template<typename AMap, typename BMap, typename V> | ||
void removeCrossReference(AMap& am, BMap& bm, const V& v) | ||
{ | ||
Q_ASSERT(&am != &bm); | ||
if(am.conains(v)) | ||
bm.remove(*am[v]); | ||
} | ||
|
||
template<typename AMap, typename BMap, typename V> | ||
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: | ||
bool existingRelation(const Left& l, const Right& r) { return mL2R.contains(l) && *mL2R[l] == r; } | ||
|
||
void removeCrossReferences(const Left& l, const Right& r) | ||
{ | ||
// Remove to-be stale relations | ||
removeCrossReference(mL2R, mR2L, l); | ||
removeCrossReference(mR2L, mL2R, r); | ||
} | ||
|
||
void 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(); | ||
} | ||
|
||
public: | ||
void insert(const Left& l, const Right& r) | ||
{ | ||
if(existingRelation(l, r)) | ||
return; | ||
|
||
removeCrossReferences(l, r); | ||
addOrUpdateRelation(l, r); | ||
} | ||
|
||
bool containsLeft(const Left& l) { return mL2R.contains(l); } | ||
bool containsRight(const Right& r) { return mR2L.contains(r); } | ||
|
||
Right fromLeft(const Left& l) | ||
{ | ||
return mL2R.contains(l) ? *mL2R[l] : Right(); | ||
} | ||
|
||
Right fromLeft(const Left& l, const Right& defaultValue) | ||
{ | ||
return mL2R.contains(l) ? *mL2R[l] : defaultValue; | ||
} | ||
|
||
Left fromRight(const Right& l) | ||
{ | ||
return mR2L.contains(l) ? *mR2L[l] : Left(); | ||
} | ||
|
||
Left fromRight(const Right& l, const Left& defaultValue) | ||
{ | ||
return mR2L.contains(l) ? *mR2L[l] : defaultValue; | ||
} | ||
|
||
bool removeLeft(const Left& l) { return remove(mL2R, mR2L, l); } | ||
bool removeRight(const Right& r) { return remove(mR2L, mL2R, r); } | ||
|
||
qsizetype size() const { return mL2R.size(); } | ||
qsizetype count() const { return size(); } | ||
bool isEmpty() const { return size() == 0; } | ||
bool empty() const { return isEmpty(); } | ||
|
||
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<Left> lefts() const { return mL2R.keys(); } | ||
QList<Right> rights() const { return mR2L.keys(); } | ||
|
||
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; | ||
}; | ||
|
||
|
||
} | ||
|
||
#endif // QX_BIMAP_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
namespace Qx | ||
{ | ||
//=============================================================================================================== | ||
// 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<Left, Right> is like QHash<Key, T>, 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() and fromRight(). | ||
* | ||
* @warning This class is somewhat incomplete as it currently does not have iterators, nor | ||
* a copy constructor/assignment operator implemented. | ||
*/ | ||
|
||
//-Constructor---------------------------------------------------------------------------------------------- | ||
//Public: | ||
/*! | ||
* @fn Bimap<Left, Right>::Bimap() | ||
* | ||
* Creates an empty bimap. | ||
* | ||
* @sa clear(). | ||
*/ | ||
|
||
/*! | ||
* @fn Bimap<Left, Right>::Bimap(std::initializer_list<std::pair<Left, Right>> list) | ||
* | ||
* Creates a bimap with a copy of each of the elements in the initializer list @a list. | ||
*/ | ||
|
||
//-Class Functions---------------------------------------------------------------------------------------------- | ||
//Public: | ||
/*! | ||
* @fn void Bimap<Left, Right>::insert(const Left& l, const Right& r) | ||
* | ||
* Inserts a new relation between the Left value @a l and Right value @a r. | ||
* | ||
* If there is already a relationship for either value, that relationship is | ||
* removed. | ||
*/ | ||
|
||
/*! | ||
* @fn bool Bimap<Left, Right>::containsLeft(const Left& l) | ||
* | ||
* 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<Left, Right>::containsRight(const Right& r) | ||
* | ||
* 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<Left, Right>::fromLeft(const Left& l) | ||
* | ||
* 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<Left, Right>::fromLeft(const Left& l, const Right& defaultValue) | ||
* | ||
* @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<Left, Right>::fromRight(const Right& r) | ||
* | ||
* 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<Left, Right>::fromRight(const Right& r, const Left& defaultValue) | ||
* | ||
* @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 bool Bimap<Left, Right>::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<Left, Right>::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<Left, Right>::size() const | ||
* | ||
* Returns the number of relations in the bimap. | ||
* | ||
* @sa isEmpty() and count(). | ||
*/ | ||
|
||
/*! | ||
* @fn qsizetype Bimap<Left, Right>::count() const | ||
* | ||
* Same as size(). | ||
*/ | ||
|
||
/*! | ||
* @fn bool Bimap<Left, Right>::isEmpty() const | ||
* | ||
* Returns @c true if the bimap contains no relations; otherwise, returns @c false. | ||
* | ||
* @sa size(). | ||
*/ | ||
|
||
/*! | ||
* @fn bool Bimap<Left, Right>::empty() const | ||
* | ||
* Same as isEmpty(). | ||
*/ | ||
|
||
/*! | ||
* @fn qsizetype Bimap<Left, Right>::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<Left, Right>::clear() | ||
* | ||
* Removes all relations from the bimap and frees up all memory used by it. | ||
* | ||
* @sa remove(). | ||
*/ | ||
|
||
/*! | ||
* @fn void Bimap<Left, Right>::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<Left, Right>::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<Left> Bimap<Left, Right>::lefts() | ||
* | ||
* 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. | ||
* | ||
* @sa rights() and fromRight(). | ||
*/ | ||
|
||
/*! | ||
* @fn QList<Right> Bimap<Left, Right>::rights() | ||
* | ||
* 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. | ||
* | ||
* @sa lefts() and fromLeft(). | ||
*/ | ||
|
||
/*! | ||
* @fn bool Bimap<Left, Right>::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<Left, Right>::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==(). | ||
*/ | ||
|
||
} |