Program Listing for File keys_set.hpp
↰ Return to documentation for file (include/caret_trace/keys_set.hpp)
// Copyright 2021 Research Institute of Systems Planning, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CARET_TRACE__KEYS_SET_HPP_
#include <functional>
#include <iostream>
#include <iterator>
#include <set>
#include <string>
#include <type_traits>
template <bool Cond, typename Then, typename Else>
struct if_
{
using type = Then;
};
template <typename Then, typename Else>
struct if_<false, Then, Else>
{
using type = Else;
};
// clang-format off
template<
typename T1,
typename T2 = std::false_type,
typename T3 = std::false_type,
typename T4 = std::false_type,
typename T5 = std::false_type,
typename T6 = std::false_type
>
// clang-format on
class HashableKeys
{
private:
using IsT1String = std::is_same<const char *, T1>;
using IsT2String = std::is_same<const char *, T2>;
using IsT3String = std::is_same<const char *, T3>;
using IsT4String = std::is_same<const char *, T4>;
using IsT5String = std::is_same<const char *, T5>;
using IsT6String = std::is_same<const char *, T6>;
// Store string literal as std::string
using T1_ = typename if_<IsT1String::value, std::string, T1>::type;
using T2_ = typename if_<IsT2String::value, std::string, T2>::type;
using T3_ = typename if_<IsT3String::value, std::string, T3>::type;
using T4_ = typename if_<IsT4String::value, std::string, T4>::type;
using T5_ = typename if_<IsT5String::value, std::string, T5>::type;
using T6_ = typename if_<IsT6String::value, std::string, T6>::type;
public:
explicit HashableKeys(T1 key1) : key1_(key1) {}
HashableKeys(T1 key1, T2 key2) : key1_(key1), key2_(key2) {}
HashableKeys(T1 key1, T2 key2, T3 key3) : key1_(key1), key2_(key2), key3_(key3) {}
HashableKeys(T1 key1, T2 key2, T3 key3, T4 key4)
: key1_(key1), key2_(key2), key3_(key3), key4_(key4)
{
}
HashableKeys(T1 key1, T2 key2, T3 key3, T4 key4, T5 key5)
: key1_(key1), key2_(key2), key3_(key3), key4_(key4), key5_(key5)
{
}
HashableKeys(T1 key1, T2 key2, T3 key3, T4 key4, T5 key5, T6 key6)
: key1_(key1), key2_(key2), key3_(key3), key4_(key4), key5_(key5), key6_(key6)
{
}
size_t hash() const
{
size_t res = 17;
if constexpr (std::true_type::value) {
res = res * 31 + std::hash<T1_>()(key1_);
}
if constexpr (!std::is_same<std::false_type, T2>::value) {
res = res * 31 + std::hash<T2_>()(key2_);
}
if constexpr (!std::is_same<std::false_type, T3>::value) {
res = res * 31 + std::hash<T3_>()(key3_);
}
if constexpr (!std::is_same_v<std::false_type, T4>) {
res = res * 31 + std::hash<T4_>()(key4_);
}
if constexpr (!std::is_same_v<std::false_type, T5>) {
res = res * 31 + std::hash<T5_>()(key5_);
}
if constexpr (!std::is_same_v<std::false_type, T6>) {
res = res * 31 + std::hash<T6_>()(key6_);
}
return res;
}
bool equal_to(const HashableKeys<T1, T2, T3, T4, T5, T6> & keys) const
{
if constexpr (!std::is_same_v<std::false_type, T6>) {
return key1_ == keys.key1_ && key2_ == keys.key2_ && key3_ == keys.key3_ &&
key4_ == keys.key4_ && key5_ == keys.key5_ && key6_ == keys.key6_;
} else if constexpr (!std::is_same_v<std::false_type, T5>) {
return key1_ == keys.key1_ && key2_ == keys.key2_ && key3_ == keys.key3_ &&
key4_ == keys.key4_ && key5_ == keys.key5_;
} else if constexpr (!std::is_same_v<std::false_type, T4>) {
return key1_ == keys.key1_ && key2_ == keys.key2_ && key3_ == keys.key3_ &&
key4_ == keys.key4_;
} else if constexpr (!std::is_same_v<std::false_type, T3>) {
return key1_ == keys.key1_ && key2_ == keys.key2_ && key3_ == keys.key3_;
} else if constexpr (!std::is_same_v<std::false_type, T2>) {
return key1_ == keys.key1_ && key2_ == keys.key2_;
} else {
return key1_ == keys.key1_;
}
}
bool operator<(const HashableKeys<T1, T2, T3, T4, T5, T6> & rhs) const
{
if (first() < rhs.first()) {
return true;
}
if constexpr (!std::is_same_v<std::false_type, T2>) {
if (second() < rhs.second()) {
return true;
}
}
if constexpr (!std::is_same_v<std::false_type, T3>) {
if (third() < rhs.third()) {
return true;
}
}
if constexpr (!std::is_same_v<std::false_type, T4>) {
if (fourth() < rhs.fourth()) {
return true;
}
}
if constexpr (!std::is_same_v<std::false_type, T5>) {
if (fifth() < rhs.fifth()) {
return true;
}
}
if constexpr (!std::is_same_v<std::false_type, T6>) {
if (sixth() < rhs.sixth()) {
return true;
}
}
return false;
}
T1 first() const
{
if constexpr (IsT1String::value) {
return key1_.c_str();
} else {
return key1_;
}
}
T2 second() const
{
static_assert(!std::is_same_v<T2, std::false_type>, "Invalid access.");
if constexpr (IsT2String::value) {
return key2_.c_str();
} else {
return key2_;
}
}
T3 third() const
{
static_assert(!std::is_same_v<T3, std::false_type>, "Invalid access.");
if constexpr (IsT3String::value) {
return key3_.c_str();
} else {
return key3_;
}
}
T4 fourth() const
{
static_assert(!std::is_same_v<T4, std::false_type>, "Invalid access.");
if constexpr (IsT4String::value) {
return key4_.c_str();
} else {
return key4_;
}
}
T5 fifth() const
{
static_assert(!std::is_same_v<T5, std::false_type>, "Invalid access.");
if constexpr (IsT5String::value) {
return key5_.c_str();
} else {
return key5_;
}
}
T6 sixth() const
{
static_assert(!std::is_same_v<T6, std::false_type>, "Invalid access.");
if constexpr (IsT6String::value) {
return key6_.c_str();
} else {
return key6_;
}
}
private:
T1_ key1_;
T2_ key2_;
T3_ key3_;
T4_ key4_;
T5_ key5_;
T6_ key6_;
};
namespace std
{
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
struct hash<HashableKeys<T1, T2, T3, T4, T5, T6>>
{
size_t operator()(const HashableKeys<T1, T2, T3, T4, T5, T6> & t) const { return t.hash(); }
};
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
struct equal_to<HashableKeys<T1, T2, T3, T4, T5, T6>>
{
size_t operator()(
const HashableKeys<T1, T2, T3, T4, T5, T6> & t,
const HashableKeys<T1, T2, T3, T4, T5, T6> & t_) const
{
return t.equal_to(t_);
}
};
} // namespace std
// clang-format off
template <
typename T1,
typename T2 = std::false_type,
typename T3 = std::false_type,
typename T4 = std::false_type,
typename T5 = std::false_type,
typename T6 = std::false_type
>
// clang-format on
class KeysSet
{
public:
// Use set to loop through iterators in order of addition.
using SetT = std::set<HashableKeys<T1, T2, T3, T4, T5, T6>>;
using IteratorT = typename SetT::iterator;
using ConstIteratorT = typename SetT::const_iterator;
void insert(T1 key1, T2 key2, T3 key3, T4 key4, T5 key5, T6 key6)
{
HashableKeys<T1, T2, T3, T4, T5, T6> keys(key1, key2, key3, key4, key5, key6);
keys_.insert(keys);
}
void insert(T1 key1, T2 key2, T3 key3, T4 key4, T5 key5)
{
HashableKeys<T1, T2, T3, T4, T5> keys(key1, key2, key3, key4, key5);
keys_.insert(keys);
}
void insert(T1 key1, T2 key2, T3 key3, T4 key4)
{
HashableKeys<T1, T2, T3, T4> keys(key1, key2, key3, key4);
keys_.insert(keys);
}
void insert(T1 key1, T2 key2, T3 key3)
{
HashableKeys<T1, T2, T3> keys(key1, key2, key3);
keys_.insert(keys);
}
void insert(T1 key1, T2 key2)
{
HashableKeys<T1, T2> keys(key1, key2);
keys_.insert(keys);
}
void insert(T1 key1)
{
HashableKeys<T1> keys(key1);
keys_.insert(keys);
}
void insert(HashableKeys<T1, T2, T3, T4, T5, T6> keys) { keys_.insert(keys); }
void clear() { keys_.clear(); }
bool has(T1 key1, T2 key2, T3 key3, T4 key4, T5 key5, T6 key6) const
{
HashableKeys<T1, T2, T3, T4, T5, T6> keys(key1, key2, key3, key4, key5, key6);
return keys_.count(keys) > 0;
}
bool has(T1 key1, T2 key2, T3 key3, T4 key4, T5 key5) const
{
HashableKeys<T1, T2, T3, T4, T5> keys(key1, key2, key3, key4, key5);
return keys_.count(keys) > 0;
}
bool has(T1 key1, T2 key2, T3 key3, T4 key4) const
{
HashableKeys<T1, T2, T3, T4> keys(key1, key2, key3, key4);
return keys_.count(keys) > 0;
}
bool has(T1 key1, T2 key2, T3 key3) const
{
HashableKeys<T1, T2, T3> keys(key1, key2, key3);
return keys_.count(keys) > 0;
}
bool has(T1 key1, T2 key2) const
{
HashableKeys<T1, T2> keys(key1, key2);
return keys_.count(keys) > 0;
}
bool has(T1 key1) const
{
HashableKeys<T1> keys(key1);
return keys_.count(keys) > 0;
}
ConstIteratorT begin() const { return keys_.cbegin(); }
ConstIteratorT end() const { return keys_.cend(); }
size_t size() const { return keys_.size(); }
private:
SetT keys_;
};
#endif // CARET_TRACE__KEYS_SET_HPP_
#define CARET_TRACE__KEYS_SET_HPP_