Flow 1.0.2
Flow project: Full implementation reference.
string_view.hpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19#pragma once
20
21#include <string>
22#include <string_view>
23
24namespace flow::util
25{
26
27// Types.
28
29/* Normally Basic_string_view would be forward-declared in a _fwd.hpp and defined here; instead it is defined here,
30 * and util_fwd.hpp simply `#include`s us. This is in accordance with the list of known reasonable exceptions to
31 * the _fwd.hpp pattern; namely since our String_view et al = glorified alias for std::string_view et al. */
32
33/**
34 * Essentially alias for a C++17-conforming string-view class template, which is a very lightweight `std::string`-like
35 * representation of a character sequence already in memory. As of March 2022 the alias is formally to
36 * `std::basic_string_view` (unlike in the past, when that was not available -- until C++17). However the alias remains
37 * to, at least, avoid breaking user code -- by providing the #String_view related alias.
38 * In addition this API-only subclass adds starts_with() and ends_with()
39 * which implement the common-sense C++20 `basic_string_view` operations `starts_with()` and `ends_width()`.
40 * These existed in the Boost `basic_string_view` that, pre-C++17, used to be the
41 * `String_view` alias target (when `Ch` is `char`). The downgrade due to their lack of inclusion in C++17 (which
42 * inaugurated `*string_view` in C++ STL) is unfortunate; but these replacements are fine.
43 *
44 * @see #String_view, which is to `std::string_view` what the present template is to `std::basic_string_view`.
45 * I.e., when working with `char` string sequences, which is typical, use #String_view.
46 *
47 * ### Rationale ###
48 * Why is this even a thing? Why not use `std::basic_string_view` and `std::string_view` all over?
49 * Answer: It is mostly historic. Flow was C++14 until ~3/2022.
50 * `std::string_view` was added in C++17. Before then, #String_view aliased to `boost::string_view`
51 * (another possibility would have been `boost::string_ref` -- same API -- long story), because it was available for
52 * C++14. Now that we're on C++17, it's better to use the `std` thing, especially since many STL (and Boost, nowadays)
53 * APIs take `std::string_view` directly. Hence the alias changed as planned all along.
54 *
55 * However the type alias remains. Pragmatically: much code uses #String_view, even outside Flow, and there's no harm
56 * in an alias, particularly since we add the nice starts_with() and ends_with(). The alias was actively useful before;
57 * now removing it is a breaking change.
58 *
59 * ### Implementation/API note ###
60 * It would have been ideal to define the various constructors by simply inheriting all of `std::basic_string_view`
61 * ctors via the single statement `using Base::Base`. However, at least with our gcc, it appears to cause some issue
62 * in propagating `constexpr`ness of these constructors (which is effectively used, at least, by the flow::log macros
63 * to make certain optimizations possible): compile errors. To avoid this and various conversion issues, a number
64 * of constructors are explicitly (re)defined.
65 */
66template<typename Ch, typename Traits = std::char_traits<Ch>>
68 public std::basic_string_view<Ch, Traits>
69{
70public:
71 // Types.
72
73 /// Short-hand for the base. We add no data of our own in this subclass, just a handful of APIs.
74 using Base = std::basic_string_view<Ch, Traits>;
75
76 // Ctors/destructor.
77
78 /// Constructs null view: identical to #Base API.
79 constexpr Basic_string_view() noexcept;
80
81 /**
82 * Constructs view to string at given start location and length: identical to #Base API.
83 * @param s
84 * See #Base API.
85 * @param count
86 * See #Base API.
87 */
88 constexpr Basic_string_view(Ch const * s, size_t count);
89
90 /**
91 * Constructs view to given NUL-terminated string: identical to #Base API.
92 * @param s
93 * See #Base API.
94 */
95 constexpr Basic_string_view(Ch const * s);
96
97 /**
98 * Boring copy constructor: identical to #Base API.
99 * @param s
100 * See #Base API.
101 */
102 constexpr Basic_string_view(const Basic_string_view& s) noexcept;
103
104 /**
105 * Identical to copy constructor but converts from a vanilla #Base.
106 * @param s
107 * See copy constructor.
108 */
109 constexpr Basic_string_view(Base s);
110
111 /**
112 * Constructs view directly into a `std::basic_string` (e.g., `std::string`). `basic_string` has a conversion
113 * operator to `basic_string_view` but technically not to our slight embellishment thereof, Basic_string_view.
114 * @param s
115 * Self-explanatory.
116 */
117 Basic_string_view(const std::basic_string<Ch, Traits>& s);
118
119 // Methods.
120
121 /**
122 * Boring copy assignment: identical to #Base API.
123 * @param s
124 * See #Base API.
125 * @return See #Base API.
126 */
127 constexpr Basic_string_view& operator=(const Basic_string_view& s) noexcept;
128
129 /**
130 * Equivalent to C++20 `basic_string_view::starts_with()` which is lacking in C++17 but present in C++20 and
131 * previously-used-in-Flow Boost equivalent `string_view`.
132 *
133 * @param needle
134 * Possible prefix within `*this`.
135 * @return Whether `*this` contains `needle` as prefix.
136 */
137 bool starts_with(Basic_string_view needle) const;
138
139 /**
140 * Equivalent to C++20 `basic_string_view::starts_with()` which is lacking in C++17 but present in C++20 and
141 * previously-used-in-Flow Boost equivalent `string_view`.
142 *
143 * @param needle
144 * Possible prefix within `*this`.
145 * @return Whether `*this` contains `needle` as prefix.
146 */
147 bool starts_with(Ch const * needle) const;
148
149 /**
150 * Equivalent to C++20 `basic_string_view::starts_with()` which is lacking in C++17 but present in C++20 and
151 * previously-used-in-Flow Boost equivalent `string_view`.
152 *
153 * @param needle
154 * Possible prefix within `*this`.
155 * @return Whether `*this` contains `needle` as prefix.
156 */
157 bool starts_with(Ch needle) const;
158
159 /**
160 * Equivalent to C++20 `basic_string_view::ends_with()` which is lacking in C++17 but present in C++20 and
161 * previously-used-in-Flow Boost equivalent `string_view`.
162 *
163 * @param needle
164 * Possible postfix within `*this`.
165 * @return Whether `*this` contains `needle` as postfix.
166 */
167 bool ends_with(Basic_string_view needle) const;
168
169 /**
170 * Equivalent to C++20 `basic_string_view::ends_with()` which is lacking in C++17 but present in C++20 and
171 * previously-used-in-Flow Boost equivalent `string_view`.
172 *
173 * @param needle
174 * Possible postfix within `*this`.
175 * @return Whether `*this` contains `needle` as postfix.
176 */
177 bool ends_with(Ch const * needle) const;
178
179 /**
180 * Equivalent to C++20 `basic_string_view::ends_with()` which is lacking in C++17 but present in C++20 and
181 * previously-used-in-Flow Boost equivalent `string_view`.
182 *
183 * @param needle
184 * Possible postfix within `*this`.
185 * @return Whether `*this` contains `needle` as postfix.
186 */
187 bool ends_with(Ch needle) const;
188}; // class Basic_string_view
189
190/// Commonly used `char`-based Basic_string_view. See its doc header.
192
193// Template implementations.
194
195template<typename Ch, typename Traits>
196constexpr Basic_string_view<Ch, Traits>::Basic_string_view(Ch const * s, size_t count) :
197 Base(s, count)
198{
199 // That's it.
200}
201
202template<typename Ch, typename Traits>
204 Base(s)
205{
206 // That's it.
207}
208
209template<typename Ch, typename Traits>
211 Base(s)
212{
213 // That's it.
214}
215template<typename Ch, typename Traits>
216Basic_string_view<Ch, Traits>::Basic_string_view(const std::basic_string<Ch, Traits>& s) :
217 Basic_string_view(s.data(), s.size())
218{
219 // That's it.
220}
221
222template<typename Ch, typename Traits>
223constexpr Basic_string_view<Ch, Traits>::Basic_string_view() noexcept = default;
224template<typename Ch, typename Traits>
225constexpr Basic_string_view<Ch, Traits>::Basic_string_view(const Basic_string_view&) noexcept = default;
226template<typename Ch, typename Traits>
227constexpr Basic_string_view<Ch, Traits>& Basic_string_view<Ch, Traits>::operator=(const Basic_string_view& s) noexcept
228 = default;
229
230template<typename Ch, typename Traits>
231bool Basic_string_view<Ch, Traits>::starts_with(Basic_string_view needle) const
232{
233 const auto needle_sz = needle.size();
234 if (this->size() < needle.size())
235 {
236 return false;
237 }
238 // else
239 for (size_t idx = 0; idx != needle_sz; ++idx) // needle_sz == 0 => no problem.
240 {
241 if (!Traits::eq((*this)[idx], needle[idx]))
242 {
243 return false;
244 }
245 }
246
247 return true;
248}
249
250template<typename Ch, typename Traits>
252{
253 /* Conceivably hand-writing it to avoid a Traits::length() search for NUL (in constructing the 2nd
254 * arg to starts_with() below) could improve perf; but on the other
255 * hand it could even slow it down in the haystack-too-small case; plus length() is likely to be
256 * assembly-optimized nicely. Let's just not worry too much about it. */
257 return starts_with(Basic_string_view(needle));
258}
259
260template<typename Ch, typename Traits>
262{
263 return (!this->empty()) && (this->front() == needle);
264}
265
266template<typename Ch, typename Traits>
268{
269 const auto needle_sz = needle.size();
270 if (this->size() < needle.size())
271 {
272 return false;
273 }
274 // else
275 const auto base_haystack_idx = this->size() - needle_sz;
276 for (size_t idx = 0; idx != needle_sz; ++idx) // needle_sz == 0 => no problem.
277 {
278 if (!Traits::eq((*this)[base_haystack_idx + idx], needle[idx]))
279 {
280 return false;
281 }
282 }
283
284 return true;
285}
286
287template<typename Ch, typename Traits>
288bool Basic_string_view<Ch, Traits>::ends_with(Ch const * needle) const
289{
290 // Same comment as in starts_with().
291 return ends_with(Basic_string_view(needle));
292}
293
294template<typename Ch, typename Traits>
296{
297 return (!this->empty()) && (this->back() == needle);
298}
299
300} // namespace flow::util
Essentially alias for a C++17-conforming string-view class template, which is a very lightweight std:...
Definition: string_view.hpp:69
bool ends_with(Basic_string_view needle) const
Equivalent to C++20 basic_string_view::ends_with() which is lacking in C++17 but present in C++20 and...
std::basic_string_view< Ch, Traits > Base
Short-hand for the base. We add no data of our own in this subclass, just a handful of APIs.
Definition: string_view.hpp:74
constexpr Basic_string_view() noexcept
Constructs null view: identical to Base API.
bool starts_with(Basic_string_view needle) const
Equivalent to C++20 basic_string_view::starts_with() which is lacking in C++17 but present in C++20 a...
Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module...
Definition: basic_blob.hpp:29
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.