2 * Copyright 2016 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/BitsFunctexcept.h>
32 #include <folly/portability/Constexpr.h>
34 // Define FOLLY_USE_CPP14_CONSTEXPR to be true if the compiler's C++14
35 // constexpr support is "good enough".
36 #ifndef FOLLY_USE_CPP14_CONSTEXPR
37 #if defined(__clang__)
38 #define FOLLY_USE_CPP14_CONSTEXPR __cplusplus >= 201300L
39 #elif defined(__GNUC__)
40 #define FOLLY_USE_CPP14_CONSTEXPR __cplusplus >= 201304L
42 #define FOLLY_USE_CPP14_CONSTEXPR 0 // MSVC?
46 #if FOLLY_USE_CPP14_CONSTEXPR
47 #define FOLLY_CPP14_CONSTEXPR constexpr
49 #define FOLLY_CPP14_CONSTEXPR inline
54 template <class Char, std::size_t N>
55 class BasicFixedString;
57 template <std::size_t N>
58 using FixedString = BasicFixedString<char, N>;
61 namespace fixedstring {
63 // This is a template so that the class static npos can be defined in the
65 template <class = void>
66 struct FixedStringBase_ {
67 static constexpr std::size_t npos = static_cast<std::size_t>(-1);
71 constexpr std::size_t FixedStringBase_<Void>::npos;
73 using FixedStringBase = FixedStringBase_<>;
75 template <class Char, std::size_t N>
76 constexpr std::size_t size(const Char (&)[N]) noexcept {
80 template <class Char, std::size_t N>
81 constexpr std::size_t size(const BasicFixedString<Char, N>& s) noexcept {
85 // Intentionally NOT constexpr. By making this not constexpr, we make
86 // checkOverflow below ill-formed in a constexpr context when the condition
87 // it's testing for fails. In this way, precondition violations are reported
88 // at compile-time instead of at runtime.
89 [[noreturn]] inline void assertOutOfBounds() {
90 assert(false && "Array index out of bounds in BasicFixedString");
91 std::__throw_out_of_range("Array index out of bounds in BasicFixedString");
94 constexpr std::size_t checkOverflow(std::size_t i, std::size_t max) {
95 return i <= max ? i : (assertOutOfBounds(), max);
98 constexpr std::size_t checkOverflowOrNpos(std::size_t i, std::size_t max) {
99 return i == FixedStringBase::npos
101 : (i <= max ? i : (assertOutOfBounds(), max));
104 // Intentionally NOT constexpr. See note above for assertOutOfBounds
105 [[noreturn]] inline void assertNotNullTerminated() noexcept {
108 "Non-null terminated string used to initialize a BasicFixedString");
109 std::terminate(); // Fail hard, fail fast.
112 // Parsing help for human readers: the following is a constexpr noexcept
113 // function that accepts a reference to an array as a parameter and returns
114 // a reference to the same array.
115 template <class Char, std::size_t N>
116 constexpr const Char (&checkNullTerminated(const Char (&a)[N]) noexcept)[N] {
117 // Strange decltype(a)(a) used to make MSVC happy.
118 return a[N - 1u] == Char(0)
120 // In Debug mode, guard against embedded nulls:
121 && N - 1u == folly::detail::constexpr_strlen_internal(a, 0u)
124 : (assertNotNullTerminated(), decltype(a)(a));
127 enum class Cmp : int { LT = -1, EQ = 0, GT = 1 };
129 template <class Left, class Right>
130 constexpr Cmp compare_(
132 std::size_t left_pos,
133 std::size_t left_size,
135 std::size_t right_pos,
136 std::size_t right_size) noexcept {
137 return left_pos == left_size
138 ? (right_pos == right_size ? Cmp::EQ : Cmp::LT)
139 : (right_pos == right_size ? Cmp::GT
140 : (left[left_pos] < right[right_pos]
142 : (left[left_pos] > right[right_pos]
144 : fixedstring::compare_(
153 template <class Left, class Right>
154 constexpr bool equal_(
156 std::size_t left_size,
158 std::size_t right_size) noexcept {
159 return left_size == right_size &&
160 Cmp::EQ == compare_(left, 0u, left_size, right, 0u, right_size);
163 template <class Char, class Left, class Right>
165 char_at_(const Left& left, const Right& right, std::size_t i) noexcept {
166 return i < fixedstring::size(left)
168 : i < (fixedstring::size(left) + fixedstring::size(right))
169 ? right[i - fixedstring::size(left)]
173 template <class Char, class Left, class Right>
174 constexpr Char char_at_(
176 std::size_t left_pos,
177 std::size_t left_count,
179 std::size_t right_pos,
180 std::size_t right_count,
181 std::size_t i) noexcept {
184 : (i < right_count + left_pos
185 ? right[i - left_pos + right_pos]
186 : (i < fixedstring::size(left) - left_count + right_count
187 ? left[i - right_count + left_count]
191 template <class Left, class Right>
192 constexpr bool find_at_(
196 std::size_t count) noexcept {
197 return 0u == count || (left[pos + count - 1u] == right[count - 1u] &&
198 find_at_(left, right, pos, count - 1u));
201 template <class Char, class Right>
203 find_one_of_at_(Char ch, const Right& right, std::size_t pos) noexcept {
205 (ch == right[pos - 1u] || find_one_of_at_(ch, right, pos - 1u));
208 template <class Left, class Right>
209 constexpr std::size_t find_(
213 std::size_t count) noexcept {
214 return find_at_(left, right, pos, count)
216 : fixedstring::size(left) <= pos + count
217 ? FixedStringBase::npos
218 : find_(left, right, pos + 1u, count);
221 template <class Left, class Right>
222 constexpr std::size_t rfind_(
226 std::size_t count) noexcept {
227 return find_at_(left, right, pos, count)
229 : 0u == pos ? FixedStringBase::npos
230 : rfind_(left, right, pos - 1u, count);
233 template <class Left, class Right>
234 constexpr std::size_t find_first_of_(
238 std::size_t count) noexcept {
239 return find_one_of_at_(left[pos], right, count)
241 : fixedstring::size(left) <= pos + 1u
242 ? FixedStringBase::npos
243 : find_first_of_(left, right, pos + 1u, count);
246 template <class Left, class Right>
247 constexpr std::size_t find_first_not_of_(
251 std::size_t count) noexcept {
252 return !find_one_of_at_(left[pos], right, count)
254 : fixedstring::size(left) <= pos + 1u
255 ? FixedStringBase::npos
256 : find_first_not_of_(left, right, pos + 1u, count);
259 template <class Left, class Right>
260 constexpr std::size_t find_last_of_(
264 std::size_t count) noexcept {
265 return find_one_of_at_(left[pos], right, count)
267 : 0u == pos ? FixedStringBase::npos
268 : find_last_of_(left, right, pos - 1u, count);
271 template <class Left, class Right>
272 constexpr std::size_t find_last_not_of_(
276 std::size_t count) noexcept {
277 return !find_one_of_at_(left[pos], right, count)
279 : 0u == pos ? FixedStringBase::npos
280 : find_last_not_of_(left, right, pos - 1u, count);
284 template <class Char, class Left, class Right, std::size_t... Is>
285 static constexpr BasicFixedString<Char, sizeof...(Is)> concat_(
288 std::index_sequence<Is...> is) noexcept {
289 return {left, right, is};
292 template <class Char, class Left, class Right, std::size_t... Is>
293 static constexpr BasicFixedString<Char, sizeof...(Is)> replace_(
295 std::size_t left_pos,
296 std::size_t left_count,
298 std::size_t right_pos,
299 std::size_t right_count,
300 std::index_sequence<Is...> is) noexcept {
301 return {left, left_pos, left_count, right, right_pos, right_count, is};
306 FOLLY_CPP14_CONSTEXPR void constexpr_swap(T& a, T& b) noexcept(
307 noexcept(a = T(std::move(a)))) {
308 T tmp((std::move(a)));
313 // FUTURE: use const_log2 to fold instantiations of BasicFixedString together.
314 // All BasicFixedString<C, N> instantiations could share the implementation
315 // of BasicFixedString<C, M>, where M is the next highest power of 2 after N.
317 // Also, because of alignment of the data_ and size_ members, N should never be
318 // smaller than `(alignof(std::size_t)/sizeof(C))-1` (-1 because of the null
319 // terminator). OR, create a specialization for BasicFixedString<C, 0u> that
320 // does not have a size_ member, since it is unnecessary.
321 constexpr std::size_t const_log2(std::size_t N, std::size_t log2 = 0u) {
322 return N / 2u == 0u ? log2 : const_log2(N / 2u, log2 + 1u);
325 // For constexpr reverse iteration over a BasicFixedString
327 struct ReverseIterator {
333 using other = typename std::conditional<
334 std::is_const<T>::value,
335 ReverseIterator<typename std::remove_const<T>::type>,
339 using value_type = typename std::remove_const<T>::type;
340 using reference = T&;
342 using difference_type = std::ptrdiff_t;
343 using iterator_category = std::random_access_iterator_tag;
345 constexpr ReverseIterator() = default;
346 constexpr ReverseIterator(const ReverseIterator&) = default;
347 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator=(const ReverseIterator&) =
349 constexpr explicit ReverseIterator(T* p) noexcept : p_(p) {}
350 constexpr /* implicit */ ReverseIterator(const other& that) noexcept
352 friend constexpr bool operator==(
354 ReverseIterator b) noexcept {
357 friend constexpr bool operator!=(
359 ReverseIterator b) noexcept {
362 constexpr reference operator*() const {
365 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator++() noexcept {
369 FOLLY_CPP14_CONSTEXPR ReverseIterator operator++(int)noexcept {
374 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator--() noexcept {
378 FOLLY_CPP14_CONSTEXPR ReverseIterator operator--(int)noexcept {
383 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator+=(std::ptrdiff_t i) noexcept {
387 friend constexpr ReverseIterator operator+(
389 ReverseIterator that) noexcept {
390 return ReverseIterator{that.p_ - i};
392 friend constexpr ReverseIterator operator+(
393 ReverseIterator that,
394 std::ptrdiff_t i) noexcept {
395 return ReverseIterator{that.p_ - i};
397 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator-=(std::ptrdiff_t i) noexcept {
401 friend constexpr ReverseIterator operator-(
402 ReverseIterator that,
403 std::ptrdiff_t i) noexcept {
404 return ReverseIterator{that.p_ + i};
406 friend constexpr std::ptrdiff_t operator-(
408 ReverseIterator b) noexcept {
411 constexpr reference operator[](std::ptrdiff_t i) const noexcept {
416 } // namespace fixedstring
417 } // namespace detail
419 // Defined in folly/Range.h
420 template <class Iter>
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::StringLiterals;
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::StringLiterals;
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 = std::make_index_sequence<N>;
536 template <class That, std::size_t... Is>
537 constexpr BasicFixedString(
540 std::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 std::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(
559 std::index_sequence<Is...>) noexcept
560 : data_{detail::fixedstring::char_at_<Char>(left, right, Is)..., Char(0)},
561 size_{detail::fixedstring::size(left) +
562 detail::fixedstring::size(right)} {}
564 // Replace constructor
565 template <class Left, class Right, std::size_t... Is>
566 constexpr BasicFixedString(
568 std::size_t left_pos,
569 std::size_t left_count,
571 std::size_t right_pos,
572 std::size_t right_count,
573 std::index_sequence<Is...>) noexcept
574 : data_{detail::fixedstring::char_at_<Char>(
583 size_{detail::fixedstring::size(left) - left_count + right_count} {}
586 using size_type = std::size_t;
587 using difference_type = std::ptrdiff_t;
588 using reference = Char&;
589 using const_reference = const Char&;
590 using pointer = Char*;
591 using const_pointer = const Char*;
592 using iterator = Char*;
593 using const_iterator = const Char*;
594 using reverse_iterator = detail::fixedstring::ReverseIterator<Char>;
595 using const_reverse_iterator =
596 detail::fixedstring::ReverseIterator<const Char>;
598 using detail::fixedstring::FixedStringBase::npos;
600 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
602 * \post `size() == 0`
603 * \post `at(0) == Char(0)`
605 constexpr BasicFixedString() : data_{}, size_{} {}
607 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
609 * \post `size() == that.size()`
610 * \post `0 == strncmp(data(), that.data(), size())`
611 * \post `at(size()) == Char(0)`
613 constexpr BasicFixedString(const BasicFixedString& /*that*/) = default;
615 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
616 * Construct from a differently-sized BasicFixedString
617 * \pre `that.size() <= N`
618 * \post `size() == that.size()`
619 * \post `0 == strncmp(data(), that.data(), size())`
620 * \post `at(size()) == Char(0)`
621 * \throw std::out_of_range when that.size() > N. When M <= N, this
622 * constructor will never throw.
623 * \note Conversions from larger-capacity BasicFixedString objects to smaller
624 * ones (`M > N`) are allowed as long as the *size()* of the source string
627 template <std::size_t M>
628 constexpr /* implicit */ BasicFixedString(
629 const BasicFixedString<Char, M>& that) noexcept(M <= N)
630 : BasicFixedString{that, 0u, that.size_} {}
632 // Why is this deleted? To avoid confusion with the constructor that takes
633 // a const Char* and a count.
634 template <std::size_t M>
635 constexpr BasicFixedString(
636 const BasicFixedString<Char, M>& that,
637 std::size_t pos) noexcept(false) = delete;
639 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
640 * Construct from an BasicFixedString, an offset, and a count
641 * \param that The source string
642 * \param pos The starting position in `that`
643 * \param count The number of characters to copy. If `npos`, `count` is taken
644 * to be `that.size()-pos`.
645 * \pre `pos <= that.size()`
646 * \pre `count <= that.size()-pos && count <= N`
647 * \post `size() == count`
648 * \post `0 == strncmp(data(), that.data()+pos, size())`
649 * \post `at(size()) == Char(0)`
650 * \throw std::out_of_range when pos+count > that.size(), or when
653 template <std::size_t M>
654 constexpr BasicFixedString(
655 const BasicFixedString<Char, M>& that,
657 std::size_t count) noexcept(false)
661 std::make_index_sequence<(M < N ? M : N)>{},
663 detail::fixedstring::checkOverflow(
664 detail::fixedstring::checkOverflowOrNpos(
667 detail::fixedstring::checkOverflow(pos, that.size_)),
670 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
671 * Construct from a string literal
673 * \pre `that[M-1] == Char(0)`
674 * \post `0 == strncmp(data(), that, M-1)`
675 * \post `size() == M-1`
676 * \post `at(size()) == Char(0)`
678 template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
679 constexpr /* implicit */ BasicFixedString(const Char (&that)[M]) noexcept
680 : BasicFixedString{detail::fixedstring::checkNullTerminated(that),
682 std::make_index_sequence<M - 1u>{}} {}
684 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
685 * Construct from a `const Char*` and count
686 * \pre `that` points to an array of at least `count` characters.
688 * \post `size() == count`
689 * \post `0 == strncmp(data(), that, size())`
690 * \post `at(size()) == Char(0)`
691 * \throw std::out_of_range when count > N
693 constexpr BasicFixedString(const Char* that, std::size_t count) noexcept(
695 : BasicFixedString{that,
696 detail::fixedstring::checkOverflow(count, N),
699 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
700 * Construct an BasicFixedString that contains `count` characters, all
703 * \post `size() == count`
704 * \post `npos == find_first_not_of(ch)`
705 * \post `at(size()) == Char(0)`
706 * \throw std::out_of_range when count > N
708 constexpr BasicFixedString(std::size_t count, Char ch) noexcept(false)
709 : BasicFixedString{detail::fixedstring::checkOverflow(count, N),
713 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
714 * Construct an BasicFixedString from a `std::initializer_list` of
716 * \pre `il.size() <= N`
717 * \post `size() == count`
718 * \post `0 == strncmp(data(), il.begin(), size())`
719 * \post `at(size()) == Char(0)`
720 * \throw std::out_of_range when il.size() > N
722 constexpr BasicFixedString(std::initializer_list<Char> il) noexcept(false)
723 : BasicFixedString{il.begin(), il.size()} {}
725 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
726 const BasicFixedString&) noexcept = default;
728 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
729 * Assign from a `BasicFixedString<Char, M>`.
730 * \pre `that.size() <= N`
731 * \post `size() == that.size()`
732 * \post `0 == strncmp(data(), that.begin(), size())`
733 * \post `at(size()) == Char(0)`
734 * \throw std::out_of_range when that.size() > N. When M <= N, this
735 * assignment operator will never throw.
736 * \note Assignments from larger-capacity BasicFixedString objects to smaller
737 * ones (`M > N`) are allowed as long as the *size* of the source string is
741 template <std::size_t M>
742 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
743 const BasicFixedString<Char, M>& that) noexcept(M <= N) {
744 detail::fixedstring::checkOverflow(that.size_, N);
745 size_ = that.copy(data_, that.size_);
746 data_[size_] = Char(0);
750 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
751 * Assign from a null-terminated array of characters.
753 * \pre `that` has no embedded null characters
754 * \pre `that[M-1]==Char(0)`
755 * \post `size() == M-1`
756 * \post `0 == strncmp(data(), that, size())`
757 * \post `at(size()) == Char(0)`
760 template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
761 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
762 const Char (&that)[M]) noexcept {
763 return assign(detail::fixedstring::checkNullTerminated(that), M - 1u);
766 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
767 * Assign from an `initializer_list` of characters.
768 * \pre `il.size() <= N`
769 * \post `size() == il.size()`
770 * \post `0 == strncmp(data(), il.begin(), size())`
771 * \post `at(size()) == Char(0)`
772 * \throw std::out_of_range when il.size() > N
775 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
776 std::initializer_list<Char> il) noexcept(false) {
777 detail::fixedstring::checkOverflow(il.size(), N);
778 for (std::size_t i = 0u; i < il.size(); ++i) {
779 data_[i] = il.begin()[i];
782 data_[size_] = Char(0);
786 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
787 * Conversion to folly::Range
788 * \return `Range<Iter>{begin(), end()}`
792 class = typename std::enable_if<
793 std::is_convertible<Char*, Iter>::value>::type>
794 FOLLY_CPP14_CONSTEXPR /* implicit */ operator Range<Iter>() noexcept {
795 return {begin(), end()};
803 class = typename std::enable_if<
804 std::is_convertible<const Char*, Iter>::value>::type>
805 constexpr /* implicit */ operator Range<Iter>() const noexcept {
806 return {begin(), end()};
809 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
810 * Conversion to folly::Range
811 * \return `Range<Char*>{begin(), end()}`
813 FOLLY_CPP14_CONSTEXPR Range<Char*> toRange() noexcept {
814 return {begin(), end()};
820 constexpr Range<const Char*> toRange() const noexcept {
821 return {begin(), end()};
824 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
825 * Conversion to std::basic_string<Char>
826 * \return `std::basic_string<Char>{begin(), end()}`
828 /* implicit */ operator std::basic_string<Char>() const noexcept(false) {
829 return std::basic_string<Char>{begin(), end()};
832 std::basic_string<Char> toStdString() const noexcept(false) {
833 return std::basic_string<Char>{begin(), end()};
836 // Think hard about whether this is a good idea. It's certainly better than
837 // an implicit conversion to `const Char*` since `delete "hi"_fs` will fail
838 // to compile. But it creates ambiguities when passing a FixedString to an
839 // API that has overloads for `const char*` and `folly::Range`, for instance.
840 // using ArrayType = Char[N];
841 // FOLLY_CPP14_CONSTEXPR /* implicit */ operator ArrayType&() noexcept {
845 // using ConstArrayType = const Char[N];
846 // constexpr /* implicit */ operator ConstArrayType&() const noexcept {
850 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
851 * Assigns a sequence of `count` characters of value `ch`.
852 * \param count The count of characters.
855 * \post `size() == count`
856 * \post `npos == find_first_not_of(ch)`
857 * \post `at(size()) == Char(0)`
858 * \throw std::out_of_range when count > N
861 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
863 Char ch) noexcept(false) {
864 detail::fixedstring::checkOverflow(count, N);
865 for (std::size_t i = 0u; i < count; ++i) {
869 data_[size_] = Char(0);
873 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
874 * Assigns characters from an `BasicFixedString` to this object.
875 * \note Equivalent to `assign(that, 0, that.size())`
877 template <std::size_t M>
878 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
879 const BasicFixedString<Char, M>& that) noexcept(M <= N) {
883 // Why is this overload deleted? So users aren't confused by the difference
884 // between str.assign("foo", N) and str.assign("foo"_fs, N). In the former,
885 // N is a count of characters. In the latter, it would be a position, which
886 // totally changes the meaning of the code.
887 template <std::size_t M>
888 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
889 const BasicFixedString<Char, M>& that,
890 std::size_t pos) noexcept(false) = delete;
892 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
893 * Assigns `count` characters from an `BasicFixedString` to this object,
894 * starting at position `pos` in the source object.
895 * \param that The source string.
896 * \param pos The starting position in the source string.
897 * \param count The number of characters to copy. If `npos`, `count` is taken
898 * to be `that.size()-pos`.
899 * \pre `pos <= that.size()`
900 * \pre `count <= that.size()-pos`
902 * \post `size() == count`
903 * \post `0 == strncmp(data(), that.begin() + pos, count)`
904 * \post `at(size()) == Char(0)`
905 * \throw std::out_of_range when pos > that.size() or count > that.size()-pos
909 template <std::size_t M>
910 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
911 const BasicFixedString<Char, M>& that,
913 std::size_t count) noexcept(false) {
914 detail::fixedstring::checkOverflow(pos, that.size_);
917 detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos));
920 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
921 * Assigns characters from an `BasicFixedString` to this object.
922 * \pre `that` contains no embedded nulls.
923 * \pre `that[M-1] == Char(0)`
924 * \note Equivalent to `assign(that, M - 1)`
926 template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
927 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
928 const Char (&that)[M]) noexcept {
929 return assign(detail::fixedstring::checkNullTerminated(that), M - 1u);
932 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
933 * Assigns `count` characters from a range of characters to this object.
934 * \param that A pointer to a range of characters.
935 * \param count The number of characters to copy.
936 * \pre `that` points to at least `count` characters.
938 * \post `size() == count`
939 * \post `0 == strncmp(data(), that, count)`
940 * \post `at(size()) == Char(0)`
941 * \throw std::out_of_range when count > N
944 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
946 std::size_t count) noexcept(false) {
947 detail::fixedstring::checkOverflow(count, N);
948 for (std::size_t i = 0u; i < count; ++i) {
952 data_[size_] = Char(0);
956 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
957 * Swap the contents of this string with `that`.
959 FOLLY_CPP14_CONSTEXPR void swap(BasicFixedString& that) noexcept {
960 // less-than-or-equal here to copy the null terminator:
961 for (std::size_t i = 0u; i <= folly::constexpr_max(size_, that.size_);
963 detail::fixedstring::constexpr_swap(data_[i], that.data_[i]);
965 detail::fixedstring::constexpr_swap(size_, that.size_);
968 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
969 * Return a pointer to a range of `size()+1` characters, the last of which
972 FOLLY_CPP14_CONSTEXPR Char* data() noexcept {
979 constexpr const Char* data() const noexcept {
983 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
986 constexpr const Char* c_str() const noexcept {
990 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
993 FOLLY_CPP14_CONSTEXPR Char* begin() noexcept {
1000 constexpr const Char* begin() const noexcept {
1004 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1007 constexpr const Char* cbegin() const noexcept {
1011 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1012 * \return `data() + size()`.
1014 FOLLY_CPP14_CONSTEXPR Char* end() noexcept {
1015 return data_ + size_;
1021 constexpr const Char* end() const noexcept {
1022 return data_ + size_;
1025 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1026 * \return `data() + size()`.
1028 constexpr const Char* cend() const noexcept {
1032 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1033 * Returns a reverse iterator to the first character of the reversed string.
1034 * It corresponds to the last + 1 character of the non-reversed string.
1036 FOLLY_CPP14_CONSTEXPR reverse_iterator rbegin() noexcept {
1037 return reverse_iterator{data_ + size_};
1043 constexpr const_reverse_iterator rbegin() const noexcept {
1044 return const_reverse_iterator{data_ + size_};
1048 * \note Equivalent to `rbegin()` on a const-qualified reference to `*this`.
1050 constexpr const_reverse_iterator crbegin() const noexcept {
1054 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1055 * Returns a reverse iterator to the last + 1 character of the reversed
1056 * string. It corresponds to the first character of the non-reversed string.
1058 FOLLY_CPP14_CONSTEXPR reverse_iterator rend() noexcept {
1059 return reverse_iterator{data_};
1065 constexpr const_reverse_iterator rend() const noexcept {
1066 return const_reverse_iterator{data_};
1070 * \note Equivalent to `rend()` on a const-qualified reference to `*this`.
1072 constexpr const_reverse_iterator crend() const noexcept {
1077 * \return The number of `Char` elements in the string.
1079 constexpr std::size_t size() const noexcept {
1084 * \return The number of `Char` elements in the string.
1086 constexpr std::size_t length() const noexcept {
1091 * \return True if and only if `size() == 0`.
1093 constexpr bool empty() const noexcept {
1100 static constexpr std::size_t capacity() noexcept {
1107 static constexpr std::size_t max_size() noexcept {
1111 // We would need to reimplement folly::Hash to make this
1113 std::uint32_t hash() const noexcept {
1114 return folly::hsieh_hash32_buf(data_, size_);
1118 * \note `at(size())` is allowed will return `Char(0)`.
1119 * \return `*(data() + i)`
1120 * \throw std::out_of_range when i > size()
1122 FOLLY_CPP14_CONSTEXPR Char& at(std::size_t i) noexcept(false) {
1125 : (std::__throw_out_of_range("Out of range in BasicFixedString::at"),
1132 constexpr const Char& at(std::size_t i) const noexcept(false) {
1135 : (std::__throw_out_of_range("Out of range in BasicFixedString::at"),
1140 * \pre `i <= size()`
1141 * \note `(*this)[size()]` is allowed will return `Char(0)`.
1142 * \return `*(data() + i)`
1144 FOLLY_CPP14_CONSTEXPR Char& operator[](std::size_t i) noexcept {
1148 return data_[detail::fixedstring::checkOverflow(i, size_)];
1155 constexpr const Char& operator[](std::size_t i) const noexcept {
1159 return data_[detail::fixedstring::checkOverflow(i, size_)];
1164 * \note Equivalent to `(*this)[0]`
1166 FOLLY_CPP14_CONSTEXPR Char& front() noexcept {
1173 constexpr const Char& front() const noexcept {
1178 * \note Equivalent to `at(size()-1)`
1181 FOLLY_CPP14_CONSTEXPR Char& back() noexcept {
1183 return data_[size_ - 1u];
1185 return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)];
1192 constexpr const Char& back() const noexcept {
1194 return data_[size_ - 1u];
1196 return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)];
1201 * Clears the contents of this string.
1202 * \post `size() == 0u`
1203 * \post `at(size()) == Char(0)`
1205 FOLLY_CPP14_CONSTEXPR void clear() noexcept {
1206 data_[0u] = Char(0);
1211 * \note Equivalent to `append(1u, ch)`.
1213 FOLLY_CPP14_CONSTEXPR void push_back(Char ch) noexcept(false) {
1214 detail::fixedstring::checkOverflow(1u, N - size_);
1216 data_[++size_] = Char(0);
1220 * \note Equivalent to `cappend(1u, ch)`.
1222 constexpr BasicFixedString<Char, N + 1u> cpush_back(Char ch) const noexcept {
1227 * Removes the last character from the string.
1229 * \post `size()` is one fewer than before calling `pop_back()`.
1230 * \post `at(size()) == Char(0)`
1231 * \post The characters in the half-open range `[0,size()-1)` are unmodified.
1232 * \throw std::out_of_range if empty().
1234 FOLLY_CPP14_CONSTEXPR void pop_back() noexcept(false) {
1235 detail::fixedstring::checkOverflow(1u, size_);
1237 data_[size_] = Char(0);
1241 * Returns a new string with the first `size()-1` characters from this string.
1243 * \note Equivalent to `BasicFixedString<Char, N-1u>{*this, 0u, size()-1u}`
1244 * \throw std::out_of_range if empty().
1246 constexpr BasicFixedString<Char, N - 1u> cpop_back() const noexcept(false) {
1247 return {*this, 0u, size_ - detail::fixedstring::checkOverflow(1u, size_)};
1250 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1251 * Appends `count` copies of `ch` to this string.
1252 * \pre `count + old_size <= N`
1253 * \post The first `old_size` characters of the string are unmodified.
1254 * \post `size() == old_size + count`
1255 * \throw std::out_of_range if count > N - size().
1257 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1259 Char ch) noexcept(false) {
1260 detail::fixedstring::checkOverflow(count, N - size_);
1261 for (std::size_t i = 0u; i < count; ++i)
1262 data_[size_ + i] = ch;
1264 data_[size_] = Char(0);
1269 * \note Equivalent to `append(*this, 0, that.size())`.
1271 template <std::size_t M>
1272 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1273 const BasicFixedString<Char, M>& that) noexcept(false) {
1274 return append(that, 0u, that.size_);
1277 // Why is this overload deleted? So as not to get confused with
1278 // append("null-terminated", N), where N would be a count instead
1280 template <std::size_t M>
1281 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1282 const BasicFixedString<Char, M>& that,
1283 std::size_t pos) noexcept(false) = delete;
1286 * Appends `count` characters from another string to this one, starting at a
1287 * given offset, `pos`.
1288 * \param that The source string.
1289 * \param pos The starting position in the source string.
1290 * \param count The number of characters to append. If `npos`, `count` is
1291 * taken to be `that.size()-pos`.
1292 * \pre `pos <= that.size()`
1293 * \pre `count <= that.size() - pos`
1294 * \pre `old_size + count <= N`
1295 * \post The first `old_size` characters of the string are unmodified.
1296 * \post `size() == old_size + count`
1297 * \post `at(size()) == Char(0)`
1298 * \throw std::out_of_range if pos + count > that.size() or if
1299 * `old_size + count > N`.
1301 template <std::size_t M>
1302 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1303 const BasicFixedString<Char, M>& that,
1305 std::size_t count) noexcept(false) {
1306 detail::fixedstring::checkOverflow(pos, that.size_);
1307 count = detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos);
1308 detail::fixedstring::checkOverflow(count, N - size_);
1309 for (std::size_t i = 0u; i < count; ++i)
1310 data_[size_ + i] = that[pos + i];
1312 data_[size_] = Char(0);
1317 * \note Equivalent to `append(that, strlen(that))`.
1319 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(const Char* that) noexcept(
1321 return append(that, folly::constexpr_strlen(that));
1325 * Appends `count` characters from the specified character array.
1326 * \pre `that` points to a range of at least `count` characters.
1327 * \pre `count + old_size <= N`
1328 * \post The first `old_size` characters of the string are unmodified.
1329 * \post `size() == old_size + count`
1330 * \post `at(size()) == Char(0)`
1331 * \throw std::out_of_range if old_size + count > N.
1333 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1335 std::size_t count) noexcept(false) {
1336 detail::fixedstring::checkOverflow(count, N - size_);
1337 for (std::size_t i = 0u; i < count; ++i)
1338 data_[size_ + i] = that[i];
1340 data_[size_] = Char(0);
1344 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1345 * Creates a new string by appending a character to an existing string, which
1346 * is left unmodified.
1347 * \note Equivalent to `*this + ch`
1349 constexpr BasicFixedString<Char, N + 1u> cappend(Char ch) const noexcept {
1354 * Creates a new string by appending a string to an existing string, which
1355 * is left unmodified.
1356 * \note Equivalent to `*this + ch`
1358 template <std::size_t M>
1359 constexpr BasicFixedString<Char, N + M> cappend(
1360 const BasicFixedString<Char, M>& that) const noexcept {
1361 return *this + that;
1364 // Deleted to avoid confusion with append("char*", N), where N is a count
1365 // instead of a position.
1366 template <std::size_t M>
1367 constexpr BasicFixedString<Char, N + M> cappend(
1368 const BasicFixedString<Char, M>& that,
1369 std::size_t pos) const noexcept(false) = delete;
1372 * Creates a new string by appending characters from one string to another,
1373 * which is left unmodified.
1374 * \note Equivalent to `*this + that.substr(pos, count)`
1376 template <std::size_t M>
1377 constexpr BasicFixedString<Char, N + M> cappend(
1378 const BasicFixedString<Char, M>& that,
1380 std::size_t count) const noexcept(false) {
1381 return creplace(size_, 0u, that, pos, count);
1385 * Creates a new string by appending a string literal to a string,
1386 * which is left unmodified.
1387 * \note Equivalent to `*this + that`
1389 template <std::size_t M>
1390 constexpr BasicFixedString<Char, N + M - 1u> cappend(
1391 const Char (&that)[M]) const noexcept {
1392 return creplace(size_, 0u, that);
1395 // Deleted to avoid confusion with append("char*", N), where N is a count
1396 // instead of a position
1397 template <std::size_t M>
1398 constexpr BasicFixedString<Char, N + M - 1u> cappend(
1399 const Char (&that)[M],
1400 std::size_t pos) const noexcept(false) = delete;
1403 * Creates a new string by appending characters from one string to another,
1404 * which is left unmodified.
1405 * \note Equivalent to `*this + makeFixedString(that).substr(pos, count)`
1407 template <std::size_t M>
1408 constexpr BasicFixedString<Char, N + M - 1u>
1409 cappend(const Char (&that)[M], std::size_t pos, std::size_t count) const
1411 return creplace(size_, 0u, that, pos, count);
1414 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1415 * Appends characters from a null-terminated string literal to this string.
1416 * \note Equivalent to `append(that)`.
1418 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(const Char* that) noexcept(
1420 return append(that);
1424 * Appends characters from another string to this one.
1425 * \note Equivalent to `append(that)`.
1427 template <std::size_t M>
1428 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(
1429 const BasicFixedString<Char, M>& that) noexcept(false) {
1430 return append(that, 0u, that.size_);
1434 * Appends a character to this string.
1435 * \note Equivalent to `push_back(ch)`.
1437 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(Char ch) noexcept(false) {
1443 * Appends characters from an `initializer_list` to this string.
1444 * \note Equivalent to `append(il.begin(), il.size())`.
1446 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(
1447 std::initializer_list<Char> il) noexcept(false) {
1448 return append(il.begin(), il.size());
1451 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1452 * Erase all characters from this string.
1453 * \note Equivalent to `clear()`
1456 FOLLY_CPP14_CONSTEXPR BasicFixedString& erase() noexcept {
1462 * Erases `count` characters from position `pos`. If `count` is `npos`,
1463 * erases from `pos` to the end of the string.
1464 * \pre `pos <= size()`
1465 * \pre `count <= size() - pos || count == npos`
1466 * \post `size() == old_size - min(count, old_size - pos)`
1467 * \post `at(size()) == Char(0)`
1469 * \throw std::out_of_range when pos > size().
1471 FOLLY_CPP14_CONSTEXPR BasicFixedString& erase(
1473 std::size_t count = npos) noexcept(false) {
1474 using A = const Char[1];
1477 detail::fixedstring::checkOverflowOrNpos(
1478 count, size_ - detail::fixedstring::checkOverflow(pos, size_)),
1484 * \note Equivalent to `erase(first - data(), 1)`
1485 * \return A pointer to the first character after the erased character.
1487 FOLLY_CPP14_CONSTEXPR Char* erase(const Char* first) noexcept(false) {
1488 erase(first - data_, 1u);
1489 return data_ + (first - data_);
1493 * \note Equivalent to `erase(first - data(), last - first)`
1494 * \return A pointer to the first character after the erased characters.
1496 FOLLY_CPP14_CONSTEXPR Char* erase(
1498 const Char* last) noexcept(false) {
1499 erase(first - data_, last - first);
1500 return data_ + (first - data_);
1503 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1504 * Create a new string by erasing all the characters from this string.
1505 * \note Equivalent to `BasicFixedString<Char, 0>{}`
1507 constexpr BasicFixedString<Char, 0u> cerase() const noexcept {
1512 * Create a new string by erasing all the characters after position `pos` from
1514 * \note Equivalent to `creplace(pos, min(count, pos - size()), "")`
1516 constexpr BasicFixedString cerase(std::size_t pos, std::size_t count = npos)
1517 const noexcept(false) {
1518 using A = const Char[1];
1521 detail::fixedstring::checkOverflowOrNpos(
1522 count, size_ - detail::fixedstring::checkOverflow(pos, size_)),
1526 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1527 * Compare two strings for lexicographical ordering.
1528 * \note Equivalent to
1529 * `compare(0, size(), that.data(), that.size())`
1531 template <std::size_t M>
1532 constexpr int compare(const BasicFixedString<Char, M>& that) const noexcept {
1533 return compare(0u, size_, that, 0u, that.size_);
1537 * Compare two strings for lexicographical ordering.
1538 * \note Equivalent to
1539 * `compare(this_pos, this_count, that.data(), that.size())`
1541 template <std::size_t M>
1542 constexpr int compare(
1543 std::size_t this_pos,
1544 std::size_t this_count,
1545 const BasicFixedString<Char, M>& that) const noexcept(false) {
1546 return compare(this_pos, this_count, that, 0u, that.size_);
1550 * Compare two strings for lexicographical ordering.
1551 * \note Equivalent to
1552 * `compare(this_pos, this_count, that.data() + that_pos, that_count)`
1554 template <std::size_t M>
1555 constexpr int compare(
1556 std::size_t this_pos,
1557 std::size_t this_count,
1558 const BasicFixedString<Char, M>& that,
1559 std::size_t that_pos,
1560 std::size_t that_count) const noexcept(false) {
1561 return static_cast<int>(detail::fixedstring::compare_(
1563 detail::fixedstring::checkOverflow(this_pos, size_),
1564 detail::fixedstring::checkOverflow(this_count, size_ - this_pos) +
1567 detail::fixedstring::checkOverflow(that_pos, that.size_),
1568 detail::fixedstring::checkOverflow(that_count, that.size_ - that_pos) +
1573 * Compare two strings for lexicographical ordering.
1574 * \note Equivalent to `compare(0, size(), that, strlen(that))`
1576 constexpr int compare(const Char* that) const noexcept {
1577 return compare(0u, size_, that, folly::constexpr_strlen(that));
1581 * Compare two strings for lexicographical ordering.
1582 * \note Equivalent to
1583 * `compare(this_pos, this_count, that, strlen(that))`
1585 constexpr int compare(
1586 std::size_t this_pos,
1587 std::size_t this_count,
1588 const Char* that) const noexcept(false) {
1589 return compare(this_pos, this_count, that, folly::constexpr_strlen(that));
1593 * Compare two strings for lexicographical ordering.
1595 * Let `A` be the the
1596 * character sequence {`(*this)[this_pos]`, ...
1597 * `(*this)[this_pos + this_count - 1]`}. Let `B` be the character sequence
1598 * {`that[0]`, ...`that[count - 1]`}. Then...
1601 * - `< 0` if `A` is ordered before the `B`
1602 * - `> 0` if `B` is ordered before `A`
1603 * - `0` if `A` equals `B`.
1605 * \throw std::out_of_range if this_pos + this_count > size().
1607 constexpr int compare(
1608 std::size_t this_pos,
1609 std::size_t this_count,
1611 std::size_t that_count) const noexcept(false) {
1612 return static_cast<int>(detail::fixedstring::compare_(
1614 detail::fixedstring::checkOverflow(this_pos, size_),
1615 detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos) +
1622 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1623 * Return a substring from `pos` to the end of the string.
1624 * \note Equivalent to `BasicFixedString{*this, pos}`
1626 constexpr BasicFixedString substr(std::size_t pos) const noexcept(false) {
1627 return {*this, pos};
1631 * Return a substring from `pos` to the end of the string.
1632 * \note Equivalent to `BasicFixedString{*this, pos, count}`
1634 constexpr BasicFixedString substr(std::size_t pos, std::size_t count) const
1636 return {*this, pos, count};
1639 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1640 * Replace the characters in the range denoted by the half-open range
1641 * [`first`, `last`) with the string `that`.
1642 * \pre `first` and `last` point to characters within this string (including
1643 * the terminating null).
1644 * \note Equivalent to
1645 * `replace(first - data(), last - first, that.data(), that.size())`
1647 template <std::size_t M>
1648 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1651 const BasicFixedString<Char, M>& that) noexcept(false) {
1652 return replace(first - data_, last - first, that, 0u, that.size_);
1656 * Replace `this_count` characters starting from position `this_pos` with the
1657 * characters from string `that` starting at position `that_pos`.
1658 * \pre `that_pos <= that.size()`
1659 * \note Equivalent to
1660 * <tt>replace(this_pos, this_count, that.data() + that_pos,
1661 * that.size() - that_pos)</tt>
1663 template <std::size_t M>
1664 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1665 std::size_t this_pos,
1666 std::size_t this_count,
1667 const BasicFixedString<Char, M>& that,
1668 std::size_t that_pos = 0u) noexcept(false) {
1669 return replace(this_pos, this_count, that, that_pos, that.size_ - that_pos);
1673 * Replace `this_count` characters starting from position `this_pos` with
1674 * `that_count` characters from string `that` starting at position
1676 * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos`
1677 * \note Equivalent to
1678 * `replace(this_pos, this_count, that.data() + that_pos, that_count)`
1680 template <std::size_t M>
1681 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1682 std::size_t this_pos,
1683 std::size_t this_count,
1684 const BasicFixedString<Char, M>& that,
1685 std::size_t that_pos,
1686 std::size_t that_count) noexcept(false) {
1687 return *this = creplace(this_pos, this_count, that, that_pos, that_count);
1691 * Replace `this_count` characters starting from position `this_pos` with
1692 * the characters from the string literal `that`.
1693 * \note Equivalent to
1694 * `replace(this_pos, this_count, that, strlen(that))`
1696 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1697 std::size_t this_pos,
1698 std::size_t this_count,
1699 const Char* that) noexcept(false) {
1700 return replace(this_pos, this_count, that, folly::constexpr_strlen(that));
1704 * Replace the characters denoted by the half-open range [`first`,`last`) with
1705 * the characters from the string literal `that`.
1706 * \pre `first` and `last` point to characters within this string (including
1707 * the terminating null).
1708 * \note Equivalent to
1709 * `replace(first - data(), last - first, that, strlen(that))`
1711 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1714 const Char* that) noexcept(false) {
1716 first - data_, last - first, that, folly::constexpr_strlen(that));
1720 * Replace `this_count` characters starting from position `this_pos` with
1721 * `that_count` characters from the character sequence pointed to by `that`.
1722 * \param this_pos The starting offset within `*this` of the first character
1724 * \param this_count The number of characters to be replaced. If `npos`,
1725 * it is treated as if `this_count` were `size() - this_pos`.
1726 * \param that A pointer to the replacement string.
1727 * \param that_count The number of characters in the replacement string.
1728 * \pre `this_pos <= size() && this_count <= size() - this_pos`
1729 * \pre `that` points to a contiguous sequence of at least `that_count`
1731 * \throw std::out_of_range on any of the following conditions:
1732 * - `this_pos > size()`
1733 * - `this_count > size() - this_pos`
1734 * - `size() - this_count + that_count > N`
1736 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1737 std::size_t this_pos,
1738 std::size_t this_count,
1740 std::size_t that_count) noexcept(false) {
1741 return *this = detail::fixedstring::Helper::replace_<Char>(
1743 detail::fixedstring::checkOverflow(this_pos, size_),
1744 detail::fixedstring::checkOverflowOrNpos(
1745 this_count, size_ - this_pos),
1753 * Replace `this_count` characters starting from position `this_pos` with
1754 * `that_count` characters `ch`.
1755 * \note Equivalent to
1756 * `replace(this_pos, this_count, BasicFixedString{that_count, ch})`
1758 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1759 std::size_t this_pos,
1760 std::size_t this_count,
1761 std::size_t that_count,
1762 Char ch) noexcept(false) {
1763 return replace(this_pos, this_count, BasicFixedString{that_count, ch});
1767 * Replace the characters denoted by the half-open range [`first`,`last`)
1768 * with `that_count` characters `ch`.
1769 * \note Equivalent to
1770 * `replace(first - data(), last - first, BasicFixedString{that_count, ch})`
1772 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1775 std::size_t that_count,
1776 Char ch) noexcept(false) {
1778 first - data_, last - first, BasicFixedString{that_count, ch});
1782 * Replace the characters denoted by the half-open range [`first`,`last`) with
1783 * the characters from the string literal `that`.
1784 * \pre `first` and `last` point to characters within this string (including
1785 * the terminating null).
1786 * \note Equivalent to
1787 * `replace(this_pos, this_count, il.begin(), il.size())`
1789 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1792 std::initializer_list<Char> il) noexcept(false) {
1793 return replace(first - data_, last - first, il.begin(), il.size());
1796 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1797 * Construct a new string by replacing `this_count` characters starting from
1798 * position `this_pos` within this string with the characters from string
1799 * `that` starting at position `that_pos`.
1800 * \pre `that_pos <= that.size()`
1801 * \note Equivalent to
1802 * <tt>creplace(this_pos, this_count, that, that_pos,
1803 * that.size() - that_pos)</tt>
1805 template <std::size_t M>
1806 constexpr BasicFixedString<Char, N + M> creplace(
1807 std::size_t this_pos,
1808 std::size_t this_count,
1809 const BasicFixedString<Char, M>& that,
1810 std::size_t that_pos = 0u) const noexcept(false) {
1816 that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_));
1820 * Construct a new string by replacing `this_count` characters starting from
1821 * position `this_pos` within this string with `that_count` characters from
1822 * string `that` starting at position `that_pos`.
1823 * \param this_pos The starting offset within `*this` of the first character
1825 * \param this_count The number of characters to be replaced. If `npos`,
1826 * it is treated as if `this_count` were `size() - this_pos`.
1827 * \param that A string that contains the replacement string.
1828 * \param that_pos The offset to the first character in the replacement
1830 * \param that_count The number of characters in the replacement string.
1831 * \pre `this_pos <= size() && this_count <= size() - this_pos`
1832 * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos`
1833 * \post The size of the returned string is `size() - this_count + that_count`
1834 * \note Equivalent to <tt>BasicFixedString<Char, N + M>{substr(0, this_pos) +
1835 * that.substr(that_pos, that_count) + substr(this_pos + this_count)}</tt>
1836 * \throw std::out_of_range on any of the following conditions:
1837 * - `this_pos > size()`
1838 * - `this_count > size() - this_pos`
1839 * - `that_pos > that.size()`
1840 * - `that_count > that.size() - that_pos`
1842 template <std::size_t M>
1843 constexpr BasicFixedString<Char, N + M> creplace(
1844 std::size_t this_pos,
1845 std::size_t this_count,
1846 const BasicFixedString<Char, M>& that,
1847 std::size_t that_pos,
1848 std::size_t that_count) const noexcept(false) {
1849 return detail::fixedstring::Helper::replace_<Char>(
1851 detail::fixedstring::checkOverflow(this_pos, size_),
1852 detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
1854 detail::fixedstring::checkOverflow(that_pos, that.size_),
1855 detail::fixedstring::checkOverflowOrNpos(
1856 that_count, that.size_ - that_pos),
1857 std::make_index_sequence<N + M>{});
1861 * Construct a new string by replacing the characters denoted by the half-open
1862 * range [`first`,`last`) within this string with the characters from string
1863 * `that` starting at position `that_pos`.
1864 * \pre `that_pos <= that.size()`
1865 * \note Equivalent to
1866 * <tt>creplace(first - data(), last - first, that, that_pos,
1867 * that.size() - that_pos)</tt>
1869 template <std::size_t M>
1870 constexpr BasicFixedString<Char, N + M> creplace(
1873 const BasicFixedString<Char, M>& that,
1874 std::size_t that_pos = 0u) const noexcept(false) {
1880 that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_));
1884 * Construct a new string by replacing the characters denoted by the half-open
1885 * range [`first`,`last`) within this string with the `that_count`
1886 * characters from string `that` starting at position `that_pos`.
1887 * \note Equivalent to
1888 * <tt>creplace(first - data(), last - first, that, that_pos,
1891 template <std::size_t M>
1892 constexpr BasicFixedString<Char, N + M> creplace(
1895 const BasicFixedString<Char, M>& that,
1896 std::size_t that_pos,
1897 std::size_t that_count) const noexcept(false) {
1898 return creplace(first - data_, last - first, that, that_pos, that_count);
1902 * Construct a new string by replacing `this_count` characters starting from
1903 * position `this_pos` within this string with `M-1` characters from
1904 * character array `that`.
1905 * \pre `strlen(that) == M-1`
1906 * \note Equivalent to
1907 * <tt>creplace(this_pos, this_count, that, 0, M - 1)</tt>
1909 template <std::size_t M>
1910 constexpr BasicFixedString<Char, N + M - 1u> creplace(
1911 std::size_t this_pos,
1912 std::size_t this_count,
1913 const Char (&that)[M]) const noexcept(false) {
1914 return creplace(this_pos, this_count, that, 0u, M - 1u);
1918 * Replace `this_count` characters starting from position `this_pos` with
1919 * `that_count` characters from the character array `that` starting at
1920 * position `that_pos`.
1921 * \param this_pos The starting offset within `*this` of the first character
1923 * \param this_count The number of characters to be replaced. If `npos`,
1924 * it is treated as if `this_count` were `size() - this_pos`.
1925 * \param that An array of characters containing the replacement string.
1926 * \param that_pos The starting offset of the replacement string.
1927 * \param that_count The number of characters in the replacement string. If
1928 * `npos`, it is treated as if `that_count` were `M - 1 - that_pos`
1929 * \pre `this_pos <= size() && this_count <= size() - this_pos`
1930 * \pre `that_pos <= M - 1 && that_count <= M - 1 - that_pos`
1931 * \post The size of the returned string is `size() - this_count + that_count`
1932 * \note Equivalent to <tt>BasicFixedString<Char, N + M - 1>{
1933 * substr(0, this_pos) +
1934 * makeFixedString(that).substr(that_pos, that_count) +
1935 * substr(this_pos + this_count)}</tt>
1936 * \throw std::out_of_range on any of the following conditions:
1937 * - `this_pos > size()`
1938 * - `this_count > size() - this_pos`
1940 * - `that_count >= M - that_pos`
1942 template <std::size_t M>
1943 constexpr BasicFixedString<Char, N + M - 1u> creplace(
1944 std::size_t this_pos,
1945 std::size_t this_count,
1946 const Char (&that)[M],
1947 std::size_t that_pos,
1948 std::size_t that_count) const noexcept(false) {
1949 return detail::fixedstring::Helper::replace_<Char>(
1951 detail::fixedstring::checkOverflow(this_pos, size_),
1952 detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
1953 detail::fixedstring::checkNullTerminated(that),
1954 detail::fixedstring::checkOverflow(that_pos, M - 1u),
1955 detail::fixedstring::checkOverflowOrNpos(that_count, M - 1u - that_pos),
1956 std::make_index_sequence<N + M - 1u>{});
1960 * Construct a new string by replacing the characters denoted by the half-open
1961 * range [`first`,`last`) within this string with the first `M-1`
1962 * characters from the character array `that`.
1963 * \pre `strlen(that) == M-1`
1964 * \note Equivalent to
1965 * <tt>creplace(first - data(), last - first, that, 0, M-1)</tt>
1967 template <std::size_t M>
1968 constexpr BasicFixedString<Char, N + M - 1u>
1969 creplace(const Char* first, const Char* last, const Char (&that)[M]) const
1971 return creplace(first - data_, last - first, that, 0u, M - 1u);
1975 * Construct a new string by replacing the characters denoted by the half-open
1976 * range [`first`,`last`) within this string with the `that_count`
1977 * characters from the character array `that` starting at position
1979 * \pre `strlen(that) == M-1`
1980 * \note Equivalent to
1981 * `creplace(first - data(), last - first, that, that_pos, that_count)`
1983 template <std::size_t M>
1984 constexpr BasicFixedString<Char, N + M - 1u> creplace(
1987 const Char (&that)[M],
1988 std::size_t that_pos,
1989 std::size_t that_count) const noexcept(false) {
1990 return creplace(first - data_, last - first, that, that_pos, that_count);
1993 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1994 * Copies `min(count, size())` characters starting from offset `0`
1995 * from this string into the buffer pointed to by `dest`.
1996 * \return The number of characters copied.
1998 FOLLY_CPP14_CONSTEXPR std::size_t copy(Char* dest, std::size_t count) const
2000 return copy(dest, count, 0u);
2004 * Copies `min(count, size() - pos)` characters starting from offset `pos`
2005 * from this string into the buffer pointed to by `dest`.
2006 * \pre `pos <= size()`
2007 * \return The number of characters copied.
2008 * \throw std::out_of_range if `pos > size()`
2010 FOLLY_CPP14_CONSTEXPR std::size_t
2011 copy(Char* dest, std::size_t count, std::size_t pos) const noexcept(false) {
2012 detail::fixedstring::checkOverflow(pos, size_);
2013 for (std::size_t i = 0u; i < count; ++i) {
2014 if (i + pos == size_)
2016 dest[i] = data_[i + pos];
2021 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2022 * Resizes the current string.
2023 * \note Equivalent to `resize(count, Char(0))`
2025 FOLLY_CPP14_CONSTEXPR void resize(std::size_t count) noexcept(false) {
2026 resize(count, Char(0));
2030 * Resizes the current string by setting the size to `count` and setting
2031 * `data()[count]` to `Char(0)`. If `count > old_size`, the characters
2032 * in the range [`old_size`,`count`) are set to `ch`.
2034 FOLLY_CPP14_CONSTEXPR void resize(std::size_t count, Char ch) noexcept(
2036 detail::fixedstring::checkOverflow(count, N);
2037 if (count == size_) {
2038 } else if (count < size_) {
2040 data_[size_] = Char(0);
2042 for (; size_ < count; ++size_) {
2045 data_[size_] = Char(0);
2049 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2050 * Finds the first occurrence of the character sequence `that` in this string.
2051 * \note Equivalent to `find(that.data(), 0, that.size())`
2053 template <std::size_t M>
2054 constexpr std::size_t find(const BasicFixedString<Char, M>& that) const
2056 return find(that, 0u);
2060 * Finds the first occurrence of the character sequence `that` in this string,
2061 * starting at offset `pos`.
2062 * \pre `pos <= size()`
2063 * \note Equivalent to `find(that.data(), pos, that.size())`
2065 template <std::size_t M>
2066 constexpr std::size_t find(
2067 const BasicFixedString<Char, M>& that,
2068 std::size_t pos) const noexcept(false) {
2069 return that.size_ <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2070 ? detail::fixedstring::find_(*this, that, pos, that.size_)
2075 * Finds the first occurrence of the character sequence `that` in this string.
2076 * \note Equivalent to `find(that.data(), 0, strlen(that))`
2078 constexpr std::size_t find(const Char* that) const noexcept {
2079 return find(that, 0u, folly::constexpr_strlen(that));
2083 * Finds the first occurrence of the character sequence `that` in this string,
2084 * starting at offset `pos`.
2085 * \pre `pos <= size()`
2086 * \note Equivalent to `find(that.data(), pos, strlen(that))`
2088 constexpr std::size_t find(const Char* that, std::size_t pos) const
2090 return find(that, pos, folly::constexpr_strlen(that));
2094 * Finds the first occurrence of the first `count` characters in the buffer
2095 * pointed to by `that` in this string, starting at offset `pos`.
2096 * \pre `pos <= size()`
2097 * \pre `that` points to a buffer containing at least `count` contiguous
2099 * \return The lowest offset `i` such that `i >= pos` and
2100 * `0 == strncmp(data() + i, that, count)`; or `npos` if there is no such
2102 * \throw std::out_of_range when `pos > size()`
2104 constexpr std::size_t find(
2107 std::size_t count) const noexcept(false) {
2108 return count <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2109 ? detail::fixedstring::find_(*this, that, pos, count)
2114 * Finds the first occurrence of the character `ch` in this string.
2115 * \note Equivalent to `find(&ch, 0, 1)`
2117 constexpr std::size_t find(Char ch) const noexcept {
2118 return find(ch, 0u);
2122 * Finds the first occurrence of the character character `c` in this string,
2123 * starting at offset `pos`.
2124 * \pre `pos <= size()`
2125 * \note Equivalent to `find(&ch, pos, 1)`
2127 constexpr std::size_t find(Char ch, std::size_t pos) const noexcept(false) {
2128 using A = const Char[1u];
2129 return 0u == size_ - detail::fixedstring::checkOverflow(pos, size_)
2131 : detail::fixedstring::find_(*this, A{ch}, pos, 1u);
2134 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2135 * Finds the last occurrence of characters in the string
2136 * `that` in this string.
2137 * \note Equivalent to `rfind(that.data(), size(), that.size())`
2139 template <std::size_t M>
2140 constexpr std::size_t rfind(const BasicFixedString<Char, M>& that) const
2142 return rfind(that, size_);
2146 * Finds the last occurrence of characters in the string
2147 * `that` in this string, starting at offset `pos`.
2148 * \note Equivalent to `rfind(that.data(), pos, that.size())`
2150 template <std::size_t M>
2151 constexpr std::size_t rfind(
2152 const BasicFixedString<Char, M>& that,
2153 std::size_t pos) const noexcept(false) {
2154 return that.size_ <= size_
2155 ? detail::fixedstring::rfind_(
2158 folly::constexpr_min(
2159 detail::fixedstring::checkOverflow(pos, size_),
2160 size_ - that.size_),
2166 * Finds the last occurrence of characters in the buffer
2167 * pointed to by `that` in this string.
2168 * \note Equivalent to `rfind(that, size(), strlen(that))`
2170 constexpr std::size_t rfind(const Char* that) const noexcept {
2171 return rfind(that, size_, folly::constexpr_strlen(that));
2175 * Finds the last occurrence of characters in the buffer
2176 * pointed to by `that` in this string, starting at offset `pos`.
2177 * \note Equivalent to `rfind(that, pos, strlen(that))`
2179 constexpr std::size_t rfind(const Char* that, std::size_t pos) const
2181 return rfind(that, pos, folly::constexpr_strlen(that));
2185 * Finds the last occurrence of the first `count` characters in the buffer
2186 * pointed to by `that` in this string, starting at offset `pos`.
2187 * \pre `pos <= size()`
2188 * \pre `that` points to a buffer containing at least `count` contiguous
2190 * \return The largest offset `i` such that `i <= pos` and
2191 * `i + count <= size()` and `0 == strncmp(data() + i, that, count)`; or
2192 * `npos` if there is no such offset `i`.
2193 * \throw std::out_of_range when `pos > size()`
2195 constexpr std::size_t rfind(
2198 std::size_t count) const noexcept(false) {
2199 return count <= size_
2200 ? detail::fixedstring::rfind_(
2203 folly::constexpr_min(
2204 detail::fixedstring::checkOverflow(pos, size_),
2211 * Finds the last occurrence of the character character `ch` in this string.
2212 * \note Equivalent to `rfind(&ch, size(), 1)`
2214 constexpr std::size_t rfind(Char ch) const noexcept {
2215 return rfind(ch, size_);
2219 * Finds the last occurrence of the character character `ch` in this string,
2220 * starting at offset `pos`.
2221 * \pre `pos <= size()`
2222 * \note Equivalent to `rfind(&ch, pos, 1)`
2224 constexpr std::size_t rfind(Char ch, std::size_t pos) const noexcept(false) {
2225 using A = const Char[1u];
2228 : detail::fixedstring::rfind_(
2231 folly::constexpr_min(
2232 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2236 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2237 * Finds the first occurrence of any character in `that` in this string.
2238 * \note Equivalent to `find_first_of(that.data(), 0, that.size())`
2240 template <std::size_t M>
2241 constexpr std::size_t find_first_of(
2242 const BasicFixedString<Char, M>& that) const noexcept {
2243 return find_first_of(that, 0u);
2247 * Finds the first occurrence of any character in `that` in this string,
2248 * starting at offset `pos`
2249 * \note Equivalent to `find_first_of(that.data(), pos, that.size())`
2251 template <std::size_t M>
2252 constexpr std::size_t find_first_of(
2253 const BasicFixedString<Char, M>& that,
2254 std::size_t pos) const noexcept(false) {
2255 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2257 : detail::fixedstring::find_first_of_(*this, that, pos, that.size_);
2261 * Finds the first occurrence of any character in the null-terminated
2262 * character sequence pointed to by `that` in this string.
2263 * \note Equivalent to `find_first_of(that, 0, strlen(that))`
2265 constexpr std::size_t find_first_of(const Char* that) const noexcept {
2266 return find_first_of(that, 0u, folly::constexpr_strlen(that));
2270 * Finds the first occurrence of any character in the null-terminated
2271 * character sequence pointed to by `that` in this string,
2272 * starting at offset `pos`
2273 * \note Equivalent to `find_first_of(that, pos, strlen(that))`
2275 constexpr std::size_t find_first_of(const Char* that, std::size_t pos) const
2277 return find_first_of(that, pos, folly::constexpr_strlen(that));
2281 * Finds the first occurrence of any character in the first `count` characters
2282 * in the buffer pointed to by `that` in this string, starting at offset
2284 * \pre `pos <= size()`
2285 * \pre `that` points to a buffer containing at least `count` contiguous
2287 * \return The smallest offset `i` such that `i >= pos` and
2288 * `std::find(that, that+count, at(i)) != that+count`; or
2289 * `npos` if there is no such offset `i`.
2290 * \throw std::out_of_range when `pos > size()`
2292 constexpr std::size_t find_first_of(
2295 std::size_t count) const noexcept(false) {
2296 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2298 : detail::fixedstring::find_first_of_(*this, that, pos, count);
2302 * Finds the first occurrence of `ch` in this string.
2303 * \note Equivalent to `find_first_of(&ch, 0, 1)`
2305 constexpr std::size_t find_first_of(Char ch) const noexcept {
2306 return find_first_of(ch, 0u);
2310 * Finds the first occurrence of `ch` in this string,
2311 * starting at offset `pos`.
2312 * \note Equivalent to `find_first_of(&ch, pos, 1)`
2314 constexpr std::size_t find_first_of(Char ch, std::size_t pos) const
2316 using A = const Char[1u];
2317 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2319 : detail::fixedstring::find_first_of_(*this, A{ch}, pos, 1u);
2322 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2323 * Finds the first occurrence of any character not in `that` in this string.
2324 * \note Equivalent to `find_first_not_of(that.data(), 0, that.size())`
2326 template <std::size_t M>
2327 constexpr std::size_t find_first_not_of(
2328 const BasicFixedString<Char, M>& that) const noexcept {
2329 return find_first_not_of(that, 0u);
2332 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2333 * Finds the first occurrence of any character not in `that` in this string.
2334 * \note Equivalent to `find_first_not_of(that.data(), 0, that.size())`
2336 template <std::size_t M>
2337 constexpr std::size_t find_first_not_of(
2338 const BasicFixedString<Char, M>& that,
2339 std::size_t pos) const noexcept(false) {
2340 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2342 : detail::fixedstring::find_first_not_of_(*this, that, pos, that.size_);
2346 * Finds the first occurrence of any character not in the null-terminated
2347 * character sequence pointed to by `that` in this string.
2348 * \note Equivalent to `find_first_not_of(that, 0, strlen(that))`
2350 constexpr std::size_t find_first_not_of(const Char* that) const noexcept {
2351 return find_first_not_of(that, 0u, folly::constexpr_strlen(that));
2355 * Finds the first occurrence of any character not in the null-terminated
2356 * character sequence pointed to by `that` in this string,
2357 * starting at offset `pos`
2358 * \note Equivalent to `find_first_not_of(that, pos, strlen(that))`
2360 constexpr std::size_t find_first_not_of(const Char* that, std::size_t pos)
2361 const noexcept(false) {
2362 return find_first_not_of(that, pos, folly::constexpr_strlen(that));
2366 * Finds the first occurrence of any character not in the first `count`
2367 * characters in the buffer pointed to by `that` in this string, starting at
2369 * \pre `pos <= size()`
2370 * \pre `that` points to a buffer containing at least `count` contiguous
2372 * \return The smallest offset `i` such that `i >= pos` and
2373 * `std::find(that, that+count, at(i)) == that+count`; or
2374 * `npos` if there is no such offset `i`.
2375 * \throw std::out_of_range when `pos > size()`
2377 constexpr std::size_t find_first_not_of(
2380 std::size_t count) const noexcept(false) {
2381 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2383 : detail::fixedstring::find_first_not_of_(*this, that, pos, count);
2387 * Finds the first occurrence of any character other than `ch` in this string.
2388 * \note Equivalent to `find_first_not_of(&ch, 0, 1)`
2390 constexpr std::size_t find_first_not_of(Char ch) const noexcept {
2391 return find_first_not_of(ch, 0u);
2395 * Finds the first occurrence of any character other than `ch` in this string,
2396 * starting at offset `pos`.
2397 * \note Equivalent to `find_first_not_of(&ch, pos, 1)`
2399 constexpr std::size_t find_first_not_of(Char ch, std::size_t pos) const
2401 using A = const Char[1u];
2402 return 1u <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2403 ? detail::fixedstring::find_first_not_of_(*this, A{ch}, pos, 1u)
2407 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2408 * Finds the last occurrence of any character in `that` in this string.
2409 * \note Equivalent to `find_last_of(that.data(), size(), that.size())`
2411 template <std::size_t M>
2412 constexpr std::size_t find_last_of(
2413 const BasicFixedString<Char, M>& that) const noexcept {
2414 return find_last_of(that, size_);
2418 * Finds the last occurrence of any character in `that` in this string,
2419 * starting at offset `pos`
2420 * \note Equivalent to `find_last_of(that.data(), pos, that.size())`
2422 template <std::size_t M>
2423 constexpr std::size_t find_last_of(
2424 const BasicFixedString<Char, M>& that,
2425 std::size_t pos) const noexcept(false) {
2428 : detail::fixedstring::find_last_of_(
2431 folly::constexpr_min(
2432 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2437 * Finds the last occurrence of any character in the null-terminated
2438 * character sequence pointed to by `that` in this string.
2439 * \note Equivalent to `find_last_of(that, size(), strlen(that))`
2441 constexpr std::size_t find_last_of(const Char* that) const noexcept {
2442 return find_last_of(that, size_, folly::constexpr_strlen(that));
2446 * Finds the last occurrence of any character in the null-terminated
2447 * character sequence pointed to by `that` in this string,
2448 * starting at offset `pos`
2449 * \note Equivalent to `find_last_of(that, pos, strlen(that))`
2451 constexpr std::size_t find_last_of(const Char* that, std::size_t pos) const
2453 return find_last_of(that, pos, folly::constexpr_strlen(that));
2457 * Finds the last occurrence of any character in the first `count` characters
2458 * in the buffer pointed to by `that` in this string, starting at offset
2460 * \pre `pos <= size()`
2461 * \pre `that` points to a buffer containing at least `count` contiguous
2463 * \return The largest offset `i` such that `i <= pos` and
2464 * `i < size()` and `std::find(that, that+count, at(i)) != that+count`; or
2465 * `npos` if there is no such offset `i`.
2466 * \throw std::out_of_range when `pos > size()`
2468 constexpr std::size_t find_last_of(
2471 std::size_t count) const noexcept(false) {
2474 : detail::fixedstring::find_last_of_(
2477 folly::constexpr_min(
2478 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2483 * Finds the last occurrence of `ch` in this string.
2484 * \note Equivalent to `find_last_of(&ch, size(), 1)`
2486 constexpr std::size_t find_last_of(Char ch) const noexcept {
2487 return find_last_of(ch, size_);
2491 * Finds the last occurrence of `ch` in this string,
2492 * starting at offset `pos`.
2493 * \note Equivalent to `find_last_of(&ch, pos, 1)`
2495 constexpr std::size_t find_last_of(Char ch, std::size_t pos) const
2497 using A = const Char[1u];
2500 : detail::fixedstring::find_last_of_(
2503 folly::constexpr_min(
2504 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2508 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2509 * Finds the last occurrence of any character not in `that` in this string.
2510 * \note Equivalent to `find_last_not_of(that.data(), size(), that.size())`
2512 template <std::size_t M>
2513 constexpr std::size_t find_last_not_of(
2514 const BasicFixedString<Char, M>& that) const noexcept {
2515 return find_last_not_of(that, size_);
2519 * Finds the last occurrence of any character not in `that` in this string,
2520 * starting at offset `pos`
2521 * \note Equivalent to `find_last_not_of(that.data(), pos, that.size())`
2523 template <std::size_t M>
2524 constexpr std::size_t find_last_not_of(
2525 const BasicFixedString<Char, M>& that,
2526 std::size_t pos) const noexcept(false) {
2529 : detail::fixedstring::find_last_not_of_(
2532 folly::constexpr_min(
2533 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2538 * Finds the last occurrence of any character not in the null-terminated
2539 * character sequence pointed to by `that` in this string.
2540 * \note Equivalent to `find_last_not_of(that, size(), strlen(that))`
2542 constexpr std::size_t find_last_not_of(const Char* that) const noexcept {
2543 return find_last_not_of(that, size_, folly::constexpr_strlen(that));
2547 * Finds the last occurrence of any character not in the null-terminated
2548 * character sequence pointed to by `that` in this string,
2549 * starting at offset `pos`
2550 * \note Equivalent to `find_last_not_of(that, pos, strlen(that))`
2552 constexpr std::size_t find_last_not_of(const Char* that, std::size_t pos)
2553 const noexcept(false) {
2554 return find_last_not_of(that, pos, folly::constexpr_strlen(that));
2558 * Finds the last occurrence of any character not in the first `count`
2559 * characters in the buffer pointed to by `that` in this string, starting at
2561 * \pre `pos <= size()`
2562 * \pre `that` points to a buffer containing at least `count` contiguous
2564 * \return The largest offset `i` such that `i <= pos` and
2565 * `i < size()` and `std::find(that, that+count, at(i)) == that+count`; or
2566 * `npos` if there is no such offset `i`.
2567 * \throw std::out_of_range when `pos > size()`
2569 constexpr std::size_t find_last_not_of(
2572 std::size_t count) const noexcept(false) {
2575 : detail::fixedstring::find_last_not_of_(
2578 folly::constexpr_min(
2579 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2584 * Finds the last occurrence of any character other than `ch` in this string.
2585 * \note Equivalent to `find_last_not_of(&ch, size(), 1)`
2587 constexpr std::size_t find_last_not_of(Char ch) const noexcept {
2588 return find_last_not_of(ch, size_);
2592 * Finds the last occurrence of any character other than `ch` in this string,
2593 * starting at offset `pos`.
2594 * \note Equivalent to `find_last_not_of(&ch, pos, 1)`
2596 constexpr std::size_t find_last_not_of(Char ch, std::size_t pos) const
2598 using A = const Char[1u];
2601 : detail::fixedstring::find_last_not_of_(
2604 folly::constexpr_min(
2605 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2609 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2610 * Asymmetric relational operators
2612 friend constexpr bool operator==(
2614 const BasicFixedString& b) noexcept {
2615 return detail::fixedstring::equal_(
2616 a, folly::constexpr_strlen(a), b, b.size());
2622 friend constexpr bool operator==(
2623 const BasicFixedString& a,
2624 const Char* b) noexcept {
2628 friend constexpr bool operator!=(
2630 const BasicFixedString& b) noexcept {
2637 friend constexpr bool operator!=(
2638 const BasicFixedString& a,
2639 const Char* b) noexcept {
2643 friend constexpr bool operator<(
2645 const BasicFixedString& b) noexcept {
2646 return detail::fixedstring::Cmp::LT ==
2647 detail::fixedstring::compare_(
2648 a, 0u, folly::constexpr_strlen(a), b, 0u, b.size_);
2654 friend constexpr bool operator<(
2655 const BasicFixedString& a,
2656 const Char* b) noexcept {
2657 return detail::fixedstring::Cmp::LT ==
2658 detail::fixedstring::compare_(
2659 a, 0u, a.size_, b, 0u, folly::constexpr_strlen(b));
2662 friend constexpr bool operator>(
2664 const BasicFixedString& b) noexcept {
2671 friend constexpr bool operator>(
2672 const BasicFixedString& a,
2673 const Char* b) noexcept {
2677 friend constexpr bool operator<=(
2679 const BasicFixedString& b) noexcept {
2686 friend constexpr bool operator<=(
2687 const BasicFixedString& a,
2688 const Char* b) noexcept {
2692 friend constexpr bool operator>=(
2694 const BasicFixedString& b) noexcept {
2701 friend constexpr bool operator>=(
2702 const BasicFixedString& a,
2703 const Char* b) noexcept {
2707 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2708 * Asymmetric concatenation
2710 template <std::size_t M>
2711 friend constexpr BasicFixedString<Char, N + M - 1u> operator+(
2713 const BasicFixedString& b) noexcept {
2714 return detail::fixedstring::Helper::concat_<Char>(
2715 detail::fixedstring::checkNullTerminated(a),
2717 std::make_index_sequence<N + M - 1u>{});
2723 template <std::size_t M>
2724 friend constexpr BasicFixedString<Char, N + M - 1u> operator+(
2725 const BasicFixedString& a,
2726 const Char (&b)[M]) noexcept {
2727 return detail::fixedstring::Helper::concat_<Char>(
2729 detail::fixedstring::checkNullTerminated(b),
2730 std::make_index_sequence<N + M - 1u>{});
2736 friend constexpr BasicFixedString<Char, N + 1u> operator+(
2738 const BasicFixedString& b) noexcept {
2739 using A = const Char[2u];
2740 return detail::fixedstring::Helper::concat_<Char>(
2741 A{a, Char(0)}, b, std::make_index_sequence<N + 1u>{});
2747 friend constexpr BasicFixedString<Char, N + 1u> operator+(
2748 const BasicFixedString& a,
2750 using A = const Char[2u];
2751 return detail::fixedstring::Helper::concat_<Char>(
2752 a, A{b, Char(0)}, std::make_index_sequence<N + 1u>{});
2756 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2757 * Symmetric relational operators
2759 template <class Char, std::size_t A, std::size_t B>
2760 constexpr bool operator==(
2761 const BasicFixedString<Char, A>& a,
2762 const BasicFixedString<Char, B>& b) noexcept {
2763 return detail::fixedstring::equal_(a, a.size(), b, b.size());
2766 template <class Char, std::size_t A, std::size_t B>
2767 constexpr bool operator!=(
2768 const BasicFixedString<Char, A>& a,
2769 const BasicFixedString<Char, B>& b) {
2773 template <class Char, std::size_t A, std::size_t B>
2774 constexpr bool operator<(
2775 const BasicFixedString<Char, A>& a,
2776 const BasicFixedString<Char, B>& b) noexcept {
2777 return detail::fixedstring::Cmp::LT ==
2778 detail::fixedstring::compare_(a, 0u, a.size(), b, 0u, b.size());
2781 template <class Char, std::size_t A, std::size_t B>
2782 constexpr bool operator>(
2783 const BasicFixedString<Char, A>& a,
2784 const BasicFixedString<Char, B>& b) noexcept {
2788 template <class Char, std::size_t A, std::size_t B>
2789 constexpr bool operator<=(
2790 const BasicFixedString<Char, A>& a,
2791 const BasicFixedString<Char, B>& b) noexcept {
2795 template <class Char, std::size_t A, std::size_t B>
2796 constexpr bool operator>=(
2797 const BasicFixedString<Char, A>& a,
2798 const BasicFixedString<Char, B>& b) noexcept {
2802 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2803 * Symmetric concatenation
2805 template <class Char, std::size_t N, std::size_t M>
2806 constexpr BasicFixedString<Char, N + M> operator+(
2807 const BasicFixedString<Char, N>& a,
2808 const BasicFixedString<Char, M>& b) noexcept {
2809 return detail::fixedstring::Helper::concat_<Char>(
2810 a, b, std::make_index_sequence<N + M>{});
2813 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2814 * Construct a `BasicFixedString` object from a null-terminated array of
2815 * characters. The capacity and size of the string will be equal to one less
2816 * than the size of the array.
2817 * \pre `a` contains no embedded null characters.
2818 * \pre `a[N-1] == Char(0)`
2819 * \post For a returned string `s`, `s[i]==a[i]` for every `i` in [`0`,`N-1`].
2821 template <class Char, std::size_t N>
2822 constexpr BasicFixedString<Char, N - 1u> makeFixedString(
2823 const Char (&a)[N]) noexcept {
2827 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2830 template <class Char, std::size_t N>
2831 FOLLY_CPP14_CONSTEXPR void swap(
2832 BasicFixedString<Char, N>& a,
2833 BasicFixedString<Char, N>& b) noexcept {
2837 inline namespace Literals {
2838 inline namespace StringLiterals {
2840 // "const std::size_t&" is so that folly::npos has the same address in every
2841 // translation unit. This is to avoid potential violations of the ODR.
2842 constexpr const std::size_t& npos = detail::fixedstring::FixedStringBase::npos;
2845 #if defined(__GNUC__)
2846 #pragma GCC diagnostic push
2847 #pragma GCC diagnostic ignored "-Wpragmas"
2848 #pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template"
2850 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
2851 * User-defined literals for creating FixedString objects from string literals
2852 * on the compilers that support it.
2857 * using namespace folly::StringLiterals;
2858 * constexpr auto hello = "hello world!"_fs;
2861 * \note This requires a GNU compiler extension
2862 * (-Wgnu-string-literal-operator-template) supported by clang and gcc,
2863 * proposed for standardization in
2864 * <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0424r0.pdf>.
2866 * For portable code, prefer the suffixes `_fs4`, `_fs8`, `_fs16`, `_fs32`,
2867 * `_fs64`, and `_fs128` for creating instances of types `FixedString<4>`,
2868 * `FixedString<8>`, `FixedString<16>`, etc.
2870 template <class Char, Char... Cs>
2871 constexpr BasicFixedString<Char, sizeof...(Cs)> operator"" _fs() noexcept {
2872 using A = const Char[sizeof...(Cs) + 1u];
2873 // The `+` in `+A{etc}` forces the array type to decay to a pointer
2874 return {+A{Cs..., Char(0)}, sizeof...(Cs)};
2877 #pragma GCC diagnostic pop
2880 #define FOLLY_DEFINE_FIXED_STRING_UDL(N) \
2881 constexpr FixedString<N> operator"" _fs##N( \
2882 const char* that, std::size_t count) noexcept(false) { \
2883 return {that, count}; \
2887 // Define UDLs _fs4, _fs8, _fs16, etc for FixedString<[4, 8, 16, ...]>
2888 FOLLY_DEFINE_FIXED_STRING_UDL(4)
2889 FOLLY_DEFINE_FIXED_STRING_UDL(8)
2890 FOLLY_DEFINE_FIXED_STRING_UDL(16)
2891 FOLLY_DEFINE_FIXED_STRING_UDL(32)
2892 FOLLY_DEFINE_FIXED_STRING_UDL(64)
2893 FOLLY_DEFINE_FIXED_STRING_UDL(128)
2895 #undef FOLLY_DEFINE_FIXED_STRING_UDL
2900 // // numeric conversions:
2901 // template <std::size_t N>
2902 // constexpr int stoi(const FixedString<N>& str, int base = 10);
2903 // template <std::size_t N>
2904 // constexpr unsigned stou(const FixedString<N>& str, int base = 10);
2905 // template <std::size_t N>
2906 // constexpr long stol(const FixedString<N>& str, int base = 10);
2907 // template <std::size_t N>
2908 // constexpr unsigned long stoul(const FixedString<N>& str, int base = 10;
2909 // template <std::size_t N>
2910 // constexpr long long stoll(const FixedString<N>& str, int base = 10);
2911 // template <std::size_t N>
2912 // constexpr unsigned long long stoull(const FixedString<N>& str,
2914 // template <std::size_t N>
2915 // constexpr float stof(const FixedString<N>& str);
2916 // template <std::size_t N>
2917 // constexpr double stod(const FixedString<N>& str);
2918 // template <std::size_t N>
2919 // constexpr long double stold(const FixedString<N>& str);
2920 // template <int val>
2921 // constexpr FixedString</*...*/> to_fixed_string_i() noexcept;
2922 // template <unsigned val>
2923 // constexpr FixedString</*...*/> to_fixed_string_u() noexcept;
2924 // template <long val>
2925 // constexpr FixedString</*...*/> to_fixed_string_l() noexcept;
2926 // template <unsigned long val>
2927 // constexpr FixedString</*...*/> to_fixed_string_ul() noexcept;
2928 // template <long long val>
2929 // constexpr FixedString</*...*/> to_fixed_string_ll() noexcept
2930 // template <unsigned long long val>
2931 // constexpr FixedString</*...*/> to_fixed_string_ull() noexcept;