morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
fixed_string.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5/// @file detail/fixed_string.hpp
6/// @brief Shared compile-time, NTTP-capable fixed string.
7
8#include <array>
9#include <concepts>
10#include <cstddef>
11#include <string>
12#include <string_view>
13
14namespace morph::detail {
15
16/// @brief A structural, NTTP-capable compile-time string.
17///
18/// A literal type with public array storage, so it satisfies the rules for a
19/// non-type template parameter. Two `FixedString` values of the same length
20/// with the same characters compare equal as template arguments, so a type
21/// parameterised on a `FixedString` written identically in two translation
22/// units is one and the same type.
23///
24/// This is the single canonical definition. The forms layer aliases it twice —
25/// as `morph::forms::FixedString` (used by `Choice`) and as
26/// `morph::forms::detail::LiteralString` (which captures an `equals` rule
27/// literal) — and the units layer once, as
28/// `morph::units::detail::FixedString` (used by `NamedQuantity`). None of them
29/// redefine their own copy.
30///
31/// @tparam N Storage size including the terminating null.
32template <std::size_t N>
34 /// @brief Character storage (null-terminated).
35 std::array<char, N> data{};
36
37 /// @brief Captures a string literal.
38 ///
39 /// `constexpr`, not `consteval`: as an NTTP this is still only ever
40 /// evaluated at compile time (that context demands it regardless), but
41 /// `constexpr` additionally lets a *function parameter* of type
42 /// `const char (&)[N]` be captured — `morph::forms::equals(&A::code, "X")`
43 /// forwards its literal exactly that way, and a `consteval` constructor
44 /// cannot be called with a reference parameter, which is not itself a
45 /// constant expression.
46 ///
47 /// @param literal The literal to copy, e.g. `"ListSamples"`.
48 // A NOLINTNEXTLINE directive must sit on ONE physical line to apply to the
49 // next one; wrapped, it silently annotates the comment instead. Hence the
50 // long lines below, and the clang-format guard around them.
51 // String literals ARE C arrays — that is the whole point of this type.
52 // clang-format off
53 // NOLINTNEXTLINE(modernize-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays, cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-pro-bounds-avoid-unchecked-container-access)
54 constexpr FixedString(const char (&literal)[N]) noexcept {
55 for (std::size_t index = 0; index < N; ++index) {
56 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-pro-bounds-avoid-unchecked-container-access)
57 data[index] = literal[index];
58 }
59 }
60 // clang-format on
61
62 /// @brief A view of the string (without the terminating null).
63 /// @return The string contents.
64 [[nodiscard]] constexpr std::string_view view() const noexcept { return {data.data(), N - 1}; }
65
66 /// @brief Compares against any string-like value.
67 ///
68 /// A hidden friend, so it is reachable by ADL from wherever a
69 /// `FixedString` is compared without polluting ordinary name lookup. Being
70 /// declared here rather than in an aliasing namespace matters: ADL keys on
71 /// the *type's* namespace (`morph::detail`), which an alias such as
72 /// `morph::forms::LiteralString` does not change.
73 ///
74 /// @tparam S String-like operand type (`std::string` or `std::string_view`).
75 /// @param lhs Value to compare.
76 /// @param rhs Captured literal to compare against.
77 /// @return `true` if both hold the same characters.
78 template <typename S>
79 requires std::same_as<S, std::string> || std::same_as<S, std::string_view>
80 [[nodiscard]] friend constexpr bool operator==(const S& lhs, const FixedString& rhs) noexcept {
81 return std::string_view{lhs} == rhs.view();
82 }
83};
84
85} // namespace morph::detail
friend constexpr bool operator==(const S &lhs, const FixedString &rhs) noexcept
Compares against any string-like value.
constexpr FixedString(const char(&literal)[N]) noexcept
Captures a string literal.
constexpr std::string_view view() const noexcept
A view of the string (without the terminating null).
std::array< char, N > data
Character storage (null-terminated).