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