WPILibC++ 2024.3.2
ct_string.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <stdint.h>
8
9#include <array>
10#include <limits>
11#include <stdexcept>
12#include <string>
13#include <string_view>
14
15namespace wpi {
16
17// derived from:
18// https://codereview.stackexchange.com/questions/282514/string-literals-concatenation-with-support-for-dynamic-strings
19
20/**
21 * Fixed length string (array of character) for compile time use.
22 *
23 * @tparam N number of characters
24 * @tparam Char character type
25 * @tparam Traits character traits
26 */
27template <typename Char, typename Traits, size_t N>
28 requires(N < (std::numeric_limits<size_t>::max)())
29struct ct_string {
30 std::array<Char, N + 1> chars;
31
32 template <size_t M>
33 requires(M <= (N + 1))
34 constexpr ct_string(Char const (&s)[M]) { // NOLINT
35 if constexpr (M == (N + 1)) {
36 if (s[N] != Char{}) {
37 throw std::logic_error{"char array not null terminated"};
38 }
39 }
40
41 // avoid dependency on <algorithm>
42 // auto p = std::ranges::copy(s, chars.begin()).out;
43 auto p = chars.begin();
44 for (auto c : s) {
45 *p++ = c;
46 }
47 // std::ranges::fill() isn't constexpr on GCC 11
48 while (p != chars.end()) {
49 *p++ = Char{};
50 }
51 }
52
53 explicit constexpr ct_string(std::basic_string_view<Char, Traits> s) {
54 // avoid dependency on <algorithm>
55 // auto p = std::ranges::copy(s, chars.begin()).out;
56 auto p = chars.begin();
57 for (auto c : s) {
58 *p++ = c;
59 }
60 // std::ranges::fill() isn't constexpr on GCC 11
61 while (p != chars.end()) {
62 *p++ = Char{};
63 }
64 }
65
66 constexpr bool operator==(const ct_string<Char, Traits, N>&) const = default;
67
68 constexpr bool operator==(const std::basic_string<Char, Traits>& rhs) const {
69 if (size() != rhs.size()) {
70 return false;
71 }
72
73 for (size_t i = 0; i < size(); ++i) {
74 if (chars[i] != rhs[i]) {
75 return false;
76 }
77 }
78
79 return true;
80 }
81
82 constexpr bool operator==(std::basic_string_view<Char, Traits> rhs) const {
83 if (size() != rhs.size()) {
84 return false;
85 }
86
87 for (size_t i = 0; i < size(); ++i) {
88 if (chars[i] != rhs[i]) {
89 return false;
90 }
91 }
92
93 return true;
94 }
95
96 template <size_t M>
97 requires(N + 1 == M)
98 constexpr bool operator==(Char const (&rhs)[M]) const {
99 for (size_t i = 0; i < M; ++i) {
100 if (chars[i] != rhs[i]) {
101 return false;
102 }
103 }
104
105 return true;
106 }
107
108 constexpr bool operator==(const Char* rhs) const {
109 for (size_t i = 0; i < N + 1; ++i) {
110 if (chars[i] != rhs[i]) {
111 return false;
112 }
113
114 // If index of rhs's null terminator is less than lhs's size - 1, rhs is
115 // shorter than lhs
116 if (rhs[i] == '\0' && i < N) {
117 return false;
118 }
119 }
120
121 return true;
122 }
123
124 constexpr auto size() const noexcept { return N; }
125
126 constexpr auto begin() const noexcept { return chars.begin(); }
127 constexpr auto end() const noexcept { return chars.begin() + N; }
128
129 constexpr auto data() const noexcept { return chars.data(); }
130 constexpr auto c_str() const noexcept { return chars.data(); }
131
132 constexpr operator std::basic_string<Char, Traits>() // NOLINT
133 const noexcept {
134 return std::basic_string<Char, Traits>{chars.data(), N};
135 }
136
137 constexpr operator std::basic_string_view<Char, Traits>() // NOLINT
138 const noexcept {
139 return std::basic_string_view<Char, Traits>{chars.data(), N};
140 }
141};
142
143template <typename Char, size_t M>
145
146inline namespace literals {
147template <ct_string S>
148constexpr auto operator""_ct_string() {
149 return S;
150}
151} // namespace literals
152
153template <typename Char, typename Traits, size_t N1, size_t N2>
154constexpr auto operator+(ct_string<Char, Traits, N1> const& s1,
155 ct_string<Char, Traits, N2> const& s2) noexcept {
156 return Concat(s1, s2);
157}
158
159/**
160 * Concatenates multiple fixed_strings into a larger fixed_string at compile
161 * time.
162 *
163 * @param s1 first string
164 * @param s second and later strings
165 * @return concatenated string
166 */
167template <typename Char, typename Traits, size_t N1, size_t... N>
168constexpr auto Concat(ct_string<Char, Traits, N1> const& s1,
169 ct_string<Char, Traits, N> const&... s) {
170 // Need a dummy array to instantiate a ct_string.
171 constexpr Char dummy[1] = {};
172 auto res = ct_string<Char, Traits, (N1 + ... + N)>{dummy};
173
174 auto p = res.chars.begin();
175 auto append = [&p](auto&& s) {
176 // avoid dependency on <algorithm>
177 // p = std::ranges::copy(s, p).out;
178 for (auto c : s) {
179 *p++ = c;
180 }
181 };
182
183 (append(s1), ..., append(s));
184
185 return res;
186}
187
188// derived from:
189// https://github.com/tcsullivan/constexpr-to-string/blob/master/to_string.hpp
190
191/**
192 * Converts any integral to a ct_string at compile-time.
193 *
194 * @tparam N number to convert
195 * @tparam Base desired base, can be from 2 to 36
196 * @tparam Char character type
197 * @tparam Traits character traits
198 */
199template <intmax_t N, int Base = 10, typename Char = char,
200 typename Traits = std::char_traits<Char>>
201 requires(Base >= 2 && Base <= 36)
202constexpr auto NumToCtString() {
203 constexpr char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
204
205 auto buflen = [] {
206 size_t len = N > 0 ? 0 : 1;
207 for (auto n = N; n; len++, n /= Base) {
208 }
209 return len;
210 };
211 constexpr size_t size = buflen();
212
213 constexpr Char dummy[1] = {};
214 auto res = ct_string<Char, Traits, size>{dummy};
215
216 auto ptr = res.chars.data() + size;
217 if (N != 0) {
218 for (auto n = N; n; n /= Base) {
219 *--ptr = digits[(N < 0 ? -1 : 1) * (n % Base)];
220 }
221 if (N < 0) {
222 *--ptr = '-';
223 }
224 } else {
225 res.chars[0] = '0';
226 }
227
228 return res;
229}
230
231} // namespace wpi
auto ptr(T p) -> const void *
\rst Converts p to const void* for pointer formatting.
Definition: format.h:4100
Definition: xchar.h:71
static constexpr const velocity::meters_per_second_t c(299792458.0)
Speed of light in vacuum.
UnitTypeLhs() max(const UnitTypeLhs &lhs, const UnitTypeRhs &rhs)
Definition: base.h:3417
Definition: ntcore_cpp.h:26
constexpr auto NumToCtString()
Converts any integral to a ct_string at compile-time.
Definition: ct_string.h:202
constexpr auto Concat(ct_string< Char, Traits, N1 > const &s1, ct_string< Char, Traits, N > const &... s)
Concatenates multiple fixed_strings into a larger fixed_string at compile time.
Definition: ct_string.h:168
constexpr auto operator+(ct_string< Char, Traits, N1 > const &s1, ct_string< Char, Traits, N2 > const &s2) noexcept
Definition: ct_string.h:154
ct_string(Char const (&s)[M]) -> ct_string< Char, std::char_traits< Char >, M - 1 >
Fixed length string (array of character) for compile time use.
Definition: ct_string.h:29
constexpr auto end() const noexcept
Definition: ct_string.h:127
constexpr bool operator==(std::basic_string_view< Char, Traits > rhs) const
Definition: ct_string.h:82
constexpr bool operator==(const ct_string< Char, Traits, N > &) const =default
constexpr bool operator==(const Char *rhs) const
Definition: ct_string.h:108
constexpr auto size() const noexcept
Definition: ct_string.h:124
constexpr auto begin() const noexcept
Definition: ct_string.h:126
constexpr ct_string(std::basic_string_view< Char, Traits > s)
Definition: ct_string.h:53
constexpr bool operator==(const std::basic_string< Char, Traits > &rhs) const
Definition: ct_string.h:68
constexpr auto data() const noexcept
Definition: ct_string.h:129
constexpr auto c_str() const noexcept
Definition: ct_string.h:130
std::array< Char, N+1 > chars
Definition: ct_string.h:30
#define S(label, offset, message)
Definition: Errors.h:119