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/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 // Intentionally NOT constexpr. By making this not constexpr, we make
76 // checkOverflow below ill-formed in a constexpr context when the condition
77 // it's testing for fails. In this way, precondition violations are reported
78 // at compile-time instead of at runtime.
79 [[noreturn]] inline void assertOutOfBounds() {
80 assert(false && "Array index out of bounds in BasicFixedString");
81 std::__throw_out_of_range("Array index out of bounds in BasicFixedString");
84 constexpr std::size_t checkOverflow(std::size_t i, std::size_t max) {
85 return i <= max ? i : (assertOutOfBounds(), max);
88 constexpr std::size_t checkOverflowOrNpos(std::size_t i, std::size_t max) {
89 return i == FixedStringBase::npos
91 : (i <= max ? i : (assertOutOfBounds(), max));
94 // Intentionally NOT constexpr. See note above for assertOutOfBounds
95 [[noreturn]] inline void assertNotNullTerminated() noexcept {
98 "Non-null terminated string used to initialize a BasicFixedString");
99 std::terminate(); // Fail hard, fail fast.
102 // Parsing help for human readers: the following is a constexpr noexcept
103 // function that accepts a reference to an array as a parameter and returns
104 // a reference to the same array.
105 template <class Char, std::size_t N>
106 constexpr const Char (&checkNullTerminated(const Char (&a)[N]) noexcept)[N] {
107 // Strange decltype(a)(a) used to make MSVC happy.
108 return a[N - 1u] == Char(0)
110 // In Debug mode, guard against embedded nulls:
111 && N - 1u == folly::detail::constexpr_strlen_internal(a, 0u)
114 : (assertNotNullTerminated(), decltype(a)(a));
117 enum class Cmp : int { LT = -1, EQ = 0, GT = 1 };
119 // Rather annoyingly, GCC's -Warray-bounds warning issues false positives for
120 // this code. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61971
121 #if defined(__GNUC__) && !defined(__CLANG__) && __GNUC__ <= 4
122 #pragma GCC diagnostic push
123 #pragma GCC diagnostic ignored "-Warray-bounds"
126 template <class Left, class Right>
127 constexpr Cmp compare_(
129 std::size_t left_pos,
130 std::size_t left_size,
132 std::size_t right_pos,
133 std::size_t right_size) noexcept {
134 return left_pos == left_size
135 ? (right_pos == right_size ? Cmp::EQ : Cmp::LT)
136 : (right_pos == right_size ? Cmp::GT
137 : (left[left_pos] < right[right_pos]
139 : (left[left_pos] > right[right_pos]
141 : fixedstring::compare_(
150 template <class Left, class Right>
151 constexpr bool equal_(
153 std::size_t left_size,
155 std::size_t right_size) noexcept {
156 return left_size == right_size &&
157 Cmp::EQ == compare_(left, 0u, left_size, right, 0u, right_size);
160 template <class Char, class Left, class Right>
161 constexpr Char char_at_(
163 std::size_t left_count,
165 std::size_t right_count,
166 std::size_t i) noexcept {
167 return i < left_count
169 : i < (left_count + right_count) ? right[i - left_count] : Char(0);
172 template <class Char, class Left, class Right>
173 constexpr Char char_at_(
175 std::size_t left_size,
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 ? right[i - left_pos + right_pos]
185 : (i < left_size - left_count + right_count
186 ? left[i - right_count + left_count]
190 template <class Left, class Right>
191 constexpr bool find_at_(
195 std::size_t count) noexcept {
196 return 0u == count || (left[pos + count - 1u] == right[count - 1u] &&
197 find_at_(left, right, pos, count - 1u));
200 template <class Char, class Right>
202 find_one_of_at_(Char ch, const Right& right, std::size_t pos) noexcept {
204 (ch == right[pos - 1u] || find_one_of_at_(ch, right, pos - 1u));
207 template <class Left, class Right>
208 constexpr std::size_t find_(
210 std::size_t left_size,
213 std::size_t count) noexcept {
214 return find_at_(left, right, pos, count) ? pos
215 : left_size <= pos + count
216 ? FixedStringBase::npos
217 : find_(left, left_size, right, pos + 1u, count);
220 template <class Left, class Right>
221 constexpr std::size_t rfind_(
225 std::size_t count) noexcept {
226 return find_at_(left, right, pos, count)
228 : 0u == pos ? FixedStringBase::npos
229 : rfind_(left, right, pos - 1u, count);
232 template <class Left, class Right>
233 constexpr std::size_t find_first_of_(
235 std::size_t left_size,
238 std::size_t count) noexcept {
239 return find_one_of_at_(left[pos], right, count) ? pos
240 : left_size <= pos + 1u
241 ? FixedStringBase::npos
242 : find_first_of_(left, left_size, right, pos + 1u, count);
245 template <class Left, class Right>
246 constexpr std::size_t find_first_not_of_(
248 std::size_t left_size,
251 std::size_t count) noexcept {
252 return !find_one_of_at_(left[pos], right, count) ? pos
253 : left_size <= pos + 1u
254 ? FixedStringBase::npos
255 : find_first_not_of_(left, left_size, right, pos + 1u, count);
258 template <class Left, class Right>
259 constexpr std::size_t find_last_of_(
263 std::size_t count) noexcept {
264 return find_one_of_at_(left[pos], right, count)
266 : 0u == pos ? FixedStringBase::npos
267 : find_last_of_(left, right, pos - 1u, count);
270 template <class Left, class Right>
271 constexpr std::size_t find_last_not_of_(
275 std::size_t count) noexcept {
276 return !find_one_of_at_(left[pos], right, count)
278 : 0u == pos ? FixedStringBase::npos
279 : find_last_not_of_(left, right, pos - 1u, count);
283 template <class Char, class Left, class Right, std::size_t... Is>
284 static constexpr BasicFixedString<Char, sizeof...(Is)> concat_(
286 std::size_t left_count,
288 std::size_t right_count,
289 std::index_sequence<Is...> is) noexcept {
290 return {left, left_count, right, right_count, is};
293 template <class Char, class Left, class Right, std::size_t... Is>
294 static constexpr BasicFixedString<Char, sizeof...(Is)> replace_(
296 std::size_t left_size,
297 std::size_t left_pos,
298 std::size_t left_count,
300 std::size_t right_pos,
301 std::size_t right_count,
302 std::index_sequence<Is...> is) noexcept {
313 template <class Char, std::size_t N>
314 static constexpr const Char (
315 &data_(const BasicFixedString<Char, N>& that) noexcept)[N + 1u] {
320 #if defined(__GNUC__) && !defined(__CLANG__) && __GNUC__ <= 4
321 #pragma GCC diagnostic pop
325 FOLLY_CPP14_CONSTEXPR void constexpr_swap(T& a, T& b) noexcept(
326 noexcept(a = T(std::move(a)))) {
327 T tmp((std::move(a)));
332 // FUTURE: use const_log2 to fold instantiations of BasicFixedString together.
333 // All BasicFixedString<C, N> instantiations could share the implementation
334 // of BasicFixedString<C, M>, where M is the next highest power of 2 after N.
336 // Also, because of alignment of the data_ and size_ members, N should never be
337 // smaller than `(alignof(std::size_t)/sizeof(C))-1` (-1 because of the null
338 // terminator). OR, create a specialization for BasicFixedString<C, 0u> that
339 // does not have a size_ member, since it is unnecessary.
340 constexpr std::size_t const_log2(std::size_t N, std::size_t log2 = 0u) {
341 return N / 2u == 0u ? log2 : const_log2(N / 2u, log2 + 1u);
344 // For constexpr reverse iteration over a BasicFixedString
346 struct ReverseIterator {
352 using other = typename std::conditional<
353 std::is_const<T>::value,
354 ReverseIterator<typename std::remove_const<T>::type>,
358 using value_type = typename std::remove_const<T>::type;
359 using reference = T&;
361 using difference_type = std::ptrdiff_t;
362 using iterator_category = std::random_access_iterator_tag;
364 constexpr ReverseIterator() = default;
365 constexpr ReverseIterator(const ReverseIterator&) = default;
366 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator=(const ReverseIterator&) =
368 constexpr explicit ReverseIterator(T* p) noexcept : p_(p) {}
369 constexpr /* implicit */ ReverseIterator(const other& that) noexcept
371 friend constexpr bool operator==(
373 ReverseIterator b) noexcept {
376 friend constexpr bool operator!=(
378 ReverseIterator b) noexcept {
381 constexpr reference operator*() const {
384 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator++() noexcept {
388 FOLLY_CPP14_CONSTEXPR ReverseIterator operator++(int)noexcept {
393 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator--() noexcept {
397 FOLLY_CPP14_CONSTEXPR ReverseIterator operator--(int)noexcept {
402 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator+=(std::ptrdiff_t i) noexcept {
406 friend constexpr ReverseIterator operator+(
408 ReverseIterator that) noexcept {
409 return ReverseIterator{that.p_ - i};
411 friend constexpr ReverseIterator operator+(
412 ReverseIterator that,
413 std::ptrdiff_t i) noexcept {
414 return ReverseIterator{that.p_ - i};
416 FOLLY_CPP14_CONSTEXPR ReverseIterator& operator-=(std::ptrdiff_t i) noexcept {
420 friend constexpr ReverseIterator operator-(
421 ReverseIterator that,
422 std::ptrdiff_t i) noexcept {
423 return ReverseIterator{that.p_ + i};
425 friend constexpr std::ptrdiff_t operator-(
427 ReverseIterator b) noexcept {
430 constexpr reference operator[](std::ptrdiff_t i) const noexcept {
435 } // namespace fixedstring
436 } // namespace detail
438 // Defined in folly/Range.h
439 template <class Iter>
442 // Defined in folly/Hash.h
443 std::uint32_t hsieh_hash32_buf(const void* buf, std::size_t len);
445 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
446 * \class BasicFixedString
448 * \tparam Char The character type. Must be a scalar type.
449 * \tparam N The capacity and max size of string instances of this type.
451 * \brief A class for holding up to `N` characters of type `Char` that is
452 * amenable to `constexpr` string manipulation. It is guaranteed to not
453 * perform any dynamic allocation.
455 * `BasicFixedString` is a `std::string` work-alike that stores characters in an
456 * internal buffer. It has minor interface differences that make it easy to work
457 * with strings in a `constexpr` context.
462 * constexpr auto hello = makeFixedString("hello"); // a FixedString<5>
463 * constexpr auto world = makeFixedString("world"); // a FixedString<5>
464 * constexpr auto hello_world = hello + ' ' + world + '!'; // a FixedString<12>
465 * static_assert(hello_world == "hello world!", "neato!");
468 * `FixedString<N>` is an alias for `BasicFixedString<char, N>`.
470 * \par Constexpr and In-place Mutation
472 * On a C++14 compiler, `BasicFixedString` supports the full `std::string`
473 * interface as `constexpr` member functions. On a C++11 compiler, the mutating
474 * members are not `constexpr`, but non-mutating alternatives, which create a
475 * new string, can be used instead. For example, instead of this:
478 * constexpr FixedString<10> replace_example_cpp14() {
479 * FixedString<10> test{"****"};
480 * test.replace(1, 2, "!!!!");
481 * return test; // returns "*!!!!*"
485 * You might write this instead:
488 * constexpr FixedString<10> replace_example_cpp11() {
489 * // GNU compilers have an extension that make it possible to create
490 * // FixedString objects with a `""_fs` user-defined literal.
491 * using namespace folly;
492 * return makeFixedString("****").creplace(1, 2, "!!!!"); // "*!!!!*"
496 * \par User-defined Literals
497 * Instead of using the `folly::makeFixedString` helper function, you can use
498 * a user-defined literal to make `FixedString` instances. The UDL feature of
499 * C++ has some limitations that make this less than ideal; you must tell the
500 * compiler roughly how many characters are in the string. The suffixes `_fs4`,
501 * `_fs8`, `_fs16`, `_fs32`, `_fs64`, and `_fs128` exist to create instances
502 * of types `FixedString<4>`, `FixedString<8>`, etc. For example:
505 * using namespace folly::string_literals;
506 * constexpr auto hello = "hello"_fs8; // A FixedString<8> containing "hello"
509 * See Error Handling below for what to expect when you try to exceed the
510 * capacity of a `FixedString` by storing too many characters in it.
512 * If your compiler supports GNU extensions, there is one additional suffix you
513 * can use: `_fs`. This suffix always creates `FixedString` objects of exactly
514 * the right size. For example:
517 * using namespace folly::string_literals;
518 * // NOTE: Only works on compilers with GNU extensions enabled. Clang and
519 * // gcc support this (-Wgnu-string-literal-operator-template):
520 * constexpr auto hello = "hello"_fs; // A FixedString<5> containing "hello"
523 * \par Error Handling:
524 * The capacity of a `BasicFixedString` is set at compile time. When the user
525 * asks the string to exceed its capacity, one of three things will happen,
526 * depending on the context:
528 * -# If the attempt is made while evaluating a constant expression, the
529 * program will fail to compile.
530 * -# Otherwise, if the program is being run in debug mode, it will `assert`.
531 * -# Otherwise, the failed operation will throw a `std::out_of_range`
534 * This is also the case if an invalid offset is passed to any member function,
535 * or if `pop_back` or `cpop_back` is called on an empty `BasicFixedString`.
537 * Member functions documented as having preconditions will assert in Debug
538 * mode (`!defined(NDEBUG)`) on precondition failures. Those documented with
539 * \b Throws clauses will throw the specified exception on failure. Those with
540 * both a precondition and a \b Throws clause will assert in Debug and throw
543 template <class Char, std::size_t N>
544 class BasicFixedString : private detail::fixedstring::FixedStringBase {
546 template <class, std::size_t>
547 friend class BasicFixedString;
548 friend struct detail::fixedstring::Helper;
550 Char data_[N + 1u]; // +1 for the null terminator
551 std::size_t size_; // Nbr of chars, not incl. null terminator. size_ <= N.
553 using Indices = std::make_index_sequence<N>;
555 template <class That, std::size_t... Is>
556 constexpr BasicFixedString(
559 std::index_sequence<Is...>,
561 std::size_t count = npos) noexcept
562 : data_{(Is < (size - pos) && Is < count ? that[Is + pos] : Char(0))...,
564 size_{folly::constexpr_min(size - pos, count)} {}
566 template <std::size_t... Is>
567 constexpr BasicFixedString(
570 std::index_sequence<Is...>) noexcept
571 : data_{((Is < count) ? ch : Char(0))..., Char(0)}, size_{count} {}
573 // Concatenation constructor
574 template <class Left, class Right, std::size_t... Is>
575 constexpr BasicFixedString(
577 std::size_t left_size,
579 std::size_t right_size,
580 std::index_sequence<Is...>) noexcept
581 : data_{detail::fixedstring::char_at_<Char>(
588 size_{left_size + right_size} {}
590 // Replace constructor
591 template <class Left, class Right, std::size_t... Is>
592 constexpr BasicFixedString(
594 std::size_t left_size,
595 std::size_t left_pos,
596 std::size_t left_count,
598 std::size_t right_pos,
599 std::size_t right_count,
600 std::index_sequence<Is...>) noexcept
601 : data_{detail::fixedstring::char_at_<Char>(
611 size_{left_size - left_count + right_count} {}
614 using size_type = std::size_t;
615 using difference_type = std::ptrdiff_t;
616 using reference = Char&;
617 using const_reference = const Char&;
618 using pointer = Char*;
619 using const_pointer = const Char*;
620 using iterator = Char*;
621 using const_iterator = const Char*;
622 using reverse_iterator = detail::fixedstring::ReverseIterator<Char>;
623 using const_reverse_iterator =
624 detail::fixedstring::ReverseIterator<const Char>;
626 using detail::fixedstring::FixedStringBase::npos;
628 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
630 * \post `size() == 0`
631 * \post `at(0) == Char(0)`
633 constexpr BasicFixedString() : data_{}, size_{} {}
635 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
637 * \post `size() == that.size()`
638 * \post `0 == strncmp(data(), that.data(), size())`
639 * \post `at(size()) == Char(0)`
641 constexpr BasicFixedString(const BasicFixedString& /*that*/) = default;
643 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
644 * Construct from a differently-sized BasicFixedString
645 * \pre `that.size() <= N`
646 * \post `size() == that.size()`
647 * \post `0 == strncmp(data(), that.data(), size())`
648 * \post `at(size()) == Char(0)`
649 * \throw std::out_of_range when that.size() > N. When M <= N, this
650 * constructor will never throw.
651 * \note Conversions from larger-capacity BasicFixedString objects to smaller
652 * ones (`M > N`) are allowed as long as the *size()* of the source string
655 template <std::size_t M>
656 constexpr /* implicit */ BasicFixedString(
657 const BasicFixedString<Char, M>& that) noexcept(M <= N)
658 : BasicFixedString{that, 0u, that.size_} {}
660 // Why is this deleted? To avoid confusion with the constructor that takes
661 // a const Char* and a count.
662 template <std::size_t M>
663 constexpr BasicFixedString(
664 const BasicFixedString<Char, M>& that,
665 std::size_t pos) noexcept(false) = delete;
667 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
668 * Construct from an BasicFixedString, an offset, and a count
669 * \param that The source string
670 * \param pos The starting position in `that`
671 * \param count The number of characters to copy. If `npos`, `count` is taken
672 * to be `that.size()-pos`.
673 * \pre `pos <= that.size()`
674 * \pre `count <= that.size()-pos && count <= N`
675 * \post `size() == count`
676 * \post `0 == strncmp(data(), that.data()+pos, size())`
677 * \post `at(size()) == Char(0)`
678 * \throw std::out_of_range when pos+count > that.size(), or when
681 template <std::size_t M>
682 constexpr BasicFixedString(
683 const BasicFixedString<Char, M>& that,
685 std::size_t count) noexcept(false)
689 std::make_index_sequence<(M < N ? M : N)>{},
691 detail::fixedstring::checkOverflow(
692 detail::fixedstring::checkOverflowOrNpos(
695 detail::fixedstring::checkOverflow(pos, that.size_)),
698 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
699 * Construct from a string literal
701 * \pre `that[M-1] == Char(0)`
702 * \post `0 == strncmp(data(), that, M-1)`
703 * \post `size() == M-1`
704 * \post `at(size()) == Char(0)`
706 template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
707 constexpr /* implicit */ BasicFixedString(const Char (&that)[M]) noexcept
708 : BasicFixedString{detail::fixedstring::checkNullTerminated(that),
710 std::make_index_sequence<M - 1u>{}} {}
712 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
713 * Construct from a `const Char*` and count
714 * \pre `that` points to an array of at least `count` characters.
716 * \post `size() == count`
717 * \post `0 == strncmp(data(), that, size())`
718 * \post `at(size()) == Char(0)`
719 * \throw std::out_of_range when count > N
721 constexpr BasicFixedString(const Char* that, std::size_t count) noexcept(
723 : BasicFixedString{that,
724 detail::fixedstring::checkOverflow(count, N),
727 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
728 * Construct an BasicFixedString that contains `count` characters, all
731 * \post `size() == count`
732 * \post `npos == find_first_not_of(ch)`
733 * \post `at(size()) == Char(0)`
734 * \throw std::out_of_range when count > N
736 constexpr BasicFixedString(std::size_t count, Char ch) noexcept(false)
737 : BasicFixedString{detail::fixedstring::checkOverflow(count, N),
741 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
742 * Construct an BasicFixedString from a `std::initializer_list` of
744 * \pre `il.size() <= N`
745 * \post `size() == count`
746 * \post `0 == strncmp(data(), il.begin(), size())`
747 * \post `at(size()) == Char(0)`
748 * \throw std::out_of_range when il.size() > N
750 constexpr BasicFixedString(std::initializer_list<Char> il) noexcept(false)
751 : BasicFixedString{il.begin(), il.size()} {}
753 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
754 const BasicFixedString&) noexcept = default;
756 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
757 * Assign from a `BasicFixedString<Char, M>`.
758 * \pre `that.size() <= N`
759 * \post `size() == that.size()`
760 * \post `0 == strncmp(data(), that.begin(), size())`
761 * \post `at(size()) == Char(0)`
762 * \throw std::out_of_range when that.size() > N. When M <= N, this
763 * assignment operator will never throw.
764 * \note Assignments from larger-capacity BasicFixedString objects to smaller
765 * ones (`M > N`) are allowed as long as the *size* of the source string is
769 template <std::size_t M>
770 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
771 const BasicFixedString<Char, M>& that) noexcept(M <= N) {
772 detail::fixedstring::checkOverflow(that.size_, N);
773 size_ = that.copy(data_, that.size_);
774 data_[size_] = Char(0);
778 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
779 * Assign from a null-terminated array of characters.
781 * \pre `that` has no embedded null characters
782 * \pre `that[M-1]==Char(0)`
783 * \post `size() == M-1`
784 * \post `0 == strncmp(data(), that, size())`
785 * \post `at(size()) == Char(0)`
788 template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
789 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
790 const Char (&that)[M]) noexcept {
791 return assign(detail::fixedstring::checkNullTerminated(that), M - 1u);
794 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
795 * Assign from an `initializer_list` of characters.
796 * \pre `il.size() <= N`
797 * \post `size() == il.size()`
798 * \post `0 == strncmp(data(), il.begin(), size())`
799 * \post `at(size()) == Char(0)`
800 * \throw std::out_of_range when il.size() > N
803 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator=(
804 std::initializer_list<Char> il) noexcept(false) {
805 detail::fixedstring::checkOverflow(il.size(), N);
806 for (std::size_t i = 0u; i < il.size(); ++i) {
807 data_[i] = il.begin()[i];
810 data_[size_] = Char(0);
814 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
815 * Conversion to folly::Range
816 * \return `Range<Iter>{begin(), end()}`
820 class = typename std::enable_if<
821 std::is_convertible<Char*, Iter>::value>::type>
822 FOLLY_CPP14_CONSTEXPR /* implicit */ operator Range<Iter>() noexcept {
823 return {begin(), end()};
831 class = typename std::enable_if<
832 std::is_convertible<const Char*, Iter>::value>::type>
833 constexpr /* implicit */ operator Range<Iter>() const noexcept {
834 return {begin(), end()};
837 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
838 * Conversion to folly::Range
839 * \return `Range<Char*>{begin(), end()}`
841 FOLLY_CPP14_CONSTEXPR Range<Char*> toRange() noexcept {
842 return {begin(), end()};
848 constexpr Range<const Char*> toRange() const noexcept {
849 return {begin(), end()};
852 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
853 * Conversion to std::basic_string<Char>
854 * \return `std::basic_string<Char>{begin(), end()}`
856 /* implicit */ operator std::basic_string<Char>() const noexcept(false) {
857 return std::basic_string<Char>{begin(), end()};
860 std::basic_string<Char> toStdString() const noexcept(false) {
861 return std::basic_string<Char>{begin(), end()};
864 // Think hard about whether this is a good idea. It's certainly better than
865 // an implicit conversion to `const Char*` since `delete "hi"_fs` will fail
866 // to compile. But it creates ambiguities when passing a FixedString to an
867 // API that has overloads for `const char*` and `folly::Range`, for instance.
868 // using ArrayType = Char[N];
869 // FOLLY_CPP14_CONSTEXPR /* implicit */ operator ArrayType&() noexcept {
873 // using ConstArrayType = const Char[N];
874 // constexpr /* implicit */ operator ConstArrayType&() const noexcept {
878 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
879 * Assigns a sequence of `count` characters of value `ch`.
880 * \param count The count of characters.
883 * \post `size() == count`
884 * \post `npos == find_first_not_of(ch)`
885 * \post `at(size()) == Char(0)`
886 * \throw std::out_of_range when count > N
889 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
891 Char ch) noexcept(false) {
892 detail::fixedstring::checkOverflow(count, N);
893 for (std::size_t i = 0u; i < count; ++i) {
897 data_[size_] = Char(0);
901 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
902 * Assigns characters from an `BasicFixedString` to this object.
903 * \note Equivalent to `assign(that, 0, that.size())`
905 template <std::size_t M>
906 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
907 const BasicFixedString<Char, M>& that) noexcept(M <= N) {
911 // Why is this overload deleted? So users aren't confused by the difference
912 // between str.assign("foo", N) and str.assign("foo"_fs, N). In the former,
913 // N is a count of characters. In the latter, it would be a position, which
914 // totally changes the meaning of the code.
915 template <std::size_t M>
916 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
917 const BasicFixedString<Char, M>& that,
918 std::size_t pos) noexcept(false) = delete;
920 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
921 * Assigns `count` characters from an `BasicFixedString` to this object,
922 * starting at position `pos` in the source object.
923 * \param that The source string.
924 * \param pos The starting position in the source string.
925 * \param count The number of characters to copy. If `npos`, `count` is taken
926 * to be `that.size()-pos`.
927 * \pre `pos <= that.size()`
928 * \pre `count <= that.size()-pos`
930 * \post `size() == count`
931 * \post `0 == strncmp(data(), that.begin() + pos, count)`
932 * \post `at(size()) == Char(0)`
933 * \throw std::out_of_range when pos > that.size() or count > that.size()-pos
937 template <std::size_t M>
938 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
939 const BasicFixedString<Char, M>& that,
941 std::size_t count) noexcept(false) {
942 detail::fixedstring::checkOverflow(pos, that.size_);
945 detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos));
948 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
949 * Assigns characters from an `BasicFixedString` to this object.
950 * \pre `that` contains no embedded nulls.
951 * \pre `that[M-1] == Char(0)`
952 * \note Equivalent to `assign(that, M - 1)`
954 template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
955 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
956 const Char (&that)[M]) noexcept {
957 return assign(detail::fixedstring::checkNullTerminated(that), M - 1u);
960 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
961 * Assigns `count` characters from a range of characters to this object.
962 * \param that A pointer to a range of characters.
963 * \param count The number of characters to copy.
964 * \pre `that` points to at least `count` characters.
966 * \post `size() == count`
967 * \post `0 == strncmp(data(), that, count)`
968 * \post `at(size()) == Char(0)`
969 * \throw std::out_of_range when count > N
972 FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
974 std::size_t count) noexcept(false) {
975 detail::fixedstring::checkOverflow(count, N);
976 for (std::size_t i = 0u; i < count; ++i) {
980 data_[size_] = Char(0);
984 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
985 * Swap the contents of this string with `that`.
987 FOLLY_CPP14_CONSTEXPR void swap(BasicFixedString& that) noexcept {
988 // less-than-or-equal here to copy the null terminator:
989 for (std::size_t i = 0u; i <= folly::constexpr_max(size_, that.size_);
991 detail::fixedstring::constexpr_swap(data_[i], that.data_[i]);
993 detail::fixedstring::constexpr_swap(size_, that.size_);
996 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
997 * Return a pointer to a range of `size()+1` characters, the last of which
1000 FOLLY_CPP14_CONSTEXPR Char* data() noexcept {
1007 constexpr const Char* data() const noexcept {
1011 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1014 constexpr const Char* c_str() const noexcept {
1018 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1021 FOLLY_CPP14_CONSTEXPR Char* begin() noexcept {
1028 constexpr const Char* begin() const noexcept {
1032 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1035 constexpr const Char* cbegin() const noexcept {
1039 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1040 * \return `data() + size()`.
1042 FOLLY_CPP14_CONSTEXPR Char* end() noexcept {
1043 return data_ + size_;
1049 constexpr const Char* end() const noexcept {
1050 return data_ + size_;
1053 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1054 * \return `data() + size()`.
1056 constexpr const Char* cend() const noexcept {
1060 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1061 * Returns a reverse iterator to the first character of the reversed string.
1062 * It corresponds to the last + 1 character of the non-reversed string.
1064 FOLLY_CPP14_CONSTEXPR reverse_iterator rbegin() noexcept {
1065 return reverse_iterator{data_ + size_};
1071 constexpr const_reverse_iterator rbegin() const noexcept {
1072 return const_reverse_iterator{data_ + size_};
1076 * \note Equivalent to `rbegin()` on a const-qualified reference to `*this`.
1078 constexpr const_reverse_iterator crbegin() const noexcept {
1082 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1083 * Returns a reverse iterator to the last + 1 character of the reversed
1084 * string. It corresponds to the first character of the non-reversed string.
1086 FOLLY_CPP14_CONSTEXPR reverse_iterator rend() noexcept {
1087 return reverse_iterator{data_};
1093 constexpr const_reverse_iterator rend() const noexcept {
1094 return const_reverse_iterator{data_};
1098 * \note Equivalent to `rend()` on a const-qualified reference to `*this`.
1100 constexpr const_reverse_iterator crend() const noexcept {
1105 * \return The number of `Char` elements in the string.
1107 constexpr std::size_t size() const noexcept {
1112 * \return The number of `Char` elements in the string.
1114 constexpr std::size_t length() const noexcept {
1119 * \return True if and only if `size() == 0`.
1121 constexpr bool empty() const noexcept {
1128 static constexpr std::size_t capacity() noexcept {
1135 static constexpr std::size_t max_size() noexcept {
1139 // We would need to reimplement folly::Hash to make this
1141 std::uint32_t hash() const noexcept {
1142 return folly::hsieh_hash32_buf(data_, size_);
1146 * \note `at(size())` is allowed will return `Char(0)`.
1147 * \return `*(data() + i)`
1148 * \throw std::out_of_range when i > size()
1150 FOLLY_CPP14_CONSTEXPR Char& at(std::size_t i) noexcept(false) {
1153 : (std::__throw_out_of_range("Out of range in BasicFixedString::at"),
1160 constexpr const Char& at(std::size_t i) const noexcept(false) {
1163 : (std::__throw_out_of_range("Out of range in BasicFixedString::at"),
1168 * \pre `i <= size()`
1169 * \note `(*this)[size()]` is allowed will return `Char(0)`.
1170 * \return `*(data() + i)`
1172 FOLLY_CPP14_CONSTEXPR Char& operator[](std::size_t i) noexcept {
1176 return data_[detail::fixedstring::checkOverflow(i, size_)];
1183 constexpr const Char& operator[](std::size_t i) const noexcept {
1187 return data_[detail::fixedstring::checkOverflow(i, size_)];
1192 * \note Equivalent to `(*this)[0]`
1194 FOLLY_CPP14_CONSTEXPR Char& front() noexcept {
1201 constexpr const Char& front() const noexcept {
1206 * \note Equivalent to `at(size()-1)`
1209 FOLLY_CPP14_CONSTEXPR Char& back() noexcept {
1211 return data_[size_ - 1u];
1213 return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)];
1220 constexpr const Char& back() const noexcept {
1222 return data_[size_ - 1u];
1224 return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)];
1229 * Clears the contents of this string.
1230 * \post `size() == 0u`
1231 * \post `at(size()) == Char(0)`
1233 FOLLY_CPP14_CONSTEXPR void clear() noexcept {
1234 data_[0u] = Char(0);
1239 * \note Equivalent to `append(1u, ch)`.
1241 FOLLY_CPP14_CONSTEXPR void push_back(Char ch) noexcept(false) {
1242 detail::fixedstring::checkOverflow(1u, N - size_);
1244 data_[++size_] = Char(0);
1248 * \note Equivalent to `cappend(1u, ch)`.
1250 constexpr BasicFixedString<Char, N + 1u> cpush_back(Char ch) const noexcept {
1255 * Removes the last character from the string.
1257 * \post `size()` is one fewer than before calling `pop_back()`.
1258 * \post `at(size()) == Char(0)`
1259 * \post The characters in the half-open range `[0,size()-1)` are unmodified.
1260 * \throw std::out_of_range if empty().
1262 FOLLY_CPP14_CONSTEXPR void pop_back() noexcept(false) {
1263 detail::fixedstring::checkOverflow(1u, size_);
1265 data_[size_] = Char(0);
1269 * Returns a new string with the first `size()-1` characters from this string.
1271 * \note Equivalent to `BasicFixedString<Char, N-1u>{*this, 0u, size()-1u}`
1272 * \throw std::out_of_range if empty().
1274 constexpr BasicFixedString<Char, N - 1u> cpop_back() const noexcept(false) {
1275 return {*this, 0u, size_ - detail::fixedstring::checkOverflow(1u, size_)};
1278 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1279 * Appends `count` copies of `ch` to this string.
1280 * \pre `count + old_size <= N`
1281 * \post The first `old_size` characters of the string are unmodified.
1282 * \post `size() == old_size + count`
1283 * \throw std::out_of_range if count > N - size().
1285 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1287 Char ch) noexcept(false) {
1288 detail::fixedstring::checkOverflow(count, N - size_);
1289 for (std::size_t i = 0u; i < count; ++i)
1290 data_[size_ + i] = ch;
1292 data_[size_] = Char(0);
1297 * \note Equivalent to `append(*this, 0, that.size())`.
1299 template <std::size_t M>
1300 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1301 const BasicFixedString<Char, M>& that) noexcept(false) {
1302 return append(that, 0u, that.size_);
1305 // Why is this overload deleted? So as not to get confused with
1306 // append("null-terminated", N), where N would be a count instead
1308 template <std::size_t M>
1309 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1310 const BasicFixedString<Char, M>& that,
1311 std::size_t pos) noexcept(false) = delete;
1314 * Appends `count` characters from another string to this one, starting at a
1315 * given offset, `pos`.
1316 * \param that The source string.
1317 * \param pos The starting position in the source string.
1318 * \param count The number of characters to append. If `npos`, `count` is
1319 * taken to be `that.size()-pos`.
1320 * \pre `pos <= that.size()`
1321 * \pre `count <= that.size() - pos`
1322 * \pre `old_size + count <= N`
1323 * \post The first `old_size` characters of the string are unmodified.
1324 * \post `size() == old_size + count`
1325 * \post `at(size()) == Char(0)`
1326 * \throw std::out_of_range if pos + count > that.size() or if
1327 * `old_size + count > N`.
1329 template <std::size_t M>
1330 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1331 const BasicFixedString<Char, M>& that,
1333 std::size_t count) noexcept(false) {
1334 detail::fixedstring::checkOverflow(pos, that.size_);
1335 count = detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos);
1336 detail::fixedstring::checkOverflow(count, N - size_);
1337 for (std::size_t i = 0u; i < count; ++i)
1338 data_[size_ + i] = that.data_[pos + i];
1340 data_[size_] = Char(0);
1345 * \note Equivalent to `append(that, strlen(that))`.
1347 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(const Char* that) noexcept(
1349 return append(that, folly::constexpr_strlen(that));
1353 * Appends `count` characters from the specified character array.
1354 * \pre `that` points to a range of at least `count` characters.
1355 * \pre `count + old_size <= N`
1356 * \post The first `old_size` characters of the string are unmodified.
1357 * \post `size() == old_size + count`
1358 * \post `at(size()) == Char(0)`
1359 * \throw std::out_of_range if old_size + count > N.
1361 FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1363 std::size_t count) noexcept(false) {
1364 detail::fixedstring::checkOverflow(count, N - size_);
1365 for (std::size_t i = 0u; i < count; ++i)
1366 data_[size_ + i] = that[i];
1368 data_[size_] = Char(0);
1372 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1373 * Creates a new string by appending a character to an existing string, which
1374 * is left unmodified.
1375 * \note Equivalent to `*this + ch`
1377 constexpr BasicFixedString<Char, N + 1u> cappend(Char ch) const noexcept {
1382 * Creates a new string by appending a string to an existing string, which
1383 * is left unmodified.
1384 * \note Equivalent to `*this + ch`
1386 template <std::size_t M>
1387 constexpr BasicFixedString<Char, N + M> cappend(
1388 const BasicFixedString<Char, M>& that) const noexcept {
1389 return *this + that;
1392 // Deleted to avoid confusion with append("char*", N), where N is a count
1393 // instead of a position.
1394 template <std::size_t M>
1395 constexpr BasicFixedString<Char, N + M> cappend(
1396 const BasicFixedString<Char, M>& that,
1397 std::size_t pos) const noexcept(false) = delete;
1400 * Creates a new string by appending characters from one string to another,
1401 * which is left unmodified.
1402 * \note Equivalent to `*this + that.substr(pos, count)`
1404 template <std::size_t M>
1405 constexpr BasicFixedString<Char, N + M> cappend(
1406 const BasicFixedString<Char, M>& that,
1408 std::size_t count) const noexcept(false) {
1409 return creplace(size_, 0u, that, pos, count);
1413 * Creates a new string by appending a string literal to a string,
1414 * which is left unmodified.
1415 * \note Equivalent to `*this + that`
1417 template <std::size_t M>
1418 constexpr BasicFixedString<Char, N + M - 1u> cappend(
1419 const Char (&that)[M]) const noexcept {
1420 return creplace(size_, 0u, that);
1423 // Deleted to avoid confusion with append("char*", N), where N is a count
1424 // instead of a position
1425 template <std::size_t M>
1426 constexpr BasicFixedString<Char, N + M - 1u> cappend(
1427 const Char (&that)[M],
1428 std::size_t pos) const noexcept(false) = delete;
1431 * Creates a new string by appending characters from one string to another,
1432 * which is left unmodified.
1433 * \note Equivalent to `*this + makeFixedString(that).substr(pos, count)`
1435 template <std::size_t M>
1436 constexpr BasicFixedString<Char, N + M - 1u>
1437 cappend(const Char (&that)[M], std::size_t pos, std::size_t count) const
1439 return creplace(size_, 0u, that, pos, count);
1442 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1443 * Appends characters from a null-terminated string literal to this string.
1444 * \note Equivalent to `append(that)`.
1446 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(const Char* that) noexcept(
1448 return append(that);
1452 * Appends characters from another string to this one.
1453 * \note Equivalent to `append(that)`.
1455 template <std::size_t M>
1456 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(
1457 const BasicFixedString<Char, M>& that) noexcept(false) {
1458 return append(that, 0u, that.size_);
1462 * Appends a character to this string.
1463 * \note Equivalent to `push_back(ch)`.
1465 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(Char ch) noexcept(false) {
1471 * Appends characters from an `initializer_list` to this string.
1472 * \note Equivalent to `append(il.begin(), il.size())`.
1474 FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(
1475 std::initializer_list<Char> il) noexcept(false) {
1476 return append(il.begin(), il.size());
1479 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1480 * Erase all characters from this string.
1481 * \note Equivalent to `clear()`
1484 FOLLY_CPP14_CONSTEXPR BasicFixedString& erase() noexcept {
1490 * Erases `count` characters from position `pos`. If `count` is `npos`,
1491 * erases from `pos` to the end of the string.
1492 * \pre `pos <= size()`
1493 * \pre `count <= size() - pos || count == npos`
1494 * \post `size() == old_size - min(count, old_size - pos)`
1495 * \post `at(size()) == Char(0)`
1497 * \throw std::out_of_range when pos > size().
1499 FOLLY_CPP14_CONSTEXPR BasicFixedString& erase(
1501 std::size_t count = npos) noexcept(false) {
1502 using A = const Char[1];
1505 detail::fixedstring::checkOverflowOrNpos(
1506 count, size_ - detail::fixedstring::checkOverflow(pos, size_)),
1512 * \note Equivalent to `erase(first - data(), 1)`
1513 * \return A pointer to the first character after the erased character.
1515 FOLLY_CPP14_CONSTEXPR Char* erase(const Char* first) noexcept(false) {
1516 erase(first - data_, 1u);
1517 return data_ + (first - data_);
1521 * \note Equivalent to `erase(first - data(), last - first)`
1522 * \return A pointer to the first character after the erased characters.
1524 FOLLY_CPP14_CONSTEXPR Char* erase(
1526 const Char* last) noexcept(false) {
1527 erase(first - data_, last - first);
1528 return data_ + (first - data_);
1531 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1532 * Create a new string by erasing all the characters from this string.
1533 * \note Equivalent to `BasicFixedString<Char, 0>{}`
1535 constexpr BasicFixedString<Char, 0u> cerase() const noexcept {
1540 * Create a new string by erasing all the characters after position `pos` from
1542 * \note Equivalent to `creplace(pos, min(count, pos - size()), "")`
1544 constexpr BasicFixedString cerase(std::size_t pos, std::size_t count = npos)
1545 const noexcept(false) {
1546 using A = const Char[1];
1549 detail::fixedstring::checkOverflowOrNpos(
1550 count, size_ - detail::fixedstring::checkOverflow(pos, size_)),
1554 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1555 * Compare two strings for lexicographical ordering.
1556 * \note Equivalent to
1557 * `compare(0, size(), that.data(), that.size())`
1559 template <std::size_t M>
1560 constexpr int compare(const BasicFixedString<Char, M>& that) const noexcept {
1561 return compare(0u, size_, that, 0u, that.size_);
1565 * Compare two strings for lexicographical ordering.
1566 * \note Equivalent to
1567 * `compare(this_pos, this_count, that.data(), that.size())`
1569 template <std::size_t M>
1570 constexpr int compare(
1571 std::size_t this_pos,
1572 std::size_t this_count,
1573 const BasicFixedString<Char, M>& that) const noexcept(false) {
1574 return compare(this_pos, this_count, that, 0u, that.size_);
1578 * Compare two strings for lexicographical ordering.
1579 * \note Equivalent to
1580 * `compare(this_pos, this_count, that.data() + that_pos, that_count)`
1582 template <std::size_t M>
1583 constexpr int compare(
1584 std::size_t this_pos,
1585 std::size_t this_count,
1586 const BasicFixedString<Char, M>& that,
1587 std::size_t that_pos,
1588 std::size_t that_count) const noexcept(false) {
1589 return static_cast<int>(detail::fixedstring::compare_(
1591 detail::fixedstring::checkOverflow(this_pos, size_),
1592 detail::fixedstring::checkOverflow(this_count, size_ - this_pos) +
1595 detail::fixedstring::checkOverflow(that_pos, that.size_),
1596 detail::fixedstring::checkOverflow(that_count, that.size_ - that_pos) +
1601 * Compare two strings for lexicographical ordering.
1602 * \note Equivalent to `compare(0, size(), that, strlen(that))`
1604 constexpr int compare(const Char* that) const noexcept {
1605 return compare(0u, size_, that, folly::constexpr_strlen(that));
1609 * Compare two strings for lexicographical ordering.
1610 * \note Equivalent to
1611 * `compare(this_pos, this_count, that, strlen(that))`
1613 constexpr int compare(
1614 std::size_t this_pos,
1615 std::size_t this_count,
1616 const Char* that) const noexcept(false) {
1617 return compare(this_pos, this_count, that, folly::constexpr_strlen(that));
1621 * Compare two strings for lexicographical ordering.
1623 * Let `A` be the the
1624 * character sequence {`(*this)[this_pos]`, ...
1625 * `(*this)[this_pos + this_count - 1]`}. Let `B` be the character sequence
1626 * {`that[0]`, ...`that[count - 1]`}. Then...
1629 * - `< 0` if `A` is ordered before the `B`
1630 * - `> 0` if `B` is ordered before `A`
1631 * - `0` if `A` equals `B`.
1633 * \throw std::out_of_range if this_pos + this_count > size().
1635 constexpr int compare(
1636 std::size_t this_pos,
1637 std::size_t this_count,
1639 std::size_t that_count) const noexcept(false) {
1640 return static_cast<int>(detail::fixedstring::compare_(
1642 detail::fixedstring::checkOverflow(this_pos, size_),
1643 detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos) +
1650 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1651 * Return a substring from `pos` to the end of the string.
1652 * \note Equivalent to `BasicFixedString{*this, pos}`
1654 constexpr BasicFixedString substr(std::size_t pos) const noexcept(false) {
1655 return {*this, pos};
1659 * Return a substring from `pos` to the end of the string.
1660 * \note Equivalent to `BasicFixedString{*this, pos, count}`
1662 constexpr BasicFixedString substr(std::size_t pos, std::size_t count) const
1664 return {*this, pos, count};
1667 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1668 * Replace the characters in the range denoted by the half-open range
1669 * [`first`, `last`) with the string `that`.
1670 * \pre `first` and `last` point to characters within this string (including
1671 * the terminating null).
1672 * \note Equivalent to
1673 * `replace(first - data(), last - first, that.data(), that.size())`
1675 template <std::size_t M>
1676 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1679 const BasicFixedString<Char, M>& that) noexcept(false) {
1680 return replace(first - data_, last - first, that, 0u, that.size_);
1684 * Replace `this_count` characters starting from position `this_pos` with the
1685 * characters from string `that` starting at position `that_pos`.
1686 * \pre `that_pos <= that.size()`
1687 * \note Equivalent to
1688 * <tt>replace(this_pos, this_count, that.data() + that_pos,
1689 * that.size() - that_pos)</tt>
1691 template <std::size_t M>
1692 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1693 std::size_t this_pos,
1694 std::size_t this_count,
1695 const BasicFixedString<Char, M>& that,
1696 std::size_t that_pos = 0u) noexcept(false) {
1697 return replace(this_pos, this_count, that, that_pos, that.size_ - that_pos);
1701 * Replace `this_count` characters starting from position `this_pos` with
1702 * `that_count` characters from string `that` starting at position
1704 * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos`
1705 * \note Equivalent to
1706 * `replace(this_pos, this_count, that.data() + that_pos, that_count)`
1708 template <std::size_t M>
1709 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1710 std::size_t this_pos,
1711 std::size_t this_count,
1712 const BasicFixedString<Char, M>& that,
1713 std::size_t that_pos,
1714 std::size_t that_count) noexcept(false) {
1715 return *this = creplace(this_pos, this_count, that, that_pos, that_count);
1719 * Replace `this_count` characters starting from position `this_pos` with
1720 * the characters from the string literal `that`.
1721 * \note Equivalent to
1722 * `replace(this_pos, this_count, that, strlen(that))`
1724 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1725 std::size_t this_pos,
1726 std::size_t this_count,
1727 const Char* that) noexcept(false) {
1728 return replace(this_pos, this_count, that, folly::constexpr_strlen(that));
1732 * Replace the characters denoted by the half-open range [`first`,`last`) with
1733 * the characters from the string literal `that`.
1734 * \pre `first` and `last` point to characters within this string (including
1735 * the terminating null).
1736 * \note Equivalent to
1737 * `replace(first - data(), last - first, that, strlen(that))`
1739 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1742 const Char* that) noexcept(false) {
1744 first - data_, last - first, that, folly::constexpr_strlen(that));
1748 * Replace `this_count` characters starting from position `this_pos` with
1749 * `that_count` characters from the character sequence pointed to by `that`.
1750 * \param this_pos The starting offset within `*this` of the first character
1752 * \param this_count The number of characters to be replaced. If `npos`,
1753 * it is treated as if `this_count` were `size() - this_pos`.
1754 * \param that A pointer to the replacement string.
1755 * \param that_count The number of characters in the replacement string.
1756 * \pre `this_pos <= size() && this_count <= size() - this_pos`
1757 * \pre `that` points to a contiguous sequence of at least `that_count`
1759 * \throw std::out_of_range on any of the following conditions:
1760 * - `this_pos > size()`
1761 * - `this_count > size() - this_pos`
1762 * - `size() - this_count + that_count > N`
1764 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1765 std::size_t this_pos,
1766 std::size_t this_count,
1768 std::size_t that_count) noexcept(false) {
1769 return *this = detail::fixedstring::Helper::replace_<Char>(
1772 detail::fixedstring::checkOverflow(this_pos, size_),
1773 detail::fixedstring::checkOverflowOrNpos(
1774 this_count, size_ - this_pos),
1782 * Replace `this_count` characters starting from position `this_pos` with
1783 * `that_count` characters `ch`.
1784 * \note Equivalent to
1785 * `replace(this_pos, this_count, BasicFixedString{that_count, ch})`
1787 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1788 std::size_t this_pos,
1789 std::size_t this_count,
1790 std::size_t that_count,
1791 Char ch) noexcept(false) {
1792 return replace(this_pos, this_count, BasicFixedString{that_count, ch});
1796 * Replace the characters denoted by the half-open range [`first`,`last`)
1797 * with `that_count` characters `ch`.
1798 * \note Equivalent to
1799 * `replace(first - data(), last - first, BasicFixedString{that_count, ch})`
1801 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1804 std::size_t that_count,
1805 Char ch) noexcept(false) {
1807 first - data_, last - first, BasicFixedString{that_count, ch});
1811 * Replace the characters denoted by the half-open range [`first`,`last`) with
1812 * the characters from the string literal `that`.
1813 * \pre `first` and `last` point to characters within this string (including
1814 * the terminating null).
1815 * \note Equivalent to
1816 * `replace(this_pos, this_count, il.begin(), il.size())`
1818 FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1821 std::initializer_list<Char> il) noexcept(false) {
1822 return replace(first - data_, last - first, il.begin(), il.size());
1825 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1826 * Construct a new string by replacing `this_count` characters starting from
1827 * position `this_pos` within this string with the characters from string
1828 * `that` starting at position `that_pos`.
1829 * \pre `that_pos <= that.size()`
1830 * \note Equivalent to
1831 * <tt>creplace(this_pos, this_count, that, that_pos,
1832 * that.size() - that_pos)</tt>
1834 template <std::size_t M>
1835 constexpr BasicFixedString<Char, N + M> creplace(
1836 std::size_t this_pos,
1837 std::size_t this_count,
1838 const BasicFixedString<Char, M>& that,
1839 std::size_t that_pos = 0u) const noexcept(false) {
1845 that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_));
1849 * Construct a new string by replacing `this_count` characters starting from
1850 * position `this_pos` within this string with `that_count` characters from
1851 * string `that` starting at position `that_pos`.
1852 * \param this_pos The starting offset within `*this` of the first character
1854 * \param this_count The number of characters to be replaced. If `npos`,
1855 * it is treated as if `this_count` were `size() - this_pos`.
1856 * \param that A string that contains the replacement string.
1857 * \param that_pos The offset to the first character in the replacement
1859 * \param that_count The number of characters in the replacement string.
1860 * \pre `this_pos <= size() && this_count <= size() - this_pos`
1861 * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos`
1862 * \post The size of the returned string is `size() - this_count + that_count`
1863 * \note Equivalent to <tt>BasicFixedString<Char, N + M>{substr(0, this_pos) +
1864 * that.substr(that_pos, that_count) + substr(this_pos + this_count)}</tt>
1865 * \throw std::out_of_range on any of the following conditions:
1866 * - `this_pos > size()`
1867 * - `this_count > size() - this_pos`
1868 * - `that_pos > that.size()`
1869 * - `that_count > that.size() - that_pos`
1871 template <std::size_t M>
1872 constexpr BasicFixedString<Char, N + M> creplace(
1873 std::size_t this_pos,
1874 std::size_t this_count,
1875 const BasicFixedString<Char, M>& that,
1876 std::size_t that_pos,
1877 std::size_t that_count) const noexcept(false) {
1878 return detail::fixedstring::Helper::replace_<Char>(
1881 detail::fixedstring::checkOverflow(this_pos, size_),
1882 detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
1884 detail::fixedstring::checkOverflow(that_pos, that.size_),
1885 detail::fixedstring::checkOverflowOrNpos(
1886 that_count, that.size_ - that_pos),
1887 std::make_index_sequence<N + M>{});
1891 * Construct a new string by replacing the characters denoted by the half-open
1892 * range [`first`,`last`) within this string with the characters from string
1893 * `that` starting at position `that_pos`.
1894 * \pre `that_pos <= that.size()`
1895 * \note Equivalent to
1896 * <tt>creplace(first - data(), last - first, that, that_pos,
1897 * that.size() - that_pos)</tt>
1899 template <std::size_t M>
1900 constexpr BasicFixedString<Char, N + M> creplace(
1903 const BasicFixedString<Char, M>& that,
1904 std::size_t that_pos = 0u) const noexcept(false) {
1910 that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_));
1914 * Construct a new string by replacing the characters denoted by the half-open
1915 * range [`first`,`last`) within this string with the `that_count`
1916 * characters from string `that` starting at position `that_pos`.
1917 * \note Equivalent to
1918 * <tt>creplace(first - data(), last - first, that, that_pos,
1921 template <std::size_t M>
1922 constexpr BasicFixedString<Char, N + M> creplace(
1925 const BasicFixedString<Char, M>& that,
1926 std::size_t that_pos,
1927 std::size_t that_count) const noexcept(false) {
1928 return creplace(first - data_, last - first, that, that_pos, that_count);
1932 * Construct a new string by replacing `this_count` characters starting from
1933 * position `this_pos` within this string with `M-1` characters from
1934 * character array `that`.
1935 * \pre `strlen(that) == M-1`
1936 * \note Equivalent to
1937 * <tt>creplace(this_pos, this_count, that, 0, M - 1)</tt>
1939 template <std::size_t M>
1940 constexpr BasicFixedString<Char, N + M - 1u> creplace(
1941 std::size_t this_pos,
1942 std::size_t this_count,
1943 const Char (&that)[M]) const noexcept(false) {
1944 return creplace(this_pos, this_count, that, 0u, M - 1u);
1948 * Replace `this_count` characters starting from position `this_pos` with
1949 * `that_count` characters from the character array `that` starting at
1950 * position `that_pos`.
1951 * \param this_pos The starting offset within `*this` of the first character
1953 * \param this_count The number of characters to be replaced. If `npos`,
1954 * it is treated as if `this_count` were `size() - this_pos`.
1955 * \param that An array of characters containing the replacement string.
1956 * \param that_pos The starting offset of the replacement string.
1957 * \param that_count The number of characters in the replacement string. If
1958 * `npos`, it is treated as if `that_count` were `M - 1 - that_pos`
1959 * \pre `this_pos <= size() && this_count <= size() - this_pos`
1960 * \pre `that_pos <= M - 1 && that_count <= M - 1 - that_pos`
1961 * \post The size of the returned string is `size() - this_count + that_count`
1962 * \note Equivalent to <tt>BasicFixedString<Char, N + M - 1>{
1963 * substr(0, this_pos) +
1964 * makeFixedString(that).substr(that_pos, that_count) +
1965 * substr(this_pos + this_count)}</tt>
1966 * \throw std::out_of_range on any of the following conditions:
1967 * - `this_pos > size()`
1968 * - `this_count > size() - this_pos`
1970 * - `that_count >= M - that_pos`
1972 template <std::size_t M>
1973 constexpr BasicFixedString<Char, N + M - 1u> creplace(
1974 std::size_t this_pos,
1975 std::size_t this_count,
1976 const Char (&that)[M],
1977 std::size_t that_pos,
1978 std::size_t that_count) const noexcept(false) {
1979 return detail::fixedstring::Helper::replace_<Char>(
1982 detail::fixedstring::checkOverflow(this_pos, size_),
1983 detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
1984 detail::fixedstring::checkNullTerminated(that),
1985 detail::fixedstring::checkOverflow(that_pos, M - 1u),
1986 detail::fixedstring::checkOverflowOrNpos(that_count, M - 1u - that_pos),
1987 std::make_index_sequence<N + M - 1u>{});
1991 * Construct a new string by replacing the characters denoted by the half-open
1992 * range [`first`,`last`) within this string with the first `M-1`
1993 * characters from the character array `that`.
1994 * \pre `strlen(that) == M-1`
1995 * \note Equivalent to
1996 * <tt>creplace(first - data(), last - first, that, 0, M-1)</tt>
1998 template <std::size_t M>
1999 constexpr BasicFixedString<Char, N + M - 1u>
2000 creplace(const Char* first, const Char* last, const Char (&that)[M]) const
2002 return creplace(first - data_, last - first, that, 0u, M - 1u);
2006 * Construct a new string by replacing the characters denoted by the half-open
2007 * range [`first`,`last`) within this string with the `that_count`
2008 * characters from the character array `that` starting at position
2010 * \pre `strlen(that) == M-1`
2011 * \note Equivalent to
2012 * `creplace(first - data(), last - first, that, that_pos, that_count)`
2014 template <std::size_t M>
2015 constexpr BasicFixedString<Char, N + M - 1u> creplace(
2018 const Char (&that)[M],
2019 std::size_t that_pos,
2020 std::size_t that_count) const noexcept(false) {
2021 return creplace(first - data_, last - first, that, that_pos, that_count);
2024 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2025 * Copies `min(count, size())` characters starting from offset `0`
2026 * from this string into the buffer pointed to by `dest`.
2027 * \return The number of characters copied.
2029 FOLLY_CPP14_CONSTEXPR std::size_t copy(Char* dest, std::size_t count) const
2031 return copy(dest, count, 0u);
2035 * Copies `min(count, size() - pos)` characters starting from offset `pos`
2036 * from this string into the buffer pointed to by `dest`.
2037 * \pre `pos <= size()`
2038 * \return The number of characters copied.
2039 * \throw std::out_of_range if `pos > size()`
2041 FOLLY_CPP14_CONSTEXPR std::size_t
2042 copy(Char* dest, std::size_t count, std::size_t pos) const noexcept(false) {
2043 detail::fixedstring::checkOverflow(pos, size_);
2044 for (std::size_t i = 0u; i < count; ++i) {
2045 if (i + pos == size_)
2047 dest[i] = data_[i + pos];
2052 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2053 * Resizes the current string.
2054 * \note Equivalent to `resize(count, Char(0))`
2056 FOLLY_CPP14_CONSTEXPR void resize(std::size_t count) noexcept(false) {
2057 resize(count, Char(0));
2061 * Resizes the current string by setting the size to `count` and setting
2062 * `data()[count]` to `Char(0)`. If `count > old_size`, the characters
2063 * in the range [`old_size`,`count`) are set to `ch`.
2065 FOLLY_CPP14_CONSTEXPR void resize(std::size_t count, Char ch) noexcept(
2067 detail::fixedstring::checkOverflow(count, N);
2068 if (count == size_) {
2069 } else if (count < size_) {
2071 data_[size_] = Char(0);
2073 for (; size_ < count; ++size_) {
2076 data_[size_] = Char(0);
2080 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2081 * Finds the first occurrence of the character sequence `that` in this string.
2082 * \note Equivalent to `find(that.data(), 0, that.size())`
2084 template <std::size_t M>
2085 constexpr std::size_t find(const BasicFixedString<Char, M>& that) const
2087 return find(that, 0u);
2091 * Finds the first occurrence of the character sequence `that` in this string,
2092 * starting at offset `pos`.
2093 * \pre `pos <= size()`
2094 * \note Equivalent to `find(that.data(), pos, that.size())`
2096 template <std::size_t M>
2097 constexpr std::size_t find(
2098 const BasicFixedString<Char, M>& that,
2099 std::size_t pos) const noexcept(false) {
2100 return that.size_ <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2101 ? detail::fixedstring::find_(data_, size_, that.data_, pos, that.size_)
2106 * Finds the first occurrence of the character sequence `that` in this string.
2107 * \note Equivalent to `find(that.data(), 0, strlen(that))`
2109 constexpr std::size_t find(const Char* that) const noexcept {
2110 return find(that, 0u, folly::constexpr_strlen(that));
2114 * Finds the first occurrence of the character sequence `that` in this string,
2115 * starting at offset `pos`.
2116 * \pre `pos <= size()`
2117 * \note Equivalent to `find(that.data(), pos, strlen(that))`
2119 constexpr std::size_t find(const Char* that, std::size_t pos) const
2121 return find(that, pos, folly::constexpr_strlen(that));
2125 * Finds the first occurrence of the first `count` characters in the buffer
2126 * pointed to by `that` in this string, starting at offset `pos`.
2127 * \pre `pos <= size()`
2128 * \pre `that` points to a buffer containing at least `count` contiguous
2130 * \return The lowest offset `i` such that `i >= pos` and
2131 * `0 == strncmp(data() + i, that, count)`; or `npos` if there is no such
2133 * \throw std::out_of_range when `pos > size()`
2135 constexpr std::size_t find(
2138 std::size_t count) const noexcept(false) {
2139 return count <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2140 ? detail::fixedstring::find_(data_, size_, that, pos, count)
2145 * Finds the first occurrence of the character `ch` in this string.
2146 * \note Equivalent to `find(&ch, 0, 1)`
2148 constexpr std::size_t find(Char ch) const noexcept {
2149 return find(ch, 0u);
2153 * Finds the first occurrence of the character character `c` in this string,
2154 * starting at offset `pos`.
2155 * \pre `pos <= size()`
2156 * \note Equivalent to `find(&ch, pos, 1)`
2158 constexpr std::size_t find(Char ch, std::size_t pos) const noexcept(false) {
2159 using A = const Char[1u];
2160 return 0u == size_ - detail::fixedstring::checkOverflow(pos, size_)
2162 : detail::fixedstring::find_(data_, size_, A{ch}, pos, 1u);
2165 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2166 * Finds the last occurrence of characters in the string
2167 * `that` in this string.
2168 * \note Equivalent to `rfind(that.data(), size(), that.size())`
2170 template <std::size_t M>
2171 constexpr std::size_t rfind(const BasicFixedString<Char, M>& that) const
2173 return rfind(that, size_);
2177 * Finds the last occurrence of characters in the string
2178 * `that` in this string, starting at offset `pos`.
2179 * \note Equivalent to `rfind(that.data(), pos, that.size())`
2181 template <std::size_t M>
2182 constexpr std::size_t rfind(
2183 const BasicFixedString<Char, M>& that,
2184 std::size_t pos) const noexcept(false) {
2185 return that.size_ <= size_
2186 ? detail::fixedstring::rfind_(
2189 folly::constexpr_min(
2190 detail::fixedstring::checkOverflow(pos, size_),
2191 size_ - that.size_),
2197 * Finds the last occurrence of characters in the buffer
2198 * pointed to by `that` in this string.
2199 * \note Equivalent to `rfind(that, size(), strlen(that))`
2201 constexpr std::size_t rfind(const Char* that) const noexcept {
2202 return rfind(that, size_, folly::constexpr_strlen(that));
2206 * Finds the last occurrence of characters in the buffer
2207 * pointed to by `that` in this string, starting at offset `pos`.
2208 * \note Equivalent to `rfind(that, pos, strlen(that))`
2210 constexpr std::size_t rfind(const Char* that, std::size_t pos) const
2212 return rfind(that, pos, folly::constexpr_strlen(that));
2216 * Finds the last occurrence of the first `count` characters in the buffer
2217 * pointed to by `that` in this string, starting at offset `pos`.
2218 * \pre `pos <= size()`
2219 * \pre `that` points to a buffer containing at least `count` contiguous
2221 * \return The largest offset `i` such that `i <= pos` and
2222 * `i + count <= size()` and `0 == strncmp(data() + i, that, count)`; or
2223 * `npos` if there is no such offset `i`.
2224 * \throw std::out_of_range when `pos > size()`
2226 constexpr std::size_t rfind(
2229 std::size_t count) const noexcept(false) {
2230 return count <= size_
2231 ? detail::fixedstring::rfind_(
2234 folly::constexpr_min(
2235 detail::fixedstring::checkOverflow(pos, size_),
2242 * Finds the last occurrence of the character character `ch` in this string.
2243 * \note Equivalent to `rfind(&ch, size(), 1)`
2245 constexpr std::size_t rfind(Char ch) const noexcept {
2246 return rfind(ch, size_);
2250 * Finds the last occurrence of the character character `ch` in this string,
2251 * starting at offset `pos`.
2252 * \pre `pos <= size()`
2253 * \note Equivalent to `rfind(&ch, pos, 1)`
2255 constexpr std::size_t rfind(Char ch, std::size_t pos) const noexcept(false) {
2256 using A = const Char[1u];
2259 : detail::fixedstring::rfind_(
2262 folly::constexpr_min(
2263 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2267 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2268 * Finds the first occurrence of any character in `that` in this string.
2269 * \note Equivalent to `find_first_of(that.data(), 0, that.size())`
2271 template <std::size_t M>
2272 constexpr std::size_t find_first_of(
2273 const BasicFixedString<Char, M>& that) const noexcept {
2274 return find_first_of(that, 0u);
2278 * Finds the first occurrence of any character in `that` in this string,
2279 * starting at offset `pos`
2280 * \note Equivalent to `find_first_of(that.data(), pos, that.size())`
2282 template <std::size_t M>
2283 constexpr std::size_t find_first_of(
2284 const BasicFixedString<Char, M>& that,
2285 std::size_t pos) const noexcept(false) {
2286 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2288 : detail::fixedstring::find_first_of_(
2289 data_, size_, that.data_, pos, that.size_);
2293 * Finds the first occurrence of any character in the null-terminated
2294 * character sequence pointed to by `that` in this string.
2295 * \note Equivalent to `find_first_of(that, 0, strlen(that))`
2297 constexpr std::size_t find_first_of(const Char* that) const noexcept {
2298 return find_first_of(that, 0u, folly::constexpr_strlen(that));
2302 * Finds the first occurrence of any character in the null-terminated
2303 * character sequence pointed to by `that` in this string,
2304 * starting at offset `pos`
2305 * \note Equivalent to `find_first_of(that, pos, strlen(that))`
2307 constexpr std::size_t find_first_of(const Char* that, std::size_t pos) const
2309 return find_first_of(that, pos, folly::constexpr_strlen(that));
2313 * Finds the first occurrence of any character in the first `count` characters
2314 * in the buffer pointed to by `that` in this string, starting at offset
2316 * \pre `pos <= size()`
2317 * \pre `that` points to a buffer containing at least `count` contiguous
2319 * \return The smallest offset `i` such that `i >= pos` and
2320 * `std::find(that, that+count, at(i)) != that+count`; or
2321 * `npos` if there is no such offset `i`.
2322 * \throw std::out_of_range when `pos > size()`
2324 constexpr std::size_t find_first_of(
2327 std::size_t count) const noexcept(false) {
2328 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2330 : detail::fixedstring::find_first_of_(data_, size_, that, pos, count);
2334 * Finds the first occurrence of `ch` in this string.
2335 * \note Equivalent to `find_first_of(&ch, 0, 1)`
2337 constexpr std::size_t find_first_of(Char ch) const noexcept {
2338 return find_first_of(ch, 0u);
2342 * Finds the first occurrence of `ch` in this string,
2343 * starting at offset `pos`.
2344 * \note Equivalent to `find_first_of(&ch, pos, 1)`
2346 constexpr std::size_t find_first_of(Char ch, std::size_t pos) const
2348 using A = const Char[1u];
2349 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2351 : detail::fixedstring::find_first_of_(data_, size_, A{ch}, pos, 1u);
2354 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2355 * Finds the first occurrence of any character not in `that` in this string.
2356 * \note Equivalent to `find_first_not_of(that.data(), 0, that.size())`
2358 template <std::size_t M>
2359 constexpr std::size_t find_first_not_of(
2360 const BasicFixedString<Char, M>& that) const noexcept {
2361 return find_first_not_of(that, 0u);
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,
2371 std::size_t pos) const noexcept(false) {
2372 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2374 : detail::fixedstring::find_first_not_of_(
2375 data_, size_, that.data_, pos, that.size_);
2379 * Finds the first occurrence of any character not in the null-terminated
2380 * character sequence pointed to by `that` in this string.
2381 * \note Equivalent to `find_first_not_of(that, 0, strlen(that))`
2383 constexpr std::size_t find_first_not_of(const Char* that) const noexcept {
2384 return find_first_not_of(that, 0u, folly::constexpr_strlen(that));
2388 * Finds the first occurrence of any character not in the null-terminated
2389 * character sequence pointed to by `that` in this string,
2390 * starting at offset `pos`
2391 * \note Equivalent to `find_first_not_of(that, pos, strlen(that))`
2393 constexpr std::size_t find_first_not_of(const Char* that, std::size_t pos)
2394 const noexcept(false) {
2395 return find_first_not_of(that, pos, folly::constexpr_strlen(that));
2399 * Finds the first occurrence of any character not in the first `count`
2400 * characters in the buffer pointed to by `that` in this string, starting at
2402 * \pre `pos <= size()`
2403 * \pre `that` points to a buffer containing at least `count` contiguous
2405 * \return The smallest offset `i` such that `i >= pos` and
2406 * `std::find(that, that+count, at(i)) == that+count`; or
2407 * `npos` if there is no such offset `i`.
2408 * \throw std::out_of_range when `pos > size()`
2410 constexpr std::size_t find_first_not_of(
2413 std::size_t count) const noexcept(false) {
2414 return size_ == detail::fixedstring::checkOverflow(pos, size_)
2416 : detail::fixedstring::find_first_not_of_(
2417 data_, size_, that, pos, count);
2421 * Finds the first occurrence of any character other than `ch` in this string.
2422 * \note Equivalent to `find_first_not_of(&ch, 0, 1)`
2424 constexpr std::size_t find_first_not_of(Char ch) const noexcept {
2425 return find_first_not_of(ch, 0u);
2429 * Finds the first occurrence of any character other than `ch` in this string,
2430 * starting at offset `pos`.
2431 * \note Equivalent to `find_first_not_of(&ch, pos, 1)`
2433 constexpr std::size_t find_first_not_of(Char ch, std::size_t pos) const
2435 using A = const Char[1u];
2436 return 1u <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2437 ? detail::fixedstring::find_first_not_of_(data_, size_, A{ch}, pos, 1u)
2441 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2442 * Finds the last occurrence of any character in `that` in this string.
2443 * \note Equivalent to `find_last_of(that.data(), size(), that.size())`
2445 template <std::size_t M>
2446 constexpr std::size_t find_last_of(
2447 const BasicFixedString<Char, M>& that) const noexcept {
2448 return find_last_of(that, size_);
2452 * Finds the last occurrence of any character in `that` in this string,
2453 * starting at offset `pos`
2454 * \note Equivalent to `find_last_of(that.data(), pos, that.size())`
2456 template <std::size_t M>
2457 constexpr std::size_t find_last_of(
2458 const BasicFixedString<Char, M>& that,
2459 std::size_t pos) const noexcept(false) {
2462 : detail::fixedstring::find_last_of_(
2465 folly::constexpr_min(
2466 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2471 * Finds the last occurrence of any character in the null-terminated
2472 * character sequence pointed to by `that` in this string.
2473 * \note Equivalent to `find_last_of(that, size(), strlen(that))`
2475 constexpr std::size_t find_last_of(const Char* that) const noexcept {
2476 return find_last_of(that, size_, folly::constexpr_strlen(that));
2480 * Finds the last occurrence of any character in the null-terminated
2481 * character sequence pointed to by `that` in this string,
2482 * starting at offset `pos`
2483 * \note Equivalent to `find_last_of(that, pos, strlen(that))`
2485 constexpr std::size_t find_last_of(const Char* that, std::size_t pos) const
2487 return find_last_of(that, pos, folly::constexpr_strlen(that));
2491 * Finds the last occurrence of any character in the first `count` characters
2492 * in the buffer pointed to by `that` in this string, starting at offset
2494 * \pre `pos <= size()`
2495 * \pre `that` points to a buffer containing at least `count` contiguous
2497 * \return The largest offset `i` such that `i <= pos` and
2498 * `i < size()` and `std::find(that, that+count, at(i)) != that+count`; or
2499 * `npos` if there is no such offset `i`.
2500 * \throw std::out_of_range when `pos > size()`
2502 constexpr std::size_t find_last_of(
2505 std::size_t count) const noexcept(false) {
2508 : detail::fixedstring::find_last_of_(
2511 folly::constexpr_min(
2512 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2517 * Finds the last occurrence of `ch` in this string.
2518 * \note Equivalent to `find_last_of(&ch, size(), 1)`
2520 constexpr std::size_t find_last_of(Char ch) const noexcept {
2521 return find_last_of(ch, size_);
2525 * Finds the last occurrence of `ch` in this string,
2526 * starting at offset `pos`.
2527 * \note Equivalent to `find_last_of(&ch, pos, 1)`
2529 constexpr std::size_t find_last_of(Char ch, std::size_t pos) const
2531 using A = const Char[1u];
2534 : detail::fixedstring::find_last_of_(
2537 folly::constexpr_min(
2538 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2542 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2543 * Finds the last occurrence of any character not in `that` in this string.
2544 * \note Equivalent to `find_last_not_of(that.data(), size(), that.size())`
2546 template <std::size_t M>
2547 constexpr std::size_t find_last_not_of(
2548 const BasicFixedString<Char, M>& that) const noexcept {
2549 return find_last_not_of(that, size_);
2553 * Finds the last occurrence of any character not in `that` in this string,
2554 * starting at offset `pos`
2555 * \note Equivalent to `find_last_not_of(that.data(), pos, that.size())`
2557 template <std::size_t M>
2558 constexpr std::size_t find_last_not_of(
2559 const BasicFixedString<Char, M>& that,
2560 std::size_t pos) const noexcept(false) {
2563 : detail::fixedstring::find_last_not_of_(
2566 folly::constexpr_min(
2567 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2572 * Finds the last occurrence of any character not in the null-terminated
2573 * character sequence pointed to by `that` in this string.
2574 * \note Equivalent to `find_last_not_of(that, size(), strlen(that))`
2576 constexpr std::size_t find_last_not_of(const Char* that) const noexcept {
2577 return find_last_not_of(that, size_, folly::constexpr_strlen(that));
2581 * Finds the last occurrence of any character not in the null-terminated
2582 * character sequence pointed to by `that` in this string,
2583 * starting at offset `pos`
2584 * \note Equivalent to `find_last_not_of(that, pos, strlen(that))`
2586 constexpr std::size_t find_last_not_of(const Char* that, std::size_t pos)
2587 const noexcept(false) {
2588 return find_last_not_of(that, pos, folly::constexpr_strlen(that));
2592 * Finds the last occurrence of any character not in the first `count`
2593 * characters in the buffer pointed to by `that` in this string, starting at
2595 * \pre `pos <= size()`
2596 * \pre `that` points to a buffer containing at least `count` contiguous
2598 * \return The largest offset `i` such that `i <= pos` and
2599 * `i < size()` and `std::find(that, that+count, at(i)) == that+count`; or
2600 * `npos` if there is no such offset `i`.
2601 * \throw std::out_of_range when `pos > size()`
2603 constexpr std::size_t find_last_not_of(
2606 std::size_t count) const noexcept(false) {
2609 : detail::fixedstring::find_last_not_of_(
2612 folly::constexpr_min(
2613 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2618 * Finds the last occurrence of any character other than `ch` in this string.
2619 * \note Equivalent to `find_last_not_of(&ch, size(), 1)`
2621 constexpr std::size_t find_last_not_of(Char ch) const noexcept {
2622 return find_last_not_of(ch, size_);
2626 * Finds the last occurrence of any character other than `ch` in this string,
2627 * starting at offset `pos`.
2628 * \note Equivalent to `find_last_not_of(&ch, pos, 1)`
2630 constexpr std::size_t find_last_not_of(Char ch, std::size_t pos) const
2632 using A = const Char[1u];
2635 : detail::fixedstring::find_last_not_of_(
2638 folly::constexpr_min(
2639 detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2643 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2644 * Asymmetric relational operators
2646 friend constexpr bool operator==(
2648 const BasicFixedString& b) noexcept {
2649 return detail::fixedstring::equal_(
2650 a, folly::constexpr_strlen(a), b.data_, b.size_);
2656 friend constexpr bool operator==(
2657 const BasicFixedString& a,
2658 const Char* b) noexcept {
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 {
2680 return detail::fixedstring::Cmp::LT ==
2681 detail::fixedstring::compare_(
2682 a, 0u, folly::constexpr_strlen(a), b.data_, 0u, b.size_);
2688 friend constexpr bool operator<(
2689 const BasicFixedString& a,
2690 const Char* b) noexcept {
2691 return detail::fixedstring::Cmp::LT ==
2692 detail::fixedstring::compare_(
2693 a.data_, 0u, a.size_, b, 0u, folly::constexpr_strlen(b));
2696 friend constexpr bool operator>(
2698 const BasicFixedString& b) noexcept {
2705 friend constexpr bool operator>(
2706 const BasicFixedString& a,
2707 const Char* b) noexcept {
2711 friend constexpr bool operator<=(
2713 const BasicFixedString& b) noexcept {
2720 friend constexpr bool operator<=(
2721 const BasicFixedString& a,
2722 const Char* b) noexcept {
2726 friend constexpr bool operator>=(
2728 const BasicFixedString& b) noexcept {
2735 friend constexpr bool operator>=(
2736 const BasicFixedString& a,
2737 const Char* b) noexcept {
2741 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2742 * Asymmetric concatenation
2744 template <std::size_t M>
2745 friend constexpr BasicFixedString<Char, N + M - 1u> operator+(
2747 const BasicFixedString& b) noexcept {
2748 return detail::fixedstring::Helper::concat_<Char>(
2749 detail::fixedstring::checkNullTerminated(a),
2753 std::make_index_sequence<N + M - 1u>{});
2759 template <std::size_t M>
2760 friend constexpr BasicFixedString<Char, N + M - 1u> operator+(
2761 const BasicFixedString& a,
2762 const Char (&b)[M]) noexcept {
2763 return detail::fixedstring::Helper::concat_<Char>(
2766 detail::fixedstring::checkNullTerminated(b),
2768 std::make_index_sequence<N + M - 1u>{});
2774 friend constexpr BasicFixedString<Char, N + 1u> operator+(
2776 const BasicFixedString& b) noexcept {
2777 using A = const Char[2u];
2778 return detail::fixedstring::Helper::concat_<Char>(
2783 std::make_index_sequence<N + 1u>{});
2789 friend constexpr BasicFixedString<Char, N + 1u> operator+(
2790 const BasicFixedString& a,
2792 using A = const Char[2u];
2793 return detail::fixedstring::Helper::concat_<Char>(
2798 std::make_index_sequence<N + 1u>{});
2802 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2803 * Symmetric relational operators
2805 template <class Char, std::size_t A, std::size_t B>
2806 constexpr bool operator==(
2807 const BasicFixedString<Char, A>& a,
2808 const BasicFixedString<Char, B>& b) noexcept {
2809 return detail::fixedstring::equal_(
2810 detail::fixedstring::Helper::data_(a),
2812 detail::fixedstring::Helper::data_(b),
2816 template <class Char, std::size_t A, std::size_t B>
2817 constexpr bool operator!=(
2818 const BasicFixedString<Char, A>& a,
2819 const BasicFixedString<Char, B>& b) {
2823 template <class Char, std::size_t A, std::size_t B>
2824 constexpr bool operator<(
2825 const BasicFixedString<Char, A>& a,
2826 const BasicFixedString<Char, B>& b) noexcept {
2827 return detail::fixedstring::Cmp::LT ==
2828 detail::fixedstring::compare_(
2829 detail::fixedstring::Helper::data_(a),
2832 detail::fixedstring::Helper::data_(b),
2837 template <class Char, std::size_t A, std::size_t B>
2838 constexpr bool operator>(
2839 const BasicFixedString<Char, A>& a,
2840 const BasicFixedString<Char, B>& b) noexcept {
2844 template <class Char, std::size_t A, std::size_t B>
2845 constexpr bool operator<=(
2846 const BasicFixedString<Char, A>& a,
2847 const BasicFixedString<Char, B>& b) noexcept {
2851 template <class Char, std::size_t A, std::size_t B>
2852 constexpr bool operator>=(
2853 const BasicFixedString<Char, A>& a,
2854 const BasicFixedString<Char, B>& b) noexcept {
2858 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2859 * Symmetric concatenation
2861 template <class Char, std::size_t N, std::size_t M>
2862 constexpr BasicFixedString<Char, N + M> operator+(
2863 const BasicFixedString<Char, N>& a,
2864 const BasicFixedString<Char, M>& b) noexcept {
2865 return detail::fixedstring::Helper::concat_<Char>(
2866 detail::fixedstring::Helper::data_(a),
2868 detail::fixedstring::Helper::data_(b),
2870 std::make_index_sequence<N + M>{});
2873 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2874 * Construct a `BasicFixedString` object from a null-terminated array of
2875 * characters. The capacity and size of the string will be equal to one less
2876 * than the size of the array.
2877 * \pre `a` contains no embedded null characters.
2878 * \pre `a[N-1] == Char(0)`
2879 * \post For a returned string `s`, `s[i]==a[i]` for every `i` in [`0`,`N-1`].
2881 template <class Char, std::size_t N>
2882 constexpr BasicFixedString<Char, N - 1u> makeFixedString(
2883 const Char (&a)[N]) noexcept {
2887 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2890 template <class Char, std::size_t N>
2891 FOLLY_CPP14_CONSTEXPR void swap(
2892 BasicFixedString<Char, N>& a,
2893 BasicFixedString<Char, N>& b) noexcept {
2897 inline namespace literals {
2898 inline namespace string_literals {
2900 // "const std::size_t&" is so that folly::npos has the same address in every
2901 // translation unit. This is to avoid potential violations of the ODR.
2902 constexpr const std::size_t& npos = detail::fixedstring::FixedStringBase::npos;
2905 #if defined(__GNUC__)
2906 #pragma GCC diagnostic push
2907 #pragma GCC diagnostic ignored "-Wpragmas"
2908 #pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template"
2910 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
2911 * User-defined literals for creating FixedString objects from string literals
2912 * on the compilers that support it.
2917 * using namespace folly::string_literals;
2918 * constexpr auto hello = "hello world!"_fs;
2921 * \note This requires a GNU compiler extension
2922 * (-Wgnu-string-literal-operator-template) supported by clang and gcc,
2923 * proposed for standardization in
2924 * <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0424r0.pdf>.
2926 * For portable code, prefer the suffixes `_fs4`, `_fs8`, `_fs16`, `_fs32`,
2927 * `_fs64`, and `_fs128` for creating instances of types `FixedString<4>`,
2928 * `FixedString<8>`, `FixedString<16>`, etc.
2930 template <class Char, Char... Cs>
2931 constexpr BasicFixedString<Char, sizeof...(Cs)> operator"" _fs() noexcept {
2932 using A = const Char[sizeof...(Cs) + 1u];
2933 // The `+` in `+A{etc}` forces the array type to decay to a pointer
2934 return {+A{Cs..., Char(0)}, sizeof...(Cs)};
2937 #pragma GCC diagnostic pop
2940 #define FOLLY_DEFINE_FIXED_STRING_UDL(N) \
2941 constexpr FixedString<N> operator"" _fs##N( \
2942 const char* that, std::size_t count) noexcept(false) { \
2943 return {that, count}; \
2947 // Define UDLs _fs4, _fs8, _fs16, etc for FixedString<[4, 8, 16, ...]>
2948 FOLLY_DEFINE_FIXED_STRING_UDL(4)
2949 FOLLY_DEFINE_FIXED_STRING_UDL(8)
2950 FOLLY_DEFINE_FIXED_STRING_UDL(16)
2951 FOLLY_DEFINE_FIXED_STRING_UDL(32)
2952 FOLLY_DEFINE_FIXED_STRING_UDL(64)
2953 FOLLY_DEFINE_FIXED_STRING_UDL(128)
2955 #undef FOLLY_DEFINE_FIXED_STRING_UDL
2960 // // numeric conversions:
2961 // template <std::size_t N>
2962 // constexpr int stoi(const FixedString<N>& str, int base = 10);
2963 // template <std::size_t N>
2964 // constexpr unsigned stou(const FixedString<N>& str, int base = 10);
2965 // template <std::size_t N>
2966 // constexpr long stol(const FixedString<N>& str, int base = 10);
2967 // template <std::size_t N>
2968 // constexpr unsigned long stoul(const FixedString<N>& str, int base = 10;
2969 // template <std::size_t N>
2970 // constexpr long long stoll(const FixedString<N>& str, int base = 10);
2971 // template <std::size_t N>
2972 // constexpr unsigned long long stoull(const FixedString<N>& str,
2974 // template <std::size_t N>
2975 // constexpr float stof(const FixedString<N>& str);
2976 // template <std::size_t N>
2977 // constexpr double stod(const FixedString<N>& str);
2978 // template <std::size_t N>
2979 // constexpr long double stold(const FixedString<N>& str);
2980 // template <int val>
2981 // constexpr FixedString</*...*/> to_fixed_string_i() noexcept;
2982 // template <unsigned val>
2983 // constexpr FixedString</*...*/> to_fixed_string_u() noexcept;
2984 // template <long val>
2985 // constexpr FixedString</*...*/> to_fixed_string_l() noexcept;
2986 // template <unsigned long val>
2987 // constexpr FixedString</*...*/> to_fixed_string_ul() noexcept;
2988 // template <long long val>
2989 // constexpr FixedString</*...*/> to_fixed_string_ll() noexcept
2990 // template <unsigned long long val>
2991 // constexpr FixedString</*...*/> to_fixed_string_ull() noexcept;