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