update stats APIs to use TimePoint vs Duration correctly
[folly.git] / folly / FBString.h
1 /*
2  * Copyright 2016 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: Andrei Alexandrescu (aalexandre)
18 // String type.
19
20 #pragma once
21
22 #include <atomic>
23 #include <limits>
24 #include <type_traits>
25
26 // This file appears in two locations: inside fbcode and in the
27 // libstdc++ source code (when embedding fbstring as std::string).
28 // To aid in this schizophrenic use, _LIBSTDCXX_FBSTRING is defined in
29 // libstdc++'s c++config.h, to gate use inside fbcode v. libstdc++.
30 #ifdef _LIBSTDCXX_FBSTRING
31
32 #pragma GCC system_header
33
34 #include "basic_fbstring_malloc.h"
35
36 // When used as std::string replacement always disable assertions.
37 #define FBSTRING_ASSERT(expr) /* empty */
38
39 #else // !_LIBSTDCXX_FBSTRING
40
41 #include <folly/Portability.h>
42
43 // libc++ doesn't provide this header, nor does msvc
44 #ifdef FOLLY_HAVE_BITS_CXXCONFIG_H
45 #include <bits/c++config.h>
46 #endif
47
48 #include <algorithm>
49 #include <cassert>
50 #include <cstring>
51 #include <string>
52 #include <utility>
53
54 #include <folly/Hash.h>
55 #include <folly/Malloc.h>
56 #include <folly/Traits.h>
57
58 #if FOLLY_HAVE_DEPRECATED_ASSOC
59 #ifdef _GLIBCXX_SYMVER
60 #include <ext/hash_set>
61 #include <ext/hash_map>
62 #endif
63 #endif
64
65 // When used in folly, assertions are not disabled.
66 #define FBSTRING_ASSERT(expr) assert(expr)
67
68 #endif
69
70 // We defined these here rather than including Likely.h to avoid
71 // redefinition errors when fbstring is imported into libstdc++.
72 #if defined(__GNUC__) && __GNUC__ >= 4
73 #define FBSTRING_LIKELY(x)   (__builtin_expect((x), 1))
74 #define FBSTRING_UNLIKELY(x) (__builtin_expect((x), 0))
75 #else
76 #define FBSTRING_LIKELY(x)   (x)
77 #define FBSTRING_UNLIKELY(x) (x)
78 #endif
79
80 #pragma GCC diagnostic push
81 // Ignore shadowing warnings within this file, so includers can use -Wshadow.
82 #pragma GCC diagnostic ignored "-Wshadow"
83 // GCC 4.9 has a false positive in setSmallSize (probably
84 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124), disable
85 // compile-time array bound checking.
86 #pragma GCC diagnostic ignored "-Warray-bounds"
87
88 // FBString cannot use throw when replacing std::string, though it may still
89 // use std::__throw_*
90 // nolint
91 #define throw FOLLY_FBSTRING_MAY_NOT_USE_THROW
92
93 #ifdef _LIBSTDCXX_FBSTRING
94 namespace std _GLIBCXX_VISIBILITY(default) {
95 _GLIBCXX_BEGIN_NAMESPACE_VERSION
96 #else
97 namespace folly {
98 #endif
99
100 #if defined(__clang__)
101 # if __has_feature(address_sanitizer)
102 #  define FBSTRING_SANITIZE_ADDRESS
103 # endif
104 #elif defined (__GNUC__) && \
105       (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ >= 5)) && \
106       __SANITIZE_ADDRESS__
107 # define FBSTRING_SANITIZE_ADDRESS
108 #endif
109
110 // When compiling with ASan, always heap-allocate the string even if
111 // it would fit in-situ, so that ASan can detect access to the string
112 // buffer after it has been invalidated (destroyed, resized, etc.).
113 // Note that this flag doesn't remove support for in-situ strings, as
114 // that would break ABI-compatibility and wouldn't allow linking code
115 // compiled with this flag with code compiled without.
116 #ifdef FBSTRING_SANITIZE_ADDRESS
117 # define FBSTRING_DISABLE_SSO true
118 #else
119 # define FBSTRING_DISABLE_SSO false
120 #endif
121
122 namespace fbstring_detail {
123
124 template <class InIt, class OutIt>
125 inline std::pair<InIt, OutIt> copy_n(
126     InIt b,
127     typename std::iterator_traits<InIt>::difference_type n,
128     OutIt d) {
129   for (; n != 0; --n, ++b, ++d) {
130     *d = *b;
131   }
132   return std::make_pair(b, d);
133 }
134
135 template <class Pod, class T>
136 inline void podFill(Pod* b, Pod* e, T c) {
137   FBSTRING_ASSERT(b && e && b <= e);
138   /*static*/ if (sizeof(T) == 1) {
139     memset(b, c, e - b);
140   } else {
141     auto const ee = b + ((e - b) & ~7u);
142     for (; b != ee; b += 8) {
143       b[0] = c;
144       b[1] = c;
145       b[2] = c;
146       b[3] = c;
147       b[4] = c;
148       b[5] = c;
149       b[6] = c;
150       b[7] = c;
151     }
152     // Leftovers
153     for (; b != e; ++b) {
154       *b = c;
155     }
156   }
157 }
158
159 /*
160  * Lightly structured memcpy, simplifies copying PODs and introduces
161  * some asserts. Unfortunately using this function may cause
162  * measurable overhead (presumably because it adjusts from a begin/end
163  * convention to a pointer/size convention, so it does some extra
164  * arithmetic even though the caller might have done the inverse
165  * adaptation outside).
166  */
167 template <class Pod>
168 inline void podCopy(const Pod* b, const Pod* e, Pod* d) {
169   FBSTRING_ASSERT(e >= b);
170   FBSTRING_ASSERT(d >= e || d + (e - b) <= b);
171   memcpy(d, b, (e - b) * sizeof(Pod));
172 }
173
174 /*
175  * Lightly structured memmove, simplifies copying PODs and introduces
176  * some asserts
177  */
178 template <class Pod>
179 inline void podMove(const Pod* b, const Pod* e, Pod* d) {
180   FBSTRING_ASSERT(e >= b);
181   memmove(d, b, (e - b) * sizeof(*b));
182 }
183
184 // always inline
185 #if defined(__GNUC__) // Clang also defines __GNUC__
186 # define FBSTRING_ALWAYS_INLINE inline __attribute__((__always_inline__))
187 #elif defined(_MSC_VER)
188 # define FBSTRING_ALWAYS_INLINE __forceinline
189 #else
190 # define FBSTRING_ALWAYS_INLINE inline
191 #endif
192
193 [[noreturn]] FBSTRING_ALWAYS_INLINE void assume_unreachable() {
194 #if defined(__GNUC__) // Clang also defines __GNUC__
195   __builtin_unreachable();
196 #elif defined(_MSC_VER)
197   __assume(0);
198 #else
199   // Well, it's better than nothing.
200   std::abort();
201 #endif
202 }
203
204 } // namespace fbstring_detail
205
206 /**
207  * Defines a special acquisition method for constructing fbstring
208  * objects. AcquireMallocatedString means that the user passes a
209  * pointer to a malloc-allocated string that the fbstring object will
210  * take into custody.
211  */
212 enum class AcquireMallocatedString {};
213
214 /*
215  * fbstring_core_model is a mock-up type that defines all required
216  * signatures of a fbstring core. The fbstring class itself uses such
217  * a core object to implement all of the numerous member functions
218  * required by the standard.
219  *
220  * If you want to define a new core, copy the definition below and
221  * implement the primitives. Then plug the core into basic_fbstring as
222  * a template argument.
223
224 template <class Char>
225 class fbstring_core_model {
226 public:
227   fbstring_core_model();
228   fbstring_core_model(const fbstring_core_model &);
229   ~fbstring_core_model();
230   // Returns a pointer to string's buffer (currently only contiguous
231   // strings are supported). The pointer is guaranteed to be valid
232   // until the next call to a non-const member function.
233   const Char * data() const;
234   // Much like data(), except the string is prepared to support
235   // character-level changes. This call is a signal for
236   // e.g. reference-counted implementation to fork the data. The
237   // pointer is guaranteed to be valid until the next call to a
238   // non-const member function.
239   Char* mutableData();
240   // Returns a pointer to string's buffer and guarantees that a
241   // readable '\0' lies right after the buffer. The pointer is
242   // guaranteed to be valid until the next call to a non-const member
243   // function.
244   const Char * c_str() const;
245   // Shrinks the string by delta characters. Asserts that delta <=
246   // size().
247   void shrink(size_t delta);
248   // Expands the string by delta characters (i.e. after this call
249   // size() will report the old size() plus delta) but without
250   // initializing the expanded region. The expanded region is
251   // zero-terminated. Returns a pointer to the memory to be
252   // initialized (the beginning of the expanded portion). The caller
253   // is expected to fill the expanded area appropriately.
254   // If expGrowth is true, exponential growth is guaranteed.
255   // It is not guaranteed not to reallocate even if size() + delta <
256   // capacity(), so all references to the buffer are invalidated.
257   Char* expandNoinit(size_t delta, bool expGrowth);
258   // Expands the string by one character and sets the last character
259   // to c.
260   void push_back(Char c);
261   // Returns the string's size.
262   size_t size() const;
263   // Returns the string's capacity, i.e. maximum size that the string
264   // can grow to without reallocation. Note that for reference counted
265   // strings that's technically a lie - even assigning characters
266   // within the existing size would cause a reallocation.
267   size_t capacity() const;
268   // Returns true if the data underlying the string is actually shared
269   // across multiple strings (in a refcounted fashion).
270   bool isShared() const;
271   // Makes sure that at least minCapacity characters are available for
272   // the string without reallocation. For reference-counted strings,
273   // it should fork the data even if minCapacity < size().
274   void reserve(size_t minCapacity);
275 private:
276   // Do not implement
277   fbstring_core_model& operator=(const fbstring_core_model &);
278 };
279 */
280
281 /**
282  * This is the core of the string. The code should work on 32- and
283  * 64-bit and both big- and little-endianan architectures with any
284  * Char size.
285  *
286  * The storage is selected as follows (assuming we store one-byte
287  * characters on a 64-bit machine): (a) "small" strings between 0 and
288  * 23 chars are stored in-situ without allocation (the rightmost byte
289  * stores the size); (b) "medium" strings from 24 through 254 chars
290  * are stored in malloc-allocated memory that is copied eagerly; (c)
291  * "large" strings of 255 chars and above are stored in a similar
292  * structure as medium arrays, except that the string is
293  * reference-counted and copied lazily. the reference count is
294  * allocated right before the character array.
295  *
296  * The discriminator between these three strategies sits in two
297  * bits of the rightmost char of the storage. If neither is set, then the
298  * string is small (and its length sits in the lower-order bits on
299  * little-endian or the high-order bits on big-endian of that
300  * rightmost character). If the MSb is set, the string is medium width.
301  * If the second MSb is set, then the string is large. On little-endian,
302  * these 2 bits are the 2 MSbs of MediumLarge::capacity_, while on
303  * big-endian, these 2 bits are the 2 LSbs. This keeps both little-endian
304  * and big-endian fbstring_core equivalent with merely different ops used
305  * to extract capacity/category.
306  */
307 template <class Char> class fbstring_core {
308 protected:
309 // It's MSVC, so we just have to guess ... and allow an override
310 #ifdef _MSC_VER
311 # ifdef FOLLY_ENDIAN_BE
312   static constexpr auto kIsLittleEndian = false;
313 # else
314   static constexpr auto kIsLittleEndian = true;
315 # endif
316 #else
317   static constexpr auto kIsLittleEndian =
318       __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__;
319 #endif
320 public:
321   fbstring_core() noexcept { reset(); }
322
323   fbstring_core(const fbstring_core & rhs) {
324     FBSTRING_ASSERT(&rhs != this);
325     switch (rhs.category()) {
326       case Category::isSmall:
327         copySmall(rhs);
328         break;
329       case Category::isMedium:
330         copyMedium(rhs);
331         break;
332       case Category::isLarge:
333         copyLarge(rhs);
334         break;
335       default:
336         fbstring_detail::assume_unreachable();
337     }
338     FBSTRING_ASSERT(size() == rhs.size());
339     FBSTRING_ASSERT(memcmp(data(), rhs.data(), size() * sizeof(Char)) == 0);
340   }
341
342   fbstring_core(fbstring_core&& goner) noexcept {
343     // Take goner's guts
344     ml_ = goner.ml_;
345     // Clean goner's carcass
346     goner.reset();
347   }
348
349   fbstring_core(const Char *const data,
350                 const size_t size,
351                 bool disableSSO = FBSTRING_DISABLE_SSO) {
352     if (!disableSSO && size <= maxSmallSize) {
353       initSmall(data, size);
354     } else if (size <= maxMediumSize) {
355       initMedium(data, size);
356     } else {
357       initLarge(data, size);
358     }
359     FBSTRING_ASSERT(this->size() == size);
360     FBSTRING_ASSERT(
361         size == 0 || memcmp(this->data(), data, size * sizeof(Char)) == 0);
362   }
363
364   ~fbstring_core() noexcept {
365     auto const c = category();
366     if (c == Category::isSmall) {
367       return;
368     }
369     if (c == Category::isMedium) {
370       free(ml_.data_);
371       return;
372     }
373     RefCounted::decrementRefs(ml_.data_);
374   }
375
376   // Snatches a previously mallocated string. The parameter "size"
377   // is the size of the string, and the parameter "allocatedSize"
378   // is the size of the mallocated block.  The string must be
379   // \0-terminated, so allocatedSize >= size + 1 and data[size] == '\0'.
380   //
381   // So if you want a 2-character string, pass malloc(3) as "data",
382   // pass 2 as "size", and pass 3 as "allocatedSize".
383   fbstring_core(Char * const data,
384                 const size_t size,
385                 const size_t allocatedSize,
386                 AcquireMallocatedString) {
387     if (size > 0) {
388       FBSTRING_ASSERT(allocatedSize >= size + 1);
389       FBSTRING_ASSERT(data[size] == '\0');
390       // Use the medium string storage
391       ml_.data_ = data;
392       ml_.size_ = size;
393       // Don't forget about null terminator
394       ml_.setCapacity(allocatedSize - 1, Category::isMedium);
395     } else {
396       // No need for the memory
397       free(data);
398       reset();
399     }
400   }
401
402   // swap below doesn't test whether &rhs == this (and instead
403   // potentially does extra work) on the premise that the rarity of
404   // that situation actually makes the check more expensive than is
405   // worth.
406   void swap(fbstring_core & rhs) {
407     auto const t = ml_;
408     ml_ = rhs.ml_;
409     rhs.ml_ = t;
410   }
411
412   // In C++11 data() and c_str() are 100% equivalent.
413   const Char * data() const {
414     return c_str();
415   }
416
417   Char* mutableData() {
418     switch (category()) {
419     case Category::isSmall:
420       return small_;
421     case Category::isMedium:
422       return ml_.data_;
423     case Category::isLarge:
424       return mutableDataLarge();
425     }
426     fbstring_detail::assume_unreachable();
427   }
428
429   const Char * c_str() const {
430     auto const c = category();
431     if (c == Category::isSmall) {
432       FBSTRING_ASSERT(small_[smallSize()] == '\0');
433       return small_;
434     }
435     FBSTRING_ASSERT(c == Category::isMedium || c == Category::isLarge);
436     FBSTRING_ASSERT(ml_.data_[ml_.size_] == '\0');
437     return ml_.data_;
438   }
439
440   void shrink(const size_t delta) {
441     if (category() == Category::isSmall) {
442       shrinkSmall(delta);
443     } else if (category() == Category::isMedium ||
444                RefCounted::refs(ml_.data_) == 1) {
445       shrinkMedium(delta);
446     } else {
447       shrinkLarge(delta);
448     }
449   }
450
451   void reserve(size_t minCapacity, bool disableSSO = FBSTRING_DISABLE_SSO) {
452     switch (category()) {
453       case Category::isSmall:
454         reserveSmall(minCapacity, disableSSO);
455         break;
456       case Category::isMedium:
457         reserveMedium(minCapacity);
458         break;
459       case Category::isLarge:
460         reserveLarge(minCapacity);
461         break;
462       default:
463         fbstring_detail::assume_unreachable();
464     }
465     FBSTRING_ASSERT(capacity() >= minCapacity);
466   }
467
468   Char* expandNoinit(
469       const size_t delta,
470       bool expGrowth = false,
471       bool disableSSO = FBSTRING_DISABLE_SSO);
472
473   void push_back(Char c) {
474     *expandNoinit(1, /* expGrowth = */ true) = c;
475   }
476
477   size_t size() const {
478     return category() == Category::isSmall ? smallSize() : ml_.size_;
479   }
480
481   size_t capacity() const {
482     switch (category()) {
483       case Category::isSmall:
484         return maxSmallSize;
485       case Category::isLarge:
486         // For large-sized strings, a multi-referenced chunk has no
487         // available capacity. This is because any attempt to append
488         // data would trigger a new allocation.
489         if (RefCounted::refs(ml_.data_) > 1) {
490           return ml_.size_;
491         }
492       default: {}
493     }
494     return ml_.capacity();
495   }
496
497   bool isShared() const {
498     return category() == Category::isLarge && RefCounted::refs(ml_.data_) > 1;
499   }
500
501 private:
502   // Disabled
503   fbstring_core & operator=(const fbstring_core & rhs);
504
505   // Equivalent to setSmallSize(0) but a few ns faster in
506   // microbenchmarks.
507   void reset() {
508     ml_.capacity_ = kIsLittleEndian
509       ? maxSmallSize << (8 * (sizeof(size_t) - sizeof(Char)))
510       : maxSmallSize << 2;
511     small_[0] = '\0';
512     FBSTRING_ASSERT(category() == Category::isSmall && size() == 0);
513   }
514
515   struct RefCounted {
516     std::atomic<size_t> refCount_;
517     Char data_[1];
518
519     static RefCounted * fromData(Char * p) {
520       return static_cast<RefCounted*>(
521         static_cast<void*>(
522           static_cast<unsigned char*>(static_cast<void*>(p))
523           - sizeof(refCount_)));
524     }
525
526     static size_t refs(Char * p) {
527       return fromData(p)->refCount_.load(std::memory_order_acquire);
528     }
529
530     static void incrementRefs(Char * p) {
531       fromData(p)->refCount_.fetch_add(1, std::memory_order_acq_rel);
532     }
533
534     static void decrementRefs(Char * p) {
535       auto const dis = fromData(p);
536       size_t oldcnt = dis->refCount_.fetch_sub(1, std::memory_order_acq_rel);
537       FBSTRING_ASSERT(oldcnt > 0);
538       if (oldcnt == 1) {
539         free(dis);
540       }
541     }
542
543     static RefCounted * create(size_t * size) {
544       // Don't forget to allocate one extra Char for the terminating
545       // null. In this case, however, one Char is already part of the
546       // struct.
547       const size_t allocSize = goodMallocSize(
548         sizeof(RefCounted) + *size * sizeof(Char));
549       auto result = static_cast<RefCounted*>(checkedMalloc(allocSize));
550       result->refCount_.store(1, std::memory_order_release);
551       *size = (allocSize - sizeof(RefCounted)) / sizeof(Char);
552       return result;
553     }
554
555     static RefCounted * create(const Char * data, size_t * size) {
556       const size_t effectiveSize = *size;
557       auto result = create(size);
558       fbstring_detail::podCopy(data, data + effectiveSize, result->data_);
559       return result;
560     }
561
562     static RefCounted * reallocate(Char *const data,
563                                    const size_t currentSize,
564                                    const size_t currentCapacity,
565                                    const size_t newCapacity) {
566       FBSTRING_ASSERT(newCapacity > 0 && newCapacity > currentSize);
567       auto const dis = fromData(data);
568       FBSTRING_ASSERT(dis->refCount_.load(std::memory_order_acquire) == 1);
569       // Don't forget to allocate one extra Char for the terminating
570       // null. In this case, however, one Char is already part of the
571       // struct.
572       auto result = static_cast<RefCounted*>(
573              smartRealloc(dis,
574                           sizeof(RefCounted) + currentSize * sizeof(Char),
575                           sizeof(RefCounted) + currentCapacity * sizeof(Char),
576                           sizeof(RefCounted) + newCapacity * sizeof(Char)));
577       FBSTRING_ASSERT(result->refCount_.load(std::memory_order_acquire) == 1);
578       return result;
579     }
580   };
581
582   typedef std::conditional<sizeof(size_t) == 4, uint32_t, uint64_t>::type
583           category_type;
584
585   enum class Category : category_type {
586     isSmall = 0,
587     isMedium = kIsLittleEndian
588       ? sizeof(size_t) == 4 ? 0x80000000 : 0x8000000000000000
589       : 0x2,
590     isLarge =  kIsLittleEndian
591       ? sizeof(size_t) == 4 ? 0x40000000 : 0x4000000000000000
592       : 0x1,
593   };
594
595   Category category() const {
596     // works for both big-endian and little-endian
597     return static_cast<Category>(ml_.capacity_ & categoryExtractMask);
598   }
599
600   struct MediumLarge {
601     Char * data_;
602     size_t size_;
603     size_t capacity_;
604
605     size_t capacity() const {
606       return kIsLittleEndian
607         ? capacity_ & capacityExtractMask
608         : capacity_ >> 2;
609     }
610
611     void setCapacity(size_t cap, Category cat) {
612         capacity_ = kIsLittleEndian
613           ? cap | static_cast<category_type>(cat)
614           : (cap << 2) | static_cast<category_type>(cat);
615     }
616   };
617
618   union {
619     Char small_[sizeof(MediumLarge) / sizeof(Char)];
620     MediumLarge ml_;
621   };
622
623   enum : size_t {
624     lastChar = sizeof(MediumLarge) - 1,
625     maxSmallSize = lastChar / sizeof(Char),
626     maxMediumSize = 254 / sizeof(Char),            // coincides with the small
627                                                    // bin size in dlmalloc
628     categoryExtractMask = kIsLittleEndian
629       ? sizeof(size_t) == 4 ? 0xC0000000 : size_t(0xC000000000000000)
630       : 0x3,
631     capacityExtractMask = kIsLittleEndian
632       ? ~categoryExtractMask
633       : 0x0 /*unused*/,
634   };
635   static_assert(!(sizeof(MediumLarge) % sizeof(Char)),
636                 "Corrupt memory layout for fbstring.");
637
638   size_t smallSize() const {
639     FBSTRING_ASSERT(category() == Category::isSmall);
640     constexpr auto shift = kIsLittleEndian ? 0 : 2;
641     auto smallShifted = static_cast<size_t>(small_[maxSmallSize]) >> shift;
642     FBSTRING_ASSERT(static_cast<size_t>(maxSmallSize) >= smallShifted);
643     return static_cast<size_t>(maxSmallSize) - smallShifted;
644   }
645
646   void setSmallSize(size_t s) {
647     // Warning: this should work with uninitialized strings too,
648     // so don't assume anything about the previous value of
649     // small_[maxSmallSize].
650     FBSTRING_ASSERT(s <= maxSmallSize);
651     constexpr auto shift = kIsLittleEndian ? 0 : 2;
652     small_[maxSmallSize] = (maxSmallSize - s) << shift;
653     small_[s] = '\0';
654     FBSTRING_ASSERT(category() == Category::isSmall && size() == s);
655   }
656
657   void copySmall(const fbstring_core&);
658   void copyMedium(const fbstring_core&);
659   void copyLarge(const fbstring_core&);
660
661   void initSmall(const Char* data, size_t size);
662   void initMedium(const Char* data, size_t size);
663   void initLarge(const Char* data, size_t size);
664
665   void reserveSmall(size_t minCapacity, bool disableSSO);
666   void reserveMedium(size_t minCapacity);
667   void reserveLarge(size_t minCapacity);
668
669   void shrinkSmall(size_t delta);
670   void shrinkMedium(size_t delta);
671   void shrinkLarge(size_t delta);
672
673   Char* mutableDataLarge();
674 };
675
676 template <class Char>
677 inline void fbstring_core<Char>::copySmall(const fbstring_core& rhs) {
678   static_assert(offsetof(MediumLarge, data_) == 0, "fbstring layout failure");
679   static_assert(
680       offsetof(MediumLarge, size_) == sizeof(ml_.data_),
681       "fbstring layout failure");
682   static_assert(
683       offsetof(MediumLarge, capacity_) == 2 * sizeof(ml_.data_),
684       "fbstring layout failure");
685   // Just write the whole thing, don't look at details. In
686   // particular we need to copy capacity anyway because we want
687   // to set the size (don't forget that the last character,
688   // which stores a short string's length, is shared with the
689   // ml_.capacity field).
690   ml_ = rhs.ml_;
691   FBSTRING_ASSERT(
692       category() == Category::isSmall && this->size() == rhs.size());
693 }
694
695 template <class Char>
696 inline void fbstring_core<Char>::copyMedium(const fbstring_core& rhs) {
697   // Medium strings are copied eagerly. Don't forget to allocate
698   // one extra Char for the null terminator.
699   auto const allocSize = goodMallocSize((1 + rhs.ml_.size_) * sizeof(Char));
700   ml_.data_ = static_cast<Char*>(checkedMalloc(allocSize));
701   // Also copies terminator.
702   fbstring_detail::podCopy(
703       rhs.ml_.data_, rhs.ml_.data_ + rhs.ml_.size_ + 1, ml_.data_);
704   ml_.size_ = rhs.ml_.size_;
705   ml_.setCapacity(allocSize / sizeof(Char) - 1, Category::isMedium);
706   FBSTRING_ASSERT(category() == Category::isMedium);
707 }
708
709 template <class Char>
710 inline void fbstring_core<Char>::copyLarge(const fbstring_core& rhs) {
711   // Large strings are just refcounted
712   ml_ = rhs.ml_;
713   RefCounted::incrementRefs(ml_.data_);
714   FBSTRING_ASSERT(category() == Category::isLarge && size() == rhs.size());
715 }
716
717 // Small strings are bitblitted
718 template <class Char>
719 inline void fbstring_core<Char>::initSmall(
720     const Char* const data, const size_t size) {
721   // Layout is: Char* data_, size_t size_, size_t capacity_
722   static_assert(
723       sizeof(*this) == sizeof(Char*) + 2 * sizeof(size_t),
724       "fbstring has unexpected size");
725   static_assert(
726       sizeof(Char*) == sizeof(size_t), "fbstring size assumption violation");
727   // sizeof(size_t) must be a power of 2
728   static_assert(
729       (sizeof(size_t) & (sizeof(size_t) - 1)) == 0,
730       "fbstring size assumption violation");
731
732 // If data is aligned, use fast word-wise copying. Otherwise,
733 // use conservative memcpy.
734 // The word-wise path reads bytes which are outside the range of
735 // the string, and makes ASan unhappy, so we disable it when
736 // compiling with ASan.
737 #ifndef FBSTRING_SANITIZE_ADDRESS
738   if ((reinterpret_cast<size_t>(data) & (sizeof(size_t) - 1)) == 0) {
739     const size_t byteSize = size * sizeof(Char);
740     constexpr size_t wordWidth = sizeof(size_t);
741     switch ((byteSize + wordWidth - 1) / wordWidth) { // Number of words.
742       case 3:
743         ml_.capacity_ = reinterpret_cast<const size_t*>(data)[2];
744       case 2:
745         ml_.size_ = reinterpret_cast<const size_t*>(data)[1];
746       case 1:
747         ml_.data_ = *reinterpret_cast<Char**>(const_cast<Char*>(data));
748       case 0:
749         break;
750     }
751   } else
752 #endif
753   {
754     if (size != 0) {
755       fbstring_detail::podCopy(data, data + size, small_);
756     }
757   }
758   setSmallSize(size);
759 }
760
761 template <class Char>
762 inline void fbstring_core<Char>::initMedium(
763     const Char* const data, const size_t size) {
764   // Medium strings are allocated normally. Don't forget to
765   // allocate one extra Char for the terminating null.
766   auto const allocSize = goodMallocSize((1 + size) * sizeof(Char));
767   ml_.data_ = static_cast<Char*>(checkedMalloc(allocSize));
768   fbstring_detail::podCopy(data, data + size, ml_.data_);
769   ml_.size_ = size;
770   ml_.setCapacity(allocSize / sizeof(Char) - 1, Category::isMedium);
771   ml_.data_[size] = '\0';
772 }
773
774 template <class Char>
775 inline void fbstring_core<Char>::initLarge(
776     const Char* const data, const size_t size) {
777   // Large strings are allocated differently
778   size_t effectiveCapacity = size;
779   auto const newRC = RefCounted::create(data, &effectiveCapacity);
780   ml_.data_ = newRC->data_;
781   ml_.size_ = size;
782   ml_.setCapacity(effectiveCapacity, Category::isLarge);
783   ml_.data_[size] = '\0';
784 }
785
786 template <class Char>
787 inline Char* fbstring_core<Char>::mutableDataLarge() {
788   FBSTRING_ASSERT(category() == Category::isLarge);
789   if (RefCounted::refs(ml_.data_) > 1) {
790     // Ensure unique.
791     size_t effectiveCapacity = ml_.capacity();
792     auto const newRC = RefCounted::create(&effectiveCapacity);
793     // If this fails, someone placed the wrong capacity in an
794     // fbstring.
795     FBSTRING_ASSERT(effectiveCapacity >= ml_.capacity());
796     // Also copies terminator.
797     fbstring_detail::podCopy(
798         ml_.data_, ml_.data_ + ml_.size_ + 1, newRC->data_);
799     RefCounted::decrementRefs(ml_.data_);
800     ml_.data_ = newRC->data_;
801   }
802   return ml_.data_;
803 }
804
805 template <class Char>
806 inline void fbstring_core<Char>::reserveLarge(size_t minCapacity) {
807   FBSTRING_ASSERT(category() == Category::isLarge);
808   // Ensure unique
809   if (RefCounted::refs(ml_.data_) > 1) {
810     // We must make it unique regardless; in-place reallocation is
811     // useless if the string is shared. In order to not surprise
812     // people, reserve the new block at current capacity or
813     // more. That way, a string's capacity never shrinks after a
814     // call to reserve.
815     minCapacity = std::max(minCapacity, ml_.capacity());
816     auto const newRC = RefCounted::create(&minCapacity);
817     // Also copies terminator.
818     fbstring_detail::podCopy(
819         ml_.data_, ml_.data_ + ml_.size_ + 1, newRC->data_);
820     RefCounted::decrementRefs(ml_.data_);
821     ml_.data_ = newRC->data_;
822     ml_.setCapacity(minCapacity, Category::isLarge);
823     // size remains unchanged
824   } else {
825     // String is not shared, so let's try to realloc (if needed)
826     if (minCapacity > ml_.capacity()) {
827       // Asking for more memory
828       auto const newRC = RefCounted::reallocate(
829           ml_.data_, ml_.size_, ml_.capacity(), minCapacity);
830       ml_.data_ = newRC->data_;
831       ml_.setCapacity(minCapacity, Category::isLarge);
832     }
833     FBSTRING_ASSERT(capacity() >= minCapacity);
834   }
835 }
836
837 template <class Char>
838 inline void fbstring_core<Char>::reserveMedium(const size_t minCapacity) {
839   FBSTRING_ASSERT(category() == Category::isMedium);
840   // String is not shared
841   if (minCapacity <= ml_.capacity()) {
842     return; // nothing to do, there's enough room
843   }
844   if (minCapacity <= maxMediumSize) {
845     // Keep the string at medium size. Don't forget to allocate
846     // one extra Char for the terminating null.
847     size_t capacityBytes = goodMallocSize((1 + minCapacity) * sizeof(Char));
848     // Also copies terminator.
849     ml_.data_ = static_cast<Char*>(smartRealloc(
850         ml_.data_,
851         (ml_.size_ + 1) * sizeof(Char),
852         (ml_.capacity() + 1) * sizeof(Char),
853         capacityBytes));
854     ml_.setCapacity(capacityBytes / sizeof(Char) - 1, Category::isMedium);
855   } else {
856     // Conversion from medium to large string
857     fbstring_core nascent;
858     // Will recurse to another branch of this function
859     nascent.reserve(minCapacity);
860     nascent.ml_.size_ = ml_.size_;
861     // Also copies terminator.
862     fbstring_detail::podCopy(
863         ml_.data_, ml_.data_ + ml_.size_ + 1, nascent.ml_.data_);
864     nascent.swap(*this);
865     FBSTRING_ASSERT(capacity() >= minCapacity);
866   }
867 }
868
869 template <class Char>
870 inline void fbstring_core<Char>::reserveSmall(
871     size_t minCapacity, const bool disableSSO) {
872   FBSTRING_ASSERT(category() == Category::isSmall);
873   if (!disableSSO && minCapacity <= maxSmallSize) {
874     // small
875     // Nothing to do, everything stays put
876   } else if (minCapacity <= maxMediumSize) {
877     // medium
878     // Don't forget to allocate one extra Char for the terminating null
879     auto const allocSizeBytes =
880         goodMallocSize((1 + minCapacity) * sizeof(Char));
881     auto const pData = static_cast<Char*>(checkedMalloc(allocSizeBytes));
882     auto const size = smallSize();
883     // Also copies terminator.
884     fbstring_detail::podCopy(small_, small_ + size + 1, pData);
885     ml_.data_ = pData;
886     ml_.size_ = size;
887     ml_.setCapacity(allocSizeBytes / sizeof(Char) - 1, Category::isMedium);
888   } else {
889     // large
890     auto const newRC = RefCounted::create(&minCapacity);
891     auto const size = smallSize();
892     // Also copies terminator.
893     fbstring_detail::podCopy(small_, small_ + size + 1, newRC->data_);
894     ml_.data_ = newRC->data_;
895     ml_.size_ = size;
896     ml_.setCapacity(minCapacity, Category::isLarge);
897     FBSTRING_ASSERT(capacity() >= minCapacity);
898   }
899 }
900
901 template <class Char>
902 inline Char* fbstring_core<Char>::expandNoinit(
903     const size_t delta,
904     bool expGrowth, /* = false */
905     bool disableSSO /* = FBSTRING_DISABLE_SSO */) {
906   // Strategy is simple: make room, then change size
907   FBSTRING_ASSERT(capacity() >= size());
908   size_t sz, newSz;
909   if (category() == Category::isSmall) {
910     sz = smallSize();
911     newSz = sz + delta;
912     if (!disableSSO && FBSTRING_LIKELY(newSz <= maxSmallSize)) {
913       setSmallSize(newSz);
914       return small_ + sz;
915     }
916     reserveSmall(
917         expGrowth ? std::max(newSz, 2 * maxSmallSize) : newSz, disableSSO);
918   } else {
919     sz = ml_.size_;
920     newSz = sz + delta;
921     if (FBSTRING_UNLIKELY(newSz > capacity())) {
922       // ensures not shared
923       reserve(expGrowth ? std::max(newSz, 1 + capacity() * 3 / 2) : newSz);
924     }
925   }
926   FBSTRING_ASSERT(capacity() >= newSz);
927   // Category can't be small - we took care of that above
928   FBSTRING_ASSERT(
929       category() == Category::isMedium || category() == Category::isLarge);
930   ml_.size_ = newSz;
931   ml_.data_[newSz] = '\0';
932   FBSTRING_ASSERT(size() == newSz);
933   return ml_.data_ + sz;
934 }
935
936 template <class Char>
937 inline void fbstring_core<Char>::shrinkSmall(const size_t delta) {
938   // Check for underflow
939   FBSTRING_ASSERT(delta <= smallSize());
940   setSmallSize(smallSize() - delta);
941 }
942
943 template <class Char>
944 inline void fbstring_core<Char>::shrinkMedium(const size_t delta) {
945   // Medium strings and unique large strings need no special
946   // handling.
947   FBSTRING_ASSERT(ml_.size_ >= delta);
948   ml_.size_ -= delta;
949   ml_.data_[ml_.size_] = '\0';
950 }
951
952 template <class Char>
953 inline void fbstring_core<Char>::shrinkLarge(const size_t delta) {
954   FBSTRING_ASSERT(ml_.size_ >= delta);
955   // Shared large string, must make unique. This is because of the
956   // durn terminator must be written, which may trample the shared
957   // data.
958   if (delta) {
959     fbstring_core(ml_.data_, ml_.size_ - delta).swap(*this);
960   }
961   // No need to write the terminator.
962 }
963
964 #ifndef _LIBSTDCXX_FBSTRING
965 /**
966  * Dummy fbstring core that uses an actual std::string. This doesn't
967  * make any sense - it's just for testing purposes.
968  */
969 template <class Char>
970 class dummy_fbstring_core {
971 public:
972   dummy_fbstring_core() {
973   }
974   dummy_fbstring_core(const dummy_fbstring_core& another)
975       : backend_(another.backend_) {
976   }
977   dummy_fbstring_core(const Char * s, size_t n)
978       : backend_(s, n) {
979   }
980   void swap(dummy_fbstring_core & rhs) {
981     backend_.swap(rhs.backend_);
982   }
983   const Char * data() const {
984     return backend_.data();
985   }
986   Char* mutableData() {
987     return const_cast<Char*>(backend_.data());
988   }
989   void shrink(size_t delta) {
990     FBSTRING_ASSERT(delta <= size());
991     backend_.resize(size() - delta);
992   }
993   Char* expandNoinit(size_t delta) {
994     auto const sz = size();
995     backend_.resize(size() + delta);
996     return backend_.data() + sz;
997   }
998   void push_back(Char c) {
999     backend_.push_back(c);
1000   }
1001   size_t size() const {
1002     return backend_.size();
1003   }
1004   size_t capacity() const {
1005     return backend_.capacity();
1006   }
1007   bool isShared() const {
1008     return false;
1009   }
1010   void reserve(size_t minCapacity) {
1011     backend_.reserve(minCapacity);
1012   }
1013
1014 private:
1015   std::basic_string<Char> backend_;
1016 };
1017 #endif // !_LIBSTDCXX_FBSTRING
1018
1019 /**
1020  * This is the basic_string replacement. For conformity,
1021  * basic_fbstring takes the same template parameters, plus the last
1022  * one which is the core.
1023  */
1024 #ifdef _LIBSTDCXX_FBSTRING
1025 template <typename E, class T, class A, class Storage>
1026 #else
1027 template <typename E,
1028           class T = std::char_traits<E>,
1029           class A = std::allocator<E>,
1030           class Storage = fbstring_core<E> >
1031 #endif
1032 class basic_fbstring {
1033   static void enforce(
1034       bool condition,
1035       void (*throw_exc)(const char*),
1036       const char* msg) {
1037     if (!condition) {
1038       throw_exc(msg);
1039     }
1040   }
1041
1042   bool isSane() const {
1043     return
1044       begin() <= end() &&
1045       empty() == (size() == 0) &&
1046       empty() == (begin() == end()) &&
1047       size() <= max_size() &&
1048       capacity() <= max_size() &&
1049       size() <= capacity() &&
1050       begin()[size()] == '\0';
1051   }
1052
1053   struct Invariant {
1054     Invariant& operator=(const Invariant&) = delete;
1055     explicit Invariant(const basic_fbstring& s) noexcept : s_(s) {
1056       FBSTRING_ASSERT(s_.isSane());
1057     }
1058     ~Invariant() noexcept {
1059       FBSTRING_ASSERT(s_.isSane());
1060     }
1061
1062    private:
1063     const basic_fbstring& s_;
1064   };
1065
1066  public:
1067   // types
1068   typedef T traits_type;
1069   typedef typename traits_type::char_type value_type;
1070   typedef A allocator_type;
1071   typedef typename A::size_type size_type;
1072   typedef typename A::difference_type difference_type;
1073
1074   typedef typename A::reference reference;
1075   typedef typename A::const_reference const_reference;
1076   typedef typename A::pointer pointer;
1077   typedef typename A::const_pointer const_pointer;
1078
1079   typedef E* iterator;
1080   typedef const E* const_iterator;
1081   typedef std::reverse_iterator<iterator
1082 #ifdef NO_ITERATOR_TRAITS
1083                                 , value_type
1084 #endif
1085                                 > reverse_iterator;
1086   typedef std::reverse_iterator<const_iterator
1087 #ifdef NO_ITERATOR_TRAITS
1088                                 , const value_type
1089 #endif
1090                                 > const_reverse_iterator;
1091
1092   static constexpr size_type npos = size_type(-1);
1093   typedef std::true_type IsRelocatable;
1094
1095 private:
1096   static void procrustes(size_type& n, size_type nmax) {
1097     if (n > nmax) {
1098       n = nmax;
1099     }
1100   }
1101
1102   static size_type traitsLength(const value_type* s);
1103
1104 public:
1105   // C++11 21.4.2 construct/copy/destroy
1106
1107   // Note: while the following two constructors can be (and previously were)
1108   // collapsed into one constructor written this way:
1109   //
1110   //   explicit basic_fbstring(const A& a = A()) noexcept { }
1111   //
1112   // This can cause Clang (at least version 3.7) to fail with the error:
1113   //   "chosen constructor is explicit in copy-initialization ...
1114   //   in implicit initialization of field '(x)' with omitted initializer"
1115   //
1116   // if used in a struct which is default-initialized.  Hence the split into
1117   // these two separate constructors.
1118
1119   basic_fbstring() noexcept : basic_fbstring(A()) {
1120   }
1121
1122   explicit basic_fbstring(const A&) noexcept {
1123   }
1124
1125   basic_fbstring(const basic_fbstring& str)
1126       : store_(str.store_) {
1127   }
1128
1129   // Move constructor
1130   basic_fbstring(basic_fbstring&& goner) noexcept
1131       : store_(std::move(goner.store_)) {
1132   }
1133
1134 #ifndef _LIBSTDCXX_FBSTRING
1135   // This is defined for compatibility with std::string
1136   /* implicit */ basic_fbstring(const std::string& str)
1137       : store_(str.data(), str.size()) {
1138   }
1139 #endif
1140
1141   basic_fbstring(const basic_fbstring& str,
1142                  size_type pos,
1143                  size_type n = npos,
1144                  const A& /* a */ = A()) {
1145     assign(str, pos, n);
1146   }
1147
1148   /* implicit */ basic_fbstring(const value_type* s, const A& /*a*/ = A())
1149       : store_(s, basic_fbstring::traitsLength(s)) {
1150   }
1151
1152   basic_fbstring(const value_type* s, size_type n, const A& /*a*/ = A())
1153       : store_(s, n) {
1154   }
1155
1156   basic_fbstring(size_type n, value_type c, const A& /*a*/ = A()) {
1157     auto const pData = store_.expandNoinit(n);
1158     fbstring_detail::podFill(pData, pData + n, c);
1159   }
1160
1161   template <class InIt>
1162   basic_fbstring(
1163       InIt begin,
1164       InIt end,
1165       typename std::enable_if<
1166           !std::is_same<InIt, value_type*>::value,
1167           const A>::type& /*a*/ = A()) {
1168     assign(begin, end);
1169   }
1170
1171   // Specialization for const char*, const char*
1172   basic_fbstring(const value_type* b, const value_type* e, const A& /*a*/ = A())
1173       : store_(b, e - b) {
1174   }
1175
1176   // Nonstandard constructor
1177   basic_fbstring(value_type *s, size_type n, size_type c,
1178                  AcquireMallocatedString a)
1179       : store_(s, n, c, a) {
1180   }
1181
1182   // Construction from initialization list
1183   basic_fbstring(std::initializer_list<value_type> il) {
1184     assign(il.begin(), il.end());
1185   }
1186
1187   ~basic_fbstring() noexcept {
1188   }
1189
1190   basic_fbstring& operator=(const basic_fbstring& lhs);
1191
1192   // Move assignment
1193   basic_fbstring& operator=(basic_fbstring&& goner) noexcept;
1194
1195 #ifndef _LIBSTDCXX_FBSTRING
1196   // Compatibility with std::string
1197   basic_fbstring & operator=(const std::string & rhs) {
1198     return assign(rhs.data(), rhs.size());
1199   }
1200
1201   // Compatibility with std::string
1202   std::string toStdString() const {
1203     return std::string(data(), size());
1204   }
1205 #else
1206   // A lot of code in fbcode still uses this method, so keep it here for now.
1207   const basic_fbstring& toStdString() const {
1208     return *this;
1209   }
1210 #endif
1211
1212   basic_fbstring& operator=(const value_type* s) {
1213     return assign(s);
1214   }
1215
1216   basic_fbstring& operator=(value_type c);
1217
1218   basic_fbstring& operator=(std::initializer_list<value_type> il) {
1219     return assign(il.begin(), il.end());
1220   }
1221
1222   // C++11 21.4.3 iterators:
1223   iterator begin() {
1224     return store_.mutableData();
1225   }
1226
1227   const_iterator begin() const {
1228     return store_.data();
1229   }
1230
1231   const_iterator cbegin() const {
1232     return begin();
1233   }
1234
1235   iterator end() {
1236     return store_.mutableData() + store_.size();
1237   }
1238
1239   const_iterator end() const {
1240     return store_.data() + store_.size();
1241   }
1242
1243   const_iterator cend() const { return end(); }
1244
1245   reverse_iterator rbegin() {
1246     return reverse_iterator(end());
1247   }
1248
1249   const_reverse_iterator rbegin() const {
1250     return const_reverse_iterator(end());
1251   }
1252
1253   const_reverse_iterator crbegin() const { return rbegin(); }
1254
1255   reverse_iterator rend() {
1256     return reverse_iterator(begin());
1257   }
1258
1259   const_reverse_iterator rend() const {
1260     return const_reverse_iterator(begin());
1261   }
1262
1263   const_reverse_iterator crend() const { return rend(); }
1264
1265   // Added by C++11
1266   // C++11 21.4.5, element access:
1267   const value_type& front() const { return *begin(); }
1268   const value_type& back() const {
1269     FBSTRING_ASSERT(!empty());
1270     // Should be begin()[size() - 1], but that branches twice
1271     return *(end() - 1);
1272   }
1273   value_type& front() { return *begin(); }
1274   value_type& back() {
1275     FBSTRING_ASSERT(!empty());
1276     // Should be begin()[size() - 1], but that branches twice
1277     return *(end() - 1);
1278   }
1279   void pop_back() {
1280     FBSTRING_ASSERT(!empty());
1281     store_.shrink(1);
1282   }
1283
1284   // C++11 21.4.4 capacity:
1285   size_type size() const { return store_.size(); }
1286
1287   size_type length() const { return size(); }
1288
1289   size_type max_size() const {
1290     return std::numeric_limits<size_type>::max();
1291   }
1292
1293   void resize(size_type n, value_type c = value_type());
1294
1295   size_type capacity() const { return store_.capacity(); }
1296
1297   void reserve(size_type res_arg = 0) {
1298     enforce(res_arg <= max_size(), std::__throw_length_error, "");
1299     store_.reserve(res_arg);
1300   }
1301
1302   void shrink_to_fit() {
1303     // Shrink only if slack memory is sufficiently large
1304     if (capacity() < size() * 3 / 2) {
1305       return;
1306     }
1307     basic_fbstring(cbegin(), cend()).swap(*this);
1308   }
1309
1310   void clear() { resize(0); }
1311
1312   bool empty() const { return size() == 0; }
1313
1314   // C++11 21.4.5 element access:
1315   const_reference operator[](size_type pos) const {
1316     return *(begin() + pos);
1317   }
1318
1319   reference operator[](size_type pos) {
1320     return *(begin() + pos);
1321   }
1322
1323   const_reference at(size_type n) const {
1324     enforce(n <= size(), std::__throw_out_of_range, "");
1325     return (*this)[n];
1326   }
1327
1328   reference at(size_type n) {
1329     enforce(n < size(), std::__throw_out_of_range, "");
1330     return (*this)[n];
1331   }
1332
1333   // C++11 21.4.6 modifiers:
1334   basic_fbstring& operator+=(const basic_fbstring& str) {
1335     return append(str);
1336   }
1337
1338   basic_fbstring& operator+=(const value_type* s) {
1339     return append(s);
1340   }
1341
1342   basic_fbstring& operator+=(const value_type c) {
1343     push_back(c);
1344     return *this;
1345   }
1346
1347   basic_fbstring& operator+=(std::initializer_list<value_type> il) {
1348     append(il);
1349     return *this;
1350   }
1351
1352   basic_fbstring& append(const basic_fbstring& str);
1353
1354   basic_fbstring&
1355   append(const basic_fbstring& str, const size_type pos, size_type n);
1356
1357   basic_fbstring& append(const value_type* s, size_type n);
1358
1359   basic_fbstring& append(const value_type* s) {
1360     return append(s, traits_type::length(s));
1361   }
1362
1363   basic_fbstring& append(size_type n, value_type c);
1364
1365   template<class InputIterator>
1366   basic_fbstring& append(InputIterator first, InputIterator last) {
1367     insert(end(), first, last);
1368     return *this;
1369   }
1370
1371   basic_fbstring& append(std::initializer_list<value_type> il) {
1372     return append(il.begin(), il.end());
1373   }
1374
1375   void push_back(const value_type c) {             // primitive
1376     store_.push_back(c);
1377   }
1378
1379   basic_fbstring& assign(const basic_fbstring& str) {
1380     if (&str == this) return *this;
1381     return assign(str.data(), str.size());
1382   }
1383
1384   basic_fbstring& assign(basic_fbstring&& str) {
1385     return *this = std::move(str);
1386   }
1387
1388   basic_fbstring&
1389   assign(const basic_fbstring& str, const size_type pos, size_type n);
1390
1391   basic_fbstring& assign(const value_type* s, const size_type n);
1392
1393   basic_fbstring& assign(const value_type* s) {
1394     return assign(s, traits_type::length(s));
1395   }
1396
1397   basic_fbstring& assign(std::initializer_list<value_type> il) {
1398     return assign(il.begin(), il.end());
1399   }
1400
1401   template <class ItOrLength, class ItOrChar>
1402   basic_fbstring& assign(ItOrLength first_or_n, ItOrChar last_or_c) {
1403     return replace(begin(), end(), first_or_n, last_or_c);
1404   }
1405
1406   basic_fbstring& insert(size_type pos1, const basic_fbstring& str) {
1407     return insert(pos1, str.data(), str.size());
1408   }
1409
1410   basic_fbstring& insert(size_type pos1, const basic_fbstring& str,
1411                          size_type pos2, size_type n) {
1412     enforce(pos2 <= str.length(), std::__throw_out_of_range, "");
1413     procrustes(n, str.length() - pos2);
1414     return insert(pos1, str.data() + pos2, n);
1415   }
1416
1417   basic_fbstring& insert(size_type pos, const value_type* s, size_type n) {
1418     enforce(pos <= length(), std::__throw_out_of_range, "");
1419     insert(begin() + pos, s, s + n);
1420     return *this;
1421   }
1422
1423   basic_fbstring& insert(size_type pos, const value_type* s) {
1424     return insert(pos, s, traits_type::length(s));
1425   }
1426
1427   basic_fbstring& insert(size_type pos, size_type n, value_type c) {
1428     enforce(pos <= length(), std::__throw_out_of_range, "");
1429     insert(begin() + pos, n, c);
1430     return *this;
1431   }
1432
1433   iterator insert(const_iterator p, const value_type c) {
1434     const size_type pos = p - cbegin();
1435     insert(p, 1, c);
1436     return begin() + pos;
1437   }
1438
1439 #ifndef _LIBSTDCXX_FBSTRING
1440  private:
1441   typedef std::basic_istream<value_type, traits_type> istream_type;
1442   istream_type& getlineImpl(istream_type& is, value_type delim);
1443
1444  public:
1445   friend inline istream_type& getline(istream_type& is,
1446                                       basic_fbstring& str,
1447                                       value_type delim) {
1448     return str.getlineImpl(is, delim);
1449   }
1450
1451   friend inline istream_type& getline(istream_type& is, basic_fbstring& str) {
1452     return getline(is, str, '\n');
1453   }
1454 #endif
1455
1456 private:
1457  iterator
1458  insertImplDiscr(const_iterator i, size_type n, value_type c, std::true_type);
1459
1460  template <class InputIter>
1461  iterator
1462  insertImplDiscr(const_iterator i, InputIter b, InputIter e, std::false_type);
1463
1464  template <class FwdIterator>
1465  iterator insertImpl(
1466      const_iterator i,
1467      FwdIterator s1,
1468      FwdIterator s2,
1469      std::forward_iterator_tag);
1470
1471  template <class InputIterator>
1472  iterator insertImpl(
1473      const_iterator i,
1474      InputIterator b,
1475      InputIterator e,
1476      std::input_iterator_tag);
1477
1478 public:
1479   template <class ItOrLength, class ItOrChar>
1480   iterator insert(const_iterator p, ItOrLength first_or_n, ItOrChar last_or_c) {
1481     using Sel = std::integral_constant<
1482         bool,
1483         std::numeric_limits<ItOrLength>::is_specialized>;
1484     return insertImplDiscr(p, first_or_n, last_or_c, Sel());
1485   }
1486
1487   iterator insert(const_iterator p, std::initializer_list<value_type> il) {
1488     return insert(p, il.begin(), il.end());
1489   }
1490
1491   basic_fbstring& erase(size_type pos = 0, size_type n = npos) {
1492     Invariant checker(*this);
1493
1494     enforce(pos <= length(), std::__throw_out_of_range, "");
1495     procrustes(n, length() - pos);
1496     std::copy(begin() + pos + n, end(), begin() + pos);
1497     resize(length() - n);
1498     return *this;
1499   }
1500
1501   iterator erase(iterator position) {
1502     const size_type pos(position - begin());
1503     enforce(pos <= size(), std::__throw_out_of_range, "");
1504     erase(pos, 1);
1505     return begin() + pos;
1506   }
1507
1508   iterator erase(iterator first, iterator last) {
1509     const size_type pos(first - begin());
1510     erase(pos, last - first);
1511     return begin() + pos;
1512   }
1513
1514   // Replaces at most n1 chars of *this, starting with pos1 with the
1515   // content of str
1516   basic_fbstring& replace(size_type pos1, size_type n1,
1517                           const basic_fbstring& str) {
1518     return replace(pos1, n1, str.data(), str.size());
1519   }
1520
1521   // Replaces at most n1 chars of *this, starting with pos1,
1522   // with at most n2 chars of str starting with pos2
1523   basic_fbstring& replace(size_type pos1, size_type n1,
1524                           const basic_fbstring& str,
1525                           size_type pos2, size_type n2) {
1526     enforce(pos2 <= str.length(), std::__throw_out_of_range, "");
1527     return replace(pos1, n1, str.data() + pos2,
1528                    std::min(n2, str.size() - pos2));
1529   }
1530
1531   // Replaces at most n1 chars of *this, starting with pos, with chars from s
1532   basic_fbstring& replace(size_type pos, size_type n1, const value_type* s) {
1533     return replace(pos, n1, s, traits_type::length(s));
1534   }
1535
1536   // Replaces at most n1 chars of *this, starting with pos, with n2
1537   // occurrences of c
1538   //
1539   // consolidated with
1540   //
1541   // Replaces at most n1 chars of *this, starting with pos, with at
1542   // most n2 chars of str.  str must have at least n2 chars.
1543   template <class StrOrLength, class NumOrChar>
1544   basic_fbstring& replace(size_type pos, size_type n1,
1545                           StrOrLength s_or_n2, NumOrChar n_or_c) {
1546     Invariant checker(*this);
1547
1548     enforce(pos <= size(), std::__throw_out_of_range, "");
1549     procrustes(n1, length() - pos);
1550     const iterator b = begin() + pos;
1551     return replace(b, b + n1, s_or_n2, n_or_c);
1552   }
1553
1554   basic_fbstring& replace(iterator i1, iterator i2, const basic_fbstring& str) {
1555     return replace(i1, i2, str.data(), str.length());
1556   }
1557
1558   basic_fbstring& replace(iterator i1, iterator i2, const value_type* s) {
1559     return replace(i1, i2, s, traits_type::length(s));
1560   }
1561
1562 private:
1563  basic_fbstring& replaceImplDiscr(
1564      iterator i1,
1565      iterator i2,
1566      const value_type* s,
1567      size_type n,
1568      std::integral_constant<int, 2>);
1569
1570  basic_fbstring& replaceImplDiscr(
1571      iterator i1,
1572      iterator i2,
1573      size_type n2,
1574      value_type c,
1575      std::integral_constant<int, 1>);
1576
1577  template <class InputIter>
1578  basic_fbstring& replaceImplDiscr(
1579      iterator i1,
1580      iterator i2,
1581      InputIter b,
1582      InputIter e,
1583      std::integral_constant<int, 0>);
1584
1585 private:
1586  template <class FwdIterator>
1587  bool replaceAliased(iterator /* i1 */,
1588                      iterator /* i2 */,
1589                      FwdIterator /* s1 */,
1590                      FwdIterator /* s2 */,
1591                      std::false_type) {
1592     return false;
1593   }
1594
1595   template <class FwdIterator>
1596   bool replaceAliased(
1597       iterator i1,
1598       iterator i2,
1599       FwdIterator s1,
1600       FwdIterator s2,
1601       std::true_type);
1602
1603   template <class FwdIterator>
1604   void replaceImpl(
1605       iterator i1,
1606       iterator i2,
1607       FwdIterator s1,
1608       FwdIterator s2,
1609       std::forward_iterator_tag);
1610
1611   template <class InputIterator>
1612   void replaceImpl(
1613       iterator i1,
1614       iterator i2,
1615       InputIterator b,
1616       InputIterator e,
1617       std::input_iterator_tag);
1618
1619  public:
1620   template <class T1, class T2>
1621   basic_fbstring& replace(iterator i1, iterator i2,
1622                           T1 first_or_n_or_s, T2 last_or_c_or_n) {
1623     constexpr bool num1 = std::numeric_limits<T1>::is_specialized,
1624                    num2 = std::numeric_limits<T2>::is_specialized;
1625     using Sel =
1626         std::integral_constant<int, num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>;
1627     return replaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n, Sel());
1628   }
1629
1630   size_type copy(value_type* s, size_type n, size_type pos = 0) const {
1631     enforce(pos <= size(), std::__throw_out_of_range, "");
1632     procrustes(n, size() - pos);
1633
1634     if (n != 0) {
1635       fbstring_detail::podCopy(data() + pos, data() + pos + n, s);
1636     }
1637     return n;
1638   }
1639
1640   void swap(basic_fbstring& rhs) {
1641     store_.swap(rhs.store_);
1642   }
1643
1644   const value_type* c_str() const {
1645     return store_.c_str();
1646   }
1647
1648   const value_type* data() const { return c_str(); }
1649
1650   allocator_type get_allocator() const {
1651     return allocator_type();
1652   }
1653
1654   size_type find(const basic_fbstring& str, size_type pos = 0) const {
1655     return find(str.data(), pos, str.length());
1656   }
1657
1658   size_type find(const value_type* needle, size_type pos, size_type nsize)
1659       const;
1660
1661   size_type find(const value_type* s, size_type pos = 0) const {
1662     return find(s, pos, traits_type::length(s));
1663   }
1664
1665   size_type find (value_type c, size_type pos = 0) const {
1666     return find(&c, pos, 1);
1667   }
1668
1669   size_type rfind(const basic_fbstring& str, size_type pos = npos) const {
1670     return rfind(str.data(), pos, str.length());
1671   }
1672
1673   size_type rfind(const value_type* s, size_type pos, size_type n) const;
1674
1675   size_type rfind(const value_type* s, size_type pos = npos) const {
1676     return rfind(s, pos, traits_type::length(s));
1677   }
1678
1679   size_type rfind(value_type c, size_type pos = npos) const {
1680     return rfind(&c, pos, 1);
1681   }
1682
1683   size_type find_first_of(const basic_fbstring& str, size_type pos = 0) const {
1684     return find_first_of(str.data(), pos, str.length());
1685   }
1686
1687   size_type find_first_of(const value_type* s, size_type pos, size_type n)
1688       const;
1689
1690   size_type find_first_of(const value_type* s, size_type pos = 0) const {
1691     return find_first_of(s, pos, traits_type::length(s));
1692   }
1693
1694   size_type find_first_of(value_type c, size_type pos = 0) const {
1695     return find_first_of(&c, pos, 1);
1696   }
1697
1698   size_type find_last_of(const basic_fbstring& str, size_type pos = npos)
1699       const {
1700     return find_last_of(str.data(), pos, str.length());
1701   }
1702
1703   size_type find_last_of(const value_type* s, size_type pos, size_type n) const;
1704
1705   size_type find_last_of (const value_type* s,
1706                           size_type pos = npos) const {
1707     return find_last_of(s, pos, traits_type::length(s));
1708   }
1709
1710   size_type find_last_of (value_type c, size_type pos = npos) const {
1711     return find_last_of(&c, pos, 1);
1712   }
1713
1714   size_type find_first_not_of(const basic_fbstring& str,
1715                               size_type pos = 0) const {
1716     return find_first_not_of(str.data(), pos, str.size());
1717   }
1718
1719   size_type find_first_not_of(const value_type* s, size_type pos, size_type n)
1720       const;
1721
1722   size_type find_first_not_of(const value_type* s,
1723                               size_type pos = 0) const {
1724     return find_first_not_of(s, pos, traits_type::length(s));
1725   }
1726
1727   size_type find_first_not_of(value_type c, size_type pos = 0) const {
1728     return find_first_not_of(&c, pos, 1);
1729   }
1730
1731   size_type find_last_not_of(const basic_fbstring& str,
1732                              size_type pos = npos) const {
1733     return find_last_not_of(str.data(), pos, str.length());
1734   }
1735
1736   size_type find_last_not_of(const value_type* s, size_type pos, size_type n)
1737       const;
1738
1739   size_type find_last_not_of(const value_type* s,
1740                              size_type pos = npos) const {
1741     return find_last_not_of(s, pos, traits_type::length(s));
1742   }
1743
1744   size_type find_last_not_of (value_type c, size_type pos = npos) const {
1745     return find_last_not_of(&c, pos, 1);
1746   }
1747
1748   basic_fbstring substr(size_type pos = 0, size_type n = npos) const& {
1749     enforce(pos <= size(), std::__throw_out_of_range, "");
1750     return basic_fbstring(data() + pos, std::min(n, size() - pos));
1751   }
1752
1753   basic_fbstring substr(size_type pos = 0, size_type n = npos) && {
1754     enforce(pos <= size(), std::__throw_out_of_range, "");
1755     erase(0, pos);
1756     if (n < size()) {
1757       resize(n);
1758     }
1759     return std::move(*this);
1760   }
1761
1762   int compare(const basic_fbstring& str) const {
1763     // FIX due to Goncalo N M de Carvalho July 18, 2005
1764     return compare(0, size(), str);
1765   }
1766
1767   int compare(size_type pos1, size_type n1,
1768               const basic_fbstring& str) const {
1769     return compare(pos1, n1, str.data(), str.size());
1770   }
1771
1772   int compare(size_type pos1, size_type n1,
1773               const value_type* s) const {
1774     return compare(pos1, n1, s, traits_type::length(s));
1775   }
1776
1777   int compare(size_type pos1, size_type n1,
1778               const value_type* s, size_type n2) const {
1779     enforce(pos1 <= size(), std::__throw_out_of_range, "");
1780     procrustes(n1, size() - pos1);
1781     // The line below fixed by Jean-Francois Bastien, 04-23-2007. Thanks!
1782     const int r = traits_type::compare(pos1 + data(), s, std::min(n1, n2));
1783     return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
1784   }
1785
1786   int compare(size_type pos1, size_type n1,
1787               const basic_fbstring& str,
1788               size_type pos2, size_type n2) const {
1789     enforce(pos2 <= str.size(), std::__throw_out_of_range, "");
1790     return compare(pos1, n1, str.data() + pos2,
1791                    std::min(n2, str.size() - pos2));
1792   }
1793
1794   // Code from Jean-Francois Bastien (03/26/2007)
1795   int compare(const value_type* s) const {
1796     // Could forward to compare(0, size(), s, traits_type::length(s))
1797     // but that does two extra checks
1798     const size_type n1(size()), n2(traits_type::length(s));
1799     const int r = traits_type::compare(data(), s, std::min(n1, n2));
1800     return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
1801   }
1802
1803 private:
1804   // Data
1805   Storage store_;
1806 };
1807
1808 template <typename E, class T, class A, class S>
1809 inline typename basic_fbstring<E, T, A, S>::size_type
1810 basic_fbstring<E, T, A, S>::traitsLength(const value_type* s) {
1811   return s ? traits_type::length(s)
1812            : (std::__throw_logic_error(
1813                   "basic_fbstring: null pointer initializer not valid"),
1814               0);
1815 }
1816
1817 template <typename E, class T, class A, class S>
1818 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=(
1819     const basic_fbstring& lhs) {
1820   Invariant checker(*this);
1821
1822   if (FBSTRING_UNLIKELY(&lhs == this)) {
1823     return *this;
1824   }
1825
1826   return assign(lhs.data(), lhs.size());
1827 }
1828
1829 // Move assignment
1830 template <typename E, class T, class A, class S>
1831 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=(
1832     basic_fbstring&& goner) noexcept {
1833   if (FBSTRING_UNLIKELY(&goner == this)) {
1834     // Compatibility with std::basic_string<>,
1835     // C++11 21.4.2 [string.cons] / 23 requires self-move-assignment support.
1836     return *this;
1837   }
1838   // No need of this anymore
1839   this->~basic_fbstring();
1840   // Move the goner into this
1841   new (&store_) S(std::move(goner.store_));
1842   return *this;
1843 }
1844
1845 template <typename E, class T, class A, class S>
1846 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=(
1847     const value_type c) {
1848   Invariant checker(*this);
1849
1850   if (empty()) {
1851     store_.expandNoinit(1);
1852   } else if (store_.isShared()) {
1853     basic_fbstring(1, c).swap(*this);
1854     return *this;
1855   } else {
1856     store_.shrink(size() - 1);
1857   }
1858   front() = c;
1859   return *this;
1860 }
1861
1862 template <typename E, class T, class A, class S>
1863 inline void basic_fbstring<E, T, A, S>::resize(
1864     const size_type n, const value_type c /*= value_type()*/) {
1865   Invariant checker(*this);
1866
1867   auto size = this->size();
1868   if (n <= size) {
1869     store_.shrink(size - n);
1870   } else {
1871     auto const delta = n - size;
1872     auto pData = store_.expandNoinit(delta);
1873     fbstring_detail::podFill(pData, pData + delta, c);
1874   }
1875   FBSTRING_ASSERT(this->size() == n);
1876 }
1877
1878 template <typename E, class T, class A, class S>
1879 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append(
1880     const basic_fbstring& str) {
1881 #ifndef NDEBUG
1882   auto desiredSize = size() + str.size();
1883 #endif
1884   append(str.data(), str.size());
1885   FBSTRING_ASSERT(size() == desiredSize);
1886   return *this;
1887 }
1888
1889 template <typename E, class T, class A, class S>
1890 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append(
1891     const basic_fbstring& str, const size_type pos, size_type n) {
1892   const size_type sz = str.size();
1893   enforce(pos <= sz, std::__throw_out_of_range, "");
1894   procrustes(n, sz - pos);
1895   return append(str.data() + pos, n);
1896 }
1897
1898 template <typename E, class T, class A, class S>
1899 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append(
1900     const value_type* s, size_type n) {
1901   Invariant checker(*this);
1902
1903   if (FBSTRING_UNLIKELY(!n)) {
1904     // Unlikely but must be done
1905     return *this;
1906   }
1907   auto const oldSize = size();
1908   auto const oldData = data();
1909   auto pData = store_.expandNoinit(n, /* expGrowth = */ true);
1910
1911   // Check for aliasing (rare). We could use "<=" here but in theory
1912   // those do not work for pointers unless the pointers point to
1913   // elements in the same array. For that reason we use
1914   // std::less_equal, which is guaranteed to offer a total order
1915   // over pointers. See discussion at http://goo.gl/Cy2ya for more
1916   // info.
1917   std::less_equal<const value_type*> le;
1918   if (FBSTRING_UNLIKELY(le(oldData, s) && !le(oldData + oldSize, s))) {
1919     FBSTRING_ASSERT(le(s + n, oldData + oldSize));
1920     // expandNoinit() could have moved the storage, restore the source.
1921     s = data() + (s - oldData);
1922     fbstring_detail::podMove(s, s + n, pData);
1923   } else {
1924     fbstring_detail::podCopy(s, s + n, pData);
1925   }
1926
1927   FBSTRING_ASSERT(size() == oldSize + n);
1928   return *this;
1929 }
1930
1931 template <typename E, class T, class A, class S>
1932 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append(
1933     size_type n, value_type c) {
1934   Invariant checker(*this);
1935   auto pData = store_.expandNoinit(n, /* expGrowth = */ true);
1936   fbstring_detail::podFill(pData, pData + n, c);
1937   return *this;
1938 }
1939
1940 template <typename E, class T, class A, class S>
1941 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::assign(
1942     const basic_fbstring& str, const size_type pos, size_type n) {
1943   const size_type sz = str.size();
1944   enforce(pos <= sz, std::__throw_out_of_range, "");
1945   procrustes(n, sz - pos);
1946   return assign(str.data() + pos, n);
1947 }
1948
1949 template <typename E, class T, class A, class S>
1950 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::assign(
1951     const value_type* s, const size_type n) {
1952   Invariant checker(*this);
1953
1954   // s can alias this, we need to use podMove.
1955   if (n == 0) {
1956     resize(0);
1957   } else if (size() >= n) {
1958     // s can alias this, we need to use podMove.
1959     fbstring_detail::podMove(s, s + n, store_.mutableData());
1960     store_.shrink(size() - n);
1961     FBSTRING_ASSERT(size() == n);
1962   } else {
1963     // If n is larger than size(), s cannot alias this string's
1964     // storage.
1965     resize(0);
1966     // Do not use exponential growth here: assign() should be tight,
1967     // to mirror the behavior of the equivalent constructor.
1968     fbstring_detail::podCopy(s, s + n, store_.expandNoinit(n));
1969   }
1970
1971   FBSTRING_ASSERT(size() == n);
1972   return *this;
1973 }
1974
1975 #ifndef _LIBSTDCXX_FBSTRING
1976 template <typename E, class T, class A, class S>
1977 inline typename basic_fbstring<E, T, A, S>::istream_type&
1978 basic_fbstring<E, T, A, S>::getlineImpl(istream_type & is, value_type delim) {
1979   Invariant checker(*this);
1980
1981   clear();
1982   size_t size = 0;
1983   while (true) {
1984     size_t avail = capacity() - size;
1985     // fbstring has 1 byte extra capacity for the null terminator,
1986     // and getline null-terminates the read string.
1987     is.getline(store_.expandNoinit(avail), avail + 1, delim);
1988     size += is.gcount();
1989
1990     if (is.bad() || is.eof() || !is.fail()) {
1991       // Done by either failure, end of file, or normal read.
1992       if (!is.bad() && !is.eof()) {
1993         --size; // gcount() also accounts for the delimiter.
1994       }
1995       resize(size);
1996       break;
1997     }
1998
1999     FBSTRING_ASSERT(size == this->size());
2000     FBSTRING_ASSERT(size == capacity());
2001     // Start at minimum allocation 63 + terminator = 64.
2002     reserve(std::max<size_t>(63, 3 * size / 2));
2003     // Clear the error so we can continue reading.
2004     is.clear();
2005   }
2006   return is;
2007 }
2008 #endif
2009
2010 template <typename E, class T, class A, class S>
2011 inline typename basic_fbstring<E, T, A, S>::size_type
2012 basic_fbstring<E, T, A, S>::find(
2013     const value_type* needle, const size_type pos, const size_type nsize)
2014     const {
2015   auto const size = this->size();
2016   // nsize + pos can overflow (eg pos == npos), guard against that by checking
2017   // that nsize + pos does not wrap around.
2018   if (nsize + pos > size || nsize + pos < pos) {
2019     return npos;
2020   }
2021
2022   if (nsize == 0) {
2023     return pos;
2024   }
2025   // Don't use std::search, use a Boyer-Moore-like trick by comparing
2026   // the last characters first
2027   auto const haystack = data();
2028   auto const nsize_1 = nsize - 1;
2029   auto const lastNeedle = needle[nsize_1];
2030
2031   // Boyer-Moore skip value for the last char in the needle. Zero is
2032   // not a valid value; skip will be computed the first time it's
2033   // needed.
2034   size_type skip = 0;
2035
2036   const E* i = haystack + pos;
2037   auto iEnd = haystack + size - nsize_1;
2038
2039   while (i < iEnd) {
2040     // Boyer-Moore: match the last element in the needle
2041     while (i[nsize_1] != lastNeedle) {
2042       if (++i == iEnd) {
2043         // not found
2044         return npos;
2045       }
2046     }
2047     // Here we know that the last char matches
2048     // Continue in pedestrian mode
2049     for (size_t j = 0;;) {
2050       FBSTRING_ASSERT(j < nsize);
2051       if (i[j] != needle[j]) {
2052         // Not found, we can skip
2053         // Compute the skip value lazily
2054         if (skip == 0) {
2055           skip = 1;
2056           while (skip <= nsize_1 && needle[nsize_1 - skip] != lastNeedle) {
2057             ++skip;
2058           }
2059         }
2060         i += skip;
2061         break;
2062       }
2063       // Check if done searching
2064       if (++j == nsize) {
2065         // Yay
2066         return i - haystack;
2067       }
2068     }
2069   }
2070   return npos;
2071 }
2072
2073 template <typename E, class T, class A, class S>
2074 inline typename basic_fbstring<E, T, A, S>::iterator
2075 basic_fbstring<E, T, A, S>::insertImplDiscr(
2076     const_iterator i, size_type n, value_type c, std::true_type) {
2077   Invariant checker(*this);
2078
2079   FBSTRING_ASSERT(i >= cbegin() && i <= cend());
2080   const size_type pos = i - cbegin();
2081
2082   auto oldSize = size();
2083   store_.expandNoinit(n, /* expGrowth = */ true);
2084   auto b = begin();
2085   fbstring_detail::podMove(b + pos, b + oldSize, b + pos + n);
2086   fbstring_detail::podFill(b + pos, b + pos + n, c);
2087
2088   return b + pos;
2089 }
2090
2091 template <typename E, class T, class A, class S>
2092 template <class InputIter>
2093 inline typename basic_fbstring<E, T, A, S>::iterator
2094 basic_fbstring<E, T, A, S>::insertImplDiscr(
2095     const_iterator i, InputIter b, InputIter e, std::false_type) {
2096   return insertImpl(
2097       i, b, e, typename std::iterator_traits<InputIter>::iterator_category());
2098 }
2099
2100 template <typename E, class T, class A, class S>
2101 template <class FwdIterator>
2102 inline typename basic_fbstring<E, T, A, S>::iterator
2103 basic_fbstring<E, T, A, S>::insertImpl(
2104     const_iterator i,
2105     FwdIterator s1,
2106     FwdIterator s2,
2107     std::forward_iterator_tag) {
2108   Invariant checker(*this);
2109
2110   FBSTRING_ASSERT(i >= cbegin() && i <= cend());
2111   const size_type pos = i - cbegin();
2112   auto n = std::distance(s1, s2);
2113   FBSTRING_ASSERT(n >= 0);
2114
2115   auto oldSize = size();
2116   store_.expandNoinit(n, /* expGrowth = */ true);
2117   auto b = begin();
2118   fbstring_detail::podMove(b + pos, b + oldSize, b + pos + n);
2119   std::copy(s1, s2, b + pos);
2120
2121   return b + pos;
2122 }
2123
2124 template <typename E, class T, class A, class S>
2125 template <class InputIterator>
2126 inline typename basic_fbstring<E, T, A, S>::iterator
2127 basic_fbstring<E, T, A, S>::insertImpl(
2128     const_iterator i,
2129     InputIterator b,
2130     InputIterator e,
2131     std::input_iterator_tag) {
2132   const auto pos = i - cbegin();
2133   basic_fbstring temp(cbegin(), i);
2134   for (; b != e; ++b) {
2135     temp.push_back(*b);
2136   }
2137   temp.append(i, cend());
2138   swap(temp);
2139   return begin() + pos;
2140 }
2141
2142 template <typename E, class T, class A, class S>
2143 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::replaceImplDiscr(
2144     iterator i1,
2145     iterator i2,
2146     const value_type* s,
2147     size_type n,
2148     std::integral_constant<int, 2>) {
2149   FBSTRING_ASSERT(i1 <= i2);
2150   FBSTRING_ASSERT(begin() <= i1 && i1 <= end());
2151   FBSTRING_ASSERT(begin() <= i2 && i2 <= end());
2152   return replace(i1, i2, s, s + n);
2153 }
2154
2155 template <typename E, class T, class A, class S>
2156 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::replaceImplDiscr(
2157     iterator i1,
2158     iterator i2,
2159     size_type n2,
2160     value_type c,
2161     std::integral_constant<int, 1>) {
2162   const size_type n1 = i2 - i1;
2163   if (n1 > n2) {
2164     std::fill(i1, i1 + n2, c);
2165     erase(i1 + n2, i2);
2166   } else {
2167     std::fill(i1, i2, c);
2168     insert(i2, n2 - n1, c);
2169   }
2170   FBSTRING_ASSERT(isSane());
2171   return *this;
2172 }
2173
2174 template <typename E, class T, class A, class S>
2175 template <class InputIter>
2176 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::replaceImplDiscr(
2177     iterator i1,
2178     iterator i2,
2179     InputIter b,
2180     InputIter e,
2181     std::integral_constant<int, 0>) {
2182   using Cat = typename std::iterator_traits<InputIter>::iterator_category;
2183   replaceImpl(i1, i2, b, e, Cat());
2184   return *this;
2185 }
2186
2187 template <typename E, class T, class A, class S>
2188 template <class FwdIterator>
2189 inline bool basic_fbstring<E, T, A, S>::replaceAliased(
2190     iterator i1, iterator i2, FwdIterator s1, FwdIterator s2, std::true_type) {
2191   std::less_equal<const value_type*> le{};
2192   const bool aliased = le(&*begin(), &*s1) && le(&*s1, &*end());
2193   if (!aliased) {
2194     return false;
2195   }
2196   // Aliased replace, copy to new string
2197   basic_fbstring temp;
2198   temp.reserve(size() - (i2 - i1) + std::distance(s1, s2));
2199   temp.append(begin(), i1).append(s1, s2).append(i2, end());
2200   swap(temp);
2201   return true;
2202 }
2203
2204 template <typename E, class T, class A, class S>
2205 template <class FwdIterator>
2206 inline void basic_fbstring<E, T, A, S>::replaceImpl(
2207     iterator i1,
2208     iterator i2,
2209     FwdIterator s1,
2210     FwdIterator s2,
2211     std::forward_iterator_tag) {
2212   Invariant checker(*this);
2213
2214   // Handle aliased replace
2215   using Sel = std::integral_constant<
2216       bool,
2217       std::is_same<FwdIterator, iterator>::value ||
2218           std::is_same<FwdIterator, const_iterator>::value>;
2219   if (replaceAliased(i1, i2, s1, s2, Sel())) {
2220     return;
2221   }
2222
2223   auto const n1 = i2 - i1;
2224   FBSTRING_ASSERT(n1 >= 0);
2225   auto const n2 = std::distance(s1, s2);
2226   FBSTRING_ASSERT(n2 >= 0);
2227
2228   if (n1 > n2) {
2229     // shrinks
2230     std::copy(s1, s2, i1);
2231     erase(i1 + n2, i2);
2232   } else {
2233     // grows
2234     s1 = fbstring_detail::copy_n(s1, n1, i1).first;
2235     insert(i2, s1, s2);
2236   }
2237   FBSTRING_ASSERT(isSane());
2238 }
2239
2240 template <typename E, class T, class A, class S>
2241 template <class InputIterator>
2242 inline void basic_fbstring<E, T, A, S>::replaceImpl(
2243     iterator i1,
2244     iterator i2,
2245     InputIterator b,
2246     InputIterator e,
2247     std::input_iterator_tag) {
2248   basic_fbstring temp(begin(), i1);
2249   temp.append(b, e).append(i2, end());
2250   swap(temp);
2251 }
2252
2253 template <typename E, class T, class A, class S>
2254 inline typename basic_fbstring<E, T, A, S>::size_type
2255 basic_fbstring<E, T, A, S>::rfind(
2256     const value_type* s, size_type pos, size_type n) const {
2257   if (n > length()) {
2258     return npos;
2259   }
2260   pos = std::min(pos, length() - n);
2261   if (n == 0) {
2262     return pos;
2263   }
2264
2265   const_iterator i(begin() + pos);
2266   for (;; --i) {
2267     if (traits_type::eq(*i, *s) && traits_type::compare(&*i, s, n) == 0) {
2268       return i - begin();
2269     }
2270     if (i == begin()) {
2271       break;
2272     }
2273   }
2274   return npos;
2275 }
2276
2277 template <typename E, class T, class A, class S>
2278 inline typename basic_fbstring<E, T, A, S>::size_type
2279 basic_fbstring<E, T, A, S>::find_first_of(
2280     const value_type* s, size_type pos, size_type n) const {
2281   if (pos > length() || n == 0) {
2282     return npos;
2283   }
2284   const_iterator i(begin() + pos), finish(end());
2285   for (; i != finish; ++i) {
2286     if (traits_type::find(s, n, *i) != 0) {
2287       return i - begin();
2288     }
2289   }
2290   return npos;
2291 }
2292
2293 template <typename E, class T, class A, class S>
2294 inline typename basic_fbstring<E, T, A, S>::size_type
2295 basic_fbstring<E, T, A, S>::find_last_of(
2296     const value_type* s, size_type pos, size_type n) const {
2297   if (!empty() && n > 0) {
2298     pos = std::min(pos, length() - 1);
2299     const_iterator i(begin() + pos);
2300     for (;; --i) {
2301       if (traits_type::find(s, n, *i) != 0) {
2302         return i - begin();
2303       }
2304       if (i == begin()) {
2305         break;
2306       }
2307     }
2308   }
2309   return npos;
2310 }
2311
2312 template <typename E, class T, class A, class S>
2313 inline typename basic_fbstring<E, T, A, S>::size_type
2314 basic_fbstring<E, T, A, S>::find_first_not_of(
2315     const value_type* s, size_type pos, size_type n) const {
2316   if (pos < length()) {
2317     const_iterator i(begin() + pos), finish(end());
2318     for (; i != finish; ++i) {
2319       if (traits_type::find(s, n, *i) == 0) {
2320         return i - begin();
2321       }
2322     }
2323   }
2324   return npos;
2325 }
2326
2327 template <typename E, class T, class A, class S>
2328 inline typename basic_fbstring<E, T, A, S>::size_type
2329 basic_fbstring<E, T, A, S>::find_last_not_of(
2330     const value_type* s, size_type pos, size_type n) const {
2331   if (!this->empty()) {
2332     pos = std::min(pos, size() - 1);
2333     const_iterator i(begin() + pos);
2334     for (;; --i) {
2335       if (traits_type::find(s, n, *i) == 0) {
2336         return i - begin();
2337       }
2338       if (i == begin()) {
2339         break;
2340       }
2341     }
2342   }
2343   return npos;
2344 }
2345
2346 // non-member functions
2347 // C++11 21.4.8.1/1
2348 template <typename E, class T, class A, class S>
2349 inline
2350 basic_fbstring<E, T, A, S> operator+(const basic_fbstring<E, T, A, S>& lhs,
2351                                      const basic_fbstring<E, T, A, S>& rhs) {
2352
2353   basic_fbstring<E, T, A, S> result;
2354   result.reserve(lhs.size() + rhs.size());
2355   result.append(lhs).append(rhs);
2356   return std::move(result);
2357 }
2358
2359 // C++11 21.4.8.1/2
2360 template <typename E, class T, class A, class S>
2361 inline
2362 basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs,
2363                                      const basic_fbstring<E, T, A, S>& rhs) {
2364   return std::move(lhs.append(rhs));
2365 }
2366
2367 // C++11 21.4.8.1/3
2368 template <typename E, class T, class A, class S>
2369 inline
2370 basic_fbstring<E, T, A, S> operator+(const basic_fbstring<E, T, A, S>& lhs,
2371                                      basic_fbstring<E, T, A, S>&& rhs) {
2372   if (rhs.capacity() >= lhs.size() + rhs.size()) {
2373     // Good, at least we don't need to reallocate
2374     return std::move(rhs.insert(0, lhs));
2375   }
2376   // Meh, no go. Forward to operator+(const&, const&).
2377   auto const& rhsC = rhs;
2378   return lhs + rhsC;
2379 }
2380
2381 // C++11 21.4.8.1/4
2382 template <typename E, class T, class A, class S>
2383 inline
2384 basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs,
2385                                      basic_fbstring<E, T, A, S>&& rhs) {
2386   return std::move(lhs.append(rhs));
2387 }
2388
2389 // C++11 21.4.8.1/5
2390 template <typename E, class T, class A, class S>
2391 inline
2392 basic_fbstring<E, T, A, S> operator+(
2393   const E* lhs,
2394   const basic_fbstring<E, T, A, S>& rhs) {
2395   //
2396   basic_fbstring<E, T, A, S> result;
2397   const auto len = basic_fbstring<E, T, A, S>::traits_type::length(lhs);
2398   result.reserve(len + rhs.size());
2399   result.append(lhs, len).append(rhs);
2400   return result;
2401 }
2402
2403 // C++11 21.4.8.1/6
2404 template <typename E, class T, class A, class S>
2405 inline
2406 basic_fbstring<E, T, A, S> operator+(
2407   const E* lhs,
2408   basic_fbstring<E, T, A, S>&& rhs) {
2409   //
2410   const auto len = basic_fbstring<E, T, A, S>::traits_type::length(lhs);
2411   if (rhs.capacity() >= len + rhs.size()) {
2412     // Good, at least we don't need to reallocate
2413     rhs.insert(rhs.begin(), lhs, lhs + len);
2414     return rhs;
2415   }
2416   // Meh, no go. Do it by hand since we have len already.
2417   basic_fbstring<E, T, A, S> result;
2418   result.reserve(len + rhs.size());
2419   result.append(lhs, len).append(rhs);
2420   return result;
2421 }
2422
2423 // C++11 21.4.8.1/7
2424 template <typename E, class T, class A, class S>
2425 inline
2426 basic_fbstring<E, T, A, S> operator+(
2427   E lhs,
2428   const basic_fbstring<E, T, A, S>& rhs) {
2429
2430   basic_fbstring<E, T, A, S> result;
2431   result.reserve(1 + rhs.size());
2432   result.push_back(lhs);
2433   result.append(rhs);
2434   return result;
2435 }
2436
2437 // C++11 21.4.8.1/8
2438 template <typename E, class T, class A, class S>
2439 inline
2440 basic_fbstring<E, T, A, S> operator+(
2441   E lhs,
2442   basic_fbstring<E, T, A, S>&& rhs) {
2443   //
2444   if (rhs.capacity() > rhs.size()) {
2445     // Good, at least we don't need to reallocate
2446     rhs.insert(rhs.begin(), lhs);
2447     return rhs;
2448   }
2449   // Meh, no go. Forward to operator+(E, const&).
2450   auto const& rhsC = rhs;
2451   return lhs + rhsC;
2452 }
2453
2454 // C++11 21.4.8.1/9
2455 template <typename E, class T, class A, class S>
2456 inline
2457 basic_fbstring<E, T, A, S> operator+(
2458   const basic_fbstring<E, T, A, S>& lhs,
2459   const E* rhs) {
2460
2461   typedef typename basic_fbstring<E, T, A, S>::size_type size_type;
2462   typedef typename basic_fbstring<E, T, A, S>::traits_type traits_type;
2463
2464   basic_fbstring<E, T, A, S> result;
2465   const size_type len = traits_type::length(rhs);
2466   result.reserve(lhs.size() + len);
2467   result.append(lhs).append(rhs, len);
2468   return result;
2469 }
2470
2471 // C++11 21.4.8.1/10
2472 template <typename E, class T, class A, class S>
2473 inline
2474 basic_fbstring<E, T, A, S> operator+(
2475   basic_fbstring<E, T, A, S>&& lhs,
2476   const E* rhs) {
2477   //
2478   return std::move(lhs += rhs);
2479 }
2480
2481 // C++11 21.4.8.1/11
2482 template <typename E, class T, class A, class S>
2483 inline
2484 basic_fbstring<E, T, A, S> operator+(
2485   const basic_fbstring<E, T, A, S>& lhs,
2486   E rhs) {
2487
2488   basic_fbstring<E, T, A, S> result;
2489   result.reserve(lhs.size() + 1);
2490   result.append(lhs);
2491   result.push_back(rhs);
2492   return result;
2493 }
2494
2495 // C++11 21.4.8.1/12
2496 template <typename E, class T, class A, class S>
2497 inline
2498 basic_fbstring<E, T, A, S> operator+(
2499   basic_fbstring<E, T, A, S>&& lhs,
2500   E rhs) {
2501   //
2502   return std::move(lhs += rhs);
2503 }
2504
2505 template <typename E, class T, class A, class S>
2506 inline
2507 bool operator==(const basic_fbstring<E, T, A, S>& lhs,
2508                 const basic_fbstring<E, T, A, S>& rhs) {
2509   return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; }
2510
2511 template <typename E, class T, class A, class S>
2512 inline
2513 bool operator==(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2514                 const basic_fbstring<E, T, A, S>& rhs) {
2515   return rhs == lhs; }
2516
2517 template <typename E, class T, class A, class S>
2518 inline
2519 bool operator==(const basic_fbstring<E, T, A, S>& lhs,
2520                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2521   return lhs.compare(rhs) == 0; }
2522
2523 template <typename E, class T, class A, class S>
2524 inline
2525 bool operator!=(const basic_fbstring<E, T, A, S>& lhs,
2526                 const basic_fbstring<E, T, A, S>& rhs) {
2527   return !(lhs == rhs); }
2528
2529 template <typename E, class T, class A, class S>
2530 inline
2531 bool operator!=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2532                 const basic_fbstring<E, T, A, S>& rhs) {
2533   return !(lhs == rhs); }
2534
2535 template <typename E, class T, class A, class S>
2536 inline
2537 bool operator!=(const basic_fbstring<E, T, A, S>& lhs,
2538                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2539   return !(lhs == rhs); }
2540
2541 template <typename E, class T, class A, class S>
2542 inline
2543 bool operator<(const basic_fbstring<E, T, A, S>& lhs,
2544                const basic_fbstring<E, T, A, S>& rhs) {
2545   return lhs.compare(rhs) < 0; }
2546
2547 template <typename E, class T, class A, class S>
2548 inline
2549 bool operator<(const basic_fbstring<E, T, A, S>& lhs,
2550                const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2551   return lhs.compare(rhs) < 0; }
2552
2553 template <typename E, class T, class A, class S>
2554 inline
2555 bool operator<(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2556                const basic_fbstring<E, T, A, S>& rhs) {
2557   return rhs.compare(lhs) > 0; }
2558
2559 template <typename E, class T, class A, class S>
2560 inline
2561 bool operator>(const basic_fbstring<E, T, A, S>& lhs,
2562                const basic_fbstring<E, T, A, S>& rhs) {
2563   return rhs < lhs; }
2564
2565 template <typename E, class T, class A, class S>
2566 inline
2567 bool operator>(const basic_fbstring<E, T, A, S>& lhs,
2568                const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2569   return rhs < lhs; }
2570
2571 template <typename E, class T, class A, class S>
2572 inline
2573 bool operator>(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2574                const basic_fbstring<E, T, A, S>& rhs) {
2575   return rhs < lhs; }
2576
2577 template <typename E, class T, class A, class S>
2578 inline
2579 bool operator<=(const basic_fbstring<E, T, A, S>& lhs,
2580                 const basic_fbstring<E, T, A, S>& rhs) {
2581   return !(rhs < lhs); }
2582
2583 template <typename E, class T, class A, class S>
2584 inline
2585 bool operator<=(const basic_fbstring<E, T, A, S>& lhs,
2586                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2587   return !(rhs < lhs); }
2588
2589 template <typename E, class T, class A, class S>
2590 inline
2591 bool operator<=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2592                 const basic_fbstring<E, T, A, S>& rhs) {
2593   return !(rhs < lhs); }
2594
2595 template <typename E, class T, class A, class S>
2596 inline
2597 bool operator>=(const basic_fbstring<E, T, A, S>& lhs,
2598                 const basic_fbstring<E, T, A, S>& rhs) {
2599   return !(lhs < rhs); }
2600
2601 template <typename E, class T, class A, class S>
2602 inline
2603 bool operator>=(const basic_fbstring<E, T, A, S>& lhs,
2604                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2605   return !(lhs < rhs); }
2606
2607 template <typename E, class T, class A, class S>
2608 inline
2609 bool operator>=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2610                 const basic_fbstring<E, T, A, S>& rhs) {
2611  return !(lhs < rhs);
2612 }
2613
2614 // C++11 21.4.8.8
2615 template <typename E, class T, class A, class S>
2616 void swap(basic_fbstring<E, T, A, S>& lhs, basic_fbstring<E, T, A, S>& rhs) {
2617   lhs.swap(rhs);
2618 }
2619
2620 // TODO: make this faster.
2621 template <typename E, class T, class A, class S>
2622 inline
2623 std::basic_istream<
2624   typename basic_fbstring<E, T, A, S>::value_type,
2625   typename basic_fbstring<E, T, A, S>::traits_type>&
2626   operator>>(
2627     std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
2628     typename basic_fbstring<E, T, A, S>::traits_type>& is,
2629     basic_fbstring<E, T, A, S>& str) {
2630   typename std::basic_istream<E, T>::sentry sentry(is);
2631   typedef std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
2632                              typename basic_fbstring<E, T, A, S>::traits_type>
2633                         __istream_type;
2634   typedef typename __istream_type::ios_base __ios_base;
2635   size_t extracted = 0;
2636   auto err = __ios_base::goodbit;
2637   if (sentry) {
2638     auto n = is.width();
2639     if (n <= 0) {
2640       n = str.max_size();
2641     }
2642     str.erase();
2643     for (auto got = is.rdbuf()->sgetc(); extracted != size_t(n); ++extracted) {
2644       if (got == T::eof()) {
2645         err |= __ios_base::eofbit;
2646         is.width(0);
2647         break;
2648       }
2649       if (isspace(got)) {
2650         break;
2651       }
2652       str.push_back(got);
2653       got = is.rdbuf()->snextc();
2654     }
2655   }
2656   if (!extracted) {
2657     err |= __ios_base::failbit;
2658   }
2659   if (err) {
2660     is.setstate(err);
2661   }
2662   return is;
2663 }
2664
2665 template <typename E, class T, class A, class S>
2666 inline
2667 std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type,
2668                    typename basic_fbstring<E, T, A, S>::traits_type>&
2669 operator<<(
2670   std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type,
2671   typename basic_fbstring<E, T, A, S>::traits_type>& os,
2672     const basic_fbstring<E, T, A, S>& str) {
2673 #if _LIBCPP_VERSION
2674   typename std::basic_ostream<
2675     typename basic_fbstring<E, T, A, S>::value_type,
2676     typename basic_fbstring<E, T, A, S>::traits_type>::sentry __s(os);
2677   if (__s) {
2678     typedef std::ostreambuf_iterator<
2679       typename basic_fbstring<E, T, A, S>::value_type,
2680       typename basic_fbstring<E, T, A, S>::traits_type> _Ip;
2681     size_t __len = str.size();
2682     bool __left =
2683       (os.flags() & std::ios_base::adjustfield) == std::ios_base::left;
2684     if (__pad_and_output(_Ip(os),
2685                          str.data(),
2686                          __left ? str.data() + __len : str.data(),
2687                          str.data() + __len,
2688                          os,
2689                          os.fill()).failed()) {
2690       os.setstate(std::ios_base::badbit | std::ios_base::failbit);
2691     }
2692   }
2693 #elif defined(_MSC_VER)
2694   // MSVC doesn't define __ostream_insert
2695   os.write(str.data(), str.size());
2696 #else
2697   std::__ostream_insert(os, str.data(), str.size());
2698 #endif
2699   return os;
2700 }
2701
2702 template <typename E1, class T, class A, class S>
2703 constexpr typename basic_fbstring<E1, T, A, S>::size_type
2704     basic_fbstring<E1, T, A, S>::npos;
2705
2706 #ifndef _LIBSTDCXX_FBSTRING
2707 // basic_string compatibility routines
2708
2709 template <typename E, class T, class A, class S>
2710 inline
2711 bool operator==(const basic_fbstring<E, T, A, S>& lhs,
2712                 const std::string& rhs) {
2713   return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) == 0;
2714 }
2715
2716 template <typename E, class T, class A, class S>
2717 inline
2718 bool operator==(const std::string& lhs,
2719                 const basic_fbstring<E, T, A, S>& rhs) {
2720   return rhs == lhs;
2721 }
2722
2723 template <typename E, class T, class A, class S>
2724 inline
2725 bool operator!=(const basic_fbstring<E, T, A, S>& lhs,
2726                 const std::string& rhs) {
2727   return !(lhs == rhs);
2728 }
2729
2730 template <typename E, class T, class A, class S>
2731 inline
2732 bool operator!=(const std::string& lhs,
2733                 const basic_fbstring<E, T, A, S>& rhs) {
2734   return !(lhs == rhs);
2735 }
2736
2737 #if !defined(_LIBSTDCXX_FBSTRING)
2738 typedef basic_fbstring<char> fbstring;
2739 #endif
2740
2741 // fbstring is relocatable
2742 template <class T, class R, class A, class S>
2743 FOLLY_ASSUME_RELOCATABLE(basic_fbstring<T, R, A, S>);
2744
2745 #else
2746 _GLIBCXX_END_NAMESPACE_VERSION
2747 #endif
2748
2749 } // namespace folly
2750
2751 #ifndef _LIBSTDCXX_FBSTRING
2752
2753 // Hash functions to make fbstring usable with e.g. hash_map
2754 //
2755 // Handle interaction with different C++ standard libraries, which
2756 // expect these types to be in different namespaces.
2757
2758 #define FOLLY_FBSTRING_HASH1(T)                                        \
2759   template <>                                                          \
2760   struct hash< ::folly::basic_fbstring<T>> {                           \
2761     size_t operator()(const ::folly::basic_fbstring<T>& s) const {     \
2762       return ::folly::hash::fnv32_buf(s.data(), s.size() * sizeof(T)); \
2763     }                                                                  \
2764   };
2765
2766 // The C++11 standard says that these four are defined
2767 #define FOLLY_FBSTRING_HASH \
2768   FOLLY_FBSTRING_HASH1(char) \
2769   FOLLY_FBSTRING_HASH1(char16_t) \
2770   FOLLY_FBSTRING_HASH1(char32_t) \
2771   FOLLY_FBSTRING_HASH1(wchar_t)
2772
2773 namespace std {
2774
2775 FOLLY_FBSTRING_HASH
2776
2777 }  // namespace std
2778
2779 #if FOLLY_HAVE_DEPRECATED_ASSOC
2780 #if defined(_GLIBCXX_SYMVER) && !defined(__BIONIC__)
2781 namespace __gnu_cxx {
2782
2783 FOLLY_FBSTRING_HASH
2784
2785 }  // namespace __gnu_cxx
2786 #endif // _GLIBCXX_SYMVER && !__BIONIC__
2787 #endif // FOLLY_HAVE_DEPRECATED_ASSOC
2788
2789 #undef FOLLY_FBSTRING_HASH
2790 #undef FOLLY_FBSTRING_HASH1
2791
2792 #endif // _LIBSTDCXX_FBSTRING
2793
2794 #pragma GCC diagnostic pop
2795
2796 #undef FBSTRING_DISABLE_SSO
2797 #undef FBSTRING_SANITIZE_ADDRESS
2798 #undef throw
2799 #undef FBSTRING_LIKELY
2800 #undef FBSTRING_UNLIKELY
2801 #undef FBSTRING_ASSERT