.gitignore: ignore local vscode workspace settings file
[lttng-tools.git] / src / common / string-utils / c-string-view.hpp
1 /*
2 * Copyright (c) 2023 Philippe Proulx <pproulx@efficios.com>
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7 #ifndef LTTNG_C_STRING_VIEW_HPP
8 #define LTTNG_C_STRING_VIEW_HPP
9
10 #include <common/format.hpp>
11 #include <common/type-traits.hpp>
12
13 #include <cstddef>
14 #include <cstring>
15 #include <functional>
16 #include <string>
17
18 namespace lttng {
19
20 /*
21 * A view on a constant null-terminated C string.
22 */
23 class c_string_view final {
24 public:
25 /*
26 * Builds an empty view (data() returns `nullptr`).
27 *
28 * Intentionally not explicit.
29 */
30 constexpr c_string_view() noexcept = default;
31
32 /*
33 * Builds a view of the C string `str` (may be `nullptr`).
34 *
35 * Intentionally not explicit.
36 */
37 /* NOLINTBEGIN(google-explicit-constructor) */
38 constexpr c_string_view(const char *const str) noexcept : _str{ str }
39 {
40 }
41 /* NOLINTEND(google-explicit-constructor) */
42
43 /*
44 * Builds a view of the string `str`.
45 */
46 /* NOLINTBEGIN(google-explicit-constructor) */
47 c_string_view(const std::string& str) noexcept : _str{ str.c_str() }
48 {
49 }
50 /* NOLINTEND */
51
52 /*
53 * Makes this view view the C string `str` (may be `nullptr`).
54 */
55 c_string_view& operator=(const char *const str) noexcept
56 {
57 _str = str;
58 return *this;
59 }
60
61 /*
62 * Viewed null-terminated C string (may be `nullptr`).
63 */
64 const char *data() const noexcept
65 {
66 return _str;
67 }
68
69 /*
70 * Alias of data().
71 */
72 operator const char *() const noexcept /* NOLINT(google-explicit-constructor) */
73 {
74 return this->data();
75 }
76
77 /*
78 * Evaluate as boolean (false means an empty string).
79 */
80 operator bool() const noexcept /* NOLINT(google-explicit-constructor) */
81 {
82 return *this->data();
83 }
84
85 /*
86 * Alias of data().
87 */
88 const char *operator*() const noexcept
89 {
90 return this->data();
91 }
92
93 /*
94 * Alias of data().
95 *
96 * data() must not return `nullptr`.
97 */
98 const char *begin() const noexcept
99 {
100 return this->data();
101 }
102
103 /*
104 * Pointer to the null character of the viewed C string.
105 *
106 * data() must not return `nullptr`.
107 */
108 const char *end() const noexcept
109 {
110 return _str + this->len();
111 }
112
113 /*
114 * Length of the viewed C string, excluding the null character.
115 *
116 * data() must not return `nullptr`.
117 */
118 std::size_t len() const noexcept
119 {
120 return std::strlen(_str);
121 }
122
123 /*
124 * Returns an `std::string` instance containing a copy of the viewed
125 * C string.
126 *
127 * data() must not return `nullptr`.
128 */
129 std::string str() const
130 {
131 return std::string{ _str };
132 }
133
134 /*
135 * Alias of str().
136 */
137 operator std::string() const /* NOLINT(google-explicit-constructor) */
138 {
139 return this->str();
140 }
141
142 /*
143 * Returns the character at index `i`.
144 *
145 * `i` must be less than what len() returns.
146 *
147 * data() must not return `nullptr`.
148 */
149 char operator[](const std::size_t i) const noexcept
150 {
151 return _str[i];
152 }
153
154 bool startsWith(const lttng::c_string_view prefix) const noexcept
155 {
156 return std::strncmp(_str, (const char *) prefix, prefix.len()) == 0;
157 }
158
159 private:
160 const char *_str = nullptr;
161 };
162
163 inline const char *format_as(const c_string_view& str)
164 {
165 return str ? *str : "(null)";
166 }
167
168 namespace internal {
169
170 template <typename StrT>
171 const char *as_const_char_ptr(StrT&& val) noexcept
172 {
173 return val.data();
174 }
175
176 inline const char *as_const_char_ptr(const char *const val) noexcept
177 {
178 return val;
179 }
180
181 template <typename StrT>
182 using comparable_with_c_string_view = lttng::traits::
183 is_one_of<typename std::decay<StrT>::type, c_string_view, std::string, const char *>;
184
185 } /* namespace internal */
186
187 /*
188 * Returns true if `lhs` is equal to `rhs`.
189 *
190 * `LhsT` and `RhsT` may be any of:
191 *
192 * • `const char *`
193 * • `std::string`
194 * • `c_string_view`
195 *
196 * Both `lhs` and `rhs` must not have an underlying `nullptr` raw data.
197 */
198 template <
199 typename LhsT,
200 typename RhsT,
201 typename =
202 typename std::enable_if<internal::comparable_with_c_string_view<LhsT>::value>::type,
203 typename =
204 typename std::enable_if<internal::comparable_with_c_string_view<RhsT>::value>::type>
205 bool operator==(LhsT&& lhs, RhsT&& rhs) noexcept
206 {
207 const auto raw_lhs = internal::as_const_char_ptr(lhs);
208 const auto raw_rhs = internal::as_const_char_ptr(rhs);
209
210 return std::strcmp(raw_lhs, raw_rhs) == 0;
211 }
212
213 /*
214 * Returns true if `lhs` is not equal to `rhs`.
215 *
216 * `LhsT` and `RhsT` may be any of:
217 *
218 * • `const char *`
219 * • `std::string`
220 * • `c_string_view`
221 *
222 * Both `lhs` and `rhs` must not have an underlying `nullptr` raw data.
223 */
224 template <
225 typename LhsT,
226 typename RhsT,
227 typename =
228 typename std::enable_if<internal::comparable_with_c_string_view<LhsT>::value>::type,
229 typename =
230 typename std::enable_if<internal::comparable_with_c_string_view<RhsT>::value>::type>
231 bool operator!=(LhsT&& lhs, RhsT&& rhs) noexcept
232 {
233 return !(std::forward<LhsT>(lhs) == std::forward<RhsT>(rhs));
234 }
235
236 } /* namespace lttng */
237
238 /*
239 * Appends `rhs` to `lhs`.
240 */
241 inline void operator+=(std::string& lhs, lttng::c_string_view rhs)
242 {
243 lhs += rhs.data();
244 }
245
246 namespace std {
247 template <>
248 struct hash<lttng::c_string_view> {
249 std::size_t operator()(const lttng::c_string_view& str) const
250 {
251 auto hash_value = std::hash<char>{}('\0');
252
253 for (auto character : str) {
254 hash_value ^= std::hash<decltype(character)>{}(character);
255 }
256
257 return hash_value;
258 }
259 };
260 } /* namespace std */
261
262 #endif /* LTTNG_C_STRING_VIEW_HPP */
This page took 0.03496 seconds and 4 git commands to generate.