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