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