Commit af1b0a8b authored by Andrei Alexandrescu's avatar Andrei Alexandrescu Committed by Sara Golemon

fbstring::shrink_to_fit

Summary: Adds the eponymous C++11 capability to fbstring.

Test Plan: fbstring runtests

Reviewed By: tudorb@fb.com

FB internal diff: D867995
parent ea72b037
...@@ -985,7 +985,7 @@ private: ...@@ -985,7 +985,7 @@ private:
} }
public: public:
// 21.3.1 construct/copy/destroy // C++11 21.4.2 construct/copy/destroy
explicit basic_fbstring(const A& a = A()) { explicit basic_fbstring(const A& a = A()) {
} }
...@@ -1047,6 +1047,11 @@ public: ...@@ -1047,6 +1047,11 @@ public:
: store_(s, n, c, a) { : store_(s, n, c, a) {
} }
// Construction from initialization list
basic_fbstring(std::initializer_list<value_type> il) {
assign(il.begin(), il.end());
}
~basic_fbstring() { ~basic_fbstring() {
} }
...@@ -1076,7 +1081,7 @@ public: ...@@ -1076,7 +1081,7 @@ public:
basic_fbstring& operator=(basic_fbstring&& goner) { basic_fbstring& operator=(basic_fbstring&& goner) {
if (FBSTRING_UNLIKELY(&goner == this)) { if (FBSTRING_UNLIKELY(&goner == this)) {
// Compatibility with std::basic_string<>, // Compatibility with std::basic_string<>,
// 21.4.2 [string.cons] / 23 requires self-move-assignment support. // C++11 21.4.2 [string.cons] / 23 requires self-move-assignment support.
return *this; return *this;
} }
// No need of this anymore // No need of this anymore
...@@ -1121,11 +1126,17 @@ public: ...@@ -1121,11 +1126,17 @@ public:
return *this; return *this;
} }
// 21.3.2 iterators: basic_fbstring& operator=(std::initializer_list<value_type> il) {
return assign(il.begin(), il.end());
}
// C++11 21.4.3 iterators:
iterator begin() { return store_.mutable_data(); } iterator begin() { return store_.mutable_data(); }
const_iterator begin() const { return store_.data(); } const_iterator begin() const { return store_.data(); }
const_iterator cbegin() const { return begin(); }
iterator end() { iterator end() {
return store_.mutable_data() + store_.size(); return store_.mutable_data() + store_.size();
} }
...@@ -1134,6 +1145,8 @@ public: ...@@ -1134,6 +1145,8 @@ public:
return store_.data() + store_.size(); return store_.data() + store_.size();
} }
const_iterator cend() const { return end(); }
reverse_iterator rbegin() { reverse_iterator rbegin() {
return reverse_iterator(end()); return reverse_iterator(end());
} }
...@@ -1142,6 +1155,8 @@ public: ...@@ -1142,6 +1155,8 @@ public:
return const_reverse_iterator(end()); return const_reverse_iterator(end());
} }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() { reverse_iterator rend() {
return reverse_iterator(begin()); return reverse_iterator(begin());
} }
...@@ -1150,6 +1165,8 @@ public: ...@@ -1150,6 +1165,8 @@ public:
return const_reverse_iterator(begin()); return const_reverse_iterator(begin());
} }
const_reverse_iterator crend() const { return rend(); }
// Added by C++11 // Added by C++11
// C++11 21.4.5, element access: // C++11 21.4.5, element access:
const value_type& front() const { return *begin(); } const value_type& front() const { return *begin(); }
...@@ -1169,7 +1186,7 @@ public: ...@@ -1169,7 +1186,7 @@ public:
store_.shrink(1); store_.shrink(1);
} }
// 21.3.3 capacity: // C++11 21.4.4 capacity:
size_type size() const { return store_.size(); } size_type size() const { return store_.size(); }
size_type length() const { return size(); } size_type length() const { return size(); }
...@@ -1213,11 +1230,19 @@ public: ...@@ -1213,11 +1230,19 @@ public:
store_.reserve(res_arg); store_.reserve(res_arg);
} }
void shrink_to_fit() {
// Shrink only if slack memory is sufficiently large
if (capacity() < size() * 3 / 2) {
return;
}
basic_fbstring(cbegin(), cend()).swap(*this);
}
void clear() { resize(0); } void clear() { resize(0); }
bool empty() const { return size() == 0; } bool empty() const { return size() == 0; }
// 21.3.4 element access: // C++11 21.4.5 element access:
const_reference operator[](size_type pos) const { const_reference operator[](size_type pos) const {
return *(c_str() + pos); return *(c_str() + pos);
} }
...@@ -1240,7 +1265,7 @@ public: ...@@ -1240,7 +1265,7 @@ public:
return (*this)[n]; return (*this)[n];
} }
// 21.3.5 modifiers: // C++11 21.4.6 modifiers:
basic_fbstring& operator+=(const basic_fbstring& str) { basic_fbstring& operator+=(const basic_fbstring& str) {
return append(str); return append(str);
} }
...@@ -1254,6 +1279,11 @@ public: ...@@ -1254,6 +1279,11 @@ public:
return *this; return *this;
} }
basic_fbstring& operator+=(std::initializer_list<value_type> il) {
append(il);
return *this;
}
basic_fbstring& append(const basic_fbstring& str) { basic_fbstring& append(const basic_fbstring& str) {
#ifndef NDEBUG #ifndef NDEBUG
auto desiredSize = size() + str.size(); auto desiredSize = size() + str.size();
...@@ -1323,6 +1353,10 @@ public: ...@@ -1323,6 +1353,10 @@ public:
return *this; return *this;
} }
basic_fbstring& append(std::initializer_list<value_type> il) {
return append(il.begin(), il.end());
}
void push_back(const value_type c) { // primitive void push_back(const value_type c) { // primitive
store_.push_back(c); store_.push_back(c);
} }
...@@ -1332,6 +1366,10 @@ public: ...@@ -1332,6 +1366,10 @@ public:
return assign(str.data(), str.size()); return assign(str.data(), str.size());
} }
basic_fbstring& assign(basic_fbstring&& str) {
return *this = std::move(str);
}
basic_fbstring& assign(const basic_fbstring& str, const size_type pos, basic_fbstring& assign(const basic_fbstring& str, const size_type pos,
size_type n) { size_type n) {
const size_type sz = str.size(); const size_type sz = str.size();
...@@ -1362,6 +1400,10 @@ public: ...@@ -1362,6 +1400,10 @@ public:
return assign(s, traits_type::length(s)); return assign(s, traits_type::length(s));
} }
basic_fbstring& assign(std::initializer_list<value_type> il) {
return assign(il.begin(), il.end());
}
template <class ItOrLength, class ItOrChar> template <class ItOrLength, class ItOrChar>
basic_fbstring& assign(ItOrLength first_or_n, ItOrChar last_or_c) { basic_fbstring& assign(ItOrLength first_or_n, ItOrChar last_or_c) {
return replace(begin(), end(), first_or_n, last_or_c); return replace(begin(), end(), first_or_n, last_or_c);
...@@ -1394,7 +1436,7 @@ public: ...@@ -1394,7 +1436,7 @@ public:
return *this; return *this;
} }
iterator insert(const iterator p, const value_type c) { iterator insert(const_iterator p, const value_type c) {
const size_type pos = p - begin(); const size_type pos = p - begin();
insert(p, 1, c); insert(p, 1, c);
return begin() + pos; return begin() + pos;
...@@ -1403,10 +1445,11 @@ public: ...@@ -1403,10 +1445,11 @@ public:
private: private:
template <int i> class Selector {}; template <int i> class Selector {};
basic_fbstring& insertImplDiscr(iterator p, iterator insertImplDiscr(const_iterator p,
size_type n, value_type c, Selector<1>) { size_type n, value_type c, Selector<1>) {
Invariant checker(*this); Invariant checker(*this);
(void) checker; (void) checker;
auto const pos = p - begin();
assert(p >= begin() && p <= end()); assert(p >= begin() && p <= end());
if (capacity() - size() < n) { if (capacity() - size() < n) {
const size_type sz = p - begin(); const size_type sz = p - begin();
...@@ -1414,33 +1457,33 @@ private: ...@@ -1414,33 +1457,33 @@ private:
p = begin() + sz; p = begin() + sz;
} }
const iterator oldEnd = end(); const iterator oldEnd = end();
if( n < size_type(oldEnd - p)) { if (n < size_type(oldEnd - p)) {
append(oldEnd - n, oldEnd); append(oldEnd - n, oldEnd);
//std::copy( //std::copy(
// reverse_iterator(oldEnd - n), // reverse_iterator(oldEnd - n),
// reverse_iterator(p), // reverse_iterator(p),
// reverse_iterator(oldEnd)); // reverse_iterator(oldEnd));
fbstring_detail::pod_move(&*p, &*oldEnd - n, &*p + n); fbstring_detail::pod_move(&*p, &*oldEnd - n,
std::fill(p, p + n, c); begin() + pos + n);
std::fill(begin() + pos, begin() + pos + n, c);
} else { } else {
append(n - (end() - p), c); append(n - (end() - p), c);
append(p, oldEnd); append(iterator(p), oldEnd);
std::fill(p, oldEnd, c); std::fill(iterator(p), oldEnd, c);
} }
store_.writeTerminator(); store_.writeTerminator();
return *this; return begin() + pos;
} }
template<class InputIter> template<class InputIter>
basic_fbstring& insertImplDiscr(iterator i, iterator insertImplDiscr(const_iterator i,
InputIter b, InputIter e, Selector<0>) { InputIter b, InputIter e, Selector<0>) {
insertImpl(i, b, e, return insertImpl(i, b, e,
typename std::iterator_traits<InputIter>::iterator_category()); typename std::iterator_traits<InputIter>::iterator_category());
return *this;
} }
template <class FwdIterator> template <class FwdIterator>
void insertImpl(iterator i, iterator insertImpl(const_iterator i,
FwdIterator s1, FwdIterator s2, std::forward_iterator_tag) { FwdIterator s1, FwdIterator s2, std::forward_iterator_tag) {
Invariant checker(*this); Invariant checker(*this);
(void) checker; (void) checker;
...@@ -1462,9 +1505,9 @@ private: ...@@ -1462,9 +1505,9 @@ private:
const iterator tailBegin = end() - n2; const iterator tailBegin = end() - n2;
store_.expand_noinit(n2); store_.expand_noinit(n2);
fbstring_detail::pod_copy(tailBegin, tailBegin + n2, end() - n2); fbstring_detail::pod_copy(tailBegin, tailBegin + n2, end() - n2);
std::copy(reverse_iterator(tailBegin), reverse_iterator(i), std::copy(const_reverse_iterator(tailBegin), const_reverse_iterator(i),
reverse_iterator(tailBegin + n2)); reverse_iterator(tailBegin + n2));
std::copy(s1, s2, i); std::copy(s1, s2, begin() + pos);
} else { } else {
FwdIterator t = s1; FwdIterator t = s1;
const size_type old_size = size(); const size_type old_size = size();
...@@ -1474,27 +1517,35 @@ private: ...@@ -1474,27 +1517,35 @@ private:
std::copy(t, s2, begin() + old_size); std::copy(t, s2, begin() + old_size);
fbstring_detail::pod_copy(data() + pos, data() + old_size, fbstring_detail::pod_copy(data() + pos, data() + old_size,
begin() + old_size + newElems); begin() + old_size + newElems);
std::copy(s1, t, i); std::copy(s1, t, begin() + pos);
} }
store_.writeTerminator(); store_.writeTerminator();
return begin() + pos;
} }
template <class InputIterator> template <class InputIterator>
void insertImpl(iterator i, iterator insertImpl(const_iterator i,
InputIterator b, InputIterator e, std::input_iterator_tag) { InputIterator b, InputIterator e,
std::input_iterator_tag) {
const auto pos = i - begin();
basic_fbstring temp(begin(), i); basic_fbstring temp(begin(), i);
for (; b != e; ++b) { for (; b != e; ++b) {
temp.push_back(*b); temp.push_back(*b);
} }
temp.append(i, end()); temp.append(i, end());
swap(temp); swap(temp);
return begin() + pos;
} }
public: public:
template <class ItOrLength, class ItOrChar> template <class ItOrLength, class ItOrChar>
void insert(iterator p, ItOrLength first_or_n, ItOrChar last_or_c) { iterator insert(const_iterator p, ItOrLength first_or_n, ItOrChar last_or_c) {
Selector<std::numeric_limits<ItOrLength>::is_specialized> sel; Selector<std::numeric_limits<ItOrLength>::is_specialized> sel;
insertImplDiscr(p, first_or_n, last_or_c, sel); return insertImplDiscr(p, first_or_n, last_or_c, sel);
}
iterator insert(const_iterator p, std::initializer_list<value_type> il) {
return insert(p, il.begin(), il.end());
} }
basic_fbstring& erase(size_type pos = 0, size_type n = npos) { basic_fbstring& erase(size_type pos = 0, size_type n = npos) {
...@@ -1690,7 +1741,6 @@ public: ...@@ -1690,7 +1741,6 @@ public:
store_.swap(rhs.store_); store_.swap(rhs.store_);
} }
// 21.3.6 string operations:
const value_type* c_str() const { const value_type* c_str() const {
return store_.c_str(); return store_.c_str();
} }
...@@ -2165,7 +2215,7 @@ bool operator>=(const typename basic_fbstring<E, T, A, S>::value_type* lhs, ...@@ -2165,7 +2215,7 @@ bool operator>=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
return !(lhs < rhs); return !(lhs < rhs);
} }
// subclause 21.3.7.8: // C++11 21.4.8.8
template <typename E, class T, class A, class S> template <typename E, class T, class A, class S>
void swap(basic_fbstring<E, T, A, S>& lhs, basic_fbstring<E, T, A, S>& rhs) { void swap(basic_fbstring<E, T, A, S>& lhs, basic_fbstring<E, T, A, S>& rhs) {
lhs.swap(rhs); lhs.swap(rhs);
......
This diff is collapsed.
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