aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/types/OrderedContainers.hpp
blob: e90000cca264146a36deae9bce2f8032dd629632 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#pragma once

#include <concepts>
#include <deque>
#include <functional>
#include <memory>

#include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>

#include "openvic-simulation/utility/Utility.hpp"

namespace OpenVic {
   struct ordered_container_string_hash {
      using is_transparent = void;
      [[nodiscard]] size_t operator()(const char* txt) const {
         return std::hash<std::string_view> {}(txt);
      }
      [[nodiscard]] size_t operator()(std::string_view txt) const {
         return std::hash<std::string_view> {}(txt);
      }
      [[nodiscard]] size_t operator()(const std::string& txt) const {
         return std::hash<std::string> {}(txt);
      }
   };

   template<typename T>
   struct container_hash : std::hash<T> {};

   template<>
   struct container_hash<std::string> : ordered_container_string_hash {};
   template<>
   struct container_hash<std::string_view> : ordered_container_string_hash {};
   template<>
   struct container_hash<const char*> : ordered_container_string_hash {};

   // Useful for contiguous memory
   template<
      class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
      class Allocator = std::allocator<std::pair<Key, T>>, class IndexType = std::uint_least32_t>
   using vector_ordered_map =
      tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator, std::vector<std::pair<Key, T>, Allocator>, IndexType>;

   // Useful for stable memory addresses (so long as you don't remove or insert values)
   template<
      class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
      class Allocator = std::allocator<std::pair<Key, T>>, class IndexType = std::uint_least32_t>
   using deque_ordered_map =
      tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator, std::deque<std::pair<Key, T>, Allocator>, IndexType>;

   template<
      class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
      class Allocator = std::allocator<std::pair<Key, T>>, class IndexType = std::uint_least32_t>
   using ordered_map = vector_ordered_map<Key, T, Hash, KeyEqual, Allocator, IndexType>;

   // Useful for contiguous memory
   template<
      class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>, class Allocator = std::allocator<Key>,
      class ValueTypeContainer = std::deque<Key, Allocator>, class IndexType = std::uint_least32_t>
   using vector_ordered_set = tsl::ordered_set<Key, Hash, KeyEqual, Allocator, std::vector<Key, Allocator>, IndexType>;

   // Useful for stable memory addresses (so long as you don't remove or insert values)
   template<
      class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>, class Allocator = std::allocator<Key>,
      class ValueTypeContainer = std::deque<Key, Allocator>, class IndexType = std::uint_least32_t>
   using deque_ordered_set = tsl::ordered_set<Key, Hash, KeyEqual, Allocator, std::deque<Key, Allocator>, IndexType>;

   template<
      class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>, class Allocator = std::allocator<Key>,
      class IndexType = std::uint_least32_t>
   using ordered_set = vector_ordered_set<Key, Hash, KeyEqual, Allocator, IndexType>;

   template<typename T>
   concept IsOrderedMap = utility::is_specialization_of_v<T, tsl::ordered_map>;
   template<typename T>
   concept IsOrderedSet = utility::is_specialization_of_v<T, tsl::ordered_set>;
   template<typename T>
   concept IsVectorOrderedMap = utility::is_specialization_of_v<T, vector_ordered_map>;
   template<typename T>
   concept IsVectorOrderedSet = utility::is_specialization_of_v<T, vector_ordered_set>;
   template<typename T>
   concept IsDequeOrderedMap = utility::is_specialization_of_v<T, deque_ordered_map>;
   template<typename T>
   concept IsDequeOrderedSet = utility::is_specialization_of_v<T, deque_ordered_set>;

   template<typename T, typename Key, typename Value>
   concept IsOrderedMapOf =
      IsOrderedMap<T> && std::same_as<Key, typename T::key_type> && std::same_as<Value, typename T::mapped_type>;
   template<typename T, typename Key>
   concept IsOrderedSetOf = IsOrderedSet<T> && std::same_as<Key, typename T::key_type>;
   template<typename T, typename Key, typename Value>
   concept IsVectorOrderedMapOf =
      IsVectorOrderedMap<T> && std::same_as<Key, typename T::key_type> && std::same_as<Value, typename T::mapped_type>;
   template<typename T, typename Key>
   concept IsVectorOrderedSetOf = IsVectorOrderedSet<T> && std::same_as<Key, typename T::key_type>;
   template<typename T, typename Key, typename Value>
   concept IsDequeOrderedMapOf =
      IsDequeOrderedMap<T> && std::same_as<Key, typename T::key_type> && std::same_as<Value, typename T::mapped_type>;
   template<typename T, typename Key>
   concept IsDequeOrderedSetOf = IsDequeOrderedSet<T> && std::same_as<Key, typename T::key_type>;
}