Compare commits

..

2 Commits

2 changed files with 55 additions and 19 deletions

34
headers/Concepts.hpp Normal file
View File

@@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: Dora "cat" <cat@thenight.club>
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef GUARD_TOURMALINE_CONCEPTS_H
#define GUARD_TOURMALINE_CONCEPTS_H
#include <concepts>
#include <functional>
namespace Tourmaline::Concepts {
template <typename T>
concept Hashable = std::equality_comparable<T> && requires(T x) {
{ std::hash<T>{}(x) } -> std::convertible_to<std::size_t>;
};
template <typename Base, typename Type1, typename Type2>
concept Either = std::same_as<Base, Type1> || std::same_as<Base, Type2>;
// Oh C++ and your jank
template <typename Base, typename Type1, typename Type2> struct _opposite_of {
using type = std::conditional_t<std::is_same_v<Base, Type1>, Type2, Type1>;
};
template <typename Base, typename Type1, typename Type2>
requires Either<Base, Type1, Type2>
using OppositeOf = _opposite_of<Base, Type1, Type2>::type;
} // namespace Tourmaline::Concepts
#endif

View File

@@ -8,8 +8,8 @@
*/ */
#ifndef GUARD_TOURMALINE_DUALKEYMAP_H #ifndef GUARD_TOURMALINE_DUALKEYMAP_H
#define GUARD_TOURMALINE_DUALKEYMAP_H #define GUARD_TOURMALINE_DUALKEYMAP_H
#include "../Concepts.hpp"
#include "../Systems/Logging.hpp" #include "../Systems/Logging.hpp"
#include "Concepts.hpp"
#include <array> #include <array>
#include <cmath> #include <cmath>
@@ -25,17 +25,16 @@
#include <vector> #include <vector>
namespace Tourmaline::Containers { namespace Tourmaline::Containers {
template <Hashable AKey, Hashable BKey, typename Value, template <Concepts::Hashable AKey, Concepts::Hashable BKey, typename Value,
uint64_t baseReservation = 2048> uint64_t baseReservation = 2048>
class DualkeyMap { class DualkeyMap {
public: public:
// Return Types // Return Types
template <typename OppositeKey, std::size_t resultKeyCount, template <typename OppositeKey, std::size_t Count>
std::size_t resultValueCount> requires Concepts::Either<OppositeKey, AKey, BKey>
requires Either<OppositeKey, AKey, BKey>
using MultiQueryResult = using MultiQueryResult =
std::pair<std::array<OppositeKey, resultKeyCount>, std::pair<const OppositeKey &,
std::array<std::reference_wrapper<Value>, resultValueCount>>; std::array<std::reference_wrapper<Value>, Count>>;
using QueryResult = using QueryResult =
std::pair<std::variant<std::monostate, std::reference_wrapper<const AKey>, std::pair<std::variant<std::monostate, std::reference_wrapper<const AKey>,
std::reference_wrapper<const BKey>>, std::reference_wrapper<const BKey>>,
@@ -197,17 +196,19 @@ public:
return finishedQuery; return finishedQuery;
} }
template <typename Key, std::size_t keyCount> template <typename Key,
requires Either<Key, AKey, BKey> typename OppositeKey = Concepts::OppositeOf<Key, AKey, BKey>,
std::size_t keyCount>
requires Concepts::Either<Key, AKey, BKey>
[[nodiscard("Discarding a very expensive query!")]] [[nodiscard("Discarding a very expensive query!")]]
int QueryWithAll(const Key (&keys)[keyCount]) { int QueryWithAll(const Key (&keys)[keyCount]) {
auto queryResults = queryWithMany<Key>(keys); std::vector<unprocessedMultiQueryResult<OppositeKey, keyCount>>
queryResults = queryWithMany<Key>(keys);
// You could very well use auto here but this helps // You could very well use auto here but this helps
// with LSP hints // with LSP hints
for (const unprocessedMultiQueryResult< for (const unprocessedMultiQueryResult<OppositeKey, keyCount> &queryRecord :
std::conditional_t<std::is_same_v<Key, AKey>, BKey, AKey>, queryResults) {
keyCount> &queryRecord : queryResults) {
if (queryRecord.howManyFound == keyCount) { if (queryRecord.howManyFound == keyCount) {
} }
} }
@@ -269,9 +270,10 @@ private:
std::stack<std::size_t> graveyard; std::stack<std::size_t> graveyard;
// Interal querying // Interal querying
template <typename Key, std::size_t keyCount> template <typename Key,
inline std::vector<unprocessedMultiQueryResult< typename OppositeKey = Concepts::OppositeOf<Key, AKey, BKey>,
std::conditional_t<std::is_same_v<Key, AKey>, BKey, AKey>, keyCount>> std::size_t keyCount>
inline std::vector<unprocessedMultiQueryResult<OppositeKey, keyCount>>
queryWithMany(const Key (&keys)[keyCount]) { queryWithMany(const Key (&keys)[keyCount]) {
constexpr bool searchingInFirstKey = std::is_same_v<Key, AKey>; constexpr bool searchingInFirstKey = std::is_same_v<Key, AKey>;
@@ -299,10 +301,10 @@ private:
uint64_t hashToCompare; uint64_t hashToCompare;
Key *keyToCompare; Key *keyToCompare;
std::conditional_t<searchingInFirstKey, BKey *, AKey *> resultKey; OppositeKey *resultKey;
std::vector<unprocessedMultiQueryResult< std::vector<unprocessedMultiQueryResult<OppositeKey, keyCount>>
std::conditional_t<searchingInFirstKey, BKey, AKey>, keyCount>>
queryResults; queryResults;
for (DualkeyHash *hash : hashList) { for (DualkeyHash *hash : hashList) {
// The hell of doing 2 conditions with similar logics in // The hell of doing 2 conditions with similar logics in
// the same logical block // the same logical block