1 | /* |
2 | * Copyright 2016-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | // @author: Eric Niebler (eniebler) |
18 | // Fixed-size string type, for constexpr string handling. |
19 | |
20 | #pragma once |
21 | |
22 | #include <cassert> |
23 | #include <cstddef> |
24 | #include <initializer_list> |
25 | #include <iosfwd> |
26 | #include <stdexcept> |
27 | #include <string> |
28 | #include <type_traits> |
29 | #include <utility> |
30 | |
31 | #include <folly/ConstexprMath.h> |
32 | #include <folly/Portability.h> |
33 | #include <folly/Range.h> |
34 | #include <folly/Utility.h> |
35 | #include <folly/lang/Exception.h> |
36 | #include <folly/lang/Ordering.h> |
37 | #include <folly/portability/Constexpr.h> |
38 | |
39 | namespace folly { |
40 | |
41 | template <class Char, std::size_t N> |
42 | class BasicFixedString; |
43 | |
44 | template <std::size_t N> |
45 | using FixedString = BasicFixedString<char, N>; |
46 | |
47 | namespace detail { |
48 | namespace fixedstring { |
49 | |
50 | // This is a template so that the class static npos can be defined in the |
51 | // header. |
52 | template <class = void> |
53 | struct FixedStringBase_ { |
54 | static constexpr std::size_t npos = static_cast<std::size_t>(-1); |
55 | }; |
56 | |
57 | template <class Void> |
58 | constexpr std::size_t FixedStringBase_<Void>::npos; |
59 | |
60 | using FixedStringBase = FixedStringBase_<>; |
61 | |
62 | // Intentionally NOT constexpr. By making this not constexpr, we make |
63 | // checkOverflow below ill-formed in a constexpr context when the condition |
64 | // it's testing for fails. In this way, precondition violations are reported |
65 | // at compile-time instead of at runtime. |
66 | [[noreturn]] inline void assertOutOfBounds() { |
67 | assert(!"Array index out of bounds in BasicFixedString" ); |
68 | throw_exception<std::out_of_range>( |
69 | "Array index out of bounds in BasicFixedString" ); |
70 | } |
71 | |
72 | constexpr std::size_t checkOverflow(std::size_t i, std::size_t max) { |
73 | return i <= max ? i : (void(assertOutOfBounds()), max); |
74 | } |
75 | |
76 | constexpr std::size_t checkOverflowOrNpos(std::size_t i, std::size_t max) { |
77 | return i == FixedStringBase::npos |
78 | ? max |
79 | : (i <= max ? i : (void(assertOutOfBounds()), max)); |
80 | } |
81 | |
82 | // Intentionally NOT constexpr. See note above for assertOutOfBounds |
83 | [[noreturn]] inline void assertNotNullTerminated() noexcept { |
84 | assert(!"Non-null terminated string used to initialize a BasicFixedString" ); |
85 | std::terminate(); // Fail hard, fail fast. |
86 | } |
87 | |
88 | // Parsing help for human readers: the following is a constexpr noexcept |
89 | // function that accepts a reference to an array as a parameter and returns |
90 | // a reference to the same array. |
91 | template <class Char, std::size_t N> |
92 | constexpr const Char (&checkNullTerminated(const Char (&a)[N]) noexcept)[N] { |
93 | // Strange decltype(a)(a) used to make MSVC happy. |
94 | return a[N - 1u] == Char(0) |
95 | #ifndef NDEBUG |
96 | // In Debug mode, guard against embedded nulls: |
97 | && N - 1u == folly::detail::constexpr_strlen_internal(a, 0u) |
98 | #endif |
99 | ? decltype(a)(a) |
100 | : (assertNotNullTerminated(), decltype(a)(a)); |
101 | } |
102 | |
103 | // Rather annoyingly, GCC's -Warray-bounds warning issues false positives for |
104 | // this code. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61971 |
105 | #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5 |
106 | #pragma GCC diagnostic push |
107 | #pragma GCC diagnostic ignored "-Warray-bounds" |
108 | #endif |
109 | |
110 | template <class Left, class Right> |
111 | constexpr ordering compare_( |
112 | const Left& left, |
113 | std::size_t left_pos, |
114 | std::size_t left_size, |
115 | const Right& right, |
116 | std::size_t right_pos, |
117 | std::size_t right_size) noexcept { |
118 | return left_pos == left_size |
119 | ? (right_pos == right_size ? ordering::eq : ordering::lt) |
120 | : (right_pos == right_size ? ordering::gt |
121 | : (left[left_pos] < right[right_pos] |
122 | ? ordering::lt |
123 | : (left[left_pos] > right[right_pos] |
124 | ? ordering::gt |
125 | : fixedstring::compare_( |
126 | left, |
127 | left_pos + 1u, |
128 | left_size, |
129 | right, |
130 | right_pos + 1u, |
131 | right_size)))); |
132 | } |
133 | |
134 | template <class Left, class Right> |
135 | constexpr bool equal_( |
136 | const Left& left, |
137 | std::size_t left_size, |
138 | const Right& right, |
139 | std::size_t right_size) noexcept { |
140 | return left_size == right_size && |
141 | ordering::eq == compare_(left, 0u, left_size, right, 0u, right_size); |
142 | } |
143 | |
144 | template <class Char, class Left, class Right> |
145 | constexpr Char char_at_( |
146 | const Left& left, |
147 | std::size_t left_count, |
148 | const Right& right, |
149 | std::size_t right_count, |
150 | std::size_t i) noexcept { |
151 | return i < left_count |
152 | ? left[i] |
153 | : i < (left_count + right_count) ? right[i - left_count] : Char(0); |
154 | } |
155 | |
156 | template <class Char, class Left, class Right> |
157 | constexpr Char char_at_( |
158 | const Left& left, |
159 | std::size_t left_size, |
160 | std::size_t left_pos, |
161 | std::size_t left_count, |
162 | const Right& right, |
163 | std::size_t right_pos, |
164 | std::size_t right_count, |
165 | std::size_t i) noexcept { |
166 | return i < left_pos |
167 | ? left[i] |
168 | : (i < right_count + left_pos ? right[i - left_pos + right_pos] |
169 | : (i < left_size - left_count + right_count |
170 | ? left[i - right_count + left_count] |
171 | : Char(0))); |
172 | } |
173 | |
174 | template <class Left, class Right> |
175 | constexpr bool find_at_( |
176 | const Left& left, |
177 | const Right& right, |
178 | std::size_t pos, |
179 | std::size_t count) noexcept { |
180 | return 0u == count || |
181 | (left[pos + count - 1u] == right[count - 1u] && |
182 | find_at_(left, right, pos, count - 1u)); |
183 | } |
184 | |
185 | template <class Char, class Right> |
186 | constexpr bool |
187 | find_one_of_at_(Char ch, const Right& right, std::size_t pos) noexcept { |
188 | return 0u != pos && |
189 | (ch == right[pos - 1u] || find_one_of_at_(ch, right, pos - 1u)); |
190 | } |
191 | |
192 | template <class Left, class Right> |
193 | constexpr std::size_t find_( |
194 | const Left& left, |
195 | std::size_t left_size, |
196 | const Right& right, |
197 | std::size_t pos, |
198 | std::size_t count) noexcept { |
199 | return find_at_(left, right, pos, count) ? pos |
200 | : left_size <= pos + count |
201 | ? FixedStringBase::npos |
202 | : find_(left, left_size, right, pos + 1u, count); |
203 | } |
204 | |
205 | template <class Left, class Right> |
206 | constexpr std::size_t rfind_( |
207 | const Left& left, |
208 | const Right& right, |
209 | std::size_t pos, |
210 | std::size_t count) noexcept { |
211 | return find_at_(left, right, pos, count) |
212 | ? pos |
213 | : 0u == pos ? FixedStringBase::npos |
214 | : rfind_(left, right, pos - 1u, count); |
215 | } |
216 | |
217 | template <class Left, class Right> |
218 | constexpr std::size_t find_first_of_( |
219 | const Left& left, |
220 | std::size_t left_size, |
221 | const Right& right, |
222 | std::size_t pos, |
223 | std::size_t count) noexcept { |
224 | return find_one_of_at_(left[pos], right, count) ? pos |
225 | : left_size <= pos + 1u |
226 | ? FixedStringBase::npos |
227 | : find_first_of_(left, left_size, right, pos + 1u, count); |
228 | } |
229 | |
230 | template <class Left, class Right> |
231 | constexpr std::size_t find_first_not_of_( |
232 | const Left& left, |
233 | std::size_t left_size, |
234 | const Right& right, |
235 | std::size_t pos, |
236 | std::size_t count) noexcept { |
237 | return !find_one_of_at_(left[pos], right, count) ? pos |
238 | : left_size <= pos + 1u |
239 | ? FixedStringBase::npos |
240 | : find_first_not_of_(left, left_size, right, pos + 1u, count); |
241 | } |
242 | |
243 | template <class Left, class Right> |
244 | constexpr std::size_t find_last_of_( |
245 | const Left& left, |
246 | const Right& right, |
247 | std::size_t pos, |
248 | std::size_t count) noexcept { |
249 | return find_one_of_at_(left[pos], right, count) |
250 | ? pos |
251 | : 0u == pos ? FixedStringBase::npos |
252 | : find_last_of_(left, right, pos - 1u, count); |
253 | } |
254 | |
255 | template <class Left, class Right> |
256 | constexpr std::size_t find_last_not_of_( |
257 | const Left& left, |
258 | const Right& right, |
259 | std::size_t pos, |
260 | std::size_t count) noexcept { |
261 | return !find_one_of_at_(left[pos], right, count) |
262 | ? pos |
263 | : 0u == pos ? FixedStringBase::npos |
264 | : find_last_not_of_(left, right, pos - 1u, count); |
265 | } |
266 | |
267 | struct Helper { |
268 | template <class Char, class Left, class Right, std::size_t... Is> |
269 | static constexpr BasicFixedString<Char, sizeof...(Is)> concat_( |
270 | const Left& left, |
271 | std::size_t left_count, |
272 | const Right& right, |
273 | std::size_t right_count, |
274 | folly::index_sequence<Is...> is) noexcept { |
275 | return {left, left_count, right, right_count, is}; |
276 | } |
277 | |
278 | template <class Char, class Left, class Right, std::size_t... Is> |
279 | static constexpr BasicFixedString<Char, sizeof...(Is)> replace_( |
280 | const Left& left, |
281 | std::size_t left_size, |
282 | std::size_t left_pos, |
283 | std::size_t left_count, |
284 | const Right& right, |
285 | std::size_t right_pos, |
286 | std::size_t right_count, |
287 | folly::index_sequence<Is...> is) noexcept { |
288 | return {left, |
289 | left_size, |
290 | left_pos, |
291 | left_count, |
292 | right, |
293 | right_pos, |
294 | right_count, |
295 | is}; |
296 | } |
297 | |
298 | template <class Char, std::size_t N> |
299 | static constexpr const Char ( |
300 | &data_(const BasicFixedString<Char, N>& that) noexcept)[N + 1u] { |
301 | return that.data_; |
302 | } |
303 | }; |
304 | |
305 | #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 4 |
306 | #pragma GCC diagnostic pop |
307 | #endif |
308 | |
309 | template <class T> |
310 | FOLLY_CPP14_CONSTEXPR void constexpr_swap(T& a, T& b) noexcept( |
311 | noexcept(a = T(std::move(a)))) { |
312 | T tmp((std::move(a))); |
313 | a = std::move(b); |
314 | b = std::move(tmp); |
315 | } |
316 | |
317 | // For constexpr reverse iteration over a BasicFixedString |
318 | template <class T> |
319 | struct ReverseIterator { |
320 | private: |
321 | T* p_ = nullptr; |
322 | struct dummy_ { |
323 | T* p_ = nullptr; |
324 | }; |
325 | using other = typename std::conditional< |
326 | std::is_const<T>::value, |
327 | ReverseIterator<typename std::remove_const<T>::type>, |
328 | dummy_>::type; |
329 | |
330 | public: |
331 | using value_type = typename std::remove_const<T>::type; |
332 | using reference = T&; |
333 | using pointer = T*; |
334 | using difference_type = std::ptrdiff_t; |
335 | using iterator_category = std::random_access_iterator_tag; |
336 | |
337 | constexpr ReverseIterator() = default; |
338 | constexpr ReverseIterator(const ReverseIterator&) = default; |
339 | FOLLY_CPP14_CONSTEXPR ReverseIterator& operator=(const ReverseIterator&) = |
340 | default; |
341 | constexpr explicit ReverseIterator(T* p) noexcept : p_(p) {} |
342 | constexpr /* implicit */ ReverseIterator(const other& that) noexcept |
343 | : p_(that.p_) {} |
344 | friend constexpr bool operator==( |
345 | ReverseIterator a, |
346 | ReverseIterator b) noexcept { |
347 | return a.p_ == b.p_; |
348 | } |
349 | friend constexpr bool operator!=( |
350 | ReverseIterator a, |
351 | ReverseIterator b) noexcept { |
352 | return !(a == b); |
353 | } |
354 | constexpr reference operator*() const { |
355 | return *(p_ - 1); |
356 | } |
357 | FOLLY_CPP14_CONSTEXPR ReverseIterator& operator++() noexcept { |
358 | --p_; |
359 | return *this; |
360 | } |
361 | FOLLY_CPP14_CONSTEXPR ReverseIterator operator++(int) noexcept { |
362 | auto tmp(*this); |
363 | --p_; |
364 | return tmp; |
365 | } |
366 | FOLLY_CPP14_CONSTEXPR ReverseIterator& operator--() noexcept { |
367 | ++p_; |
368 | return *this; |
369 | } |
370 | FOLLY_CPP14_CONSTEXPR ReverseIterator operator--(int) noexcept { |
371 | auto tmp(*this); |
372 | ++p_; |
373 | return tmp; |
374 | } |
375 | FOLLY_CPP14_CONSTEXPR ReverseIterator& operator+=(std::ptrdiff_t i) noexcept { |
376 | p_ -= i; |
377 | return *this; |
378 | } |
379 | friend constexpr ReverseIterator operator+( |
380 | std::ptrdiff_t i, |
381 | ReverseIterator that) noexcept { |
382 | return ReverseIterator{that.p_ - i}; |
383 | } |
384 | friend constexpr ReverseIterator operator+( |
385 | ReverseIterator that, |
386 | std::ptrdiff_t i) noexcept { |
387 | return ReverseIterator{that.p_ - i}; |
388 | } |
389 | FOLLY_CPP14_CONSTEXPR ReverseIterator& operator-=(std::ptrdiff_t i) noexcept { |
390 | p_ += i; |
391 | return *this; |
392 | } |
393 | friend constexpr ReverseIterator operator-( |
394 | ReverseIterator that, |
395 | std::ptrdiff_t i) noexcept { |
396 | return ReverseIterator{that.p_ + i}; |
397 | } |
398 | friend constexpr std::ptrdiff_t operator-( |
399 | ReverseIterator a, |
400 | ReverseIterator b) noexcept { |
401 | return b.p_ - a.p_; |
402 | } |
403 | constexpr reference operator[](std::ptrdiff_t i) const noexcept { |
404 | return *(*this + i); |
405 | } |
406 | }; |
407 | |
408 | } // namespace fixedstring |
409 | } // namespace detail |
410 | |
411 | // Defined in folly/hash/Hash.h |
412 | std::uint32_t hsieh_hash32_buf(const void* buf, std::size_t len); |
413 | |
414 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * |
415 | * \class BasicFixedString |
416 | * |
417 | * \tparam Char The character type. Must be a scalar type. |
418 | * \tparam N The capacity and max size of string instances of this type. |
419 | * |
420 | * \brief A class for holding up to `N` characters of type `Char` that is |
421 | * amenable to `constexpr` string manipulation. It is guaranteed to not |
422 | * perform any dynamic allocation. |
423 | * |
424 | * `BasicFixedString` is a `std::string` work-alike that stores characters in an |
425 | * internal buffer. It has minor interface differences that make it easy to work |
426 | * with strings in a `constexpr` context. |
427 | * |
428 | * \par Example: |
429 | * \par |
430 | * \code |
431 | * constexpr auto hello = makeFixedString("hello"); // a FixedString<5> |
432 | * constexpr auto world = makeFixedString("world"); // a FixedString<5> |
433 | * constexpr auto hello_world = hello + ' ' + world + '!'; // a FixedString<12> |
434 | * static_assert(hello_world == "hello world!", "neato!"); |
435 | * \endcode |
436 | * \par |
437 | * `FixedString<N>` is an alias for `BasicFixedString<char, N>`. |
438 | * |
439 | * \par Constexpr and In-place Mutation |
440 | * \par |
441 | * On a C++14 compiler, `BasicFixedString` supports the full `std::string` |
442 | * interface as `constexpr` member functions. On a C++11 compiler, the mutating |
443 | * members are not `constexpr`, but non-mutating alternatives, which create a |
444 | * new string, can be used instead. For example, instead of this: |
445 | * \par |
446 | * \code |
447 | * constexpr FixedString<10> replace_example_cpp14() { |
448 | * FixedString<10> test{"****"}; |
449 | * test.replace(1, 2, "!!!!"); |
450 | * return test; // returns "*!!!!*" |
451 | * } |
452 | * \endcode |
453 | * \par |
454 | * You might write this instead: |
455 | * \par |
456 | * \code |
457 | * constexpr FixedString<10> replace_example_cpp11() { |
458 | * // GNU compilers have an extension that make it possible to create |
459 | * // FixedString objects with a `""_fs` user-defined literal. |
460 | * using namespace folly; |
461 | * return makeFixedString("****").creplace(1, 2, "!!!!"); // "*!!!!*" |
462 | * } |
463 | * \endcode |
464 | * |
465 | * \par User-defined Literals |
466 | * Instead of using the `folly::makeFixedString` helper function, you can use |
467 | * a user-defined literal to make `FixedString` instances. The UDL feature of |
468 | * C++ has some limitations that make this less than ideal; you must tell the |
469 | * compiler roughly how many characters are in the string. The suffixes `_fs4`, |
470 | * `_fs8`, `_fs16`, `_fs32`, `_fs64`, and `_fs128` exist to create instances |
471 | * of types `FixedString<4>`, `FixedString<8>`, etc. For example: |
472 | * \par |
473 | * \code |
474 | * using namespace folly::string_literals; |
475 | * constexpr auto hello = "hello"_fs8; // A FixedString<8> containing "hello" |
476 | * \endcode |
477 | * \par |
478 | * See Error Handling below for what to expect when you try to exceed the |
479 | * capacity of a `FixedString` by storing too many characters in it. |
480 | * \par |
481 | * If your compiler supports GNU extensions, there is one additional suffix you |
482 | * can use: `_fs`. This suffix always creates `FixedString` objects of exactly |
483 | * the right size. For example: |
484 | * \par |
485 | * \code |
486 | * using namespace folly::string_literals; |
487 | * // NOTE: Only works on compilers with GNU extensions enabled. Clang and |
488 | * // gcc support this (-Wgnu-string-literal-operator-template): |
489 | * constexpr auto hello = "hello"_fs; // A FixedString<5> containing "hello" |
490 | * \endcode |
491 | * |
492 | * \par Error Handling: |
493 | * The capacity of a `BasicFixedString` is set at compile time. When the user |
494 | * asks the string to exceed its capacity, one of three things will happen, |
495 | * depending on the context: |
496 | *\par |
497 | * -# If the attempt is made while evaluating a constant expression, the |
498 | * program will fail to compile. |
499 | * -# Otherwise, if the program is being run in debug mode, it will `assert`. |
500 | * -# Otherwise, the failed operation will throw a `std::out_of_range` |
501 | * exception. |
502 | *\par |
503 | * This is also the case if an invalid offset is passed to any member function, |
504 | * or if `pop_back` or `cpop_back` is called on an empty `BasicFixedString`. |
505 | * |
506 | * Member functions documented as having preconditions will assert in Debug |
507 | * mode (`!defined(NDEBUG)`) on precondition failures. Those documented with |
508 | * \b Throws clauses will throw the specified exception on failure. Those with |
509 | * both a precondition and a \b Throws clause will assert in Debug and throw |
510 | * in Release mode. |
511 | */ |
512 | template <class Char, std::size_t N> |
513 | class BasicFixedString : private detail::fixedstring::FixedStringBase { |
514 | private: |
515 | template <class, std::size_t> |
516 | friend class BasicFixedString; |
517 | friend struct detail::fixedstring::Helper; |
518 | |
519 | // FUTURE: use constexpr_log2 to fold instantiations of BasicFixedString |
520 | // together. All BasicFixedString<C, N> instantiations could share the |
521 | // implementation of BasicFixedString<C, M>, where M is the next highest power |
522 | // of 2 after N. |
523 | // |
524 | // Also, because of alignment of the data_ and size_ members, N should never |
525 | // be smaller than `(alignof(std::size_t)/sizeof(C))-1` (-1 because of the |
526 | // null terminator). OR, create a specialization for BasicFixedString<C, 0u> |
527 | // that does not have a size_ member, since it is unnecessary. |
528 | Char data_[N + 1u]; // +1 for the null terminator |
529 | std::size_t size_; // Nbr of chars, not incl. null terminator. size_ <= N. |
530 | |
531 | using Indices = folly::make_index_sequence<N>; |
532 | |
533 | template <class That, std::size_t... Is> |
534 | constexpr BasicFixedString( |
535 | const That& that, |
536 | std::size_t size, |
537 | folly::index_sequence<Is...>, |
538 | std::size_t pos = 0, |
539 | std::size_t count = npos) noexcept |
540 | : data_{(Is < (size - pos) && Is < count ? that[Is + pos] : Char(0))..., |
541 | Char(0)}, |
542 | size_{folly::constexpr_min(size - pos, count)} {} |
543 | |
544 | template <std::size_t... Is> |
545 | constexpr BasicFixedString( |
546 | std::size_t count, |
547 | Char ch, |
548 | folly::index_sequence<Is...>) noexcept |
549 | : data_{((Is < count) ? ch : Char(0))..., Char(0)}, size_{count} {} |
550 | |
551 | // Concatenation constructor |
552 | template <class Left, class Right, std::size_t... Is> |
553 | constexpr BasicFixedString( |
554 | const Left& left, |
555 | std::size_t left_size, |
556 | const Right& right, |
557 | std::size_t right_size, |
558 | folly::index_sequence<Is...>) noexcept |
559 | : data_{detail::fixedstring::char_at_<Char>( |
560 | left, |
561 | left_size, |
562 | right, |
563 | right_size, |
564 | Is)..., |
565 | Char(0)}, |
566 | size_{left_size + right_size} {} |
567 | |
568 | // Replace constructor |
569 | template <class Left, class Right, std::size_t... Is> |
570 | constexpr BasicFixedString( |
571 | const Left& left, |
572 | std::size_t left_size, |
573 | std::size_t left_pos, |
574 | std::size_t left_count, |
575 | const Right& right, |
576 | std::size_t right_pos, |
577 | std::size_t right_count, |
578 | folly::index_sequence<Is...>) noexcept |
579 | : data_{detail::fixedstring::char_at_<Char>( |
580 | left, |
581 | left_size, |
582 | left_pos, |
583 | left_count, |
584 | right, |
585 | right_pos, |
586 | right_count, |
587 | Is)..., |
588 | Char(0)}, |
589 | size_{left_size - left_count + right_count} {} |
590 | |
591 | public: |
592 | using size_type = std::size_t; |
593 | using difference_type = std::ptrdiff_t; |
594 | using reference = Char&; |
595 | using const_reference = const Char&; |
596 | using pointer = Char*; |
597 | using const_pointer = const Char*; |
598 | using iterator = Char*; |
599 | using const_iterator = const Char*; |
600 | using reverse_iterator = detail::fixedstring::ReverseIterator<Char>; |
601 | using const_reverse_iterator = |
602 | detail::fixedstring::ReverseIterator<const Char>; |
603 | |
604 | using detail::fixedstring::FixedStringBase::npos; |
605 | |
606 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
607 | * Default construct |
608 | * \post `size() == 0` |
609 | * \post `at(0) == Char(0)` |
610 | */ |
611 | constexpr BasicFixedString() : data_{}, size_{} {} |
612 | |
613 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
614 | * Copy construct |
615 | * \post `size() == that.size()` |
616 | * \post `0 == strncmp(data(), that.data(), size())` |
617 | * \post `at(size()) == Char(0)` |
618 | */ |
619 | constexpr BasicFixedString(const BasicFixedString& /*that*/) = default; |
620 | |
621 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
622 | * Construct from a differently-sized BasicFixedString |
623 | * \pre `that.size() <= N` |
624 | * \post `size() == that.size()` |
625 | * \post `0 == strncmp(data(), that.data(), size())` |
626 | * \post `at(size()) == Char(0)` |
627 | * \throw std::out_of_range when that.size() > N. When M <= N, this |
628 | * constructor will never throw. |
629 | * \note Conversions from larger-capacity BasicFixedString objects to smaller |
630 | * ones (`M > N`) are allowed as long as the *size()* of the source string |
631 | * is small enough. |
632 | */ |
633 | template <std::size_t M> |
634 | constexpr /* implicit */ BasicFixedString( |
635 | const BasicFixedString<Char, M>& that) noexcept(M <= N) |
636 | : BasicFixedString{that, 0u, that.size_} {} |
637 | |
638 | // Why is this deleted? To avoid confusion with the constructor that takes |
639 | // a const Char* and a count. |
640 | template <std::size_t M> |
641 | constexpr BasicFixedString( |
642 | const BasicFixedString<Char, M>& that, |
643 | std::size_t pos) noexcept(false) = delete; |
644 | |
645 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
646 | * Construct from an BasicFixedString, an offset, and a count |
647 | * \param that The source string |
648 | * \param pos The starting position in `that` |
649 | * \param count The number of characters to copy. If `npos`, `count` is taken |
650 | * to be `that.size()-pos`. |
651 | * \pre `pos <= that.size()` |
652 | * \pre `count <= that.size()-pos && count <= N` |
653 | * \post `size() == count` |
654 | * \post `0 == strncmp(data(), that.data()+pos, size())` |
655 | * \post `at(size()) == Char(0)` |
656 | * \throw std::out_of_range when pos+count > that.size(), or when |
657 | * `count > N` |
658 | */ |
659 | template <std::size_t M> |
660 | constexpr BasicFixedString( |
661 | const BasicFixedString<Char, M>& that, |
662 | std::size_t pos, |
663 | std::size_t count) noexcept(false) |
664 | : BasicFixedString{ |
665 | that.data_, |
666 | that.size_, |
667 | folly::make_index_sequence<(M < N ? M : N)>{}, |
668 | pos, |
669 | detail::fixedstring::checkOverflow( |
670 | detail::fixedstring::checkOverflowOrNpos( |
671 | count, |
672 | that.size_ - |
673 | detail::fixedstring::checkOverflow(pos, that.size_)), |
674 | N)} {} |
675 | |
676 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
677 | * Construct from a string literal |
678 | * \pre `M-1 <= N` |
679 | * \pre `that[M-1] == Char(0)` |
680 | * \post `0 == strncmp(data(), that, M-1)` |
681 | * \post `size() == M-1` |
682 | * \post `at(size()) == Char(0)` |
683 | */ |
684 | template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type> |
685 | constexpr /* implicit */ BasicFixedString(const Char (&that)[M]) noexcept |
686 | : BasicFixedString{detail::fixedstring::checkNullTerminated(that), |
687 | M - 1u, |
688 | folly::make_index_sequence<M - 1u>{}} {} |
689 | |
690 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
691 | * Construct from a `const Char*` and count |
692 | * \pre `that` points to an array of at least `count` characters. |
693 | * \pre `count <= N` |
694 | * \post `size() == count` |
695 | * \post `0 == strncmp(data(), that, size())` |
696 | * \post `at(size()) == Char(0)` |
697 | * \throw std::out_of_range when count > N |
698 | */ |
699 | constexpr BasicFixedString(const Char* that, std::size_t count) noexcept( |
700 | false) |
701 | : BasicFixedString{that, |
702 | detail::fixedstring::checkOverflow(count, N), |
703 | Indices{}} {} |
704 | |
705 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
706 | * Construct an BasicFixedString that contains `count` characters, all |
707 | * of which are `ch`. |
708 | * \pre `count <= N` |
709 | * \post `size() == count` |
710 | * \post `npos == find_first_not_of(ch)` |
711 | * \post `at(size()) == Char(0)` |
712 | * \throw std::out_of_range when count > N |
713 | */ |
714 | constexpr BasicFixedString(std::size_t count, Char ch) noexcept(false) |
715 | : BasicFixedString{detail::fixedstring::checkOverflow(count, N), |
716 | ch, |
717 | Indices{}} {} |
718 | |
719 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
720 | * Construct an BasicFixedString from a `std::initializer_list` of |
721 | * characters. |
722 | * \pre `il.size() <= N` |
723 | * \post `size() == count` |
724 | * \post `0 == strncmp(data(), il.begin(), size())` |
725 | * \post `at(size()) == Char(0)` |
726 | * \throw std::out_of_range when il.size() > N |
727 | */ |
728 | constexpr BasicFixedString(std::initializer_list<Char> il) noexcept(false) |
729 | : BasicFixedString{il.begin(), il.size()} {} |
730 | |
731 | FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=( |
732 | const BasicFixedString&) noexcept = default; |
733 | |
734 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
735 | * Assign from a `BasicFixedString<Char, M>`. |
736 | * \pre `that.size() <= N` |
737 | * \post `size() == that.size()` |
738 | * \post `0 == strncmp(data(), that.begin(), size())` |
739 | * \post `at(size()) == Char(0)` |
740 | * \throw std::out_of_range when that.size() > N. When M <= N, this |
741 | * assignment operator will never throw. |
742 | * \note Assignments from larger-capacity BasicFixedString objects to smaller |
743 | * ones (`M > N`) are allowed as long as the *size* of the source string is |
744 | * small enough. |
745 | * \return `*this` |
746 | */ |
747 | template <std::size_t M> |
748 | FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=( |
749 | const BasicFixedString<Char, M>& that) noexcept(M <= N) { |
750 | detail::fixedstring::checkOverflow(that.size_, N); |
751 | size_ = that.copy(data_, that.size_); |
752 | data_[size_] = Char(0); |
753 | return *this; |
754 | } |
755 | |
756 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
757 | * Assign from a null-terminated array of characters. |
758 | * \pre `M < N` |
759 | * \pre `that` has no embedded null characters |
760 | * \pre `that[M-1]==Char(0)` |
761 | * \post `size() == M-1` |
762 | * \post `0 == strncmp(data(), that, size())` |
763 | * \post `at(size()) == Char(0)` |
764 | * \return `*this` |
765 | */ |
766 | template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type> |
767 | FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=( |
768 | const Char (&that)[M]) noexcept { |
769 | return assign(detail::fixedstring::checkNullTerminated(that), M - 1u); |
770 | } |
771 | |
772 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
773 | * Assign from an `initializer_list` of characters. |
774 | * \pre `il.size() <= N` |
775 | * \post `size() == il.size()` |
776 | * \post `0 == strncmp(data(), il.begin(), size())` |
777 | * \post `at(size()) == Char(0)` |
778 | * \throw std::out_of_range when il.size() > N |
779 | * \return `*this` |
780 | */ |
781 | FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=( |
782 | std::initializer_list<Char> il) noexcept(false) { |
783 | detail::fixedstring::checkOverflow(il.size(), N); |
784 | for (std::size_t i = 0u; i < il.size(); ++i) { |
785 | data_[i] = il.begin()[i]; |
786 | } |
787 | size_ = il.size(); |
788 | data_[size_] = Char(0); |
789 | return *this; |
790 | } |
791 | |
792 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
793 | * Conversion to folly::Range |
794 | * \return `Range<Char*>{begin(), end()}` |
795 | */ |
796 | FOLLY_CPP14_CONSTEXPR Range<Char*> toRange() noexcept { |
797 | return {begin(), end()}; |
798 | } |
799 | |
800 | /** |
801 | * \overload |
802 | */ |
803 | constexpr Range<const Char*> toRange() const noexcept { |
804 | return {begin(), end()}; |
805 | } |
806 | |
807 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
808 | * Conversion to std::basic_string<Char> |
809 | * \return `std::basic_string<Char>{begin(), end()}` |
810 | */ |
811 | /* implicit */ operator std::basic_string<Char>() const noexcept(false) { |
812 | return std::basic_string<Char>{begin(), end()}; |
813 | } |
814 | |
815 | std::basic_string<Char> toStdString() const noexcept(false) { |
816 | return std::basic_string<Char>{begin(), end()}; |
817 | } |
818 | |
819 | // Think hard about whether this is a good idea. It's certainly better than |
820 | // an implicit conversion to `const Char*` since `delete "hi"_fs` will fail |
821 | // to compile. But it creates ambiguities when passing a FixedString to an |
822 | // API that has overloads for `const char*` and `folly::Range`, for instance. |
823 | // using ArrayType = Char[N]; |
824 | // FOLLY_CPP14_CONSTEXPR /* implicit */ operator ArrayType&() noexcept { |
825 | // return data_; |
826 | // } |
827 | |
828 | // using ConstArrayType = const Char[N]; |
829 | // constexpr /* implicit */ operator ConstArrayType&() const noexcept { |
830 | // return data_; |
831 | // } |
832 | |
833 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
834 | * Assigns a sequence of `count` characters of value `ch`. |
835 | * \param count The count of characters. |
836 | * \param ch |
837 | * \pre `count <= N` |
838 | * \post `size() == count` |
839 | * \post `npos == find_first_not_of(ch)` |
840 | * \post `at(size()) == Char(0)` |
841 | * \throw std::out_of_range when count > N |
842 | * \return `*this` |
843 | */ |
844 | FOLLY_CPP14_CONSTEXPR BasicFixedString& assign( |
845 | std::size_t count, |
846 | Char ch) noexcept(false) { |
847 | detail::fixedstring::checkOverflow(count, N); |
848 | for (std::size_t i = 0u; i < count; ++i) { |
849 | data_[i] = ch; |
850 | } |
851 | size_ = count; |
852 | data_[size_] = Char(0); |
853 | return *this; |
854 | } |
855 | |
856 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
857 | * Assigns characters from an `BasicFixedString` to this object. |
858 | * \note Equivalent to `assign(that, 0, that.size())` |
859 | */ |
860 | template <std::size_t M> |
861 | FOLLY_CPP14_CONSTEXPR BasicFixedString& assign( |
862 | const BasicFixedString<Char, M>& that) noexcept(M <= N) { |
863 | return *this = that; |
864 | } |
865 | |
866 | // Why is this overload deleted? So users aren't confused by the difference |
867 | // between str.assign("foo", N) and str.assign("foo"_fs, N). In the former, |
868 | // N is a count of characters. In the latter, it would be a position, which |
869 | // totally changes the meaning of the code. |
870 | template <std::size_t M> |
871 | FOLLY_CPP14_CONSTEXPR BasicFixedString& assign( |
872 | const BasicFixedString<Char, M>& that, |
873 | std::size_t pos) noexcept(false) = delete; |
874 | |
875 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
876 | * Assigns `count` characters from an `BasicFixedString` to this object, |
877 | * starting at position `pos` in the source object. |
878 | * \param that The source string. |
879 | * \param pos The starting position in the source string. |
880 | * \param count The number of characters to copy. If `npos`, `count` is taken |
881 | * to be `that.size()-pos`. |
882 | * \pre `pos <= that.size()` |
883 | * \pre `count <= that.size()-pos` |
884 | * \pre `count <= N` |
885 | * \post `size() == count` |
886 | * \post `0 == strncmp(data(), that.begin() + pos, count)` |
887 | * \post `at(size()) == Char(0)` |
888 | * \throw std::out_of_range when pos > that.size() or count > that.size()-pos |
889 | * or count > N. |
890 | * \return `*this` |
891 | */ |
892 | template <std::size_t M> |
893 | FOLLY_CPP14_CONSTEXPR BasicFixedString& assign( |
894 | const BasicFixedString<Char, M>& that, |
895 | std::size_t pos, |
896 | std::size_t count) noexcept(false) { |
897 | detail::fixedstring::checkOverflow(pos, that.size_); |
898 | return assign( |
899 | that.data_ + pos, |
900 | detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos)); |
901 | } |
902 | |
903 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
904 | * Assigns characters from an `BasicFixedString` to this object. |
905 | * \pre `that` contains no embedded nulls. |
906 | * \pre `that[M-1] == Char(0)` |
907 | * \note Equivalent to `assign(that, M - 1)` |
908 | */ |
909 | template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type> |
910 | FOLLY_CPP14_CONSTEXPR BasicFixedString& assign( |
911 | const Char (&that)[M]) noexcept { |
912 | return assign(detail::fixedstring::checkNullTerminated(that), M - 1u); |
913 | } |
914 | |
915 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
916 | * Assigns `count` characters from a range of characters to this object. |
917 | * \param that A pointer to a range of characters. |
918 | * \param count The number of characters to copy. |
919 | * \pre `that` points to at least `count` characters. |
920 | * \pre `count <= N` |
921 | * \post `size() == count` |
922 | * \post `0 == strncmp(data(), that, count)` |
923 | * \post `at(size()) == Char(0)` |
924 | * \throw std::out_of_range when count > N |
925 | * \return `*this` |
926 | */ |
927 | FOLLY_CPP14_CONSTEXPR BasicFixedString& assign( |
928 | const Char* that, |
929 | std::size_t count) noexcept(false) { |
930 | detail::fixedstring::checkOverflow(count, N); |
931 | for (std::size_t i = 0u; i < count; ++i) { |
932 | data_[i] = that[i]; |
933 | } |
934 | size_ = count; |
935 | data_[size_] = Char(0); |
936 | return *this; |
937 | } |
938 | |
939 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
940 | * Swap the contents of this string with `that`. |
941 | */ |
942 | FOLLY_CPP14_CONSTEXPR void swap(BasicFixedString& that) noexcept { |
943 | // less-than-or-equal here to copy the null terminator: |
944 | for (std::size_t i = 0u; i <= folly::constexpr_max(size_, that.size_); |
945 | ++i) { |
946 | detail::fixedstring::constexpr_swap(data_[i], that.data_[i]); |
947 | } |
948 | detail::fixedstring::constexpr_swap(size_, that.size_); |
949 | } |
950 | |
951 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
952 | * Return a pointer to a range of `size()+1` characters, the last of which |
953 | * is `Char(0)`. |
954 | */ |
955 | FOLLY_CPP14_CONSTEXPR Char* data() noexcept { |
956 | return data_; |
957 | } |
958 | |
959 | /** |
960 | * \overload |
961 | */ |
962 | constexpr const Char* data() const noexcept { |
963 | return data_; |
964 | } |
965 | |
966 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
967 | * \return `data()`. |
968 | */ |
969 | constexpr const Char* c_str() const noexcept { |
970 | return data_; |
971 | } |
972 | |
973 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
974 | * \return `data()`. |
975 | */ |
976 | FOLLY_CPP14_CONSTEXPR Char* begin() noexcept { |
977 | return data_; |
978 | } |
979 | |
980 | /** |
981 | * \overload |
982 | */ |
983 | constexpr const Char* begin() const noexcept { |
984 | return data_; |
985 | } |
986 | |
987 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
988 | * \return `data()`. |
989 | */ |
990 | constexpr const Char* cbegin() const noexcept { |
991 | return begin(); |
992 | } |
993 | |
994 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
995 | * \return `data() + size()`. |
996 | */ |
997 | FOLLY_CPP14_CONSTEXPR Char* end() noexcept { |
998 | return data_ + size_; |
999 | } |
1000 | |
1001 | /** |
1002 | * \overload |
1003 | */ |
1004 | constexpr const Char* end() const noexcept { |
1005 | return data_ + size_; |
1006 | } |
1007 | |
1008 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1009 | * \return `data() + size()`. |
1010 | */ |
1011 | constexpr const Char* cend() const noexcept { |
1012 | return end(); |
1013 | } |
1014 | |
1015 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1016 | * Returns a reverse iterator to the first character of the reversed string. |
1017 | * It corresponds to the last + 1 character of the non-reversed string. |
1018 | */ |
1019 | FOLLY_CPP14_CONSTEXPR reverse_iterator rbegin() noexcept { |
1020 | return reverse_iterator{data_ + size_}; |
1021 | } |
1022 | |
1023 | /** |
1024 | * \overload |
1025 | */ |
1026 | constexpr const_reverse_iterator rbegin() const noexcept { |
1027 | return const_reverse_iterator{data_ + size_}; |
1028 | } |
1029 | |
1030 | /** |
1031 | * \note Equivalent to `rbegin()` on a const-qualified reference to `*this`. |
1032 | */ |
1033 | constexpr const_reverse_iterator crbegin() const noexcept { |
1034 | return rbegin(); |
1035 | } |
1036 | |
1037 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1038 | * Returns a reverse iterator to the last + 1 character of the reversed |
1039 | * string. It corresponds to the first character of the non-reversed string. |
1040 | */ |
1041 | FOLLY_CPP14_CONSTEXPR reverse_iterator rend() noexcept { |
1042 | return reverse_iterator{data_}; |
1043 | } |
1044 | |
1045 | /** |
1046 | * \overload |
1047 | */ |
1048 | constexpr const_reverse_iterator rend() const noexcept { |
1049 | return const_reverse_iterator{data_}; |
1050 | } |
1051 | |
1052 | /** |
1053 | * \note Equivalent to `rend()` on a const-qualified reference to `*this`. |
1054 | */ |
1055 | constexpr const_reverse_iterator crend() const noexcept { |
1056 | return rend(); |
1057 | } |
1058 | |
1059 | /** |
1060 | * \return The number of `Char` elements in the string. |
1061 | */ |
1062 | constexpr std::size_t size() const noexcept { |
1063 | return size_; |
1064 | } |
1065 | |
1066 | /** |
1067 | * \return The number of `Char` elements in the string. |
1068 | */ |
1069 | constexpr std::size_t length() const noexcept { |
1070 | return size_; |
1071 | } |
1072 | |
1073 | /** |
1074 | * \return True if and only if `size() == 0`. |
1075 | */ |
1076 | constexpr bool empty() const noexcept { |
1077 | return 0u == size_; |
1078 | } |
1079 | |
1080 | /** |
1081 | * \return `N`. |
1082 | */ |
1083 | static constexpr std::size_t capacity() noexcept { |
1084 | return N; |
1085 | } |
1086 | |
1087 | /** |
1088 | * \return `N`. |
1089 | */ |
1090 | static constexpr std::size_t max_size() noexcept { |
1091 | return N; |
1092 | } |
1093 | |
1094 | // We would need to reimplement folly::Hash to make this |
1095 | // constexpr. :-( |
1096 | std::uint32_t hash() const noexcept { |
1097 | return folly::hsieh_hash32_buf(data_, size_); |
1098 | } |
1099 | |
1100 | /** |
1101 | * \note `at(size())` is allowed will return `Char(0)`. |
1102 | * \return `*(data() + i)` |
1103 | * \throw std::out_of_range when i > size() |
1104 | */ |
1105 | FOLLY_CPP14_CONSTEXPR Char& at(std::size_t i) noexcept(false) { |
1106 | return i <= size_ ? data_[i] |
1107 | : (throw_exception<std::out_of_range>( |
1108 | "Out of range in BasicFixedString::at" ), |
1109 | data_[size_]); |
1110 | } |
1111 | |
1112 | /** |
1113 | * \overload |
1114 | */ |
1115 | constexpr const Char& at(std::size_t i) const noexcept(false) { |
1116 | return i <= size_ ? data_[i] |
1117 | : (throw_exception<std::out_of_range>( |
1118 | "Out of range in BasicFixedString::at" ), |
1119 | data_[size_]); |
1120 | } |
1121 | |
1122 | /** |
1123 | * \pre `i <= size()` |
1124 | * \note `(*this)[size()]` is allowed will return `Char(0)`. |
1125 | * \return `*(data() + i)` |
1126 | */ |
1127 | FOLLY_CPP14_CONSTEXPR Char& operator[](std::size_t i) noexcept { |
1128 | #ifdef NDEBUG |
1129 | return data_[i]; |
1130 | #else |
1131 | return data_[detail::fixedstring::checkOverflow(i, size_)]; |
1132 | #endif |
1133 | } |
1134 | |
1135 | /** |
1136 | * \overload |
1137 | */ |
1138 | constexpr const Char& operator[](std::size_t i) const noexcept { |
1139 | #ifdef NDEBUG |
1140 | return data_[i]; |
1141 | #else |
1142 | return data_[detail::fixedstring::checkOverflow(i, size_)]; |
1143 | #endif |
1144 | } |
1145 | |
1146 | /** |
1147 | * \note Equivalent to `(*this)[0]` |
1148 | */ |
1149 | FOLLY_CPP14_CONSTEXPR Char& front() noexcept { |
1150 | return (*this)[0u]; |
1151 | } |
1152 | |
1153 | /** |
1154 | * \overload |
1155 | */ |
1156 | constexpr const Char& front() const noexcept { |
1157 | return (*this)[0u]; |
1158 | } |
1159 | |
1160 | /** |
1161 | * \note Equivalent to `at(size()-1)` |
1162 | * \pre `!empty()` |
1163 | */ |
1164 | FOLLY_CPP14_CONSTEXPR Char& back() noexcept { |
1165 | #ifdef NDEBUG |
1166 | return data_[size_ - 1u]; |
1167 | #else |
1168 | return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)]; |
1169 | #endif |
1170 | } |
1171 | |
1172 | /** |
1173 | * \overload |
1174 | */ |
1175 | constexpr const Char& back() const noexcept { |
1176 | #ifdef NDEBUG |
1177 | return data_[size_ - 1u]; |
1178 | #else |
1179 | return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)]; |
1180 | #endif |
1181 | } |
1182 | |
1183 | /** |
1184 | * Clears the contents of this string. |
1185 | * \post `size() == 0u` |
1186 | * \post `at(size()) == Char(0)` |
1187 | */ |
1188 | FOLLY_CPP14_CONSTEXPR void clear() noexcept { |
1189 | data_[0u] = Char(0); |
1190 | size_ = 0u; |
1191 | } |
1192 | |
1193 | /** |
1194 | * \note Equivalent to `append(1u, ch)`. |
1195 | */ |
1196 | FOLLY_CPP14_CONSTEXPR void push_back(Char ch) noexcept(false) { |
1197 | detail::fixedstring::checkOverflow(1u, N - size_); |
1198 | data_[size_] = ch; |
1199 | data_[++size_] = Char(0); |
1200 | } |
1201 | |
1202 | /** |
1203 | * \note Equivalent to `cappend(1u, ch)`. |
1204 | */ |
1205 | constexpr BasicFixedString<Char, N + 1u> cpush_back(Char ch) const noexcept { |
1206 | return cappend(ch); |
1207 | } |
1208 | |
1209 | /** |
1210 | * Removes the last character from the string. |
1211 | * \pre `!empty()` |
1212 | * \post `size()` is one fewer than before calling `pop_back()`. |
1213 | * \post `at(size()) == Char(0)` |
1214 | * \post The characters in the half-open range `[0,size()-1)` are unmodified. |
1215 | * \throw std::out_of_range if empty(). |
1216 | */ |
1217 | FOLLY_CPP14_CONSTEXPR void pop_back() noexcept(false) { |
1218 | detail::fixedstring::checkOverflow(1u, size_); |
1219 | --size_; |
1220 | data_[size_] = Char(0); |
1221 | } |
1222 | |
1223 | /** |
1224 | * Returns a new string with the first `size()-1` characters from this string. |
1225 | * \pre `!empty()` |
1226 | * \note Equivalent to `BasicFixedString<Char, N-1u>{*this, 0u, size()-1u}` |
1227 | * \throw std::out_of_range if empty(). |
1228 | */ |
1229 | constexpr BasicFixedString<Char, N - 1u> cpop_back() const noexcept(false) { |
1230 | return {*this, 0u, size_ - detail::fixedstring::checkOverflow(1u, size_)}; |
1231 | } |
1232 | |
1233 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1234 | * Appends `count` copies of `ch` to this string. |
1235 | * \pre `count + old_size <= N` |
1236 | * \post The first `old_size` characters of the string are unmodified. |
1237 | * \post `size() == old_size + count` |
1238 | * \throw std::out_of_range if count > N - size(). |
1239 | */ |
1240 | FOLLY_CPP14_CONSTEXPR BasicFixedString& append( |
1241 | std::size_t count, |
1242 | Char ch) noexcept(false) { |
1243 | detail::fixedstring::checkOverflow(count, N - size_); |
1244 | for (std::size_t i = 0u; i < count; ++i) { |
1245 | data_[size_ + i] = ch; |
1246 | } |
1247 | size_ += count; |
1248 | data_[size_] = Char(0); |
1249 | return *this; |
1250 | } |
1251 | |
1252 | /** |
1253 | * \note Equivalent to `append(*this, 0, that.size())`. |
1254 | */ |
1255 | template <std::size_t M> |
1256 | FOLLY_CPP14_CONSTEXPR BasicFixedString& append( |
1257 | const BasicFixedString<Char, M>& that) noexcept(false) { |
1258 | return append(that, 0u, that.size_); |
1259 | } |
1260 | |
1261 | // Why is this overload deleted? So as not to get confused with |
1262 | // append("null-terminated", N), where N would be a count instead |
1263 | // of a position. |
1264 | template <std::size_t M> |
1265 | FOLLY_CPP14_CONSTEXPR BasicFixedString& append( |
1266 | const BasicFixedString<Char, M>& that, |
1267 | std::size_t pos) noexcept(false) = delete; |
1268 | |
1269 | /** |
1270 | * Appends `count` characters from another string to this one, starting at a |
1271 | * given offset, `pos`. |
1272 | * \param that The source string. |
1273 | * \param pos The starting position in the source string. |
1274 | * \param count The number of characters to append. If `npos`, `count` is |
1275 | * taken to be `that.size()-pos`. |
1276 | * \pre `pos <= that.size()` |
1277 | * \pre `count <= that.size() - pos` |
1278 | * \pre `old_size + count <= N` |
1279 | * \post The first `old_size` characters of the string are unmodified. |
1280 | * \post `size() == old_size + count` |
1281 | * \post `at(size()) == Char(0)` |
1282 | * \throw std::out_of_range if pos + count > that.size() or if |
1283 | * `old_size + count > N`. |
1284 | */ |
1285 | template <std::size_t M> |
1286 | FOLLY_CPP14_CONSTEXPR BasicFixedString& append( |
1287 | const BasicFixedString<Char, M>& that, |
1288 | std::size_t pos, |
1289 | std::size_t count) noexcept(false) { |
1290 | detail::fixedstring::checkOverflow(pos, that.size_); |
1291 | count = detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos); |
1292 | detail::fixedstring::checkOverflow(count, N - size_); |
1293 | for (std::size_t i = 0u; i < count; ++i) { |
1294 | data_[size_ + i] = that.data_[pos + i]; |
1295 | } |
1296 | size_ += count; |
1297 | data_[size_] = Char(0); |
1298 | return *this; |
1299 | } |
1300 | |
1301 | /** |
1302 | * \note Equivalent to `append(that, strlen(that))`. |
1303 | */ |
1304 | FOLLY_CPP14_CONSTEXPR BasicFixedString& append(const Char* that) noexcept( |
1305 | false) { |
1306 | return append(that, folly::constexpr_strlen(that)); |
1307 | } |
1308 | |
1309 | /** |
1310 | * Appends `count` characters from the specified character array. |
1311 | * \pre `that` points to a range of at least `count` characters. |
1312 | * \pre `count + old_size <= N` |
1313 | * \post The first `old_size` characters of the string are unmodified. |
1314 | * \post `size() == old_size + count` |
1315 | * \post `at(size()) == Char(0)` |
1316 | * \throw std::out_of_range if old_size + count > N. |
1317 | */ |
1318 | FOLLY_CPP14_CONSTEXPR BasicFixedString& append( |
1319 | const Char* that, |
1320 | std::size_t count) noexcept(false) { |
1321 | detail::fixedstring::checkOverflow(count, N - size_); |
1322 | for (std::size_t i = 0u; i < count; ++i) { |
1323 | data_[size_ + i] = that[i]; |
1324 | } |
1325 | size_ += count; |
1326 | data_[size_] = Char(0); |
1327 | return *this; |
1328 | } |
1329 | |
1330 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1331 | * Creates a new string by appending a character to an existing string, which |
1332 | * is left unmodified. |
1333 | * \note Equivalent to `*this + ch` |
1334 | */ |
1335 | constexpr BasicFixedString<Char, N + 1u> cappend(Char ch) const noexcept { |
1336 | return *this + ch; |
1337 | } |
1338 | |
1339 | /** |
1340 | * Creates a new string by appending a string to an existing string, which |
1341 | * is left unmodified. |
1342 | * \note Equivalent to `*this + ch` |
1343 | */ |
1344 | template <std::size_t M> |
1345 | constexpr BasicFixedString<Char, N + M> cappend( |
1346 | const BasicFixedString<Char, M>& that) const noexcept { |
1347 | return *this + that; |
1348 | } |
1349 | |
1350 | // Deleted to avoid confusion with append("char*", N), where N is a count |
1351 | // instead of a position. |
1352 | template <std::size_t M> |
1353 | constexpr BasicFixedString<Char, N + M> cappend( |
1354 | const BasicFixedString<Char, M>& that, |
1355 | std::size_t pos) const noexcept(false) = delete; |
1356 | |
1357 | /** |
1358 | * Creates a new string by appending characters from one string to another, |
1359 | * which is left unmodified. |
1360 | * \note Equivalent to `*this + that.substr(pos, count)` |
1361 | */ |
1362 | template <std::size_t M> |
1363 | constexpr BasicFixedString<Char, N + M> cappend( |
1364 | const BasicFixedString<Char, M>& that, |
1365 | std::size_t pos, |
1366 | std::size_t count) const noexcept(false) { |
1367 | return creplace(size_, 0u, that, pos, count); |
1368 | } |
1369 | |
1370 | /** |
1371 | * Creates a new string by appending a string literal to a string, |
1372 | * which is left unmodified. |
1373 | * \note Equivalent to `*this + that` |
1374 | */ |
1375 | template <std::size_t M> |
1376 | constexpr BasicFixedString<Char, N + M - 1u> cappend( |
1377 | const Char (&that)[M]) const noexcept { |
1378 | return creplace(size_, 0u, that); |
1379 | } |
1380 | |
1381 | // Deleted to avoid confusion with append("char*", N), where N is a count |
1382 | // instead of a position |
1383 | template <std::size_t M> |
1384 | constexpr BasicFixedString<Char, N + M - 1u> cappend( |
1385 | const Char (&that)[M], |
1386 | std::size_t pos) const noexcept(false) = delete; |
1387 | |
1388 | /** |
1389 | * Creates a new string by appending characters from one string to another, |
1390 | * which is left unmodified. |
1391 | * \note Equivalent to `*this + makeFixedString(that).substr(pos, count)` |
1392 | */ |
1393 | template <std::size_t M> |
1394 | constexpr BasicFixedString<Char, N + M - 1u> |
1395 | cappend(const Char (&that)[M], std::size_t pos, std::size_t count) const |
1396 | noexcept(false) { |
1397 | return creplace(size_, 0u, that, pos, count); |
1398 | } |
1399 | |
1400 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1401 | * Appends characters from a null-terminated string literal to this string. |
1402 | * \note Equivalent to `append(that)`. |
1403 | */ |
1404 | FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(const Char* that) noexcept( |
1405 | false) { |
1406 | return append(that); |
1407 | } |
1408 | |
1409 | /** |
1410 | * Appends characters from another string to this one. |
1411 | * \note Equivalent to `append(that)`. |
1412 | */ |
1413 | template <std::size_t M> |
1414 | FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=( |
1415 | const BasicFixedString<Char, M>& that) noexcept(false) { |
1416 | return append(that, 0u, that.size_); |
1417 | } |
1418 | |
1419 | /** |
1420 | * Appends a character to this string. |
1421 | * \note Equivalent to `push_back(ch)`. |
1422 | */ |
1423 | FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(Char ch) noexcept(false) { |
1424 | push_back(ch); |
1425 | return *this; |
1426 | } |
1427 | |
1428 | /** |
1429 | * Appends characters from an `initializer_list` to this string. |
1430 | * \note Equivalent to `append(il.begin(), il.size())`. |
1431 | */ |
1432 | FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=( |
1433 | std::initializer_list<Char> il) noexcept(false) { |
1434 | return append(il.begin(), il.size()); |
1435 | } |
1436 | |
1437 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1438 | * Erase all characters from this string. |
1439 | * \note Equivalent to `clear()` |
1440 | * \return *this; |
1441 | */ |
1442 | FOLLY_CPP14_CONSTEXPR BasicFixedString& erase() noexcept { |
1443 | clear(); |
1444 | return *this; |
1445 | } |
1446 | |
1447 | /** |
1448 | * Erases `count` characters from position `pos`. If `count` is `npos`, |
1449 | * erases from `pos` to the end of the string. |
1450 | * \pre `pos <= size()` |
1451 | * \pre `count <= size() - pos || count == npos` |
1452 | * \post `size() == old_size - min(count, old_size - pos)` |
1453 | * \post `at(size()) == Char(0)` |
1454 | * \return *this; |
1455 | * \throw std::out_of_range when pos > size(). |
1456 | */ |
1457 | FOLLY_CPP14_CONSTEXPR BasicFixedString& erase( |
1458 | std::size_t pos, |
1459 | std::size_t count = npos) noexcept(false) { |
1460 | using A = const Char[1]; |
1461 | constexpr A a{Char(0)}; |
1462 | return replace( |
1463 | pos, |
1464 | detail::fixedstring::checkOverflowOrNpos( |
1465 | count, size_ - detail::fixedstring::checkOverflow(pos, size_)), |
1466 | a, |
1467 | 0u); |
1468 | } |
1469 | |
1470 | /** |
1471 | * \note Equivalent to `erase(first - data(), 1)` |
1472 | * \return A pointer to the first character after the erased character. |
1473 | */ |
1474 | FOLLY_CPP14_CONSTEXPR Char* erase(const Char* first) noexcept(false) { |
1475 | erase(first - data_, 1u); |
1476 | return data_ + (first - data_); |
1477 | } |
1478 | |
1479 | /** |
1480 | * \note Equivalent to `erase(first - data(), last - first)` |
1481 | * \return A pointer to the first character after the erased characters. |
1482 | */ |
1483 | FOLLY_CPP14_CONSTEXPR Char* erase( |
1484 | const Char* first, |
1485 | const Char* last) noexcept(false) { |
1486 | erase(first - data_, last - first); |
1487 | return data_ + (first - data_); |
1488 | } |
1489 | |
1490 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1491 | * Create a new string by erasing all the characters from this string. |
1492 | * \note Equivalent to `BasicFixedString<Char, 0>{}` |
1493 | */ |
1494 | constexpr BasicFixedString<Char, 0u> cerase() const noexcept { |
1495 | return {}; |
1496 | } |
1497 | |
1498 | /** |
1499 | * Create a new string by erasing all the characters after position `pos` from |
1500 | * this string. |
1501 | * \note Equivalent to `creplace(pos, min(count, pos - size()), "")` |
1502 | */ |
1503 | constexpr BasicFixedString cerase(std::size_t pos, std::size_t count = npos) |
1504 | const noexcept(false) { |
1505 | using A = const Char[1]; |
1506 | return creplace( |
1507 | pos, |
1508 | detail::fixedstring::checkOverflowOrNpos( |
1509 | count, size_ - detail::fixedstring::checkOverflow(pos, size_)), |
1510 | A{Char(0)}); |
1511 | } |
1512 | |
1513 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1514 | * Compare two strings for lexicographical ordering. |
1515 | * \note Equivalent to |
1516 | * `compare(0, size(), that.data(), that.size())` |
1517 | */ |
1518 | template <std::size_t M> |
1519 | constexpr int compare(const BasicFixedString<Char, M>& that) const noexcept { |
1520 | return compare(0u, size_, that, 0u, that.size_); |
1521 | } |
1522 | |
1523 | /** |
1524 | * Compare two strings for lexicographical ordering. |
1525 | * \note Equivalent to |
1526 | * `compare(this_pos, this_count, that.data(), that.size())` |
1527 | */ |
1528 | template <std::size_t M> |
1529 | constexpr int compare( |
1530 | std::size_t this_pos, |
1531 | std::size_t this_count, |
1532 | const BasicFixedString<Char, M>& that) const noexcept(false) { |
1533 | return compare(this_pos, this_count, that, 0u, that.size_); |
1534 | } |
1535 | |
1536 | /** |
1537 | * Compare two strings for lexicographical ordering. |
1538 | * \note Equivalent to |
1539 | * `compare(this_pos, this_count, that.data() + that_pos, that_count)` |
1540 | */ |
1541 | template <std::size_t M> |
1542 | constexpr int compare( |
1543 | std::size_t this_pos, |
1544 | std::size_t this_count, |
1545 | const BasicFixedString<Char, M>& that, |
1546 | std::size_t that_pos, |
1547 | std::size_t that_count) const noexcept(false) { |
1548 | return static_cast<int>(detail::fixedstring::compare_( |
1549 | data_, |
1550 | detail::fixedstring::checkOverflow(this_pos, size_), |
1551 | detail::fixedstring::checkOverflow(this_count, size_ - this_pos) + |
1552 | this_pos, |
1553 | that.data_, |
1554 | detail::fixedstring::checkOverflow(that_pos, that.size_), |
1555 | detail::fixedstring::checkOverflow(that_count, that.size_ - that_pos) + |
1556 | that_pos)); |
1557 | } |
1558 | |
1559 | /** |
1560 | * Compare two strings for lexicographical ordering. |
1561 | * \note Equivalent to `compare(0, size(), that, strlen(that))` |
1562 | */ |
1563 | constexpr int compare(const Char* that) const noexcept { |
1564 | return compare(0u, size_, that, folly::constexpr_strlen(that)); |
1565 | } |
1566 | |
1567 | /** |
1568 | * \overload |
1569 | */ |
1570 | constexpr int compare(Range<const Char*> that) const noexcept { |
1571 | return compare(0u, size_, that.begin(), that.size()); |
1572 | } |
1573 | |
1574 | /** |
1575 | * Compare two strings for lexicographical ordering. |
1576 | * \note Equivalent to |
1577 | * `compare(this_pos, this_count, that, strlen(that))` |
1578 | */ |
1579 | constexpr int compare( |
1580 | std::size_t this_pos, |
1581 | std::size_t this_count, |
1582 | const Char* that) const noexcept(false) { |
1583 | return compare(this_pos, this_count, that, folly::constexpr_strlen(that)); |
1584 | } |
1585 | |
1586 | /** |
1587 | * \overload |
1588 | */ |
1589 | constexpr int compare( |
1590 | std::size_t this_pos, |
1591 | std::size_t this_count, |
1592 | Range<const Char*> that) const noexcept(false) { |
1593 | return compare(this_pos, this_count, that.begin(), that.size()); |
1594 | } |
1595 | |
1596 | /** |
1597 | * Compare two strings for lexicographical ordering. |
1598 | * |
1599 | * Let `A` be the the |
1600 | * character sequence {`(*this)[this_pos]`, ... |
1601 | * `(*this)[this_pos + this_count - 1]`}. Let `B` be the character sequence |
1602 | * {`that[0]`, ...`that[count - 1]`}. Then... |
1603 | * |
1604 | * \return |
1605 | * - `< 0` if `A` is ordered before the `B` |
1606 | * - `> 0` if `B` is ordered before `A` |
1607 | * - `0` if `A` equals `B`. |
1608 | * |
1609 | * \throw std::out_of_range if this_pos + this_count > size(). |
1610 | */ |
1611 | constexpr int compare( |
1612 | std::size_t this_pos, |
1613 | std::size_t this_count, |
1614 | const Char* that, |
1615 | std::size_t that_count) const noexcept(false) { |
1616 | return static_cast<int>(detail::fixedstring::compare_( |
1617 | data_, |
1618 | detail::fixedstring::checkOverflow(this_pos, size_), |
1619 | detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos) + |
1620 | this_pos, |
1621 | that, |
1622 | 0u, |
1623 | that_count)); |
1624 | } |
1625 | |
1626 | constexpr int compare( |
1627 | std::size_t this_pos, |
1628 | std::size_t this_count, |
1629 | Range<const Char*> that, |
1630 | std::size_t that_count) const noexcept(false) { |
1631 | return compare( |
1632 | this_pos, |
1633 | this_count, |
1634 | that.begin(), |
1635 | detail::fixedstring::checkOverflow(that_count, that.size())); |
1636 | } |
1637 | |
1638 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1639 | * Return a substring from `pos` to the end of the string. |
1640 | * \note Equivalent to `BasicFixedString{*this, pos}` |
1641 | */ |
1642 | constexpr BasicFixedString substr(std::size_t pos) const noexcept(false) { |
1643 | return {*this, pos}; |
1644 | } |
1645 | |
1646 | /** |
1647 | * Return a substring from `pos` to the end of the string. |
1648 | * \note Equivalent to `BasicFixedString{*this, pos, count}` |
1649 | */ |
1650 | constexpr BasicFixedString substr(std::size_t pos, std::size_t count) const |
1651 | noexcept(false) { |
1652 | return {*this, pos, count}; |
1653 | } |
1654 | |
1655 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1656 | * Replace the characters in the range denoted by the half-open range |
1657 | * [`first`, `last`) with the string `that`. |
1658 | * \pre `first` and `last` point to characters within this string (including |
1659 | * the terminating null). |
1660 | * \note Equivalent to |
1661 | * `replace(first - data(), last - first, that.data(), that.size())` |
1662 | */ |
1663 | template <std::size_t M> |
1664 | FOLLY_CPP14_CONSTEXPR BasicFixedString& replace( |
1665 | const Char* first, |
1666 | const Char* last, |
1667 | const BasicFixedString<Char, M>& that) noexcept(false) { |
1668 | return replace(first - data_, last - first, that, 0u, that.size_); |
1669 | } |
1670 | |
1671 | /** |
1672 | * Replace `this_count` characters starting from position `this_pos` with the |
1673 | * characters from string `that` starting at position `that_pos`. |
1674 | * \pre `that_pos <= that.size()` |
1675 | * \note Equivalent to |
1676 | * <tt>replace(this_pos, this_count, that.data() + that_pos, |
1677 | * that.size() - that_pos)</tt> |
1678 | */ |
1679 | template <std::size_t M> |
1680 | FOLLY_CPP14_CONSTEXPR BasicFixedString& replace( |
1681 | std::size_t this_pos, |
1682 | std::size_t this_count, |
1683 | const BasicFixedString<Char, M>& that, |
1684 | std::size_t that_pos = 0u) noexcept(false) { |
1685 | return replace(this_pos, this_count, that, that_pos, that.size_ - that_pos); |
1686 | } |
1687 | |
1688 | /** |
1689 | * Replace `this_count` characters starting from position `this_pos` with |
1690 | * `that_count` characters from string `that` starting at position |
1691 | * `that_pos`. |
1692 | * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos` |
1693 | * \note Equivalent to |
1694 | * `replace(this_pos, this_count, that.data() + that_pos, that_count)` |
1695 | */ |
1696 | template <std::size_t M> |
1697 | FOLLY_CPP14_CONSTEXPR BasicFixedString& replace( |
1698 | std::size_t this_pos, |
1699 | std::size_t this_count, |
1700 | const BasicFixedString<Char, M>& that, |
1701 | std::size_t that_pos, |
1702 | std::size_t that_count) noexcept(false) { |
1703 | return *this = creplace(this_pos, this_count, that, that_pos, that_count); |
1704 | } |
1705 | |
1706 | /** |
1707 | * Replace `this_count` characters starting from position `this_pos` with |
1708 | * the characters from the string literal `that`. |
1709 | * \note Equivalent to |
1710 | * `replace(this_pos, this_count, that, strlen(that))` |
1711 | */ |
1712 | FOLLY_CPP14_CONSTEXPR BasicFixedString& replace( |
1713 | std::size_t this_pos, |
1714 | std::size_t this_count, |
1715 | const Char* that) noexcept(false) { |
1716 | return replace(this_pos, this_count, that, folly::constexpr_strlen(that)); |
1717 | } |
1718 | |
1719 | /** |
1720 | * Replace the characters denoted by the half-open range [`first`,`last`) with |
1721 | * the characters from the string literal `that`. |
1722 | * \pre `first` and `last` point to characters within this string (including |
1723 | * the terminating null). |
1724 | * \note Equivalent to |
1725 | * `replace(first - data(), last - first, that, strlen(that))` |
1726 | */ |
1727 | FOLLY_CPP14_CONSTEXPR BasicFixedString& replace( |
1728 | const Char* first, |
1729 | const Char* last, |
1730 | const Char* that) noexcept(false) { |
1731 | return replace( |
1732 | first - data_, last - first, that, folly::constexpr_strlen(that)); |
1733 | } |
1734 | |
1735 | /** |
1736 | * Replace `this_count` characters starting from position `this_pos` with |
1737 | * `that_count` characters from the character sequence pointed to by `that`. |
1738 | * \param this_pos The starting offset within `*this` of the first character |
1739 | * to be replaced. |
1740 | * \param this_count The number of characters to be replaced. If `npos`, |
1741 | * it is treated as if `this_count` were `size() - this_pos`. |
1742 | * \param that A pointer to the replacement string. |
1743 | * \param that_count The number of characters in the replacement string. |
1744 | * \pre `this_pos <= size() && this_count <= size() - this_pos` |
1745 | * \pre `that` points to a contiguous sequence of at least `that_count` |
1746 | * characters |
1747 | * \throw std::out_of_range on any of the following conditions: |
1748 | * - `this_pos > size()` |
1749 | * - `this_count > size() - this_pos` |
1750 | * - `size() - this_count + that_count > N` |
1751 | */ |
1752 | FOLLY_CPP14_CONSTEXPR BasicFixedString& replace( |
1753 | std::size_t this_pos, |
1754 | std::size_t this_count, |
1755 | const Char* that, |
1756 | std::size_t that_count) noexcept(false) { |
1757 | return *this = detail::fixedstring::Helper::replace_<Char>( |
1758 | data_, |
1759 | size_, |
1760 | detail::fixedstring::checkOverflow(this_pos, size_), |
1761 | detail::fixedstring::checkOverflowOrNpos( |
1762 | this_count, size_ - this_pos), |
1763 | that, |
1764 | 0u, |
1765 | that_count, |
1766 | Indices{}); |
1767 | } |
1768 | |
1769 | /** |
1770 | * Replace `this_count` characters starting from position `this_pos` with |
1771 | * `that_count` characters `ch`. |
1772 | * \note Equivalent to |
1773 | * `replace(this_pos, this_count, BasicFixedString{that_count, ch})` |
1774 | */ |
1775 | FOLLY_CPP14_CONSTEXPR BasicFixedString& replace( |
1776 | std::size_t this_pos, |
1777 | std::size_t this_count, |
1778 | std::size_t that_count, |
1779 | Char ch) noexcept(false) { |
1780 | return replace(this_pos, this_count, BasicFixedString{that_count, ch}); |
1781 | } |
1782 | |
1783 | /** |
1784 | * Replace the characters denoted by the half-open range [`first`,`last`) |
1785 | * with `that_count` characters `ch`. |
1786 | * \note Equivalent to |
1787 | * `replace(first - data(), last - first, BasicFixedString{that_count, ch})` |
1788 | */ |
1789 | FOLLY_CPP14_CONSTEXPR BasicFixedString& replace( |
1790 | const Char* first, |
1791 | const Char* last, |
1792 | std::size_t that_count, |
1793 | Char ch) noexcept(false) { |
1794 | return replace( |
1795 | first - data_, last - first, BasicFixedString{that_count, ch}); |
1796 | } |
1797 | |
1798 | /** |
1799 | * Replace the characters denoted by the half-open range [`first`,`last`) with |
1800 | * the characters from the string literal `that`. |
1801 | * \pre `first` and `last` point to characters within this string (including |
1802 | * the terminating null). |
1803 | * \note Equivalent to |
1804 | * `replace(this_pos, this_count, il.begin(), il.size())` |
1805 | */ |
1806 | FOLLY_CPP14_CONSTEXPR BasicFixedString& replace( |
1807 | const Char* first, |
1808 | const Char* last, |
1809 | std::initializer_list<Char> il) noexcept(false) { |
1810 | return replace(first - data_, last - first, il.begin(), il.size()); |
1811 | } |
1812 | |
1813 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
1814 | * Construct a new string by replacing `this_count` characters starting from |
1815 | * position `this_pos` within this string with the characters from string |
1816 | * `that` starting at position `that_pos`. |
1817 | * \pre `that_pos <= that.size()` |
1818 | * \note Equivalent to |
1819 | * <tt>creplace(this_pos, this_count, that, that_pos, |
1820 | * that.size() - that_pos)</tt> |
1821 | */ |
1822 | template <std::size_t M> |
1823 | constexpr BasicFixedString<Char, N + M> creplace( |
1824 | std::size_t this_pos, |
1825 | std::size_t this_count, |
1826 | const BasicFixedString<Char, M>& that, |
1827 | std::size_t that_pos = 0u) const noexcept(false) { |
1828 | return creplace( |
1829 | this_pos, |
1830 | this_count, |
1831 | that, |
1832 | that_pos, |
1833 | that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_)); |
1834 | } |
1835 | |
1836 | /** |
1837 | * Construct a new string by replacing `this_count` characters starting from |
1838 | * position `this_pos` within this string with `that_count` characters from |
1839 | * string `that` starting at position `that_pos`. |
1840 | * \param this_pos The starting offset within `*this` of the first character |
1841 | * to be replaced. |
1842 | * \param this_count The number of characters to be replaced. If `npos`, |
1843 | * it is treated as if `this_count` were `size() - this_pos`. |
1844 | * \param that A string that contains the replacement string. |
1845 | * \param that_pos The offset to the first character in the replacement |
1846 | * string. |
1847 | * \param that_count The number of characters in the replacement string. |
1848 | * \pre `this_pos <= size() && this_count <= size() - this_pos` |
1849 | * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos` |
1850 | * \post The size of the returned string is `size() - this_count + that_count` |
1851 | * \note Equivalent to <tt>BasicFixedString<Char, N + M>{substr(0, this_pos) + |
1852 | * that.substr(that_pos, that_count) + substr(this_pos + this_count)}</tt> |
1853 | * \throw std::out_of_range on any of the following conditions: |
1854 | * - `this_pos > size()` |
1855 | * - `this_count > size() - this_pos` |
1856 | * - `that_pos > that.size()` |
1857 | * - `that_count > that.size() - that_pos` |
1858 | */ |
1859 | template <std::size_t M> |
1860 | constexpr BasicFixedString<Char, N + M> creplace( |
1861 | std::size_t this_pos, |
1862 | std::size_t this_count, |
1863 | const BasicFixedString<Char, M>& that, |
1864 | std::size_t that_pos, |
1865 | std::size_t that_count) const noexcept(false) { |
1866 | return detail::fixedstring::Helper::replace_<Char>( |
1867 | data_, |
1868 | size_, |
1869 | detail::fixedstring::checkOverflow(this_pos, size_), |
1870 | detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos), |
1871 | that.data_, |
1872 | detail::fixedstring::checkOverflow(that_pos, that.size_), |
1873 | detail::fixedstring::checkOverflowOrNpos( |
1874 | that_count, that.size_ - that_pos), |
1875 | folly::make_index_sequence<N + M>{}); |
1876 | } |
1877 | |
1878 | /** |
1879 | * Construct a new string by replacing the characters denoted by the half-open |
1880 | * range [`first`,`last`) within this string with the characters from string |
1881 | * `that` starting at position `that_pos`. |
1882 | * \pre `that_pos <= that.size()` |
1883 | * \note Equivalent to |
1884 | * <tt>creplace(first - data(), last - first, that, that_pos, |
1885 | * that.size() - that_pos)</tt> |
1886 | */ |
1887 | template <std::size_t M> |
1888 | constexpr BasicFixedString<Char, N + M> creplace( |
1889 | const Char* first, |
1890 | const Char* last, |
1891 | const BasicFixedString<Char, M>& that, |
1892 | std::size_t that_pos = 0u) const noexcept(false) { |
1893 | return creplace( |
1894 | first - data_, |
1895 | last - first, |
1896 | that, |
1897 | that_pos, |
1898 | that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_)); |
1899 | } |
1900 | |
1901 | /** |
1902 | * Construct a new string by replacing the characters denoted by the half-open |
1903 | * range [`first`,`last`) within this string with the `that_count` |
1904 | * characters from string `that` starting at position `that_pos`. |
1905 | * \note Equivalent to |
1906 | * <tt>creplace(first - data(), last - first, that, that_pos, |
1907 | * that_count)</tt> |
1908 | */ |
1909 | template <std::size_t M> |
1910 | constexpr BasicFixedString<Char, N + M> creplace( |
1911 | const Char* first, |
1912 | const Char* last, |
1913 | const BasicFixedString<Char, M>& that, |
1914 | std::size_t that_pos, |
1915 | std::size_t that_count) const noexcept(false) { |
1916 | return creplace(first - data_, last - first, that, that_pos, that_count); |
1917 | } |
1918 | |
1919 | /** |
1920 | * Construct a new string by replacing `this_count` characters starting from |
1921 | * position `this_pos` within this string with `M-1` characters from |
1922 | * character array `that`. |
1923 | * \pre `strlen(that) == M-1` |
1924 | * \note Equivalent to |
1925 | * <tt>creplace(this_pos, this_count, that, 0, M - 1)</tt> |
1926 | */ |
1927 | template <std::size_t M> |
1928 | constexpr BasicFixedString<Char, N + M - 1u> creplace( |
1929 | std::size_t this_pos, |
1930 | std::size_t this_count, |
1931 | const Char (&that)[M]) const noexcept(false) { |
1932 | return creplace(this_pos, this_count, that, 0u, M - 1u); |
1933 | } |
1934 | |
1935 | /** |
1936 | * Replace `this_count` characters starting from position `this_pos` with |
1937 | * `that_count` characters from the character array `that` starting at |
1938 | * position `that_pos`. |
1939 | * \param this_pos The starting offset within `*this` of the first character |
1940 | * to be replaced. |
1941 | * \param this_count The number of characters to be replaced. If `npos`, |
1942 | * it is treated as if `this_count` were `size() - this_pos`. |
1943 | * \param that An array of characters containing the replacement string. |
1944 | * \param that_pos The starting offset of the replacement string. |
1945 | * \param that_count The number of characters in the replacement string. If |
1946 | * `npos`, it is treated as if `that_count` were `M - 1 - that_pos` |
1947 | * \pre `this_pos <= size() && this_count <= size() - this_pos` |
1948 | * \pre `that_pos <= M - 1 && that_count <= M - 1 - that_pos` |
1949 | * \post The size of the returned string is `size() - this_count + that_count` |
1950 | * \note Equivalent to <tt>BasicFixedString<Char, N + M - 1>{ |
1951 | * substr(0, this_pos) + |
1952 | * makeFixedString(that).substr(that_pos, that_count) + |
1953 | * substr(this_pos + this_count)}</tt> |
1954 | * \throw std::out_of_range on any of the following conditions: |
1955 | * - `this_pos > size()` |
1956 | * - `this_count > size() - this_pos` |
1957 | * - `that_pos >= M` |
1958 | * - `that_count >= M - that_pos` |
1959 | */ |
1960 | template <std::size_t M> |
1961 | constexpr BasicFixedString<Char, N + M - 1u> creplace( |
1962 | std::size_t this_pos, |
1963 | std::size_t this_count, |
1964 | const Char (&that)[M], |
1965 | std::size_t that_pos, |
1966 | std::size_t that_count) const noexcept(false) { |
1967 | return detail::fixedstring::Helper::replace_<Char>( |
1968 | data_, |
1969 | size_, |
1970 | detail::fixedstring::checkOverflow(this_pos, size_), |
1971 | detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos), |
1972 | detail::fixedstring::checkNullTerminated(that), |
1973 | detail::fixedstring::checkOverflow(that_pos, M - 1u), |
1974 | detail::fixedstring::checkOverflowOrNpos(that_count, M - 1u - that_pos), |
1975 | folly::make_index_sequence<N + M - 1u>{}); |
1976 | } |
1977 | |
1978 | /** |
1979 | * Construct a new string by replacing the characters denoted by the half-open |
1980 | * range [`first`,`last`) within this string with the first `M-1` |
1981 | * characters from the character array `that`. |
1982 | * \pre `strlen(that) == M-1` |
1983 | * \note Equivalent to |
1984 | * <tt>creplace(first - data(), last - first, that, 0, M-1)</tt> |
1985 | */ |
1986 | template <std::size_t M> |
1987 | constexpr BasicFixedString<Char, N + M - 1u> |
1988 | creplace(const Char* first, const Char* last, const Char (&that)[M]) const |
1989 | noexcept(false) { |
1990 | return creplace(first - data_, last - first, that, 0u, M - 1u); |
1991 | } |
1992 | |
1993 | /** |
1994 | * Construct a new string by replacing the characters denoted by the half-open |
1995 | * range [`first`,`last`) within this string with the `that_count` |
1996 | * characters from the character array `that` starting at position |
1997 | * `that_pos`. |
1998 | * \pre `strlen(that) == M-1` |
1999 | * \note Equivalent to |
2000 | * `creplace(first - data(), last - first, that, that_pos, that_count)` |
2001 | */ |
2002 | template <std::size_t M> |
2003 | constexpr BasicFixedString<Char, N + M - 1u> creplace( |
2004 | const Char* first, |
2005 | const Char* last, |
2006 | const Char (&that)[M], |
2007 | std::size_t that_pos, |
2008 | std::size_t that_count) const noexcept(false) { |
2009 | return creplace(first - data_, last - first, that, that_pos, that_count); |
2010 | } |
2011 | |
2012 | /** |
2013 | * Copies `min(count, size())` characters starting from offset `0` |
2014 | * from this string into the buffer pointed to by `dest`. |
2015 | * \return The number of characters copied. |
2016 | */ |
2017 | FOLLY_CPP14_CONSTEXPR std::size_t copy(Char* dest, std::size_t count) const |
2018 | noexcept { |
2019 | return copy(dest, count, 0u); |
2020 | } |
2021 | |
2022 | /** |
2023 | * Copies `min(count, size() - pos)` characters starting from offset `pos` |
2024 | * from this string into the buffer pointed to by `dest`. |
2025 | * \pre `pos <= size()` |
2026 | * \return The number of characters copied. |
2027 | * \throw std::out_of_range if `pos > size()` |
2028 | */ |
2029 | FOLLY_CPP14_CONSTEXPR std::size_t |
2030 | copy(Char* dest, std::size_t count, std::size_t pos) const noexcept(false) { |
2031 | detail::fixedstring::checkOverflow(pos, size_); |
2032 | for (std::size_t i = 0u; i < count; ++i) { |
2033 | if (i + pos == size_) { |
2034 | return size_; |
2035 | } |
2036 | dest[i] = data_[i + pos]; |
2037 | } |
2038 | return count; |
2039 | } |
2040 | |
2041 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2042 | * Resizes the current string. |
2043 | * \note Equivalent to `resize(count, Char(0))` |
2044 | */ |
2045 | FOLLY_CPP14_CONSTEXPR void resize(std::size_t count) noexcept(false) { |
2046 | resize(count, Char(0)); |
2047 | } |
2048 | |
2049 | /** |
2050 | * Resizes the current string by setting the size to `count` and setting |
2051 | * `data()[count]` to `Char(0)`. If `count > old_size`, the characters |
2052 | * in the range [`old_size`,`count`) are set to `ch`. |
2053 | */ |
2054 | FOLLY_CPP14_CONSTEXPR void resize(std::size_t count, Char ch) noexcept( |
2055 | false) { |
2056 | detail::fixedstring::checkOverflow(count, N); |
2057 | if (count == size_) { |
2058 | } else if (count < size_) { |
2059 | size_ = count; |
2060 | data_[size_] = Char(0); |
2061 | } else { |
2062 | for (; size_ < count; ++size_) { |
2063 | data_[size_] = ch; |
2064 | } |
2065 | data_[size_] = Char(0); |
2066 | } |
2067 | } |
2068 | |
2069 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2070 | * Finds the first occurrence of the character sequence `that` in this string. |
2071 | * \note Equivalent to `find(that.data(), 0, that.size())` |
2072 | */ |
2073 | template <std::size_t M> |
2074 | constexpr std::size_t find(const BasicFixedString<Char, M>& that) const |
2075 | noexcept { |
2076 | return find(that, 0u); |
2077 | } |
2078 | |
2079 | /** |
2080 | * Finds the first occurrence of the character sequence `that` in this string, |
2081 | * starting at offset `pos`. |
2082 | * \pre `pos <= size()` |
2083 | * \note Equivalent to `find(that.data(), pos, that.size())` |
2084 | */ |
2085 | template <std::size_t M> |
2086 | constexpr std::size_t find( |
2087 | const BasicFixedString<Char, M>& that, |
2088 | std::size_t pos) const noexcept(false) { |
2089 | return that.size_ <= size_ - detail::fixedstring::checkOverflow(pos, size_) |
2090 | ? detail::fixedstring::find_(data_, size_, that.data_, pos, that.size_) |
2091 | : npos; |
2092 | } |
2093 | |
2094 | /** |
2095 | * Finds the first occurrence of the character sequence `that` in this string. |
2096 | * \note Equivalent to `find(that.data(), 0, strlen(that))` |
2097 | */ |
2098 | constexpr std::size_t find(const Char* that) const noexcept { |
2099 | return find(that, 0u, folly::constexpr_strlen(that)); |
2100 | } |
2101 | |
2102 | /** |
2103 | * Finds the first occurrence of the character sequence `that` in this string, |
2104 | * starting at offset `pos`. |
2105 | * \pre `pos <= size()` |
2106 | * \note Equivalent to `find(that.data(), pos, strlen(that))` |
2107 | */ |
2108 | constexpr std::size_t find(const Char* that, std::size_t pos) const |
2109 | noexcept(false) { |
2110 | return find(that, pos, folly::constexpr_strlen(that)); |
2111 | } |
2112 | |
2113 | /** |
2114 | * Finds the first occurrence of the first `count` characters in the buffer |
2115 | * pointed to by `that` in this string, starting at offset `pos`. |
2116 | * \pre `pos <= size()` |
2117 | * \pre `that` points to a buffer containing at least `count` contiguous |
2118 | * characters. |
2119 | * \return The lowest offset `i` such that `i >= pos` and |
2120 | * `0 == strncmp(data() + i, that, count)`; or `npos` if there is no such |
2121 | * offset `i`. |
2122 | * \throw std::out_of_range when `pos > size()` |
2123 | */ |
2124 | constexpr std::size_t find( |
2125 | const Char* that, |
2126 | std::size_t pos, |
2127 | std::size_t count) const noexcept(false) { |
2128 | return count <= size_ - detail::fixedstring::checkOverflow(pos, size_) |
2129 | ? detail::fixedstring::find_(data_, size_, that, pos, count) |
2130 | : npos; |
2131 | } |
2132 | |
2133 | /** |
2134 | * Finds the first occurrence of the character `ch` in this string. |
2135 | * \note Equivalent to `find(&ch, 0, 1)` |
2136 | */ |
2137 | constexpr std::size_t find(Char ch) const noexcept { |
2138 | return find(ch, 0u); |
2139 | } |
2140 | |
2141 | /** |
2142 | * Finds the first occurrence of the character character `c` in this string, |
2143 | * starting at offset `pos`. |
2144 | * \pre `pos <= size()` |
2145 | * \note Equivalent to `find(&ch, pos, 1)` |
2146 | */ |
2147 | constexpr std::size_t find(Char ch, std::size_t pos) const noexcept(false) { |
2148 | using A = const Char[1u]; |
2149 | return 0u == size_ - detail::fixedstring::checkOverflow(pos, size_) |
2150 | ? npos |
2151 | : detail::fixedstring::find_(data_, size_, A{ch}, pos, 1u); |
2152 | } |
2153 | |
2154 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2155 | * Finds the last occurrence of characters in the string |
2156 | * `that` in this string. |
2157 | * \note Equivalent to `rfind(that.data(), size(), that.size())` |
2158 | */ |
2159 | template <std::size_t M> |
2160 | constexpr std::size_t rfind(const BasicFixedString<Char, M>& that) const |
2161 | noexcept { |
2162 | return rfind(that, size_); |
2163 | } |
2164 | |
2165 | /** |
2166 | * Finds the last occurrence of characters in the string |
2167 | * `that` in this string, starting at offset `pos`. |
2168 | * \note Equivalent to `rfind(that.data(), pos, that.size())` |
2169 | */ |
2170 | template <std::size_t M> |
2171 | constexpr std::size_t rfind( |
2172 | const BasicFixedString<Char, M>& that, |
2173 | std::size_t pos) const noexcept(false) { |
2174 | return that.size_ <= size_ |
2175 | ? detail::fixedstring::rfind_( |
2176 | data_, |
2177 | that.data_, |
2178 | folly::constexpr_min( |
2179 | detail::fixedstring::checkOverflow(pos, size_), |
2180 | size_ - that.size_), |
2181 | that.size_) |
2182 | : npos; |
2183 | } |
2184 | |
2185 | /** |
2186 | * Finds the last occurrence of characters in the buffer |
2187 | * pointed to by `that` in this string. |
2188 | * \note Equivalent to `rfind(that, size(), strlen(that))` |
2189 | */ |
2190 | constexpr std::size_t rfind(const Char* that) const noexcept { |
2191 | return rfind(that, size_, folly::constexpr_strlen(that)); |
2192 | } |
2193 | |
2194 | /** |
2195 | * Finds the last occurrence of characters in the buffer |
2196 | * pointed to by `that` in this string, starting at offset `pos`. |
2197 | * \note Equivalent to `rfind(that, pos, strlen(that))` |
2198 | */ |
2199 | constexpr std::size_t rfind(const Char* that, std::size_t pos) const |
2200 | noexcept(false) { |
2201 | return rfind(that, pos, folly::constexpr_strlen(that)); |
2202 | } |
2203 | |
2204 | /** |
2205 | * Finds the last occurrence of the first `count` characters in the buffer |
2206 | * pointed to by `that` in this string, starting at offset `pos`. |
2207 | * \pre `pos <= size()` |
2208 | * \pre `that` points to a buffer containing at least `count` contiguous |
2209 | * characters. |
2210 | * \return The largest offset `i` such that `i <= pos` and |
2211 | * `i + count <= size()` and `0 == strncmp(data() + i, that, count)`; or |
2212 | * `npos` if there is no such offset `i`. |
2213 | * \throw std::out_of_range when `pos > size()` |
2214 | */ |
2215 | constexpr std::size_t rfind( |
2216 | const Char* that, |
2217 | std::size_t pos, |
2218 | std::size_t count) const noexcept(false) { |
2219 | return count <= size_ |
2220 | ? detail::fixedstring::rfind_( |
2221 | data_, |
2222 | that, |
2223 | folly::constexpr_min( |
2224 | detail::fixedstring::checkOverflow(pos, size_), |
2225 | size_ - count), |
2226 | count) |
2227 | : npos; |
2228 | } |
2229 | |
2230 | /** |
2231 | * Finds the last occurrence of the character character `ch` in this string. |
2232 | * \note Equivalent to `rfind(&ch, size(), 1)` |
2233 | */ |
2234 | constexpr std::size_t rfind(Char ch) const noexcept { |
2235 | return rfind(ch, size_); |
2236 | } |
2237 | |
2238 | /** |
2239 | * Finds the last occurrence of the character character `ch` in this string, |
2240 | * starting at offset `pos`. |
2241 | * \pre `pos <= size()` |
2242 | * \note Equivalent to `rfind(&ch, pos, 1)` |
2243 | */ |
2244 | constexpr std::size_t rfind(Char ch, std::size_t pos) const noexcept(false) { |
2245 | using A = const Char[1u]; |
2246 | return 0u == size_ |
2247 | ? npos |
2248 | : detail::fixedstring::rfind_( |
2249 | data_, |
2250 | A{ch}, |
2251 | folly::constexpr_min( |
2252 | detail::fixedstring::checkOverflow(pos, size_), size_ - 1u), |
2253 | 1u); |
2254 | } |
2255 | |
2256 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2257 | * Finds the first occurrence of any character in `that` in this string. |
2258 | * \note Equivalent to `find_first_of(that.data(), 0, that.size())` |
2259 | */ |
2260 | template <std::size_t M> |
2261 | constexpr std::size_t find_first_of( |
2262 | const BasicFixedString<Char, M>& that) const noexcept { |
2263 | return find_first_of(that, 0u); |
2264 | } |
2265 | |
2266 | /** |
2267 | * Finds the first occurrence of any character in `that` in this string, |
2268 | * starting at offset `pos` |
2269 | * \note Equivalent to `find_first_of(that.data(), pos, that.size())` |
2270 | */ |
2271 | template <std::size_t M> |
2272 | constexpr std::size_t find_first_of( |
2273 | const BasicFixedString<Char, M>& that, |
2274 | std::size_t pos) const noexcept(false) { |
2275 | return size_ == detail::fixedstring::checkOverflow(pos, size_) |
2276 | ? npos |
2277 | : detail::fixedstring::find_first_of_( |
2278 | data_, size_, that.data_, pos, that.size_); |
2279 | } |
2280 | |
2281 | /** |
2282 | * Finds the first occurrence of any character in the null-terminated |
2283 | * character sequence pointed to by `that` in this string. |
2284 | * \note Equivalent to `find_first_of(that, 0, strlen(that))` |
2285 | */ |
2286 | constexpr std::size_t find_first_of(const Char* that) const noexcept { |
2287 | return find_first_of(that, 0u, folly::constexpr_strlen(that)); |
2288 | } |
2289 | |
2290 | /** |
2291 | * Finds the first occurrence of any character in the null-terminated |
2292 | * character sequence pointed to by `that` in this string, |
2293 | * starting at offset `pos` |
2294 | * \note Equivalent to `find_first_of(that, pos, strlen(that))` |
2295 | */ |
2296 | constexpr std::size_t find_first_of(const Char* that, std::size_t pos) const |
2297 | noexcept(false) { |
2298 | return find_first_of(that, pos, folly::constexpr_strlen(that)); |
2299 | } |
2300 | |
2301 | /** |
2302 | * Finds the first occurrence of any character in the first `count` characters |
2303 | * in the buffer pointed to by `that` in this string, starting at offset |
2304 | * `pos`. |
2305 | * \pre `pos <= size()` |
2306 | * \pre `that` points to a buffer containing at least `count` contiguous |
2307 | * characters. |
2308 | * \return The smallest offset `i` such that `i >= pos` and |
2309 | * `std::find(that, that+count, at(i)) != that+count`; or |
2310 | * `npos` if there is no such offset `i`. |
2311 | * \throw std::out_of_range when `pos > size()` |
2312 | */ |
2313 | constexpr std::size_t find_first_of( |
2314 | const Char* that, |
2315 | std::size_t pos, |
2316 | std::size_t count) const noexcept(false) { |
2317 | return size_ == detail::fixedstring::checkOverflow(pos, size_) |
2318 | ? npos |
2319 | : detail::fixedstring::find_first_of_(data_, size_, that, pos, count); |
2320 | } |
2321 | |
2322 | /** |
2323 | * Finds the first occurrence of `ch` in this string. |
2324 | * \note Equivalent to `find_first_of(&ch, 0, 1)` |
2325 | */ |
2326 | constexpr std::size_t find_first_of(Char ch) const noexcept { |
2327 | return find_first_of(ch, 0u); |
2328 | } |
2329 | |
2330 | /** |
2331 | * Finds the first occurrence of `ch` in this string, |
2332 | * starting at offset `pos`. |
2333 | * \note Equivalent to `find_first_of(&ch, pos, 1)` |
2334 | */ |
2335 | constexpr std::size_t find_first_of(Char ch, std::size_t pos) const |
2336 | noexcept(false) { |
2337 | using A = const Char[1u]; |
2338 | return size_ == detail::fixedstring::checkOverflow(pos, size_) |
2339 | ? npos |
2340 | : detail::fixedstring::find_first_of_(data_, size_, A{ch}, pos, 1u); |
2341 | } |
2342 | |
2343 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2344 | * Finds the first occurrence of any character not in `that` in this string. |
2345 | * \note Equivalent to `find_first_not_of(that.data(), 0, that.size())` |
2346 | */ |
2347 | template <std::size_t M> |
2348 | constexpr std::size_t find_first_not_of( |
2349 | const BasicFixedString<Char, M>& that) const noexcept { |
2350 | return find_first_not_of(that, 0u); |
2351 | } |
2352 | |
2353 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2354 | * Finds the first occurrence of any character not in `that` in this string. |
2355 | * \note Equivalent to `find_first_not_of(that.data(), 0, that.size())` |
2356 | */ |
2357 | template <std::size_t M> |
2358 | constexpr std::size_t find_first_not_of( |
2359 | const BasicFixedString<Char, M>& that, |
2360 | std::size_t pos) const noexcept(false) { |
2361 | return size_ == detail::fixedstring::checkOverflow(pos, size_) |
2362 | ? npos |
2363 | : detail::fixedstring::find_first_not_of_( |
2364 | data_, size_, that.data_, pos, that.size_); |
2365 | } |
2366 | |
2367 | /** |
2368 | * Finds the first occurrence of any character not in the null-terminated |
2369 | * character sequence pointed to by `that` in this string. |
2370 | * \note Equivalent to `find_first_not_of(that, 0, strlen(that))` |
2371 | */ |
2372 | constexpr std::size_t find_first_not_of(const Char* that) const noexcept { |
2373 | return find_first_not_of(that, 0u, folly::constexpr_strlen(that)); |
2374 | } |
2375 | |
2376 | /** |
2377 | * Finds the first occurrence of any character not in the null-terminated |
2378 | * character sequence pointed to by `that` in this string, |
2379 | * starting at offset `pos` |
2380 | * \note Equivalent to `find_first_not_of(that, pos, strlen(that))` |
2381 | */ |
2382 | constexpr std::size_t find_first_not_of(const Char* that, std::size_t pos) |
2383 | const noexcept(false) { |
2384 | return find_first_not_of(that, pos, folly::constexpr_strlen(that)); |
2385 | } |
2386 | |
2387 | /** |
2388 | * Finds the first occurrence of any character not in the first `count` |
2389 | * characters in the buffer pointed to by `that` in this string, starting at |
2390 | * offset `pos`. |
2391 | * \pre `pos <= size()` |
2392 | * \pre `that` points to a buffer containing at least `count` contiguous |
2393 | * characters. |
2394 | * \return The smallest offset `i` such that `i >= pos` and |
2395 | * `std::find(that, that+count, at(i)) == that+count`; or |
2396 | * `npos` if there is no such offset `i`. |
2397 | * \throw std::out_of_range when `pos > size()` |
2398 | */ |
2399 | constexpr std::size_t find_first_not_of( |
2400 | const Char* that, |
2401 | std::size_t pos, |
2402 | std::size_t count) const noexcept(false) { |
2403 | return size_ == detail::fixedstring::checkOverflow(pos, size_) |
2404 | ? npos |
2405 | : detail::fixedstring::find_first_not_of_( |
2406 | data_, size_, that, pos, count); |
2407 | } |
2408 | |
2409 | /** |
2410 | * Finds the first occurrence of any character other than `ch` in this string. |
2411 | * \note Equivalent to `find_first_not_of(&ch, 0, 1)` |
2412 | */ |
2413 | constexpr std::size_t find_first_not_of(Char ch) const noexcept { |
2414 | return find_first_not_of(ch, 0u); |
2415 | } |
2416 | |
2417 | /** |
2418 | * Finds the first occurrence of any character other than `ch` in this string, |
2419 | * starting at offset `pos`. |
2420 | * \note Equivalent to `find_first_not_of(&ch, pos, 1)` |
2421 | */ |
2422 | constexpr std::size_t find_first_not_of(Char ch, std::size_t pos) const |
2423 | noexcept(false) { |
2424 | using A = const Char[1u]; |
2425 | return 1u <= size_ - detail::fixedstring::checkOverflow(pos, size_) |
2426 | ? detail::fixedstring::find_first_not_of_(data_, size_, A{ch}, pos, 1u) |
2427 | : npos; |
2428 | } |
2429 | |
2430 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2431 | * Finds the last occurrence of any character in `that` in this string. |
2432 | * \note Equivalent to `find_last_of(that.data(), size(), that.size())` |
2433 | */ |
2434 | template <std::size_t M> |
2435 | constexpr std::size_t find_last_of( |
2436 | const BasicFixedString<Char, M>& that) const noexcept { |
2437 | return find_last_of(that, size_); |
2438 | } |
2439 | |
2440 | /** |
2441 | * Finds the last occurrence of any character in `that` in this string, |
2442 | * starting at offset `pos` |
2443 | * \note Equivalent to `find_last_of(that.data(), pos, that.size())` |
2444 | */ |
2445 | template <std::size_t M> |
2446 | constexpr std::size_t find_last_of( |
2447 | const BasicFixedString<Char, M>& that, |
2448 | std::size_t pos) const noexcept(false) { |
2449 | return 0u == size_ |
2450 | ? npos |
2451 | : detail::fixedstring::find_last_of_( |
2452 | data_, |
2453 | that.data_, |
2454 | folly::constexpr_min( |
2455 | detail::fixedstring::checkOverflow(pos, size_), size_ - 1u), |
2456 | that.size_); |
2457 | } |
2458 | |
2459 | /** |
2460 | * Finds the last occurrence of any character in the null-terminated |
2461 | * character sequence pointed to by `that` in this string. |
2462 | * \note Equivalent to `find_last_of(that, size(), strlen(that))` |
2463 | */ |
2464 | constexpr std::size_t find_last_of(const Char* that) const noexcept { |
2465 | return find_last_of(that, size_, folly::constexpr_strlen(that)); |
2466 | } |
2467 | |
2468 | /** |
2469 | * Finds the last occurrence of any character in the null-terminated |
2470 | * character sequence pointed to by `that` in this string, |
2471 | * starting at offset `pos` |
2472 | * \note Equivalent to `find_last_of(that, pos, strlen(that))` |
2473 | */ |
2474 | constexpr std::size_t find_last_of(const Char* that, std::size_t pos) const |
2475 | noexcept(false) { |
2476 | return find_last_of(that, pos, folly::constexpr_strlen(that)); |
2477 | } |
2478 | |
2479 | /** |
2480 | * Finds the last occurrence of any character in the first `count` characters |
2481 | * in the buffer pointed to by `that` in this string, starting at offset |
2482 | * `pos`. |
2483 | * \pre `pos <= size()` |
2484 | * \pre `that` points to a buffer containing at least `count` contiguous |
2485 | * characters. |
2486 | * \return The largest offset `i` such that `i <= pos` and |
2487 | * `i < size()` and `std::find(that, that+count, at(i)) != that+count`; or |
2488 | * `npos` if there is no such offset `i`. |
2489 | * \throw std::out_of_range when `pos > size()` |
2490 | */ |
2491 | constexpr std::size_t find_last_of( |
2492 | const Char* that, |
2493 | std::size_t pos, |
2494 | std::size_t count) const noexcept(false) { |
2495 | return 0u == size_ |
2496 | ? npos |
2497 | : detail::fixedstring::find_last_of_( |
2498 | data_, |
2499 | that, |
2500 | folly::constexpr_min( |
2501 | detail::fixedstring::checkOverflow(pos, size_), size_ - 1u), |
2502 | count); |
2503 | } |
2504 | |
2505 | /** |
2506 | * Finds the last occurrence of `ch` in this string. |
2507 | * \note Equivalent to `find_last_of(&ch, size(), 1)` |
2508 | */ |
2509 | constexpr std::size_t find_last_of(Char ch) const noexcept { |
2510 | return find_last_of(ch, size_); |
2511 | } |
2512 | |
2513 | /** |
2514 | * Finds the last occurrence of `ch` in this string, |
2515 | * starting at offset `pos`. |
2516 | * \note Equivalent to `find_last_of(&ch, pos, 1)` |
2517 | */ |
2518 | constexpr std::size_t find_last_of(Char ch, std::size_t pos) const |
2519 | noexcept(false) { |
2520 | using A = const Char[1u]; |
2521 | return 0u == size_ |
2522 | ? npos |
2523 | : detail::fixedstring::find_last_of_( |
2524 | data_, |
2525 | A{ch}, |
2526 | folly::constexpr_min( |
2527 | detail::fixedstring::checkOverflow(pos, size_), size_ - 1u), |
2528 | 1u); |
2529 | } |
2530 | |
2531 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2532 | * Finds the last occurrence of any character not in `that` in this string. |
2533 | * \note Equivalent to `find_last_not_of(that.data(), size(), that.size())` |
2534 | */ |
2535 | template <std::size_t M> |
2536 | constexpr std::size_t find_last_not_of( |
2537 | const BasicFixedString<Char, M>& that) const noexcept { |
2538 | return find_last_not_of(that, size_); |
2539 | } |
2540 | |
2541 | /** |
2542 | * Finds the last occurrence of any character not in `that` in this string, |
2543 | * starting at offset `pos` |
2544 | * \note Equivalent to `find_last_not_of(that.data(), pos, that.size())` |
2545 | */ |
2546 | template <std::size_t M> |
2547 | constexpr std::size_t find_last_not_of( |
2548 | const BasicFixedString<Char, M>& that, |
2549 | std::size_t pos) const noexcept(false) { |
2550 | return 0u == size_ |
2551 | ? npos |
2552 | : detail::fixedstring::find_last_not_of_( |
2553 | data_, |
2554 | that.data_, |
2555 | folly::constexpr_min( |
2556 | detail::fixedstring::checkOverflow(pos, size_), size_ - 1u), |
2557 | that.size_); |
2558 | } |
2559 | |
2560 | /** |
2561 | * Finds the last occurrence of any character not in the null-terminated |
2562 | * character sequence pointed to by `that` in this string. |
2563 | * \note Equivalent to `find_last_not_of(that, size(), strlen(that))` |
2564 | */ |
2565 | constexpr std::size_t find_last_not_of(const Char* that) const noexcept { |
2566 | return find_last_not_of(that, size_, folly::constexpr_strlen(that)); |
2567 | } |
2568 | |
2569 | /** |
2570 | * Finds the last occurrence of any character not in the null-terminated |
2571 | * character sequence pointed to by `that` in this string, |
2572 | * starting at offset `pos` |
2573 | * \note Equivalent to `find_last_not_of(that, pos, strlen(that))` |
2574 | */ |
2575 | constexpr std::size_t find_last_not_of(const Char* that, std::size_t pos) |
2576 | const noexcept(false) { |
2577 | return find_last_not_of(that, pos, folly::constexpr_strlen(that)); |
2578 | } |
2579 | |
2580 | /** |
2581 | * Finds the last occurrence of any character not in the first `count` |
2582 | * characters in the buffer pointed to by `that` in this string, starting at |
2583 | * offset `pos`. |
2584 | * \pre `pos <= size()` |
2585 | * \pre `that` points to a buffer containing at least `count` contiguous |
2586 | * characters. |
2587 | * \return The largest offset `i` such that `i <= pos` and |
2588 | * `i < size()` and `std::find(that, that+count, at(i)) == that+count`; or |
2589 | * `npos` if there is no such offset `i`. |
2590 | * \throw std::out_of_range when `pos > size()` |
2591 | */ |
2592 | constexpr std::size_t find_last_not_of( |
2593 | const Char* that, |
2594 | std::size_t pos, |
2595 | std::size_t count) const noexcept(false) { |
2596 | return 0u == size_ |
2597 | ? npos |
2598 | : detail::fixedstring::find_last_not_of_( |
2599 | data_, |
2600 | that, |
2601 | folly::constexpr_min( |
2602 | detail::fixedstring::checkOverflow(pos, size_), size_ - 1u), |
2603 | count); |
2604 | } |
2605 | |
2606 | /** |
2607 | * Finds the last occurrence of any character other than `ch` in this string. |
2608 | * \note Equivalent to `find_last_not_of(&ch, size(), 1)` |
2609 | */ |
2610 | constexpr std::size_t find_last_not_of(Char ch) const noexcept { |
2611 | return find_last_not_of(ch, size_); |
2612 | } |
2613 | |
2614 | /** |
2615 | * Finds the last occurrence of any character other than `ch` in this string, |
2616 | * starting at offset `pos`. |
2617 | * \note Equivalent to `find_last_not_of(&ch, pos, 1)` |
2618 | */ |
2619 | constexpr std::size_t find_last_not_of(Char ch, std::size_t pos) const |
2620 | noexcept(false) { |
2621 | using A = const Char[1u]; |
2622 | return 0u == size_ |
2623 | ? npos |
2624 | : detail::fixedstring::find_last_not_of_( |
2625 | data_, |
2626 | A{ch}, |
2627 | folly::constexpr_min( |
2628 | detail::fixedstring::checkOverflow(pos, size_), size_ - 1u), |
2629 | 1u); |
2630 | } |
2631 | |
2632 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2633 | * Asymmetric relational operators |
2634 | */ |
2635 | friend constexpr bool operator==( |
2636 | const Char* a, |
2637 | const BasicFixedString& b) noexcept { |
2638 | return detail::fixedstring::equal_( |
2639 | a, folly::constexpr_strlen(a), b.data_, b.size_); |
2640 | } |
2641 | |
2642 | /** |
2643 | * \overload |
2644 | */ |
2645 | friend constexpr bool operator==( |
2646 | const BasicFixedString& a, |
2647 | const Char* b) noexcept { |
2648 | return b == a; |
2649 | } |
2650 | |
2651 | /** |
2652 | * \overload |
2653 | */ |
2654 | friend constexpr bool operator==( |
2655 | Range<const Char*> a, |
2656 | const BasicFixedString& b) noexcept { |
2657 | return detail::fixedstring::equal_(a.begin(), a.size(), b.data_, b.size_); |
2658 | } |
2659 | |
2660 | /** |
2661 | * \overload |
2662 | */ |
2663 | friend constexpr bool operator==( |
2664 | const BasicFixedString& a, |
2665 | Range<const Char*> b) noexcept { |
2666 | return b == a; |
2667 | } |
2668 | |
2669 | friend constexpr bool operator!=( |
2670 | const Char* a, |
2671 | const BasicFixedString& b) noexcept { |
2672 | return !(a == b); |
2673 | } |
2674 | |
2675 | /** |
2676 | * \overload |
2677 | */ |
2678 | friend constexpr bool operator!=( |
2679 | const BasicFixedString& a, |
2680 | const Char* b) noexcept { |
2681 | return !(b == a); |
2682 | } |
2683 | |
2684 | /** |
2685 | * \overload |
2686 | */ |
2687 | friend constexpr bool operator!=( |
2688 | Range<const Char*> a, |
2689 | const BasicFixedString& b) noexcept { |
2690 | return !(a == b); |
2691 | } |
2692 | |
2693 | /** |
2694 | * \overload |
2695 | */ |
2696 | friend constexpr bool operator!=( |
2697 | const BasicFixedString& a, |
2698 | Range<const Char*> b) noexcept { |
2699 | return !(a == b); |
2700 | } |
2701 | |
2702 | friend constexpr bool operator<( |
2703 | const Char* a, |
2704 | const BasicFixedString& b) noexcept { |
2705 | return ordering::lt == |
2706 | detail::fixedstring::compare_( |
2707 | a, 0u, folly::constexpr_strlen(a), b.data_, 0u, b.size_); |
2708 | } |
2709 | |
2710 | /** |
2711 | * \overload |
2712 | */ |
2713 | friend constexpr bool operator<( |
2714 | const BasicFixedString& a, |
2715 | const Char* b) noexcept { |
2716 | return ordering::lt == |
2717 | detail::fixedstring::compare_( |
2718 | a.data_, 0u, a.size_, b, 0u, folly::constexpr_strlen(b)); |
2719 | } |
2720 | |
2721 | /** |
2722 | * \overload |
2723 | */ |
2724 | friend constexpr bool operator<( |
2725 | Range<const Char*> a, |
2726 | const BasicFixedString& b) noexcept { |
2727 | return ordering::lt == |
2728 | detail::fixedstring::compare_( |
2729 | a.begin(), 0u, a.size(), b.data_, 0u, b.size_); |
2730 | } |
2731 | |
2732 | /** |
2733 | * \overload |
2734 | */ |
2735 | friend constexpr bool operator<( |
2736 | const BasicFixedString& a, |
2737 | Range<const Char*> b) noexcept { |
2738 | return ordering::lt == |
2739 | detail::fixedstring::compare_( |
2740 | a.data_, 0u, a.size_, b.begin(), 0u, b.size()); |
2741 | } |
2742 | |
2743 | friend constexpr bool operator>( |
2744 | const Char* a, |
2745 | const BasicFixedString& b) noexcept { |
2746 | return b < a; |
2747 | } |
2748 | |
2749 | /** |
2750 | * \overload |
2751 | */ |
2752 | friend constexpr bool operator>( |
2753 | const BasicFixedString& a, |
2754 | const Char* b) noexcept { |
2755 | return b < a; |
2756 | } |
2757 | |
2758 | /** |
2759 | * \overload |
2760 | */ |
2761 | friend constexpr bool operator>( |
2762 | Range<const Char*> a, |
2763 | const BasicFixedString& b) noexcept { |
2764 | return b < a; |
2765 | } |
2766 | |
2767 | /** |
2768 | * \overload |
2769 | */ |
2770 | friend constexpr bool operator>( |
2771 | const BasicFixedString& a, |
2772 | Range<const Char*> b) noexcept { |
2773 | return b < a; |
2774 | } |
2775 | |
2776 | friend constexpr bool operator<=( |
2777 | const Char* a, |
2778 | const BasicFixedString& b) noexcept { |
2779 | return !(b < a); |
2780 | } |
2781 | |
2782 | /** |
2783 | * \overload |
2784 | */ |
2785 | friend constexpr bool operator<=( |
2786 | const BasicFixedString& a, |
2787 | const Char* b) noexcept { |
2788 | return !(b < a); |
2789 | } |
2790 | |
2791 | /** |
2792 | * \overload |
2793 | */ |
2794 | friend constexpr bool operator<=( |
2795 | Range<const Char*> const& a, |
2796 | const BasicFixedString& b) noexcept { |
2797 | return !(b < a); |
2798 | } |
2799 | |
2800 | /** |
2801 | * \overload |
2802 | */ |
2803 | friend constexpr bool operator<=( |
2804 | const BasicFixedString& a, |
2805 | Range<const Char*> b) noexcept { |
2806 | return !(b < a); |
2807 | } |
2808 | |
2809 | friend constexpr bool operator>=( |
2810 | const Char* a, |
2811 | const BasicFixedString& b) noexcept { |
2812 | return !(a < b); |
2813 | } |
2814 | |
2815 | /** |
2816 | * \overload |
2817 | */ |
2818 | friend constexpr bool operator>=( |
2819 | const BasicFixedString& a, |
2820 | const Char* b) noexcept { |
2821 | return !(a < b); |
2822 | } |
2823 | |
2824 | /** |
2825 | * \overload |
2826 | */ |
2827 | friend constexpr bool operator>=( |
2828 | Range<const Char*> a, |
2829 | const BasicFixedString& b) noexcept { |
2830 | return !(a < b); |
2831 | } |
2832 | |
2833 | /** |
2834 | * \overload |
2835 | */ |
2836 | friend constexpr bool operator>=( |
2837 | const BasicFixedString& a, |
2838 | Range<const Char*> const& b) noexcept { |
2839 | return !(a < b); |
2840 | } |
2841 | |
2842 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2843 | * Asymmetric concatenation |
2844 | */ |
2845 | template <std::size_t M> |
2846 | friend constexpr BasicFixedString<Char, N + M - 1u> operator+( |
2847 | const Char (&a)[M], |
2848 | const BasicFixedString& b) noexcept { |
2849 | return detail::fixedstring::Helper::concat_<Char>( |
2850 | detail::fixedstring::checkNullTerminated(a), |
2851 | M - 1u, |
2852 | b.data_, |
2853 | b.size_, |
2854 | folly::make_index_sequence<N + M - 1u>{}); |
2855 | } |
2856 | |
2857 | /** |
2858 | * \overload |
2859 | */ |
2860 | template <std::size_t M> |
2861 | friend constexpr BasicFixedString<Char, N + M - 1u> operator+( |
2862 | const BasicFixedString& a, |
2863 | const Char (&b)[M]) noexcept { |
2864 | return detail::fixedstring::Helper::concat_<Char>( |
2865 | a.data_, |
2866 | a.size_, |
2867 | detail::fixedstring::checkNullTerminated(b), |
2868 | M - 1u, |
2869 | folly::make_index_sequence<N + M - 1u>{}); |
2870 | } |
2871 | |
2872 | /** |
2873 | * \overload |
2874 | */ |
2875 | friend constexpr BasicFixedString<Char, N + 1u> operator+( |
2876 | Char a, |
2877 | const BasicFixedString& b) noexcept { |
2878 | using A = const Char[2u]; |
2879 | return detail::fixedstring::Helper::concat_<Char>( |
2880 | A{a, Char(0)}, |
2881 | 1u, |
2882 | b.data_, |
2883 | b.size_, |
2884 | folly::make_index_sequence<N + 1u>{}); |
2885 | } |
2886 | |
2887 | /** |
2888 | * \overload |
2889 | */ |
2890 | friend constexpr BasicFixedString<Char, N + 1u> operator+( |
2891 | const BasicFixedString& a, |
2892 | Char b) noexcept { |
2893 | using A = const Char[2u]; |
2894 | return detail::fixedstring::Helper::concat_<Char>( |
2895 | a.data_, |
2896 | a.size_, |
2897 | A{b, Char(0)}, |
2898 | 1u, |
2899 | folly::make_index_sequence<N + 1u>{}); |
2900 | } |
2901 | }; |
2902 | |
2903 | template <class C, std::size_t N> |
2904 | inline std::basic_ostream<C>& operator<<( |
2905 | std::basic_ostream<C>& os, |
2906 | const BasicFixedString<C, N>& string) { |
2907 | using StreamSize = decltype(os.width()); |
2908 | os.write(string.begin(), static_cast<StreamSize>(string.size())); |
2909 | return os; |
2910 | } |
2911 | |
2912 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2913 | * Symmetric relational operators |
2914 | */ |
2915 | template <class Char, std::size_t A, std::size_t B> |
2916 | constexpr bool operator==( |
2917 | const BasicFixedString<Char, A>& a, |
2918 | const BasicFixedString<Char, B>& b) noexcept { |
2919 | return detail::fixedstring::equal_( |
2920 | detail::fixedstring::Helper::data_(a), |
2921 | a.size(), |
2922 | detail::fixedstring::Helper::data_(b), |
2923 | b.size()); |
2924 | } |
2925 | |
2926 | template <class Char, std::size_t A, std::size_t B> |
2927 | constexpr bool operator!=( |
2928 | const BasicFixedString<Char, A>& a, |
2929 | const BasicFixedString<Char, B>& b) { |
2930 | return !(a == b); |
2931 | } |
2932 | |
2933 | template <class Char, std::size_t A, std::size_t B> |
2934 | constexpr bool operator<( |
2935 | const BasicFixedString<Char, A>& a, |
2936 | const BasicFixedString<Char, B>& b) noexcept { |
2937 | return ordering::lt == |
2938 | detail::fixedstring::compare_( |
2939 | detail::fixedstring::Helper::data_(a), |
2940 | 0u, |
2941 | a.size(), |
2942 | detail::fixedstring::Helper::data_(b), |
2943 | 0u, |
2944 | b.size()); |
2945 | } |
2946 | |
2947 | template <class Char, std::size_t A, std::size_t B> |
2948 | constexpr bool operator>( |
2949 | const BasicFixedString<Char, A>& a, |
2950 | const BasicFixedString<Char, B>& b) noexcept { |
2951 | return b < a; |
2952 | } |
2953 | |
2954 | template <class Char, std::size_t A, std::size_t B> |
2955 | constexpr bool operator<=( |
2956 | const BasicFixedString<Char, A>& a, |
2957 | const BasicFixedString<Char, B>& b) noexcept { |
2958 | return !(b < a); |
2959 | } |
2960 | |
2961 | template <class Char, std::size_t A, std::size_t B> |
2962 | constexpr bool operator>=( |
2963 | const BasicFixedString<Char, A>& a, |
2964 | const BasicFixedString<Char, B>& b) noexcept { |
2965 | return !(a < b); |
2966 | } |
2967 | |
2968 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2969 | * Symmetric concatenation |
2970 | */ |
2971 | template <class Char, std::size_t N, std::size_t M> |
2972 | constexpr BasicFixedString<Char, N + M> operator+( |
2973 | const BasicFixedString<Char, N>& a, |
2974 | const BasicFixedString<Char, M>& b) noexcept { |
2975 | return detail::fixedstring::Helper::concat_<Char>( |
2976 | detail::fixedstring::Helper::data_(a), |
2977 | a.size(), |
2978 | detail::fixedstring::Helper::data_(b), |
2979 | b.size(), |
2980 | folly::make_index_sequence<N + M>{}); |
2981 | } |
2982 | |
2983 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2984 | * Construct a `BasicFixedString` object from a null-terminated array of |
2985 | * characters. The capacity and size of the string will be equal to one less |
2986 | * than the size of the array. |
2987 | * \pre `a` contains no embedded null characters. |
2988 | * \pre `a[N-1] == Char(0)` |
2989 | * \post For a returned string `s`, `s[i]==a[i]` for every `i` in [`0`,`N-1`]. |
2990 | */ |
2991 | template <class Char, std::size_t N> |
2992 | constexpr BasicFixedString<Char, N - 1u> makeFixedString( |
2993 | const Char (&a)[N]) noexcept { |
2994 | return {a}; |
2995 | } |
2996 | |
2997 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** |
2998 | * Swap function |
2999 | */ |
3000 | template <class Char, std::size_t N> |
3001 | FOLLY_CPP14_CONSTEXPR void swap( |
3002 | BasicFixedString<Char, N>& a, |
3003 | BasicFixedString<Char, N>& b) noexcept { |
3004 | a.swap(b); |
3005 | } |
3006 | |
3007 | inline namespace literals { |
3008 | inline namespace string_literals { |
3009 | inline namespace { |
3010 | // "const std::size_t&" is so that folly::npos has the same address in every |
3011 | // translation unit. This is to avoid potential violations of the ODR. |
3012 | constexpr const std::size_t& npos = detail::fixedstring::FixedStringBase::npos; |
3013 | } // namespace |
3014 | |
3015 | #if defined(__GNUC__) && !defined(__ICC) |
3016 | #pragma GCC diagnostic push |
3017 | #pragma GCC diagnostic ignored "-Wpragmas" |
3018 | #pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template" |
3019 | |
3020 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * |
3021 | * User-defined literals for creating FixedString objects from string literals |
3022 | * on the compilers that support it. |
3023 | * |
3024 | * \par Example: |
3025 | * \par |
3026 | * \code |
3027 | * using namespace folly::string_literals; |
3028 | * constexpr auto hello = "hello world!"_fs; |
3029 | * \endcode |
3030 | * |
3031 | * \note This requires a GNU compiler extension |
3032 | * (-Wgnu-string-literal-operator-template) supported by clang and gcc, |
3033 | * proposed for standardization in |
3034 | * <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0424r0.pdf>. |
3035 | * \par |
3036 | * For portable code, prefer the suffixes `_fs4`, `_fs8`, `_fs16`, `_fs32`, |
3037 | * `_fs64`, and `_fs128` for creating instances of types `FixedString<4>`, |
3038 | * `FixedString<8>`, `FixedString<16>`, etc. |
3039 | */ |
3040 | template <class Char, Char... Cs> |
3041 | constexpr BasicFixedString<Char, sizeof...(Cs)> operator"" _fs() noexcept { |
3042 | #if __cplusplus >= 201402L |
3043 | const Char a[] = {Cs..., Char(0)}; |
3044 | return {+a, sizeof...(Cs)}; |
3045 | #else |
3046 | using A = const Char[sizeof...(Cs) + 1u]; |
3047 | // The `+` in `+A{etc}` forces the array type to decay to a pointer |
3048 | return {+A{Cs..., Char(0)}, sizeof...(Cs)}; |
3049 | #endif |
3050 | } |
3051 | |
3052 | #pragma GCC diagnostic pop |
3053 | #endif |
3054 | |
3055 | #define FOLLY_DEFINE_FIXED_STRING_UDL(N) \ |
3056 | constexpr FixedString<N> operator"" _fs##N( \ |
3057 | const char* that, std::size_t count) noexcept(false) { \ |
3058 | return {that, count}; \ |
3059 | } \ |
3060 | /**/ |
3061 | |
3062 | // Define UDLs _fs4, _fs8, _fs16, etc for FixedString<[4, 8, 16, ...]> |
3063 | FOLLY_DEFINE_FIXED_STRING_UDL(4) |
3064 | FOLLY_DEFINE_FIXED_STRING_UDL(8) |
3065 | FOLLY_DEFINE_FIXED_STRING_UDL(16) |
3066 | FOLLY_DEFINE_FIXED_STRING_UDL(32) |
3067 | FOLLY_DEFINE_FIXED_STRING_UDL(64) |
3068 | FOLLY_DEFINE_FIXED_STRING_UDL(128) |
3069 | |
3070 | #undef FOLLY_DEFINE_FIXED_STRING_UDL |
3071 | } // namespace string_literals |
3072 | } // namespace literals |
3073 | |
3074 | // TODO: |
3075 | // // numeric conversions: |
3076 | // template <std::size_t N> |
3077 | // constexpr int stoi(const FixedString<N>& str, int base = 10); |
3078 | // template <std::size_t N> |
3079 | // constexpr unsigned stou(const FixedString<N>& str, int base = 10); |
3080 | // template <std::size_t N> |
3081 | // constexpr long stol(const FixedString<N>& str, int base = 10); |
3082 | // template <std::size_t N> |
3083 | // constexpr unsigned long stoul(const FixedString<N>& str, int base = 10; |
3084 | // template <std::size_t N> |
3085 | // constexpr long long stoll(const FixedString<N>& str, int base = 10); |
3086 | // template <std::size_t N> |
3087 | // constexpr unsigned long long stoull(const FixedString<N>& str, |
3088 | // int base = 10); |
3089 | // template <std::size_t N> |
3090 | // constexpr float stof(const FixedString<N>& str); |
3091 | // template <std::size_t N> |
3092 | // constexpr double stod(const FixedString<N>& str); |
3093 | // template <std::size_t N> |
3094 | // constexpr long double stold(const FixedString<N>& str); |
3095 | // template <int val> |
3096 | // constexpr FixedString</*...*/> to_fixed_string_i() noexcept; |
3097 | // template <unsigned val> |
3098 | // constexpr FixedString</*...*/> to_fixed_string_u() noexcept; |
3099 | // template <long val> |
3100 | // constexpr FixedString</*...*/> to_fixed_string_l() noexcept; |
3101 | // template <unsigned long val> |
3102 | // constexpr FixedString</*...*/> to_fixed_string_ul() noexcept; |
3103 | // template <long long val> |
3104 | // constexpr FixedString</*...*/> to_fixed_string_ll() noexcept |
3105 | // template <unsigned long long val> |
3106 | // constexpr FixedString</*...*/> to_fixed_string_ull() noexcept; |
3107 | } // namespace folly |
3108 | |