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