-
Notifications
You must be signed in to change notification settings - Fork 6
/
cx_map.hpp
142 lines (125 loc) · 4.18 KB
/
cx_map.hpp
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#pragma once
#include <stdx/compiler.hpp>
#include <stdx/concepts.hpp>
#include <stdx/iterator.hpp>
#include <stdx/utility.hpp>
#include <array>
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace stdx {
inline namespace v1 {
template <typename Key, typename Value> struct cx_map_value {
using key_type = Key;
using mapped_type = Value;
key_type key{};
mapped_type value{};
};
template <typename K, typename V> cx_map_value(K, V) -> cx_map_value<K, V>;
template <typename Key, typename Value, std::size_t N> class cx_map {
public:
using value_type = cx_map_value<Key, Value>;
using key_type = typename value_type::key_type;
using mapped_type = typename value_type::mapped_type;
using size_type = std::size_t;
using reference = value_type &;
using const_reference = value_type const &;
using iterator = value_type *;
using const_iterator = value_type const *;
private:
std::array<value_type, N> storage{};
std::size_t current_size{};
public:
constexpr cx_map() = default;
template <typename... Vs, std::enable_if_t<((sizeof...(Vs) <= N) and ... and
stdx::same_as<value_type, Vs>),
int> = 0>
constexpr explicit cx_map(Vs const &...vs)
: storage{vs...}, current_size{sizeof...(Vs)} {}
[[nodiscard]] constexpr auto begin() LIFETIMEBOUND -> iterator {
return std::begin(storage);
}
[[nodiscard]] constexpr auto begin() const LIFETIMEBOUND -> const_iterator {
return std::begin(storage);
}
[[nodiscard]] constexpr auto
cbegin() const LIFETIMEBOUND -> const_iterator {
return std::cbegin(storage);
}
[[nodiscard]] constexpr auto end() LIFETIMEBOUND -> iterator {
return std::begin(storage) + current_size;
}
[[nodiscard]] constexpr auto end() const LIFETIMEBOUND -> const_iterator {
return std::begin(storage) + current_size;
}
[[nodiscard]] constexpr auto cend() const LIFETIMEBOUND -> const_iterator {
return std::cbegin(storage) + current_size;
}
[[nodiscard]] constexpr auto size() const -> std::size_t {
return current_size;
}
constexpr static std::integral_constant<size_type, N> capacity{};
[[nodiscard]] constexpr auto full() const -> bool {
return current_size == N;
}
[[nodiscard]] constexpr auto empty() const -> bool {
return current_size == 0;
}
constexpr auto clear() -> void { current_size = 0; }
[[nodiscard]] constexpr auto pop_back() -> value_type {
return storage[--current_size];
}
[[nodiscard]] constexpr auto
get(key_type const &key) LIFETIMEBOUND -> mapped_type & {
for (auto &[k, v] : *this) {
if (k == key) {
return v;
}
}
unreachable();
}
[[nodiscard]] constexpr auto
get(key_type const &key) const LIFETIMEBOUND -> mapped_type const & {
for (auto const &[k, v] : *this) {
if (k == key) {
return v;
}
}
unreachable();
}
[[nodiscard]] constexpr auto contains(key_type const &key) const -> bool {
for (auto const &[k, v] : *this) {
if (k == key) {
return true;
}
}
return false;
}
constexpr auto insert_or_assign(key_type const &key,
mapped_type const &value) -> bool {
for (auto &[k, v] : *this) {
if (k == key) {
v = value;
return false;
}
}
storage[current_size++] = {key, value};
return true;
}
constexpr auto put(key_type const &key, mapped_type const &value) -> bool {
return insert_or_assign(key, value);
}
constexpr auto erase(key_type const &key) -> size_type {
for (auto &v : *this) {
if (v.key == key) {
v = storage[--current_size];
return 1u;
}
}
return 0u;
}
};
template <typename K, typename V, std::size_t N>
constexpr auto ct_capacity_v<cx_map<K, V, N>> = N;
} // namespace v1
} // namespace stdx