Migrating folly to gcc-4.7.1
[folly.git] / folly / FBString.h
1 /*
2  * Copyright 2013 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 #ifndef FOLLY_BASE_FBSTRING_H_
21 #define FOLLY_BASE_FBSTRING_H_
22
23 /**
24    fbstring's behavior can be configured via two macro definitions, as
25    follows. Normally, fbstring does not write a '\0' at the end of
26    each string whenever it changes the underlying characters. Instead,
27    it lazily writes the '\0' whenever either c_str() or data()
28    called.
29
30    This is standard-compliant behavior and may save costs in some
31    circumstances. However, it may be surprising to some client code
32    because c_str() and data() are const member functions (fbstring
33    uses the "mutable" storage class for its own state).
34
35    In order to appease client code that expects fbstring to be
36    zero-terminated at all times, if the preprocessor symbol
37    FBSTRING_CONSERVATIVE is defined, fbstring does exactly that,
38    i.e. it goes the extra mile to guarantee a '\0' is always planted
39    at the end of its data.
40
41    On the contrary, if the desire is to debug faulty client code that
42    unduly assumes the '\0' is present, fbstring plants a '^' (i.e.,
43    emphatically NOT a zero) at the end of each string if
44    FBSTRING_PERVERSE is defined. (Calling c_str() or data() still
45    writes the '\0', of course.)
46
47    The preprocessor symbols FBSTRING_PERVERSE and
48    FBSTRING_CONSERVATIVE cannot be defined simultaneously. This is
49    enforced during preprocessing.
50 */
51
52 //#define FBSTRING_PERVERSE
53 //#define FBSTRING_CONSERVATIVE
54
55 #ifdef FBSTRING_PERVERSE
56 #ifdef FBSTRING_CONSERVATIVE
57 #error Cannot define both FBSTRING_PERVERSE and FBSTRING_CONSERVATIVE.
58 #endif
59 #endif
60
61 // This file appears in two locations: inside fbcode and in the
62 // libstdc++ source code (when embedding fbstring as std::string).
63 // To aid in this schizophrenic use, two macros are defined in
64 // c++config.h:
65 //   _LIBSTDCXX_FBSTRING - Set inside libstdc++.  This is useful to
66 //      gate use inside fbcode v. libstdc++
67 #include <bits/c++config.h>
68
69 #ifdef _LIBSTDCXX_FBSTRING
70
71 #pragma GCC system_header
72
73 // Handle the cases where the fbcode version (folly/Malloc.h) is included
74 // either before or after this inclusion.
75 #ifdef FOLLY_MALLOC_H_
76 #undef FOLLY_MALLOC_H_
77 #include "basic_fbstring_malloc.h"
78 #else
79 #include "basic_fbstring_malloc.h"
80 #undef FOLLY_MALLOC_H_
81 #endif
82
83 #else // !_LIBSTDCXX_FBSTRING
84
85 #include <string>
86 #include <cstring>
87 #include <cassert>
88
89 #include "folly/Traits.h"
90 #include "folly/Malloc.h"
91 #include "folly/Hash.h"
92
93 #endif
94
95 // We defined these here rather than including Likely.h to avoid
96 // redefinition errors when fbstring is imported into libstdc++.
97 #define FBSTRING_LIKELY(x)   (__builtin_expect((x), 1))
98 #define FBSTRING_UNLIKELY(x) (__builtin_expect((x), 0))
99
100 #include <atomic>
101 #include <limits>
102 #include <type_traits>
103
104 // Ignore shadowing warnings within this file, so includers can use -Wshadow.
105 #pragma GCC diagnostic push
106 #pragma GCC diagnostic ignored "-Wshadow"
107
108 // FBString cannot use throw when replacing std::string, though it may still
109 // use std::__throw_*
110 #define throw
111
112 #ifdef _LIBSTDCXX_FBSTRING
113 namespace std _GLIBCXX_VISIBILITY(default) {
114 _GLIBCXX_BEGIN_NAMESPACE_VERSION
115 #else
116 namespace folly {
117 #endif
118
119 // Different versions of gcc/clang support different versions of
120 // the address sanitizer attribute.  Unfortunately, this attribute
121 // has issues when inlining is used, so disable that as well.
122 #if defined(__clang__)
123 # if __has_feature(address_sanitizer)
124 #  if __has_attribute(__no_address_safety_analysis__)
125 #   define FBSTRING_DISABLE_ADDRESS_SANITIZER \
126       __attribute__((__no_address_safety_analysis__, __noinline__))
127 #  elif __has_attribute(__no_sanitize_address__)
128 #   define FBSTRING_DISABLE_ADDRESS_SANITIZER \
129       __attribute__((__no_sanitize_address__, __noinline__))
130 #  endif
131 # endif
132 #elif defined (__GNUC__) && \
133       (__GNUC__ == 4) && \
134       (__GNUC_MINOR__ >= 8) && \
135       __SANITIZE_ADDRESS__
136 # define FBSTRING_DISABLE_ADDRESS_SANITIZER \
137     __attribute__((__no_address_safety_analysis__, __noinline__))
138 #endif
139 #ifndef FBSTRING_DISABLE_ADDRESS_SANITIZER
140 # define FBSTRING_DISABLE_ADDRESS_SANITIZER
141 #endif
142
143 namespace fbstring_detail {
144
145 template <class InIt, class OutIt>
146 inline
147 OutIt copy_n(InIt b,
148              typename std::iterator_traits<InIt>::difference_type n,
149              OutIt d) {
150   for (; n != 0; --n, ++b, ++d) {
151     assert((const void*)&*d != &*b);
152     *d = *b;
153   }
154   return d;
155 }
156
157 template <class Pod, class T>
158 inline void pod_fill(Pod* b, Pod* e, T c) {
159   assert(b && e && b <= e);
160   /*static*/ if (sizeof(T) == 1) {
161     memset(b, c, e - b);
162   } else {
163     auto const ee = b + ((e - b) & ~7u);
164     for (; b != ee; b += 8) {
165       b[0] = c;
166       b[1] = c;
167       b[2] = c;
168       b[3] = c;
169       b[4] = c;
170       b[5] = c;
171       b[6] = c;
172       b[7] = c;
173     }
174     // Leftovers
175     for (; b != e; ++b) {
176       *b = c;
177     }
178   }
179 }
180
181 /*
182  * Lightly structured memcpy, simplifies copying PODs and introduces
183  * some asserts. Unfortunately using this function may cause
184  * measurable overhead (presumably because it adjusts from a begin/end
185  * convention to a pointer/size convention, so it does some extra
186  * arithmetic even though the caller might have done the inverse
187  * adaptation outside).
188  */
189 template <class Pod>
190 inline void pod_copy(const Pod* b, const Pod* e, Pod* d) {
191   assert(e >= b);
192   assert(d >= e || d + (e - b) <= b);
193   memcpy(d, b, (e - b) * sizeof(Pod));
194 }
195
196 /*
197  * Lightly structured memmove, simplifies copying PODs and introduces
198  * some asserts
199  */
200 template <class Pod>
201 inline void pod_move(const Pod* b, const Pod* e, Pod* d) {
202   assert(e >= b);
203   memmove(d, b, (e - b) * sizeof(*b));
204 }
205
206 } // namespace fbstring_detail
207
208 /**
209  * Defines a special acquisition method for constructing fbstring
210  * objects. AcquireMallocatedString means that the user passes a
211  * pointer to a malloc-allocated string that the fbstring object will
212  * take into custody.
213  */
214 enum class AcquireMallocatedString {};
215
216 /*
217  * fbstring_core_model is a mock-up type that defines all required
218  * signatures of a fbstring core. The fbstring class itself uses such
219  * a core object to implement all of the numerous member functions
220  * required by the standard.
221  *
222  * If you want to define a new core, copy the definition below and
223  * implement the primitives. Then plug the core into basic_fbstring as
224  * a template argument.
225
226 template <class Char>
227 class fbstring_core_model {
228 public:
229   fbstring_core_model();
230   fbstring_core_model(const fbstring_core_model &);
231   ~fbstring_core_model();
232   // Returns a pointer to string's buffer (currently only contiguous
233   // strings are supported). The pointer is guaranteed to be valid
234   // until the next call to a non-const member function.
235   const Char * data() const;
236   // Much like data(), except the string is prepared to support
237   // character-level changes. This call is a signal for
238   // e.g. reference-counted implementation to fork the data. The
239   // pointer is guaranteed to be valid until the next call to a
240   // non-const member function.
241   Char * mutable_data();
242   // Returns a pointer to string's buffer and guarantees that a
243   // readable '\0' lies right after the buffer. The pointer is
244   // guaranteed to be valid until the next call to a non-const member
245   // function.
246   const Char * c_str() const;
247   // Shrinks the string by delta characters. Asserts that delta <=
248   // size().
249   void shrink(size_t delta);
250   // Expands the string by delta characters (i.e. after this call
251   // size() will report the old size() plus delta) but without
252   // initializing the expanded region. Returns a pointer to the memory
253   // to be initialized (the beginning of the expanded portion). The
254   // caller is expected to fill the expanded area appropriately.
255   Char* expand_noinit(size_t delta);
256   // Expands the string by one character and sets the last character
257   // to c.
258   void push_back(Char c);
259   // Returns the string's size.
260   size_t size() const;
261   // Returns the string's capacity, i.e. maximum size that the string
262   // can grow to without reallocation. Note that for reference counted
263   // strings that's technically a lie - even assigning characters
264   // within the existing size would cause a reallocation.
265   size_t capacity() const;
266   // Returns true if the data underlying the string is actually shared
267   // across multiple strings (in a refcounted fashion).
268   bool isShared() const;
269   // Makes sure that at least minCapacity characters are available for
270   // the string without reallocation. For reference-counted strings,
271   // it should fork the data even if minCapacity < size().
272   void reserve(size_t minCapacity);
273 private:
274   // Do not implement
275   fbstring_core_model& operator=(const fbstring_core_model &);
276 };
277 */
278
279 /**
280  * gcc-4.7 throws what appears to be some false positive uninitialized
281  * warnings for the members of the MediumLarge struct.  So, mute them here.
282  */
283 #if defined(__GNUC__) && !defined(__clang__)
284 # pragma GCC diagnostic push
285 # pragma GCC diagnostic ignored "-Wuninitialized"
286 #endif
287
288 /**
289  * This is the core of the string. The code should work on 32- and
290  * 64-bit architectures and with any Char size. Porting to big endian
291  * architectures would require some changes.
292  *
293  * The storage is selected as follows (assuming we store one-byte
294  * characters on a 64-bit machine): (a) "small" strings between 0 and
295  * 23 chars are stored in-situ without allocation (the rightmost byte
296  * stores the size); (b) "medium" strings from 24 through 254 chars
297  * are stored in malloc-allocated memory that is copied eagerly; (c)
298  * "large" strings of 255 chars and above are stored in a similar
299  * structure as medium arrays, except that the string is
300  * reference-counted and copied lazily. the reference count is
301  * allocated right before the character array.
302  *
303  * The discriminator between these three strategies sits in the two
304  * most significant bits of the rightmost char of the storage. If
305  * neither is set, then the string is small (and its length sits in
306  * the lower-order bits of that rightmost character). If the MSb is
307  * set, the string is medium width. If the second MSb is set, then the
308  * string is large.
309  */
310 template <class Char> class fbstring_core {
311 public:
312   fbstring_core() noexcept {
313     // Only initialize the tag, will set the MSBs (i.e. the small
314     // string size) to zero too
315     ml_.capacity_ = maxSmallSize << (8 * (sizeof(size_t) - sizeof(Char)));
316     // or: setSmallSize(0);
317     writeTerminator();
318     assert(category() == isSmall && size() == 0);
319   }
320
321   fbstring_core(const fbstring_core & rhs) {
322     assert(&rhs != this);
323     // Simplest case first: small strings are bitblitted
324     if (rhs.category() == isSmall) {
325       assert(offsetof(MediumLarge, data_) == 0);
326       assert(offsetof(MediumLarge, size_) == sizeof(ml_.data_));
327       assert(offsetof(MediumLarge, capacity_) == 2 * sizeof(ml_.data_));
328       const size_t size = rhs.smallSize();
329       if (size == 0) {
330         ml_.capacity_ = rhs.ml_.capacity_;
331         writeTerminator();
332       } else {
333         // Just write the whole thing, don't look at details. In
334         // particular we need to copy capacity anyway because we want
335         // to set the size (don't forget that the last character,
336         // which stores a short string's length, is shared with the
337         // ml_.capacity field).
338         ml_ = rhs.ml_;
339       }
340       assert(category() == isSmall && this->size() == rhs.size());
341     } else if (rhs.category() == isLarge) {
342       // Large strings are just refcounted
343       ml_ = rhs.ml_;
344       RefCounted::incrementRefs(ml_.data_);
345       assert(category() == isLarge && size() == rhs.size());
346     } else {
347       // Medium strings are copied eagerly. Don't forget to allocate
348       // one extra Char for the null terminator.
349       auto const allocSize =
350            goodMallocSize((1 + rhs.ml_.size_) * sizeof(Char));
351       ml_.data_ = static_cast<Char*>(checkedMalloc(allocSize));
352       fbstring_detail::pod_copy(rhs.ml_.data_,
353                                 // 1 for terminator
354                                 rhs.ml_.data_ + rhs.ml_.size_ + 1,
355                                 ml_.data_);
356       // No need for writeTerminator() here, we copied one extra
357       // element just above.
358       ml_.size_ = rhs.ml_.size_;
359       ml_.capacity_ = (allocSize / sizeof(Char) - 1) | isMedium;
360       assert(category() == isMedium);
361     }
362     assert(size() == rhs.size());
363     assert(memcmp(data(), rhs.data(), size() * sizeof(Char)) == 0);
364   }
365
366   fbstring_core(fbstring_core&& goner) noexcept {
367     if (goner.category() == isSmall) {
368       // Just copy, leave the goner in peace
369       new(this) fbstring_core(goner.small_, goner.smallSize());
370     } else {
371       // Take goner's guts
372       ml_ = goner.ml_;
373       // Clean goner's carcass
374       goner.setSmallSize(0);
375     }
376   }
377
378   // NOTE(agallagher): The word-aligned copy path copies bytes which are
379   // outside the range of the string, and makes address sanitizer unhappy,
380   // so just disable it on this function.
381   fbstring_core(const Char *const data, const size_t size)
382       FBSTRING_DISABLE_ADDRESS_SANITIZER {
383     // Simplest case first: small strings are bitblitted
384     if (size <= maxSmallSize) {
385       // Layout is: Char* data_, size_t size_, size_t capacity_
386       /*static_*/assert(sizeof(*this) == sizeof(Char*) + 2 * sizeof(size_t));
387       /*static_*/assert(sizeof(Char*) == sizeof(size_t));
388       // sizeof(size_t) must be a power of 2
389       /*static_*/assert((sizeof(size_t) & (sizeof(size_t) - 1)) == 0);
390
391       // If data is aligned, use fast word-wise copying. Otherwise,
392       // use conservative memcpy.
393       if (reinterpret_cast<size_t>(data) & (sizeof(size_t) - 1)) {
394         fbstring_detail::pod_copy(data, data + size, small_);
395       } else {
396         // Copy one word (64 bits) at a time
397         const size_t byteSize = size * sizeof(Char);
398         if (byteSize > 2 * sizeof(size_t)) {
399           // Copy three words
400           ml_.capacity_ = reinterpret_cast<const size_t*>(data)[2];
401           copyTwo:
402           ml_.size_ = reinterpret_cast<const size_t*>(data)[1];
403           copyOne:
404           ml_.data_ = *reinterpret_cast<Char**>(const_cast<Char*>(data));
405         } else if (byteSize > sizeof(size_t)) {
406           // Copy two words
407           goto copyTwo;
408         } else if (size > 0) {
409           // Copy one word
410           goto copyOne;
411         }
412       }
413       setSmallSize(size);
414     } else if (size <= maxMediumSize) {
415       // Medium strings are allocated normally. Don't forget to
416       // allocate one extra Char for the terminating null.
417       auto const allocSize = goodMallocSize((1 + size) * sizeof(Char));
418       ml_.data_ = static_cast<Char*>(checkedMalloc(allocSize));
419       fbstring_detail::pod_copy(data, data + size, ml_.data_);
420       ml_.size_ = size;
421       ml_.capacity_ = (allocSize / sizeof(Char) - 1) | isMedium;
422     } else {
423       // Large strings are allocated differently
424       size_t effectiveCapacity = size;
425       auto const newRC = RefCounted::create(data, & effectiveCapacity);
426       ml_.data_ = newRC->data_;
427       ml_.size_ = size;
428       ml_.capacity_ = effectiveCapacity | isLarge;
429     }
430     writeTerminator();
431     assert(this->size() == size);
432     assert(memcmp(this->data(), data, size * sizeof(Char)) == 0);
433   }
434
435   ~fbstring_core() noexcept {
436     auto const c = category();
437     if (c == isSmall) {
438       return;
439     }
440     if (c == isMedium) {
441       free(ml_.data_);
442       return;
443     }
444     RefCounted::decrementRefs(ml_.data_);
445   }
446
447   // Snatches a previously mallocated string. The parameter "size"
448   // is the size of the string, and the parameter "capacity" is the size
449   // of the mallocated block.  The string must be \0-terminated, so
450   // data[size] == '\0' and capacity >= size + 1.
451   //
452   // So if you want a 2-character string, pass malloc(3) as "data", pass 2 as
453   // "size", and pass 3 as "capacity".
454   fbstring_core(Char *const data, const size_t size,
455                 const size_t capacity,
456                 AcquireMallocatedString) {
457     if (size > 0) {
458       assert(capacity > size);
459       assert(data[size] == '\0');
460       // Use the medium string storage
461       ml_.data_ = data;
462       ml_.size_ = size;
463       ml_.capacity_ = capacity | isMedium;
464     } else {
465       // No need for the memory
466       free(data);
467       setSmallSize(0);
468     }
469   }
470
471   // swap below doesn't test whether &rhs == this (and instead
472   // potentially does extra work) on the premise that the rarity of
473   // that situation actually makes the check more expensive than is
474   // worth.
475   void swap(fbstring_core & rhs) {
476     auto const t = ml_;
477     ml_ = rhs.ml_;
478     rhs.ml_ = t;
479   }
480
481   // In C++11 data() and c_str() are 100% equivalent.
482   const Char * data() const {
483     return c_str();
484   }
485
486   Char * mutable_data() {
487     auto const c = category();
488     if (c == isSmall) {
489       return small_;
490     }
491     assert(c == isMedium || c == isLarge);
492     if (c == isLarge && RefCounted::refs(ml_.data_) > 1) {
493       // Ensure unique.
494       size_t effectiveCapacity = ml_.capacity();
495       auto const newRC = RefCounted::create(& effectiveCapacity);
496       // If this fails, someone placed the wrong capacity in an
497       // fbstring.
498       assert(effectiveCapacity >= ml_.capacity());
499       fbstring_detail::pod_copy(ml_.data_, ml_.data_ + ml_.size_ + 1,
500                                 newRC->data_);
501       RefCounted::decrementRefs(ml_.data_);
502       ml_.data_ = newRC->data_;
503       // No need to call writeTerminator(), we have + 1 above.
504     }
505     return ml_.data_;
506   }
507
508   const Char * c_str() const {
509     auto const c = category();
510 #ifdef FBSTRING_PERVERSE
511     if (c == isSmall) {
512       assert(small_[smallSize()] == TERMINATOR || smallSize() == maxSmallSize
513              || small_[smallSize()] == '\0');
514       small_[smallSize()] = '\0';
515       return small_;
516     }
517     assert(c == isMedium || c == isLarge);
518     assert(ml_.data_[ml_.size_] == TERMINATOR || ml_.data_[ml_.size_] == '\0');
519     ml_.data_[ml_.size_] = '\0';
520 #elif defined(FBSTRING_CONSERVATIVE)
521     if (c == isSmall) {
522       assert(small_[smallSize()] == '\0');
523       return small_;
524     }
525     assert(c == isMedium || c == isLarge);
526     assert(ml_.data_[ml_.size_] == '\0');
527 #else
528     if (c == isSmall) {
529       small_[smallSize()] = '\0';
530       return small_;
531     }
532     assert(c == isMedium || c == isLarge);
533     ml_.data_[ml_.size_] = '\0';
534 #endif
535     return ml_.data_;
536   }
537
538   void shrink(const size_t delta) {
539     if (category() == isSmall) {
540       // Check for underflow
541       assert(delta <= smallSize());
542       setSmallSize(smallSize() - delta);
543     } else if (category() == isMedium || RefCounted::refs(ml_.data_) == 1) {
544       // Medium strings and unique large strings need no special
545       // handling.
546       assert(ml_.size_ >= delta);
547       ml_.size_ -= delta;
548     } else {
549       assert(ml_.size_ >= delta);
550       // Shared large string, must make unique. This is because of the
551       // durn terminator must be written, which may trample the shared
552       // data.
553       if (delta) {
554         fbstring_core(ml_.data_, ml_.size_ - delta).swap(*this);
555       }
556       // No need to write the terminator.
557       return;
558     }
559     writeTerminator();
560   }
561
562   void reserve(size_t minCapacity) {
563     if (category() == isLarge) {
564       // Ensure unique
565       if (RefCounted::refs(ml_.data_) > 1) {
566         // We must make it unique regardless; in-place reallocation is
567         // useless if the string is shared. In order to not surprise
568         // people, reserve the new block at current capacity or
569         // more. That way, a string's capacity never shrinks after a
570         // call to reserve.
571         minCapacity = std::max(minCapacity, ml_.capacity());
572         auto const newRC = RefCounted::create(& minCapacity);
573         fbstring_detail::pod_copy(ml_.data_, ml_.data_ + ml_.size_ + 1,
574                                    newRC->data_);
575         // Done with the old data. No need to call writeTerminator(),
576         // we have + 1 above.
577         RefCounted::decrementRefs(ml_.data_);
578         ml_.data_ = newRC->data_;
579         ml_.capacity_ = minCapacity | isLarge;
580         // size remains unchanged
581       } else {
582         // String is not shared, so let's try to realloc (if needed)
583         if (minCapacity > ml_.capacity()) {
584           // Asking for more memory
585           auto const newRC =
586                RefCounted::reallocate(ml_.data_, ml_.size_,
587                                       ml_.capacity(), minCapacity);
588           ml_.data_ = newRC->data_;
589           ml_.capacity_ = minCapacity | isLarge;
590           writeTerminator();
591         }
592         assert(capacity() >= minCapacity);
593       }
594     } else if (category() == isMedium) {
595       // String is not shared
596       if (minCapacity <= ml_.capacity()) {
597         return; // nothing to do, there's enough room
598       }
599       if (minCapacity <= maxMediumSize) {
600         // Keep the string at medium size. Don't forget to allocate
601         // one extra Char for the terminating null.
602         size_t capacityBytes = goodMallocSize((1 + minCapacity) * sizeof(Char));
603         ml_.data_ = static_cast<Char *>(
604           smartRealloc(
605             ml_.data_,
606             ml_.size_ * sizeof(Char),
607             ml_.capacity() * sizeof(Char),
608             capacityBytes));
609         writeTerminator();
610         ml_.capacity_ = (capacityBytes / sizeof(Char) - 1) | isMedium;
611       } else {
612         // Conversion from medium to large string
613         fbstring_core nascent;
614         // Will recurse to another branch of this function
615         nascent.reserve(minCapacity);
616         nascent.ml_.size_ = ml_.size_;
617         fbstring_detail::pod_copy(ml_.data_, ml_.data_ + ml_.size_,
618                                   nascent.ml_.data_);
619         nascent.swap(*this);
620         writeTerminator();
621         assert(capacity() >= minCapacity);
622       }
623     } else {
624       assert(category() == isSmall);
625       if (minCapacity > maxMediumSize) {
626         // large
627         auto const newRC = RefCounted::create(& minCapacity);
628         auto const size = smallSize();
629         fbstring_detail::pod_copy(small_, small_ + size + 1, newRC->data_);
630         // No need for writeTerminator(), we wrote it above with + 1.
631         ml_.data_ = newRC->data_;
632         ml_.size_ = size;
633         ml_.capacity_ = minCapacity | isLarge;
634         assert(capacity() >= minCapacity);
635       } else if (minCapacity > maxSmallSize) {
636         // medium
637         // Don't forget to allocate one extra Char for the terminating null
638         auto const allocSizeBytes =
639           goodMallocSize((1 + minCapacity) * sizeof(Char));
640         auto const data = static_cast<Char*>(checkedMalloc(allocSizeBytes));
641         auto const size = smallSize();
642         fbstring_detail::pod_copy(small_, small_ + size + 1, data);
643         // No need for writeTerminator(), we wrote it above with + 1.
644         ml_.data_ = data;
645         ml_.size_ = size;
646         ml_.capacity_ = (allocSizeBytes / sizeof(Char) - 1) | isMedium;
647       } else {
648         // small
649         // Nothing to do, everything stays put
650       }
651     }
652     assert(capacity() >= minCapacity);
653   }
654
655   Char * expand_noinit(const size_t delta) {
656     // Strategy is simple: make room, then change size
657     assert(capacity() >= size());
658     size_t sz, newSz;
659     if (category() == isSmall) {
660       sz = smallSize();
661       newSz = sz + delta;
662       if (newSz <= maxSmallSize) {
663         setSmallSize(newSz);
664         writeTerminator();
665         return small_ + sz;
666       }
667       reserve(newSz);
668     } else {
669       sz = ml_.size_;
670       newSz = ml_.size_ + delta;
671       if (newSz > capacity()) {
672         reserve(newSz);
673       }
674     }
675     assert(capacity() >= newSz);
676     // Category can't be small - we took care of that above
677     assert(category() == isMedium || category() == isLarge);
678     ml_.size_ = newSz;
679     writeTerminator();
680     assert(size() == newSz);
681     return ml_.data_ + sz;
682   }
683
684   void push_back(Char c) {
685     assert(capacity() >= size());
686     size_t sz;
687     if (category() == isSmall) {
688       sz = smallSize();
689       if (sz < maxSmallSize) {
690         setSmallSize(sz + 1);
691         small_[sz] = c;
692         writeTerminator();
693         return;
694       }
695       reserve(maxSmallSize * 2);
696     } else {
697       sz = ml_.size_;
698       if (sz == capacity()) {  // always true for isShared()
699         reserve(sz * 3 / 2);  // ensures not shared
700       }
701     }
702     assert(!isShared());
703     assert(capacity() >= sz + 1);
704     // Category can't be small - we took care of that above
705     assert(category() == isMedium || category() == isLarge);
706     ml_.size_ = sz + 1;
707     ml_.data_[sz] = c;
708     writeTerminator();
709   }
710
711   size_t size() const {
712     return category() == isSmall ? smallSize() : ml_.size_;
713   }
714
715   size_t capacity() const {
716     switch (category()) {
717       case isSmall:
718         return maxSmallSize;
719       case isLarge:
720         // For large-sized strings, a multi-referenced chunk has no
721         // available capacity. This is because any attempt to append
722         // data would trigger a new allocation.
723         if (RefCounted::refs(ml_.data_) > 1) return ml_.size_;
724       default: {}
725     }
726     return ml_.capacity();
727   }
728
729   bool isShared() const {
730     return category() == isLarge && RefCounted::refs(ml_.data_) > 1;
731   }
732
733 #ifdef FBSTRING_PERVERSE
734   enum { TERMINATOR = '^' };
735 #else
736   enum { TERMINATOR = '\0' };
737 #endif
738
739   void writeTerminator() {
740 #if defined(FBSTRING_PERVERSE) || defined(FBSTRING_CONSERVATIVE)
741     if (category() == isSmall) {
742       const auto s = smallSize();
743       if (s != maxSmallSize) {
744         small_[s] = TERMINATOR;
745       }
746     } else {
747       ml_.data_[ml_.size_] = TERMINATOR;
748     }
749 #endif
750   }
751
752 private:
753   // Disabled
754   fbstring_core & operator=(const fbstring_core & rhs);
755
756   struct MediumLarge {
757     Char * data_;
758     size_t size_;
759     size_t capacity_;
760
761     size_t capacity() const {
762       return capacity_ & capacityExtractMask;
763     }
764   };
765
766   struct RefCounted {
767     std::atomic<size_t> refCount_;
768     Char data_[1];
769
770     static RefCounted * fromData(Char * p) {
771       return static_cast<RefCounted*>(
772         static_cast<void*>(
773           static_cast<unsigned char*>(static_cast<void*>(p))
774           - sizeof(refCount_)));
775     }
776
777     static size_t refs(Char * p) {
778       return fromData(p)->refCount_.load(std::memory_order_acquire);
779     }
780
781     static void incrementRefs(Char * p) {
782       fromData(p)->refCount_.fetch_add(1, std::memory_order_acq_rel);
783     }
784
785     static void decrementRefs(Char * p) {
786       auto const dis = fromData(p);
787       size_t oldcnt = dis->refCount_.fetch_sub(1, std::memory_order_acq_rel);
788       assert(oldcnt > 0);
789       if (oldcnt == 1) {
790         free(dis);
791       }
792     }
793
794     static RefCounted * create(size_t * size) {
795       // Don't forget to allocate one extra Char for the terminating
796       // null. In this case, however, one Char is already part of the
797       // struct.
798       const size_t allocSize = goodMallocSize(
799         sizeof(RefCounted) + *size * sizeof(Char));
800       auto result = static_cast<RefCounted*>(checkedMalloc(allocSize));
801       result->refCount_.store(1, std::memory_order_release);
802       *size = (allocSize - sizeof(RefCounted)) / sizeof(Char);
803       return result;
804     }
805
806     static RefCounted * create(const Char * data, size_t * size) {
807       const size_t effectiveSize = *size;
808       auto result = create(size);
809       fbstring_detail::pod_copy(data, data + effectiveSize, result->data_);
810       return result;
811     }
812
813     static RefCounted * reallocate(Char *const data,
814                                    const size_t currentSize,
815                                    const size_t currentCapacity,
816                                    const size_t newCapacity) {
817       assert(newCapacity > 0 && newCapacity > currentSize);
818       auto const dis = fromData(data);
819       assert(dis->refCount_.load(std::memory_order_acquire) == 1);
820       // Don't forget to allocate one extra Char for the terminating
821       // null. In this case, however, one Char is already part of the
822       // struct.
823       auto result = static_cast<RefCounted*>(
824              smartRealloc(dis,
825                           sizeof(RefCounted) + currentSize * sizeof(Char),
826                           sizeof(RefCounted) + currentCapacity * sizeof(Char),
827                           sizeof(RefCounted) + newCapacity * sizeof(Char)));
828       assert(result->refCount_.load(std::memory_order_acquire) == 1);
829       return result;
830     }
831   };
832
833   union {
834     mutable Char small_[sizeof(MediumLarge) / sizeof(Char)];
835     mutable MediumLarge ml_;
836   };
837
838   enum {
839     lastChar = sizeof(MediumLarge) - 1,
840     maxSmallSize = lastChar / sizeof(Char),
841     maxMediumSize = 254 / sizeof(Char),            // coincides with the small
842                                                    // bin size in dlmalloc
843     categoryExtractMask = sizeof(size_t) == 4 ? 0xC0000000 : 0xC000000000000000,
844     capacityExtractMask = ~categoryExtractMask,
845   };
846   static_assert(!(sizeof(MediumLarge) % sizeof(Char)),
847                 "Corrupt memory layout for fbstring.");
848
849   enum Category {
850     isSmall = 0,
851     isMedium = sizeof(size_t) == 4 ? 0x80000000 : 0x8000000000000000,
852     isLarge =  sizeof(size_t) == 4 ? 0x40000000 : 0x4000000000000000,
853   };
854
855   Category category() const {
856     // Assumes little endian
857     return static_cast<Category>(ml_.capacity_ & categoryExtractMask);
858   }
859
860   size_t smallSize() const {
861     assert(category() == isSmall && small_[maxSmallSize] <= maxSmallSize);
862     return static_cast<size_t>(maxSmallSize)
863       - static_cast<size_t>(small_[maxSmallSize]);
864   }
865
866   void setSmallSize(size_t s) {
867     // Warning: this should work with uninitialized strings too,
868     // so don't assume anything about the previous value of
869     // small_[maxSmallSize].
870     assert(s <= maxSmallSize);
871     small_[maxSmallSize] = maxSmallSize - s;
872   }
873 };
874
875 #if defined(__GNUC__) && !defined(__clang__)
876 # pragma GCC diagnostic pop
877 #endif
878
879 #ifndef _LIBSTDCXX_FBSTRING
880 /**
881  * Dummy fbstring core that uses an actual std::string. This doesn't
882  * make any sense - it's just for testing purposes.
883  */
884 template <class Char>
885 class dummy_fbstring_core {
886 public:
887   dummy_fbstring_core() {
888   }
889   dummy_fbstring_core(const dummy_fbstring_core& another)
890       : backend_(another.backend_) {
891   }
892   dummy_fbstring_core(const Char * s, size_t n)
893       : backend_(s, n) {
894   }
895   void swap(dummy_fbstring_core & rhs) {
896     backend_.swap(rhs.backend_);
897   }
898   const Char * data() const {
899     return backend_.data();
900   }
901   Char * mutable_data() {
902     //assert(!backend_.empty());
903     return &*backend_.begin();
904   }
905   void shrink(size_t delta) {
906     assert(delta <= size());
907     backend_.resize(size() - delta);
908   }
909   Char * expand_noinit(size_t delta) {
910     auto const sz = size();
911     backend_.resize(size() + delta);
912     return backend_.data() + sz;
913   }
914   void push_back(Char c) {
915     backend_.push_back(c);
916   }
917   size_t size() const {
918     return backend_.size();
919   }
920   size_t capacity() const {
921     return backend_.capacity();
922   }
923   bool isShared() const {
924     return false;
925   }
926   void reserve(size_t minCapacity) {
927     backend_.reserve(minCapacity);
928   }
929
930 private:
931   std::basic_string<Char> backend_;
932 };
933 #endif // !_LIBSTDCXX_FBSTRING
934
935 /**
936  * This is the basic_string replacement. For conformity,
937  * basic_fbstring takes the same template parameters, plus the last
938  * one which is the core.
939  */
940 #ifdef _LIBSTDCXX_FBSTRING
941 template <typename E, class T, class A, class Storage>
942 #else
943 template <typename E,
944           class T = std::char_traits<E>,
945           class A = std::allocator<E>,
946           class Storage = fbstring_core<E> >
947 #endif
948 class basic_fbstring {
949
950   static void enforce(
951       bool condition,
952       void (*throw_exc)(const char*),
953       const char* msg) {
954     if (!condition) throw_exc(msg);
955   }
956
957   bool isSane() const {
958     return
959       begin() <= end() &&
960       empty() == (size() == 0) &&
961       empty() == (begin() == end()) &&
962       size() <= max_size() &&
963       capacity() <= max_size() &&
964       size() <= capacity() &&
965       (begin()[size()] == Storage::TERMINATOR || begin()[size()] == '\0');
966   }
967
968   struct Invariant;
969   friend struct Invariant;
970   struct Invariant {
971 #ifndef NDEBUG
972     explicit Invariant(const basic_fbstring& s) : s_(s) {
973       assert(s_.isSane());
974     }
975     ~Invariant() {
976       assert(s_.isSane());
977     }
978   private:
979     const basic_fbstring& s_;
980 #else
981     explicit Invariant(const basic_fbstring&) {}
982 #endif
983     Invariant& operator=(const Invariant&);
984   };
985
986 public:
987   // types
988   typedef T traits_type;
989   typedef typename traits_type::char_type value_type;
990   typedef A allocator_type;
991   typedef typename A::size_type size_type;
992   typedef typename A::difference_type difference_type;
993
994   typedef typename A::reference reference;
995   typedef typename A::const_reference const_reference;
996   typedef typename A::pointer pointer;
997   typedef typename A::const_pointer const_pointer;
998
999   typedef E* iterator;
1000   typedef const E* const_iterator;
1001   typedef std::reverse_iterator<iterator
1002 #ifdef NO_ITERATOR_TRAITS
1003                                 , value_type
1004 #endif
1005                                 > reverse_iterator;
1006   typedef std::reverse_iterator<const_iterator
1007 #ifdef NO_ITERATOR_TRAITS
1008                                 , const value_type
1009 #endif
1010                                 > const_reverse_iterator;
1011
1012   static const size_type npos;                     // = size_type(-1)
1013
1014 private:
1015   static void procrustes(size_type& n, size_type nmax) {
1016     if (n > nmax) n = nmax;
1017   }
1018
1019 public:
1020   // C++11 21.4.2 construct/copy/destroy
1021   explicit basic_fbstring(const A& a = A()) noexcept {
1022   }
1023
1024   basic_fbstring(const basic_fbstring& str)
1025       : store_(str.store_) {
1026   }
1027
1028   // Move constructor
1029   basic_fbstring(basic_fbstring&& goner) noexcept
1030       : store_(std::move(goner.store_)) {
1031   }
1032
1033 #ifndef _LIBSTDCXX_FBSTRING
1034   // This is defined for compatibility with std::string
1035   /* implicit */ basic_fbstring(const std::string& str)
1036       : store_(str.data(), str.size()) {
1037   }
1038 #endif
1039
1040   basic_fbstring(const basic_fbstring& str, size_type pos,
1041                  size_type n = npos, const A& a = A()) {
1042     assign(str, pos, n);
1043   }
1044
1045   /* implicit */ basic_fbstring(const value_type* s, const A& a = A())
1046       : store_(s, s ? traits_type::length(s) : ({
1047           basic_fbstring<char> err = __PRETTY_FUNCTION__;
1048           err += ": null pointer initializer not valid";
1049           std::__throw_logic_error(err.c_str());
1050           0;
1051       })) {
1052   }
1053
1054   basic_fbstring(const value_type* s, size_type n, const A& a = A())
1055       : store_(s, n) {
1056   }
1057
1058   basic_fbstring(size_type n, value_type c, const A& a = A()) {
1059     auto const data = store_.expand_noinit(n);
1060     fbstring_detail::pod_fill(data, data + n, c);
1061     store_.writeTerminator();
1062   }
1063
1064   template <class InIt>
1065   basic_fbstring(InIt begin, InIt end,
1066                  typename std::enable_if<
1067                  !std::is_same<typename std::remove_const<InIt>::type,
1068                  value_type*>::value, const A>::type & a = A()) {
1069     assign(begin, end);
1070   }
1071
1072   // Specialization for const char*, const char*
1073   basic_fbstring(const value_type* b, const value_type* e)
1074       : store_(b, e - b) {
1075   }
1076
1077   // Nonstandard constructor
1078   basic_fbstring(value_type *s, size_type n, size_type c,
1079                  AcquireMallocatedString a)
1080       : store_(s, n, c, a) {
1081   }
1082
1083   // Construction from initialization list
1084   basic_fbstring(std::initializer_list<value_type> il) {
1085     assign(il.begin(), il.end());
1086   }
1087
1088   ~basic_fbstring() noexcept {
1089   }
1090
1091   basic_fbstring& operator=(const basic_fbstring& lhs) {
1092     if (FBSTRING_UNLIKELY(&lhs == this)) {
1093       return *this;
1094     }
1095     auto const oldSize = size();
1096     auto const srcSize = lhs.size();
1097     if (capacity() >= srcSize && !store_.isShared()) {
1098       // great, just copy the contents
1099       if (oldSize < srcSize)
1100         store_.expand_noinit(srcSize - oldSize);
1101       else
1102         store_.shrink(oldSize - srcSize);
1103       assert(size() == srcSize);
1104       fbstring_detail::pod_copy(lhs.begin(), lhs.end(), begin());
1105       store_.writeTerminator();
1106     } else {
1107       // need to reallocate, so we may as well create a brand new string
1108       basic_fbstring(lhs).swap(*this);
1109     }
1110     return *this;
1111   }
1112
1113   // Move assignment
1114   basic_fbstring& operator=(basic_fbstring&& goner) noexcept {
1115     if (FBSTRING_UNLIKELY(&goner == this)) {
1116       // Compatibility with std::basic_string<>,
1117       // C++11 21.4.2 [string.cons] / 23 requires self-move-assignment support.
1118       return *this;
1119     }
1120     // No need of this anymore
1121     this->~basic_fbstring();
1122     // Move the goner into this
1123     new(&store_) fbstring_core<E>(std::move(goner.store_));
1124     return *this;
1125   }
1126
1127 #ifndef _LIBSTDCXX_FBSTRING
1128   // Compatibility with std::string
1129   basic_fbstring & operator=(const std::string & rhs) {
1130     return assign(rhs.data(), rhs.size());
1131   }
1132
1133   // Compatibility with std::string
1134   std::string toStdString() const {
1135     return std::string(data(), size());
1136   }
1137 #else
1138   // A lot of code in fbcode still uses this method, so keep it here for now.
1139   const basic_fbstring& toStdString() const {
1140     return *this;
1141   }
1142 #endif
1143
1144   basic_fbstring& operator=(const value_type* s) {
1145     return assign(s);
1146   }
1147
1148   basic_fbstring& operator=(value_type c) {
1149     if (empty()) {
1150       store_.expand_noinit(1);
1151     } else if (store_.isShared()) {
1152       basic_fbstring(1, c).swap(*this);
1153       return *this;
1154     } else {
1155       store_.shrink(size() - 1);
1156     }
1157     *store_.mutable_data() = c;
1158     store_.writeTerminator();
1159     return *this;
1160   }
1161
1162   basic_fbstring& operator=(std::initializer_list<value_type> il) {
1163     return assign(il.begin(), il.end());
1164   }
1165
1166   // C++11 21.4.3 iterators:
1167   iterator begin() { return store_.mutable_data(); }
1168
1169   const_iterator begin() const { return store_.data(); }
1170
1171   const_iterator cbegin() const { return begin(); }
1172
1173   iterator end() {
1174     return store_.mutable_data() + store_.size();
1175   }
1176
1177   const_iterator end() const {
1178     return store_.data() + store_.size();
1179   }
1180
1181   const_iterator cend() const { return end(); }
1182
1183   reverse_iterator rbegin() {
1184     return reverse_iterator(end());
1185   }
1186
1187   const_reverse_iterator rbegin() const {
1188     return const_reverse_iterator(end());
1189   }
1190
1191   const_reverse_iterator crbegin() const { return rbegin(); }
1192
1193   reverse_iterator rend() {
1194     return reverse_iterator(begin());
1195   }
1196
1197   const_reverse_iterator rend() const {
1198     return const_reverse_iterator(begin());
1199   }
1200
1201   const_reverse_iterator crend() const { return rend(); }
1202
1203   // Added by C++11
1204   // C++11 21.4.5, element access:
1205   const value_type& front() const { return *begin(); }
1206   const value_type& back() const {
1207     assert(!empty());
1208     // Should be begin()[size() - 1], but that branches twice
1209     return *(end() - 1);
1210   }
1211   value_type& front() { return *begin(); }
1212   value_type& back() {
1213     assert(!empty());
1214     // Should be begin()[size() - 1], but that branches twice
1215     return *(end() - 1);
1216   }
1217   void pop_back() {
1218     assert(!empty());
1219     store_.shrink(1);
1220   }
1221
1222   // C++11 21.4.4 capacity:
1223   size_type size() const { return store_.size(); }
1224
1225   size_type length() const { return size(); }
1226
1227   size_type max_size() const {
1228     return std::numeric_limits<size_type>::max();
1229   }
1230
1231   void resize(const size_type n, const value_type c = value_type()) {
1232     auto size = this->size();
1233     if (n <= size) {
1234       store_.shrink(size - n);
1235     } else {
1236       // Do this in two steps to minimize slack memory copied (see
1237       // smartRealloc).
1238       auto const capacity = this->capacity();
1239       assert(capacity >= size);
1240       if (size < capacity) {
1241         auto delta = std::min(n, capacity) - size;
1242         store_.expand_noinit(delta);
1243         fbstring_detail::pod_fill(begin() + size, end(), c);
1244         size += delta;
1245         if (size == n) {
1246           store_.writeTerminator();
1247           return;
1248         }
1249         assert(size < n);
1250       }
1251       auto const delta = n - size;
1252       store_.expand_noinit(delta);
1253       fbstring_detail::pod_fill(end() - delta, end(), c);
1254       store_.writeTerminator();
1255     }
1256     assert(this->size() == n);
1257   }
1258
1259   size_type capacity() const { return store_.capacity(); }
1260
1261   void reserve(size_type res_arg = 0) {
1262     enforce(res_arg <= max_size(), std::__throw_length_error, "");
1263     store_.reserve(res_arg);
1264   }
1265
1266   void shrink_to_fit() {
1267     // Shrink only if slack memory is sufficiently large
1268     if (capacity() < size() * 3 / 2) {
1269       return;
1270     }
1271     basic_fbstring(cbegin(), cend()).swap(*this);
1272   }
1273
1274   void clear() { resize(0); }
1275
1276   bool empty() const { return size() == 0; }
1277
1278   // C++11 21.4.5 element access:
1279   const_reference operator[](size_type pos) const {
1280     return *(c_str() + pos);
1281   }
1282
1283   reference operator[](size_type pos) {
1284     if (pos == size()) {
1285       // Just call c_str() to make sure '\0' is present
1286       c_str();
1287     }
1288     return *(begin() + pos);
1289   }
1290
1291   const_reference at(size_type n) const {
1292     enforce(n <= size(), std::__throw_out_of_range, "");
1293     return (*this)[n];
1294   }
1295
1296   reference at(size_type n) {
1297     enforce(n < size(), std::__throw_out_of_range, "");
1298     return (*this)[n];
1299   }
1300
1301   // C++11 21.4.6 modifiers:
1302   basic_fbstring& operator+=(const basic_fbstring& str) {
1303     return append(str);
1304   }
1305
1306   basic_fbstring& operator+=(const value_type* s) {
1307     return append(s);
1308   }
1309
1310   basic_fbstring& operator+=(const value_type c) {
1311     push_back(c);
1312     return *this;
1313   }
1314
1315   basic_fbstring& operator+=(std::initializer_list<value_type> il) {
1316     append(il);
1317     return *this;
1318   }
1319
1320   basic_fbstring& append(const basic_fbstring& str) {
1321 #ifndef NDEBUG
1322     auto desiredSize = size() + str.size();
1323 #endif
1324     append(str.data(), str.size());
1325     assert(size() == desiredSize);
1326     return *this;
1327   }
1328
1329   basic_fbstring& append(const basic_fbstring& str, const size_type pos,
1330                          size_type n) {
1331     const size_type sz = str.size();
1332     enforce(pos <= sz, std::__throw_out_of_range, "");
1333     procrustes(n, sz - pos);
1334     return append(str.data() + pos, n);
1335   }
1336
1337   basic_fbstring& append(const value_type* s, size_type n) {
1338 #ifndef NDEBUG
1339     Invariant checker(*this);
1340     (void) checker;
1341 #endif
1342     if (FBSTRING_UNLIKELY(!n)) {
1343       // Unlikely but must be done
1344       return *this;
1345     }
1346     auto const oldSize = size();
1347     auto const oldData = data();
1348     // Check for aliasing (rare). We could use "<=" here but in theory
1349     // those do not work for pointers unless the pointers point to
1350     // elements in the same array. For that reason we use
1351     // std::less_equal, which is guaranteed to offer a total order
1352     // over pointers. See discussion at http://goo.gl/Cy2ya for more
1353     // info.
1354     std::less_equal<const value_type*> le;
1355     if (FBSTRING_UNLIKELY(le(oldData, s) && !le(oldData + oldSize, s))) {
1356       assert(le(s + n, oldData + oldSize));
1357       const size_type offset = s - oldData;
1358       store_.reserve(oldSize + n);
1359       // Restore the source
1360       s = data() + offset;
1361     }
1362     // Warning! Repeated appends with short strings may actually incur
1363     // practically quadratic performance. Avoid that by pushing back
1364     // the first character (which ensures exponential growth) and then
1365     // appending the rest normally. Worst case the append may incur a
1366     // second allocation but that will be rare.
1367     push_back(*s++);
1368     --n;
1369     memcpy(store_.expand_noinit(n), s, n * sizeof(value_type));
1370     assert(size() == oldSize + n + 1);
1371     return *this;
1372   }
1373
1374   basic_fbstring& append(const value_type* s) {
1375     return append(s, traits_type::length(s));
1376   }
1377
1378   basic_fbstring& append(size_type n, value_type c) {
1379     resize(size() + n, c);
1380     return *this;
1381   }
1382
1383   template<class InputIterator>
1384   basic_fbstring& append(InputIterator first, InputIterator last) {
1385     insert(end(), first, last);
1386     return *this;
1387   }
1388
1389   basic_fbstring& append(std::initializer_list<value_type> il) {
1390     return append(il.begin(), il.end());
1391   }
1392
1393   void push_back(const value_type c) {             // primitive
1394     store_.push_back(c);
1395   }
1396
1397   basic_fbstring& assign(const basic_fbstring& str) {
1398     if (&str == this) return *this;
1399     return assign(str.data(), str.size());
1400   }
1401
1402   basic_fbstring& assign(basic_fbstring&& str) {
1403     return *this = std::move(str);
1404   }
1405
1406   basic_fbstring& assign(const basic_fbstring& str, const size_type pos,
1407                          size_type n) {
1408     const size_type sz = str.size();
1409     enforce(pos <= sz, std::__throw_out_of_range, "");
1410     procrustes(n, sz - pos);
1411     return assign(str.data() + pos, n);
1412   }
1413
1414   basic_fbstring& assign(const value_type* s, const size_type n) {
1415     Invariant checker(*this);
1416     (void) checker;
1417     if (size() >= n) {
1418       std::copy(s, s + n, begin());
1419       resize(n);
1420       assert(size() == n);
1421     } else {
1422       const value_type *const s2 = s + size();
1423       std::copy(s, s2, begin());
1424       append(s2, n - size());
1425       assert(size() == n);
1426     }
1427     store_.writeTerminator();
1428     assert(size() == n);
1429     return *this;
1430   }
1431
1432   basic_fbstring& assign(const value_type* s) {
1433     return assign(s, traits_type::length(s));
1434   }
1435
1436   basic_fbstring& assign(std::initializer_list<value_type> il) {
1437     return assign(il.begin(), il.end());
1438   }
1439
1440   template <class ItOrLength, class ItOrChar>
1441   basic_fbstring& assign(ItOrLength first_or_n, ItOrChar last_or_c) {
1442     return replace(begin(), end(), first_or_n, last_or_c);
1443   }
1444
1445   basic_fbstring& insert(size_type pos1, const basic_fbstring& str) {
1446     return insert(pos1, str.data(), str.size());
1447   }
1448
1449   basic_fbstring& insert(size_type pos1, const basic_fbstring& str,
1450                          size_type pos2, size_type n) {
1451     enforce(pos2 <= str.length(), std::__throw_out_of_range, "");
1452     procrustes(n, str.length() - pos2);
1453     return insert(pos1, str.data() + pos2, n);
1454   }
1455
1456   basic_fbstring& insert(size_type pos, const value_type* s, size_type n) {
1457     enforce(pos <= length(), std::__throw_out_of_range, "");
1458     insert(begin() + pos, s, s + n);
1459     return *this;
1460   }
1461
1462   basic_fbstring& insert(size_type pos, const value_type* s) {
1463     return insert(pos, s, traits_type::length(s));
1464   }
1465
1466   basic_fbstring& insert(size_type pos, size_type n, value_type c) {
1467     enforce(pos <= length(), std::__throw_out_of_range, "");
1468     insert(begin() + pos, n, c);
1469     return *this;
1470   }
1471
1472   iterator insert(const_iterator p, const value_type c) {
1473     const size_type pos = p - begin();
1474     insert(p, 1, c);
1475     return begin() + pos;
1476   }
1477
1478 private:
1479   template <int i> class Selector {};
1480
1481   iterator insertImplDiscr(const_iterator p,
1482                            size_type n, value_type c, Selector<1>) {
1483     Invariant checker(*this);
1484     (void) checker;
1485     auto const pos = p - begin();
1486     assert(p >= begin() && p <= end());
1487     if (capacity() - size() < n) {
1488       const size_type sz = p - begin();
1489       reserve(size() + n);
1490       p = begin() + sz;
1491     }
1492     const iterator oldEnd = end();
1493     if (n < size_type(oldEnd - p)) {
1494       append(oldEnd - n, oldEnd);
1495       //std::copy(
1496       //    reverse_iterator(oldEnd - n),
1497       //    reverse_iterator(p),
1498       //    reverse_iterator(oldEnd));
1499       fbstring_detail::pod_move(&*p, &*oldEnd - n,
1500                                 begin() + pos + n);
1501       std::fill(begin() + pos, begin() + pos + n, c);
1502     } else {
1503       append(n - (end() - p), c);
1504       append(iterator(p), oldEnd);
1505       std::fill(iterator(p), oldEnd, c);
1506     }
1507     store_.writeTerminator();
1508     return begin() + pos;
1509   }
1510
1511   template<class InputIter>
1512   iterator insertImplDiscr(const_iterator i,
1513                            InputIter b, InputIter e, Selector<0>) {
1514     return insertImpl(i, b, e,
1515                typename std::iterator_traits<InputIter>::iterator_category());
1516   }
1517
1518   template <class FwdIterator>
1519   iterator insertImpl(const_iterator i,
1520                   FwdIterator s1, FwdIterator s2, std::forward_iterator_tag) {
1521     Invariant checker(*this);
1522     (void) checker;
1523     const size_type pos = i - begin();
1524     const typename std::iterator_traits<FwdIterator>::difference_type n2 =
1525       std::distance(s1, s2);
1526     assert(n2 >= 0);
1527     using namespace fbstring_detail;
1528     assert(pos <= size());
1529
1530     const typename std::iterator_traits<FwdIterator>::difference_type maxn2 =
1531       capacity() - size();
1532     if (maxn2 < n2) {
1533       // realloc the string
1534       reserve(size() + n2);
1535       i = begin() + pos;
1536     }
1537     if (pos + n2 <= size()) {
1538       const iterator tailBegin = end() - n2;
1539       store_.expand_noinit(n2);
1540       fbstring_detail::pod_copy(tailBegin, tailBegin + n2, end() - n2);
1541       std::copy(const_reverse_iterator(tailBegin), const_reverse_iterator(i),
1542                 reverse_iterator(tailBegin + n2));
1543       std::copy(s1, s2, begin() + pos);
1544     } else {
1545       FwdIterator t = s1;
1546       const size_type old_size = size();
1547       std::advance(t, old_size - pos);
1548       const size_t newElems = std::distance(t, s2);
1549       store_.expand_noinit(n2);
1550       std::copy(t, s2, begin() + old_size);
1551       fbstring_detail::pod_copy(data() + pos, data() + old_size,
1552                                  begin() + old_size + newElems);
1553       std::copy(s1, t, begin() + pos);
1554     }
1555     store_.writeTerminator();
1556     return begin() + pos;
1557   }
1558
1559   template <class InputIterator>
1560   iterator insertImpl(const_iterator i,
1561                       InputIterator b, InputIterator e,
1562                       std::input_iterator_tag) {
1563     const auto pos = i - begin();
1564     basic_fbstring temp(begin(), i);
1565     for (; b != e; ++b) {
1566       temp.push_back(*b);
1567     }
1568     temp.append(i, cend());
1569     swap(temp);
1570     return begin() + pos;
1571   }
1572
1573 public:
1574   template <class ItOrLength, class ItOrChar>
1575   iterator insert(const_iterator p, ItOrLength first_or_n, ItOrChar last_or_c) {
1576     Selector<std::numeric_limits<ItOrLength>::is_specialized> sel;
1577     return insertImplDiscr(p, first_or_n, last_or_c, sel);
1578   }
1579
1580   iterator insert(const_iterator p, std::initializer_list<value_type> il) {
1581     return insert(p, il.begin(), il.end());
1582   }
1583
1584   basic_fbstring& erase(size_type pos = 0, size_type n = npos) {
1585     Invariant checker(*this);
1586     (void) checker;
1587     enforce(pos <= length(), std::__throw_out_of_range, "");
1588     procrustes(n, length() - pos);
1589     std::copy(begin() + pos + n, end(), begin() + pos);
1590     resize(length() - n);
1591     return *this;
1592   }
1593
1594   iterator erase(iterator position) {
1595     const size_type pos(position - begin());
1596     enforce(pos <= size(), std::__throw_out_of_range, "");
1597     erase(pos, 1);
1598     return begin() + pos;
1599   }
1600
1601   iterator erase(iterator first, iterator last) {
1602     const size_type pos(first - begin());
1603     erase(pos, last - first);
1604     return begin() + pos;
1605   }
1606
1607   // Replaces at most n1 chars of *this, starting with pos1 with the
1608   // content of str
1609   basic_fbstring& replace(size_type pos1, size_type n1,
1610                           const basic_fbstring& str) {
1611     return replace(pos1, n1, str.data(), str.size());
1612   }
1613
1614   // Replaces at most n1 chars of *this, starting with pos1,
1615   // with at most n2 chars of str starting with pos2
1616   basic_fbstring& replace(size_type pos1, size_type n1,
1617                           const basic_fbstring& str,
1618                           size_type pos2, size_type n2) {
1619     enforce(pos2 <= str.length(), std::__throw_out_of_range, "");
1620     return replace(pos1, n1, str.data() + pos2,
1621                    std::min(n2, str.size() - pos2));
1622   }
1623
1624   // Replaces at most n1 chars of *this, starting with pos, with chars from s
1625   basic_fbstring& replace(size_type pos, size_type n1, const value_type* s) {
1626     return replace(pos, n1, s, traits_type::length(s));
1627   }
1628
1629   // Replaces at most n1 chars of *this, starting with pos, with n2
1630   // occurrences of c
1631   //
1632   // consolidated with
1633   //
1634   // Replaces at most n1 chars of *this, starting with pos, with at
1635   // most n2 chars of str.  str must have at least n2 chars.
1636   template <class StrOrLength, class NumOrChar>
1637   basic_fbstring& replace(size_type pos, size_type n1,
1638                           StrOrLength s_or_n2, NumOrChar n_or_c) {
1639     Invariant checker(*this);
1640     (void) checker;
1641     enforce(pos <= size(), std::__throw_out_of_range, "");
1642     procrustes(n1, length() - pos);
1643     const iterator b = begin() + pos;
1644     return replace(b, b + n1, s_or_n2, n_or_c);
1645   }
1646
1647   basic_fbstring& replace(iterator i1, iterator i2, const basic_fbstring& str) {
1648     return replace(i1, i2, str.data(), str.length());
1649   }
1650
1651   basic_fbstring& replace(iterator i1, iterator i2, const value_type* s) {
1652     return replace(i1, i2, s, traits_type::length(s));
1653   }
1654
1655 private:
1656   basic_fbstring& replaceImplDiscr(iterator i1, iterator i2,
1657                                    const value_type* s, size_type n,
1658                                    Selector<2>) {
1659     assert(i1 <= i2);
1660     assert(begin() <= i1 && i1 <= end());
1661     assert(begin() <= i2 && i2 <= end());
1662     return replace(i1, i2, s, s + n);
1663   }
1664
1665   basic_fbstring& replaceImplDiscr(iterator i1, iterator i2,
1666                                    size_type n2, value_type c, Selector<1>) {
1667     const size_type n1 = i2 - i1;
1668     if (n1 > n2) {
1669       std::fill(i1, i1 + n2, c);
1670       erase(i1 + n2, i2);
1671     } else {
1672       std::fill(i1, i2, c);
1673       insert(i2, n2 - n1, c);
1674     }
1675     assert(isSane());
1676     return *this;
1677   }
1678
1679   template <class InputIter>
1680   basic_fbstring& replaceImplDiscr(iterator i1, iterator i2,
1681                                    InputIter b, InputIter e,
1682                                    Selector<0>) {
1683     replaceImpl(i1, i2, b, e,
1684                 typename std::iterator_traits<InputIter>::iterator_category());
1685     return *this;
1686   }
1687
1688 private:
1689   template <class FwdIterator, class P>
1690   bool replaceAliased(iterator i1, iterator i2,
1691                       FwdIterator s1, FwdIterator s2, P*) {
1692     return false;
1693   }
1694
1695   template <class FwdIterator>
1696   bool replaceAliased(iterator i1, iterator i2,
1697                       FwdIterator s1, FwdIterator s2, value_type*) {
1698     static const std::less_equal<const value_type*> le =
1699       std::less_equal<const value_type*>();
1700     const bool aliased = le(&*begin(), &*s1) && le(&*s1, &*end());
1701     if (!aliased) {
1702       return false;
1703     }
1704     // Aliased replace, copy to new string
1705     basic_fbstring temp;
1706     temp.reserve(size() - (i2 - i1) + std::distance(s1, s2));
1707     temp.append(begin(), i1).append(s1, s2).append(i2, end());
1708     swap(temp);
1709     return true;
1710   }
1711
1712 public:
1713   template <class FwdIterator>
1714   void replaceImpl(iterator i1, iterator i2,
1715                    FwdIterator s1, FwdIterator s2, std::forward_iterator_tag) {
1716     Invariant checker(*this);
1717     (void) checker;
1718
1719     // Handle aliased replace
1720     if (replaceAliased(i1, i2, s1, s2, &*s1)) {
1721       return;
1722     }
1723
1724     auto const n1 = i2 - i1;
1725     assert(n1 >= 0);
1726     auto const n2 = std::distance(s1, s2);
1727     assert(n2 >= 0);
1728
1729     if (n1 > n2) {
1730       // shrinks
1731       std::copy(s1, s2, i1);
1732       erase(i1 + n2, i2);
1733     } else {
1734       // grows
1735       fbstring_detail::copy_n(s1, n1, i1);
1736       std::advance(s1, n1);
1737       insert(i2, s1, s2);
1738     }
1739     assert(isSane());
1740   }
1741
1742   template <class InputIterator>
1743   void replaceImpl(iterator i1, iterator i2,
1744                    InputIterator b, InputIterator e, std::input_iterator_tag) {
1745     basic_fbstring temp(begin(), i1);
1746     temp.append(b, e).append(i2, end());
1747     swap(temp);
1748   }
1749
1750 public:
1751   template <class T1, class T2>
1752   basic_fbstring& replace(iterator i1, iterator i2,
1753                           T1 first_or_n_or_s, T2 last_or_c_or_n) {
1754     const bool
1755       num1 = std::numeric_limits<T1>::is_specialized,
1756       num2 = std::numeric_limits<T2>::is_specialized;
1757     return replaceImplDiscr(
1758       i1, i2, first_or_n_or_s, last_or_c_or_n,
1759       Selector<num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>());
1760   }
1761
1762   size_type copy(value_type* s, size_type n, size_type pos = 0) const {
1763     enforce(pos <= size(), std::__throw_out_of_range, "");
1764     procrustes(n, size() - pos);
1765
1766     fbstring_detail::pod_copy(
1767       data() + pos,
1768       data() + pos + n,
1769       s);
1770     return n;
1771   }
1772
1773   void swap(basic_fbstring& rhs) {
1774     store_.swap(rhs.store_);
1775   }
1776
1777   const value_type* c_str() const {
1778     return store_.c_str();
1779   }
1780
1781   const value_type* data() const { return c_str(); }
1782
1783   allocator_type get_allocator() const {
1784     return allocator_type();
1785   }
1786
1787   size_type find(const basic_fbstring& str, size_type pos = 0) const {
1788     return find(str.data(), pos, str.length());
1789   }
1790
1791   size_type find(const value_type* needle, const size_type pos,
1792                  const size_type nsize) const {
1793     if (!nsize) return pos;
1794     auto const size = this->size();
1795     if (nsize + pos > size) return npos;
1796     // Don't use std::search, use a Boyer-Moore-like trick by comparing
1797     // the last characters first
1798     auto const haystack = data();
1799     auto const nsize_1 = nsize - 1;
1800     auto const lastNeedle = needle[nsize_1];
1801
1802     // Boyer-Moore skip value for the last char in the needle. Zero is
1803     // not a valid value; skip will be computed the first time it's
1804     // needed.
1805     size_type skip = 0;
1806
1807     const E * i = haystack + pos;
1808     auto iEnd = haystack + size - nsize_1;
1809
1810     while (i < iEnd) {
1811       // Boyer-Moore: match the last element in the needle
1812       while (i[nsize_1] != lastNeedle) {
1813         if (++i == iEnd) {
1814           // not found
1815           return npos;
1816         }
1817       }
1818       // Here we know that the last char matches
1819       // Continue in pedestrian mode
1820       for (size_t j = 0; ; ) {
1821         assert(j < nsize);
1822         if (i[j] != needle[j]) {
1823           // Not found, we can skip
1824           // Compute the skip value lazily
1825           if (skip == 0) {
1826             skip = 1;
1827             while (skip <= nsize_1 && needle[nsize_1 - skip] != lastNeedle) {
1828               ++skip;
1829             }
1830           }
1831           i += skip;
1832           break;
1833         }
1834         // Check if done searching
1835         if (++j == nsize) {
1836           // Yay
1837           return i - haystack;
1838         }
1839       }
1840     }
1841     return npos;
1842   }
1843
1844   size_type find(const value_type* s, size_type pos = 0) const {
1845     return find(s, pos, traits_type::length(s));
1846   }
1847
1848   size_type find (value_type c, size_type pos = 0) const {
1849     return find(&c, pos, 1);
1850   }
1851
1852   size_type rfind(const basic_fbstring& str, size_type pos = npos) const {
1853     return rfind(str.data(), pos, str.length());
1854   }
1855
1856   size_type rfind(const value_type* s, size_type pos, size_type n) const {
1857     if (n > length()) return npos;
1858     pos = std::min(pos, length() - n);
1859     if (n == 0) return pos;
1860
1861     const_iterator i(begin() + pos);
1862     for (; ; --i) {
1863       if (traits_type::eq(*i, *s)
1864           && traits_type::compare(&*i, s, n) == 0) {
1865         return i - begin();
1866       }
1867       if (i == begin()) break;
1868     }
1869     return npos;
1870   }
1871
1872   size_type rfind(const value_type* s, size_type pos = npos) const {
1873     return rfind(s, pos, traits_type::length(s));
1874   }
1875
1876   size_type rfind(value_type c, size_type pos = npos) const {
1877     return rfind(&c, pos, 1);
1878   }
1879
1880   size_type find_first_of(const basic_fbstring& str, size_type pos = 0) const {
1881     return find_first_of(str.data(), pos, str.length());
1882   }
1883
1884   size_type find_first_of(const value_type* s,
1885                           size_type pos, size_type n) const {
1886     if (pos > length() || n == 0) return npos;
1887     const_iterator i(begin() + pos),
1888       finish(end());
1889     for (; i != finish; ++i) {
1890       if (traits_type::find(s, n, *i) != 0) {
1891         return i - begin();
1892       }
1893     }
1894     return npos;
1895   }
1896
1897   size_type find_first_of(const value_type* s, size_type pos = 0) const {
1898     return find_first_of(s, pos, traits_type::length(s));
1899   }
1900
1901   size_type find_first_of(value_type c, size_type pos = 0) const {
1902     return find_first_of(&c, pos, 1);
1903   }
1904
1905   size_type find_last_of (const basic_fbstring& str,
1906                           size_type pos = npos) const {
1907     return find_last_of(str.data(), pos, str.length());
1908   }
1909
1910   size_type find_last_of (const value_type* s, size_type pos,
1911                           size_type n) const {
1912     if (!empty() && n > 0) {
1913       pos = std::min(pos, length() - 1);
1914       const_iterator i(begin() + pos);
1915       for (;; --i) {
1916         if (traits_type::find(s, n, *i) != 0) {
1917           return i - begin();
1918         }
1919         if (i == begin()) break;
1920       }
1921     }
1922     return npos;
1923   }
1924
1925   size_type find_last_of (const value_type* s,
1926                           size_type pos = npos) const {
1927     return find_last_of(s, pos, traits_type::length(s));
1928   }
1929
1930   size_type find_last_of (value_type c, size_type pos = npos) const {
1931     return find_last_of(&c, pos, 1);
1932   }
1933
1934   size_type find_first_not_of(const basic_fbstring& str,
1935                               size_type pos = 0) const {
1936     return find_first_not_of(str.data(), pos, str.size());
1937   }
1938
1939   size_type find_first_not_of(const value_type* s, size_type pos,
1940                               size_type n) const {
1941     if (pos < length()) {
1942       const_iterator
1943         i(begin() + pos),
1944         finish(end());
1945       for (; i != finish; ++i) {
1946         if (traits_type::find(s, n, *i) == 0) {
1947           return i - begin();
1948         }
1949       }
1950     }
1951     return npos;
1952   }
1953
1954   size_type find_first_not_of(const value_type* s,
1955                               size_type pos = 0) const {
1956     return find_first_not_of(s, pos, traits_type::length(s));
1957   }
1958
1959   size_type find_first_not_of(value_type c, size_type pos = 0) const {
1960     return find_first_not_of(&c, pos, 1);
1961   }
1962
1963   size_type find_last_not_of(const basic_fbstring& str,
1964                              size_type pos = npos) const {
1965     return find_last_not_of(str.data(), pos, str.length());
1966   }
1967
1968   size_type find_last_not_of(const value_type* s, size_type pos,
1969                              size_type n) const {
1970     if (!this->empty()) {
1971       pos = std::min(pos, size() - 1);
1972       const_iterator i(begin() + pos);
1973       for (;; --i) {
1974         if (traits_type::find(s, n, *i) == 0) {
1975           return i - begin();
1976         }
1977         if (i == begin()) break;
1978       }
1979     }
1980     return npos;
1981   }
1982
1983   size_type find_last_not_of(const value_type* s,
1984                              size_type pos = npos) const {
1985     return find_last_not_of(s, pos, traits_type::length(s));
1986   }
1987
1988   size_type find_last_not_of (value_type c, size_type pos = npos) const {
1989     return find_last_not_of(&c, pos, 1);
1990   }
1991
1992   basic_fbstring substr(size_type pos = 0, size_type n = npos) const {
1993     enforce(pos <= size(), std::__throw_out_of_range, "");
1994     return basic_fbstring(data() + pos, std::min(n, size() - pos));
1995   }
1996
1997   int compare(const basic_fbstring& str) const {
1998     // FIX due to Goncalo N M de Carvalho July 18, 2005
1999     return compare(0, size(), str);
2000   }
2001
2002   int compare(size_type pos1, size_type n1,
2003               const basic_fbstring& str) const {
2004     return compare(pos1, n1, str.data(), str.size());
2005   }
2006
2007   int compare(size_type pos1, size_type n1,
2008               const value_type* s) const {
2009     return compare(pos1, n1, s, traits_type::length(s));
2010   }
2011
2012   int compare(size_type pos1, size_type n1,
2013               const value_type* s, size_type n2) const {
2014     enforce(pos1 <= size(), std::__throw_out_of_range, "");
2015     procrustes(n1, size() - pos1);
2016     // The line below fixed by Jean-Francois Bastien, 04-23-2007. Thanks!
2017     const int r = traits_type::compare(pos1 + data(), s, std::min(n1, n2));
2018     return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
2019   }
2020
2021   int compare(size_type pos1, size_type n1,
2022               const basic_fbstring& str,
2023               size_type pos2, size_type n2) const {
2024     enforce(pos2 <= str.size(), std::__throw_out_of_range, "");
2025     return compare(pos1, n1, str.data() + pos2,
2026                    std::min(n2, str.size() - pos2));
2027   }
2028
2029   // Code from Jean-Francois Bastien (03/26/2007)
2030   int compare(const value_type* s) const {
2031     // Could forward to compare(0, size(), s, traits_type::length(s))
2032     // but that does two extra checks
2033     const size_type n1(size()), n2(traits_type::length(s));
2034     const int r = traits_type::compare(data(), s, std::min(n1, n2));
2035     return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
2036   }
2037
2038 private:
2039   // Data
2040   Storage store_;
2041 };
2042
2043 // non-member functions
2044 // C++11 21.4.8.1/2
2045 template <typename E, class T, class A, class S>
2046 inline
2047 basic_fbstring<E, T, A, S> operator+(const basic_fbstring<E, T, A, S>& lhs,
2048                                      const basic_fbstring<E, T, A, S>& rhs) {
2049
2050   basic_fbstring<E, T, A, S> result;
2051   result.reserve(lhs.size() + rhs.size());
2052   result.append(lhs).append(rhs);
2053   return std::move(result);
2054 }
2055
2056 // C++11 21.4.8.1/2
2057 template <typename E, class T, class A, class S>
2058 inline
2059 basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs,
2060                                      const basic_fbstring<E, T, A, S>& rhs) {
2061   return std::move(lhs.append(rhs));
2062 }
2063
2064 // C++11 21.4.8.1/3
2065 template <typename E, class T, class A, class S>
2066 inline
2067 basic_fbstring<E, T, A, S> operator+(const basic_fbstring<E, T, A, S>& lhs,
2068                                      basic_fbstring<E, T, A, S>&& rhs) {
2069   if (rhs.capacity() >= lhs.size() + rhs.size()) {
2070     // Good, at least we don't need to reallocate
2071     return std::move(rhs.insert(0, lhs));
2072   }
2073   // Meh, no go. Forward to operator+(const&, const&).
2074   auto const& rhsC = rhs;
2075   return lhs + rhsC;
2076 }
2077
2078 // C++11 21.4.8.1/4
2079 template <typename E, class T, class A, class S>
2080 inline
2081 basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs,
2082                                      basic_fbstring<E, T, A, S>&& rhs) {
2083   return std::move(lhs.append(rhs));
2084 }
2085
2086 template <typename E, class T, class A, class S>
2087 inline
2088 basic_fbstring<E, T, A, S> operator+(
2089   const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2090   const basic_fbstring<E, T, A, S>& rhs) {
2091   //
2092   basic_fbstring<E, T, A, S> result;
2093   const typename basic_fbstring<E, T, A, S>::size_type len =
2094     basic_fbstring<E, T, A, S>::traits_type::length(lhs);
2095   result.reserve(len + rhs.size());
2096   result.append(lhs, len).append(rhs);
2097   return result;
2098 }
2099
2100 template <typename E, class T, class A, class S>
2101 inline
2102 basic_fbstring<E, T, A, S> operator+(
2103   typename basic_fbstring<E, T, A, S>::value_type lhs,
2104   const basic_fbstring<E, T, A, S>& rhs) {
2105
2106   basic_fbstring<E, T, A, S> result;
2107   result.reserve(1 + rhs.size());
2108   result.push_back(lhs);
2109   result.append(rhs);
2110   return result;
2111 }
2112
2113 template <typename E, class T, class A, class S>
2114 inline
2115 basic_fbstring<E, T, A, S> operator+(
2116   const basic_fbstring<E, T, A, S>& lhs,
2117   const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2118
2119   typedef typename basic_fbstring<E, T, A, S>::size_type size_type;
2120   typedef typename basic_fbstring<E, T, A, S>::traits_type traits_type;
2121
2122   basic_fbstring<E, T, A, S> result;
2123   const size_type len = traits_type::length(rhs);
2124   result.reserve(lhs.size() + len);
2125   result.append(lhs).append(rhs, len);
2126   return result;
2127 }
2128
2129 template <typename E, class T, class A, class S>
2130 inline
2131 basic_fbstring<E, T, A, S> operator+(
2132   const basic_fbstring<E, T, A, S>& lhs,
2133   typename basic_fbstring<E, T, A, S>::value_type rhs) {
2134
2135   basic_fbstring<E, T, A, S> result;
2136   result.reserve(lhs.size() + 1);
2137   result.append(lhs);
2138   result.push_back(rhs);
2139   return result;
2140 }
2141
2142 template <typename E, class T, class A, class S>
2143 inline
2144 bool operator==(const basic_fbstring<E, T, A, S>& lhs,
2145                 const basic_fbstring<E, T, A, S>& rhs) {
2146   return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; }
2147
2148 template <typename E, class T, class A, class S>
2149 inline
2150 bool operator==(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2151                 const basic_fbstring<E, T, A, S>& rhs) {
2152   return rhs == lhs; }
2153
2154 template <typename E, class T, class A, class S>
2155 inline
2156 bool operator==(const basic_fbstring<E, T, A, S>& lhs,
2157                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2158   return lhs.compare(rhs) == 0; }
2159
2160 template <typename E, class T, class A, class S>
2161 inline
2162 bool operator!=(const basic_fbstring<E, T, A, S>& lhs,
2163                 const basic_fbstring<E, T, A, S>& rhs) {
2164   return !(lhs == rhs); }
2165
2166 template <typename E, class T, class A, class S>
2167 inline
2168 bool operator!=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2169                 const basic_fbstring<E, T, A, S>& rhs) {
2170   return !(lhs == rhs); }
2171
2172 template <typename E, class T, class A, class S>
2173 inline
2174 bool operator!=(const basic_fbstring<E, T, A, S>& lhs,
2175                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2176   return !(lhs == rhs); }
2177
2178 template <typename E, class T, class A, class S>
2179 inline
2180 bool operator<(const basic_fbstring<E, T, A, S>& lhs,
2181                const basic_fbstring<E, T, A, S>& rhs) {
2182   return lhs.compare(rhs) < 0; }
2183
2184 template <typename E, class T, class A, class S>
2185 inline
2186 bool operator<(const basic_fbstring<E, T, A, S>& lhs,
2187                const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2188   return lhs.compare(rhs) < 0; }
2189
2190 template <typename E, class T, class A, class S>
2191 inline
2192 bool operator<(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2193                const basic_fbstring<E, T, A, S>& rhs) {
2194   return rhs.compare(lhs) > 0; }
2195
2196 template <typename E, class T, class A, class S>
2197 inline
2198 bool operator>(const basic_fbstring<E, T, A, S>& lhs,
2199                const basic_fbstring<E, T, A, S>& rhs) {
2200   return rhs < lhs; }
2201
2202 template <typename E, class T, class A, class S>
2203 inline
2204 bool operator>(const basic_fbstring<E, T, A, S>& lhs,
2205                const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2206   return rhs < lhs; }
2207
2208 template <typename E, class T, class A, class S>
2209 inline
2210 bool operator>(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2211                const basic_fbstring<E, T, A, S>& rhs) {
2212   return rhs < lhs; }
2213
2214 template <typename E, class T, class A, class S>
2215 inline
2216 bool operator<=(const basic_fbstring<E, T, A, S>& lhs,
2217                 const basic_fbstring<E, T, A, S>& rhs) {
2218   return !(rhs < lhs); }
2219
2220 template <typename E, class T, class A, class S>
2221 inline
2222 bool operator<=(const basic_fbstring<E, T, A, S>& lhs,
2223                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2224   return !(rhs < lhs); }
2225
2226 template <typename E, class T, class A, class S>
2227 inline
2228 bool operator<=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2229                 const basic_fbstring<E, T, A, S>& rhs) {
2230   return !(rhs < lhs); }
2231
2232 template <typename E, class T, class A, class S>
2233 inline
2234 bool operator>=(const basic_fbstring<E, T, A, S>& lhs,
2235                 const basic_fbstring<E, T, A, S>& rhs) {
2236   return !(lhs < rhs); }
2237
2238 template <typename E, class T, class A, class S>
2239 inline
2240 bool operator>=(const basic_fbstring<E, T, A, S>& lhs,
2241                 const typename basic_fbstring<E, T, A, S>::value_type* rhs) {
2242   return !(lhs < rhs); }
2243
2244 template <typename E, class T, class A, class S>
2245 inline
2246 bool operator>=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
2247                 const basic_fbstring<E, T, A, S>& rhs) {
2248  return !(lhs < rhs);
2249 }
2250
2251 // C++11 21.4.8.8
2252 template <typename E, class T, class A, class S>
2253 void swap(basic_fbstring<E, T, A, S>& lhs, basic_fbstring<E, T, A, S>& rhs) {
2254   lhs.swap(rhs);
2255 }
2256
2257 // TODO: make this faster.
2258 template <typename E, class T, class A, class S>
2259 inline
2260 std::basic_istream<
2261   typename basic_fbstring<E, T, A, S>::value_type,
2262   typename basic_fbstring<E, T, A, S>::traits_type>&
2263   operator>>(
2264     std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
2265     typename basic_fbstring<E, T, A, S>::traits_type>& is,
2266     basic_fbstring<E, T, A, S>& str) {
2267   typename std::basic_istream<E, T>::sentry sentry(is);
2268   typedef std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
2269                              typename basic_fbstring<E, T, A, S>::traits_type>
2270                         __istream_type;
2271   typedef typename __istream_type::ios_base __ios_base;
2272   size_t extracted = 0;
2273   auto err = __ios_base::goodbit;
2274   if (sentry) {
2275     auto n = is.width();
2276     if (n == 0) {
2277       n = str.max_size();
2278     }
2279     str.erase();
2280     auto got = is.rdbuf()->sgetc();
2281     for (; extracted != n && got != T::eof() && !isspace(got); ++extracted) {
2282       // Whew. We get to store this guy
2283       str.push_back(got);
2284       got = is.rdbuf()->snextc();
2285     }
2286     if (got == T::eof()) {
2287       err |= __ios_base::eofbit;
2288       is.width(0);
2289     }
2290   }
2291   if (!extracted) {
2292     err |= __ios_base::failbit;
2293   }
2294   if (err) {
2295     is.setstate(err);
2296   }
2297   return is;
2298 }
2299
2300 template <typename E, class T, class A, class S>
2301 inline
2302 std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type,
2303                    typename basic_fbstring<E, T, A, S>::traits_type>&
2304 operator<<(
2305   std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type,
2306   typename basic_fbstring<E, T, A, S>::traits_type>& os,
2307     const basic_fbstring<E, T, A, S>& str) {
2308   os.write(str.data(), str.size());
2309   return os;
2310 }
2311
2312 #ifndef _LIBSTDCXX_FBSTRING
2313
2314 template <typename E, class T, class A, class S>
2315 inline
2316 std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
2317                    typename basic_fbstring<E, T, A, S>::traits_type>&
2318 getline(
2319   std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
2320   typename basic_fbstring<E, T, A, S>::traits_type>& is,
2321     basic_fbstring<E, T, A, S>& str,
2322   typename basic_fbstring<E, T, A, S>::value_type delim) {
2323   // Use the nonstandard getdelim()
2324   char * buf = NULL;
2325   size_t size = 0;
2326   for (;;) {
2327     // This looks quadratic but it really depends on realloc
2328     auto const newSize = size + 128;
2329     buf = static_cast<char*>(checkedRealloc(buf, newSize));
2330     is.getline(buf + size, newSize - size, delim);
2331     if (is.bad() || is.eof() || !is.fail()) {
2332       // done by either failure, end of file, or normal read
2333       size += std::strlen(buf + size);
2334       break;
2335     }
2336     // Here we have failed due to too short a buffer
2337     // Minus one to discount the terminating '\0'
2338     size = newSize - 1;
2339     assert(buf[size] == 0);
2340     // Clear the error so we can continue reading
2341     is.clear();
2342   }
2343   basic_fbstring<E, T, A, S> result(buf, size, size + 1,
2344                                     AcquireMallocatedString());
2345   result.swap(str);
2346   return is;
2347 }
2348
2349 template <typename E, class T, class A, class S>
2350 inline
2351 std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
2352                    typename basic_fbstring<E, T, A, S>::traits_type>&
2353 getline(
2354   std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
2355   typename basic_fbstring<E, T, A, S>::traits_type>& is,
2356   basic_fbstring<E, T, A, S>& str) {
2357   // Just forward to the version with a delimiter
2358   return getline(is, str, '\n');
2359 }
2360
2361 #endif
2362
2363 template <typename E1, class T, class A, class S>
2364 const typename basic_fbstring<E1, T, A, S>::size_type
2365 basic_fbstring<E1, T, A, S>::npos =
2366               static_cast<typename basic_fbstring<E1, T, A, S>::size_type>(-1);
2367
2368 #ifndef _LIBSTDCXX_FBSTRING
2369 // basic_string compatibility routines
2370
2371 template <typename E, class T, class A, class S>
2372 inline
2373 bool operator==(const basic_fbstring<E, T, A, S>& lhs,
2374                 const std::string& rhs) {
2375   return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) == 0;
2376 }
2377
2378 template <typename E, class T, class A, class S>
2379 inline
2380 bool operator==(const std::string& lhs,
2381                 const basic_fbstring<E, T, A, S>& rhs) {
2382   return rhs == lhs;
2383 }
2384
2385 template <typename E, class T, class A, class S>
2386 inline
2387 bool operator!=(const basic_fbstring<E, T, A, S>& lhs,
2388                 const std::string& rhs) {
2389   return !(lhs == rhs);
2390 }
2391
2392 template <typename E, class T, class A, class S>
2393 inline
2394 bool operator!=(const std::string& lhs,
2395                 const basic_fbstring<E, T, A, S>& rhs) {
2396   return !(lhs == rhs);
2397 }
2398
2399 #if !defined(_LIBSTDCXX_FBSTRING)
2400 typedef basic_fbstring<char> fbstring;
2401 #endif
2402
2403 // fbstring is relocatable
2404 template <class T, class R, class A, class S>
2405 FOLLY_ASSUME_RELOCATABLE(basic_fbstring<T, R, A, S>);
2406
2407 #else
2408 _GLIBCXX_END_NAMESPACE_VERSION
2409 #endif
2410
2411 } // namespace folly
2412
2413 #pragma GCC diagnostic pop
2414
2415 #ifndef _LIBSTDCXX_FBSTRING
2416
2417 namespace std {
2418 template <>
2419 struct hash< ::folly::fbstring> {
2420   size_t operator()(const ::folly::fbstring& s) const {
2421     return ::folly::hash::fnv32_buf(s.data(), s.size());
2422   }
2423 };
2424 }
2425
2426 #endif // _LIBSTDCXX_FBSTRING
2427
2428 #undef FBSTRING_DISABLE_ADDRESS_SANITIZER
2429 #undef throw
2430 #undef FBSTRING_LIKELY
2431 #undef FBSTRING_UNLIKELY
2432
2433 #endif // FOLLY_BASE_FBSTRING_H_