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