proxygen
folly::fbstring_core< Char > Class Template Reference

#include <FBString.h>

Classes

struct  MediumLarge
 
struct  RefCounted
 

Public Member Functions

 fbstring_core () noexcept
 
 fbstring_core (const fbstring_core &rhs)
 
 fbstring_core (fbstring_core &&goner) noexcept
 
 fbstring_core (const Char *const data, const size_t size, bool disableSSO=false)
 
 ~fbstring_core () noexcept
 
 fbstring_core (Char *const data, const size_t size, const size_t allocatedSize, AcquireMallocatedString)
 
void swap (fbstring_core &rhs)
 
const Char * data () const
 
Char * mutableData ()
 
const Char * c_str () const
 
void shrink (const size_t delta)
 
FOLLY_MALLOC_NOINLINE void reserve (size_t minCapacity, bool disableSSO=false)
 
Char * expandNoinit (const size_t delta, bool expGrowth=false, bool disableSSO=false)
 
void push_back (Char c)
 
size_t size () const
 
size_t capacity () const
 
bool isShared () const
 

Static Protected Attributes

static constexpr auto kIsLittleEndian
 

Private Types

enum  Category : category_type { Category::isSmall = 0, Category::isMedium = kIsLittleEndian ? 0x80 : 0x2, Category::isLarge = kIsLittleEndian ? 0x40 : 0x1 }
 
typedef uint8_t category_type
 

Private Member Functions

fbstring_coreoperator= (const fbstring_core &rhs)
 
void reset ()
 
FOLLY_MALLOC_NOINLINE void destroyMediumLarge () noexcept
 
Category category () const
 
size_t smallSize () const
 
void setSmallSize (size_t s)
 
void copySmall (const fbstring_core &)
 
void copyMedium (const fbstring_core &)
 
void copyLarge (const fbstring_core &)
 
void initSmall (const Char *data, size_t size)
 
void initMedium (const Char *data, size_t size)
 
void initLarge (const Char *data, size_t size)
 
void reserveSmall (size_t minCapacity, bool disableSSO)
 
void reserveMedium (size_t minCapacity)
 
void reserveLarge (size_t minCapacity)
 
void shrinkSmall (size_t delta)
 
void shrinkMedium (size_t delta)
 
void shrinkLarge (size_t delta)
 
void unshare (size_t minCapacity=0)
 
Char * mutableDataLarge ()
 

Private Attributes

union {
   uint8_t   bytes_ [sizeof(MediumLarge)]
 
   Char   small_ [sizeof(MediumLarge)/sizeof(Char)]
 
   MediumLarge   ml_
 
}; 
 

Static Private Attributes

static constexpr size_t lastChar = sizeof(MediumLarge) - 1
 
static constexpr size_t maxSmallSize = lastChar / sizeof(Char)
 
static constexpr size_t maxMediumSize = 254 / sizeof(Char)
 
static constexpr uint8_t categoryExtractMask = kIsLittleEndian ? 0xC0 : 0x3
 
static constexpr size_t kCategoryShift = (sizeof(size_t) - 1) * 8
 
static constexpr size_t capacityExtractMask
 

Detailed Description

template<class Char>
class folly::fbstring_core< Char >

This is the core of the string. The code should work on 32- and 64-bit and both big- and little-endianan architectures with any Char size.

The storage is selected as follows (assuming we store one-byte characters on a 64-bit machine): (a) "small" strings between 0 and 23 chars are stored in-situ without allocation (the rightmost byte stores the size); (b) "medium" strings from 24 through 254 chars are stored in malloc-allocated memory that is copied eagerly; (c) "large" strings of 255 chars and above are stored in a similar structure as medium arrays, except that the string is reference-counted and copied lazily. the reference count is allocated right before the character array.

The discriminator between these three strategies sits in two bits of the rightmost char of the storage:

  • If neither is set, then the string is small. Its length is represented by the lower-order bits on little-endian or the high-order bits on big-endian of that rightmost character. The value of these six bits is maxSmallSize - size, so this quantity must be subtracted from maxSmallSize to compute the size of the string (see smallSize()). This scheme ensures that when size ==maxSmallSize`, the last byte in the storage is \0. This way, storage will be a null-terminated sequence of bytes, even if all 23 bytes of data are used on a 64-bit architecture. This enables c_str() and data() to simply return a pointer to the storage.
  • If the MSb is set, the string is medium width.
  • If the second MSb is set, then the string is large. On little-endian, these 2 bits are the 2 MSbs of MediumLarge::capacity_, while on big-endian, these 2 bits are the 2 LSbs. This keeps both little-endian and big-endian fbstring_core equivalent with merely different ops used to extract capacity/category.

Definition at line 327 of file FBString.h.

Member Typedef Documentation

template<class Char>
typedef uint8_t folly::fbstring_core< Char >::category_type
private

Definition at line 619 of file FBString.h.

Member Enumeration Documentation

template<class Char>
enum folly::fbstring_core::Category : category_type
strongprivate
Enumerator
isSmall 
isMedium 
isLarge 

Definition at line 621 of file FBString.h.

621  : category_type {
622  isSmall = 0,
623  isMedium = kIsLittleEndian ? 0x80 : 0x2,
624  isLarge = kIsLittleEndian ? 0x40 : 0x1,
625  };
uint8_t category_type
Definition: FBString.h:619
static constexpr auto kIsLittleEndian
Definition: FBString.h:337

Constructor & Destructor Documentation

template<class Char>
folly::fbstring_core< Char >::fbstring_core ( )
inlinenoexcept

Definition at line 341 of file FBString.h.

341  {
342  reset();
343  }
template<class Char>
folly::fbstring_core< Char >::fbstring_core ( const fbstring_core< Char > &  rhs)
inline

Definition at line 345 of file FBString.h.

345  {
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  }
void copyLarge(const fbstring_core &)
Definition: FBString.h:741
void copyMedium(const fbstring_core &)
Definition: FBString.h:726
const Char * data() const
Definition: FBString.h:432
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
size_t size() const
Definition: FBString.h:493
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
void copySmall(const fbstring_core &)
Definition: FBString.h:707
template<class Char>
folly::fbstring_core< Char >::fbstring_core ( fbstring_core< Char > &&  goner)
inlinenoexcept

Definition at line 364 of file FBString.h.

364  {
365  // Take goner's guts
366  ml_ = goner.ml_;
367  // Clean goner's carcass
368  goner.reset();
369  }
MediumLarge ml_
Definition: FBString.h:651
template<class Char>
folly::fbstring_core< Char >::fbstring_core ( const Char *const  data,
const size_t  size,
bool  disableSSO = false 
)
inline

Definition at line 371 of file FBString.h.

374  {
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  }
void initSmall(const Char *data, size_t size)
Definition: FBString.h:751
static constexpr size_t maxSmallSize
Definition: FBString.h:655
const Char * data() const
Definition: FBString.h:432
void initLarge(const Char *data, size_t size)
Definition: FBString.h:814
void initMedium(const Char *data, size_t size)
Definition: FBString.h:798
size_t size() const
Definition: FBString.h:493
static constexpr size_t maxMediumSize
Definition: FBString.h:656
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
template<class Char>
folly::fbstring_core< Char >::~fbstring_core ( )
inlinenoexcept

Definition at line 387 of file FBString.h.

387  {
388  if (category() == Category::isSmall) {
389  return;
390  }
392  }
Category category() const
Definition: FBString.h:627
FOLLY_MALLOC_NOINLINE void destroyMediumLarge() noexcept
Definition: FBString.h:539
template<class Char>
folly::fbstring_core< Char >::fbstring_core ( Char *const  data,
const size_t  size,
const size_t  allocatedSize,
AcquireMallocatedString   
)
inline

Definition at line 401 of file FBString.h.

405  {
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  }
const Char * data() const
Definition: FBString.h:432
size_t size() const
Definition: FBString.h:493
void free()
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
void setCapacity(size_t cap, Category cat)
Definition: FBString.h:641
MediumLarge ml_
Definition: FBString.h:651

Member Function Documentation

template<class Char>
const Char* folly::fbstring_core< Char >::c_str ( ) const
inline

Definition at line 448 of file FBString.h.

448  {
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  }
void * ptr
Category category() const
Definition: FBString.h:627
MediumLarge ml_
Definition: FBString.h:651
Char small_[sizeof(MediumLarge)/sizeof(Char)]
Definition: FBString.h:650
template<class Char>
size_t folly::fbstring_core< Char >::capacity ( ) const
inline

Definition at line 509 of file FBString.h.

Referenced by folly::operator+().

509  {
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  }
static size_t refs(Char *p)
Definition: FBString.h:563
static constexpr size_t maxSmallSize
Definition: FBString.h:655
Category category() const
Definition: FBString.h:627
MediumLarge ml_
Definition: FBString.h:651
template<class Char>
Category folly::fbstring_core< Char >::category ( ) const
inlineprivate

Definition at line 627 of file FBString.h.

Referenced by folly::fbstring_core< char >::fbstring_core().

627  {
628  // works for both big-endian and little-endian
629  return static_cast<Category>(bytes_[lastChar] & categoryExtractMask);
630  }
static constexpr size_t lastChar
Definition: FBString.h:654
static constexpr uint8_t categoryExtractMask
Definition: FBString.h:657
uint8_t bytes_[sizeof(MediumLarge)]
Definition: FBString.h:649
template<class Char >
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::copyLarge ( const fbstring_core< Char > &  rhs)
inlineprivate

Definition at line 741 of file FBString.h.

References FBSTRING_ASSERT, folly::fbstring_core< Char >::ml_, folly::size(), and folly::fbstring_core< Char >::size().

742  {
743  // Large strings are just refcounted
744  ml_ = rhs.ml_;
746  FBSTRING_ASSERT(category() == Category::isLarge && size() == rhs.size());
747 }
static void incrementRefs(Char *p)
Definition: FBString.h:567
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
Category category() const
Definition: FBString.h:627
size_t size() const
Definition: FBString.h:493
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
MediumLarge ml_
Definition: FBString.h:651
template<class Char >
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::copyMedium ( const fbstring_core< Char > &  rhs)
inlineprivate

Definition at line 726 of file FBString.h.

References testing::gmock_generated_actions_test::Char(), folly::checkedMalloc(), folly::fbstring_core< Char >::MediumLarge::data_, FBSTRING_ASSERT, folly::goodMallocSize(), folly::fbstring_core< Char >::ml_, folly::fbstring_detail::podCopy(), and folly::fbstring_core< Char >::MediumLarge::size_.

727  {
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);
738 }
void * checkedMalloc(size_t size)
Definition: Malloc.h:227
void podCopy(const Pod *b, const Pod *e, Pod *d)
Definition: FBString.h:174
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
Category category() const
Definition: FBString.h:627
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
void setCapacity(size_t cap, Category cat)
Definition: FBString.h:641
MediumLarge ml_
Definition: FBString.h:651
size_t goodMallocSize(size_t minSize) noexcept
Definition: Malloc.h:201
template<class Char >
void folly::fbstring_core< Char >::copySmall ( const fbstring_core< Char > &  rhs)
inlineprivate

Definition at line 707 of file FBString.h.

References data_, FBSTRING_ASSERT, folly::fbstring_core< Char >::ml_, folly::size(), and folly::fbstring_core< Char >::size().

707  {
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 }
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
Category category() const
Definition: FBString.h:627
size_t size() const
Definition: FBString.h:493
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
MediumLarge ml_
Definition: FBString.h:651
StringPiece data_
template<class Char>
const Char* folly::fbstring_core< Char >::data ( ) const
inline

Definition at line 432 of file FBString.h.

Referenced by folly::fbstring_core< char >::fbstring_core().

432  {
433  return c_str();
434  }
const Char * c_str() const
Definition: FBString.h:448
template<class Char>
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::destroyMediumLarge ( )
inlineprivatenoexcept

Definition at line 539 of file FBString.h.

539  {
540  auto const c = category();
542  if (c == Category::isMedium) {
543  free(ml_.data_);
544  } else {
546  }
547  }
static void decrementRefs(Char *p)
Definition: FBString.h:571
Category category() const
Definition: FBString.h:627
void free()
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
MediumLarge ml_
Definition: FBString.h:651
char c
template<class Char >
Char * folly::fbstring_core< Char >::expandNoinit ( const size_t  delta,
bool  expGrowth = false,
bool  disableSSO = false 
)
inline

Definition at line 943 of file FBString.h.

References FBSTRING_ASSERT, FBSTRING_LIKELY, FBSTRING_UNLIKELY, max, reserve(), and folly::size().

946  {
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
971  ml_.size_ = newSz;
972  ml_.data_[newSz] = '\0';
973  FBSTRING_ASSERT(size() == newSz);
974  return ml_.data_ + sz;
975 }
void reserveSmall(size_t minCapacity, bool disableSSO)
Definition: FBString.h:910
size_t smallSize() const
Definition: FBString.h:667
LogLevel max
Definition: LogLevel.cpp:31
#define FBSTRING_UNLIKELY(x)
Definition: FBString.h:75
static constexpr size_t maxSmallSize
Definition: FBString.h:655
void setSmallSize(size_t s)
Definition: FBString.h:675
#define FBSTRING_LIKELY(x)
Definition: FBString.h:74
Category category() const
Definition: FBString.h:627
size_t size() const
Definition: FBString.h:493
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
size_t capacity() const
Definition: FBString.h:509
MediumLarge ml_
Definition: FBString.h:651
Char small_[sizeof(MediumLarge)/sizeof(Char)]
Definition: FBString.h:650
FOLLY_MALLOC_NOINLINE void reserve(size_t minCapacity, bool disableSSO=false)
Definition: FBString.h:467
template<class Char>
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::initLarge ( const Char *  data,
size_t  size 
)
inlineprivate

Definition at line 814 of file FBString.h.

References folly::size().

816  {
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 }
const Char * data() const
Definition: FBString.h:432
static RefCounted * create(size_t *size)
Definition: FBString.h:580
size_t size() const
Definition: FBString.h:493
void setCapacity(size_t cap, Category cat)
Definition: FBString.h:641
MediumLarge ml_
Definition: FBString.h:651
template<class Char>
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::initMedium ( const Char *  data,
size_t  size 
)
inlineprivate

Definition at line 798 of file FBString.h.

References testing::gmock_generated_actions_test::Char(), folly::checkedMalloc(), FBSTRING_LIKELY, folly::goodMallocSize(), folly::fbstring_detail::podCopy(), and folly::size().

800  {
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)) {
807  }
808  ml_.size_ = size;
809  ml_.setCapacity(allocSize / sizeof(Char) - 1, Category::isMedium);
810  ml_.data_[size] = '\0';
811 }
void * checkedMalloc(size_t size)
Definition: Malloc.h:227
void podCopy(const Pod *b, const Pod *e, Pod *d)
Definition: FBString.h:174
const Char * data() const
Definition: FBString.h:432
#define FBSTRING_LIKELY(x)
Definition: FBString.h:74
size_t size() const
Definition: FBString.h:493
void setCapacity(size_t cap, Category cat)
Definition: FBString.h:641
MediumLarge ml_
Definition: FBString.h:651
size_t goodMallocSize(size_t minSize) noexcept
Definition: Malloc.h:201
template<class Char>
void folly::fbstring_core< Char >::initSmall ( const Char *  data,
size_t  size 
)
inlineprivate

Definition at line 751 of file FBString.h.

References testing::gmock_generated_actions_test::Char(), data, FOLLY_FALLTHROUGH, and folly::fbstring_detail::podCopy().

753  {
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) {
792  }
793  }
795 }
void podCopy(const Pod *b, const Pod *e, Pod *d)
Definition: FBString.h:174
const Char * data() const
Definition: FBString.h:432
void setSmallSize(size_t s)
Definition: FBString.h:675
size_t size() const
Definition: FBString.h:493
MediumLarge ml_
Definition: FBString.h:651
Char small_[sizeof(MediumLarge)/sizeof(Char)]
Definition: FBString.h:650
#define FOLLY_FALLTHROUGH
Definition: CppAttributes.h:63
template<class Char>
bool folly::fbstring_core< Char >::isShared ( ) const
inline

Definition at line 527 of file FBString.h.

template<class Char>
Char* folly::fbstring_core< Char >::mutableData ( )
inline

Definition at line 436 of file FBString.h.

436  {
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  }
Char * mutableDataLarge()
Definition: FBString.h:844
Category category() const
Definition: FBString.h:627
MediumLarge ml_
Definition: FBString.h:651
Char small_[sizeof(MediumLarge)/sizeof(Char)]
Definition: FBString.h:650
template<class Char >
Char * folly::fbstring_core< Char >::mutableDataLarge ( )
inlineprivate

Definition at line 844 of file FBString.h.

References FBSTRING_ASSERT, and refs.

844  {
846  if (RefCounted::refs(ml_.data_) > 1) { // Ensure unique.
847  unshare();
848  }
849  return ml_.data_;
850 }
static size_t refs(Char *p)
Definition: FBString.h:563
void unshare(size_t minCapacity=0)
Definition: FBString.h:827
Category category() const
Definition: FBString.h:627
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
MediumLarge ml_
Definition: FBString.h:651
template<class Char>
fbstring_core& folly::fbstring_core< Char >::operator= ( const fbstring_core< Char > &  rhs)
private
template<class Char>
void folly::fbstring_core< Char >::push_back ( Char  c)
inline

Definition at line 489 of file FBString.h.

489  {
490  *expandNoinit(1, /* expGrowth = */ true) = c;
491  }
Char * expandNoinit(const size_t delta, bool expGrowth=false, bool disableSSO=false)
Definition: FBString.h:943
char c
template<class Char>
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::reserve ( size_t  minCapacity,
bool  disableSSO = false 
)
inline

Definition at line 467 of file FBString.h.

Referenced by folly::fbstring_core< Char >::reserveMedium().

467  {
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  }
void reserveSmall(size_t minCapacity, bool disableSSO)
Definition: FBString.h:910
Category category() const
Definition: FBString.h:627
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
size_t capacity() const
Definition: FBString.h:509
void reserveMedium(size_t minCapacity)
Definition: FBString.h:877
void reserveLarge(size_t minCapacity)
Definition: FBString.h:853
template<class Char >
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::reserveLarge ( size_t  minCapacity)
inlineprivate

Definition at line 853 of file FBString.h.

References FBSTRING_ASSERT, and refs.

854  {
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 }
static size_t refs(Char *p)
Definition: FBString.h:563
static RefCounted * reallocate(Char *const data, const size_t currentSize, const size_t currentCapacity, size_t *newCapacity)
Definition: FBString.h:598
void unshare(size_t minCapacity=0)
Definition: FBString.h:827
Category category() const
Definition: FBString.h:627
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
size_t capacity() const
Definition: FBString.h:509
void setCapacity(size_t cap, Category cat)
Definition: FBString.h:641
MediumLarge ml_
Definition: FBString.h:651
template<class Char >
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::reserveMedium ( size_t  minCapacity)
inlineprivate

Definition at line 877 of file FBString.h.

References testing::gmock_generated_actions_test::Char(), folly::fbstring_core< Char >::MediumLarge::data_, FBSTRING_ASSERT, folly::goodMallocSize(), folly::fbstring_core< Char >::ml_, folly::fbstring_detail::podCopy(), folly::fbstring_core< Char >::reserve(), folly::fbstring_core< Char >::MediumLarge::size_, folly::smartRealloc(), and folly::fbstring_core< Char >::swap().

878  {
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 }
void podCopy(const Pod *b, const Pod *e, Pod *d)
Definition: FBString.h:174
fbstring_core() noexcept
Definition: FBString.h:341
Category category() const
Definition: FBString.h:627
static constexpr size_t maxMediumSize
Definition: FBString.h:656
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
size_t capacity() const
Definition: FBString.h:509
void setCapacity(size_t cap, Category cat)
Definition: FBString.h:641
void * smartRealloc(void *p, const size_t currentSize, const size_t currentCapacity, const size_t newCapacity)
Definition: Malloc.h:261
MediumLarge ml_
Definition: FBString.h:651
size_t goodMallocSize(size_t minSize) noexcept
Definition: Malloc.h:201
template<class Char >
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::reserveSmall ( size_t  minCapacity,
bool  disableSSO 
)
inlineprivate

Definition at line 910 of file FBString.h.

References testing::gmock_generated_actions_test::Char(), folly::checkedMalloc(), FBSTRING_ASSERT, folly::goodMallocSize(), folly::fbstring_detail::podCopy(), and folly::size().

912  {
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.
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 }
void * checkedMalloc(size_t size)
Definition: Malloc.h:227
size_t smallSize() const
Definition: FBString.h:667
void podCopy(const Pod *b, const Pod *e, Pod *d)
Definition: FBString.h:174
static constexpr size_t maxSmallSize
Definition: FBString.h:655
static RefCounted * create(size_t *size)
Definition: FBString.h:580
Category category() const
Definition: FBString.h:627
size_t size() const
Definition: FBString.h:493
static constexpr size_t maxMediumSize
Definition: FBString.h:656
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
size_t capacity() const
Definition: FBString.h:509
void setCapacity(size_t cap, Category cat)
Definition: FBString.h:641
MediumLarge ml_
Definition: FBString.h:651
Char small_[sizeof(MediumLarge)/sizeof(Char)]
Definition: FBString.h:650
size_t goodMallocSize(size_t minSize) noexcept
Definition: Malloc.h:201
template<class Char>
void folly::fbstring_core< Char >::reset ( )
inlineprivate

Definition at line 535 of file FBString.h.

535  {
536  setSmallSize(0);
537  }
void setSmallSize(size_t s)
Definition: FBString.h:675
template<class Char>
void folly::fbstring_core< Char >::setSmallSize ( size_t  s)
inlineprivate

Definition at line 675 of file FBString.h.

675  {
676  // Warning: this should work with uninitialized strings too,
677  // so don't assume anything about the previous value of
678  // small_[maxSmallSize].
680  constexpr auto shift = kIsLittleEndian ? 0 : 2;
681  small_[maxSmallSize] = char((maxSmallSize - s) << shift);
682  small_[s] = '\0';
684  }
static constexpr size_t maxSmallSize
Definition: FBString.h:655
Category category() const
Definition: FBString.h:627
size_t size() const
Definition: FBString.h:493
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
static set< string > s
static constexpr auto kIsLittleEndian
Definition: FBString.h:337
Char small_[sizeof(MediumLarge)/sizeof(Char)]
Definition: FBString.h:650
template<class Char>
void folly::fbstring_core< Char >::shrink ( const size_t  delta)
inline

Definition at line 455 of file FBString.h.

455  {
456  if (category() == Category::isSmall) {
457  shrinkSmall(delta);
458  } else if (
460  shrinkMedium(delta);
461  } else {
462  shrinkLarge(delta);
463  }
464  }
void shrinkMedium(size_t delta)
Definition: FBString.h:985
static size_t refs(Char *p)
Definition: FBString.h:563
void shrinkLarge(size_t delta)
Definition: FBString.h:994
Category category() const
Definition: FBString.h:627
void shrinkSmall(size_t delta)
Definition: FBString.h:978
MediumLarge ml_
Definition: FBString.h:651
template<class Char >
void folly::fbstring_core< Char >::shrinkLarge ( size_t  delta)
inlineprivate

Definition at line 994 of file FBString.h.

References FBSTRING_ASSERT, and folly::fbstring_core< Char >::swap().

994  {
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 }
fbstring_core() noexcept
Definition: FBString.h:341
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
MediumLarge ml_
Definition: FBString.h:651
template<class Char >
void folly::fbstring_core< Char >::shrinkMedium ( size_t  delta)
inlineprivate

Definition at line 985 of file FBString.h.

References FBSTRING_ASSERT.

985  {
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 }
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
MediumLarge ml_
Definition: FBString.h:651
template<class Char >
void folly::fbstring_core< Char >::shrinkSmall ( size_t  delta)
inlineprivate

Definition at line 978 of file FBString.h.

References FBSTRING_ASSERT.

978  {
979  // Check for underflow
980  FBSTRING_ASSERT(delta <= smallSize());
981  setSmallSize(smallSize() - delta);
982 }
size_t smallSize() const
Definition: FBString.h:667
void setSmallSize(size_t s)
Definition: FBString.h:675
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
template<class Char>
size_t folly::fbstring_core< Char >::size ( ) const
inline

Definition at line 493 of file FBString.h.

Referenced by folly::fbstring_core< Char >::copyLarge(), folly::fbstring_core< Char >::copySmall(), folly::fbstring_core< char >::fbstring_core(), and folly::operator+().

493  {
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  }
size_t smallSize() const
Definition: FBString.h:667
PskType type
static constexpr size_t maxSmallSize
Definition: FBString.h:655
Category category() const
Definition: FBString.h:627
static constexpr auto kIsLittleEndian
Definition: FBString.h:337
MediumLarge ml_
Definition: FBString.h:651
Char small_[sizeof(MediumLarge)/sizeof(Char)]
Definition: FBString.h:650
template<class Char>
size_t folly::fbstring_core< Char >::smallSize ( ) const
inlineprivate

Definition at line 667 of file FBString.h.

667  {
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  }
static constexpr size_t maxSmallSize
Definition: FBString.h:655
Category category() const
Definition: FBString.h:627
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
static constexpr auto kIsLittleEndian
Definition: FBString.h:337
Char small_[sizeof(MediumLarge)/sizeof(Char)]
Definition: FBString.h:650
template<class Char>
void folly::fbstring_core< Char >::swap ( fbstring_core< Char > &  rhs)
inline

Definition at line 425 of file FBString.h.

Referenced by folly::fbstring_core< Char >::reserveMedium(), and folly::fbstring_core< Char >::shrinkLarge().

425  {
426  auto const t = ml_;
427  ml_ = rhs.ml_;
428  rhs.ml_ = t;
429  }
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
MediumLarge ml_
Definition: FBString.h:651
template<class Char >
FOLLY_MALLOC_NOINLINE void folly::fbstring_core< Char >::unshare ( size_t  minCapacity = 0)
inlineprivate

Definition at line 827 of file FBString.h.

References FBSTRING_ASSERT, max, and folly::fbstring_detail::podCopy().

828  {
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_);
838  ml_.data_ = newRC->data_;
839  ml_.setCapacity(effectiveCapacity, Category::isLarge);
840  // size_ remains unchanged.
841 }
static void decrementRefs(Char *p)
Definition: FBString.h:571
LogLevel max
Definition: LogLevel.cpp:31
void podCopy(const Pod *b, const Pod *e, Pod *d)
Definition: FBString.h:174
static RefCounted * create(size_t *size)
Definition: FBString.h:580
Category category() const
Definition: FBString.h:627
#define FBSTRING_ASSERT(expr)
Definition: FBString.h:64
void setCapacity(size_t cap, Category cat)
Definition: FBString.h:641
MediumLarge ml_
Definition: FBString.h:651

Member Data Documentation

union { ... }
template<class Char>
uint8_t folly::fbstring_core< Char >::bytes_[sizeof(MediumLarge)]

Definition at line 649 of file FBString.h.

template<class Char>
constexpr size_t folly::fbstring_core< Char >::capacityExtractMask
staticprivate
Initial value:

Definition at line 659 of file FBString.h.

template<class Char>
constexpr uint8_t folly::fbstring_core< Char >::categoryExtractMask = kIsLittleEndian ? 0xC0 : 0x3
staticprivate

Definition at line 657 of file FBString.h.

template<class Char>
constexpr size_t folly::fbstring_core< Char >::kCategoryShift = (sizeof(size_t) - 1) * 8
staticprivate

Definition at line 658 of file FBString.h.

template<class Char>
constexpr auto folly::fbstring_core< Char >::kIsLittleEndian
staticprotected
Initial value:
=
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__

Definition at line 337 of file FBString.h.

template<class Char>
constexpr size_t folly::fbstring_core< Char >::lastChar = sizeof(MediumLarge) - 1
staticprivate

Definition at line 654 of file FBString.h.

template<class Char>
constexpr size_t folly::fbstring_core< Char >::maxMediumSize = 254 / sizeof(Char)
staticprivate

Definition at line 656 of file FBString.h.

template<class Char>
constexpr size_t folly::fbstring_core< Char >::maxSmallSize = lastChar / sizeof(Char)
staticprivate

Definition at line 655 of file FBString.h.

template<class Char>
Char folly::fbstring_core< Char >::small_[sizeof(MediumLarge)/sizeof(Char)]

Definition at line 650 of file FBString.h.


The documentation for this class was generated from the following file: