From 7167ce41b61d2ba2cdb526777a4233eb84a3b66a Mon Sep 17 00:00:00 2001 From: Unit 193 Date: Sat, 6 Dec 2014 17:33:25 -0500 Subject: Imported Upstream version 2.99.6 --- SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h | 362 ++++++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h (limited to 'SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h') diff --git a/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h new file mode 100644 index 0000000..65c907b --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h @@ -0,0 +1,362 @@ +#ifndef BISTRHASH_H +#define BISTRHASH_H + +#include "bihash.h" +#include +#include + +/** + * @brief Bi-directional string-oriented hash. + * + * This hash is very similar to BiHash, except it always uses QString + * for both left and right values. Given that, it also provides Qt::CaseSensitivity support + * for any operations accepting values in parameters. + * + * Just like BiHash, the BiStrHash doesn't provide operator[]. For more details see BiHash. + */ +class BiStrHash +{ + public: + /** + * @brief Creates empty hash. + */ + BiStrHash() {} + + /** + * @brief Creates pre-initialized hash. + * @param list C++11 style initializer list, like: {{"x"="y"}, {"a"="b"}} + */ + BiStrHash(std::initializer_list> list) + { + hash = QHash(list); + initInvertedAndLower(); + } + + /** + * @brief Creates BiStrHash basing on QHash. + * @param other QHash to copy values from. + * + * Any conflicting values from the \p other hash will overwrite + * current values in the hash. + */ + BiStrHash(const QHash & other) + { + unite(other); + } + + /** + * @brief Copy constructor. + * @param other Other hash to copy. + */ + BiStrHash(const BiStrHash& other) : hash(other.hash), inverted(other.inverted), + lowerHash(other.lowerHash), lowerInverted(other.lowerInverted) {} + + /** + * @brief Inserts entry into the hash. + * @param left Left-side value to insert. + * @param right Right-side value to insert. + * + * Inserting to the hash is done in case-insensitive manner, hence any conflicting + * values matched with case insensitive method will be replaced with the new entry. + */ + void insert(const QString& left, const QString& right) + { + if (lowerHash.contains(left.toLower())) + removeLeft(left, Qt::CaseInsensitive); + + if (lowerInverted.contains(right.toLower())) + removeRight(right, Qt::CaseInsensitive); + + inverted.insert(right, left); + hash.insert(left, right); + lowerHash.insert(left.toLower(), left); + lowerInverted.insert(right.toLower(), right); + } + + /** + * @brief Tests if given value is in the left values of the hash. + * @param left Left-side value to match. + * @param cs Case sensitivity flag. + * @return true if the key was matched in left side values, or false otherwise. + */ + bool containsLeft(const QString& left, Qt::CaseSensitivity cs = Qt::CaseSensitive) + { + if (cs == Qt::CaseSensitive) + return hash.contains(left); + else + return lowerHash.contains(left.toLower()); + } + + /** + * @brief Tests if given value is in the right values of the hash. + * @param right Right-side value to match. + * @param cs Case sensitivity flag. + * @return true if the key was matched in right side values, or false otherwise. + */ + bool containsRight(const QString& right, Qt::CaseSensitivity cs = Qt::CaseSensitive) + { + if (cs == Qt::CaseSensitive) + return inverted.contains(right); + else + return lowerInverted.contains(right.toLower()); + } + + /** + * @brief Removes entry matching given value in left-side values. + * @param left Left-side value to match. + * @param cs Case sensitivity flag. + * @return Number of entries removed. + */ + int removeLeft(const QString& left, Qt::CaseSensitivity cs = Qt::CaseSensitive) + { + if (cs == Qt::CaseSensitive) + { + if (!hash.contains(left)) + return 0; + + inverted.remove(hash.value(left)); + hash.remove(left); + + return 1; + } + else + { + QString lowerLeft = left.toLower(); + if (!lowerHash.contains(lowerLeft)) + return 0; + + QString right = hash.value(lowerHash.value(lowerLeft)); + + hash.remove(inverted.value(right)); + inverted.remove(right); + lowerHash.remove(lowerLeft); + lowerInverted.remove(right.toLower()); + + return 1; + } + } + + /** + * @brief Removes entry matching given value in right-side values. + * @param right Right-side value to match. + * @param cs Case sensitivity flag. + * @return Number of entries removed. + */ + int removeRight(const QString& right, Qt::CaseSensitivity cs = Qt::CaseSensitive) + { + if (cs == Qt::CaseSensitive) + { + if (!inverted.contains(right)) + return 0; + + hash.remove(inverted.value(right)); + inverted.remove(right); + + return 1; + } + else + { + QString lowerRight = right.toLower(); + if (!lowerInverted.contains(lowerRight)) + return 0; + + QString left = inverted.value(lowerInverted.value(lowerRight)); + + inverted.remove(hash.value(left)); + hash.remove(left); + lowerHash.remove(left.toLower()); + lowerInverted.remove(lowerRight); + + return 1; + } + } + + /** + * @brief Removes entry from hash and returns it. + * @param left Left-side value to match. + * @param cs Case sensitivity flag. + * @return Right side value, or null string if the \p left was not matched. + */ + QString takeLeft(const QString& left, Qt::CaseSensitivity cs = Qt::CaseSensitive) + { + if (cs == Qt::CaseSensitive) + { + QString right = hash.take(left); + inverted.remove(right); + return right; + } + else + { + QString right = hash.take(lowerHash.take(left.toLower())); + inverted.remove(lowerInverted.take(right.toLower())); + return right; + } + } + + /** + * @brief Removes entry from hash and returns it. + * @param right Right-side value to match. + * @param cs Case sensitivity flag. + * @return Left side value, or null string if the \p left was not matched. + */ + QString takeRight(const QString& right, Qt::CaseSensitivity cs = Qt::CaseSensitive) + { + if (cs == Qt::CaseSensitive) + { + QString left = inverted.take(right); + hash.remove(left); + return left; + } + else + { + QString left = inverted.take(lowerInverted.take(right.toLower())); + hash.remove(lowerHash.take(left.toLower())); + return left; + } + } + + /** + * @brief Copies all entries from the other hash to this hash. + * @param other Other hash to copy values from. + * @return Reference to this hash, after update. + */ + BiStrHash& unite(const BiStrHash& other) + { + unite(other.hash); + return *this; + } + + /** + * @overload + */ + BiStrHash& unite(const QHash& other) + { + QHashIterator it(other); + while (it.hasNext()) + insert(it.next().key(), it.value()); + + return *this; + } + + /** + * @brief Finds right-side value by matching the left-side value. + * @param left Left-side value to match. + * @param cs Case sensitivity flag. + * @return Right-side value, or null string if left-side value was not matched. + */ + QString valueByLeft(const QString& left, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + { + if (cs == Qt::CaseSensitive) + return hash.value(left); + else + return hash.value(lowerHash.value(left.toLower())); + } + + /** + * @brief Finds left-side value by matching the right-side value. + * @param right Right-side value to match. + * @param cs Case sensitivity flag. + * @return Left-side value, or null string if right-side value was not matched. + */ + QString valueByRight(const QString& right, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + { + if (cs == Qt::CaseSensitive) + return inverted.value(right); + else + return inverted.value(lowerInverted.value(right.toLower())); + } + + /** + * @brief Gives all left-side values. + * @return List of values. + */ + QStringList leftValues() const + { + return hash.keys(); + } + + /** + * @brief Gives all right-side values. + * @return List of values. + */ + QStringList rightValues() const + { + return inverted.keys(); + } + + /** + * @brief Provides java-style iterator for this hash. + * @return Iterator object. + */ + QHashIterator iterator() const + { + return QHashIterator(hash); + } + + /** + * @brief Removes all entries from the hash. + */ + void clear() + { + hash.clear(); + inverted.clear(); + lowerHash.clear(); + lowerInverted.clear(); + } + + /** + * @brief Counts all entries in the hash. + * @return Number of entries in the hash. + */ + int count() const + { + return hash.count(); + } + + /** + * @brief Tests whether the hash is empty or not. + * @return true if the hash is empty, false otherwise. + */ + bool isEmpty() const + { + return hash.isEmpty(); + } + + private: + /** + * @brief Fills inverted and lower internal hashes basing on the main hash class member. + */ + void initInvertedAndLower() + { + QHashIterator it(hash); + while (it.hasNext()) + { + it.next(); + inverted[it.value()] = it.key(); + lowerHash[it.key().toLower()] = it.key(); + lowerInverted[it.value().toLower()] = it.value(); + } + } + + /** + * @brief Standard mapping - left to right. + */ + QHash hash; + + /** + * @brief Right to left mapping. + */ + QHash inverted; + + /** + * @brief Lower left to true left key mapping. + */ + QHash lowerHash; + + /** + * @brief Lower right to true right key mapping. + */ + QHash lowerInverted; +}; + +#endif // BISTRHASH_H -- cgit v1.2.3