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