HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
fixed_string.hpp
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "../macros.hpp"
8#include "assert.hpp"
9#include "cast.hpp"
10#include "terminate.hpp"
11#include "exception.hpp"
12#include "misc.hpp"
13#include <string>
14#include <string_view>
15#include <format>
16#include <array>
17#include <ranges>
18#include <compare>
19
20hi_export_module(hikogui.utility.fixed_string);
21
22hi_export namespace hi { inline namespace v1 {
23
41hi_export template<size_t N>
43 using value_type = char;
44
45 std::array<char, N> _str = {};
46
47 constexpr fixed_string() noexcept = default;
48 constexpr fixed_string(fixed_string const&) noexcept = default;
49 constexpr fixed_string(fixed_string&&) noexcept = default;
50 constexpr fixed_string& operator=(fixed_string const&) noexcept = default;
51 constexpr fixed_string& operator=(fixed_string&&) noexcept = default;
52
53 template<std::size_t O>
54 constexpr fixed_string(char const (&str)[O]) noexcept
55 requires((O - 1) == N)
56 {
57 for (auto i = 0_uz; i != (O - 1); ++i) {
58 _str[i] = str[i];
59 }
60 }
61
64 template<std::invocable F>
65 constexpr fixed_string(F const& f) noexcept
66 {
67 auto str = f();
68
69 hi_assert(str.size() == N);
70 for (auto i = 0_uz; i != str.size(); ++i) {
71 _str[i] = char_cast<char>(str[i]);
72 }
73 }
74
75 constexpr operator std::string_view() const noexcept
76 {
77 return std::string_view{_str.data(), size()};
78 }
79
80 constexpr operator std::string() const noexcept
81 {
82 return std::string{_str.data(), size()};
83 }
84
85 [[nodiscard]] constexpr std::size_t size() const noexcept
86 {
87 return N;
88 }
89
90 [[nodiscard]] constexpr bool empty() const noexcept
91 {
92 return N == 0;
93 }
94
95 template<size_t I>
96 [[nodiscard]] constexpr friend char& get(fixed_string& a) noexcept
97 {
98 return std::get<I>(a._str);
99 }
100
101 template<size_t I>
102 [[nodiscard]] constexpr friend char const& get(fixed_string const& a) noexcept
103 {
104 return std::get<I>(a._str);
105 }
106
107 [[nodiscard]] constexpr char& operator[](size_t index) noexcept
108 {
109#ifndef NDEBUG
110 if (not(index < N)) {
112 }
113#endif
114 return _str[index];
115 }
116
117 [[nodiscard]] constexpr char const& operator[](size_t index) const noexcept
118 {
119#ifndef NDEBUG
120 if (not(index < N)) {
122 }
123#endif
124 return _str[index];
125 }
126
127 [[nodiscard]] constexpr auto begin() noexcept
128 {
129 return _str.begin();
130 }
131
132 [[nodiscard]] constexpr auto end() noexcept
133 {
134 return _str.begin() + size();
135 }
136
137 [[nodiscard]] constexpr bool operator==(fixed_string const& rhs) const noexcept = default;
138 [[nodiscard]] constexpr auto operator<=>(fixed_string const& rhs) const noexcept = default;
139
140 template<size_t O>
141 [[nodiscard]] constexpr bool operator==(fixed_string<O> const& rhs) const noexcept
142 requires(O != N)
143 {
144 return false;
145 }
146
147 template<size_t O>
148 [[nodiscard]] constexpr auto operator<=>(fixed_string<O> const& rhs) const noexcept
149 requires(O != N)
150 {
151 return static_cast<std::string_view>(*this) <=> static_cast<std::string_view>(rhs);
152 }
153
154 [[nodiscard]] constexpr bool operator==(std::string_view rhs) const noexcept
155 {
156 return static_cast<std::string_view>(*this) == rhs;
157 }
158
159 [[nodiscard]] constexpr auto operator<=>(std::string_view rhs) const noexcept
160 {
161 return static_cast<std::string_view>(*this) <=> rhs;
162 }
163
164 [[nodiscard]] constexpr bool operator==(std::string const& rhs) const noexcept
165 {
166 return static_cast<std::string_view>(*this) == rhs;
167 }
168
169 [[nodiscard]] constexpr auto operator<=>(std::string const& rhs) const noexcept
170 {
171 return static_cast<std::string_view>(*this) <=> rhs;
172 }
173
174 [[nodiscard]] constexpr bool operator==(char const *rhs) const noexcept
175 {
176 return static_cast<std::string_view>(*this) == rhs;
177 }
178
179 [[nodiscard]] constexpr auto operator<=>(char const *rhs) const noexcept
180 {
181 return static_cast<std::string_view>(*this) <=> rhs;
182 }
183
184 template<size_t O>
185 [[nodiscard]] constexpr bool operator==(char const (&rhs)[O]) const noexcept
186 {
187 return *this == fixed_string<O - 1>(rhs);
188 }
189
190 template<size_t O>
191 [[nodiscard]] constexpr auto operator<=>(char const (&rhs)[O]) const noexcept
192 {
193 return *this <=> fixed_string<O - 1>(rhs);
194 }
195
198 template<size_t R>
199 [[nodiscard]] constexpr auto operator+(fixed_string<R> const& rhs) const noexcept
200 {
201 auto r = fixed_string<N + R>{};
202 auto dst_i = 0_uz;
203 for (auto src_i = 0_uz; src_i != N; ++src_i, ++dst_i) {
204 r[dst_i] = (*this)[src_i];
205 }
206 for (auto src_i = 0_uz; src_i != R; ++src_i, ++dst_i) {
207 r[dst_i] = rhs[src_i];
208 }
209
210 return r;
211 }
212
213 template<size_t R>
214 [[nodiscard]] constexpr auto operator+(char const (&rhs)[R]) const noexcept
215 {
216 return *this + fixed_string<R - 1>(rhs);
217 }
218
223 template<size_t R>
224 [[nodiscard]] constexpr auto operator/(fixed_string<R> const& rhs) const noexcept
225 {
226 constexpr auto has_dot = N != 0 and R != 0 ? 1_uz : 0_uz;
228
229 auto dst_i = 0_uz;
230 for (auto src_i = 0_uz; src_i != N; ++src_i, ++dst_i) {
231 r[dst_i] = (*this)[src_i];
232 }
233
234 if (has_dot) {
235 r[dst_i++] = '/';
236 }
237
238 for (auto src_i = 0_uz; src_i != R; ++src_i, ++dst_i) {
239 r[dst_i] = rhs[src_i];
240 }
241
242 return r;
243 }
244
245 template<size_t R>
246 [[nodiscard]] constexpr auto operator/(char const (&rhs)[R]) const noexcept
247 {
248 return *this / fixed_string<R - 1>(rhs);
249 }
250};
251
252hi_export template<fixed_string Tag>
253[[nodiscard]] consteval uint32_t fourcc() noexcept
254{
255 static_assert(Tag.size() == 4, "fourcc must get a 4 character fixed_string");
256
257 return (static_cast<uint32_t>(get<0>(Tag)) << 24) | (static_cast<uint32_t>(get<1>(Tag)) << 16) |
258 (static_cast<uint32_t>(get<2>(Tag)) << 8) | static_cast<uint32_t>(get<3>(Tag));
259}
260
261hi_export template<fixed_string Tag>
262consteval uint32_t operator"" _fcc()
263{
264 return fourcc<Tag>();
265}
266
267hi_export template<std::size_t N>
268fixed_string(char const (&str)[N]) -> fixed_string<N - 1>;
269
270hi_export template<std::invocable F>
271fixed_string(F const& f) -> fixed_string<F{}().size()>;
272
273// clang-format off
274#define hi_to_fixed_string(x) ::hi::fixed_string{[]{ return x; }}
275// clang-format on
276
277}} // namespace hi::v1
278
279// XXX #617 MSVC bug does not handle partial specialization in modules, outside a namespace.
280namespace std {
281hi_export template<std::size_t N>
282struct formatter<hi::fixed_string<N>, char> : formatter<std::string_view, char> {
283 constexpr auto format(hi::fixed_string<N> const& t, auto& fc) const
284 {
285 return std::formatter<std::string_view, char>::format(static_cast<std::string_view>(t), fc);
286 }
287};
288}
Utilities to assert and bound check.
Functions for casting values between types savely.
Utilities for throwing exceptions and terminating the application.
STL namespace.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
A string which may be used as a none-type template parameter.
Definition fixed_string.hpp:42
constexpr auto operator/(fixed_string< R > const &rhs) const noexcept
Join two strings with a slash '/'.
Definition fixed_string.hpp:224
constexpr fixed_string(F const &f) noexcept
Create a fixed string from function returning a string-like.
Definition fixed_string.hpp:65
constexpr auto operator+(fixed_string< R > const &rhs) const noexcept
Append two strings.
Definition fixed_string.hpp:199
T begin(T... args)
T data(T... args)
T terminate(T... args)