Commit aafcc64b authored by Giuseppe Ottaviano's avatar Giuseppe Ottaviano Committed by Facebook Github Bot 7

fbstring: Make SSO disabling and insertImplDiscr implementation simpler

Summary:Instead of using preprocessor to disable SSO, use a default argument. Also
reimplement `insertImplDiscr` to mirror `insertImpl`.

Reviewed By: philippv

Differential Revision: D3130901

fb-gh-sync-id: a5b0ba97b3c7d91323be01ab617ca9b09dbb0fd2
fbshipit-source-id: a5b0ba97b3c7d91323be01ab617ca9b09dbb0fd2
parent 0d1a8a82
...@@ -122,7 +122,9 @@ namespace folly { ...@@ -122,7 +122,9 @@ namespace folly {
// that would break ABI-compatibility and wouldn't allow linking code // that would break ABI-compatibility and wouldn't allow linking code
// compiled with this flag with code compiled without. // compiled with this flag with code compiled without.
#ifdef FBSTRING_SANITIZE_ADDRESS #ifdef FBSTRING_SANITIZE_ADDRESS
# define FBSTRING_DISABLE_SMALL_STRING_OPTIMIZATION # define FBSTRING_DISABLE_SSO true
#else
# define FBSTRING_DISABLE_SSO false
#endif #endif
namespace fbstring_detail { namespace fbstring_detail {
...@@ -353,7 +355,9 @@ public: ...@@ -353,7 +355,9 @@ public:
goner.reset(); goner.reset();
} }
fbstring_core(const Char *const data, const size_t size) { fbstring_core(const Char *const data,
const size_t size,
bool disableSSO = FBSTRING_DISABLE_SSO) {
#ifndef NDEBUG #ifndef NDEBUG
#ifndef _LIBSTDCXX_FBSTRING #ifndef _LIBSTDCXX_FBSTRING
SCOPE_EXIT { SCOPE_EXIT {
...@@ -363,9 +367,8 @@ public: ...@@ -363,9 +367,8 @@ public:
#endif #endif
#endif #endif
#ifndef FBSTRING_DISABLE_SMALL_STRING_OPTIMIZATION
// Simplest case first: small strings are bitblitted // Simplest case first: small strings are bitblitted
if (size <= maxSmallSize) { if (!disableSSO && size <= maxSmallSize) {
// Layout is: Char* data_, size_t size_, size_t capacity_ // Layout is: Char* data_, size_t size_, size_t capacity_
static_assert(sizeof(*this) == sizeof(Char*) + 2 * sizeof(size_t), static_assert(sizeof(*this) == sizeof(Char*) + 2 * sizeof(size_t),
"fbstring has unexpected size"); "fbstring has unexpected size");
...@@ -377,14 +380,11 @@ public: ...@@ -377,14 +380,11 @@ public:
// If data is aligned, use fast word-wise copying. Otherwise, // If data is aligned, use fast word-wise copying. Otherwise,
// use conservative memcpy. // use conservative memcpy.
if (reinterpret_cast<size_t>(data) & (sizeof(size_t) - 1)) { // The word-wise path reads bytes which are outside the range of
fbstring_detail::pod_copy(data, data + size, small_); // the string, and makes ASan unhappy, so we disable it when
} else { // compiling with ASan.
// Copy one word at a time. #ifndef FBSTRING_SANITIZE_ADDRESS
// NOTE: This reads bytes which are outside the range of the if ((reinterpret_cast<size_t>(data) & (sizeof(size_t) - 1)) == 0) {
// string, and makes ASan unhappy, but the small case is
// disabled under ASan.
const size_t byteSize = size * sizeof(Char); const size_t byteSize = size * sizeof(Char);
constexpr size_t wordWidth = sizeof(size_t); constexpr size_t wordWidth = sizeof(size_t);
switch ((byteSize + wordWidth - 1) / wordWidth) { // Number of words. switch ((byteSize + wordWidth - 1) / wordWidth) { // Number of words.
...@@ -397,11 +397,13 @@ public: ...@@ -397,11 +397,13 @@ public:
case 0: case 0:
break; break;
} }
}
setSmallSize(size);
} else } else
#endif // FBSTRING_DISABLE_SMALL_STRING_OPTIMIZATION #endif
{ {
fbstring_detail::pod_copy(data, data + size, small_);
}
setSmallSize(size);
} else {
if (size <= maxMediumSize) { if (size <= maxMediumSize) {
// Medium strings are allocated normally. Don't forget to // Medium strings are allocated normally. Don't forget to
// allocate one extra Char for the terminating null. // allocate one extra Char for the terminating null.
...@@ -532,7 +534,7 @@ public: ...@@ -532,7 +534,7 @@ public:
} }
} }
void reserve(size_t minCapacity) { void reserve(size_t minCapacity, bool disableSSO = FBSTRING_DISABLE_SSO) {
if (category() == Category::isLarge) { if (category() == Category::isLarge) {
// Ensure unique // Ensure unique
if (RefCounted::refs(ml_.data_) > 1) { if (RefCounted::refs(ml_.data_) > 1) {
...@@ -593,13 +595,10 @@ public: ...@@ -593,13 +595,10 @@ public:
} }
} else { } else {
assert(category() == Category::isSmall); assert(category() == Category::isSmall);
#ifndef FBSTRING_DISABLE_SMALL_STRING_OPTIMIZATION if (!disableSSO && minCapacity <= maxSmallSize) {
if (minCapacity <= maxSmallSize) {
// small // small
// Nothing to do, everything stays put // Nothing to do, everything stays put
} else } else if (minCapacity <= maxMediumSize) {
#endif // FBSTRING_DISABLE_SMALL_STRING_OPTIMIZATION
if (minCapacity <= maxMediumSize) {
// medium // medium
// Don't forget to allocate one extra Char for the terminating null // Don't forget to allocate one extra Char for the terminating null
auto const allocSizeBytes = auto const allocSizeBytes =
...@@ -626,19 +625,19 @@ public: ...@@ -626,19 +625,19 @@ public:
assert(capacity() >= minCapacity); assert(capacity() >= minCapacity);
} }
Char * expand_noinit(const size_t delta, bool expGrowth = false) { Char * expand_noinit(const size_t delta,
bool expGrowth = false,
bool disableSSO = FBSTRING_DISABLE_SSO) {
// Strategy is simple: make room, then change size // Strategy is simple: make room, then change size
assert(capacity() >= size()); assert(capacity() >= size());
size_t sz, newSz; size_t sz, newSz;
if (category() == Category::isSmall) { if (category() == Category::isSmall) {
sz = smallSize(); sz = smallSize();
newSz = sz + delta; newSz = sz + delta;
#ifndef FBSTRING_DISABLE_SMALL_STRING_OPTIMIZATION if (!disableSSO && FBSTRING_LIKELY(newSz <= maxSmallSize)) {
if (FBSTRING_LIKELY(newSz <= maxSmallSize)) {
setSmallSize(newSz); setSmallSize(newSz);
return small_ + sz; return small_ + sz;
} }
#endif // FBSTRING_DISABLE_SMALL_STRING_OPTIMIZATION
reserve(expGrowth ? std::max(newSz, 2 * maxSmallSize) : newSz); reserve(expGrowth ? std::max(newSz, 2 * maxSmallSize) : newSz);
} else { } else {
sz = ml_.size_; sz = ml_.size_;
...@@ -1482,29 +1481,20 @@ public: ...@@ -1482,29 +1481,20 @@ public:
private: private:
template <int i> class Selector {}; template <int i> class Selector {};
iterator insertImplDiscr(const_iterator p, iterator insertImplDiscr(const_iterator i,
size_type n, value_type c, Selector<1>) { size_type n, value_type c, Selector<1>) {
Invariant checker(*this); Invariant checker(*this);
auto const pos = p - begin(); assert(i >= begin() && i <= end());
assert(p >= begin() && p <= end()); const size_type pos = i - begin();
if (capacity() - size() < n) {
const size_type sz = p - begin(); auto oldSize = size();
reserve(size() + n); store_.expand_noinit(n, /* expGrowth = */ true);
p = begin() + sz; auto b = begin();
} fbstring_detail::pod_move(b + pos, b + oldSize, b + pos + n);
const iterator oldEnd = end(); fbstring_detail::pod_fill(b + pos, b + pos + n, c);
if (n < size_type(oldEnd - p)) {
append(oldEnd - n, oldEnd); return b + pos;
// Also copies terminator.
fbstring_detail::pod_move(&*p, &*oldEnd - n + 1, begin() + pos + n);
std::fill(begin() + pos, begin() + pos + n, c);
} else {
append(n - (end() - p), c);
append(iterator(p), oldEnd);
std::fill(iterator(p), oldEnd, c);
}
return begin() + pos;
} }
template<class InputIter> template<class InputIter>
...@@ -1521,10 +1511,10 @@ private: ...@@ -1521,10 +1511,10 @@ private:
std::forward_iterator_tag) { std::forward_iterator_tag) {
Invariant checker(*this); Invariant checker(*this);
assert(i >= begin() && i <= end());
const size_type pos = i - begin(); const size_type pos = i - begin();
auto n = std::distance(s1, s2); auto n = std::distance(s1, s2);
assert(n >= 0); assert(n >= 0);
assert(pos <= size());
auto oldSize = size(); auto oldSize = size();
store_.expand_noinit(n, /* expGrowth = */ true); store_.expand_noinit(n, /* expGrowth = */ true);
...@@ -2481,7 +2471,7 @@ FOLLY_FBSTRING_HASH ...@@ -2481,7 +2471,7 @@ FOLLY_FBSTRING_HASH
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#undef FBSTRING_DISABLE_SMALL_STRING_OPTIMIZATION #undef FBSTRING_DISABLE_SSO
#undef FBSTRING_SANITIZE_ADDRESS #undef FBSTRING_SANITIZE_ADDRESS
#undef throw #undef throw
#undef FBSTRING_LIKELY #undef FBSTRING_LIKELY
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment