Commit aeef60dd authored by Giuseppe Ottaviano's avatar Giuseppe Ottaviano Committed by Facebook Github Bot 1

Make fbstring::assign() tight, and simplify operator=() and append()

Summary:
`fbstring::assign()` uses `append()`, which triggers exponential growth, but it's preferable that `assign()` behaves like the `fbstring(const char*, size_t)` constructor, which is tight.

Also rewrite `operator=()` in terms of `assign()`, to avoid duplicating the logic, and refactor the logic of `append()` for the aliasing case so that it uses the same expansion operation as the non-aliasing case.

Reviewed By: luciang

Differential Revision: D3754932

fbshipit-source-id: 5423f2a360b4268b6a05dd0ae9d2fe5bd1eb855d
parent 89166c82
...@@ -1076,24 +1076,8 @@ public: ...@@ -1076,24 +1076,8 @@ public:
if (FBSTRING_UNLIKELY(&lhs == this)) { if (FBSTRING_UNLIKELY(&lhs == this)) {
return *this; return *this;
} }
auto const oldSize = size();
auto const srcSize = lhs.size(); return assign(lhs.data(), lhs.size());
if (capacity() >= srcSize && !store_.isShared()) {
// great, just copy the contents
if (oldSize < srcSize) {
store_.expand_noinit(srcSize - oldSize);
} else {
store_.shrink(oldSize - srcSize);
}
assert(size() == srcSize);
auto srcData = lhs.data();
fbstring_detail::pod_copy(
srcData, srcData + srcSize, store_.mutable_data());
} else {
// need to reallocate, so we may as well create a brand new string
basic_fbstring(lhs).swap(*this);
}
return *this;
} }
// Move assignment // Move assignment
...@@ -1312,6 +1296,8 @@ public: ...@@ -1312,6 +1296,8 @@ public:
} }
auto const oldSize = size(); auto const oldSize = size();
auto const oldData = data(); auto const oldData = data();
auto pData = store_.expand_noinit(n, /* expGrowth = */ true);
// Check for aliasing (rare). We could use "<=" here but in theory // Check for aliasing (rare). We could use "<=" here but in theory
// those do not work for pointers unless the pointers point to // those do not work for pointers unless the pointers point to
// elements in the same array. For that reason we use // elements in the same array. For that reason we use
...@@ -1321,14 +1307,13 @@ public: ...@@ -1321,14 +1307,13 @@ public:
std::less_equal<const value_type*> le; std::less_equal<const value_type*> le;
if (FBSTRING_UNLIKELY(le(oldData, s) && !le(oldData + oldSize, s))) { if (FBSTRING_UNLIKELY(le(oldData, s) && !le(oldData + oldSize, s))) {
assert(le(s + n, oldData + oldSize)); assert(le(s + n, oldData + oldSize));
const size_type offset = s - oldData; // expand_noinit() could have moved the storage, restore the source.
store_.reserve(oldSize + n); s = data() + (s - oldData);
// Restore the source fbstring_detail::pod_move(s, s + n, pData);
s = data() + offset; } else {
fbstring_detail::pod_copy(s, s + n, pData);
} }
fbstring_detail::pod_copy(
s, s + n, store_.expand_noinit(n, /* expGrowth = */ true));
assert(size() == oldSize + n); assert(size() == oldSize + n);
return *this; return *this;
} }
...@@ -1378,21 +1363,22 @@ public: ...@@ -1378,21 +1363,22 @@ public:
basic_fbstring& assign(const value_type* s, const size_type n) { basic_fbstring& assign(const value_type* s, const size_type n) {
Invariant checker(*this); Invariant checker(*this);
// s can alias this, we need to use pod_move.
if (n == 0) { if (n == 0) {
resize(0); resize(0);
} else if (size() >= n) { } else if (size() >= n) {
// s can alias this, we need to use pod_move.
fbstring_detail::pod_move(s, s + n, store_.mutable_data()); fbstring_detail::pod_move(s, s + n, store_.mutable_data());
resize(n); store_.shrink(size() - n);
assert(size() == n); assert(size() == n);
} else { } else {
const value_type *const s2 = s + size(); // If n is larger than size(), s cannot alias this string's
// size() < n!so [s,s + n) and [data(),data() + size()] can not overlap // storage.
// so we can use pod_copy instead of pod_move. resize(0);
fbstring_detail::pod_copy(s, s2, store_.mutable_data()); // Do not use exponential growth here: assign() should be tight,
append(s2, n - size()); // to mirror the behavior of the equivalent constructor.
assert(size() == n); fbstring_detail::pod_copy(s, s + n, store_.expand_noinit(n));
} }
assert(size() == n); assert(size() == n);
return *this; return *this;
} }
......
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