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