Stop using ScopeGuardImpl in DynamicParser
[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/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<Char*>{begin(), end()}`
796    */
797   FOLLY_CPP14_CONSTEXPR Range<Char*> toRange() noexcept {
798     return {begin(), end()};
799   }
800
801   /**
802    * \overload
803    */
804   constexpr Range<const Char*> toRange() const noexcept {
805     return {begin(), end()};
806   }
807
808   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
809    * Conversion to std::basic_string<Char>
810    * \return `std::basic_string<Char>{begin(), end()}`
811    */
812   /* implicit */ operator std::basic_string<Char>() const noexcept(false) {
813     return std::basic_string<Char>{begin(), end()};
814   }
815
816   std::basic_string<Char> toStdString() const noexcept(false) {
817     return std::basic_string<Char>{begin(), end()};
818   }
819
820   // Think hard about whether this is a good idea. It's certainly better than
821   // an implicit conversion to `const Char*` since `delete "hi"_fs` will fail
822   // to compile. But it creates ambiguities when passing a FixedString to an
823   // API that has overloads for `const char*` and `folly::Range`, for instance.
824   // using ArrayType = Char[N];
825   // FOLLY_CPP14_CONSTEXPR /* implicit */ operator ArrayType&() noexcept {
826   //   return data_;
827   // }
828
829   // using ConstArrayType = const Char[N];
830   // constexpr /* implicit */ operator ConstArrayType&() const noexcept {
831   //   return data_;
832   // }
833
834   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
835    * Assigns a sequence of `count` characters of value `ch`.
836    * \param count The count of characters.
837    * \param ch
838    * \pre `count <= N`
839    * \post `size() == count`
840    * \post `npos == find_first_not_of(ch)`
841    * \post `at(size()) == Char(0)`
842    * \throw std::out_of_range when count > N
843    * \return `*this`
844    */
845   FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
846       std::size_t count,
847       Char ch) noexcept(false) {
848     detail::fixedstring::checkOverflow(count, N);
849     for (std::size_t i = 0u; i < count; ++i) {
850       data_[i] = ch;
851     }
852     size_ = count;
853     data_[size_] = Char(0);
854     return *this;
855   }
856
857   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
858    * Assigns characters from an `BasicFixedString` to this object.
859    * \note Equivalent to `assign(that, 0, that.size())`
860    */
861   template <std::size_t M>
862   FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
863       const BasicFixedString<Char, M>& that) noexcept(M <= N) {
864     return *this = that;
865   }
866
867   // Why is this overload deleted? So users aren't confused by the difference
868   // between str.assign("foo", N) and str.assign("foo"_fs, N). In the former,
869   // N is a count of characters. In the latter, it would be a position, which
870   // totally changes the meaning of the code.
871   template <std::size_t M>
872   FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
873       const BasicFixedString<Char, M>& that,
874       std::size_t pos) noexcept(false) = delete;
875
876   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
877    * Assigns `count` characters from an `BasicFixedString` to this object,
878    *   starting at position `pos` in the source object.
879    * \param that The source string.
880    * \param pos The starting position in the source string.
881    * \param count The number of characters to copy. If `npos`, `count` is taken
882    *              to be `that.size()-pos`.
883    * \pre `pos <= that.size()`
884    * \pre `count <= that.size()-pos`
885    * \pre `count <= N`
886    * \post `size() == count`
887    * \post `0 == strncmp(data(), that.begin() + pos, count)`
888    * \post `at(size()) == Char(0)`
889    * \throw std::out_of_range when pos > that.size() or count > that.size()-pos
890    *        or count > N.
891    * \return `*this`
892    */
893   template <std::size_t M>
894   FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
895       const BasicFixedString<Char, M>& that,
896       std::size_t pos,
897       std::size_t count) noexcept(false) {
898     detail::fixedstring::checkOverflow(pos, that.size_);
899     return assign(
900         that.data_ + pos,
901         detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos));
902   }
903
904   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
905    * Assigns characters from an `BasicFixedString` to this object.
906    * \pre `that` contains no embedded nulls.
907    * \pre `that[M-1] == Char(0)`
908    * \note Equivalent to `assign(that, M - 1)`
909    */
910   template <std::size_t M, class = typename std::enable_if<(M - 1u <= N)>::type>
911   FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
912       const Char (&that)[M]) noexcept {
913     return assign(detail::fixedstring::checkNullTerminated(that), M - 1u);
914   }
915
916   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
917    * Assigns `count` characters from a range of characters to this object.
918    * \param that A pointer to a range of characters.
919    * \param count The number of characters to copy.
920    * \pre `that` points to at least `count` characters.
921    * \pre `count <= N`
922    * \post `size() == count`
923    * \post `0 == strncmp(data(), that, count)`
924    * \post `at(size()) == Char(0)`
925    * \throw std::out_of_range when count > N
926    * \return `*this`
927    */
928   FOLLY_CPP14_CONSTEXPR BasicFixedString& assign(
929       const Char* that,
930       std::size_t count) noexcept(false) {
931     detail::fixedstring::checkOverflow(count, N);
932     for (std::size_t i = 0u; i < count; ++i) {
933       data_[i] = that[i];
934     }
935     size_ = count;
936     data_[size_] = Char(0);
937     return *this;
938   }
939
940   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
941    * Swap the contents of this string with `that`.
942    */
943   FOLLY_CPP14_CONSTEXPR void swap(BasicFixedString& that) noexcept {
944     // less-than-or-equal here to copy the null terminator:
945     for (std::size_t i = 0u; i <= folly::constexpr_max(size_, that.size_);
946          ++i) {
947       detail::fixedstring::constexpr_swap(data_[i], that.data_[i]);
948     }
949     detail::fixedstring::constexpr_swap(size_, that.size_);
950   }
951
952   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
953    * Return a pointer to a range of `size()+1` characters, the last of which
954    * is `Char(0)`.
955    */
956   FOLLY_CPP14_CONSTEXPR Char* data() noexcept {
957     return data_;
958   }
959
960   /**
961    * \overload
962    */
963   constexpr const Char* data() const noexcept {
964     return data_;
965   }
966
967   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
968    * \return `data()`.
969    */
970   constexpr const Char* c_str() const noexcept {
971     return data_;
972   }
973
974   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
975    * \return `data()`.
976    */
977   FOLLY_CPP14_CONSTEXPR Char* begin() noexcept {
978     return data_;
979   }
980
981   /**
982    * \overload
983    */
984   constexpr const Char* begin() const noexcept {
985     return data_;
986   }
987
988   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
989    * \return `data()`.
990    */
991   constexpr const Char* cbegin() const noexcept {
992     return begin();
993   }
994
995   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
996    * \return `data() + size()`.
997    */
998   FOLLY_CPP14_CONSTEXPR Char* end() noexcept {
999     return data_ + size_;
1000   }
1001
1002   /**
1003    * \overload
1004    */
1005   constexpr const Char* end() const noexcept {
1006     return data_ + size_;
1007   }
1008
1009   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1010    * \return `data() + size()`.
1011    */
1012   constexpr const Char* cend() const noexcept {
1013     return end();
1014   }
1015
1016   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1017    * Returns a reverse iterator to the first character of the reversed string.
1018    * It corresponds to the last + 1 character of the non-reversed string.
1019    */
1020   FOLLY_CPP14_CONSTEXPR reverse_iterator rbegin() noexcept {
1021     return reverse_iterator{data_ + size_};
1022   }
1023
1024   /**
1025    * \overload
1026    */
1027   constexpr const_reverse_iterator rbegin() const noexcept {
1028     return const_reverse_iterator{data_ + size_};
1029   }
1030
1031   /**
1032    * \note Equivalent to `rbegin()` on a const-qualified reference to `*this`.
1033    */
1034   constexpr const_reverse_iterator crbegin() const noexcept {
1035     return rbegin();
1036   }
1037
1038   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1039    * Returns a reverse iterator to the last + 1 character of the reversed
1040    * string. It corresponds to the first character of the non-reversed string.
1041    */
1042   FOLLY_CPP14_CONSTEXPR reverse_iterator rend() noexcept {
1043     return reverse_iterator{data_};
1044   }
1045
1046   /**
1047    * \overload
1048    */
1049   constexpr const_reverse_iterator rend() const noexcept {
1050     return const_reverse_iterator{data_};
1051   }
1052
1053   /**
1054    * \note Equivalent to `rend()` on a const-qualified reference to `*this`.
1055    */
1056   constexpr const_reverse_iterator crend() const noexcept {
1057     return rend();
1058   }
1059
1060   /**
1061    * \return The number of `Char` elements in the string.
1062    */
1063   constexpr std::size_t size() const noexcept {
1064     return size_;
1065   }
1066
1067   /**
1068    * \return The number of `Char` elements in the string.
1069    */
1070   constexpr std::size_t length() const noexcept {
1071     return size_;
1072   }
1073
1074   /**
1075    * \return True if and only if `size() == 0`.
1076    */
1077   constexpr bool empty() const noexcept {
1078     return 0u == size_;
1079   }
1080
1081   /**
1082    * \return `N`.
1083    */
1084   static constexpr std::size_t capacity() noexcept {
1085     return N;
1086   }
1087
1088   /**
1089    * \return `N`.
1090    */
1091   static constexpr std::size_t max_size() noexcept {
1092     return N;
1093   }
1094
1095   // We would need to reimplement folly::Hash to make this
1096   // constexpr. :-(
1097   std::uint32_t hash() const noexcept {
1098     return folly::hsieh_hash32_buf(data_, size_);
1099   }
1100
1101   /**
1102    * \note `at(size())` is allowed will return `Char(0)`.
1103    * \return `*(data() + i)`
1104    * \throw std::out_of_range when i > size()
1105    */
1106   FOLLY_CPP14_CONSTEXPR Char& at(std::size_t i) noexcept(false) {
1107     return i <= size_
1108         ? data_[i]
1109         : (std::__throw_out_of_range("Out of range in BasicFixedString::at"),
1110            data_[size_]);
1111   }
1112
1113   /**
1114    * \overload
1115    */
1116   constexpr const Char& at(std::size_t i) const noexcept(false) {
1117     return i <= size_
1118         ? data_[i]
1119         : (std::__throw_out_of_range("Out of range in BasicFixedString::at"),
1120            data_[size_]);
1121   }
1122
1123   /**
1124    * \pre `i <= size()`
1125    * \note `(*this)[size()]` is allowed will return `Char(0)`.
1126    * \return `*(data() + i)`
1127    */
1128   FOLLY_CPP14_CONSTEXPR Char& operator[](std::size_t i) noexcept {
1129 #ifdef NDEBUG
1130     return data_[i];
1131 #else
1132     return data_[detail::fixedstring::checkOverflow(i, size_)];
1133 #endif
1134   }
1135
1136   /**
1137    * \overload
1138    */
1139   constexpr const Char& operator[](std::size_t i) const noexcept {
1140 #ifdef NDEBUG
1141     return data_[i];
1142 #else
1143     return data_[detail::fixedstring::checkOverflow(i, size_)];
1144 #endif
1145   }
1146
1147   /**
1148    * \note Equivalent to `(*this)[0]`
1149    */
1150   FOLLY_CPP14_CONSTEXPR Char& front() noexcept {
1151     return (*this)[0u];
1152   }
1153
1154   /**
1155    * \overload
1156    */
1157   constexpr const Char& front() const noexcept {
1158     return (*this)[0u];
1159   }
1160
1161   /**
1162    * \note Equivalent to `at(size()-1)`
1163    * \pre `!empty()`
1164    */
1165   FOLLY_CPP14_CONSTEXPR Char& back() noexcept {
1166 #ifdef NDEBUG
1167     return data_[size_ - 1u];
1168 #else
1169     return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)];
1170 #endif
1171   }
1172
1173   /**
1174    * \overload
1175    */
1176   constexpr const Char& back() const noexcept {
1177 #ifdef NDEBUG
1178     return data_[size_ - 1u];
1179 #else
1180     return data_[size_ - detail::fixedstring::checkOverflow(1u, size_)];
1181 #endif
1182   }
1183
1184   /**
1185    * Clears the contents of this string.
1186    * \post `size() == 0u`
1187    * \post `at(size()) == Char(0)`
1188    */
1189   FOLLY_CPP14_CONSTEXPR void clear() noexcept {
1190     data_[0u] = Char(0);
1191     size_ = 0u;
1192   }
1193
1194   /**
1195    * \note Equivalent to `append(1u, ch)`.
1196    */
1197   FOLLY_CPP14_CONSTEXPR void push_back(Char ch) noexcept(false) {
1198     detail::fixedstring::checkOverflow(1u, N - size_);
1199     data_[size_] = ch;
1200     data_[++size_] = Char(0);
1201   }
1202
1203   /**
1204    * \note Equivalent to `cappend(1u, ch)`.
1205    */
1206   constexpr BasicFixedString<Char, N + 1u> cpush_back(Char ch) const noexcept {
1207     return cappend(ch);
1208   }
1209
1210   /**
1211    * Removes the last character from the string.
1212    * \pre `!empty()`
1213    * \post `size()` is one fewer than before calling `pop_back()`.
1214    * \post `at(size()) == Char(0)`
1215    * \post The characters in the half-open range `[0,size()-1)` are unmodified.
1216    * \throw std::out_of_range if empty().
1217    */
1218   FOLLY_CPP14_CONSTEXPR void pop_back() noexcept(false) {
1219     detail::fixedstring::checkOverflow(1u, size_);
1220     --size_;
1221     data_[size_] = Char(0);
1222   }
1223
1224   /**
1225    * Returns a new string with the first `size()-1` characters from this string.
1226    * \pre `!empty()`
1227    * \note Equivalent to `BasicFixedString<Char, N-1u>{*this, 0u, size()-1u}`
1228    * \throw std::out_of_range if empty().
1229    */
1230   constexpr BasicFixedString<Char, N - 1u> cpop_back() const noexcept(false) {
1231     return {*this, 0u, size_ - detail::fixedstring::checkOverflow(1u, size_)};
1232   }
1233
1234   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1235    * Appends `count` copies of `ch` to this string.
1236    * \pre `count + old_size <= N`
1237    * \post The first `old_size` characters of the string are unmodified.
1238    * \post `size() == old_size + count`
1239    * \throw std::out_of_range if count > N - size().
1240    */
1241   FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1242       std::size_t count,
1243       Char ch) noexcept(false) {
1244     detail::fixedstring::checkOverflow(count, N - size_);
1245     for (std::size_t i = 0u; i < count; ++i) {
1246       data_[size_ + i] = ch;
1247     }
1248     size_ += count;
1249     data_[size_] = Char(0);
1250     return *this;
1251   }
1252
1253   /**
1254    * \note Equivalent to `append(*this, 0, that.size())`.
1255    */
1256   template <std::size_t M>
1257   FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1258       const BasicFixedString<Char, M>& that) noexcept(false) {
1259     return append(that, 0u, that.size_);
1260   }
1261
1262   // Why is this overload deleted? So as not to get confused with
1263   // append("null-terminated", N), where N would be a count instead
1264   // of a position.
1265   template <std::size_t M>
1266   FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1267       const BasicFixedString<Char, M>& that,
1268       std::size_t pos) noexcept(false) = delete;
1269
1270   /**
1271    * Appends `count` characters from another string to this one, starting at a
1272    * given offset, `pos`.
1273    * \param that The source string.
1274    * \param pos The starting position in the source string.
1275    * \param count The number of characters to append. If `npos`, `count` is
1276    *              taken to be `that.size()-pos`.
1277    * \pre `pos <= that.size()`
1278    * \pre `count <= that.size() - pos`
1279    * \pre `old_size + count <= N`
1280    * \post The first `old_size` characters of the string are unmodified.
1281    * \post `size() == old_size + count`
1282    * \post `at(size()) == Char(0)`
1283    * \throw std::out_of_range if pos + count > that.size() or if
1284    *        `old_size + count > N`.
1285    */
1286   template <std::size_t M>
1287   FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1288       const BasicFixedString<Char, M>& that,
1289       std::size_t pos,
1290       std::size_t count) noexcept(false) {
1291     detail::fixedstring::checkOverflow(pos, that.size_);
1292     count = detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos);
1293     detail::fixedstring::checkOverflow(count, N - size_);
1294     for (std::size_t i = 0u; i < count; ++i) {
1295       data_[size_ + i] = that.data_[pos + i];
1296     }
1297     size_ += count;
1298     data_[size_] = Char(0);
1299     return *this;
1300   }
1301
1302   /**
1303    * \note Equivalent to `append(that, strlen(that))`.
1304    */
1305   FOLLY_CPP14_CONSTEXPR BasicFixedString& append(const Char* that) noexcept(
1306       false) {
1307     return append(that, folly::constexpr_strlen(that));
1308   }
1309
1310   /**
1311    * Appends `count` characters from the specified character array.
1312    * \pre `that` points to a range of at least `count` characters.
1313    * \pre `count + old_size <= N`
1314    * \post The first `old_size` characters of the string are unmodified.
1315    * \post `size() == old_size + count`
1316    * \post `at(size()) == Char(0)`
1317    * \throw std::out_of_range if old_size + count > N.
1318    */
1319   FOLLY_CPP14_CONSTEXPR BasicFixedString& append(
1320       const Char* that,
1321       std::size_t count) noexcept(false) {
1322     detail::fixedstring::checkOverflow(count, N - size_);
1323     for (std::size_t i = 0u; i < count; ++i) {
1324       data_[size_ + i] = that[i];
1325     }
1326     size_ += count;
1327     data_[size_] = Char(0);
1328     return *this;
1329   }
1330
1331   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1332    * Creates a new string by appending a character to an existing string, which
1333    *   is left unmodified.
1334    * \note Equivalent to `*this + ch`
1335    */
1336   constexpr BasicFixedString<Char, N + 1u> cappend(Char ch) const noexcept {
1337     return *this + ch;
1338   }
1339
1340   /**
1341    * Creates a new string by appending a string to an existing string, which
1342    *   is left unmodified.
1343    * \note Equivalent to `*this + ch`
1344    */
1345   template <std::size_t M>
1346   constexpr BasicFixedString<Char, N + M> cappend(
1347       const BasicFixedString<Char, M>& that) const noexcept {
1348     return *this + that;
1349   }
1350
1351   // Deleted to avoid confusion with append("char*", N), where N is a count
1352   // instead of a position.
1353   template <std::size_t M>
1354   constexpr BasicFixedString<Char, N + M> cappend(
1355       const BasicFixedString<Char, M>& that,
1356       std::size_t pos) const noexcept(false) = delete;
1357
1358   /**
1359    * Creates a new string by appending characters from one string to another,
1360    *   which is left unmodified.
1361    * \note Equivalent to `*this + that.substr(pos, count)`
1362    */
1363   template <std::size_t M>
1364   constexpr BasicFixedString<Char, N + M> cappend(
1365       const BasicFixedString<Char, M>& that,
1366       std::size_t pos,
1367       std::size_t count) const noexcept(false) {
1368     return creplace(size_, 0u, that, pos, count);
1369   }
1370
1371   /**
1372    * Creates a new string by appending a string literal to a string,
1373    *   which is left unmodified.
1374    * \note Equivalent to `*this + that`
1375    */
1376   template <std::size_t M>
1377   constexpr BasicFixedString<Char, N + M - 1u> cappend(
1378       const Char (&that)[M]) const noexcept {
1379     return creplace(size_, 0u, that);
1380   }
1381
1382   // Deleted to avoid confusion with append("char*", N), where N is a count
1383   // instead of a position
1384   template <std::size_t M>
1385   constexpr BasicFixedString<Char, N + M - 1u> cappend(
1386       const Char (&that)[M],
1387       std::size_t pos) const noexcept(false) = delete;
1388
1389   /**
1390    * Creates a new string by appending characters from one string to another,
1391    *   which is left unmodified.
1392    * \note Equivalent to `*this + makeFixedString(that).substr(pos, count)`
1393    */
1394   template <std::size_t M>
1395   constexpr BasicFixedString<Char, N + M - 1u>
1396   cappend(const Char (&that)[M], std::size_t pos, std::size_t count) const
1397       noexcept(false) {
1398     return creplace(size_, 0u, that, pos, count);
1399   }
1400
1401   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1402    * Appends characters from a null-terminated string literal to this string.
1403    * \note Equivalent to `append(that)`.
1404    */
1405   FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(const Char* that) noexcept(
1406       false) {
1407     return append(that);
1408   }
1409
1410   /**
1411    * Appends characters from another string to this one.
1412    * \note Equivalent to `append(that)`.
1413    */
1414   template <std::size_t M>
1415   FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(
1416       const BasicFixedString<Char, M>& that) noexcept(false) {
1417     return append(that, 0u, that.size_);
1418   }
1419
1420   /**
1421    * Appends a character to this string.
1422    * \note Equivalent to `push_back(ch)`.
1423    */
1424   FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(Char ch) noexcept(false) {
1425     push_back(ch);
1426     return *this;
1427   }
1428
1429   /**
1430    * Appends characters from an `initializer_list` to this string.
1431    * \note Equivalent to `append(il.begin(), il.size())`.
1432    */
1433   FOLLY_CPP14_CONSTEXPR BasicFixedString& operator+=(
1434       std::initializer_list<Char> il) noexcept(false) {
1435     return append(il.begin(), il.size());
1436   }
1437
1438   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1439    * Erase all characters from this string.
1440    * \note Equivalent to `clear()`
1441    * \return *this;
1442    */
1443   FOLLY_CPP14_CONSTEXPR BasicFixedString& erase() noexcept {
1444     clear();
1445     return *this;
1446   }
1447
1448   /**
1449    * Erases `count` characters from position `pos`. If `count` is `npos`,
1450    *   erases from `pos` to the end of the string.
1451    * \pre `pos <= size()`
1452    * \pre `count <= size() - pos || count == npos`
1453    * \post `size() == old_size - min(count, old_size - pos)`
1454    * \post `at(size()) == Char(0)`
1455    * \return *this;
1456    * \throw std::out_of_range when pos > size().
1457    */
1458   FOLLY_CPP14_CONSTEXPR BasicFixedString& erase(
1459       std::size_t pos,
1460       std::size_t count = npos) noexcept(false) {
1461     using A = const Char[1];
1462     return replace(
1463         pos,
1464         detail::fixedstring::checkOverflowOrNpos(
1465             count, size_ - detail::fixedstring::checkOverflow(pos, size_)),
1466         A{Char(0)},
1467         0u);
1468   }
1469
1470   /**
1471    * \note Equivalent to `erase(first - data(), 1)`
1472    * \return A pointer to the first character after the erased character.
1473    */
1474   FOLLY_CPP14_CONSTEXPR Char* erase(const Char* first) noexcept(false) {
1475     erase(first - data_, 1u);
1476     return data_ + (first - data_);
1477   }
1478
1479   /**
1480    * \note Equivalent to `erase(first - data(), last - first)`
1481    * \return A pointer to the first character after the erased characters.
1482    */
1483   FOLLY_CPP14_CONSTEXPR Char* erase(
1484       const Char* first,
1485       const Char* last) noexcept(false) {
1486     erase(first - data_, last - first);
1487     return data_ + (first - data_);
1488   }
1489
1490   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1491    * Create a new string by erasing all the characters from this string.
1492    * \note Equivalent to `BasicFixedString<Char, 0>{}`
1493    */
1494   constexpr BasicFixedString<Char, 0u> cerase() const noexcept {
1495     return {};
1496   }
1497
1498   /**
1499    * Create a new string by erasing all the characters after position `pos` from
1500    *   this string.
1501    * \note Equivalent to `creplace(pos, min(count, pos - size()), "")`
1502    */
1503   constexpr BasicFixedString cerase(std::size_t pos, std::size_t count = npos)
1504       const noexcept(false) {
1505     using A = const Char[1];
1506     return creplace(
1507         pos,
1508         detail::fixedstring::checkOverflowOrNpos(
1509             count, size_ - detail::fixedstring::checkOverflow(pos, size_)),
1510         A{Char(0)});
1511   }
1512
1513   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1514    * Compare two strings for lexicographical ordering.
1515    * \note Equivalent to
1516    * `compare(0, size(), that.data(), that.size())`
1517    */
1518   template <std::size_t M>
1519   constexpr int compare(const BasicFixedString<Char, M>& that) const noexcept {
1520     return compare(0u, size_, that, 0u, that.size_);
1521   }
1522
1523   /**
1524    * Compare two strings for lexicographical ordering.
1525    * \note Equivalent to
1526    * `compare(this_pos, this_count, that.data(), that.size())`
1527    */
1528   template <std::size_t M>
1529   constexpr int compare(
1530       std::size_t this_pos,
1531       std::size_t this_count,
1532       const BasicFixedString<Char, M>& that) const noexcept(false) {
1533     return compare(this_pos, this_count, that, 0u, that.size_);
1534   }
1535
1536   /**
1537    * Compare two strings for lexicographical ordering.
1538    * \note Equivalent to
1539    * `compare(this_pos, this_count, that.data() + that_pos, that_count)`
1540    */
1541   template <std::size_t M>
1542   constexpr int compare(
1543       std::size_t this_pos,
1544       std::size_t this_count,
1545       const BasicFixedString<Char, M>& that,
1546       std::size_t that_pos,
1547       std::size_t that_count) const noexcept(false) {
1548     return static_cast<int>(detail::fixedstring::compare_(
1549         data_,
1550         detail::fixedstring::checkOverflow(this_pos, size_),
1551         detail::fixedstring::checkOverflow(this_count, size_ - this_pos) +
1552             this_pos,
1553         that.data_,
1554         detail::fixedstring::checkOverflow(that_pos, that.size_),
1555         detail::fixedstring::checkOverflow(that_count, that.size_ - that_pos) +
1556             that_pos));
1557   }
1558
1559   /**
1560    * Compare two strings for lexicographical ordering.
1561    * \note Equivalent to `compare(0, size(), that, strlen(that))`
1562    */
1563   constexpr int compare(const Char* that) const noexcept {
1564     return compare(0u, size_, that, folly::constexpr_strlen(that));
1565   }
1566
1567   /**
1568    * \overload
1569    */
1570   constexpr int compare(Range<const Char*> that) const noexcept {
1571     return compare(0u, size_, that.begin(), that.size());
1572   }
1573
1574   /**
1575    * Compare two strings for lexicographical ordering.
1576    * \note Equivalent to
1577    *   `compare(this_pos, this_count, that, strlen(that))`
1578    */
1579   constexpr int compare(
1580       std::size_t this_pos,
1581       std::size_t this_count,
1582       const Char* that) const noexcept(false) {
1583     return compare(this_pos, this_count, that, folly::constexpr_strlen(that));
1584   }
1585
1586   /**
1587    * \overload
1588    */
1589   constexpr int compare(
1590       std::size_t this_pos,
1591       std::size_t this_count,
1592       Range<const Char*> that) const noexcept(false) {
1593     return compare(this_pos, this_count, that.begin(), that.size());
1594   }
1595
1596   /**
1597    * Compare two strings for lexicographical ordering.
1598    *
1599    * Let `A` be the the
1600    *   character sequence {`(*this)[this_pos]`, ...
1601    *   `(*this)[this_pos + this_count - 1]`}. Let `B` be the character sequence
1602    *   {`that[0]`, ...`that[count - 1]`}. Then...
1603    *
1604    * \return
1605    *   - `< 0` if `A` is ordered before the `B`
1606    *   - `> 0` if `B` is ordered before `A`
1607    *   - `0` if `A` equals `B`.
1608    *
1609    * \throw std::out_of_range if this_pos + this_count > size().
1610    */
1611   constexpr int compare(
1612       std::size_t this_pos,
1613       std::size_t this_count,
1614       const Char* that,
1615       std::size_t that_count) const noexcept(false) {
1616     return static_cast<int>(detail::fixedstring::compare_(
1617         data_,
1618         detail::fixedstring::checkOverflow(this_pos, size_),
1619         detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos) +
1620             this_pos,
1621         that,
1622         0u,
1623         that_count));
1624   }
1625
1626   constexpr int compare(
1627       std::size_t this_pos,
1628       std::size_t this_count,
1629       Range<const Char*> that,
1630       std::size_t that_count) const noexcept(false) {
1631     return compare(
1632         this_pos,
1633         this_count,
1634         that.begin(),
1635         detail::fixedstring::checkOverflow(that_count, that.size()));
1636   }
1637
1638   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1639    * Return a substring from `pos` to the end of the string.
1640    * \note Equivalent to `BasicFixedString{*this, pos}`
1641    */
1642   constexpr BasicFixedString substr(std::size_t pos) const noexcept(false) {
1643     return {*this, pos};
1644   }
1645
1646   /**
1647    * Return a substring from `pos` to the end of the string.
1648    * \note Equivalent to `BasicFixedString{*this, pos, count}`
1649    */
1650   constexpr BasicFixedString substr(std::size_t pos, std::size_t count) const
1651       noexcept(false) {
1652     return {*this, pos, count};
1653   }
1654
1655   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1656    * Replace the characters in the range denoted by the half-open range
1657    *   [`first`, `last`) with the string `that`.
1658    * \pre `first` and `last` point to characters within this string (including
1659    *   the terminating null).
1660    * \note Equivalent to
1661    *   `replace(first - data(), last - first, that.data(), that.size())`
1662    */
1663   template <std::size_t M>
1664   FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1665       const Char* first,
1666       const Char* last,
1667       const BasicFixedString<Char, M>& that) noexcept(false) {
1668     return replace(first - data_, last - first, that, 0u, that.size_);
1669   }
1670
1671   /**
1672    * Replace `this_count` characters starting from position `this_pos` with the
1673    *   characters from string `that` starting at position `that_pos`.
1674    * \pre `that_pos <= that.size()`
1675    * \note Equivalent to
1676    *   <tt>replace(this_pos, this_count, that.data() + that_pos,
1677    *   that.size() - that_pos)</tt>
1678    */
1679   template <std::size_t M>
1680   FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1681       std::size_t this_pos,
1682       std::size_t this_count,
1683       const BasicFixedString<Char, M>& that,
1684       std::size_t that_pos = 0u) noexcept(false) {
1685     return replace(this_pos, this_count, that, that_pos, that.size_ - that_pos);
1686   }
1687
1688   /**
1689    * Replace `this_count` characters starting from position `this_pos` with
1690    *   `that_count` characters from string `that` starting at position
1691    *   `that_pos`.
1692    * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos`
1693    * \note Equivalent to
1694    *   `replace(this_pos, this_count, that.data() + that_pos, that_count)`
1695    */
1696   template <std::size_t M>
1697   FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1698       std::size_t this_pos,
1699       std::size_t this_count,
1700       const BasicFixedString<Char, M>& that,
1701       std::size_t that_pos,
1702       std::size_t that_count) noexcept(false) {
1703     return *this = creplace(this_pos, this_count, that, that_pos, that_count);
1704   }
1705
1706   /**
1707    * Replace `this_count` characters starting from position `this_pos` with
1708    *   the characters from the string literal `that`.
1709    * \note Equivalent to
1710    *   `replace(this_pos, this_count, that, strlen(that))`
1711    */
1712   FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1713       std::size_t this_pos,
1714       std::size_t this_count,
1715       const Char* that) noexcept(false) {
1716     return replace(this_pos, this_count, that, folly::constexpr_strlen(that));
1717   }
1718
1719   /**
1720    * Replace the characters denoted by the half-open range [`first`,`last`) with
1721    *   the characters from the string literal `that`.
1722    * \pre `first` and `last` point to characters within this string (including
1723    *   the terminating null).
1724    * \note Equivalent to
1725    *   `replace(first - data(), last - first, that, strlen(that))`
1726    */
1727   FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1728       const Char* first,
1729       const Char* last,
1730       const Char* that) noexcept(false) {
1731     return replace(
1732         first - data_, last - first, that, folly::constexpr_strlen(that));
1733   }
1734
1735   /**
1736    * Replace `this_count` characters starting from position `this_pos` with
1737    *   `that_count` characters from the character sequence pointed to by `that`.
1738    * \param this_pos The starting offset within `*this` of the first character
1739    *   to be replaced.
1740    * \param this_count The number of characters to be replaced. If `npos`,
1741    *   it is treated as if `this_count` were `size() - this_pos`.
1742    * \param that A pointer to the replacement string.
1743    * \param that_count The number of characters in the replacement string.
1744    * \pre `this_pos <= size() && this_count <= size() - this_pos`
1745    * \pre `that` points to a contiguous sequence of at least `that_count`
1746    *   characters
1747    * \throw std::out_of_range on any of the following conditions:
1748    *   - `this_pos > size()`
1749    *   - `this_count > size() - this_pos`
1750    *   - `size() - this_count + that_count > N`
1751    */
1752   FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1753       std::size_t this_pos,
1754       std::size_t this_count,
1755       const Char* that,
1756       std::size_t that_count) noexcept(false) {
1757     return *this = detail::fixedstring::Helper::replace_<Char>(
1758                data_,
1759                size_,
1760                detail::fixedstring::checkOverflow(this_pos, size_),
1761                detail::fixedstring::checkOverflowOrNpos(
1762                    this_count, size_ - this_pos),
1763                that,
1764                0u,
1765                that_count,
1766                Indices{});
1767   }
1768
1769   /**
1770    * Replace `this_count` characters starting from position `this_pos` with
1771    *   `that_count` characters `ch`.
1772    * \note Equivalent to
1773    *   `replace(this_pos, this_count, BasicFixedString{that_count, ch})`
1774    */
1775   FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1776       std::size_t this_pos,
1777       std::size_t this_count,
1778       std::size_t that_count,
1779       Char ch) noexcept(false) {
1780     return replace(this_pos, this_count, BasicFixedString{that_count, ch});
1781   }
1782
1783   /**
1784    * Replace the characters denoted by the half-open range [`first`,`last`)
1785    *   with `that_count` characters `ch`.
1786    * \note Equivalent to
1787    *   `replace(first - data(), last - first, BasicFixedString{that_count, ch})`
1788    */
1789   FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1790       const Char* first,
1791       const Char* last,
1792       std::size_t that_count,
1793       Char ch) noexcept(false) {
1794     return replace(
1795         first - data_, last - first, BasicFixedString{that_count, ch});
1796   }
1797
1798   /**
1799    * Replace the characters denoted by the half-open range [`first`,`last`) with
1800    *   the characters from the string literal `that`.
1801    * \pre `first` and `last` point to characters within this string (including
1802    *   the terminating null).
1803    * \note Equivalent to
1804    *   `replace(this_pos, this_count, il.begin(), il.size())`
1805    */
1806   FOLLY_CPP14_CONSTEXPR BasicFixedString& replace(
1807       const Char* first,
1808       const Char* last,
1809       std::initializer_list<Char> il) noexcept(false) {
1810     return replace(first - data_, last - first, il.begin(), il.size());
1811   }
1812
1813   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
1814    * Construct a new string by replacing `this_count` characters starting from
1815    *   position `this_pos` within this string with the characters from string
1816    *   `that` starting at position `that_pos`.
1817    * \pre `that_pos <= that.size()`
1818    * \note Equivalent to
1819    *   <tt>creplace(this_pos, this_count, that, that_pos,
1820    *   that.size() - that_pos)</tt>
1821    */
1822   template <std::size_t M>
1823   constexpr BasicFixedString<Char, N + M> creplace(
1824       std::size_t this_pos,
1825       std::size_t this_count,
1826       const BasicFixedString<Char, M>& that,
1827       std::size_t that_pos = 0u) const noexcept(false) {
1828     return creplace(
1829         this_pos,
1830         this_count,
1831         that,
1832         that_pos,
1833         that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_));
1834   }
1835
1836   /**
1837    * Construct a new string by replacing `this_count` characters starting from
1838    *   position `this_pos` within this string with `that_count` characters from
1839    *   string `that` starting at position `that_pos`.
1840    * \param this_pos The starting offset within `*this` of the first character
1841    *   to be replaced.
1842    * \param this_count The number of characters to be replaced. If `npos`,
1843    *   it is treated as if `this_count` were `size() - this_pos`.
1844    * \param that A string that contains the replacement string.
1845    * \param that_pos The offset to the first character in the replacement
1846    *   string.
1847    * \param that_count The number of characters in the replacement string.
1848    * \pre `this_pos <= size() && this_count <= size() - this_pos`
1849    * \pre `that_pos <= that.size() && that_count <= that.size() - that_pos`
1850    * \post The size of the returned string is `size() - this_count + that_count`
1851    * \note Equivalent to <tt>BasicFixedString<Char, N + M>{substr(0, this_pos) +
1852    *    that.substr(that_pos, that_count) + substr(this_pos + this_count)}</tt>
1853    * \throw std::out_of_range on any of the following conditions:
1854    *   - `this_pos > size()`
1855    *   - `this_count > size() - this_pos`
1856    *   - `that_pos > that.size()`
1857    *   - `that_count > that.size() - that_pos`
1858    */
1859   template <std::size_t M>
1860   constexpr BasicFixedString<Char, N + M> creplace(
1861       std::size_t this_pos,
1862       std::size_t this_count,
1863       const BasicFixedString<Char, M>& that,
1864       std::size_t that_pos,
1865       std::size_t that_count) const noexcept(false) {
1866     return detail::fixedstring::Helper::replace_<Char>(
1867         data_,
1868         size_,
1869         detail::fixedstring::checkOverflow(this_pos, size_),
1870         detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
1871         that.data_,
1872         detail::fixedstring::checkOverflow(that_pos, that.size_),
1873         detail::fixedstring::checkOverflowOrNpos(
1874             that_count, that.size_ - that_pos),
1875         folly::make_index_sequence<N + M>{});
1876   }
1877
1878   /**
1879    * Construct a new string by replacing the characters denoted by the half-open
1880    *   range [`first`,`last`) within this string with the characters from string
1881    *   `that` starting at position `that_pos`.
1882    * \pre `that_pos <= that.size()`
1883    * \note Equivalent to
1884    *   <tt>creplace(first - data(), last - first, that, that_pos,
1885    *   that.size() - that_pos)</tt>
1886    */
1887   template <std::size_t M>
1888   constexpr BasicFixedString<Char, N + M> creplace(
1889       const Char* first,
1890       const Char* last,
1891       const BasicFixedString<Char, M>& that,
1892       std::size_t that_pos = 0u) const noexcept(false) {
1893     return creplace(
1894         first - data_,
1895         last - first,
1896         that,
1897         that_pos,
1898         that.size_ - detail::fixedstring::checkOverflow(that_pos, that.size_));
1899   }
1900
1901   /**
1902    * Construct a new string by replacing the characters denoted by the half-open
1903    *   range [`first`,`last`) within this string with the `that_count`
1904    *   characters from string `that` starting at position `that_pos`.
1905    * \note Equivalent to
1906    *   <tt>creplace(first - data(), last - first, that, that_pos,
1907    *   that_count)</tt>
1908    */
1909   template <std::size_t M>
1910   constexpr BasicFixedString<Char, N + M> creplace(
1911       const Char* first,
1912       const Char* last,
1913       const BasicFixedString<Char, M>& that,
1914       std::size_t that_pos,
1915       std::size_t that_count) const noexcept(false) {
1916     return creplace(first - data_, last - first, that, that_pos, that_count);
1917   }
1918
1919   /**
1920    * Construct a new string by replacing `this_count` characters starting from
1921    *   position `this_pos` within this string with `M-1` characters from
1922    *   character array `that`.
1923    * \pre `strlen(that) == M-1`
1924    * \note Equivalent to
1925    *   <tt>creplace(this_pos, this_count, that, 0, M - 1)</tt>
1926    */
1927   template <std::size_t M>
1928   constexpr BasicFixedString<Char, N + M - 1u> creplace(
1929       std::size_t this_pos,
1930       std::size_t this_count,
1931       const Char (&that)[M]) const noexcept(false) {
1932     return creplace(this_pos, this_count, that, 0u, M - 1u);
1933   }
1934
1935   /**
1936    * Replace `this_count` characters starting from position `this_pos` with
1937    *   `that_count` characters from the character array `that` starting at
1938    *   position `that_pos`.
1939    * \param this_pos The starting offset within `*this` of the first character
1940    *   to be replaced.
1941    * \param this_count The number of characters to be replaced. If `npos`,
1942    *   it is treated as if `this_count` were `size() - this_pos`.
1943    * \param that An array of characters containing the replacement string.
1944    * \param that_pos The starting offset of the replacement string.
1945    * \param that_count The number of characters in the replacement string.  If
1946    *   `npos`, it is treated as if `that_count` were `M - 1 - that_pos`
1947    * \pre `this_pos <= size() && this_count <= size() - this_pos`
1948    * \pre `that_pos <= M - 1 && that_count <= M - 1 - that_pos`
1949    * \post The size of the returned string is `size() - this_count + that_count`
1950    * \note Equivalent to <tt>BasicFixedString<Char, N + M - 1>{
1951    *    substr(0, this_pos) +
1952    *    makeFixedString(that).substr(that_pos, that_count) +
1953    *    substr(this_pos + this_count)}</tt>
1954    * \throw std::out_of_range on any of the following conditions:
1955    *   - `this_pos > size()`
1956    *   - `this_count > size() - this_pos`
1957    *   - `that_pos >= M`
1958    *   - `that_count >= M - that_pos`
1959    */
1960   template <std::size_t M>
1961   constexpr BasicFixedString<Char, N + M - 1u> creplace(
1962       std::size_t this_pos,
1963       std::size_t this_count,
1964       const Char (&that)[M],
1965       std::size_t that_pos,
1966       std::size_t that_count) const noexcept(false) {
1967     return detail::fixedstring::Helper::replace_<Char>(
1968         data_,
1969         size_,
1970         detail::fixedstring::checkOverflow(this_pos, size_),
1971         detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
1972         detail::fixedstring::checkNullTerminated(that),
1973         detail::fixedstring::checkOverflow(that_pos, M - 1u),
1974         detail::fixedstring::checkOverflowOrNpos(that_count, M - 1u - that_pos),
1975         folly::make_index_sequence<N + M - 1u>{});
1976   }
1977
1978   /**
1979    * Construct a new string by replacing the characters denoted by the half-open
1980    *   range [`first`,`last`) within this string with the first `M-1`
1981    *   characters from the character array `that`.
1982    * \pre `strlen(that) == M-1`
1983    * \note Equivalent to
1984    *   <tt>creplace(first - data(), last - first, that, 0, M-1)</tt>
1985    */
1986   template <std::size_t M>
1987   constexpr BasicFixedString<Char, N + M - 1u>
1988   creplace(const Char* first, const Char* last, const Char (&that)[M]) const
1989       noexcept(false) {
1990     return creplace(first - data_, last - first, that, 0u, M - 1u);
1991   }
1992
1993   /**
1994    * Construct a new string by replacing the characters denoted by the half-open
1995    *   range [`first`,`last`) within this string with the `that_count`
1996    *   characters from the character array `that` starting at position
1997    *   `that_pos`.
1998    * \pre `strlen(that) == M-1`
1999    * \note Equivalent to
2000    *   `creplace(first - data(), last - first, that, that_pos, that_count)`
2001    */
2002   template <std::size_t M>
2003   constexpr BasicFixedString<Char, N + M - 1u> creplace(
2004       const Char* first,
2005       const Char* last,
2006       const Char (&that)[M],
2007       std::size_t that_pos,
2008       std::size_t that_count) const noexcept(false) {
2009     return creplace(first - data_, last - first, that, that_pos, that_count);
2010   }
2011
2012   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2013   * Copies `min(count, size())` characters starting from offset `0`
2014   *   from this string into the buffer pointed to by `dest`.
2015   * \return The number of characters copied.
2016    */
2017   FOLLY_CPP14_CONSTEXPR std::size_t copy(Char* dest, std::size_t count) const
2018       noexcept {
2019     return copy(dest, count, 0u);
2020   }
2021
2022   /**
2023    * Copies `min(count, size() - pos)` characters starting from offset `pos`
2024    *   from this string into the buffer pointed to by `dest`.
2025    * \pre `pos <= size()`
2026    * \return The number of characters copied.
2027    * \throw std::out_of_range if `pos > size()`
2028    */
2029   FOLLY_CPP14_CONSTEXPR std::size_t
2030   copy(Char* dest, std::size_t count, std::size_t pos) const noexcept(false) {
2031     detail::fixedstring::checkOverflow(pos, size_);
2032     for (std::size_t i = 0u; i < count; ++i) {
2033       if (i + pos == size_) {
2034         return size_;
2035       }
2036       dest[i] = data_[i + pos];
2037     }
2038     return count;
2039   }
2040
2041   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2042    * Resizes the current string.
2043    * \note Equivalent to `resize(count, Char(0))`
2044    */
2045   FOLLY_CPP14_CONSTEXPR void resize(std::size_t count) noexcept(false) {
2046     resize(count, Char(0));
2047   }
2048
2049   /**
2050    * Resizes the current string by setting the size to `count` and setting
2051    *   `data()[count]` to `Char(0)`. If `count > old_size`, the characters
2052    *   in the range [`old_size`,`count`) are set to `ch`.
2053    */
2054   FOLLY_CPP14_CONSTEXPR void resize(std::size_t count, Char ch) noexcept(
2055       false) {
2056     detail::fixedstring::checkOverflow(count, N);
2057     if (count == size_) {
2058     } else if (count < size_) {
2059       size_ = count;
2060       data_[size_] = Char(0);
2061     } else {
2062       for (; size_ < count; ++size_) {
2063         data_[size_] = ch;
2064       }
2065       data_[size_] = Char(0);
2066     }
2067   }
2068
2069   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2070    * Finds the first occurrence of the character sequence `that` in this string.
2071    * \note Equivalent to `find(that.data(), 0, that.size())`
2072    */
2073   template <std::size_t M>
2074   constexpr std::size_t find(const BasicFixedString<Char, M>& that) const
2075       noexcept {
2076     return find(that, 0u);
2077   }
2078
2079   /**
2080    * Finds the first occurrence of the character sequence `that` in this string,
2081    *   starting at offset `pos`.
2082    * \pre `pos <= size()`
2083    * \note Equivalent to `find(that.data(), pos, that.size())`
2084    */
2085   template <std::size_t M>
2086   constexpr std::size_t find(
2087       const BasicFixedString<Char, M>& that,
2088       std::size_t pos) const noexcept(false) {
2089     return that.size_ <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2090         ? detail::fixedstring::find_(data_, size_, that.data_, pos, that.size_)
2091         : npos;
2092   }
2093
2094   /**
2095    * Finds the first occurrence of the character sequence `that` in this string.
2096    * \note Equivalent to `find(that.data(), 0, strlen(that))`
2097    */
2098   constexpr std::size_t find(const Char* that) const noexcept {
2099     return find(that, 0u, folly::constexpr_strlen(that));
2100   }
2101
2102   /**
2103    * Finds the first occurrence of the character sequence `that` in this string,
2104    *   starting at offset `pos`.
2105    * \pre `pos <= size()`
2106    * \note Equivalent to `find(that.data(), pos, strlen(that))`
2107    */
2108   constexpr std::size_t find(const Char* that, std::size_t pos) const
2109       noexcept(false) {
2110     return find(that, pos, folly::constexpr_strlen(that));
2111   }
2112
2113   /**
2114    * Finds the first occurrence of the first `count` characters in the buffer
2115    *   pointed to by `that` in this string, starting at offset `pos`.
2116    * \pre `pos <= size()`
2117    * \pre `that` points to a buffer containing at least `count` contiguous
2118    *   characters.
2119    * \return The lowest offset `i` such that `i >= pos` and
2120    *   `0 == strncmp(data() + i, that, count)`; or `npos` if there is no such
2121    *   offset `i`.
2122    * \throw std::out_of_range when `pos > size()`
2123    */
2124   constexpr std::size_t find(
2125       const Char* that,
2126       std::size_t pos,
2127       std::size_t count) const noexcept(false) {
2128     return count <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2129         ? detail::fixedstring::find_(data_, size_, that, pos, count)
2130         : npos;
2131   }
2132
2133   /**
2134    * Finds the first occurrence of the character `ch` in this string.
2135    * \note Equivalent to `find(&ch, 0, 1)`
2136    */
2137   constexpr std::size_t find(Char ch) const noexcept {
2138     return find(ch, 0u);
2139   }
2140
2141   /**
2142    * Finds the first occurrence of the character character `c` in this string,
2143    *   starting at offset `pos`.
2144    * \pre `pos <= size()`
2145    * \note Equivalent to `find(&ch, pos, 1)`
2146    */
2147   constexpr std::size_t find(Char ch, std::size_t pos) const noexcept(false) {
2148     using A = const Char[1u];
2149     return 0u == size_ - detail::fixedstring::checkOverflow(pos, size_)
2150         ? npos
2151         : detail::fixedstring::find_(data_, size_, A{ch}, pos, 1u);
2152   }
2153
2154   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2155    * Finds the last occurrence of characters in the string
2156    *   `that` in this string.
2157    * \note Equivalent to `rfind(that.data(), size(), that.size())`
2158    */
2159   template <std::size_t M>
2160   constexpr std::size_t rfind(const BasicFixedString<Char, M>& that) const
2161       noexcept {
2162     return rfind(that, size_);
2163   }
2164
2165   /**
2166    * Finds the last occurrence of characters in the string
2167    *   `that` in this string, starting at offset `pos`.
2168    * \note Equivalent to `rfind(that.data(), pos, that.size())`
2169    */
2170   template <std::size_t M>
2171   constexpr std::size_t rfind(
2172       const BasicFixedString<Char, M>& that,
2173       std::size_t pos) const noexcept(false) {
2174     return that.size_ <= size_
2175         ? detail::fixedstring::rfind_(
2176               data_,
2177               that.data_,
2178               folly::constexpr_min(
2179                   detail::fixedstring::checkOverflow(pos, size_),
2180                   size_ - that.size_),
2181               that.size_)
2182         : npos;
2183   }
2184
2185   /**
2186    * Finds the last occurrence of characters in the buffer
2187    *   pointed to by `that` in this string.
2188    * \note Equivalent to `rfind(that, size(), strlen(that))`
2189    */
2190   constexpr std::size_t rfind(const Char* that) const noexcept {
2191     return rfind(that, size_, folly::constexpr_strlen(that));
2192   }
2193
2194   /**
2195    * Finds the last occurrence of characters in the buffer
2196    *   pointed to by `that` in this string, starting at offset `pos`.
2197    * \note Equivalent to `rfind(that, pos, strlen(that))`
2198    */
2199   constexpr std::size_t rfind(const Char* that, std::size_t pos) const
2200       noexcept(false) {
2201     return rfind(that, pos, folly::constexpr_strlen(that));
2202   }
2203
2204   /**
2205    * Finds the last occurrence of the first `count` characters in the buffer
2206    *   pointed to by `that` in this string, starting at offset `pos`.
2207    * \pre `pos <= size()`
2208    * \pre `that` points to a buffer containing at least `count` contiguous
2209    *   characters.
2210    * \return The largest offset `i` such that `i <= pos` and
2211    *   `i + count <= size()` and `0 == strncmp(data() + i, that, count)`; or
2212    *   `npos` if there is no such offset `i`.
2213    * \throw std::out_of_range when `pos > size()`
2214    */
2215   constexpr std::size_t rfind(
2216       const Char* that,
2217       std::size_t pos,
2218       std::size_t count) const noexcept(false) {
2219     return count <= size_
2220         ? detail::fixedstring::rfind_(
2221               data_,
2222               that,
2223               folly::constexpr_min(
2224                   detail::fixedstring::checkOverflow(pos, size_),
2225                   size_ - count),
2226               count)
2227         : npos;
2228   }
2229
2230   /**
2231    * Finds the last occurrence of the character character `ch` in this string.
2232    * \note Equivalent to `rfind(&ch, size(), 1)`
2233    */
2234   constexpr std::size_t rfind(Char ch) const noexcept {
2235     return rfind(ch, size_);
2236   }
2237
2238   /**
2239    * Finds the last occurrence of the character character `ch` in this string,
2240    *   starting at offset `pos`.
2241    * \pre `pos <= size()`
2242    * \note Equivalent to `rfind(&ch, pos, 1)`
2243    */
2244   constexpr std::size_t rfind(Char ch, std::size_t pos) const noexcept(false) {
2245     using A = const Char[1u];
2246     return 0u == size_
2247         ? npos
2248         : detail::fixedstring::rfind_(
2249               data_,
2250               A{ch},
2251               folly::constexpr_min(
2252                   detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2253               1u);
2254   }
2255
2256   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2257    * Finds the first occurrence of any character in `that` in this string.
2258    * \note Equivalent to `find_first_of(that.data(), 0, that.size())`
2259    */
2260   template <std::size_t M>
2261   constexpr std::size_t find_first_of(
2262       const BasicFixedString<Char, M>& that) const noexcept {
2263     return find_first_of(that, 0u);
2264   }
2265
2266   /**
2267    * Finds the first occurrence of any character in `that` in this string,
2268    *   starting at offset `pos`
2269    * \note Equivalent to `find_first_of(that.data(), pos, that.size())`
2270    */
2271   template <std::size_t M>
2272   constexpr std::size_t find_first_of(
2273       const BasicFixedString<Char, M>& that,
2274       std::size_t pos) const noexcept(false) {
2275     return size_ == detail::fixedstring::checkOverflow(pos, size_)
2276         ? npos
2277         : detail::fixedstring::find_first_of_(
2278               data_, size_, that.data_, pos, that.size_);
2279   }
2280
2281   /**
2282    * Finds the first occurrence of any character in the null-terminated
2283    *   character sequence pointed to by `that` in this string.
2284    * \note Equivalent to `find_first_of(that, 0, strlen(that))`
2285    */
2286   constexpr std::size_t find_first_of(const Char* that) const noexcept {
2287     return find_first_of(that, 0u, folly::constexpr_strlen(that));
2288   }
2289
2290   /**
2291    * Finds the first occurrence of any character in the null-terminated
2292    *   character sequence pointed to by `that` in this string,
2293    *   starting at offset `pos`
2294    * \note Equivalent to `find_first_of(that, pos, strlen(that))`
2295    */
2296   constexpr std::size_t find_first_of(const Char* that, std::size_t pos) const
2297       noexcept(false) {
2298     return find_first_of(that, pos, folly::constexpr_strlen(that));
2299   }
2300
2301   /**
2302    * Finds the first occurrence of any character in the first `count` characters
2303    *   in the buffer pointed to by `that` in this string, starting at offset
2304    *  `pos`.
2305    * \pre `pos <= size()`
2306    * \pre `that` points to a buffer containing at least `count` contiguous
2307    *   characters.
2308    * \return The smallest offset `i` such that `i >= pos` and
2309    *   `std::find(that, that+count, at(i)) != that+count`; or
2310    *   `npos` if there is no such offset `i`.
2311    * \throw std::out_of_range when `pos > size()`
2312    */
2313   constexpr std::size_t find_first_of(
2314       const Char* that,
2315       std::size_t pos,
2316       std::size_t count) const noexcept(false) {
2317     return size_ == detail::fixedstring::checkOverflow(pos, size_)
2318         ? npos
2319         : detail::fixedstring::find_first_of_(data_, size_, that, pos, count);
2320   }
2321
2322   /**
2323    * Finds the first occurrence of `ch` in this string.
2324    * \note Equivalent to `find_first_of(&ch, 0, 1)`
2325    */
2326   constexpr std::size_t find_first_of(Char ch) const noexcept {
2327     return find_first_of(ch, 0u);
2328   }
2329
2330   /**
2331    * Finds the first occurrence of `ch` in this string,
2332    *   starting at offset `pos`.
2333    * \note Equivalent to `find_first_of(&ch, pos, 1)`
2334    */
2335   constexpr std::size_t find_first_of(Char ch, std::size_t pos) const
2336       noexcept(false) {
2337     using A = const Char[1u];
2338     return size_ == detail::fixedstring::checkOverflow(pos, size_)
2339         ? npos
2340         : detail::fixedstring::find_first_of_(data_, size_, A{ch}, pos, 1u);
2341   }
2342
2343   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2344    * Finds the first occurrence of any character not in `that` in this string.
2345    * \note Equivalent to `find_first_not_of(that.data(), 0, that.size())`
2346    */
2347   template <std::size_t M>
2348   constexpr std::size_t find_first_not_of(
2349       const BasicFixedString<Char, M>& that) const noexcept {
2350     return find_first_not_of(that, 0u);
2351   }
2352
2353   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2354    * Finds the first occurrence of any character not in `that` in this string.
2355    * \note Equivalent to `find_first_not_of(that.data(), 0, that.size())`
2356    */
2357   template <std::size_t M>
2358   constexpr std::size_t find_first_not_of(
2359       const BasicFixedString<Char, M>& that,
2360       std::size_t pos) const noexcept(false) {
2361     return size_ == detail::fixedstring::checkOverflow(pos, size_)
2362         ? npos
2363         : detail::fixedstring::find_first_not_of_(
2364               data_, size_, that.data_, pos, that.size_);
2365   }
2366
2367   /**
2368    * Finds the first occurrence of any character not in the null-terminated
2369    *   character sequence pointed to by `that` in this string.
2370    * \note Equivalent to `find_first_not_of(that, 0, strlen(that))`
2371    */
2372   constexpr std::size_t find_first_not_of(const Char* that) const noexcept {
2373     return find_first_not_of(that, 0u, folly::constexpr_strlen(that));
2374   }
2375
2376   /**
2377    * Finds the first occurrence of any character not in the null-terminated
2378    *   character sequence pointed to by `that` in this string,
2379    *   starting at offset `pos`
2380    * \note Equivalent to `find_first_not_of(that, pos, strlen(that))`
2381    */
2382   constexpr std::size_t find_first_not_of(const Char* that, std::size_t pos)
2383       const noexcept(false) {
2384     return find_first_not_of(that, pos, folly::constexpr_strlen(that));
2385   }
2386
2387   /**
2388    * Finds the first occurrence of any character not in the first `count`
2389    *   characters in the buffer pointed to by `that` in this string, starting at
2390    *   offset `pos`.
2391    * \pre `pos <= size()`
2392    * \pre `that` points to a buffer containing at least `count` contiguous
2393    *   characters.
2394    * \return The smallest offset `i` such that `i >= pos` and
2395    *   `std::find(that, that+count, at(i)) == that+count`; or
2396    *   `npos` if there is no such offset `i`.
2397    * \throw std::out_of_range when `pos > size()`
2398    */
2399   constexpr std::size_t find_first_not_of(
2400       const Char* that,
2401       std::size_t pos,
2402       std::size_t count) const noexcept(false) {
2403     return size_ == detail::fixedstring::checkOverflow(pos, size_)
2404         ? npos
2405         : detail::fixedstring::find_first_not_of_(
2406               data_, size_, that, pos, count);
2407   }
2408
2409   /**
2410    * Finds the first occurrence of any character other than `ch` in this string.
2411    * \note Equivalent to `find_first_not_of(&ch, 0, 1)`
2412    */
2413   constexpr std::size_t find_first_not_of(Char ch) const noexcept {
2414     return find_first_not_of(ch, 0u);
2415   }
2416
2417   /**
2418    * Finds the first occurrence of any character other than `ch` in this string,
2419    *   starting at offset `pos`.
2420    * \note Equivalent to `find_first_not_of(&ch, pos, 1)`
2421    */
2422   constexpr std::size_t find_first_not_of(Char ch, std::size_t pos) const
2423       noexcept(false) {
2424     using A = const Char[1u];
2425     return 1u <= size_ - detail::fixedstring::checkOverflow(pos, size_)
2426         ? detail::fixedstring::find_first_not_of_(data_, size_, A{ch}, pos, 1u)
2427         : npos;
2428   }
2429
2430   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2431    * Finds the last occurrence of any character in `that` in this string.
2432    * \note Equivalent to `find_last_of(that.data(), size(), that.size())`
2433    */
2434   template <std::size_t M>
2435   constexpr std::size_t find_last_of(
2436       const BasicFixedString<Char, M>& that) const noexcept {
2437     return find_last_of(that, size_);
2438   }
2439
2440   /**
2441    * Finds the last occurrence of any character in `that` in this string,
2442    *   starting at offset `pos`
2443    * \note Equivalent to `find_last_of(that.data(), pos, that.size())`
2444    */
2445   template <std::size_t M>
2446   constexpr std::size_t find_last_of(
2447       const BasicFixedString<Char, M>& that,
2448       std::size_t pos) const noexcept(false) {
2449     return 0u == size_
2450         ? npos
2451         : detail::fixedstring::find_last_of_(
2452               data_,
2453               that.data_,
2454               folly::constexpr_min(
2455                   detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2456               that.size_);
2457   }
2458
2459   /**
2460    * Finds the last occurrence of any character in the null-terminated
2461    *   character sequence pointed to by `that` in this string.
2462    * \note Equivalent to `find_last_of(that, size(), strlen(that))`
2463    */
2464   constexpr std::size_t find_last_of(const Char* that) const noexcept {
2465     return find_last_of(that, size_, folly::constexpr_strlen(that));
2466   }
2467
2468   /**
2469    * Finds the last occurrence of any character in the null-terminated
2470    *   character sequence pointed to by `that` in this string,
2471    *   starting at offset `pos`
2472    * \note Equivalent to `find_last_of(that, pos, strlen(that))`
2473    */
2474   constexpr std::size_t find_last_of(const Char* that, std::size_t pos) const
2475       noexcept(false) {
2476     return find_last_of(that, pos, folly::constexpr_strlen(that));
2477   }
2478
2479   /**
2480    * Finds the last occurrence of any character in the first `count` characters
2481    *   in the buffer pointed to by `that` in this string, starting at offset
2482    *  `pos`.
2483    * \pre `pos <= size()`
2484    * \pre `that` points to a buffer containing at least `count` contiguous
2485    *   characters.
2486    * \return The largest offset `i` such that `i <= pos` and
2487    *   `i < size()` and `std::find(that, that+count, at(i)) != that+count`; or
2488    *   `npos` if there is no such offset `i`.
2489    * \throw std::out_of_range when `pos > size()`
2490    */
2491   constexpr std::size_t find_last_of(
2492       const Char* that,
2493       std::size_t pos,
2494       std::size_t count) const noexcept(false) {
2495     return 0u == size_
2496         ? npos
2497         : detail::fixedstring::find_last_of_(
2498               data_,
2499               that,
2500               folly::constexpr_min(
2501                   detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2502               count);
2503   }
2504
2505   /**
2506    * Finds the last occurrence of `ch` in this string.
2507    * \note Equivalent to `find_last_of(&ch, size(), 1)`
2508    */
2509   constexpr std::size_t find_last_of(Char ch) const noexcept {
2510     return find_last_of(ch, size_);
2511   }
2512
2513   /**
2514    * Finds the last occurrence of `ch` in this string,
2515    *   starting at offset `pos`.
2516    * \note Equivalent to `find_last_of(&ch, pos, 1)`
2517    */
2518   constexpr std::size_t find_last_of(Char ch, std::size_t pos) const
2519       noexcept(false) {
2520     using A = const Char[1u];
2521     return 0u == size_
2522         ? npos
2523         : detail::fixedstring::find_last_of_(
2524               data_,
2525               A{ch},
2526               folly::constexpr_min(
2527                   detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2528               1u);
2529   }
2530
2531   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2532    * Finds the last occurrence of any character not in `that` in this string.
2533    * \note Equivalent to `find_last_not_of(that.data(), size(), that.size())`
2534    */
2535   template <std::size_t M>
2536   constexpr std::size_t find_last_not_of(
2537       const BasicFixedString<Char, M>& that) const noexcept {
2538     return find_last_not_of(that, size_);
2539   }
2540
2541   /**
2542    * Finds the last occurrence of any character not in `that` in this string,
2543    *   starting at offset `pos`
2544    * \note Equivalent to `find_last_not_of(that.data(), pos, that.size())`
2545    */
2546   template <std::size_t M>
2547   constexpr std::size_t find_last_not_of(
2548       const BasicFixedString<Char, M>& that,
2549       std::size_t pos) const noexcept(false) {
2550     return 0u == size_
2551         ? npos
2552         : detail::fixedstring::find_last_not_of_(
2553               data_,
2554               that.data_,
2555               folly::constexpr_min(
2556                   detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2557               that.size_);
2558   }
2559
2560   /**
2561    * Finds the last occurrence of any character not in the null-terminated
2562    *   character sequence pointed to by `that` in this string.
2563    * \note Equivalent to `find_last_not_of(that, size(), strlen(that))`
2564    */
2565   constexpr std::size_t find_last_not_of(const Char* that) const noexcept {
2566     return find_last_not_of(that, size_, folly::constexpr_strlen(that));
2567   }
2568
2569   /**
2570    * Finds the last occurrence of any character not in the null-terminated
2571    *   character sequence pointed to by `that` in this string,
2572    *   starting at offset `pos`
2573    * \note Equivalent to `find_last_not_of(that, pos, strlen(that))`
2574    */
2575   constexpr std::size_t find_last_not_of(const Char* that, std::size_t pos)
2576       const noexcept(false) {
2577     return find_last_not_of(that, pos, folly::constexpr_strlen(that));
2578   }
2579
2580   /**
2581    * Finds the last occurrence of any character not in the first `count`
2582    *   characters in the buffer pointed to by `that` in this string, starting at
2583    *   offset `pos`.
2584    * \pre `pos <= size()`
2585    * \pre `that` points to a buffer containing at least `count` contiguous
2586    *   characters.
2587    * \return The largest offset `i` such that `i <= pos` and
2588    *   `i < size()` and `std::find(that, that+count, at(i)) == that+count`; or
2589    *   `npos` if there is no such offset `i`.
2590    * \throw std::out_of_range when `pos > size()`
2591    */
2592   constexpr std::size_t find_last_not_of(
2593       const Char* that,
2594       std::size_t pos,
2595       std::size_t count) const noexcept(false) {
2596     return 0u == size_
2597         ? npos
2598         : detail::fixedstring::find_last_not_of_(
2599               data_,
2600               that,
2601               folly::constexpr_min(
2602                   detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2603               count);
2604   }
2605
2606   /**
2607    * Finds the last occurrence of any character other than `ch` in this string.
2608    * \note Equivalent to `find_last_not_of(&ch, size(), 1)`
2609    */
2610   constexpr std::size_t find_last_not_of(Char ch) const noexcept {
2611     return find_last_not_of(ch, size_);
2612   }
2613
2614   /**
2615    * Finds the last occurrence of any character other than `ch` in this string,
2616    *   starting at offset `pos`.
2617    * \note Equivalent to `find_last_not_of(&ch, pos, 1)`
2618    */
2619   constexpr std::size_t find_last_not_of(Char ch, std::size_t pos) const
2620       noexcept(false) {
2621     using A = const Char[1u];
2622     return 0u == size_
2623         ? npos
2624         : detail::fixedstring::find_last_not_of_(
2625               data_,
2626               A{ch},
2627               folly::constexpr_min(
2628                   detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
2629               1u);
2630   }
2631
2632   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2633    * Asymmetric relational operators
2634    */
2635   friend constexpr bool operator==(
2636       const Char* a,
2637       const BasicFixedString& b) noexcept {
2638     return detail::fixedstring::equal_(
2639         a, folly::constexpr_strlen(a), b.data_, b.size_);
2640   }
2641
2642   /**
2643    * \overload
2644    */
2645   friend constexpr bool operator==(
2646       const BasicFixedString& a,
2647       const Char* b) noexcept {
2648     return b == a;
2649   }
2650
2651   /**
2652    * \overload
2653    */
2654   friend constexpr bool operator==(
2655       Range<const Char*> a,
2656       const BasicFixedString& b) noexcept {
2657     return detail::fixedstring::equal_(a.begin(), a.size(), b.data_, b.size_);
2658   }
2659
2660   /**
2661    * \overload
2662    */
2663   friend constexpr bool operator==(
2664       const BasicFixedString& a,
2665       Range<const Char*> b) noexcept {
2666     return b == a;
2667   }
2668
2669   friend constexpr bool operator!=(
2670       const Char* a,
2671       const BasicFixedString& b) noexcept {
2672     return !(a == b);
2673   }
2674
2675   /**
2676    * \overload
2677    */
2678   friend constexpr bool operator!=(
2679       const BasicFixedString& a,
2680       const Char* b) noexcept {
2681     return !(b == a);
2682   }
2683
2684   /**
2685    * \overload
2686    */
2687   friend constexpr bool operator!=(
2688       Range<const Char*> a,
2689       const BasicFixedString& b) noexcept {
2690     return !(a == b);
2691   }
2692
2693   /**
2694    * \overload
2695    */
2696   friend constexpr bool operator!=(
2697       const BasicFixedString& a,
2698       Range<const Char*> b) noexcept {
2699     return !(a == b);
2700   }
2701
2702   friend constexpr bool operator<(
2703       const Char* a,
2704       const BasicFixedString& b) noexcept {
2705     return detail::fixedstring::Cmp::LT ==
2706         detail::fixedstring::compare_(
2707                a, 0u, folly::constexpr_strlen(a), b.data_, 0u, b.size_);
2708   }
2709
2710   /**
2711    * \overload
2712    */
2713   friend constexpr bool operator<(
2714       const BasicFixedString& a,
2715       const Char* b) noexcept {
2716     return detail::fixedstring::Cmp::LT ==
2717         detail::fixedstring::compare_(
2718                a.data_, 0u, a.size_, b, 0u, folly::constexpr_strlen(b));
2719   }
2720
2721   /**
2722    * \overload
2723    */
2724   friend constexpr bool operator<(
2725       Range<const Char*> a,
2726       const BasicFixedString& b) noexcept {
2727     return detail::fixedstring::Cmp::LT ==
2728         detail::fixedstring::compare_(
2729                a.begin(), 0u, a.size(), b.data_, 0u, b.size_);
2730   }
2731
2732   /**
2733    * \overload
2734    */
2735   friend constexpr bool operator<(
2736       const BasicFixedString& a,
2737       Range<const Char*> b) noexcept {
2738     return detail::fixedstring::Cmp::LT ==
2739         detail::fixedstring::compare_(
2740                a.data_, 0u, a.size_, b.begin(), 0u, b.size());
2741   }
2742
2743   friend constexpr bool operator>(
2744       const Char* a,
2745       const BasicFixedString& b) noexcept {
2746     return b < a;
2747   }
2748
2749   /**
2750    * \overload
2751    */
2752   friend constexpr bool operator>(
2753       const BasicFixedString& a,
2754       const Char* b) noexcept {
2755     return b < a;
2756   }
2757
2758   /**
2759    * \overload
2760    */
2761   friend constexpr bool operator>(
2762       Range<const Char*> a,
2763       const BasicFixedString& b) noexcept {
2764     return b < a;
2765   }
2766
2767   /**
2768    * \overload
2769    */
2770   friend constexpr bool operator>(
2771       const BasicFixedString& a,
2772       Range<const Char*> b) noexcept {
2773     return b < a;
2774   }
2775
2776   friend constexpr bool operator<=(
2777       const Char* a,
2778       const BasicFixedString& b) noexcept {
2779     return !(b < a);
2780   }
2781
2782   /**
2783    * \overload
2784    */
2785   friend constexpr bool operator<=(
2786       const BasicFixedString& a,
2787       const Char* b) noexcept {
2788     return !(b < a);
2789   }
2790
2791   /**
2792    * \overload
2793    */
2794   friend constexpr bool operator<=(
2795       Range<const Char*> const& a,
2796       const BasicFixedString& b) noexcept {
2797     return !(b < a);
2798   }
2799
2800   /**
2801    * \overload
2802    */
2803   friend constexpr bool operator<=(
2804       const BasicFixedString& a,
2805       Range<const Char*> b) noexcept {
2806     return !(b < a);
2807   }
2808
2809   friend constexpr bool operator>=(
2810       const Char* a,
2811       const BasicFixedString& b) noexcept {
2812     return !(a < b);
2813   }
2814
2815   /**
2816    * \overload
2817    */
2818   friend constexpr bool operator>=(
2819       const BasicFixedString& a,
2820       const Char* b) noexcept {
2821     return !(a < b);
2822   }
2823
2824   /**
2825    * \overload
2826    */
2827   friend constexpr bool operator>=(
2828       Range<const Char*> a,
2829       const BasicFixedString& b) noexcept {
2830     return !(a < b);
2831   }
2832
2833   /**
2834    * \overload
2835    */
2836   friend constexpr bool operator>=(
2837       const BasicFixedString& a,
2838       Range<const Char*> const& b) noexcept {
2839     return !(a < b);
2840   }
2841
2842   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2843    * Asymmetric concatenation
2844    */
2845   template <std::size_t M>
2846   friend constexpr BasicFixedString<Char, N + M - 1u> operator+(
2847       const Char (&a)[M],
2848       const BasicFixedString& b) noexcept {
2849     return detail::fixedstring::Helper::concat_<Char>(
2850         detail::fixedstring::checkNullTerminated(a),
2851         M - 1u,
2852         b.data_,
2853         b.size_,
2854         folly::make_index_sequence<N + M - 1u>{});
2855   }
2856
2857   /**
2858    * \overload
2859    */
2860   template <std::size_t M>
2861   friend constexpr BasicFixedString<Char, N + M - 1u> operator+(
2862       const BasicFixedString& a,
2863       const Char (&b)[M]) noexcept {
2864     return detail::fixedstring::Helper::concat_<Char>(
2865         a.data_,
2866         a.size_,
2867         detail::fixedstring::checkNullTerminated(b),
2868         M - 1u,
2869         folly::make_index_sequence<N + M - 1u>{});
2870   }
2871
2872   /**
2873    * \overload
2874    */
2875   friend constexpr BasicFixedString<Char, N + 1u> operator+(
2876       Char a,
2877       const BasicFixedString& b) noexcept {
2878     using A = const Char[2u];
2879     return detail::fixedstring::Helper::concat_<Char>(
2880         A{a, Char(0)},
2881         1u,
2882         b.data_,
2883         b.size_,
2884         folly::make_index_sequence<N + 1u>{});
2885   }
2886
2887   /**
2888    * \overload
2889    */
2890   friend constexpr BasicFixedString<Char, N + 1u> operator+(
2891       const BasicFixedString& a,
2892       Char b) noexcept {
2893     using A = const Char[2u];
2894     return detail::fixedstring::Helper::concat_<Char>(
2895         a.data_,
2896         a.size_,
2897         A{b, Char(0)},
2898         1u,
2899         folly::make_index_sequence<N + 1u>{});
2900   }
2901 };
2902
2903 template <class C, std::size_t N>
2904 inline std::basic_ostream<C>& operator<<(
2905     std::basic_ostream<C>& os,
2906     const BasicFixedString<C, N>& string) {
2907   using StreamSize = decltype(os.width());
2908   os.write(string.begin(), static_cast<StreamSize>(string.size()));
2909   return os;
2910 }
2911
2912 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2913  * Symmetric relational operators
2914  */
2915 template <class Char, std::size_t A, std::size_t B>
2916 constexpr bool operator==(
2917     const BasicFixedString<Char, A>& a,
2918     const BasicFixedString<Char, B>& b) noexcept {
2919   return detail::fixedstring::equal_(
2920       detail::fixedstring::Helper::data_(a),
2921       a.size(),
2922       detail::fixedstring::Helper::data_(b),
2923       b.size());
2924 }
2925
2926 template <class Char, std::size_t A, std::size_t B>
2927 constexpr bool operator!=(
2928     const BasicFixedString<Char, A>& a,
2929     const BasicFixedString<Char, B>& b) {
2930   return !(a == b);
2931 }
2932
2933 template <class Char, std::size_t A, std::size_t B>
2934 constexpr bool operator<(
2935     const BasicFixedString<Char, A>& a,
2936     const BasicFixedString<Char, B>& b) noexcept {
2937   return detail::fixedstring::Cmp::LT ==
2938       detail::fixedstring::compare_(
2939              detail::fixedstring::Helper::data_(a),
2940              0u,
2941              a.size(),
2942              detail::fixedstring::Helper::data_(b),
2943              0u,
2944              b.size());
2945 }
2946
2947 template <class Char, std::size_t A, std::size_t B>
2948 constexpr bool operator>(
2949     const BasicFixedString<Char, A>& a,
2950     const BasicFixedString<Char, B>& b) noexcept {
2951   return b < a;
2952 }
2953
2954 template <class Char, std::size_t A, std::size_t B>
2955 constexpr bool operator<=(
2956     const BasicFixedString<Char, A>& a,
2957     const BasicFixedString<Char, B>& b) noexcept {
2958   return !(b < a);
2959 }
2960
2961 template <class Char, std::size_t A, std::size_t B>
2962 constexpr bool operator>=(
2963     const BasicFixedString<Char, A>& a,
2964     const BasicFixedString<Char, B>& b) noexcept {
2965   return !(a < b);
2966 }
2967
2968 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2969  * Symmetric concatenation
2970  */
2971 template <class Char, std::size_t N, std::size_t M>
2972 constexpr BasicFixedString<Char, N + M> operator+(
2973     const BasicFixedString<Char, N>& a,
2974     const BasicFixedString<Char, M>& b) noexcept {
2975   return detail::fixedstring::Helper::concat_<Char>(
2976       detail::fixedstring::Helper::data_(a),
2977       a.size(),
2978       detail::fixedstring::Helper::data_(b),
2979       b.size(),
2980       folly::make_index_sequence<N + M>{});
2981 }
2982
2983 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2984  * Construct a `BasicFixedString` object from a null-terminated array of
2985  * characters. The capacity and size of the string will be equal to one less
2986  * than the size of the array.
2987  * \pre `a` contains no embedded null characters.
2988  * \pre `a[N-1] == Char(0)`
2989  * \post For a returned string `s`, `s[i]==a[i]` for every `i` in [`0`,`N-1`].
2990  */
2991 template <class Char, std::size_t N>
2992 constexpr BasicFixedString<Char, N - 1u> makeFixedString(
2993     const Char (&a)[N]) noexcept {
2994   return {a};
2995 }
2996
2997 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
2998  * Swap function
2999  */
3000 template <class Char, std::size_t N>
3001 FOLLY_CPP14_CONSTEXPR void swap(
3002     BasicFixedString<Char, N>& a,
3003     BasicFixedString<Char, N>& b) noexcept {
3004   a.swap(b);
3005 }
3006
3007 inline namespace literals {
3008 inline namespace string_literals {
3009 inline namespace {
3010 // "const std::size_t&" is so that folly::npos has the same address in every
3011 // translation unit. This is to avoid potential violations of the ODR.
3012 constexpr const std::size_t& npos = detail::fixedstring::FixedStringBase::npos;
3013 } // namespace
3014
3015 #if defined(__GNUC__)
3016 #pragma GCC diagnostic push
3017 #pragma GCC diagnostic ignored "-Wpragmas"
3018 #pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template"
3019
3020 /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
3021  * User-defined literals for creating FixedString objects from string literals
3022  * on the compilers that support it.
3023  *
3024  * \par Example:
3025  * \par
3026  * \code
3027  * using namespace folly::string_literals;
3028  * constexpr auto hello = "hello world!"_fs;
3029  * \endcode
3030  *
3031  * \note This requires a GNU compiler extension
3032  *   (-Wgnu-string-literal-operator-template) supported by clang and gcc,
3033  *   proposed for standardization in
3034  *   <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0424r0.pdf>.
3035  *   \par
3036  *   For portable code, prefer the suffixes `_fs4`, `_fs8`, `_fs16`, `_fs32`,
3037  *   `_fs64`, and `_fs128` for creating instances of types `FixedString<4>`,
3038  *   `FixedString<8>`, `FixedString<16>`, etc.
3039  */
3040 template <class Char, Char... Cs>
3041 constexpr BasicFixedString<Char, sizeof...(Cs)> operator"" _fs() noexcept {
3042   using A = const Char[sizeof...(Cs) + 1u];
3043   // The `+` in `+A{etc}` forces the array type to decay to a pointer
3044   return {+A{Cs..., Char(0)}, sizeof...(Cs)};
3045 }
3046
3047 #pragma GCC diagnostic pop
3048 #endif
3049
3050 #define FOLLY_DEFINE_FIXED_STRING_UDL(N)                     \
3051   constexpr FixedString<N> operator"" _fs##N(                \
3052       const char* that, std::size_t count) noexcept(false) { \
3053     return {that, count};                                    \
3054   }                                                          \
3055 /**/
3056
3057 // Define UDLs _fs4, _fs8, _fs16, etc for FixedString<[4, 8, 16, ...]>
3058 FOLLY_DEFINE_FIXED_STRING_UDL(4)
3059 FOLLY_DEFINE_FIXED_STRING_UDL(8)
3060 FOLLY_DEFINE_FIXED_STRING_UDL(16)
3061 FOLLY_DEFINE_FIXED_STRING_UDL(32)
3062 FOLLY_DEFINE_FIXED_STRING_UDL(64)
3063 FOLLY_DEFINE_FIXED_STRING_UDL(128)
3064
3065 #undef FOLLY_DEFINE_FIXED_STRING_UDL
3066 } // namespace string_literals
3067 } // namespace literals
3068
3069 // TODO:
3070 // // numeric conversions:
3071 // template <std::size_t N>
3072 // constexpr int stoi(const FixedString<N>& str, int base = 10);
3073 // template <std::size_t N>
3074 // constexpr unsigned stou(const FixedString<N>& str, int base = 10);
3075 // template <std::size_t N>
3076 // constexpr long stol(const FixedString<N>& str, int base = 10);
3077 // template <std::size_t N>
3078 // constexpr unsigned long stoul(const FixedString<N>& str, int base = 10;
3079 // template <std::size_t N>
3080 // constexpr long long stoll(const FixedString<N>& str, int base = 10);
3081 // template <std::size_t N>
3082 // constexpr unsigned long long stoull(const FixedString<N>& str,
3083 // int base = 10);
3084 // template <std::size_t N>
3085 // constexpr float stof(const FixedString<N>& str);
3086 // template <std::size_t N>
3087 // constexpr double stod(const FixedString<N>& str);
3088 // template <std::size_t N>
3089 // constexpr long double stold(const FixedString<N>& str);
3090 // template <int val>
3091 // constexpr FixedString</*...*/> to_fixed_string_i() noexcept;
3092 // template <unsigned val>
3093 // constexpr FixedString</*...*/> to_fixed_string_u() noexcept;
3094 // template <long val>
3095 // constexpr FixedString</*...*/> to_fixed_string_l() noexcept;
3096 // template <unsigned long val>
3097 // constexpr FixedString</*...*/> to_fixed_string_ul() noexcept;
3098 // template <long long val>
3099 // constexpr FixedString</*...*/> to_fixed_string_ll() noexcept
3100 // template <unsigned long long val>
3101 // constexpr FixedString</*...*/> to_fixed_string_ull() noexcept;
3102 } // namespace folly