StormByte C++ Library 1.2.0
StormByte is a comprehensive, cross-platform C++ library aimed at easing system programming, configuration management, logging, and database handling tasks. This library provides a unified API that abstracts away the complexities and inconsistencies of different platforms (Windows, Linux).
Loading...
Searching...
No Matches
iterable.txx
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024-2026 David C. Manuelda (StormBytePP)
3 *
4 * This file is part of StormByte.
5 *
6 * StormByte is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version 3
8 * or later, as published by the Free Software Foundation.
9 *
10 * StormByte is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with StormByte. If not, see
17 * <https://www.gnu.org/licenses/lgpl-3.0.html>.
18 */
19
20#pragma once
21
22// Out-of-line implementation of StormByte::Iterable (and its nested Iterator /
23// ConstIterator adapters), included by iterable.hxx.
24// See iterable.hxx for documentation of each member.
25
26namespace StormByte {
27 // --- Iterable<Container>::Iterator ---
28
29 template <typename Container>
30 typename Iterable<Container>::Iterator::reference Iterable<Container>::Iterator::operator*() { return *m_it; }
31
32 template <typename Container>
33 typename Iterable<Container>::Iterator::pointer Iterable<Container>::Iterator::operator->() { return m_it.operator->(); }
34
35 template <typename Container>
36 typename Iterable<Container>::Iterator& Iterable<Container>::Iterator::operator++() { ++m_it; return *this; }
37
38 template <typename Container>
39 typename Iterable<Container>::Iterator Iterable<Container>::Iterator::operator++(int) { Iterator tmp = *this; ++m_it; return tmp; }
40
41 template <typename Container>
42 typename Iterable<Container>::Iterator& Iterable<Container>::Iterator::operator--() { --m_it; return *this; }
43
44 template <typename Container>
45 typename Iterable<Container>::Iterator Iterable<Container>::Iterator::operator--(int) { Iterator tmp = *this; --m_it; return tmp; }
46
47 template <typename Container>
48 typename Iterable<Container>::Iterator& Iterable<Container>::Iterator::operator+=(difference_type n) {
49 std::advance(m_it, n);
50 return *this;
51 }
52
53 template <typename Container>
54 typename Iterable<Container>::Iterator& Iterable<Container>::Iterator::operator-=(difference_type n) {
55 std::advance(m_it, -n);
56 return *this;
57 }
58
59 template <typename Container>
60 typename Iterable<Container>::Iterator Iterable<Container>::Iterator::operator+(difference_type n) const {
61 Iterator result = *this;
62 std::advance(result.m_it, n);
63 return result;
64 }
65
66 template <typename Container>
67 typename Iterable<Container>::Iterator Iterable<Container>::Iterator::operator-(difference_type n) const {
68 Iterator result = *this;
69 std::advance(result.m_it, -n);
70 return result;
71 }
72
73 template <typename Container>
74 typename Iterable<Container>::Iterator::difference_type Iterable<Container>::Iterator::operator-(const Iterator& other) const {
75 return std::distance(other.m_it, m_it);
76 }
77
78 template <typename Container>
79 bool Iterable<Container>::Iterator::operator==(const Iterator& other) const { return m_it == other.m_it; }
80
81 template <typename Container>
82 bool Iterable<Container>::Iterator::operator!=(const Iterator& other) const { return m_it != other.m_it; }
83
84 template <typename Container>
85 Iterable<Container>::Iterator::Iterator(typename Container::iterator it): m_it(it) {}
86
87 // --- Iterable<Container>::ConstIterator ---
88
89 template <typename Container>
90 typename Iterable<Container>::ConstIterator::reference Iterable<Container>::ConstIterator::operator*() const { return *m_it; }
91
92 template <typename Container>
93 typename Iterable<Container>::ConstIterator::pointer Iterable<Container>::ConstIterator::operator->() const { return m_it.operator->(); }
94
95 template <typename Container>
96 typename Iterable<Container>::ConstIterator& Iterable<Container>::ConstIterator::operator++() { ++m_it; return *this; }
97
98 template <typename Container>
99 typename Iterable<Container>::ConstIterator Iterable<Container>::ConstIterator::operator++(int) { ConstIterator tmp = *this; ++m_it; return tmp; }
100
101 template <typename Container>
102 typename Iterable<Container>::ConstIterator& Iterable<Container>::ConstIterator::operator--() { --m_it; return *this; }
103
104 template <typename Container>
105 typename Iterable<Container>::ConstIterator Iterable<Container>::ConstIterator::operator--(int) { ConstIterator tmp = *this; --m_it; return tmp; }
106
107 template <typename Container>
108 typename Iterable<Container>::ConstIterator& Iterable<Container>::ConstIterator::operator+=(difference_type n) {
109 std::advance(m_it, n);
110 return *this;
111 }
112
113 template <typename Container>
114 typename Iterable<Container>::ConstIterator& Iterable<Container>::ConstIterator::operator-=(difference_type n) {
115 std::advance(m_it, -n);
116 return *this;
117 }
118
119 template <typename Container>
120 typename Iterable<Container>::ConstIterator Iterable<Container>::ConstIterator::operator+(difference_type n) const {
121 ConstIterator result = *this;
122 std::advance(result.m_it, n);
123 return result;
124 }
125
126 template <typename Container>
127 typename Iterable<Container>::ConstIterator Iterable<Container>::ConstIterator::operator-(difference_type n) const {
128 ConstIterator result = *this;
129 std::advance(result.m_it, -n);
130 return result;
131 }
132
133 template <typename Container>
134 typename Iterable<Container>::ConstIterator::difference_type Iterable<Container>::ConstIterator::operator-(const ConstIterator& other) const {
135 return std::distance(other.m_it, m_it);
136 }
137
138 template <typename Container>
139 bool Iterable<Container>::ConstIterator::operator==(const ConstIterator& other) const { return m_it == other.m_it; }
140
141 template <typename Container>
142 bool Iterable<Container>::ConstIterator::operator!=(const ConstIterator& other) const { return m_it != other.m_it; }
143
144 template <typename Container>
145 Iterable<Container>::ConstIterator::ConstIterator(typename Container::const_iterator it): m_it(it) {}
146
147 // --- Iterable<Container> ---
148
149 template <typename Container>
150 template <typename C>
151 Iterable<Container>::Iterable(C&& data)
152 requires Type::SameAs<C, Container> && (
153 (Type::LvalueReference<C> && Type::CopyConstructible<value_type>) ||
154 (!Type::LvalueReference<C> && Type::MoveConstructible<value_type>)
155 ): m_data(std::forward<C>(data)) {}
156
157 template <typename Container>
158 Iterable<Container>::Iterable(const Iterable& other)
159 : m_data([&] {
160 if constexpr (Type::CopyConstructible<Container>) {
161 return other.m_data;
162 } else {
163 return Container{};
164 }
165 }()) {
166 if constexpr (!Type::CopyConstructible<Container>) {
167 throw Exception(Component("Iterable"), "container type is not copyable");
168 }
169 }
170
171 template <typename Container>
172 Iterable<Container>& Iterable<Container>::operator=(const Iterable& other) {
173 if constexpr (Type::CopyAssignable<Container>) {
174 if (this != &other)
175 m_data = other.m_data;
176 return *this;
177 } else {
178 throw Exception(Component("Iterable"), "container type is not copy-assignable");
179 }
180 }
181
182 template <typename Container>
183 bool Iterable<Container>::operator==(const Iterable& other) const { return m_data == other.m_data; }
184
185 template <typename Container>
186 bool Iterable<Container>::operator!=(const Iterable& other) const { return m_data != other.m_data; }
187
188 template <typename Container>
189 typename Iterable<Container>::iterator Iterable<Container>::begin() noexcept { return iterator(m_data.begin()); }
190
191 template <typename Container>
192 typename Iterable<Container>::const_iterator Iterable<Container>::begin() const noexcept { return const_iterator(m_data.begin()); }
193
194 template <typename Container>
195 typename Iterable<Container>::iterator Iterable<Container>::end() noexcept { return iterator(m_data.end()); }
196
197 template <typename Container>
198 typename Iterable<Container>::const_iterator Iterable<Container>::end() const noexcept { return const_iterator(m_data.end()); }
199
200 template <typename Container>
201 typename Iterable<Container>::const_iterator Iterable<Container>::cbegin() const noexcept { return const_iterator(m_data.cbegin()); }
202
203 template <typename Container>
204 typename Iterable<Container>::const_iterator Iterable<Container>::cend() const noexcept { return const_iterator(m_data.cend()); }
205
206 template <typename Container>
207 typename Iterable<Container>::reverse_iterator Iterable<Container>::rbegin() noexcept { return reverse_iterator(end()); }
208
209 template <typename Container>
210 typename Iterable<Container>::reverse_iterator Iterable<Container>::rend() noexcept { return reverse_iterator(begin()); }
211
212 template <typename Container>
213 typename Iterable<Container>::const_reverse_iterator Iterable<Container>::rbegin() const noexcept { return const_reverse_iterator(end()); }
214
215 template <typename Container>
216 typename Iterable<Container>::const_reverse_iterator Iterable<Container>::rend() const noexcept { return const_reverse_iterator(begin()); }
217
218 template <typename Container>
219 typename Iterable<Container>::const_reverse_iterator Iterable<Container>::crbegin() const noexcept { return const_reverse_iterator(cend()); }
220
221 template <typename Container>
222 typename Iterable<Container>::const_reverse_iterator Iterable<Container>::crend() const noexcept { return const_reverse_iterator(cbegin()); }
223
224 template <typename Container>
225 typename Iterable<Container>::size_type Iterable<Container>::size() const noexcept { return m_data.size(); }
226
227 template <typename Container>
228 bool Iterable<Container>::empty() const noexcept { return m_data.empty(); }
229
230 template <typename Container>
231 typename Iterable<Container>::reference Iterable<Container>::operator[](size_type i) {
232 if (i >= m_data.size())
233 throw OutOfBoundsError("Index {} out of bounds in Iterable::operator[]", i);
234 if constexpr (Type::HasSubscript<Container, size_type>) {
235 return m_data[i];
236 } else {
237 auto it = m_data.begin();
238 std::advance(it, static_cast<difference_type>(i));
239 return *it;
240 }
241 }
242
243 template <typename Container>
244 template<typename K>
245 auto Iterable<Container>::operator[](K const& key) -> decltype(auto)
246 requires (Type::HasMappedType<Container>) {
247 return m_data[static_cast<typename Container::key_type>(key)];
248 }
249
250 template <typename Container>
251 template<typename K>
252 auto Iterable<Container>::operator[](K const& key) const -> decltype(auto)
253 requires (Type::HasMappedType<const Container>) {
254 auto k = static_cast<typename Container::key_type>(key);
255 auto it = m_data.find(k);
256 if (it == m_data.cend())
257 throw OutOfBoundsError("Key not found in Iterable::operator[]");
258 return it->second;
259 }
260
261 template <typename Container>
262 typename Iterable<Container>::const_reference Iterable<Container>::operator[](size_type i) const {
263 if (i >= m_data.size())
264 throw OutOfBoundsError("Index {} out of bounds in Iterable::operator[]", i);
265 if constexpr (Type::HasSubscript<const Container, size_type>) {
266 return m_data[i];
267 } else {
268 auto it = m_data.cbegin();
269 std::advance(it, static_cast<difference_type>(i));
270 return *it;
271 }
272 }
273
274 template <typename Container>
275 template <typename T>
276 void Iterable<Container>::add(T&& value)
277 requires (
278 (Type::LvalueReference<T> && Type::CopyConstructible<value_type>) ||
279 (!Type::LvalueReference<T> && Type::MoveConstructible<value_type>)
280 ) {
281 if constexpr (Type::HasPushBack<Container>) {
282 m_data.push_back(std::forward<T>(value));
283 } else if constexpr (Type::HasPushFront<Container>) {
284 m_data.push_front(std::forward<T>(value));
285 } else if constexpr (Type::HasInsert<Container>) {
286 m_data.insert(std::forward<T>(value));
287 } else {
288 static_assert(Type::HasPushBack<Container> || Type::HasPushFront<Container> || Type::HasInsert<Container>,
289 "StormByte::Iterable: container must support push_back, push_front, or insert");
290 }
291 }
292
293 template <typename Container>
294 void Iterable<Container>::add(value_type value)
295 requires Type::MoveConstructible<value_type> {
296 if constexpr (Type::HasPushBack<Container>) {
297 m_data.push_back(std::move(value));
298 } else if constexpr (Type::HasPushFront<Container>) {
299 m_data.push_front(std::move(value));
300 } else if constexpr (Type::HasInsert<Container>) {
301 m_data.insert(std::move(value));
302 } else {
303 static_assert(Type::HasPushBack<Container> || Type::HasPushFront<Container> || Type::HasInsert<Container>,
304 "StormByte::Iterable: container must support push_back, push_front, or insert");
305 }
306 }
307
308 template <typename Container>
309 bool Iterable<Container>::has_item(const value_type& value) const {
310 for (const auto& item : m_data) {
311 if (item == value) {
312 return true;
313 }
314 }
315 return false;
316 }
317
318 template <typename Container>
319 template<typename M>
320 bool Iterable<Container>::has_item(M const& value) const
321 requires Type::HasMappedType<const Container> && std::convertible_to<M, typename Container::mapped_type> {
322 for (const auto& item : m_data) {
323 if (item.second == value) return true;
324 }
325 return false;
326 }
327
328 template <typename Container>
329 template<typename K>
330 bool Iterable<Container>::has_key(const K& key) const
331 requires Type::HasMappedType<const Container> {
332 auto k = static_cast<typename Container::key_type>(key);
333 return m_data.find(k) != m_data.cend();
334 }
335}