Platform.Data.Doublets C++
Loading...
Searching...
No Matches
Link.h
Go to the documentation of this file.
2{
3 template <std::integral TLinkAddress>
4 struct Link;
5
6 namespace Details
7 {
8 template <std::integral TLinkAddress>
9 inline constexpr Link<TLinkAddress> NullLink{};
10 }
11
12 template <std::integral TLinkAddress>
13 struct Link
14 {
16
17 public:
18 // A reference delays instantiating the self-typed value until Link is
19 // complete, while keeping Null usable in C++20 constant expressions.
20 static constexpr const Link& Null = Details::NullLink<TLinkAddress>;
21
22 private:
23 static constexpr LinksConstants<TLinkAddress> _constants{};
24
25 private:
26 static constexpr std::size_t Length = 3;
27
28 public:
29 TLinkAddress Index = _constants.Null;
30
31 public:
32 TLinkAddress Source = _constants.Null;
33
34 public:
35 TLinkAddress Target = _constants.Null;
36
37 public:
38 Link() noexcept = default;
39
40 public:
41 Link(const Link&) noexcept = default;
42
43 public:
44 Link(Link&&) noexcept = default;
45
46 public:
47 auto& operator=(const Link& other)
48 {
49 Index = other.Index;
50 Source = other.Source;
51 Target = other.Target;
52 return *this;
53 }
54
55 public:
56 bool operator==(const Link&) const noexcept = default;
57
58 public:
60 : Index(index), Source(source), Target(target)
61 {
62 }
63
64 public:
65 Link(std::convertible_to<TLinkAddress> auto... valuesPack)
66 {
67 constexpr auto length = sizeof...(valuesPack);
68 std::array<TLinkAddress, length> values{static_cast<TLinkAddress>(valuesPack)...};
69 if constexpr (0 == length)
70 {
71 Index = _constants.Null;
72 Source = _constants.Null;
73 Target = _constants.Null;
74 }
75 else if constexpr (1 == length)
76 {
77 Index = values[0];
78 Source = _constants.Null;
79 Target = _constants.Null;
80 }
81 else if constexpr (2 == length)
82 {
83 Index = values[0];
84 Source = values[1];
85 Target = _constants.Null;
86 }
87 else if constexpr (3 == length)
88 {
89 Index = values[0];
90 Source = values[1];
91 Target = values[2];
92 }
93 else
94 {
95 throw std::invalid_argument("Link: too many values");
96 }
97 }
98
99 public:
100 Link(std::ranges::range auto&& range)
101 {
102 for (std::size_t i = 0; auto&& item : range | std::views::take(3))
103 {
104 (*this)[i++] = item; // TODO: later later use std::forward
105 }
106 }
107
108 public:
109 operator std::vector<TLinkAddress>()
110 {
111 return std::vector<TLinkAddress>{Index, Source, Target};
112 }
113
114 public:
115 bool IsNull() const noexcept
116 {
117 constexpr auto null = _constants.Null;
118 return *this == Link{null, null, null};
119 }
120
121 public:
122 auto&& operator[](std::size_t index) const
123 {
124 using namespace Platform::Ranges; // TODO: EnsureExtensions
125 if (index == _constants.IndexPart)
126 {
127 return Index;
128 }
129 if (index == _constants.SourcePart)
130 {
131 return Source;
132 }
133 if (index == _constants.TargetPart)
134 {
135 return Target;
136 }
137 throw std::out_of_range("Link index out of range");
138 }
139
140 public:
141 auto&& operator[](std::size_t index)
142 {
143 using namespace Platform::Ranges; // TODO: EnsureExtensions
144 if (index == _constants.IndexPart)
145 {
146 return Index;
147 }
148 if (index == _constants.SourcePart)
149 {
150 return Source;
151 }
152 if (index == _constants.TargetPart)
153 {
154 return Target;
155 }
156 throw std::out_of_range("Link index out of range");
157 }
158
159 public:
160 std::size_t size() const noexcept
161 {
162 return Length;
163 }
164
165 public:
166 bool empty() const noexcept
167 {
168 return 0 == size();
169 }
170
171 // TODO: a little unsafe
172 public:
173 auto begin() const noexcept
174 {
175 return &Index;
176 }
177
178 public:
179 auto end() const noexcept
180 {
181 return &Target + 1;
182 }
183
184 public:
185 explicit operator std::string() const
186 {
187 return Index == _constants.Null ? ToString(Source, Target) : ToString(Index, Source, Target);
188 }
189
190 public:
191 friend auto& operator<<(std::ostream& stream, const Link<TLinkAddress>& self)
192 {
193 return stream << static_cast<std::string>(self);
194 }
195
196 public:
197 static std::string ToString(TLinkAddress index, TLinkAddress source, TLinkAddress target)
198 {
199 return std::string("(")
200 .append(Platform::Converters::To<std::string>(index))
201 .append(": ")
202 .append(Platform::Converters::To<std::string>(source))
203 .append("->")
204 .append(Platform::Converters::To<std::string>(target))
205 .append(1, ')');
206 }
207
208 public:
209 static std::string ToString(TLinkAddress source, TLinkAddress target)
210 {
211 return std::string("(")
212 .append(Platform::Converters::To<std::string>(source))
213 .append("->")
214 .append(Platform::Converters::To<std::string>(target))
215 .append(1, ')');
216 }
217 };
218
219 template <typename... Args>
220 Link(Args...) -> Link<std::common_type_t<Args...>>;
221
222 template <std::ranges::range Range>
224} // namespace Platform::Data::Doublets
225
226template <std::integral TLinkAddress>
227struct std::hash<Platform::Data::Doublets::Link<TLinkAddress>>
228{
230 std::size_t operator()(const Self& self) const noexcept
231 {
232 return Platform::Hashing::Hash(self.Index, self.Source, self.Target);
233 }
234};
constexpr Link< TLinkAddress > NullLink
Definition Link.h:9
Definition TargetMatcher.h:2
Link(Args...) -> Link< std::common_type_t< Args... > >
Definition TargetMatcher.h:2