2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // @author: Eric Niebler (eniebler)
18 // Fixed-size string type, for constexpr string handling.
24 #include <initializer_list>
28 #include <type_traits>
31 #include <folly/Portability.h>
32 #include <folly/Range.h>
33 #include <folly/Utility.h>
34 #include <folly/portability/BitsFunctexcept.h>
35 #include <folly/portability/Constexpr.h>
39 template <class Char, std::size_t N>
40 class BasicFixedString;
42 template <std::size_t N>
43 using FixedString = BasicFixedString<char, N>;
46 namespace fixedstring {
48 // This is a template so that the class static npos can be defined in the
50 template <class = void>
51 struct FixedStringBase_ {
52 static constexpr std::size_t npos = static_cast<std::size_t>(-1);
56 constexpr std::size_t FixedStringBase_<Void>::npos;
58 using FixedStringBase = FixedStringBase_<>;
60 // Intentionally NOT constexpr. By making this not constexpr, we make
61 // checkOverflow below ill-formed in a constexpr context when the condition
62 // it's testing for fails. In this way, precondition violations are reported
63 // at compile-time instead of at runtime.
64 [[noreturn]] inline void assertOutOfBounds() {
65 assert(false && "Array index out of bounds in BasicFixedString");
66 std::__throw_out_of_range("Array index out of bounds in BasicFixedString");
69 constexpr std::size_t checkOverflow(std::size_t i, std::size_t max) {
70 return i <= max ? i : (assertOutOfBounds(), max);
73 constexpr std::size_t checkOverflowOrNpos(std::size_t i, std::size_t max) {
74 return i == FixedStringBase::npos
76 : (i <= max ? i : (assertOutOfBounds(), max));
79 // Intentionally NOT constexpr. See note above for assertOutOfBounds
80 [[noreturn]] inline void assertNotNullTerminated() noexcept {
83 "Non-null terminated string used to initialize a BasicFixedString");
84 std::terminate(); // Fail hard, fail fast.
87 // Parsing help for human readers: the following is a constexpr noexcept
88 // function that accepts a reference to an array as a parameter and returns
89 // a reference to the same array.
90 template <class Char, std::size_t N>
91 constexpr const Char (&checkNullTerminated(const Char (&a)[N]) noexcept)[N] {
92 // Strange decltype(a)(a) used to make MSVC happy.
93 return a[N - 1u] == Char(0)
95 // In Debug mode, guard against embedded nulls:
96 && N - 1u == folly::detail::constexpr_strlen_internal(a, 0u)
99 : (assertNotNullTerminated(), decltype(a)(a));
102 enum class Cmp : int { LT = -1, EQ = 0, GT = 1 };
104 // Rather annoyingly, GCC's -Warray-bounds warning issues false positives for
105 // this code. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61971
106 #if defined(__GNUC__) && !defined(__CLANG__) && __GNUC__ <= 5
107 #pragma GCC diagnostic push
108 #pragma GCC diagnostic ignored "-Warray-bounds"
111 template <class Left, class Right>
112 constexpr Cmp compare_(
114 std::size_t left_pos,
115 std::size_t left_size,
117 std::size_t right_pos,
118 std::size_t right_size) noexcept {
119 return left_pos == left_size
120 ? (right_pos == right_size ? Cmp::EQ : Cmp::LT)
121 : (right_pos == right_size ? Cmp::GT
122 : (left[left_pos] < right[right_pos]
124 : (left[left_pos] > right[right_pos]
126 : fixedstring::compare_(
135 template <class Left, class Right>
136 constexpr bool equal_(
138 std::size_t left_size,
140 std::size_t right_size) noexcept {
141 return left_size == right_size &&
142 Cmp::EQ == compare_(left, 0u, left_size, right, 0u, right_size);
145 template <class Char, class Left, class Right>
146 constexpr Char char_at_(
148 std::size_t left_count,
150 std::size_t right_count,
151 std::size_t i) noexcept {
152 return i < left_count
154 : i < (left_count + right_count) ? right[i - left_count] : Char(0);
157 template <class Char, class Left, class Right>
158 constexpr Char char_at_(
160 std::size_t left_size,
161 std::size_t left_pos,
162 std::size_t left_count,
164 std::size_t right_pos,
165 std::size_t right_count,
166 std::size_t i) noexcept {
169 : (i < right_count + left_pos ? right[i - left_pos + right_pos]
170 : (i < left_size - left_count + right_count
171 ? left[i - right_count + left_count]
175 template <class Left, class Right>
176 constexpr bool find_at_(
180 std::size_t count) noexcept {
181 return 0u == count || (left[pos + count - 1u] == right[count - 1u] &&
182 find_at_(left, right, pos, count - 1u));
185 template <class Char, class Right>
187 find_one_of_at_(Char ch, const Right& right, std::size_t pos) noexcept {
189 (ch == right[pos - 1u] || find_one_of_at_(ch, right, pos - 1u));
192 template <class Left, class Right>
193 constexpr std::size_t find_(
195 std::size_t left_size,
198 std::size_t count) noexcept {
199 return find_at_(left, right, pos, count) ? pos
200 : left_size <= pos + count
201 ? FixedStringBase::npos
202 : find_(left, left_size, right, pos + 1u, count);
205 template <class Left, class Right>
206 constexpr std::size_t rfind_(
210 std::size_t count) noexcept {
211 return find_at_(left, right, pos, count)
213 : 0u == pos ? FixedStringBase::npos
214 : rfind_(left, right, pos - 1u, count);
217 template <class Left, class Right>
218 constexpr std::size_t find_first_of_(
220 std::size_t left_size,
223 std::size_t count) noexcept {
224 return find_one_of_at_(left[pos], right, count) ? pos
225 : left_size <= pos + 1u
226 ? FixedStringBase::npos
227 : find_first_of_(left, left_size, right, pos + 1u, count);
230 template <class Left, class Right>
231 constexpr std::size_t find_first_not_of_(
233 std::size_t left_size,
236 std::size_t count) noexcept {
237 return !find_one_of_at_(left[pos], right, count) ? pos
238 : left_size <= pos + 1u
239 ? FixedStringBase::npos
240 : find_first_not_of_(left, left_size, right, pos + 1u, count);
243 template <class Left, class Right>
244 constexpr std::size_t find_last_of_(
248 std::size_t count) noexcept {
249 return find_one_of_at_(left[pos], right, count)
251 : 0u == pos ? FixedStringBase::npos
252 : find_last_of_(left, right, pos - 1u, count);
255 template <class Left, class Right>
256 constexpr std::size_t find_last_not_of_(
260 std::size_t count) noexcept {
261 return !find_one_of_at_(left[pos], right, count)
263 : 0u == pos ? FixedStringBase::npos
264 : find_last_not_of_(left, right, pos - 1u, count);
268 template <class Char, class Left, class Right, std::size_t... Is>
269 static constexpr BasicFixedString<Char, sizeof...(Is)> concat_(
271 std::size_t left_count,
273 std::size_t right_count,
274 folly::index_sequence<Is...> is) noexcept {
275 return {left, left_count, right, right_count, is};
278 template <class Char, class Left, class Right, std::size_t... Is>
279 static constexpr BasicFixedString<Char, sizeof...(Is)> replace_(
281 std::size_t left_size,
282 std::size_t left_pos,
283 std::size_t left_count,
285 std::size_t right_pos,
286 std::size_t right_count,
287 folly::index_sequence<Is...> is) noexcept {
298 template <class Char, std::size_t N>
299 static constexpr const Char (
300 &data_(const BasicFixedString<Char, N>& that) noexcept)[N + 1u] {
305 #if defined(__GNUC__) && !defined(__CLANG__) && __GNUC__ <= 4
306 #pragma GCC diagnostic pop
310 FOLLY_CPP14_CONSTEXPR void constexpr_swap(T& a, T& b) noexcept(
311 noexcept(a = T(std::move(a)))) {
312 T tmp((std::move(a)));
317 // FUTURE: use const_log2 to fold instantiations of BasicFixedString together.
318 // All BasicFixedString<C, N> instantiations could share the implementation
319 // of BasicFixedString<C, M>, where M is the next highest power of 2 after N.
321 // Also, because of alignment of the data_ and size_ members, N should never be
322 // smaller than `(alignof(std::size_t)/sizeof(C))-1` (-1 because of the null
323 // terminator). OR, create a specialization for BasicFixedString<C, 0u> that
324 // does not have a size_ member, since it is unnecessary.
325 constexpr std::size_t const_log2(std::size_t N, std::size_t log2 = 0u) {
326 return N / 2u == 0u ? log2 : const_log2(N / 2u, log2 + 1u);
329 // For constexpr reverse iteration over a BasicFixedString
331 struct ReverseIterator {
337 using other = typename std::conditional<
338 std::is_const<T>::value,
339 ReverseIterator<typename std::remove_const<T>::type>,
343 using value_type = typename std::remove_const<T>::type;
344 using reference = T&;
346 using difference_type = std::ptrdiff_t;
347 using iterator_category = std::random_access_iterator_tag;
349 constexpr ReverseIterator() = default;
350 constexpr ReverseIterator(const ReverseIterator&) = default;
351 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator=(const ReverseIterator&) =
353 constexpr explicit ReverseIterator(T* p) noexcept : p_(p) {}
354 constexpr /* implicit */ ReverseIterator(const other& that) noexcept
356 friend constexpr bool operator==(
358 ReverseIterator b) noexcept {
361 friend constexpr bool operator!=(
363 ReverseIterator b) noexcept {
366 constexpr reference operator*() const {
369 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator++() noexcept {
373 FOLLY_CPP14_CONSTEXPR ReverseIterator operator++(int)noexcept {
378 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator--() noexcept {
382 FOLLY_CPP14_CONSTEXPR ReverseIterator operator--(int)noexcept {
387 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator+=(std::ptrdiff_t i) noexcept {
391 friend constexpr ReverseIterator operator+(
393 ReverseIterator that) noexcept {
394 return ReverseIterator{that.p_ - i};
396 friend constexpr ReverseIterator operator+(
397 ReverseIterator that,
398 std::ptrdiff_t i) noexcept {
399 return ReverseIterator{that.p_ - i};
401 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator-=(std::ptrdiff_t i) noexcept {
405 friend constexpr ReverseIterator operator-(
406 ReverseIterator that,
407 std::ptrdiff_t i) noexcept {
408 return ReverseIterator{that.p_ + i};
410 friend constexpr std::ptrdiff_t operator-(
412 ReverseIterator b) noexcept {
415 constexpr reference operator[](std::ptrdiff_t i) const noexcept {
420 } // namespace fixedstring
421 } // namespace detail
423 // Defined in folly/Hash.h
424 std::uint32_t hsieh_hash32_buf(const void* buf, std::size_t len);
426 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
427 * \class BasicFixedString
429 * \tparam Char The character type. Must be a scalar type.
430 * \tparam N The capacity and max size of string instances of this type.
432 * \brief A class for holding up to `N` characters of type `Char` that is
433 * amenable to `constexpr` string manipulation. It is guaranteed to not
434 * perform any dynamic allocation.
436 * `BasicFixedString` is a `std::string` work-alike that stores characters in an
437 * internal buffer. It has minor interface differences that make it easy to work
438 * with strings in a `constexpr` context.
443 * constexpr auto hello = makeFixedString("hello"); // a FixedString<5>
444 * constexpr auto world = makeFixedString("world"); // a FixedString<5>
445 * constexpr auto hello_world = hello + ' ' + world + '!'; // a FixedString<12>
446 * static_assert(hello_world == "hello world!", "neato!");
449 * `FixedString<N>` is an alias for `BasicFixedString<char, N>`.
451 * \par Constexpr and In-place Mutation
453 * On a C++14 compiler, `BasicFixedString` supports the full `std::string`
454 * interface as `constexpr` member functions. On a C++11 compiler, the mutating
455 * members are not `constexpr`, but non-mutating alternatives, which create a
456 * new string, can be used instead. For example, instead of this:
459 * constexpr FixedString<10> replace_example_cpp14() {
460 * FixedString<10> test{"****"};
461 * test.replace(1, 2, "!!!!");
462 * return test; // returns "*!!!!*"
466 * You might write this instead:
469 * constexpr FixedString<10> replace_example_cpp11() {
470 * // GNU compilers have an extension that make it possible to create
471 * // FixedString objects with a `""_fs` user-defined literal.
472 * using namespace folly;
473 * return makeFixedString("****").creplace(1, 2, "!!!!"); // "*!!!!*"
477 * \par User-defined Literals
478 * Instead of using the `folly::makeFixedString` helper function, you can use
479 * a user-defined literal to make `FixedString` instances. The UDL feature of
480 * C++ has some limitations that make this less than ideal; you must tell the
481 * compiler roughly how many characters are in the string. The suffixes `_fs4`,
482 * `_fs8`, `_fs16`, `_fs32`, `_fs64`, and `_fs128` exist to create instances
483 * of types `FixedString<4>`, `FixedString<8>`, etc. For example:
486 * using namespace folly::string_literals;
487 * constexpr auto hello = "hello"_fs8; // A FixedString<8> containing "hello"
490 * See Error Handling below for what to expect when you try to exceed the
491 * capacity of a `FixedString` by storing too many characters in it.
493 * If your compiler supports GNU extensions, there is one additional suffix you
494 * can use: `_fs`. This suffix always creates `FixedString` objects of exactly
495 * the right size. For example:
498 * using namespace folly::string_literals;
499 * // NOTE: Only works on compilers with GNU extensions enabled. Clang and
500 * // gcc support this (-Wgnu-string-literal-operator-template):
501 * constexpr auto hello = "hello"_fs; // A FixedString<5> containing "hello"
504 * \par Error Handling:
505 * The capacity of a `BasicFixedString` is set at compile time. When the user
506 * asks the string to exceed its capacity, one of three things will happen,
507 * depending on the context:
509 * -# If the attempt is made while evaluating a constant expression, the
510 * program will fail to compile.
511 * -# Otherwise, if the program is being run in debug mode, it will `assert`.
512 * -# Otherwise, the failed operation will throw a `std::out_of_range`
515 * This is also the case if an invalid offset is passed to any member function,
516 * or if `pop_back` or `cpop_back` is called on an empty `BasicFixedString`.
518 * Member functions documented as having preconditions will assert in Debug
519 * mode (`!defined(NDEBUG)`) on precondition failures. Those documented with
520 * \b Throws clauses will throw the specified exception on failure. Those with
521 * both a precondition and a \b Throws clause will assert in Debug and throw
524 template <class Char, std::size_t N>
525 class BasicFixedString : private detail::fixedstring::FixedStringBase {
527 template <class, std::size_t>
528 friend class BasicFixedString;
529 friend struct detail::fixedstring::Helper;
531 Char data_[N + 1u]; // +1 for the null terminator
532 std::size_t size_; // Nbr of chars, not incl. null terminator. size_ <= N.
534 using Indices = folly::make_index_sequence<N>;
536 template <class That, std::size_t... Is>
537 constexpr BasicFixedString(
540 folly::index_sequence<Is...>,
542 std::size_t count = npos) noexcept
543 : data_{(Is < (size - pos) && Is < count ? that[Is + pos] : Char(0))...,
545 size_{folly::constexpr_min(size - pos, count)} {}
547 template <std::size_t... Is>
548 constexpr BasicFixedString(
551 folly::index_sequence<Is...>) noexcept
552 : data_{((Is < count) ? ch : Char(0))..., Char(0)}, size_{count} {}
554 // Concatenation constructor
555 template <class Left, class Right, std::size_t... Is>
556 constexpr BasicFixedString(
558 std::size_t left_size,
560 std::size_t right_size,
561 folly::index_sequence<Is...>) noexcept
562 : data_{detail::fixedstring::char_at_<Char>(
569 size_{left_size + right_size} {}
571 // Replace constructor
572 template <class Left, class Right, std::size_t... Is>
573 constexpr BasicFixedString(
575 std::size_t left_size,
576 std::size_t left_pos,
577 std::size_t left_count,
579 std::size_t right_pos,
580 std::size_t right_count,
581 folly::index_sequence<Is...>) noexcept
582 : data_{detail::fixedstring::char_at_<Char>(
592 size_{left_size - left_count + right_count} {}
595 using size_type = std::size_t;
596 using difference_type = std::ptrdiff_t;
597 using reference = Char&;
598 using const_reference = const Char&;
599 using pointer = Char*;
600 using const_pointer = const Char*;
601 using iterator = Char*;
602 using const_iterator = const Char*;
603 using reverse_iterator = detail::fixedstring::ReverseIterator<Char>;
604 using const_reverse_iterator =
605 detail::fixedstring::ReverseIterator<const Char>;
607 using detail::fixedstring::FixedStringBase::npos;
609 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
611 * \post `size() == 0`
612 * \post `at(0) == Char(0)`
614 constexpr BasicFixedString() : data_{}, size_{} {}
616 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
618 * \post `size() == that.size()`
619 * \post `0 == strncmp(data(), that.data(), size())`
620 * \post `at(size()) == Char(0)`
622 constexpr BasicFixedString(const BasicFixedString& /*that*/) = default;
624 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
625 * Construct from a differently-sized BasicFixedString
626 * \pre `that.size() <= N`
627 * \post `size() == that.size()`
628 * \post `0 == strncmp(data(), that.data(), size())`
629 * \post `at(size()) == Char(0)`
630 * \throw std::out_of_range when that.size() > N. When M <= N, this
631 * constructor will never throw.
632 * \note Conversions from larger-capacity BasicFixedString objects to smaller
633 * ones (`M > N`) are allowed as long as the *size()* of the source string
636 template <std::size_t M>
637 constexpr /* implicit */ BasicFixedString(
638 const BasicFixedString<Char, M>& that) noexcept(M <= N)
639 : BasicFixedString{that, 0u, that.size_} {}
641 // Why is this deleted? To avoid confusion with the constructor that takes
642 // a const Char* and a count.
643 template <std::size_t M>
644 constexpr BasicFixedString(
645 const BasicFixedString<Char, M>& that,
646 std::size_t pos) noexcept(false) = delete;
648 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
649 * Construct from an BasicFixedString, an offset, and a count
650 * \param that The source string
651 * \param pos The starting position in `that`
652 * \param count The number of characters to copy. If `npos`, `count` is taken
653 * to be `that.size()-pos`.
654 * \pre `pos <= that.size()`
655 * \pre `count <= that.size()-pos && count <= N`
656 * \post `size() == count`
657 * \post `0 == strncmp(data(), that.data()+pos, size())`
658 * \post `at(size()) == Char(0)`
659 * \throw std::out_of_range when pos+count > that.size(), or when
662 template <std::size_t M>
663 constexpr BasicFixedString(
664 const BasicFixedString<Char, M>& that,
666 std::size_t count) noexcept(false)
670 folly::make_index_sequence<(M < N ? M : N)>{},
672 detail::fixedstring::checkOverflow(
673 detail::fixedstring::checkOverflowOrNpos(
676 detail::fixedstring::checkOverflow(pos, that.size_)),
679 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
680 * Construct from a string literal
682 * \pre `that[M-1] == Char(0)`
683 * \post `0 == strncmp(data(), that, M-1)`
684 * \post `size() == M-1`
685 * \post `at(size()) == Char(0)`
687 template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
688 constexpr /* implicit */ BasicFixedString(const Char (&that)[M]) noexcept
689 : BasicFixedString{detail::fixedstring::checkNullTerminated(that),
691 folly::make_index_sequence<M - 1u>{}} {}
693 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
694 * Construct from a `const Char*` and count
695 * \pre `that` points to an array of at least `count` characters.
697 * \post `size() == count`
698 * \post `0 == strncmp(data(), that, size())`
699 * \post `at(size()) == Char(0)`
700 * \throw std::out_of_range when count > N
702 constexpr BasicFixedString(const Char* that, std::size_t count) noexcept(
704 : BasicFixedString{that,
705 detail::fixedstring::checkOverflow(count, N),
708 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
709 * Construct an BasicFixedString that contains `count` characters, all
712 * \post `size() == count`
713 * \post `npos == find_first_not_of(ch)`
714 * \post `at(size()) == Char(0)`
715 * \throw std::out_of_range when count > N
717 constexpr BasicFixedString(std::size_t count, Char ch) noexcept(false)
718 : BasicFixedString{detail::fixedstring::checkOverflow(count, N),
722 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
723 * Construct an BasicFixedString from a `std::initializer_list` of
725 * \pre `il.size() <= N`
726 * \post `size() == count`
727 * \post `0 == strncmp(data(), il.begin(), size())`
728 * \post `at(size()) == Char(0)`
729 * \throw std::out_of_range when il.size() > N
731 constexpr BasicFixedString(std::initializer_list<Char> il) noexcept(false)
732 : BasicFixedString{il.begin(), il.size()} {}
734 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
735 const BasicFixedString&) noexcept = default;
737 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
738 * Assign from a `BasicFixedString<Char, M>`.
739 * \pre `that.size() <= N`
740 * \post `size() == that.size()`
741 * \post `0 == strncmp(data(), that.begin(), size())`
742 * \post `at(size()) == Char(0)`
743 * \throw std::out_of_range when that.size() > N. When M <= N, this
744 * assignment operator will never throw.
745 * \note Assignments from larger-capacity BasicFixedString objects to smaller
746 * ones (`M > N`) are allowed as long as the *size* of the source string is
750 template <std::size_t M>
751 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
752 const BasicFixedString<Char, M>& that) noexcept(M <= N) {
753 detail::fixedstring::checkOverflow(that.size_, N);
754 size_ = that.copy(data_, that.size_);
755 data_[size_] = Char(0);
759 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
760 * Assign from a null-terminated array of characters.
762 * \pre `that` has no embedded null characters
763 * \pre `that[M-1]==Char(0)`
764 * \post `size() == M-1`
765 * \post `0 == strncmp(data(), that, size())`
766 * \post `at(size()) == Char(0)`
769 template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
770 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
771 const Char (&that)[M]) noexcept {
772 return assign(detail::fixedstring::checkNullTerminated(that), M - 1u);
775 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
776 * Assign from an `initializer_list` of characters.
777 * \pre `il.size() <= N`
778 * \post `size() == il.size()`
779 * \post `0 == strncmp(data(), il.begin(), size())`
780 * \post `at(size()) == Char(0)`
781 * \throw std::out_of_range when il.size() > N
784 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
785 std::initializer_list<Char> il) noexcept(false) {
786 detail::fixedstring::checkOverflow(il.size(), N);
787 for (std::size_t i = 0u; i < il.size(); ++i) {
788 data_[i] = il.begin()[i];
791 data_[size_] = Char(0);
795 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
796 * Conversion to folly::Range
797 * \return `Range<Iter>{begin(), end()}`
801 class = typename std::enable_if<
802 std::is_convertible<Char*, Iter>::value>::type>
803 FOLLY_CPP14_CONSTEXPR /* implicit */ operator Range<Iter>() noexcept {
804 return {begin(), end()};
812 class = typename std::enable_if<
813 std::is_convertible<const Char*, Iter>::value>::type>
814 constexpr /* implicit */ operator Range<Iter>() const noexcept {
815 return {begin(), end()};
818 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
819 * Conversion to folly::Range
820 * \return `Range<Char*>{begin(), end()}`
822 FOLLY_CPP14_CONSTEXPR Range<Char*> toRange() noexcept {
823 return {begin(), end()};
829 constexpr Range<const Char*> toRange() const noexcept {
830 return {begin(), end()};
833 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
834 * Conversion to std::basic_string<Char>
835 * \return `std::basic_string<Char>{begin(), end()}`
837 /* implicit */ operator std::basic_string<Char>() const noexcept(false) {
838 return std::basic_string<Char>{begin(), end()};
841 std::basic_string<Char> toStdString() const noexcept(false) {
842 return std::basic_string<Char>{begin(), end()};
845 // Think hard about whether this is a good idea. It's certainly better than
846 // an implicit conversion to `const Char*` since `delete "hi"_fs` will fail
847 // to compile. But it creates ambiguities when passing a FixedString to an
848 // API that has overloads for `const char*` and `folly::Range`, for instance.
849 // using ArrayType = Char[N];
850 // FOLLY_CPP14_CONSTEXPR /* implicit */ operator ArrayType&() noexcept {
854 // using ConstArrayType = const Char[N];
855 // constexpr /* implicit */ operator ConstArrayType&() const noexcept {
859 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
860 * Assigns a sequence of `count` characters of value `ch`.
861 * \param count The count of characters.
864 * \post `size() == count`
865 * \post `npos == find_first_not_of(ch)`
866 * \post `at(size()) == Char(0)`
867 * \throw std::out_of_range when count > N
870 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
872 Char ch) noexcept(false) {
873 detail::fixedstring::checkOverflow(count, N);
874 for (std::size_t i = 0u; i < count; ++i) {
878 data_[size_] = Char(0);
882 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
883 * Assigns characters from an `BasicFixedString` to this object.
884 * \note Equivalent to `assign(that, 0, that.size())`
886 template <std::size_t M>
887 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
888 const BasicFixedString<Char, M>& that) noexcept(M <= N) {
892 // Why is this overload deleted? So users aren't confused by the difference
893 // between str.assign("foo", N) and str.assign("foo"_fs, N). In the former,
894 // N is a count of characters. In the latter, it would be a position, which
895 // totally changes the meaning of the code.
896 template <std::size_t M>
897 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
898 const BasicFixedString<Char, M>& that,
899 std::size_t pos) noexcept(false) = delete;
901 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
902 * Assigns `count` characters from an `BasicFixedString` to this object,
903 * starting at position `pos` in the source object.
904 * \param that The source string.
905 * \param pos The starting position in the source string.
906 * \param count The number of characters to copy. If `npos`, `count` is taken
907 * to be `that.size()-pos`.
908 * \pre `pos <= that.size()`
909 * \pre `count <= that.size()-pos`
911 * \post `size() == count`
912 * \post `0 == strncmp(data(), that.begin() + pos, count)`
913 * \post `at(size()) == Char(0)`
914 * \throw std::out_of_range when pos > that.size() or count > that.size()-pos
918 template <std::size_t M>
919 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
920 const BasicFixedString<Char, M>& that,
922 std::size_t count) noexcept(false) {
923 detail::fixedstring::checkOverflow(pos, that.size_);
926 detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos));
929 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
930 * Assigns characters from an `BasicFixedString` to this object.
931 * \pre `that` contains no embedded nulls.
932 * \pre `that[M-1] == Char(0)`
933 * \note Equivalent to `assign(that, M - 1)`
935 template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
936 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
937 const Char (&that)[M]) noexcept {
938 return assign(detail::fixedstring::checkNullTerminated(that), M - 1u);
941 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
942 * Assigns `count` characters from a range of characters to this object.
943 * \param that A pointer to a range of characters.
944 * \param count The number of characters to copy.
945 * \pre `that` points to at least `count` characters.
947 * \post `size() == count`
948 * \post `0 == strncmp(data(), that, count)`
949 * \post `at(size()) == Char(0)`
950 * \throw std::out_of_range when count > N
953 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
955 std::size_t count) noexcept(false) {
956 detail::fixedstring::checkOverflow(count, N);
957 for (std::size_t i = 0u; i < count; ++i) {
961 data_[size_] = Char(0);
965 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
966 * Swap the contents of this string with `that`.
968 FOLLY_CPP14_CONSTEXPR void swap(BasicFixedString& that) noexcept {
969 // less-than-or-equal here to copy the null terminator:
970 for (std::size_t i = 0u; i <= folly::constexpr_max(size_, that.size_);
972 detail::fixedstring::constexpr_swap(data_[i], that.data_[i]);
974 detail::fixedstring::constexpr_swap(size_, that.size_);
977 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
978 * Return a pointer to a range of `size()+1` characters, the last of which
981 FOLLY_CPP14_CONSTEXPR Char* data() noexcept {
988 constexpr const Char* data() const noexcept {
992 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
995 constexpr const Char* c_str() const noexcept {
999 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1002 FOLLY_CPP14_CONSTEXPR Char* begin() noexcept {
1009 constexpr const Char* begin() const noexcept {
1013 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1016 constexpr const Char* cbegin() const noexcept {
1020 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1021 * \return `data() + size()`.
1023 FOLLY_CPP14_CONSTEXPR Char* end() noexcept {
1024 return data_ + size_;
1030 constexpr const Char* end() const noexcept {
1031 return data_ + size_;
1034 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1035 * \return `data() + size()`.
1037 constexpr const Char* cend() const noexcept {
1041 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1042 * Returns a reverse iterator to the first character of the reversed string.
1043 * It corresponds to the last + 1 character of the non-reversed string.
1045 FOLLY_CPP14_CONSTEXPR reverse_iterator rbegin() noexcept {
1046 return reverse_iterator{data_ + size_};
1052 constexpr const_reverse_iterator rbegin() const noexcept {
1053 return const_reverse_iterator{data_ + size_};
1057 * \note Equivalent to `rbegin()` on a const-qualified reference to `*this`.
1059 constexpr const_reverse_iterator crbegin() const noexcept {
1063 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1064 * Returns a reverse iterator to the last + 1 character of the reversed
1065 * string. It corresponds to the first character of the non-reversed string.
1067 FOLLY_CPP14_CONSTEXPR reverse_iterator rend() noexcept {
1068 return reverse_iterator{data_};
1074 constexpr const_reverse_iterator rend() const noexcept {
1075 return const_reverse_iterator{data_};
1079 * \note Equivalent to `rend()` on a const-qualified reference to `*this`.
1081 constexpr const_reverse_iterator crend() const noexcept {
1086 * \return The number of `Char` elements in the string.
1088 constexpr std::size_t size() const noexcept {
1093 * \return The number of `Char` elements in the string.
1095 constexpr std::size_t length() const noexcept {
1100 * \return True if and only if `size() == 0`.
1102 constexpr bool empty() const noexcept {
1109 static constexpr std::size_t capacity() noexcept {
1116 static constexpr std::size_t max_size() noexcept {
1120 // We would need to reimplement folly::Hash to make this
1122 std::uint32_t hash() const noexcept {
1123 return folly::hsieh_hash32_buf(data_, size_);
1127 * \note `at(size())` is allowed will return `Char(0)`.
1128 * \return `*(data() + i)`
1129 * \throw std::out_of_range when i > size()
1131 FOLLY_CPP14_CONSTEXPR Char& at(std::size_t i) noexcept(false) {
1134 : (std::__throw_out_of_range("Out of range in BasicFixedString::at"),
1141 constexpr const Char& at(std::size_t i) const noexcept(false) {
1144 : (std::__throw_out_of_range("Out of range in BasicFixedString::at"),
1149 * \pre `i <= size()`
1150 * \note `(*this)[size()]` is allowed will return `Char(0)`.
1151 * \return `*(data() + i)`
1153 FOLLY_CPP14_CONSTEXPR Char& operator[](std::size_t i) noexcept {
1157 return data_[detail::fixedstring::checkOverflow(i, size_)];
1164 constexpr const Char& operator[](std::size_t i) const noexcept {
1168 return data_[detail::fixedstring::checkOverflow(i, size_)];
1173 * \note Equivalent to `(*this)[0]`
1175 FOLLY_CPP14_CONSTEXPR Char& front() noexcept {
1182 constexpr const Char& front() const noexcept {
1187 * \note Equivalent to `at(size()-1)`
1190 FOLLY_CPP14_CONSTEXPR Char& back() noexcept {
1192 return data_[size_ - 1u];
1194 return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)];
1201 constexpr const Char& back() const noexcept {
1203 return data_[size_ - 1u];
1205 return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)];
1210 * Clears the contents of this string.
1211 * \post `size() == 0u`
1212 * \post `at(size()) == Char(0)`
1214 FOLLY_CPP14_CONSTEXPR void clear() noexcept {
1215 data_[0u] = Char(0);
1220 * \note Equivalent to `append(1u, ch)`.
1222 FOLLY_CPP14_CONSTEXPR void push_back(Char ch) noexcept(false) {
1223 detail::fixedstring::checkOverflow(1u, N - size_);
1225 data_[++size_] = Char(0);
1229 * \note Equivalent to `cappend(1u, ch)`.
1231 constexpr BasicFixedString<Char, N + 1u> cpush_back(Char ch) const noexcept {
1236 * Removes the last character from the string.
1238 * \post `size()` is one fewer than before calling `pop_back()`.
1239 * \post `at(size()) == Char(0)`
1240 * \post The characters in the half-open range `[0,size()-1)` are unmodified.
1241 * \throw std::out_of_range if empty().
1243 FOLLY_CPP14_CONSTEXPR void pop_back() noexcept(false) {
1244 detail::fixedstring::checkOverflow(1u, size_);
1246 data_[size_] = Char(0);
1250 * Returns a new string with the first `size()-1` characters from this string.
1252 * \note Equivalent to `BasicFixedString<Char, N-1u>{*this, 0u, size()-1u}`
1253 * \throw std::out_of_range if empty().
1255 constexpr BasicFixedString<Char, N - 1u> cpop_back() const noexcept(false) {
1256 return {*this, 0u, size_ - detail::fixedstring::checkOverflow(1u, size_)};
1259 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1260 * Appends `count` copies of `ch` to this string.
1261 * \pre `count + old_size <= N`
1262 * \post The first `old_size` characters of the string are unmodified.
1263 * \post `size() == old_size + count`
1264 * \throw std::out_of_range if count > N - size().
1266 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1268 Char ch) noexcept(false) {
1269 detail::fixedstring::checkOverflow(count, N - size_);
1270 for (std::size_t i = 0u; i < count; ++i)
1271 data_[size_ + i] = ch;
1273 data_[size_] = Char(0);
1278 * \note Equivalent to `append(*this, 0, that.size())`.
1280 template <std::size_t M>
1281 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1282 const BasicFixedString<Char, M>& that) noexcept(false) {
1283 return append(that, 0u, that.size_);
1286 // Why is this overload deleted? So as not to get confused with
1287 // append("null-terminated", N), where N would be a count instead
1289 template <std::size_t M>
1290 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1291 const BasicFixedString<Char, M>& that,
1292 std::size_t pos) noexcept(false) = delete;
1295 * Appends `count` characters from another string to this one, starting at a
1296 * given offset, `pos`.
1297 * \param that The source string.
1298 * \param pos The starting position in the source string.
1299 * \param count The number of characters to append. If `npos`, `count` is
1300 * taken to be `that.size()-pos`.
1301 * \pre `pos <= that.size()`
1302 * \pre `count <= that.size() - pos`
1303 * \pre `old_size + count <= N`
1304 * \post The first `old_size` characters of the string are unmodified.
1305 * \post `size() == old_size + count`
1306 * \post `at(size()) == Char(0)`
1307 * \throw std::out_of_range if pos + count > that.size() or if
1308 * `old_size + count > N`.
1310 template <std::size_t M>
1311 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1312 const BasicFixedString<Char, M>& that,
1314 std::size_t count) noexcept(false) {
1315 detail::fixedstring::checkOverflow(pos, that.size_);
1316 count = detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos);
1317 detail::fixedstring::checkOverflow(count, N - size_);
1318 for (std::size_t i = 0u; i < count; ++i)
1319 data_[size_ + i] = that.data_[pos + i];
1321 data_[size_] = Char(0);
1326 * \note Equivalent to `append(that, strlen(that))`.
1328 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(const Char* that) noexcept(
1330 return append(that, folly::constexpr_strlen(that));
1334 * Appends `count` characters from the specified character array.
1335 * \pre `that` points to a range of at least `count` characters.
1336 * \pre `count + old_size <= N`
1337 * \post The first `old_size` characters of the string are unmodified.
1338 * \post `size() == old_size + count`
1339 * \post `at(size()) == Char(0)`
1340 * \throw std::out_of_range if old_size + count > N.
1342 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1344 std::size_t count) noexcept(false) {
1345 detail::fixedstring::checkOverflow(count, N - size_);
1346 for (std::size_t i = 0u; i < count; ++i)
1347 data_[size_ + i] = that[i];
1349 data_[size_] = Char(0);
1353 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1354 * Creates a new string by appending a character to an existing string, which
1355 * is left unmodified.
1356 * \note Equivalent to `*this + ch`
1358 constexpr BasicFixedString<Char, N + 1u> cappend(Char ch) const noexcept {
1363 * Creates a new string by appending a string to an existing string, which
1364 * is left unmodified.
1365 * \note Equivalent to `*this + ch`
1367 template <std::size_t M>
1368 constexpr BasicFixedString<Char, N + M> cappend(
1369 const BasicFixedString<Char, M>& that) const noexcept {
1370 return *this + that;
1373 // Deleted to avoid confusion with append("char*", N), where N is a count
1374 // instead of a position.
1375 template <std::size_t M>
1376 constexpr BasicFixedString<Char, N + M> cappend(
1377 const BasicFixedString<Char, M>& that,
1378 std::size_t pos) const noexcept(false) = delete;
1381 * Creates a new string by appending characters from one string to another,
1382 * which is left unmodified.
1383 * \note Equivalent to `*this + that.substr(pos, count)`
1385 template <std::size_t M>
1386 constexpr BasicFixedString<Char, N + M> cappend(
1387 const BasicFixedString<Char, M>& that,
1389 std::size_t count) const noexcept(false) {
1390 return creplace(size_, 0u, that, pos, count);
1394 * Creates a new string by appending a string literal to a string,
1395 * which is left unmodified.
1396 * \note Equivalent to `*this + that`
1398 template <std::size_t M>
1399 constexpr BasicFixedString<Char, N + M - 1u> cappend(
1400 const Char (&that)[M]) const noexcept {
1401 return creplace(size_, 0u, that);
1404 // Deleted to avoid confusion with append("char*", N), where N is a count
1405 // instead of a position
1406 template <std::size_t M>
1407 constexpr BasicFixedString<Char, N + M - 1u> cappend(
1408 const Char (&that)[M],
1409 std::size_t pos) const noexcept(false) = delete;
1412 * Creates a new string by appending characters from one string to another,
1413 * which is left unmodified.
1414 * \note Equivalent to `*this + makeFixedString(that).substr(pos, count)`
1416 template <std::size_t M>
1417 constexpr BasicFixedString<Char, N + M - 1u>
1418 cappend(const Char (&that)[M], std::size_t pos, std::size_t count) const
1420 return creplace(size_, 0u, that, pos, count);
1423 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1424 * Appends characters from a null-terminated string literal to this string.
1425 * \note Equivalent to `append(that)`.
1427 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(const Char* that) noexcept(
1429 return append(that);
1433 * Appends characters from another string to this one.
1434 * \note Equivalent to `append(that)`.
1436 template <std::size_t M>
1437 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(
1438 const BasicFixedString<Char, M>& that) noexcept(false) {
1439 return append(that, 0u, that.size_);
1443 * Appends a character to this string.
1444 * \note Equivalent to `push_back(ch)`.
1446 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(Char ch) noexcept(false) {
1452 * Appends characters from an `initializer_list` to this string.
1453 * \note Equivalent to `append(il.begin(), il.size())`.
1455 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(
1456 std::initializer_list<Char> il) noexcept(false) {
1457 return append(il.begin(), il.size());
1460 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1461 * Erase all characters from this string.
1462 * \note Equivalent to `clear()`
1465 FOLLY_CPP14_CONSTEXPR BasicFixedString& erase() noexcept {
1471 * Erases `count` characters from position `pos`. If `count` is `npos`,
1472 * erases from `pos` to the end of the string.
1473 * \pre `pos <= size()`
1474 * \pre `count <= size() - pos || count == npos`
1475 * \post `size() == old_size - min(count, old_size - pos)`
1476 * \post `at(size()) == Char(0)`
1478 * \throw std::out_of_range when pos > size().
1480 FOLLY_CPP14_CONSTEXPR BasicFixedString& erase(
1482 std::size_t count = npos) noexcept(false) {
1483 using A = const Char[1];
1486 detail::fixedstring::checkOverflowOrNpos(
1487 count, size_ - detail::fixedstring::checkOverflow(pos, size_)),
1493 * \note Equivalent to `erase(first - data(), 1)`
1494 * \return A pointer to the first character after the erased character.
1496 FOLLY_CPP14_CONSTEXPR Char* erase(const Char* first) noexcept(false) {
1497 erase(first - data_, 1u);
1498 return data_ + (first - data_);
1502 * \note Equivalent to `erase(first - data(), last - first)`
1503 * \return A pointer to the first character after the erased characters.
1505 FOLLY_CPP14_CONSTEXPR Char* erase(
1507 const Char* last) noexcept(false) {
1508 erase(first - data_, last - first);
1509 return data_ + (first - data_);
1512 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1513 * Create a new string by erasing all the characters from this string.
1514 * \note Equivalent to `BasicFixedString<Char, 0>{}`
1516 constexpr BasicFixedString<Char, 0u> cerase() const noexcept {
1521 * Create a new string by erasing all the characters after position `pos` from
1523 * \note Equivalent to `creplace(pos, min(count, pos - size()), "")`
1525 constexpr BasicFixedString cerase(std::size_t pos, std::size_t count = npos)
1526 const noexcept(false) {
1527 using A = const Char[1];
1530 detail::fixedstring::checkOverflowOrNpos(
1531 count, size_ - detail::fixedstring::checkOverflow(pos, size_)),
1535 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1536 * Compare two strings for lexicographical ordering.
1537 * \note Equivalent to
1538 * `compare(0, size(), that.data(), that.size())`
1540 template <std::size_t M>
1541 constexpr int compare(const BasicFixedString<Char, M>& that) const noexcept {
1542 return compare(0u, size_, that, 0u, that.size_);
1546 * Compare two strings for lexicographical ordering.
1547 * \note Equivalent to
1548 * `compare(this_pos, this_count, that.data(), that.size())`
1550 template <std::size_t M>
1551 constexpr int compare(
1552 std::size_t this_pos,
1553 std::size_t this_count,
1554 const BasicFixedString<Char, M>& that) const noexcept(false) {
1555 return compare(this_pos, this_count, that, 0u, that.size_);
1559 * Compare two strings for lexicographical ordering.
1560 * \note Equivalent to
1561 * `compare(this_pos, this_count, that.data() + that_pos, that_count)`
1563 template <std::size_t M>
1564 constexpr int compare(
1565 std::size_t this_pos,
1566 std::size_t this_count,
1567 const BasicFixedString<Char, M>& that,
1568 std::size_t that_pos,
1569 std::size_t that_count) const noexcept(false) {
1570 return static_cast<int>(detail::fixedstring::compare_(
1572 detail::fixedstring::checkOverflow(this_pos, size_),
1573 detail::fixedstring::checkOverflow(this_count, size_ - this_pos) +
1576 detail::fixedstring::checkOverflow(that_pos, that.size_),
1577 detail::fixedstring::checkOverflow(that_count, that.size_ - that_pos) +
1582 * Compare two strings for lexicographical ordering.
1583 * \note Equivalent to `compare(0, size(), that, strlen(that))`
1585 constexpr int compare(const Char* that) const noexcept {
1586 return compare(0u, size_, that, folly::constexpr_strlen(that));
1592 constexpr int compare(Range<const Char*> that) const noexcept {
1593 return compare(0u, size_, that.begin(), that.size());
1597 * Compare two strings for lexicographical ordering.
1598 * \note Equivalent to
1599 * `compare(this_pos, this_count, that, strlen(that))`
1601 constexpr int compare(
1602 std::size_t this_pos,
1603 std::size_t this_count,
1604 const Char* that) const noexcept(false) {
1605 return compare(this_pos, this_count, that, folly::constexpr_strlen(that));
1611 constexpr int compare(
1612 std::size_t this_pos,
1613 std::size_t this_count,
1614 Range<const Char*> that) const noexcept(false) {
1615 return compare(this_pos, this_count, that.begin(), that.size());
1619 * Compare two strings for lexicographical ordering.
1621 * Let `A` be the the
1622 * character sequence {`(*this)[this_pos]`, ...
1623 * `(*this)[this_pos + this_count - 1]`}. Let `B` be the character sequence
1624 * {`that[0]`, ...`that[count - 1]`}. Then...
1627 * - `< 0` if `A` is ordered before the `B`
1628 * - `> 0` if `B` is ordered before `A`
1629 * - `0` if `A` equals `B`.
1631 * \throw std::out_of_range if this_pos + this_count > size().
1633 constexpr int compare(
1634 std::size_t this_pos,
1635 std::size_t this_count,
1637 std::size_t that_count) const noexcept(false) {
1638 return static_cast<int>(detail::fixedstring::compare_(
1640 detail::fixedstring::checkOverflow(this_pos, size_),
1641 detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos) +
1648 constexpr int compare(
1649 std::size_t this_pos,
1650 std::size_t this_count,
1651 Range<const Char*> that,
1652 std::size_t that_count) const noexcept(false) {
1657 detail::fixedstring::checkOverflow(that_count, that.size()));
1660 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1661 * Return a substring from `pos` to the end of the string.
1662 * \note Equivalent to `BasicFixedString{*this, pos}`
1664 constexpr BasicFixedString substr(std::size_t pos) const noexcept(false) {
1665 return {*this, pos};
1669 * Return a substring from `pos` to the end of the string.
1670 * \note Equivalent to `BasicFixedString{*this, pos, count}`
1672 constexpr BasicFixedString substr(std::size_t pos, std::size_t count) const
1674 return {*this, pos, count};
1677 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1678 * Replace the characters in the range denoted by the half-open range
1679 * [`first`, `last`) with the string `that`.
1680 * \pre `first` and `last` point to characters within this string (including
1681 * the terminating null).
1682 * \note Equivalent to
1683 * `replace(first - data(), last - first, that.data(), that.size())`
1685 template <std::size_t M>
1686 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1689 const BasicFixedString<Char, M>& that) noexcept(false) {
1690 return replace(first - data_, last - first, that, 0u, that.size_);
1694 * Replace `this_count` characters starting from position `this_pos` with the
1695 * characters from string `that` starting at position `that_pos`.
1696 * \pre `that_pos <= that.size()`
1697 * \note Equivalent to
1698 * <tt>replace(this_pos, this_count, that.data() + that_pos,
1699 * that.size() - that_pos)</tt>
1701 template <std::size_t M>
1702 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1703 std::size_t this_pos,
1704 std::size_t this_count,
1705 const BasicFixedString<Char, M>& that,
1706 std::size_t that_pos = 0u) noexcept(false) {
1707 return replace(this_pos, this_count, that, that_pos, that.size_ - that_pos);
1711 * Replace `this_count` characters starting from position `this_pos` with
1712 * `that_count` characters from string `that` starting at position
1714 * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos`
1715 * \note Equivalent to
1716 * `replace(this_pos, this_count, that.data() + that_pos, that_count)`
1718 template <std::size_t M>
1719 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1720 std::size_t this_pos,
1721 std::size_t this_count,
1722 const BasicFixedString<Char, M>& that,
1723 std::size_t that_pos,
1724 std::size_t that_count) noexcept(false) {
1725 return *this = creplace(this_pos, this_count, that, that_pos, that_count);
1729 * Replace `this_count` characters starting from position `this_pos` with
1730 * the characters from the string literal `that`.
1731 * \note Equivalent to
1732 * `replace(this_pos, this_count, that, strlen(that))`
1734 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1735 std::size_t this_pos,
1736 std::size_t this_count,
1737 const Char* that) noexcept(false) {
1738 return replace(this_pos, this_count, that, folly::constexpr_strlen(that));
1742 * Replace the characters denoted by the half-open range [`first`,`last`) with
1743 * the characters from the string literal `that`.
1744 * \pre `first` and `last` point to characters within this string (including
1745 * the terminating null).
1746 * \note Equivalent to
1747 * `replace(first - data(), last - first, that, strlen(that))`
1749 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1752 const Char* that) noexcept(false) {
1754 first - data_, last - first, that, folly::constexpr_strlen(that));
1758 * Replace `this_count` characters starting from position `this_pos` with
1759 * `that_count` characters from the character sequence pointed to by `that`.
1760 * \param this_pos The starting offset within `*this` of the first character
1762 * \param this_count The number of characters to be replaced. If `npos`,
1763 * it is treated as if `this_count` were `size() - this_pos`.
1764 * \param that A pointer to the replacement string.
1765 * \param that_count The number of characters in the replacement string.
1766 * \pre `this_pos <= size() && this_count <= size() - this_pos`
1767 * \pre `that` points to a contiguous sequence of at least `that_count`
1769 * \throw std::out_of_range on any of the following conditions:
1770 * - `this_pos > size()`
1771 * - `this_count > size() - this_pos`
1772 * - `size() - this_count + that_count > N`
1774 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1775 std::size_t this_pos,
1776 std::size_t this_count,
1778 std::size_t that_count) noexcept(false) {
1779 return *this = detail::fixedstring::Helper::replace_<Char>(
1782 detail::fixedstring::checkOverflow(this_pos, size_),
1783 detail::fixedstring::checkOverflowOrNpos(
1784 this_count, size_ - this_pos),
1792 * Replace `this_count` characters starting from position `this_pos` with
1793 * `that_count` characters `ch`.
1794 * \note Equivalent to
1795 * `replace(this_pos, this_count, BasicFixedString{that_count, ch})`
1797 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1798 std::size_t this_pos,
1799 std::size_t this_count,
1800 std::size_t that_count,
1801 Char ch) noexcept(false) {
1802 return replace(this_pos, this_count, BasicFixedString{that_count, ch});
1806 * Replace the characters denoted by the half-open range [`first`,`last`)
1807 * with `that_count` characters `ch`.
1808 * \note Equivalent to
1809 * `replace(first - data(), last - first, BasicFixedString{that_count, ch})`
1811 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1814 std::size_t that_count,
1815 Char ch) noexcept(false) {
1817 first - data_, last - first, BasicFixedString{that_count, ch});
1821 * Replace the characters denoted by the half-open range [`first`,`last`) with
1822 * the characters from the string literal `that`.
1823 * \pre `first` and `last` point to characters within this string (including
1824 * the terminating null).
1825 * \note Equivalent to
1826 * `replace(this_pos, this_count, il.begin(), il.size())`
1828 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1831 std::initializer_list<Char> il) noexcept(false) {
1832 return replace(first - data_, last - first, il.begin(), il.size());
1835 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1836 * Construct a new string by replacing `this_count` characters starting from
1837 * position `this_pos` within this string with the characters from string
1838 * `that` starting at position `that_pos`.
1839 * \pre `that_pos <= that.size()`
1840 * \note Equivalent to
1841 * <tt>creplace(this_pos, this_count, that, that_pos,
1842 * that.size() - that_pos)</tt>
1844 template <std::size_t M>
1845 constexpr BasicFixedString<Char, N + M> creplace(
1846 std::size_t this_pos,
1847 std::size_t this_count,
1848 const BasicFixedString<Char, M>& that,
1849 std::size_t that_pos = 0u) const noexcept(false) {
1855 that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_));
1859 * Construct a new string by replacing `this_count` characters starting from
1860 * position `this_pos` within this string with `that_count` characters from
1861 * string `that` starting at position `that_pos`.
1862 * \param this_pos The starting offset within `*this` of the first character
1864 * \param this_count The number of characters to be replaced. If `npos`,
1865 * it is treated as if `this_count` were `size() - this_pos`.
1866 * \param that A string that contains the replacement string.
1867 * \param that_pos The offset to the first character in the replacement
1869 * \param that_count The number of characters in the replacement string.
1870 * \pre `this_pos <= size() && this_count <= size() - this_pos`
1871 * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos`
1872 * \post The size of the returned string is `size() - this_count + that_count`
1873 * \note Equivalent to <tt>BasicFixedString<Char, N + M>{substr(0, this_pos) +
1874 * that.substr(that_pos, that_count) + substr(this_pos + this_count)}</tt>
1875 * \throw std::out_of_range on any of the following conditions:
1876 * - `this_pos > size()`
1877 * - `this_count > size() - this_pos`
1878 * - `that_pos > that.size()`
1879 * - `that_count > that.size() - that_pos`
1881 template <std::size_t M>
1882 constexpr BasicFixedString<Char, N + M> creplace(
1883 std::size_t this_pos,
1884 std::size_t this_count,
1885 const BasicFixedString<Char, M>& that,
1886 std::size_t that_pos,
1887 std::size_t that_count) const noexcept(false) {
1888 return detail::fixedstring::Helper::replace_<Char>(
1891 detail::fixedstring::checkOverflow(this_pos, size_),
1892 detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
1894 detail::fixedstring::checkOverflow(that_pos, that.size_),
1895 detail::fixedstring::checkOverflowOrNpos(
1896 that_count, that.size_ - that_pos),
1897 folly::make_index_sequence<N + M>{});
1901 * Construct a new string by replacing the characters denoted by the half-open
1902 * range [`first`,`last`) within this string with the characters from string
1903 * `that` starting at position `that_pos`.
1904 * \pre `that_pos <= that.size()`
1905 * \note Equivalent to
1906 * <tt>creplace(first - data(), last - first, that, that_pos,
1907 * that.size() - that_pos)</tt>
1909 template <std::size_t M>
1910 constexpr BasicFixedString<Char, N + M> creplace(
1913 const BasicFixedString<Char, M>& that,
1914 std::size_t that_pos = 0u) const noexcept(false) {
1920 that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_));
1924 * Construct a new string by replacing the characters denoted by the half-open
1925 * range [`first`,`last`) within this string with the `that_count`
1926 * characters from string `that` starting at position `that_pos`.
1927 * \note Equivalent to
1928 * <tt>creplace(first - data(), last - first, that, that_pos,
1931 template <std::size_t M>
1932 constexpr BasicFixedString<Char, N + M> creplace(
1935 const BasicFixedString<Char, M>& that,
1936 std::size_t that_pos,
1937 std::size_t that_count) const noexcept(false) {
1938 return creplace(first - data_, last - first, that, that_pos, that_count);
1942 * Construct a new string by replacing `this_count` characters starting from
1943 * position `this_pos` within this string with `M-1` characters from
1944 * character array `that`.
1945 * \pre `strlen(that) == M-1`
1946 * \note Equivalent to
1947 * <tt>creplace(this_pos, this_count, that, 0, M - 1)</tt>
1949 template <std::size_t M>
1950 constexpr BasicFixedString<Char, N + M - 1u> creplace(
1951 std::size_t this_pos,
1952 std::size_t this_count,
1953 const Char (&that)[M]) const noexcept(false) {
1954 return creplace(this_pos, this_count, that, 0u, M - 1u);
1958 * Replace `this_count` characters starting from position `this_pos` with
1959 * `that_count` characters from the character array `that` starting at
1960 * position `that_pos`.
1961 * \param this_pos The starting offset within `*this` of the first character
1963 * \param this_count The number of characters to be replaced. If `npos`,
1964 * it is treated as if `this_count` were `size() - this_pos`.
1965 * \param that An array of characters containing the replacement string.
1966 * \param that_pos The starting offset of the replacement string.
1967 * \param that_count The number of characters in the replacement string. If
1968 * `npos`, it is treated as if `that_count` were `M - 1 - that_pos`
1969 * \pre `this_pos <= size() && this_count <= size() - this_pos`
1970 * \pre `that_pos <= M - 1 && that_count <= M - 1 - that_pos`
1971 * \post The size of the returned string is `size() - this_count + that_count`
1972 * \note Equivalent to <tt>BasicFixedString<Char, N + M - 1>{
1973 * substr(0, this_pos) +
1974 * makeFixedString(that).substr(that_pos, that_count) +
1975 * substr(this_pos + this_count)}</tt>
1976 * \throw std::out_of_range on any of the following conditions:
1977 * - `this_pos > size()`
1978 * - `this_count > size() - this_pos`
1980 * - `that_count >= M - that_pos`
1982 template <std::size_t M>
1983 constexpr BasicFixedString<Char, N + M - 1u> creplace(
1984 std::size_t this_pos,
1985 std::size_t this_count,
1986 const Char (&that)[M],
1987 std::size_t that_pos,
1988 std::size_t that_count) const noexcept(false) {
1989 return detail::fixedstring::Helper::replace_<Char>(
1992 detail::fixedstring::checkOverflow(this_pos, size_),
1993 detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
1994 detail::fixedstring::checkNullTerminated(that),
1995 detail::fixedstring::checkOverflow(that_pos, M - 1u),
1996 detail::fixedstring::checkOverflowOrNpos(that_count, M - 1u - that_pos),
1997 folly::make_index_sequence<N + M - 1u>{});
2001 * Construct a new string by replacing the characters denoted by the half-open
2002 * range [`first`,`last`) within this string with the first `M-1`
2003 * characters from the character array `that`.
2004 * \pre `strlen(that) == M-1`
2005 * \note Equivalent to
2006 * <tt>creplace(first - data(), last - first, that, 0, M-1)</tt>
2008 template <std::size_t M>
2009 constexpr BasicFixedString<Char, N + M - 1u>
2010 creplace(const Char* first, const Char* last, const Char (&that)[M]) const
2012 return creplace(first - data_, last - first, that, 0u, M - 1u);
2016 * Construct a new string by replacing the characters denoted by the half-open
2017 * range [`first`,`last`) within this string with the `that_count`
2018 * characters from the character array `that` starting at position
2020 * \pre `strlen(that) == M-1`
2021 * \note Equivalent to
2022 * `creplace(first - data(), last - first, that, that_pos, that_count)`
2024 template <std::size_t M>
2025 constexpr BasicFixedString<Char, N + M - 1u> creplace(
2028 const Char (&that)[M],
2029 std::size_t that_pos,
2030 std::size_t that_count) const noexcept(false) {
2031 return creplace(first - data_, last - first, that, that_pos, that_count);
2034 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2035 * Copies `min(count, size())` characters starting from offset `0`
2036 * from this string into the buffer pointed to by `dest`.
2037 * \return The number of characters copied.
2039 FOLLY_CPP14_CONSTEXPR std::size_t copy(Char* dest, std::size_t count) const
2041 return copy(dest, count, 0u);
2045 * Copies `min(count, size() - pos)` characters starting from offset `pos`
2046 * from this string into the buffer pointed to by `dest`.
2047 * \pre `pos <= size()`
2048 * \return The number of characters copied.
2049 * \throw std::out_of_range if `pos > size()`
2051 FOLLY_CPP14_CONSTEXPR std::size_t
2052 copy(Char* dest, std::size_t count, std::size_t pos) const noexcept(false) {
2053 detail::fixedstring::checkOverflow(pos, size_);
2054 for (std::size_t i = 0u; i < count; ++i) {
2055 if (i + pos == size_)
2057 dest[i] = data_[i + pos];
2062 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2063 * Resizes the current string.
2064 * \note Equivalent to `resize(count, Char(0))`
2066 FOLLY_CPP14_CONSTEXPR void resize(std::size_t count) noexcept(false) {
2067 resize(count, Char(0));
2071 * Resizes the current string by setting the size to `count` and setting
2072 * `data()[count]` to `Char(0)`. If `count > old_size`, the characters
2073 * in the range [`old_size`,`count`) are set to `ch`.
2075 FOLLY_CPP14_CONSTEXPR void resize(std::size_t count, Char ch) noexcept(
2077 detail::fixedstring::checkOverflow(count, N);
2078 if (count == size_) {
2079 } else if (count < size_) {
2081 data_[size_] = Char(0);
2083 for (; size_ < count; ++size_) {
2086 data_[size_] = Char(0);
2090 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2091 * Finds the first occurrence of the character sequence `that` in this string.
2092 * \note Equivalent to `find(that.data(), 0, that.size())`
2094 template <std::size_t M>
2095 constexpr std::size_t find(const BasicFixedString<Char, M>& that) const
2097 return find(that, 0u);
2101 * Finds the first occurrence of the character sequence `that` in this string,
2102 * starting at offset `pos`.
2103 * \pre `pos <= size()`
2104 * \note Equivalent to `find(that.data(), pos, that.size())`
2106 template <std::size_t M>
2107 constexpr std::size_t find(
2108 const BasicFixedString<Char, M>& that,
2109 std::size_t pos) const noexcept(false) {
2110 return that.size_ <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2111 ? detail::fixedstring::find_(data_, size_, that.data_, pos, that.size_)
2116 * Finds the first occurrence of the character sequence `that` in this string.
2117 * \note Equivalent to `find(that.data(), 0, strlen(that))`
2119 constexpr std::size_t find(const Char* that) const noexcept {
2120 return find(that, 0u, folly::constexpr_strlen(that));
2124 * Finds the first occurrence of the character sequence `that` in this string,
2125 * starting at offset `pos`.
2126 * \pre `pos <= size()`
2127 * \note Equivalent to `find(that.data(), pos, strlen(that))`
2129 constexpr std::size_t find(const Char* that, std::size_t pos) const
2131 return find(that, pos, folly::constexpr_strlen(that));
2135 * Finds the first occurrence of the first `count` characters in the buffer
2136 * pointed to by `that` in this string, starting at offset `pos`.
2137 * \pre `pos <= size()`
2138 * \pre `that` points to a buffer containing at least `count` contiguous
2140 * \return The lowest offset `i` such that `i >= pos` and
2141 * `0 == strncmp(data() + i, that, count)`; or `npos` if there is no such
2143 * \throw std::out_of_range when `pos > size()`
2145 constexpr std::size_t find(
2148 std::size_t count) const noexcept(false) {
2149 return count <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2150 ? detail::fixedstring::find_(data_, size_, that, pos, count)
2155 * Finds the first occurrence of the character `ch` in this string.
2156 * \note Equivalent to `find(&ch, 0, 1)`
2158 constexpr std::size_t find(Char ch) const noexcept {
2159 return find(ch, 0u);
2163 * Finds the first occurrence of the character character `c` in this string,
2164 * starting at offset `pos`.
2165 * \pre `pos <= size()`
2166 * \note Equivalent to `find(&ch, pos, 1)`
2168 constexpr std::size_t find(Char ch, std::size_t pos) const noexcept(false) {
2169 using A = const Char[1u];
2170 return 0u == size_ - detail::fixedstring::checkOverflow(pos, size_)
2172 : detail::fixedstring::find_(data_, size_, A{ch}, pos, 1u);
2175 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2176 * Finds the last occurrence of characters in the string
2177 * `that` in this string.
2178 * \note Equivalent to `rfind(that.data(), size(), that.size())`
2180 template <std::size_t M>
2181 constexpr std::size_t rfind(const BasicFixedString<Char, M>& that) const
2183 return rfind(that, size_);
2187 * Finds the last occurrence of characters in the string
2188 * `that` in this string, starting at offset `pos`.
2189 * \note Equivalent to `rfind(that.data(), pos, that.size())`
2191 template <std::size_t M>
2192 constexpr std::size_t rfind(
2193 const BasicFixedString<Char, M>& that,
2194 std::size_t pos) const noexcept(false) {
2195 return that.size_ <= size_
2196 ? detail::fixedstring::rfind_(
2199 folly::constexpr_min(
2200 detail::fixedstring::checkOverflow(pos, size_),
2201 size_ - that.size_),
2207 * Finds the last occurrence of characters in the buffer
2208 * pointed to by `that` in this string.
2209 * \note Equivalent to `rfind(that, size(), strlen(that))`
2211 constexpr std::size_t rfind(const Char* that) const noexcept {
2212 return rfind(that, size_, folly::constexpr_strlen(that));
2216 * Finds the last occurrence of characters in the buffer
2217 * pointed to by `that` in this string, starting at offset `pos`.
2218 * \note Equivalent to `rfind(that, pos, strlen(that))`
2220 constexpr std::size_t rfind(const Char* that, std::size_t pos) const
2222 return rfind(that, pos, folly::constexpr_strlen(that));
2226 * Finds the last occurrence of the first `count` characters in the buffer
2227 * pointed to by `that` in this string, starting at offset `pos`.
2228 * \pre `pos <= size()`
2229 * \pre `that` points to a buffer containing at least `count` contiguous
2231 * \return The largest offset `i` such that `i <= pos` and
2232 * `i + count <= size()` and `0 == strncmp(data() + i, that, count)`; or
2233 * `npos` if there is no such offset `i`.
2234 * \throw std::out_of_range when `pos > size()`
2236 constexpr std::size_t rfind(
2239 std::size_t count) const noexcept(false) {
2240 return count <= size_
2241 ? detail::fixedstring::rfind_(
2244 folly::constexpr_min(
2245 detail::fixedstring::checkOverflow(pos, size_),
2252 * Finds the last occurrence of the character character `ch` in this string.
2253 * \note Equivalent to `rfind(&ch, size(), 1)`
2255 constexpr std::size_t rfind(Char ch) const noexcept {
2256 return rfind(ch, size_);
2260 * Finds the last occurrence of the character character `ch` in this string,
2261 * starting at offset `pos`.
2262 * \pre `pos <= size()`
2263 * \note Equivalent to `rfind(&ch, pos, 1)`
2265 constexpr std::size_t rfind(Char ch, std::size_t pos) const noexcept(false) {
2266 using A = const Char[1u];
2269 : detail::fixedstring::rfind_(
2272 folly::constexpr_min(
2273 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2277 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2278 * Finds the first occurrence of any character in `that` in this string.
2279 * \note Equivalent to `find_first_of(that.data(), 0, that.size())`
2281 template <std::size_t M>
2282 constexpr std::size_t find_first_of(
2283 const BasicFixedString<Char, M>& that) const noexcept {
2284 return find_first_of(that, 0u);
2288 * Finds the first occurrence of any character in `that` in this string,
2289 * starting at offset `pos`
2290 * \note Equivalent to `find_first_of(that.data(), pos, that.size())`
2292 template <std::size_t M>
2293 constexpr std::size_t find_first_of(
2294 const BasicFixedString<Char, M>& that,
2295 std::size_t pos) const noexcept(false) {
2296 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2298 : detail::fixedstring::find_first_of_(
2299 data_, size_, that.data_, pos, that.size_);
2303 * Finds the first occurrence of any character in the null-terminated
2304 * character sequence pointed to by `that` in this string.
2305 * \note Equivalent to `find_first_of(that, 0, strlen(that))`
2307 constexpr std::size_t find_first_of(const Char* that) const noexcept {
2308 return find_first_of(that, 0u, folly::constexpr_strlen(that));
2312 * Finds the first occurrence of any character in the null-terminated
2313 * character sequence pointed to by `that` in this string,
2314 * starting at offset `pos`
2315 * \note Equivalent to `find_first_of(that, pos, strlen(that))`
2317 constexpr std::size_t find_first_of(const Char* that, std::size_t pos) const
2319 return find_first_of(that, pos, folly::constexpr_strlen(that));
2323 * Finds the first occurrence of any character in the first `count` characters
2324 * in the buffer pointed to by `that` in this string, starting at offset
2326 * \pre `pos <= size()`
2327 * \pre `that` points to a buffer containing at least `count` contiguous
2329 * \return The smallest offset `i` such that `i >= pos` and
2330 * `std::find(that, that+count, at(i)) != that+count`; or
2331 * `npos` if there is no such offset `i`.
2332 * \throw std::out_of_range when `pos > size()`
2334 constexpr std::size_t find_first_of(
2337 std::size_t count) const noexcept(false) {
2338 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2340 : detail::fixedstring::find_first_of_(data_, size_, that, pos, count);
2344 * Finds the first occurrence of `ch` in this string.
2345 * \note Equivalent to `find_first_of(&ch, 0, 1)`
2347 constexpr std::size_t find_first_of(Char ch) const noexcept {
2348 return find_first_of(ch, 0u);
2352 * Finds the first occurrence of `ch` in this string,
2353 * starting at offset `pos`.
2354 * \note Equivalent to `find_first_of(&ch, pos, 1)`
2356 constexpr std::size_t find_first_of(Char ch, std::size_t pos) const
2358 using A = const Char[1u];
2359 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2361 : detail::fixedstring::find_first_of_(data_, size_, A{ch}, pos, 1u);
2364 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2365 * Finds the first occurrence of any character not in `that` in this string.
2366 * \note Equivalent to `find_first_not_of(that.data(), 0, that.size())`
2368 template <std::size_t M>
2369 constexpr std::size_t find_first_not_of(
2370 const BasicFixedString<Char, M>& that) const noexcept {
2371 return find_first_not_of(that, 0u);
2374 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2375 * Finds the first occurrence of any character not in `that` in this string.
2376 * \note Equivalent to `find_first_not_of(that.data(), 0, that.size())`
2378 template <std::size_t M>
2379 constexpr std::size_t find_first_not_of(
2380 const BasicFixedString<Char, M>& that,
2381 std::size_t pos) const noexcept(false) {
2382 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2384 : detail::fixedstring::find_first_not_of_(
2385 data_, size_, that.data_, pos, that.size_);
2389 * Finds the first occurrence of any character not in the null-terminated
2390 * character sequence pointed to by `that` in this string.
2391 * \note Equivalent to `find_first_not_of(that, 0, strlen(that))`
2393 constexpr std::size_t find_first_not_of(const Char* that) const noexcept {
2394 return find_first_not_of(that, 0u, folly::constexpr_strlen(that));
2398 * Finds the first occurrence of any character not in the null-terminated
2399 * character sequence pointed to by `that` in this string,
2400 * starting at offset `pos`
2401 * \note Equivalent to `find_first_not_of(that, pos, strlen(that))`
2403 constexpr std::size_t find_first_not_of(const Char* that, std::size_t pos)
2404 const noexcept(false) {
2405 return find_first_not_of(that, pos, folly::constexpr_strlen(that));
2409 * Finds the first occurrence of any character not in the first `count`
2410 * characters in the buffer pointed to by `that` in this string, starting at
2412 * \pre `pos <= size()`
2413 * \pre `that` points to a buffer containing at least `count` contiguous
2415 * \return The smallest offset `i` such that `i >= pos` and
2416 * `std::find(that, that+count, at(i)) == that+count`; or
2417 * `npos` if there is no such offset `i`.
2418 * \throw std::out_of_range when `pos > size()`
2420 constexpr std::size_t find_first_not_of(
2423 std::size_t count) const noexcept(false) {
2424 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2426 : detail::fixedstring::find_first_not_of_(
2427 data_, size_, that, pos, count);
2431 * Finds the first occurrence of any character other than `ch` in this string.
2432 * \note Equivalent to `find_first_not_of(&ch, 0, 1)`
2434 constexpr std::size_t find_first_not_of(Char ch) const noexcept {
2435 return find_first_not_of(ch, 0u);
2439 * Finds the first occurrence of any character other than `ch` in this string,
2440 * starting at offset `pos`.
2441 * \note Equivalent to `find_first_not_of(&ch, pos, 1)`
2443 constexpr std::size_t find_first_not_of(Char ch, std::size_t pos) const
2445 using A = const Char[1u];
2446 return 1u <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2447 ? detail::fixedstring::find_first_not_of_(data_, size_, A{ch}, pos, 1u)
2451 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2452 * Finds the last occurrence of any character in `that` in this string.
2453 * \note Equivalent to `find_last_of(that.data(), size(), that.size())`
2455 template <std::size_t M>
2456 constexpr std::size_t find_last_of(
2457 const BasicFixedString<Char, M>& that) const noexcept {
2458 return find_last_of(that, size_);
2462 * Finds the last occurrence of any character in `that` in this string,
2463 * starting at offset `pos`
2464 * \note Equivalent to `find_last_of(that.data(), pos, that.size())`
2466 template <std::size_t M>
2467 constexpr std::size_t find_last_of(
2468 const BasicFixedString<Char, M>& that,
2469 std::size_t pos) const noexcept(false) {
2472 : detail::fixedstring::find_last_of_(
2475 folly::constexpr_min(
2476 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2481 * Finds the last occurrence of any character in the null-terminated
2482 * character sequence pointed to by `that` in this string.
2483 * \note Equivalent to `find_last_of(that, size(), strlen(that))`
2485 constexpr std::size_t find_last_of(const Char* that) const noexcept {
2486 return find_last_of(that, size_, folly::constexpr_strlen(that));
2490 * Finds the last occurrence of any character in the null-terminated
2491 * character sequence pointed to by `that` in this string,
2492 * starting at offset `pos`
2493 * \note Equivalent to `find_last_of(that, pos, strlen(that))`
2495 constexpr std::size_t find_last_of(const Char* that, std::size_t pos) const
2497 return find_last_of(that, pos, folly::constexpr_strlen(that));
2501 * Finds the last occurrence of any character in the first `count` characters
2502 * in the buffer pointed to by `that` in this string, starting at offset
2504 * \pre `pos <= size()`
2505 * \pre `that` points to a buffer containing at least `count` contiguous
2507 * \return The largest offset `i` such that `i <= pos` and
2508 * `i < size()` and `std::find(that, that+count, at(i)) != that+count`; or
2509 * `npos` if there is no such offset `i`.
2510 * \throw std::out_of_range when `pos > size()`
2512 constexpr std::size_t find_last_of(
2515 std::size_t count) const noexcept(false) {
2518 : detail::fixedstring::find_last_of_(
2521 folly::constexpr_min(
2522 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2527 * Finds the last occurrence of `ch` in this string.
2528 * \note Equivalent to `find_last_of(&ch, size(), 1)`
2530 constexpr std::size_t find_last_of(Char ch) const noexcept {
2531 return find_last_of(ch, size_);
2535 * Finds the last occurrence of `ch` in this string,
2536 * starting at offset `pos`.
2537 * \note Equivalent to `find_last_of(&ch, pos, 1)`
2539 constexpr std::size_t find_last_of(Char ch, std::size_t pos) const
2541 using A = const Char[1u];
2544 : detail::fixedstring::find_last_of_(
2547 folly::constexpr_min(
2548 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2552 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2553 * Finds the last occurrence of any character not in `that` in this string.
2554 * \note Equivalent to `find_last_not_of(that.data(), size(), that.size())`
2556 template <std::size_t M>
2557 constexpr std::size_t find_last_not_of(
2558 const BasicFixedString<Char, M>& that) const noexcept {
2559 return find_last_not_of(that, size_);
2563 * Finds the last occurrence of any character not in `that` in this string,
2564 * starting at offset `pos`
2565 * \note Equivalent to `find_last_not_of(that.data(), pos, that.size())`
2567 template <std::size_t M>
2568 constexpr std::size_t find_last_not_of(
2569 const BasicFixedString<Char, M>& that,
2570 std::size_t pos) const noexcept(false) {
2573 : detail::fixedstring::find_last_not_of_(
2576 folly::constexpr_min(
2577 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2582 * Finds the last occurrence of any character not in the null-terminated
2583 * character sequence pointed to by `that` in this string.
2584 * \note Equivalent to `find_last_not_of(that, size(), strlen(that))`
2586 constexpr std::size_t find_last_not_of(const Char* that) const noexcept {
2587 return find_last_not_of(that, size_, folly::constexpr_strlen(that));
2591 * Finds the last occurrence of any character not in the null-terminated
2592 * character sequence pointed to by `that` in this string,
2593 * starting at offset `pos`
2594 * \note Equivalent to `find_last_not_of(that, pos, strlen(that))`
2596 constexpr std::size_t find_last_not_of(const Char* that, std::size_t pos)
2597 const noexcept(false) {
2598 return find_last_not_of(that, pos, folly::constexpr_strlen(that));
2602 * Finds the last occurrence of any character not in the first `count`
2603 * characters in the buffer pointed to by `that` in this string, starting at
2605 * \pre `pos <= size()`
2606 * \pre `that` points to a buffer containing at least `count` contiguous
2608 * \return The largest offset `i` such that `i <= pos` and
2609 * `i < size()` and `std::find(that, that+count, at(i)) == that+count`; or
2610 * `npos` if there is no such offset `i`.
2611 * \throw std::out_of_range when `pos > size()`
2613 constexpr std::size_t find_last_not_of(
2616 std::size_t count) const noexcept(false) {
2619 : detail::fixedstring::find_last_not_of_(
2622 folly::constexpr_min(
2623 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2628 * Finds the last occurrence of any character other than `ch` in this string.
2629 * \note Equivalent to `find_last_not_of(&ch, size(), 1)`
2631 constexpr std::size_t find_last_not_of(Char ch) const noexcept {
2632 return find_last_not_of(ch, size_);
2636 * Finds the last occurrence of any character other than `ch` in this string,
2637 * starting at offset `pos`.
2638 * \note Equivalent to `find_last_not_of(&ch, pos, 1)`
2640 constexpr std::size_t find_last_not_of(Char ch, std::size_t pos) const
2642 using A = const Char[1u];
2645 : detail::fixedstring::find_last_not_of_(
2648 folly::constexpr_min(
2649 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2653 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2654 * Asymmetric relational operators
2656 friend constexpr bool operator==(
2658 const BasicFixedString& b) noexcept {
2659 return detail::fixedstring::equal_(
2660 a, folly::constexpr_strlen(a), b.data_, b.size_);
2666 friend constexpr bool operator==(
2667 const BasicFixedString& a,
2668 const Char* b) noexcept {
2675 friend constexpr bool operator==(
2676 Range<const Char*> a,
2677 const BasicFixedString& b) noexcept {
2678 return detail::fixedstring::equal_(a.begin(), a.size(), b.data_, b.size_);
2684 friend constexpr bool operator==(
2685 const BasicFixedString& a,
2686 Range<const Char*> b) noexcept {
2690 friend constexpr bool operator!=(
2692 const BasicFixedString& b) noexcept {
2699 friend constexpr bool operator!=(
2700 const BasicFixedString& a,
2701 const Char* b) noexcept {
2708 friend constexpr bool operator!=(
2709 Range<const Char*> a,
2710 const BasicFixedString& b) noexcept {
2717 friend constexpr bool operator!=(
2718 const BasicFixedString& a,
2719 Range<const Char*> b) noexcept {
2723 friend constexpr bool operator<(
2725 const BasicFixedString& b) noexcept {
2726 return detail::fixedstring::Cmp::LT ==
2727 detail::fixedstring::compare_(
2728 a, 0u, folly::constexpr_strlen(a), b.data_, 0u, b.size_);
2734 friend constexpr bool operator<(
2735 const BasicFixedString& a,
2736 const Char* b) noexcept {
2737 return detail::fixedstring::Cmp::LT ==
2738 detail::fixedstring::compare_(
2739 a.data_, 0u, a.size_, b, 0u, folly::constexpr_strlen(b));
2745 friend constexpr bool operator<(
2746 Range<const Char*> a,
2747 const BasicFixedString& b) noexcept {
2748 return detail::fixedstring::Cmp::LT ==
2749 detail::fixedstring::compare_(
2750 a.begin(), 0u, a.size(), b.data_, 0u, b.size_);
2756 friend constexpr bool operator<(
2757 const BasicFixedString& a,
2758 Range<const Char*> b) noexcept {
2759 return detail::fixedstring::Cmp::LT ==
2760 detail::fixedstring::compare_(
2761 a.data_, 0u, a.size_, b.begin(), 0u, b.size());
2764 friend constexpr bool operator>(
2766 const BasicFixedString& b) noexcept {
2773 friend constexpr bool operator>(
2774 const BasicFixedString& a,
2775 const Char* b) noexcept {
2782 friend constexpr bool operator>(
2783 Range<const Char*> a,
2784 const BasicFixedString& b) noexcept {
2791 friend constexpr bool operator>(
2792 const BasicFixedString& a,
2793 Range<const Char*> b) noexcept {
2797 friend constexpr bool operator<=(
2799 const BasicFixedString& b) noexcept {
2806 friend constexpr bool operator<=(
2807 const BasicFixedString& a,
2808 const Char* b) noexcept {
2815 friend constexpr bool operator<=(
2816 Range<const Char*> const& a,
2817 const BasicFixedString& b) noexcept {
2824 friend constexpr bool operator<=(
2825 const BasicFixedString& a,
2826 Range<const Char*> b) noexcept {
2830 friend constexpr bool operator>=(
2832 const BasicFixedString& b) noexcept {
2839 friend constexpr bool operator>=(
2840 const BasicFixedString& a,
2841 const Char* b) noexcept {
2848 friend constexpr bool operator>=(
2849 Range<const Char*> a,
2850 const BasicFixedString& b) noexcept {
2857 friend constexpr bool operator>=(
2858 const BasicFixedString& a,
2859 Range<const Char*> const& b) noexcept {
2863 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2864 * Asymmetric concatenation
2866 template <std::size_t M>
2867 friend constexpr BasicFixedString<Char, N + M - 1u> operator+(
2869 const BasicFixedString& b) noexcept {
2870 return detail::fixedstring::Helper::concat_<Char>(
2871 detail::fixedstring::checkNullTerminated(a),
2875 folly::make_index_sequence<N + M - 1u>{});
2881 template <std::size_t M>
2882 friend constexpr BasicFixedString<Char, N + M - 1u> operator+(
2883 const BasicFixedString& a,
2884 const Char (&b)[M]) noexcept {
2885 return detail::fixedstring::Helper::concat_<Char>(
2888 detail::fixedstring::checkNullTerminated(b),
2890 folly::make_index_sequence<N + M - 1u>{});
2896 friend constexpr BasicFixedString<Char, N + 1u> operator+(
2898 const BasicFixedString& b) noexcept {
2899 using A = const Char[2u];
2900 return detail::fixedstring::Helper::concat_<Char>(
2905 folly::make_index_sequence<N + 1u>{});
2911 friend constexpr BasicFixedString<Char, N + 1u> operator+(
2912 const BasicFixedString& a,
2914 using A = const Char[2u];
2915 return detail::fixedstring::Helper::concat_<Char>(
2920 folly::make_index_sequence<N + 1u>{});
2924 template <class C, std::size_t N>
2925 inline std::basic_ostream<C>& operator<<(
2926 std::basic_ostream<C>& os,
2927 const BasicFixedString<C, N>& string) {
2928 using StreamSize = decltype(os.width());
2929 os.write(string.begin(), static_cast<StreamSize>(string.size()));
2933 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2934 * Symmetric relational operators
2936 template <class Char, std::size_t A, std::size_t B>
2937 constexpr bool operator==(
2938 const BasicFixedString<Char, A>& a,
2939 const BasicFixedString<Char, B>& b) noexcept {
2940 return detail::fixedstring::equal_(
2941 detail::fixedstring::Helper::data_(a),
2943 detail::fixedstring::Helper::data_(b),
2947 template <class Char, std::size_t A, std::size_t B>
2948 constexpr bool operator!=(
2949 const BasicFixedString<Char, A>& a,
2950 const BasicFixedString<Char, B>& b) {
2954 template <class Char, std::size_t A, std::size_t B>
2955 constexpr bool operator<(
2956 const BasicFixedString<Char, A>& a,
2957 const BasicFixedString<Char, B>& b) noexcept {
2958 return detail::fixedstring::Cmp::LT ==
2959 detail::fixedstring::compare_(
2960 detail::fixedstring::Helper::data_(a),
2963 detail::fixedstring::Helper::data_(b),
2968 template <class Char, std::size_t A, std::size_t B>
2969 constexpr bool operator>(
2970 const BasicFixedString<Char, A>& a,
2971 const BasicFixedString<Char, B>& b) noexcept {
2975 template <class Char, std::size_t A, std::size_t B>
2976 constexpr bool operator<=(
2977 const BasicFixedString<Char, A>& a,
2978 const BasicFixedString<Char, B>& b) noexcept {
2982 template <class Char, std::size_t A, std::size_t B>
2983 constexpr bool operator>=(
2984 const BasicFixedString<Char, A>& a,
2985 const BasicFixedString<Char, B>& b) noexcept {
2989 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2990 * Symmetric concatenation
2992 template <class Char, std::size_t N, std::size_t M>
2993 constexpr BasicFixedString<Char, N + M> operator+(
2994 const BasicFixedString<Char, N>& a,
2995 const BasicFixedString<Char, M>& b) noexcept {
2996 return detail::fixedstring::Helper::concat_<Char>(
2997 detail::fixedstring::Helper::data_(a),
2999 detail::fixedstring::Helper::data_(b),
3001 folly::make_index_sequence<N + M>{});
3004 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
3005 * Construct a `BasicFixedString` object from a null-terminated array of
3006 * characters. The capacity and size of the string will be equal to one less
3007 * than the size of the array.
3008 * \pre `a` contains no embedded null characters.
3009 * \pre `a[N-1] == Char(0)`
3010 * \post For a returned string `s`, `s[i]==a[i]` for every `i` in [`0`,`N-1`].
3012 template <class Char, std::size_t N>
3013 constexpr BasicFixedString<Char, N - 1u> makeFixedString(
3014 const Char (&a)[N]) noexcept {
3018 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
3021 template <class Char, std::size_t N>
3022 FOLLY_CPP14_CONSTEXPR void swap(
3023 BasicFixedString<Char, N>& a,
3024 BasicFixedString<Char, N>& b) noexcept {
3028 inline namespace literals {
3029 inline namespace string_literals {
3031 // "const std::size_t&" is so that folly::npos has the same address in every
3032 // translation unit. This is to avoid potential violations of the ODR.
3033 constexpr const std::size_t& npos = detail::fixedstring::FixedStringBase::npos;
3036 #if defined(__GNUC__)
3037 #pragma GCC diagnostic push
3038 #pragma GCC diagnostic ignored "-Wpragmas"
3039 #pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template"
3041 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
3042 * User-defined literals for creating FixedString objects from string literals
3043 * on the compilers that support it.
3048 * using namespace folly::string_literals;
3049 * constexpr auto hello = "hello world!"_fs;
3052 * \note This requires a GNU compiler extension
3053 * (-Wgnu-string-literal-operator-template) supported by clang and gcc,
3054 * proposed for standardization in
3055 * <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0424r0.pdf>.
3057 * For portable code, prefer the suffixes `_fs4`, `_fs8`, `_fs16`, `_fs32`,
3058 * `_fs64`, and `_fs128` for creating instances of types `FixedString<4>`,
3059 * `FixedString<8>`, `FixedString<16>`, etc.
3061 template <class Char, Char... Cs>
3062 constexpr BasicFixedString<Char, sizeof...(Cs)> operator"" _fs() noexcept {
3063 using A = const Char[sizeof...(Cs) + 1u];
3064 // The `+` in `+A{etc}` forces the array type to decay to a pointer
3065 return {+A{Cs..., Char(0)}, sizeof...(Cs)};
3068 #pragma GCC diagnostic pop
3071 #define FOLLY_DEFINE_FIXED_STRING_UDL(N) \
3072 constexpr FixedString<N> operator"" _fs##N( \
3073 const char* that, std::size_t count) noexcept(false) { \
3074 return {that, count}; \
3078 // Define UDLs _fs4, _fs8, _fs16, etc for FixedString<[4, 8, 16, ...]>
3079 FOLLY_DEFINE_FIXED_STRING_UDL(4)
3080 FOLLY_DEFINE_FIXED_STRING_UDL(8)
3081 FOLLY_DEFINE_FIXED_STRING_UDL(16)
3082 FOLLY_DEFINE_FIXED_STRING_UDL(32)
3083 FOLLY_DEFINE_FIXED_STRING_UDL(64)
3084 FOLLY_DEFINE_FIXED_STRING_UDL(128)
3086 #undef FOLLY_DEFINE_FIXED_STRING_UDL
3091 // // numeric conversions:
3092 // template <std::size_t N>
3093 // constexpr int stoi(const FixedString<N>& str, int base = 10);
3094 // template <std::size_t N>
3095 // constexpr unsigned stou(const FixedString<N>& str, int base = 10);
3096 // template <std::size_t N>
3097 // constexpr long stol(const FixedString<N>& str, int base = 10);
3098 // template <std::size_t N>
3099 // constexpr unsigned long stoul(const FixedString<N>& str, int base = 10;
3100 // template <std::size_t N>
3101 // constexpr long long stoll(const FixedString<N>& str, int base = 10);
3102 // template <std::size_t N>
3103 // constexpr unsigned long long stoull(const FixedString<N>& str,
3105 // template <std::size_t N>
3106 // constexpr float stof(const FixedString<N>& str);
3107 // template <std::size_t N>
3108 // constexpr double stod(const FixedString<N>& str);
3109 // template <std::size_t N>
3110 // constexpr long double stold(const FixedString<N>& str);
3111 // template <int val>
3112 // constexpr FixedString</*...*/> to_fixed_string_i() noexcept;
3113 // template <unsigned val>
3114 // constexpr FixedString</*...*/> to_fixed_string_u() noexcept;
3115 // template <long val>
3116 // constexpr FixedString</*...*/> to_fixed_string_l() noexcept;
3117 // template <unsigned long val>
3118 // constexpr FixedString</*...*/> to_fixed_string_ul() noexcept;
3119 // template <long long val>
3120 // constexpr FixedString</*...*/> to_fixed_string_ll() noexcept
3121 // template <unsigned long long val>
3122 // constexpr FixedString</*...*/> to_fixed_string_ull() noexcept;