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