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