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