Merge branch 'master' into master
This commit is contained in:
commit
200b5a7cb0
38 changed files with 461 additions and 191 deletions
|
@ -112,6 +112,9 @@ cc_library(
|
|||
srcs = ["internal/test_instance_tracker.cc"],
|
||||
hdrs = ["internal/test_instance_tracker.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
visibility = [
|
||||
"//absl:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
|
|
|
@ -82,7 +82,8 @@ class InlinedVector {
|
|||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
InlinedVector() noexcept(noexcept(allocator_type()))
|
||||
InlinedVector() noexcept(
|
||||
std::is_nothrow_default_constructible<allocator_type>::value)
|
||||
: allocator_and_tag_(allocator_type()) {}
|
||||
|
||||
explicit InlinedVector(const allocator_type& alloc) noexcept
|
||||
|
@ -148,6 +149,9 @@ class InlinedVector {
|
|||
~InlinedVector() { clear(); }
|
||||
|
||||
InlinedVector& operator=(const InlinedVector& v) {
|
||||
if (this == &v) {
|
||||
return *this;
|
||||
}
|
||||
// Optimized to avoid reallocation.
|
||||
// Prefer reassignment to copy construction for elements.
|
||||
if (size() < v.size()) { // grow
|
||||
|
@ -680,6 +684,8 @@ class InlinedVector {
|
|||
// portion and the start of the uninitialized portion of the created gap.
|
||||
// The number of initialized spots is pair.second - pair.first;
|
||||
// the number of raw spots is n - (pair.second - pair.first).
|
||||
//
|
||||
// Updates the size of the InlinedVector internally.
|
||||
std::pair<iterator, iterator> ShiftRight(const_iterator position,
|
||||
size_type n);
|
||||
|
||||
|
@ -1013,28 +1019,19 @@ typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::emplace(
|
|||
emplace_back(std::forward<Args>(args)...);
|
||||
return end() - 1;
|
||||
}
|
||||
size_type s = size();
|
||||
size_type idx = std::distance(cbegin(), position);
|
||||
if (s == capacity()) {
|
||||
EnlargeBy(1);
|
||||
}
|
||||
assert(s < capacity());
|
||||
iterator pos = begin() + idx; // Set 'pos' to a post-enlarge iterator.
|
||||
|
||||
pointer space;
|
||||
if (allocated()) {
|
||||
tag().set_allocated_size(s + 1);
|
||||
space = allocated_space();
|
||||
T new_t = T(std::forward<Args>(args)...);
|
||||
|
||||
auto range = ShiftRight(position, 1);
|
||||
if (range.first == range.second) {
|
||||
// constructing into uninitialized memory
|
||||
Construct(range.first, std::move(new_t));
|
||||
} else {
|
||||
tag().set_inline_size(s + 1);
|
||||
space = inlined_space();
|
||||
// assigning into moved-from object
|
||||
*range.first = T(std::move(new_t));
|
||||
}
|
||||
Construct(space + s, std::move(space[s - 1]));
|
||||
std::move_backward(pos, space + s - 1, space + s);
|
||||
Destroy(pos, pos + 1);
|
||||
Construct(pos, std::forward<Args>(args)...);
|
||||
|
||||
return pos;
|
||||
return range.first;
|
||||
}
|
||||
|
||||
template <typename T, size_t N, typename A>
|
||||
|
@ -1219,6 +1216,7 @@ auto InlinedVector<T, N, A>::ShiftRight(const_iterator position, size_type n)
|
|||
start_used = pos;
|
||||
start_raw = pos + new_elements_in_used_space;
|
||||
}
|
||||
tag().add_size(n);
|
||||
return std::make_pair(start_used, start_raw);
|
||||
}
|
||||
|
||||
|
@ -1297,10 +1295,12 @@ auto InlinedVector<T, N, A>::InsertWithCount(const_iterator position,
|
|||
-> iterator {
|
||||
assert(position >= begin() && position <= end());
|
||||
if (n == 0) return const_cast<iterator>(position);
|
||||
|
||||
value_type copy = v;
|
||||
std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
|
||||
std::fill(it_pair.first, it_pair.second, v);
|
||||
UninitializedFill(it_pair.second, it_pair.first + n, v);
|
||||
tag().add_size(n);
|
||||
std::fill(it_pair.first, it_pair.second, copy);
|
||||
UninitializedFill(it_pair.second, it_pair.first + n, copy);
|
||||
|
||||
return it_pair.first;
|
||||
}
|
||||
|
||||
|
@ -1336,7 +1336,6 @@ auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
|
|||
ForwardIter open_spot = std::next(first, used_spots);
|
||||
std::copy(first, open_spot, it_pair.first);
|
||||
UninitializedCopy(open_spot, last, it_pair.second);
|
||||
tag().add_size(n);
|
||||
return it_pair.first;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "absl/container/inlined_vector.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
@ -569,6 +570,16 @@ TEST(IntVec, CopyConstructorAndAssignment) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(IntVec, AliasingCopyAssignment) {
|
||||
for (int len = 0; len < 20; ++len) {
|
||||
IntVec original;
|
||||
Fill(&original, len);
|
||||
IntVec dup = original;
|
||||
dup = dup;
|
||||
EXPECT_EQ(dup, original);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IntVec, MoveConstructorAndAssignment) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
IntVec v_in;
|
||||
|
@ -606,6 +617,78 @@ TEST(IntVec, MoveConstructorAndAssignment) {
|
|||
}
|
||||
}
|
||||
|
||||
class NotTriviallyDestructible {
|
||||
public:
|
||||
NotTriviallyDestructible() : p_(new int(1)) {}
|
||||
explicit NotTriviallyDestructible(int i) : p_(new int(i)) {}
|
||||
|
||||
NotTriviallyDestructible(const NotTriviallyDestructible& other)
|
||||
: p_(new int(*other.p_)) {}
|
||||
|
||||
NotTriviallyDestructible& operator=(const NotTriviallyDestructible& other) {
|
||||
p_ = absl::make_unique<int>(*other.p_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const NotTriviallyDestructible& other) const {
|
||||
return *p_ == *other.p_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<int> p_;
|
||||
};
|
||||
|
||||
TEST(AliasingTest, Emplace) {
|
||||
for (int i = 2; i < 20; ++i) {
|
||||
absl::InlinedVector<NotTriviallyDestructible, 10> vec;
|
||||
for (int j = 0; j < i; ++j) {
|
||||
vec.push_back(NotTriviallyDestructible(j));
|
||||
}
|
||||
vec.emplace(vec.begin(), vec[0]);
|
||||
EXPECT_EQ(vec[0], vec[1]);
|
||||
vec.emplace(vec.begin() + i / 2, vec[i / 2]);
|
||||
EXPECT_EQ(vec[i / 2], vec[i / 2 + 1]);
|
||||
vec.emplace(vec.end() - 1, vec.back());
|
||||
EXPECT_EQ(vec[vec.size() - 2], vec.back());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AliasingTest, InsertWithCount) {
|
||||
for (int i = 1; i < 20; ++i) {
|
||||
absl::InlinedVector<NotTriviallyDestructible, 10> vec;
|
||||
for (int j = 0; j < i; ++j) {
|
||||
vec.push_back(NotTriviallyDestructible(j));
|
||||
}
|
||||
for (int n = 0; n < 5; ++n) {
|
||||
// We use back where we can because it's guaranteed to become invalidated
|
||||
vec.insert(vec.begin(), n, vec.back());
|
||||
auto b = vec.begin();
|
||||
EXPECT_TRUE(
|
||||
std::all_of(b, b + n, [&vec](const NotTriviallyDestructible& x) {
|
||||
return x == vec.back();
|
||||
}));
|
||||
|
||||
auto m_idx = vec.size() / 2;
|
||||
vec.insert(vec.begin() + m_idx, n, vec.back());
|
||||
auto m = vec.begin() + m_idx;
|
||||
EXPECT_TRUE(
|
||||
std::all_of(m, m + n, [&vec](const NotTriviallyDestructible& x) {
|
||||
return x == vec.back();
|
||||
}));
|
||||
|
||||
// We want distinct values so the equality test is meaningful,
|
||||
// vec[vec.size() - 1] is also almost always invalidated.
|
||||
auto old_e = vec.size() - 1;
|
||||
auto val = vec[old_e];
|
||||
vec.insert(vec.end(), n, vec[old_e]);
|
||||
auto e = vec.begin() + old_e;
|
||||
EXPECT_TRUE(std::all_of(
|
||||
e, e + n,
|
||||
[&val](const NotTriviallyDestructible& x) { return x == val; }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OverheadTest, Storage) {
|
||||
// Check for size overhead.
|
||||
// In particular, ensure that std::allocator doesn't cost anything to store.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue