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