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