summaryrefslogtreecommitdiffstats
path: root/server/src/util.cppm
diff options
context:
space:
mode:
authorRutger Broekhoff2026-08-28 21:12:55 +0200
committerRutger Broekhoff2026-08-28 21:12:55 +0200
commita5d95afb96eb9a3b65d82f5f84bf8e4a4fb4c8ac (patch)
treeb4e0ec57c3799e9f649c6bfe27cb6c3313b97364 /server/src/util.cppm
parent973aec43ea54bbf95b64fbcb636403401d1ca60e (diff)
downloadroutemon-a5d95afb96eb9a3b65d82f5f84bf8e4a4fb4c8ac.tar.gz
routemon-a5d95afb96eb9a3b65d82f5f84bf8e4a4fb4c8ac.zip
clang-format C++ sources
Diffstat (limited to 'server/src/util.cppm')
-rw-r--r--server/src/util.cppm428
1 files changed, 232 insertions, 196 deletions
diff --git a/server/src/util.cppm b/server/src/util.cppm
index 65f4d67..bdccf10 100644
--- a/server/src/util.cppm
+++ b/server/src/util.cppm
@@ -6,249 +6,285 @@ import std;
6 6
7namespace routemon::util { 7namespace routemon::util {
8 8
9 // For use with e.g. std::visit (on std::variant). 9// For use with e.g. std::visit (on std::variant).
10 template<class... Ts> 10template <class... Ts>
11 struct overloaded : Ts... { 11struct overloaded : Ts...
12 using Ts::operator()...; 12{
13 }; 13 using Ts::operator()...;
14};
14 15
15 export constexpr auto parse_double(std::string_view s, std::chars_format fmt = std::chars_format::general) noexcept -> std::optional<double> { 16export constexpr auto parse_double(
16 auto x = 0.0; 17 std::string_view s,
17 auto [_, ec] = std::from_chars(s.data(), s.data() + s.size(), x, fmt); 18 std::chars_format fmt = std::chars_format::general) noexcept
18 if (ec == std::errc{}) { 19 -> std::optional<double>
19 return x; 20{
20 } else { 21 auto x = 0.0;
21 return std::nullopt; 22 auto [_, ec] = std::from_chars(s.data(), s.data() + s.size(), x, fmt);
22 } 23 if (ec == std::errc{})
24 {
25 return x;
26 }
27 else
28 {
29 return std::nullopt;
23 } 30 }
31}
24 32
25 export constexpr auto parse_float(std::string_view s, std::chars_format fmt = std::chars_format::general) noexcept -> std::optional<float> { 33export constexpr auto parse_float(
26 auto x = 0.0; 34 std::string_view s,
27 auto [_, ec] = std::from_chars(s.data(), s.data() + s.size(), x, fmt); 35 std::chars_format fmt = std::chars_format::general) noexcept
28 if (ec == std::errc{}) { 36 -> std::optional<float>
29 return x; 37{
30 } else { 38 auto x = 0.0;
31 return std::nullopt; 39 auto [_, ec] = std::from_chars(s.data(), s.data() + s.size(), x, fmt);
32 } 40 if (ec == std::errc{})
41 {
42 return x;
33 } 43 }
44 else
45 {
46 return std::nullopt;
47 }
48}
34 49
35 export template<class T> 50export template <class T>
36 class aolist : public std::enable_shared_from_this<aolist<T>> { 51class aolist : public std::enable_shared_from_this<aolist<T>>
37 T v_; 52{
38 std::shared_ptr<aolist<T> const> next_; 53 T v_;
54 std::shared_ptr<aolist<T> const> next_;
39 55
40 explicit aolist(T v, std::shared_ptr<aolist<T> const> next) 56 explicit aolist(T v, std::shared_ptr<aolist<T> const> next)
41 : v_{v}, next_{next} 57 : v_{v}, next_{next}
42 {} 58 {
59 }
43 60
44 public: 61public:
45 static auto nil() -> std::shared_ptr<aolist<T>> { 62 static auto nil() -> std::shared_ptr<aolist<T>> { return nullptr; }
46 return nullptr;
47 }
48 63
49 static auto cons(T v, std::shared_ptr<aolist<T> const> l) -> std::shared_ptr<aolist<T>> { 64 static auto cons(T v, std::shared_ptr<aolist<T> const> l)
50 return std::shared_ptr<aolist<T>>{new aolist<T>{v, l}}; 65 -> std::shared_ptr<aolist<T>>
51 } 66 {
67 return std::shared_ptr<aolist<T>>{new aolist<T>{v, l}};
68 }
52 69
53 auto next() const -> std::shared_ptr<aolist<T> const> { 70 auto next() const -> std::shared_ptr<aolist<T> const> { return next_; }
54 return next_;
55 }
56 71
57 auto value() const noexcept -> T const& { 72 auto value() const noexcept -> T const& { return v_; }
58 return v_; 73};
59 }
60 };
61 74
62 export constexpr auto size_from_int(int x) -> std::optional<std::size_t> { 75export constexpr auto size_from_int(int x) -> std::optional<std::size_t>
63 static_assert(sizeof(int) <= sizeof(std::size_t), "cannot cast int to smaller size_t type"); 76{
64 if (x < 0) 77 static_assert(
65 return std::nullopt; 78 sizeof(int) <= sizeof(std::size_t),
66 return static_cast<std::size_t>(x); 79 "cannot cast int to smaller size_t type");
80 if (x < 0)
81 return std::nullopt;
82 return static_cast<std::size_t>(x);
83}
84
85export constexpr auto int_from_size(std::size_t x) -> std::optional<int>
86{
87 constexpr auto int_max = size_from_int(std::numeric_limits<int>::max());
88 static_assert(int_max.has_value());
89 if (x > *int_max)
90 return std::nullopt;
91 return static_cast<int>(x);
92}
93
94export class zstring_view
95{
96 char const* s_;
97 std::size_t length_;
98
99public:
100 constexpr explicit zstring_view(char const* s, std::size_t length)
101 : s_{s}, length_{length}
102 {
67 } 103 }
68 104
69 export constexpr auto int_from_size(std::size_t x) -> std::optional<int> { 105 constexpr zstring_view(char const* s)
70 constexpr auto int_max = size_from_int(std::numeric_limits<int>::max()); 106 : zstring_view{s, std::char_traits<char>::length(s)}
71 static_assert(int_max.has_value()); 107 {
72 if (x > *int_max)
73 return std::nullopt;
74 return static_cast<int>(x);
75 } 108 }
76 109
77 export class zstring_view { 110 auto length() const -> std::size_t { return length_; }
78 char const* s_;
79 std::size_t length_;
80 111
81 public: 112 auto c_str() const -> char const* { return s_; }
82 constexpr explicit zstring_view(char const* s, std::size_t length) :
83 s_{s}, length_{length}
84 {}
85 113
86 constexpr zstring_view(char const* s) : 114 operator std::string_view() const { return std::string_view{s_, length_}; }
87 zstring_view{s, std::char_traits<char>::length(s)}
88 {}
89 115
90 auto length() const -> std::size_t { 116 operator char const*() const { return s_; }
91 return length_; 117};
92 }
93 118
94 auto c_str() const -> char const* { 119// View for null-terminated strings for which we might not
95 return s_; 120// necessarily be interested in the length. String length is only
96 } 121// calculated on demand, at most once on each thread (on more than
122// one thread when racing). May be null.
123//
124// It is undefined behavior to assign to a lazy_zstring_view when
125// it is in use by other threads.
126export class lazy_zstring_view
127{
128 static constexpr auto unset_length = std::numeric_limits<std::size_t>::max();
97 129
98 operator std::string_view() const { 130 char const* s_; // nullable
99 return std::string_view{s_, length_}; 131 mutable std::atomic<std::size_t> length_;
100 } 132 static_assert(decltype(length_)::is_always_lock_free);
101 133
102 operator char const*() const { 134public:
103 return s_; 135 constexpr explicit lazy_zstring_view(char const* s)
104 } 136 : s_{s}, length_{s ? unset_length : 0}
105 }; 137 {
138 }
106 139
107 // View for null-terminated strings for which we might not 140 ~lazy_zstring_view() = default;
108 // necessarily be interested in the length. String length is only
109 // calculated on demand, at most once on each thread (on more than
110 // one thread when racing). May be null.
111 //
112 // It is undefined behavior to assign to a lazy_zstring_view when
113 // it is in use by other threads.
114 export class lazy_zstring_view {
115 static constexpr auto unset_length = std::numeric_limits<std::size_t>::max();
116 141
117 char const* s_; // nullable 142 lazy_zstring_view(lazy_zstring_view const& sv) noexcept
118 mutable std::atomic<std::size_t> length_; 143 : s_{sv.s_}, length_{sv.length_.load(std::memory_order_acquire)}
119 static_assert(decltype(length_)::is_always_lock_free); 144 {
145 }
120 146
121 public: 147 lazy_zstring_view(lazy_zstring_view&& sv) noexcept
122 constexpr explicit lazy_zstring_view(char const* s) : 148 : s_{sv.s_}, length_{sv.length_.load(std::memory_order_acquire)}
123 s_{s}, length_{s ? unset_length : 0} 149 {
124 {} 150 }
125 ~lazy_zstring_view() = default;
126 151
127 lazy_zstring_view(lazy_zstring_view const& sv) noexcept 152 auto operator=(lazy_zstring_view const& rhs) noexcept -> lazy_zstring_view&
128 : s_{sv.s_}, length_{sv.length_.load(std::memory_order_acquire)} 153 {
129 {} 154 if (this != &rhs)
130 lazy_zstring_view(lazy_zstring_view&& sv) noexcept 155 {
131 : s_{sv.s_}, length_{sv.length_.load(std::memory_order_acquire)} 156 s_ = rhs.s_;
132 {} 157 length_.store(
133 auto operator=(lazy_zstring_view const& rhs) noexcept -> lazy_zstring_view& { 158 rhs.length_.load(std::memory_order_acquire),
134 if (this != &rhs) { 159 std::memory_order_release);
135 s_ = rhs.s_;
136 length_.store(rhs.length_.load(std::memory_order_acquire), std::memory_order_release);
137 }
138 return *this;
139 }
140 auto operator=(lazy_zstring_view&& rhs) noexcept -> lazy_zstring_view& {
141 return *this = rhs; // use the copy assignment operator
142 } 160 }
161 return *this;
162 }
143 163
144 auto length() const noexcept -> std::size_t { 164 auto operator=(lazy_zstring_view&& rhs) noexcept -> lazy_zstring_view&
145 if (auto v = length_.load(std::memory_order_acquire); v != unset_length) 165 {
146 return v; 166 return *this = rhs; // use the copy assignment operator
147 auto l = std::char_traits<char>::length(s_); 167 }
148 length_.store(l, std::memory_order_release);
149 return l;
150 }
151 168
152 auto c_str() const noexcept -> char const* { 169 auto length() const noexcept -> std::size_t
153 return s_; 170 {
154 } 171 if (auto v = length_.load(std::memory_order_acquire); v != unset_length)
172 return v;
173 auto l = std::char_traits<char>::length(s_);
174 length_.store(l, std::memory_order_release);
175 return l;
176 }
155 177
156 operator std::string_view() const noexcept { 178 auto c_str() const noexcept -> char const* { return s_; }
157 return std::string_view{s_, length()};
158 }
159 179
160 operator char const*() const noexcept { 180 operator std::string_view() const noexcept
161 return s_; 181 {
162 } 182 return std::string_view{s_, length()};
183 }
163 184
164 auto operator==(std::string_view sv) const noexcept -> bool { 185 operator char const*() const noexcept { return s_; }
165 if (auto v = length_.load(std::memory_order_acquire); v != unset_length)
166 if (sv.length() != v)
167 return false;
168 auto res = std::char_traits<char>::compare(s_, sv.data(), sv.length());
169 if (res != 0)
170 return false;
171 // Strings are equal for sv.length() characters.
172 if (s_[sv.length()] != '\0')
173 return false;
174 // Strings are actually equal, and we have just found out the
175 // length of this string, so we might as well set it.
176 length_.store(sv.length(), std::memory_order_release);
177 return true;
178 }
179 };
180 186
181 constexpr auto operator""_zsv(char const* s, std::size_t length) noexcept -> zstring_view { 187 auto operator==(std::string_view sv) const noexcept -> bool
182 return zstring_view{s, length}; 188 {
189 if (auto v = length_.load(std::memory_order_acquire); v != unset_length)
190 if (sv.length() != v)
191 return false;
192 auto res = std::char_traits<char>::compare(s_, sv.data(), sv.length());
193 if (res != 0)
194 return false;
195 // Strings are equal for sv.length() characters.
196 if (s_[sv.length()] != '\0')
197 return false;
198 // Strings are actually equal, and we have just found out the
199 // length of this string, so we might as well set it.
200 length_.store(sv.length(), std::memory_order_release);
201 return true;
183 } 202 }
203};
184 204
185 auto operator==(zstring_view lhs, zstring_view rhs) -> bool { 205constexpr auto operator""_zsv(char const* s, std::size_t length) noexcept
186 return std::string_view{lhs} == std::string_view{rhs}; 206 -> zstring_view
187 } 207{
208 return zstring_view{s, length};
209}
188 210
189 export constexpr auto split_on(std::string_view s, char c) -> std::pair<std::string_view, std::optional<std::string_view>> { 211auto operator==(zstring_view lhs, zstring_view rhs) -> bool
190 if (auto i = s.find(c); i != std::string_view::npos) 212{
191 return std::make_pair(s.substr(0, i), s.substr(i + 1)); 213 return std::string_view{lhs} == std::string_view{rhs};
192 return std::make_pair(s, std::nullopt); 214}
193 }
194 215
195 export template<class T> 216export constexpr auto split_on(std::string_view s, char c)
196 class not_null; 217 -> std::pair<std::string_view, std::optional<std::string_view>>
218{
219 if (auto i = s.find(c); i != std::string_view::npos)
220 return std::make_pair(s.substr(0, i), s.substr(i + 1));
221 return std::make_pair(s, std::nullopt);
222}
197 223
198 export template<class T> 224export template <class T>
199 class not_null<T*> { 225class not_null;
200 T* p_;
201 226
202 struct guaranteed_not_null_t {}; 227export template <class T>
203 explicit not_null(T* p, guaranteed_not_null_t) noexcept : p_{p} {} 228class not_null<T*>
229{
230 T* p_;
204 231
205 public: 232 struct guaranteed_not_null_t
206 explicit not_null(T* p) 233 {
207 : p_{p} 234 };
208 { if (!p_) throw std::runtime_error{"not_null constructed with null pointer"}; } 235 explicit not_null(T* p, guaranteed_not_null_t) noexcept : p_{p} {}
209 ~not_null() = default;
210 236
211 not_null(not_null const& other) = default; 237public:
212 not_null(not_null&& other) noexcept = default; 238 explicit not_null(T* p) : p_{p}
213 auto operator=(not_null const& rhs) noexcept -> not_null& = default; 239 {
214 auto operator=(not_null&& rhs) noexcept -> not_null& = default; 240 if (!p_)
241 throw std::runtime_error{"not_null constructed with null pointer"};
242 }
243 ~not_null() = default;
215 244
216 friend auto make_not_null(T* p) noexcept -> std::optional<not_null> { 245 not_null(not_null const& other) = default;
217 if (p) return not_null(p, guaranteed_not_null_t{}); 246 not_null(not_null&& other) noexcept = default;
218 else return std::nullopt; 247 auto operator=(not_null const& rhs) noexcept -> not_null& = default;
219 } 248 auto operator=(not_null&& rhs) noexcept -> not_null& = default;
220 249
221 [[nodiscard]] auto get() const noexcept -> T* { 250 friend auto make_not_null(T* p) noexcept -> std::optional<not_null>
222 return p_; 251 {
223 } 252 if (p)
253 return not_null(p, guaranteed_not_null_t{});
254 else
255 return std::nullopt;
256 }
224 257
225 auto operator*() const noexcept -> std::add_lvalue_reference_t<T> { 258 [[nodiscard]] auto get() const noexcept -> T* { return p_; }
226 return *p_;
227 }
228 259
229 auto operator->() const noexcept -> T* { 260 auto operator*() const noexcept -> std::add_lvalue_reference_t<T>
230 return p_; 261 {
231 } 262 return *p_;
232 }; 263 }
233 export template<class T> explicit not_null(T*) -> not_null<T*>;
234 264
235 export template<> 265 auto operator->() const noexcept -> T* { return p_; }
236 class not_null<lazy_zstring_view> { 266};
237 lazy_zstring_view s_; 267export template <class T>
268explicit not_null(T*) -> not_null<T*>;
238 269
239 public: 270export template <>
240 explicit not_null(lazy_zstring_view s) 271class not_null<lazy_zstring_view>
241 : s_{std::move(s)} 272{
242 { if (!s_) throw std::runtime_error{"not_null constructed with null pointer"}; } 273 lazy_zstring_view s_;
243 274
244 [[nodiscard]] auto get() const noexcept -> lazy_zstring_view { 275public:
245 return s_; 276 explicit not_null(lazy_zstring_view s) : s_{std::move(s)}
246 } 277 {
278 if (!s_)
279 throw std::runtime_error{"not_null constructed with null pointer"};
280 }
247 281
248 operator lazy_zstring_view() const noexcept { return s_; } 282 [[nodiscard]] auto get() const noexcept -> lazy_zstring_view { return s_; }
249 operator std::string_view() const noexcept { return s_; } 283
250 operator char const*() const noexcept { return s_; } 284 operator lazy_zstring_view() const noexcept { return s_; }
251 }; 285 operator std::string_view() const noexcept { return s_; }
252 export explicit not_null(lazy_zstring_view s) -> not_null<lazy_zstring_view>; 286 operator char const*() const noexcept { return s_; }
287};
288export explicit not_null(lazy_zstring_view s) -> not_null<lazy_zstring_view>;
253 289
254} // namespace routemon::util 290} // namespace routemon::util