Remove FOLLY_SKIP_LIBCPP_4000_THROW_BACKPORTS
[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   template <typename A2>
1145   /* implicit */ basic_fbstring(const std::basic_string<E, T, A2>& str)
1146       : store_(str.data(), str.size()) {}
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   template <typename A2>
1209   basic_fbstring& operator=(const std::basic_string<E, T, A2>& rhs) {
1210     return assign(rhs.data(), rhs.size());
1211   }
1212
1213   // Compatibility with std::string
1214   std::basic_string<E, T, A> toStdString() const {
1215     return std::basic_string<E, T, A>(data(), size());
1216   }
1217 #else
1218   // A lot of code in fbcode still uses this method, so keep it here for now.
1219   const basic_fbstring& toStdString() const {
1220     return *this;
1221   }
1222 #endif
1223
1224   basic_fbstring& operator=(const value_type* s) {
1225     return assign(s);
1226   }
1227
1228   // This actually goes directly against the C++ spec, but the
1229   // value_type overload is dangerous, so we're explicitly deleting
1230   // any overloads of operator= that could implicitly convert to
1231   // value_type.
1232   // Note that we do need to explicitly specify the template types because
1233   // otherwise MSVC 2017 will aggressively pre-resolve value_type to
1234   // traits_type::char_type, which won't compare as equal when determining
1235   // which overload the implementation is referring to.
1236   // Also note that MSVC 2015 Update 3 requires us to explicitly specify the
1237   // namespace in-which to search for basic_fbstring, otherwise it tries to
1238   // look for basic_fbstring::basic_fbstring, which is just plain wrong.
1239   template <typename TP>
1240   typename std::enable_if<
1241       std::is_same<
1242           typename std::decay<TP>::type,
1243           typename folly::basic_fbstring<E, T, A, Storage>::value_type>::value,
1244       basic_fbstring<E, T, A, Storage>&>::type
1245   operator=(TP c);
1246
1247   basic_fbstring& operator=(std::initializer_list<value_type> il) {
1248     return assign(il.begin(), il.end());
1249   }
1250
1251   // C++11 21.4.3 iterators:
1252   iterator begin() {
1253     return store_.mutableData();
1254   }
1255
1256   const_iterator begin() const {
1257     return store_.data();
1258   }
1259
1260   const_iterator cbegin() const {
1261     return begin();
1262   }
1263
1264   iterator end() {
1265     return store_.mutableData() + store_.size();
1266   }
1267
1268   const_iterator end() const {
1269     return store_.data() + store_.size();
1270   }
1271
1272   const_iterator cend() const { return end(); }
1273
1274   reverse_iterator rbegin() {
1275     return reverse_iterator(end());
1276   }
1277
1278   const_reverse_iterator rbegin() const {
1279     return const_reverse_iterator(end());
1280   }
1281
1282   const_reverse_iterator crbegin() const { return rbegin(); }
1283
1284   reverse_iterator rend() {
1285     return reverse_iterator(begin());
1286   }
1287
1288   const_reverse_iterator rend() const {
1289     return const_reverse_iterator(begin());
1290   }
1291
1292   const_reverse_iterator crend() const { return rend(); }
1293
1294   // Added by C++11
1295   // C++11 21.4.5, element access:
1296   const value_type& front() const { return *begin(); }
1297   const value_type& back() const {
1298     FBSTRING_ASSERT(!empty());
1299     // Should be begin()[size() - 1], but that branches twice
1300     return *(end() - 1);
1301   }
1302   value_type& front() { return *begin(); }
1303   value_type& back() {
1304     FBSTRING_ASSERT(!empty());
1305     // Should be begin()[size() - 1], but that branches twice
1306     return *(end() - 1);
1307   }
1308   void pop_back() {
1309     FBSTRING_ASSERT(!empty());
1310     store_.shrink(1);
1311   }
1312
1313   // C++11 21.4.4 capacity:
1314   size_type size() const { return store_.size(); }
1315
1316   size_type length() const { return size(); }
1317
1318   size_type max_size() const {
1319     return std::numeric_limits<size_type>::max();
1320   }
1321
1322   void resize(size_type n, value_type c = value_type());
1323
1324   size_type capacity() const { return store_.capacity(); }
1325
1326   void reserve(size_type res_arg = 0) {
1327     enforce(res_arg <= max_size(), std::__throw_length_error, "");
1328     store_.reserve(res_arg);
1329   }
1330
1331   void shrink_to_fit() {
1332     // Shrink only if slack memory is sufficiently large
1333     if (capacity() < size() * 3 / 2) {
1334       return;
1335     }
1336     basic_fbstring(cbegin(), cend()).swap(*this);
1337   }
1338
1339   void clear() { resize(0); }
1340
1341   bool empty() const { return size() == 0; }
1342
1343   // C++11 21.4.5 element access:
1344   const_reference operator[](size_type pos) const {
1345     return *(begin() + pos);
1346   }
1347
1348   reference operator[](size_type pos) {
1349     return *(begin() + pos);
1350   }
1351
1352   const_reference at(size_type n) const {
1353     enforce(n <= size(), std::__throw_out_of_range, "");
1354     return (*this)[n];
1355   }
1356
1357   reference at(size_type n) {
1358     enforce(n < size(), std::__throw_out_of_range, "");
1359     return (*this)[n];
1360   }
1361
1362   // C++11 21.4.6 modifiers:
1363   basic_fbstring& operator+=(const basic_fbstring& str) {
1364     return append(str);
1365   }
1366
1367   basic_fbstring& operator+=(const value_type* s) {
1368     return append(s);
1369   }
1370
1371   basic_fbstring& operator+=(const value_type c) {
1372     push_back(c);
1373     return *this;
1374   }
1375
1376   basic_fbstring& operator+=(std::initializer_list<value_type> il) {
1377     append(il);
1378     return *this;
1379   }
1380
1381   basic_fbstring& append(const basic_fbstring& str);
1382
1383   basic_fbstring&
1384   append(const basic_fbstring& str, const size_type pos, size_type n);
1385
1386   basic_fbstring& append(const value_type* s, size_type n);
1387
1388   basic_fbstring& append(const value_type* s) {
1389     return append(s, traitsLength(s));
1390   }
1391
1392   basic_fbstring& append(size_type n, value_type c);
1393
1394   template<class InputIterator>
1395   basic_fbstring& append(InputIterator first, InputIterator last) {
1396     insert(end(), first, last);
1397     return *this;
1398   }
1399
1400   basic_fbstring& append(std::initializer_list<value_type> il) {
1401     return append(il.begin(), il.end());
1402   }
1403
1404   void push_back(const value_type c) {             // primitive
1405     store_.push_back(c);
1406   }
1407
1408   basic_fbstring& assign(const basic_fbstring& str) {
1409     if (&str == this) return *this;
1410     return assign(str.data(), str.size());
1411   }
1412
1413   basic_fbstring& assign(basic_fbstring&& str) {
1414     return *this = std::move(str);
1415   }
1416
1417   basic_fbstring&
1418   assign(const basic_fbstring& str, const size_type pos, size_type n);
1419
1420   basic_fbstring& assign(const value_type* s, const size_type n);
1421
1422   basic_fbstring& assign(const value_type* s) {
1423     return assign(s, traitsLength(s));
1424   }
1425
1426   basic_fbstring& assign(std::initializer_list<value_type> il) {
1427     return assign(il.begin(), il.end());
1428   }
1429
1430   template <class ItOrLength, class ItOrChar>
1431   basic_fbstring& assign(ItOrLength first_or_n, ItOrChar last_or_c) {
1432     return replace(begin(), end(), first_or_n, last_or_c);
1433   }
1434
1435   basic_fbstring& insert(size_type pos1, const basic_fbstring& str) {
1436     return insert(pos1, str.data(), str.size());
1437   }
1438
1439   basic_fbstring& insert(size_type pos1, const basic_fbstring& str,
1440                          size_type pos2, size_type n) {
1441     enforce(pos2 <= str.length(), std::__throw_out_of_range, "");
1442     procrustes(n, str.length() - pos2);
1443     return insert(pos1, str.data() + pos2, n);
1444   }
1445
1446   basic_fbstring& insert(size_type pos, const value_type* s, size_type n) {
1447     enforce(pos <= length(), std::__throw_out_of_range, "");
1448     insert(begin() + pos, s, s + n);
1449     return *this;
1450   }
1451
1452   basic_fbstring& insert(size_type pos, const value_type* s) {
1453     return insert(pos, s, traitsLength(s));
1454   }
1455
1456   basic_fbstring& insert(size_type pos, size_type n, value_type c) {
1457     enforce(pos <= length(), std::__throw_out_of_range, "");
1458     insert(begin() + pos, n, c);
1459     return *this;
1460   }
1461
1462   iterator insert(const_iterator p, const value_type c) {
1463     const size_type pos = p - cbegin();
1464     insert(p, 1, c);
1465     return begin() + pos;
1466   }
1467
1468 #ifndef _LIBSTDCXX_FBSTRING
1469  private:
1470   typedef std::basic_istream<value_type, traits_type> istream_type;
1471   istream_type& getlineImpl(istream_type& is, value_type delim);
1472
1473  public:
1474   friend inline istream_type& getline(istream_type& is,
1475                                       basic_fbstring& str,
1476                                       value_type delim) {
1477     return str.getlineImpl(is, delim);
1478   }
1479
1480   friend inline istream_type& getline(istream_type& is, basic_fbstring& str) {
1481     return getline(is, str, '\n');
1482   }
1483 #endif
1484
1485 private:
1486  iterator
1487  insertImplDiscr(const_iterator i, size_type n, value_type c, std::true_type);
1488
1489  template <class InputIter>
1490  iterator
1491  insertImplDiscr(const_iterator i, InputIter b, InputIter e, std::false_type);
1492
1493  template <class FwdIterator>
1494  iterator insertImpl(
1495      const_iterator i,
1496      FwdIterator s1,
1497      FwdIterator s2,
1498      std::forward_iterator_tag);
1499
1500  template <class InputIterator>
1501  iterator insertImpl(
1502      const_iterator i,
1503      InputIterator b,
1504      InputIterator e,
1505      std::input_iterator_tag);
1506
1507 public:
1508   template <class ItOrLength, class ItOrChar>
1509   iterator insert(const_iterator p, ItOrLength first_or_n, ItOrChar last_or_c) {
1510     using Sel = std::integral_constant<
1511         bool,
1512         std::numeric_limits<ItOrLength>::is_specialized>;
1513     return insertImplDiscr(p, first_or_n, last_or_c, Sel());
1514   }
1515
1516   iterator insert(const_iterator p, std::initializer_list<value_type> il) {
1517     return insert(p, il.begin(), il.end());
1518   }
1519
1520   basic_fbstring& erase(size_type pos = 0, size_type n = npos) {
1521     Invariant checker(*this);
1522
1523     enforce(pos <= length(), std::__throw_out_of_range, "");
1524     procrustes(n, length() - pos);
1525     std::copy(begin() + pos + n, end(), begin() + pos);
1526     resize(length() - n);
1527     return *this;
1528   }
1529
1530   iterator erase(iterator position) {
1531     const size_type pos(position - begin());
1532     enforce(pos <= size(), std::__throw_out_of_range, "");
1533     erase(pos, 1);
1534     return begin() + pos;
1535   }
1536
1537   iterator erase(iterator first, iterator last) {
1538     const size_type pos(first - begin());
1539     erase(pos, last - first);
1540     return begin() + pos;
1541   }
1542
1543   // Replaces at most n1 chars of *this, starting with pos1 with the
1544   // content of str
1545   basic_fbstring& replace(size_type pos1, size_type n1,
1546                           const basic_fbstring& str) {
1547     return replace(pos1, n1, str.data(), str.size());
1548   }
1549
1550   // Replaces at most n1 chars of *this, starting with pos1,
1551   // with at most n2 chars of str starting with pos2
1552   basic_fbstring& replace(size_type pos1, size_type n1,
1553                           const basic_fbstring& str,
1554                           size_type pos2, size_type n2) {
1555     enforce(pos2 <= str.length(), std::__throw_out_of_range, "");
1556     return replace(pos1, n1, str.data() + pos2,
1557                    std::min(n2, str.size() - pos2));
1558   }
1559
1560   // Replaces at most n1 chars of *this, starting with pos, with chars from s
1561   basic_fbstring& replace(size_type pos, size_type n1, const value_type* s) {
1562     return replace(pos, n1, s, traitsLength(s));
1563   }
1564
1565   // Replaces at most n1 chars of *this, starting with pos, with n2
1566   // occurrences of c
1567   //
1568   // consolidated with
1569   //
1570   // Replaces at most n1 chars of *this, starting with pos, with at
1571   // most n2 chars of str.  str must have at least n2 chars.
1572   template <class StrOrLength, class NumOrChar>
1573   basic_fbstring& replace(size_type pos, size_type n1,
1574                           StrOrLength s_or_n2, NumOrChar n_or_c) {
1575     Invariant checker(*this);
1576
1577     enforce(pos <= size(), std::__throw_out_of_range, "");
1578     procrustes(n1, length() - pos);
1579     const iterator b = begin() + pos;
1580     return replace(b, b + n1, s_or_n2, n_or_c);
1581   }
1582
1583   basic_fbstring& replace(iterator i1, iterator i2, const basic_fbstring& str) {
1584     return replace(i1, i2, str.data(), str.length());
1585   }
1586
1587   basic_fbstring& replace(iterator i1, iterator i2, const value_type* s) {
1588     return replace(i1, i2, s, traitsLength(s));
1589   }
1590
1591 private:
1592  basic_fbstring& replaceImplDiscr(
1593      iterator i1,
1594      iterator i2,
1595      const value_type* s,
1596      size_type n,
1597      std::integral_constant<int, 2>);
1598
1599  basic_fbstring& replaceImplDiscr(
1600      iterator i1,
1601      iterator i2,
1602      size_type n2,
1603      value_type c,
1604      std::integral_constant<int, 1>);
1605
1606  template <class InputIter>
1607  basic_fbstring& replaceImplDiscr(
1608      iterator i1,
1609      iterator i2,
1610      InputIter b,
1611      InputIter e,
1612      std::integral_constant<int, 0>);
1613
1614 private:
1615  template <class FwdIterator>
1616  bool replaceAliased(iterator /* i1 */,
1617                      iterator /* i2 */,
1618                      FwdIterator /* s1 */,
1619                      FwdIterator /* s2 */,
1620                      std::false_type) {
1621     return false;
1622   }
1623
1624   template <class FwdIterator>
1625   bool replaceAliased(
1626       iterator i1,
1627       iterator i2,
1628       FwdIterator s1,
1629       FwdIterator s2,
1630       std::true_type);
1631
1632   template <class FwdIterator>
1633   void replaceImpl(
1634       iterator i1,
1635       iterator i2,
1636       FwdIterator s1,
1637       FwdIterator s2,
1638       std::forward_iterator_tag);
1639
1640   template <class InputIterator>
1641   void replaceImpl(
1642       iterator i1,
1643       iterator i2,
1644       InputIterator b,
1645       InputIterator e,
1646       std::input_iterator_tag);
1647
1648  public:
1649   template <class T1, class T2>
1650   basic_fbstring& replace(iterator i1, iterator i2,
1651                           T1 first_or_n_or_s, T2 last_or_c_or_n) {
1652     constexpr bool num1 = std::numeric_limits<T1>::is_specialized,
1653                    num2 = std::numeric_limits<T2>::is_specialized;
1654     using Sel =
1655         std::integral_constant<int, num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>;
1656     return replaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n, Sel());
1657   }
1658
1659   size_type copy(value_type* s, size_type n, size_type pos = 0) const {
1660     enforce(pos <= size(), std::__throw_out_of_range, "");
1661     procrustes(n, size() - pos);
1662
1663     if (n != 0) {
1664       fbstring_detail::podCopy(data() + pos, data() + pos + n, s);
1665     }
1666     return n;
1667   }
1668
1669   void swap(basic_fbstring& rhs) {
1670     store_.swap(rhs.store_);
1671   }
1672
1673   const value_type* c_str() const {
1674     return store_.c_str();
1675   }
1676
1677   const value_type* data() const { return c_str(); }
1678
1679   allocator_type get_allocator() const {
1680     return allocator_type();
1681   }
1682
1683   size_type find(const basic_fbstring& str, size_type pos = 0) const {
1684     return find(str.data(), pos, str.length());
1685   }
1686
1687   size_type find(const value_type* needle, size_type pos, size_type nsize)
1688       const;
1689
1690   size_type find(const value_type* s, size_type pos = 0) const {
1691     return find(s, pos, traitsLength(s));
1692   }
1693
1694   size_type find (value_type c, size_type pos = 0) const {
1695     return find(&c, pos, 1);
1696   }
1697
1698   size_type rfind(const basic_fbstring& str, size_type pos = npos) const {
1699     return rfind(str.data(), pos, str.length());
1700   }
1701
1702   size_type rfind(const value_type* s, size_type pos, size_type n) const;
1703
1704   size_type rfind(const value_type* s, size_type pos = npos) const {
1705     return rfind(s, pos, traitsLength(s));
1706   }
1707
1708   size_type rfind(value_type c, size_type pos = npos) const {
1709     return rfind(&c, pos, 1);
1710   }
1711
1712   size_type find_first_of(const basic_fbstring& str, size_type pos = 0) const {
1713     return find_first_of(str.data(), pos, str.length());
1714   }
1715
1716   size_type find_first_of(const value_type* s, size_type pos, size_type n)
1717       const;
1718
1719   size_type find_first_of(const value_type* s, size_type pos = 0) const {
1720     return find_first_of(s, pos, traitsLength(s));
1721   }
1722
1723   size_type find_first_of(value_type c, size_type pos = 0) const {
1724     return find_first_of(&c, pos, 1);
1725   }
1726
1727   size_type find_last_of(const basic_fbstring& str, size_type pos = npos)
1728       const {
1729     return find_last_of(str.data(), pos, str.length());
1730   }
1731
1732   size_type find_last_of(const value_type* s, size_type pos, size_type n) const;
1733
1734   size_type find_last_of (const value_type* s,
1735                           size_type pos = npos) const {
1736     return find_last_of(s, pos, traitsLength(s));
1737   }
1738
1739   size_type find_last_of (value_type c, size_type pos = npos) const {
1740     return find_last_of(&c, pos, 1);
1741   }
1742
1743   size_type find_first_not_of(const basic_fbstring& str,
1744                               size_type pos = 0) const {
1745     return find_first_not_of(str.data(), pos, str.size());
1746   }
1747
1748   size_type find_first_not_of(const value_type* s, size_type pos, size_type n)
1749       const;
1750
1751   size_type find_first_not_of(const value_type* s,
1752                               size_type pos = 0) const {
1753     return find_first_not_of(s, pos, traitsLength(s));
1754   }
1755
1756   size_type find_first_not_of(value_type c, size_type pos = 0) const {
1757     return find_first_not_of(&c, pos, 1);
1758   }
1759
1760   size_type find_last_not_of(const basic_fbstring& str,
1761                              size_type pos = npos) const {
1762     return find_last_not_of(str.data(), pos, str.length());
1763   }
1764
1765   size_type find_last_not_of(const value_type* s, size_type pos, size_type n)
1766       const;
1767
1768   size_type find_last_not_of(const value_type* s,
1769                              size_type pos = npos) const {
1770     return find_last_not_of(s, pos, traitsLength(s));
1771   }
1772
1773   size_type find_last_not_of (value_type c, size_type pos = npos) const {
1774     return find_last_not_of(&c, pos, 1);
1775   }
1776
1777   basic_fbstring substr(size_type pos = 0, size_type n = npos) const& {
1778     enforce(pos <= size(), std::__throw_out_of_range, "");
1779     return basic_fbstring(data() + pos, std::min(n, size() - pos));
1780   }
1781
1782   basic_fbstring substr(size_type pos = 0, size_type n = npos) && {
1783     enforce(pos <= size(), std::__throw_out_of_range, "");
1784     erase(0, pos);
1785     if (n < size()) {
1786       resize(n);
1787     }
1788     return std::move(*this);
1789   }
1790
1791   int compare(const basic_fbstring& str) const {
1792     // FIX due to Goncalo N M de Carvalho July 18, 2005
1793     return compare(0, size(), str);
1794   }
1795
1796   int compare(size_type pos1, size_type n1,
1797               const basic_fbstring& str) const {
1798     return compare(pos1, n1, str.data(), str.size());
1799   }
1800
1801   int compare(size_type pos1, size_type n1,
1802               const value_type* s) const {
1803     return compare(pos1, n1, s, traitsLength(s));
1804   }
1805
1806   int compare(size_type pos1, size_type n1,
1807               const value_type* s, size_type n2) const {
1808     enforce(pos1 <= size(), std::__throw_out_of_range, "");
1809     procrustes(n1, size() - pos1);
1810     // The line below fixed by Jean-Francois Bastien, 04-23-2007. Thanks!
1811     const int r = traits_type::compare(pos1 + data(), s, std::min(n1, n2));
1812     return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
1813   }
1814
1815   int compare(size_type pos1, size_type n1,
1816               const basic_fbstring& str,
1817               size_type pos2, size_type n2) const {
1818     enforce(pos2 <= str.size(), std::__throw_out_of_range, "");
1819     return compare(pos1, n1, str.data() + pos2,
1820                    std::min(n2, str.size() - pos2));
1821   }
1822
1823   // Code from Jean-Francois Bastien (03/26/2007)
1824   int compare(const value_type* s) const {
1825     // Could forward to compare(0, size(), s, traitsLength(s))
1826     // but that does two extra checks
1827     const size_type n1(size()), n2(traitsLength(s));
1828     const int r = traits_type::compare(data(), s, std::min(n1, n2));
1829     return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
1830   }
1831
1832 private:
1833   // Data
1834   Storage store_;
1835 };
1836
1837 template <typename E, class T, class A, class S>
1838 FOLLY_MALLOC_NOINLINE inline typename basic_fbstring<E, T, A, S>::size_type
1839 basic_fbstring<E, T, A, S>::traitsLength(const value_type* s) {
1840   return s ? traits_type::length(s)
1841            : (std::__throw_logic_error(
1842                   "basic_fbstring: null pointer initializer not valid"),
1843               0);
1844 }
1845
1846 template <typename E, class T, class A, class S>
1847 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=(
1848     const basic_fbstring& lhs) {
1849   Invariant checker(*this);
1850
1851   if (FBSTRING_UNLIKELY(&lhs == this)) {
1852     return *this;
1853   }
1854
1855   return assign(lhs.data(), lhs.size());
1856 }
1857
1858 // Move assignment
1859 template <typename E, class T, class A, class S>
1860 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=(
1861     basic_fbstring&& goner) noexcept {
1862   if (FBSTRING_UNLIKELY(&goner == this)) {
1863     // Compatibility with std::basic_string<>,
1864     // C++11 21.4.2 [string.cons] / 23 requires self-move-assignment support.
1865     return *this;
1866   }
1867   // No need of this anymore
1868   this->~basic_fbstring();
1869   // Move the goner into this
1870   new (&store_) S(std::move(goner.store_));
1871   return *this;
1872 }
1873
1874 template <typename E, class T, class A, class S>
1875 template <typename TP>
1876 inline typename std::enable_if<
1877     std::is_same<
1878         typename std::decay<TP>::type,
1879         typename basic_fbstring<E, T, A, S>::value_type>::value,
1880     basic_fbstring<E, T, A, S>&>::type
1881 basic_fbstring<E, T, A, S>::operator=(TP c) {
1882   Invariant checker(*this);
1883
1884   if (empty()) {
1885     store_.expandNoinit(1);
1886   } else if (store_.isShared()) {
1887     basic_fbstring(1, c).swap(*this);
1888     return *this;
1889   } else {
1890     store_.shrink(size() - 1);
1891   }
1892   front() = c;
1893   return *this;
1894 }
1895
1896 template <typename E, class T, class A, class S>
1897 inline void basic_fbstring<E, T, A, S>::resize(
1898     const size_type n, const value_type c /*= value_type()*/) {
1899   Invariant checker(*this);
1900
1901   auto size = this->size();
1902   if (n <= size) {
1903     store_.shrink(size - n);
1904   } else {
1905     auto const delta = n - size;
1906     auto pData = store_.expandNoinit(delta);
1907     fbstring_detail::podFill(pData, pData + delta, c);
1908   }
1909   FBSTRING_ASSERT(this->size() == n);
1910 }
1911
1912 template <typename E, class T, class A, class S>
1913 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append(
1914     const basic_fbstring& str) {
1915 #ifndef NDEBUG
1916   auto desiredSize = size() + str.size();
1917 #endif
1918   append(str.data(), str.size());
1919   FBSTRING_ASSERT(size() == desiredSize);
1920   return *this;
1921 }
1922
1923 template <typename E, class T, class A, class S>
1924 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append(
1925     const basic_fbstring& str, const size_type pos, size_type n) {
1926   const size_type sz = str.size();
1927   enforce(pos <= sz, std::__throw_out_of_range, "");
1928   procrustes(n, sz - pos);
1929   return append(str.data() + pos, n);
1930 }
1931
1932 template <typename E, class T, class A, class S>
1933 FOLLY_MALLOC_NOINLINE inline basic_fbstring<E, T, A, S>&
1934 basic_fbstring<E, T, A, S>::append(const value_type* s, size_type n) {
1935   Invariant checker(*this);
1936
1937   if (FBSTRING_UNLIKELY(!n)) {
1938     // Unlikely but must be done
1939     return *this;
1940   }
1941   auto const oldSize = size();
1942   auto const oldData = data();
1943   auto pData = store_.expandNoinit(n, /* expGrowth = */ true);
1944
1945   // Check for aliasing (rare). We could use "<=" here but in theory
1946   // those do not work for pointers unless the pointers point to
1947   // elements in the same array. For that reason we use
1948   // std::less_equal, which is guaranteed to offer a total order
1949   // over pointers. See discussion at http://goo.gl/Cy2ya for more
1950   // info.
1951   std::less_equal<const value_type*> le;
1952   if (FBSTRING_UNLIKELY(le(oldData, s) && !le(oldData + oldSize, s))) {
1953     FBSTRING_ASSERT(le(s + n, oldData + oldSize));
1954     // expandNoinit() could have moved the storage, restore the source.
1955     s = data() + (s - oldData);
1956     fbstring_detail::podMove(s, s + n, pData);
1957   } else {
1958     fbstring_detail::podCopy(s, s + n, pData);
1959   }
1960
1961   FBSTRING_ASSERT(size() == oldSize + n);
1962   return *this;
1963 }
1964
1965 template <typename E, class T, class A, class S>
1966 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append(
1967     size_type n, value_type c) {
1968   Invariant checker(*this);
1969   auto pData = store_.expandNoinit(n, /* expGrowth = */ true);
1970   fbstring_detail::podFill(pData, pData + n, c);
1971   return *this;
1972 }
1973
1974 template <typename E, class T, class A, class S>
1975 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::assign(
1976     const basic_fbstring& str, const size_type pos, size_type n) {
1977   const size_type sz = str.size();
1978   enforce(pos <= sz, std::__throw_out_of_range, "");
1979   procrustes(n, sz - pos);
1980   return assign(str.data() + pos, n);
1981 }
1982
1983 template <typename E, class T, class A, class S>
1984 FOLLY_MALLOC_NOINLINE inline basic_fbstring<E, T, A, S>&
1985 basic_fbstring<E, T, A, S>::assign(const value_type* s, const size_type n) {
1986   Invariant checker(*this);
1987
1988   if (n == 0) {
1989     resize(0);
1990   } else if (size() >= n) {
1991     // s can alias this, we need to use podMove.
1992     fbstring_detail::podMove(s, s + n, store_.mutableData());
1993     store_.shrink(size() - n);
1994     FBSTRING_ASSERT(size() == n);
1995   } else {
1996     // If n is larger than size(), s cannot alias this string's
1997     // storage.
1998     resize(0);
1999     // Do not use exponential growth here: assign() should be tight,
2000     // to mirror the behavior of the equivalent constructor.
2001     fbstring_detail::podCopy(s, s + n, store_.expandNoinit(n));
2002   }
2003
2004   FBSTRING_ASSERT(size() == n);
2005   return *this;
2006 }
2007
2008 #ifndef _LIBSTDCXX_FBSTRING
2009 template <typename E, class T, class A, class S>
2010 inline typename basic_fbstring<E, T, A, S>::istream_type&
2011 basic_fbstring<E, T, A, S>::getlineImpl(istream_type & is, value_type delim) {
2012   Invariant checker(*this);
2013
2014   clear();
2015   size_t size = 0;
2016   while (true) {
2017     size_t avail = capacity() - size;
2018     // fbstring has 1 byte extra capacity for the null terminator,
2019     // and getline null-terminates the read string.
2020     is.getline(store_.expandNoinit(avail), avail + 1, delim);
2021     size += is.gcount();
2022
2023     if (is.bad() || is.eof() || !is.fail()) {
2024       // Done by either failure, end of file, or normal read.
2025       if (!is.bad() && !is.eof()) {
2026         --size; // gcount() also accounts for the delimiter.
2027       }
2028       resize(size);
2029       break;
2030     }
2031
2032     FBSTRING_ASSERT(size == this->size());
2033     FBSTRING_ASSERT(size == capacity());
2034     // Start at minimum allocation 63 + terminator = 64.
2035     reserve(std::max<size_t>(63, 3 * size / 2));
2036     // Clear the error so we can continue reading.
2037     is.clear();
2038   }
2039   return is;
2040 }
2041 #endif
2042
2043 template <typename E, class T, class A, class S>
2044 inline typename basic_fbstring<E, T, A, S>::size_type
2045 basic_fbstring<E, T, A, S>::find(
2046     const value_type* needle, const size_type pos, const size_type nsize)
2047     const {
2048   auto const size = this->size();
2049   // nsize + pos can overflow (eg pos == npos), guard against that by checking
2050   // that nsize + pos does not wrap around.
2051   if (nsize + pos > size || nsize + pos < pos) {
2052     return npos;
2053   }
2054
2055   if (nsize == 0) {
2056     return pos;
2057   }
2058   // Don't use std::search, use a Boyer-Moore-like trick by comparing
2059   // the last characters first
2060   auto const haystack = data();
2061   auto const nsize_1 = nsize - 1;
2062   auto const lastNeedle = needle[nsize_1];
2063
2064   // Boyer-Moore skip value for the last char in the needle. Zero is
2065   // not a valid value; skip will be computed the first time it's
2066   // needed.
2067   size_type skip = 0;
2068
2069   const E* i = haystack + pos;
2070   auto iEnd = haystack + size - nsize_1;
2071
2072   while (i < iEnd) {
2073     // Boyer-Moore: match the last element in the needle
2074     while (i[nsize_1] != lastNeedle) {
2075       if (++i == iEnd) {
2076         // not found
2077         return npos;
2078       }
2079     }
2080     // Here we know that the last char matches
2081     // Continue in pedestrian mode
2082     for (size_t j = 0;;) {
2083       FBSTRING_ASSERT(j < nsize);
2084       if (i[j] != needle[j]) {
2085         // Not found, we can skip
2086         // Compute the skip value lazily
2087         if (skip == 0) {
2088           skip = 1;
2089           while (skip <= nsize_1 && needle[nsize_1 - skip] != lastNeedle) {
2090             ++skip;
2091           }
2092         }
2093         i += skip;
2094         break;
2095       }
2096       // Check if done searching
2097       if (++j == nsize) {
2098         // Yay
2099         return i - haystack;
2100       }
2101     }
2102   }
2103   return npos;
2104 }
2105
2106 template <typename E, class T, class A, class S>
2107 inline typename basic_fbstring<E, T, A, S>::iterator
2108 basic_fbstring<E, T, A, S>::insertImplDiscr(
2109     const_iterator i, size_type n, value_type c, std::true_type) {
2110   Invariant checker(*this);
2111
2112   FBSTRING_ASSERT(i >= cbegin() && i <= cend());
2113   const size_type pos = i - cbegin();
2114
2115   auto oldSize = size();
2116   store_.expandNoinit(n, /* expGrowth = */ true);
2117   auto b = begin();
2118   fbstring_detail::podMove(b + pos, b + oldSize, b + pos + n);
2119   fbstring_detail::podFill(b + pos, b + pos + n, c);
2120
2121   return b + pos;
2122 }
2123
2124 template <typename E, class T, class A, class S>
2125 template <class InputIter>
2126 inline typename basic_fbstring<E, T, A, S>::iterator
2127 basic_fbstring<E, T, A, S>::insertImplDiscr(
2128     const_iterator i, InputIter b, InputIter e, std::false_type) {
2129   return insertImpl(
2130       i, b, e, typename std::iterator_traits<InputIter>::iterator_category());
2131 }
2132
2133 template <typename E, class T, class A, class S>
2134 template <class FwdIterator>
2135 inline typename basic_fbstring<E, T, A, S>::iterator
2136 basic_fbstring<E, T, A, S>::insertImpl(
2137     const_iterator i,
2138     FwdIterator s1,
2139     FwdIterator s2,
2140     std::forward_iterator_tag) {
2141   Invariant checker(*this);
2142
2143   FBSTRING_ASSERT(i >= cbegin() && i <= cend());
2144   const size_type pos = i - cbegin();
2145   auto n = std::distance(s1, s2);
2146   FBSTRING_ASSERT(n >= 0);
2147
2148   auto oldSize = size();
2149   store_.expandNoinit(n, /* expGrowth = */ true);
2150   auto b = begin();
2151   fbstring_detail::podMove(b + pos, b + oldSize, b + pos + n);
2152   std::copy(s1, s2, b + pos);
2153
2154   return b + pos;
2155 }
2156
2157 template <typename E, class T, class A, class S>
2158 template <class InputIterator>
2159 inline typename basic_fbstring<E, T, A, S>::iterator
2160 basic_fbstring<E, T, A, S>::insertImpl(
2161     const_iterator i,
2162     InputIterator b,
2163     InputIterator e,
2164     std::input_iterator_tag) {
2165   const auto pos = i - cbegin();
2166   basic_fbstring temp(cbegin(), i);
2167   for (; b != e; ++b) {
2168     temp.push_back(*b);
2169   }
2170   temp.append(i, cend());
2171   swap(temp);
2172   return begin() + pos;
2173 }
2174
2175 template <typename E, class T, class A, class S>
2176 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::replaceImplDiscr(
2177     iterator i1,
2178     iterator i2,
2179     const value_type* s,
2180     size_type n,
2181     std::integral_constant<int, 2>) {
2182   FBSTRING_ASSERT(i1 <= i2);
2183   FBSTRING_ASSERT(begin() <= i1 && i1 <= end());
2184   FBSTRING_ASSERT(begin() <= i2 && i2 <= end());
2185   return replace(i1, i2, s, s + n);
2186 }
2187
2188 template <typename E, class T, class A, class S>
2189 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::replaceImplDiscr(
2190     iterator i1,
2191     iterator i2,
2192     size_type n2,
2193     value_type c,
2194     std::integral_constant<int, 1>) {
2195   const size_type n1 = i2 - i1;
2196   if (n1 > n2) {
2197     std::fill(i1, i1 + n2, c);
2198     erase(i1 + n2, i2);
2199   } else {
2200     std::fill(i1, i2, c);
2201     insert(i2, n2 - n1, c);
2202   }
2203   FBSTRING_ASSERT(isSane());
2204   return *this;
2205 }
2206
2207 template <typename E, class T, class A, class S>
2208 template <class InputIter>
2209 inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::replaceImplDiscr(
2210     iterator i1,
2211     iterator i2,
2212     InputIter b,
2213     InputIter e,
2214     std::integral_constant<int, 0>) {
2215   using Cat = typename std::iterator_traits<InputIter>::iterator_category;
2216   replaceImpl(i1, i2, b, e, Cat());
2217   return *this;
2218 }
2219
2220 template <typename E, class T, class A, class S>
2221 template <class FwdIterator>
2222 inline bool basic_fbstring<E, T, A, S>::replaceAliased(
2223     iterator i1, iterator i2, FwdIterator s1, FwdIterator s2, std::true_type) {
2224   std::less_equal<const value_type*> le{};
2225   const bool aliased = le(&*begin(), &*s1) && le(&*s1, &*end());
2226   if (!aliased) {
2227     return false;
2228   }
2229   // Aliased replace, copy to new string
2230   basic_fbstring temp;
2231   temp.reserve(size() - (i2 - i1) + std::distance(s1, s2));
2232   temp.append(begin(), i1).append(s1, s2).append(i2, end());
2233   swap(temp);
2234   return true;
2235 }
2236
2237 template <typename E, class T, class A, class S>
2238 template <class FwdIterator>
2239 inline void basic_fbstring<E, T, A, S>::replaceImpl(
2240     iterator i1,
2241     iterator i2,
2242     FwdIterator s1,
2243     FwdIterator s2,
2244     std::forward_iterator_tag) {
2245   Invariant checker(*this);
2246
2247   // Handle aliased replace
2248   using Sel = std::integral_constant<
2249       bool,
2250       std::is_same<FwdIterator, iterator>::value ||
2251           std::is_same<FwdIterator, const_iterator>::value>;
2252   if (replaceAliased(i1, i2, s1, s2, Sel())) {
2253     return;
2254   }
2255
2256   auto const n1 = i2 - i1;
2257   FBSTRING_ASSERT(n1 >= 0);
2258   auto const n2 = std::distance(s1, s2);
2259   FBSTRING_ASSERT(n2 >= 0);
2260
2261   if (n1 > n2) {
2262     // shrinks
2263     std::copy(s1, s2, i1);
2264     erase(i1 + n2, i2);
2265   } else {
2266     // grows
2267     s1 = fbstring_detail::copy_n(s1, n1, i1).first;
2268     insert(i2, s1, s2);
2269   }
2270   FBSTRING_ASSERT(isSane());
2271 }
2272
2273 template <typename E, class T, class A, class S>
2274 template <class InputIterator>
2275 inline void basic_fbstring<E, T, A, S>::replaceImpl(
2276     iterator i1,
2277     iterator i2,
2278     InputIterator b,
2279     InputIterator e,
2280     std::input_iterator_tag) {
2281   basic_fbstring temp(begin(), i1);
2282   temp.append(b, e).append(i2, end());
2283   swap(temp);
2284 }
2285
2286 template <typename E, class T, class A, class S>
2287 inline typename basic_fbstring<E, T, A, S>::size_type
2288 basic_fbstring<E, T, A, S>::rfind(
2289     const value_type* s, size_type pos, size_type n) const {
2290   if (n > length()) {
2291     return npos;
2292   }
2293   pos = std::min(pos, length() - n);
2294   if (n == 0) {
2295     return pos;
2296   }
2297
2298   const_iterator i(begin() + pos);
2299   for (;; --i) {
2300     if (traits_type::eq(*i, *s) && traits_type::compare(&*i, s, n) == 0) {
2301       return i - begin();
2302     }
2303     if (i == begin()) {
2304       break;
2305     }
2306   }
2307   return npos;
2308 }
2309
2310 template <typename E, class T, class A, class S>
2311 inline typename basic_fbstring<E, T, A, S>::size_type
2312 basic_fbstring<E, T, A, S>::find_first_of(
2313     const value_type* s, size_type pos, size_type n) const {
2314   if (pos > length() || n == 0) {
2315     return npos;
2316   }
2317   const_iterator i(begin() + pos), finish(end());
2318   for (; i != finish; ++i) {
2319     if (traits_type::find(s, n, *i) != 0) {
2320       return i - begin();
2321     }
2322   }
2323   return npos;
2324 }
2325
2326 template <typename E, class T, class A, class S>
2327 inline typename basic_fbstring<E, T, A, S>::size_type
2328 basic_fbstring<E, T, A, S>::find_last_of(
2329     const value_type* s, size_type pos, size_type n) const {
2330   if (!empty() && n > 0) {
2331     pos = std::min(pos, length() - 1);
2332     const_iterator i(begin() + pos);
2333     for (;; --i) {
2334       if (traits_type::find(s, n, *i) != 0) {
2335         return i - begin();
2336       }
2337       if (i == begin()) {
2338         break;
2339       }
2340     }
2341   }
2342   return npos;
2343 }
2344
2345 template <typename E, class T, class A, class S>
2346 inline typename basic_fbstring<E, T, A, S>::size_type
2347 basic_fbstring<E, T, A, S>::find_first_not_of(
2348     const value_type* s, size_type pos, size_type n) const {
2349   if (pos < length()) {
2350     const_iterator i(begin() + pos), finish(end());
2351     for (; i != finish; ++i) {
2352       if (traits_type::find(s, n, *i) == 0) {
2353         return i - begin();
2354       }
2355     }
2356   }
2357   return npos;
2358 }
2359
2360 template <typename E, class T, class A, class S>
2361 inline typename basic_fbstring<E, T, A, S>::size_type
2362 basic_fbstring<E, T, A, S>::find_last_not_of(
2363     const value_type* s, size_type pos, size_type n) const {
2364   if (!this->empty()) {
2365     pos = std::min(pos, size() - 1);
2366     const_iterator i(begin() + pos);
2367     for (;; --i) {
2368       if (traits_type::find(s, n, *i) == 0) {
2369         return i - begin();
2370       }
2371       if (i == begin()) {
2372         break;
2373       }
2374     }
2375   }
2376   return npos;
2377 }
2378
2379 // non-member functions
2380 // C++11 21.4.8.1/1
2381 template <typename E, class T, class A, class S>
2382 inline
2383 basic_fbstring<E, T, A, S> operator+(const basic_fbstring<E, T, A, S>& lhs,
2384                                      const basic_fbstring<E, T, A, S>& rhs) {
2385
2386   basic_fbstring<E, T, A, S> result;
2387   result.reserve(lhs.size() + rhs.size());
2388   result.append(lhs).append(rhs);
2389   return std::move(result);
2390 }
2391
2392 // C++11 21.4.8.1/2
2393 template <typename E, class T, class A, class S>
2394 inline
2395 basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs,
2396                                      const basic_fbstring<E, T, A, S>& rhs) {
2397   return std::move(lhs.append(rhs));
2398 }
2399
2400 // C++11 21.4.8.1/3
2401 template <typename E, class T, class A, class S>
2402 inline
2403 basic_fbstring<E, T, A, S> operator+(const basic_fbstring<E, T, A, S>& lhs,
2404                                      basic_fbstring<E, T, A, S>&& rhs) {
2405   if (rhs.capacity() >= lhs.size() + rhs.size()) {
2406     // Good, at least we don't need to reallocate
2407     return std::move(rhs.insert(0, lhs));
2408   }
2409   // Meh, no go. Forward to operator+(const&, const&).
2410   auto const& rhsC = rhs;
2411   return lhs + rhsC;
2412 }
2413
2414 // C++11 21.4.8.1/4
2415 template <typename E, class T, class A, class S>
2416 inline
2417 basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs,
2418                                      basic_fbstring<E, T, A, S>&& rhs) {
2419   return std::move(lhs.append(rhs));
2420 }
2421
2422 // C++11 21.4.8.1/5
2423 template <typename E, class T, class A, class S>
2424 inline
2425 basic_fbstring<E, T, A, S> operator+(
2426   const E* lhs,
2427   const basic_fbstring<E, T, A, S>& rhs) {
2428   //
2429   basic_fbstring<E, T, A, S> result;
2430   const auto len = basic_fbstring<E, T, A, S>::traits_type::length(lhs);
2431   result.reserve(len + rhs.size());
2432   result.append(lhs, len).append(rhs);
2433   return result;
2434 }
2435
2436 // C++11 21.4.8.1/6
2437 template <typename E, class T, class A, class S>
2438 inline
2439 basic_fbstring<E, T, A, S> operator+(
2440   const E* lhs,
2441   basic_fbstring<E, T, A, S>&& rhs) {
2442   //
2443   const auto len = basic_fbstring<E, T, A, S>::traits_type::length(lhs);
2444   if (rhs.capacity() >= len + rhs.size()) {
2445     // Good, at least we don't need to reallocate
2446     rhs.insert(rhs.begin(), lhs, lhs + len);
2447     return rhs;
2448   }
2449   // Meh, no go. Do it by hand since we have len already.
2450   basic_fbstring<E, T, A, S> result;
2451   result.reserve(len + rhs.size());
2452   result.append(lhs, len).append(rhs);
2453   return result;
2454 }
2455
2456 // C++11 21.4.8.1/7
2457 template <typename E, class T, class A, class S>
2458 inline
2459 basic_fbstring<E, T, A, S> operator+(
2460   E lhs,
2461   const basic_fbstring<E, T, A, S>& rhs) {
2462
2463   basic_fbstring<E, T, A, S> result;
2464   result.reserve(1 + rhs.size());
2465   result.push_back(lhs);
2466   result.append(rhs);
2467   return result;
2468 }
2469
2470 // C++11 21.4.8.1/8
2471 template <typename E, class T, class A, class S>
2472 inline
2473 basic_fbstring<E, T, A, S> operator+(
2474   E lhs,
2475   basic_fbstring<E, T, A, S>&& rhs) {
2476   //
2477   if (rhs.capacity() > rhs.size()) {
2478     // Good, at least we don't need to reallocate
2479     rhs.insert(rhs.begin(), lhs);
2480     return rhs;
2481   }
2482   // Meh, no go. Forward to operator+(E, const&).
2483   auto const& rhsC = rhs;
2484   return lhs + rhsC;
2485 }
2486
2487 // C++11 21.4.8.1/9
2488 template <typename E, class T, class A, class S>
2489 inline
2490 basic_fbstring<E, T, A, S> operator+(
2491   const basic_fbstring<E, T, A, S>& lhs,
2492   const E* rhs) {
2493
2494   typedef typename basic_fbstring<E, T, A, S>::size_type size_type;
2495   typedef typename basic_fbstring<E, T, A, S>::traits_type traits_type;
2496
2497   basic_fbstring<E, T, A, S> result;
2498   const size_type len = traits_type::length(rhs);
2499   result.reserve(lhs.size() + len);
2500   result.append(lhs).append(rhs, len);
2501   return result;
2502 }
2503
2504 // C++11 21.4.8.1/10
2505 template <typename E, class T, class A, class S>
2506 inline
2507 basic_fbstring<E, T, A, S> operator+(
2508   basic_fbstring<E, T, A, S>&& lhs,
2509   const E* rhs) {
2510   //
2511   return std::move(lhs += rhs);
2512 }
2513
2514 // C++11 21.4.8.1/11
2515 template <typename E, class T, class A, class S>
2516 inline
2517 basic_fbstring<E, T, A, S> operator+(
2518   const basic_fbstring<E, T, A, S>& lhs,
2519   E rhs) {
2520
2521   basic_fbstring<E, T, A, S> result;
2522   result.reserve(lhs.size() + 1);
2523   result.append(lhs);
2524   result.push_back(rhs);
2525   return result;
2526 }
2527
2528 // C++11 21.4.8.1/12
2529 template <typename E, class T, class A, class S>
2530 inline
2531 basic_fbstring<E, T, A, S> operator+(
2532   basic_fbstring<E, T, A, S>&& lhs,
2533   E rhs) {
2534   //
2535   return std::move(lhs += rhs);
2536 }
2537
2538 template <typename E, class T, class A, class S>
2539 inline
2540 bool operator==(const basic_fbstring<E, T, A, S>& lhs,
2541                 const basic_fbstring<E, T, A, S>& rhs) {
2542   return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; }
2543
2544 template <typename E, class T, class A, class S>
2545 inline
2546 bool operator==(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2547                 const basic_fbstring<E, T, A, S>& rhs) {
2548   return rhs == lhs; }
2549
2550 template <typename E, class T, class A, class S>
2551 inline
2552 bool operator==(const basic_fbstring<E, T, A, S>& lhs,
2553                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2554   return lhs.compare(rhs) == 0; }
2555
2556 template <typename E, class T, class A, class S>
2557 inline
2558 bool operator!=(const basic_fbstring<E, T, A, S>& lhs,
2559                 const basic_fbstring<E, T, A, S>& rhs) {
2560   return !(lhs == rhs); }
2561
2562 template <typename E, class T, class A, class S>
2563 inline
2564 bool operator!=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2565                 const basic_fbstring<E, T, A, S>& rhs) {
2566   return !(lhs == rhs); }
2567
2568 template <typename E, class T, class A, class S>
2569 inline
2570 bool operator!=(const basic_fbstring<E, T, A, S>& lhs,
2571                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2572   return !(lhs == rhs); }
2573
2574 template <typename E, class T, class A, class S>
2575 inline
2576 bool operator<(const basic_fbstring<E, T, A, S>& lhs,
2577                const basic_fbstring<E, T, A, S>& rhs) {
2578   return lhs.compare(rhs) < 0; }
2579
2580 template <typename E, class T, class A, class S>
2581 inline
2582 bool operator<(const basic_fbstring<E, T, A, S>& lhs,
2583                const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2584   return lhs.compare(rhs) < 0; }
2585
2586 template <typename E, class T, class A, class S>
2587 inline
2588 bool operator<(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2589                const basic_fbstring<E, T, A, S>& rhs) {
2590   return rhs.compare(lhs) > 0; }
2591
2592 template <typename E, class T, class A, class S>
2593 inline
2594 bool operator>(const basic_fbstring<E, T, A, S>& lhs,
2595                const basic_fbstring<E, T, A, S>& rhs) {
2596   return rhs < lhs; }
2597
2598 template <typename E, class T, class A, class S>
2599 inline
2600 bool operator>(const basic_fbstring<E, T, A, S>& lhs,
2601                const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2602   return rhs < lhs; }
2603
2604 template <typename E, class T, class A, class S>
2605 inline
2606 bool operator>(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2607                const basic_fbstring<E, T, A, S>& rhs) {
2608   return rhs < lhs; }
2609
2610 template <typename E, class T, class A, class S>
2611 inline
2612 bool operator<=(const basic_fbstring<E, T, A, S>& lhs,
2613                 const basic_fbstring<E, T, A, S>& rhs) {
2614   return !(rhs < lhs); }
2615
2616 template <typename E, class T, class A, class S>
2617 inline
2618 bool operator<=(const basic_fbstring<E, T, A, S>& lhs,
2619                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2620   return !(rhs < lhs); }
2621
2622 template <typename E, class T, class A, class S>
2623 inline
2624 bool operator<=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2625                 const basic_fbstring<E, T, A, S>& rhs) {
2626   return !(rhs < lhs); }
2627
2628 template <typename E, class T, class A, class S>
2629 inline
2630 bool operator>=(const basic_fbstring<E, T, A, S>& lhs,
2631                 const basic_fbstring<E, T, A, S>& rhs) {
2632   return !(lhs < rhs); }
2633
2634 template <typename E, class T, class A, class S>
2635 inline
2636 bool operator>=(const basic_fbstring<E, T, A, S>& lhs,
2637                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2638   return !(lhs < rhs); }
2639
2640 template <typename E, class T, class A, class S>
2641 inline
2642 bool operator>=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2643                 const basic_fbstring<E, T, A, S>& rhs) {
2644  return !(lhs < rhs);
2645 }
2646
2647 // C++11 21.4.8.8
2648 template <typename E, class T, class A, class S>
2649 void swap(basic_fbstring<E, T, A, S>& lhs, basic_fbstring<E, T, A, S>& rhs) {
2650   lhs.swap(rhs);
2651 }
2652
2653 // TODO: make this faster.
2654 template <typename E, class T, class A, class S>
2655 inline
2656 std::basic_istream<
2657   typename basic_fbstring<E, T, A, S>::value_type,
2658   typename basic_fbstring<E, T, A, S>::traits_type>&
2659   operator>>(
2660     std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
2661     typename basic_fbstring<E, T, A, S>::traits_type>& is,
2662     basic_fbstring<E, T, A, S>& str) {
2663   typedef std::basic_istream<
2664       typename basic_fbstring<E, T, A, S>::value_type,
2665       typename basic_fbstring<E, T, A, S>::traits_type>
2666       _istream_type;
2667   typename _istream_type::sentry sentry(is);
2668   size_t extracted = 0;
2669   auto err = _istream_type::goodbit;
2670   if (sentry) {
2671     auto n = is.width();
2672     if (n <= 0) {
2673       n = str.max_size();
2674     }
2675     str.erase();
2676     for (auto got = is.rdbuf()->sgetc(); extracted != size_t(n); ++extracted) {
2677       if (got == T::eof()) {
2678         err |= _istream_type::eofbit;
2679         is.width(0);
2680         break;
2681       }
2682       if (isspace(got)) {
2683         break;
2684       }
2685       str.push_back(got);
2686       got = is.rdbuf()->snextc();
2687     }
2688   }
2689   if (!extracted) {
2690     err |= _istream_type::failbit;
2691   }
2692   if (err) {
2693     is.setstate(err);
2694   }
2695   return is;
2696 }
2697
2698 template <typename E, class T, class A, class S>
2699 inline
2700 std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type,
2701                    typename basic_fbstring<E, T, A, S>::traits_type>&
2702 operator<<(
2703   std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type,
2704   typename basic_fbstring<E, T, A, S>::traits_type>& os,
2705     const basic_fbstring<E, T, A, S>& str) {
2706 #if _LIBCPP_VERSION
2707   typedef std::basic_ostream<
2708       typename basic_fbstring<E, T, A, S>::value_type,
2709       typename basic_fbstring<E, T, A, S>::traits_type>
2710       _ostream_type;
2711   typename _ostream_type::sentry _s(os);
2712   if (_s) {
2713     typedef std::ostreambuf_iterator<
2714       typename basic_fbstring<E, T, A, S>::value_type,
2715       typename basic_fbstring<E, T, A, S>::traits_type> _Ip;
2716     size_t __len = str.size();
2717     bool __left =
2718         (os.flags() & _ostream_type::adjustfield) == _ostream_type::left;
2719     if (__pad_and_output(_Ip(os),
2720                          str.data(),
2721                          __left ? str.data() + __len : str.data(),
2722                          str.data() + __len,
2723                          os,
2724                          os.fill()).failed()) {
2725       os.setstate(_ostream_type::badbit | _ostream_type::failbit);
2726     }
2727   }
2728 #elif defined(_MSC_VER)
2729   typedef decltype(os.precision()) streamsize;
2730   // MSVC doesn't define __ostream_insert
2731   os.write(str.data(), static_cast<streamsize>(str.size()));
2732 #else
2733   std::__ostream_insert(os, str.data(), str.size());
2734 #endif
2735   return os;
2736 }
2737
2738 template <typename E1, class T, class A, class S>
2739 constexpr typename basic_fbstring<E1, T, A, S>::size_type
2740     basic_fbstring<E1, T, A, S>::npos;
2741
2742 #ifndef _LIBSTDCXX_FBSTRING
2743 // basic_string compatibility routines
2744
2745 template <typename E, class T, class A, class S, class A2>
2746 inline bool operator==(
2747     const basic_fbstring<E, T, A, S>& lhs,
2748     const std::basic_string<E, T, A2>& rhs) {
2749   return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) == 0;
2750 }
2751
2752 template <typename E, class T, class A, class S, class A2>
2753 inline bool operator==(
2754     const std::basic_string<E, T, A2>& lhs,
2755     const basic_fbstring<E, T, A, S>& rhs) {
2756   return rhs == lhs;
2757 }
2758
2759 template <typename E, class T, class A, class S, class A2>
2760 inline bool operator!=(
2761     const basic_fbstring<E, T, A, S>& lhs,
2762     const std::basic_string<E, T, A2>& rhs) {
2763   return !(lhs == rhs);
2764 }
2765
2766 template <typename E, class T, class A, class S, class A2>
2767 inline bool operator!=(
2768     const std::basic_string<E, T, A2>& lhs,
2769     const basic_fbstring<E, T, A, S>& rhs) {
2770   return !(lhs == rhs);
2771 }
2772
2773 template <typename E, class T, class A, class S, class A2>
2774 inline bool operator<(
2775     const basic_fbstring<E, T, A, S>& lhs,
2776     const std::basic_string<E, T, A2>& rhs) {
2777   return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) < 0;
2778 }
2779
2780 template <typename E, class T, class A, class S, class A2>
2781 inline bool operator>(
2782     const basic_fbstring<E, T, A, S>& lhs,
2783     const std::basic_string<E, T, A2>& rhs) {
2784   return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) > 0;
2785 }
2786
2787 template <typename E, class T, class A, class S, class A2>
2788 inline bool operator<(
2789     const std::basic_string<E, T, A2>& lhs,
2790     const basic_fbstring<E, T, A, S>& rhs) {
2791   return rhs > lhs;
2792 }
2793
2794 template <typename E, class T, class A, class S, class A2>
2795 inline bool operator>(
2796     const std::basic_string<E, T, A2>& lhs,
2797     const basic_fbstring<E, T, A, S>& rhs) {
2798   return rhs < lhs;
2799 }
2800
2801 template <typename E, class T, class A, class S, class A2>
2802 inline bool operator<=(
2803     const basic_fbstring<E, T, A, S>& lhs,
2804     const std::basic_string<E, T, A2>& rhs) {
2805   return !(lhs > rhs);
2806 }
2807
2808 template <typename E, class T, class A, class S, class A2>
2809 inline bool operator>=(
2810     const basic_fbstring<E, T, A, S>& lhs,
2811     const std::basic_string<E, T, A2>& rhs) {
2812   return !(lhs < rhs);
2813 }
2814
2815 template <typename E, class T, class A, class S, class A2>
2816 inline bool operator<=(
2817     const std::basic_string<E, T, A2>& lhs,
2818     const basic_fbstring<E, T, A, S>& rhs) {
2819   return !(lhs > rhs);
2820 }
2821
2822 template <typename E, class T, class A, class S, class A2>
2823 inline bool operator>=(
2824     const std::basic_string<E, T, A2>& lhs,
2825     const basic_fbstring<E, T, A, S>& rhs) {
2826   return !(lhs < rhs);
2827 }
2828
2829 #if !defined(_LIBSTDCXX_FBSTRING)
2830 typedef basic_fbstring<char> fbstring;
2831 #endif
2832
2833 // fbstring is relocatable
2834 template <class T, class R, class A, class S>
2835 FOLLY_ASSUME_RELOCATABLE(basic_fbstring<T, R, A, S>);
2836
2837 #else
2838 _GLIBCXX_END_NAMESPACE_VERSION
2839 #endif
2840
2841 } // namespace folly
2842
2843 #ifndef _LIBSTDCXX_FBSTRING
2844
2845 // Hash functions to make fbstring usable with e.g. hash_map
2846 //
2847 // Handle interaction with different C++ standard libraries, which
2848 // expect these types to be in different namespaces.
2849
2850 #define FOLLY_FBSTRING_HASH1(T)                                        \
2851   template <>                                                          \
2852   struct hash< ::folly::basic_fbstring<T>> {                           \
2853     size_t operator()(const ::folly::basic_fbstring<T>& s) const {     \
2854       return ::folly::hash::fnv32_buf(s.data(), s.size() * sizeof(T)); \
2855     }                                                                  \
2856   };
2857
2858 // The C++11 standard says that these four are defined
2859 #define FOLLY_FBSTRING_HASH \
2860   FOLLY_FBSTRING_HASH1(char) \
2861   FOLLY_FBSTRING_HASH1(char16_t) \
2862   FOLLY_FBSTRING_HASH1(char32_t) \
2863   FOLLY_FBSTRING_HASH1(wchar_t)
2864
2865 namespace std {
2866
2867 FOLLY_FBSTRING_HASH
2868
2869 }  // namespace std
2870
2871 #undef FOLLY_FBSTRING_HASH
2872 #undef FOLLY_FBSTRING_HASH1
2873
2874 #endif // _LIBSTDCXX_FBSTRING
2875
2876 FOLLY_POP_WARNING
2877
2878 #undef FBSTRING_DISABLE_SSO
2879 #undef FBSTRING_SANITIZE_ADDRESS
2880 #undef throw
2881 #undef FBSTRING_LIKELY
2882 #undef FBSTRING_UNLIKELY
2883 #undef FBSTRING_ASSERT