Export of internal Abseil changes.
-- ab1a58c85a462884413ec0022dc1fff19ccb8602 by Abseil Team <absl-team@google.com>: Clarified the documentation in str_format.h to say that use of absl::FormatSpec is ok for wrapper functions. Added tests that express this. PiperOrigin-RevId: 247657991 -- fef9481e58d579f1514babcb960ca60a51883fd8 by CJ Johnson <johnsoncj@google.com>: Adds exception safety tests for InlinedVector::InlinedVector() and InlinedVector::InlinedVector(const allocator_type&). PiperOrigin-RevId: 247617048 -- ef3217e1cd1e9a6ff5f2025e061b8ce3735af78f by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 247614063 -- ed4c3345c4a04d8ec5c9e627058f17fce55925b1 by CJ Johnson <johnsoncj@google.com>: Update InlinedVector::clear() Introduces inlined_vector_exception_safety_test with the first test (clear), adds new benchmarks (for clear), and updates the implementation of clear. PiperOrigin-RevId: 247496049 -- 144a3a77c93bc8b2226da6f4b56166ee3d9868de by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 247482532 -- 286bbb89e154d5424955b644edad5fe04be487f8 by Derek Mauro <dmauro@google.com>: Add scripts to run ASAN and TSAN on CI. PiperOrigin-RevId: 247479658 GitOrigin-RevId: ab1a58c85a462884413ec0022dc1fff19ccb8602 Change-Id: Ief4c5a62587d0c59d405735df469d498aa6bf101
This commit is contained in:
parent
27c2f6e2f3
commit
0cbdc774b9
18 changed files with 422 additions and 36 deletions
|
@ -198,11 +198,23 @@ cc_test(
|
|||
deps = [
|
||||
":inlined_vector",
|
||||
"//absl/base",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/strings",
|
||||
"@com_github_google_benchmark//:benchmark_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "inlined_vector_exception_safety_test",
|
||||
srcs = ["inlined_vector_exception_safety_test.cc"],
|
||||
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
deps = [
|
||||
":inlined_vector",
|
||||
"//absl/base:exception_safety_testing",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "test_instance_tracker",
|
||||
testonly = 1,
|
||||
|
|
|
@ -195,6 +195,22 @@ absl_cc_test(
|
|||
gmock_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
inlined_vector_exception_safety_test
|
||||
SRCS
|
||||
"inlined_vector_exception_safety_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
${ABSL_EXCEPTIONS_FLAG}
|
||||
LINKOPTS
|
||||
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
|
||||
DEPS
|
||||
absl::inlined_vector
|
||||
absl::exception_safety_testing
|
||||
gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
test_instance_tracker
|
||||
|
|
|
@ -784,16 +784,20 @@ class InlinedVector {
|
|||
// Destroys all elements in the inlined vector, sets the size of `0` and
|
||||
// deallocates the heap allocation if the inlined vector was allocated.
|
||||
void clear() noexcept {
|
||||
size_type s = size();
|
||||
if (storage_.GetIsAllocated()) {
|
||||
Destroy(storage_.GetAllocatedData(), storage_.GetAllocatedData() + s);
|
||||
AllocatorTraits::deallocate(storage_.GetAllocator(),
|
||||
storage_.GetAllocatedData(),
|
||||
const bool is_allocated = storage_.GetIsAllocated();
|
||||
|
||||
pointer the_data =
|
||||
is_allocated ? storage_.GetAllocatedData() : storage_.GetInlinedData();
|
||||
|
||||
inlined_vector_internal::DestroyElements(storage_.GetAllocator(), the_data,
|
||||
storage_.GetSize());
|
||||
|
||||
if (is_allocated) {
|
||||
AllocatorTraits::deallocate(storage_.GetAllocator(), the_data,
|
||||
storage_.GetAllocatedCapacity());
|
||||
} else if (s != 0) { // do nothing for empty vectors
|
||||
Destroy(storage_.GetInlinedData(), storage_.GetInlinedData() + s);
|
||||
}
|
||||
storage_.SetInlinedSize(0);
|
||||
|
||||
storage_.SetInlinedSize(/* size = */ 0);
|
||||
}
|
||||
|
||||
// `InlinedVector::reserve()`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Abseil Authors.
|
||||
// Copyright 2019 The Abseil Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -12,13 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "absl/container/inlined_vector.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/container/inlined_vector.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
||||
namespace {
|
||||
|
@ -373,4 +373,72 @@ void BM_StdVectorEmpty(benchmark::State& state) {
|
|||
}
|
||||
BENCHMARK(BM_StdVectorEmpty);
|
||||
|
||||
constexpr size_t kInlineElements = 4;
|
||||
constexpr size_t kSmallSize = kInlineElements / 2;
|
||||
constexpr size_t kLargeSize = kInlineElements * 2;
|
||||
constexpr size_t kBatchSize = 100;
|
||||
|
||||
struct TrivialType {
|
||||
size_t val;
|
||||
};
|
||||
|
||||
using TrivialVec = absl::InlinedVector<TrivialType, kInlineElements>;
|
||||
|
||||
class NontrivialType {
|
||||
public:
|
||||
ABSL_ATTRIBUTE_NOINLINE NontrivialType() : val_() {}
|
||||
|
||||
ABSL_ATTRIBUTE_NOINLINE NontrivialType(const NontrivialType& other)
|
||||
: val_(other.val_) {}
|
||||
|
||||
ABSL_ATTRIBUTE_NOINLINE NontrivialType& operator=(
|
||||
const NontrivialType& other) {
|
||||
val_ = other.val_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_NOINLINE ~NontrivialType() noexcept {}
|
||||
|
||||
private:
|
||||
size_t val_;
|
||||
};
|
||||
|
||||
using NontrivialVec = absl::InlinedVector<NontrivialType, kInlineElements>;
|
||||
|
||||
#define BENCHMARK_OPERATION(BM_Function) \
|
||||
BENCHMARK_TEMPLATE(BM_Function, TrivialVec, kSmallSize); \
|
||||
BENCHMARK_TEMPLATE(BM_Function, TrivialVec, kLargeSize); \
|
||||
BENCHMARK_TEMPLATE(BM_Function, NontrivialVec, kSmallSize); \
|
||||
BENCHMARK_TEMPLATE(BM_Function, NontrivialVec, kLargeSize)
|
||||
|
||||
template <typename VecT, typename PrepareVec, typename TestVec>
|
||||
void BatchedBenchmark(benchmark::State& state, PrepareVec prepare_vec,
|
||||
TestVec test_vec) {
|
||||
VecT vectors[kBatchSize];
|
||||
|
||||
while (state.KeepRunningBatch(kBatchSize)) {
|
||||
// Prepare batch
|
||||
state.PauseTiming();
|
||||
for (auto& vec : vectors) {
|
||||
prepare_vec(&vec);
|
||||
}
|
||||
benchmark::DoNotOptimize(vectors);
|
||||
state.ResumeTiming();
|
||||
|
||||
// Test batch
|
||||
for (auto& vec : vectors) {
|
||||
test_vec(&vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VecT, size_t Size>
|
||||
void BM_Clear(benchmark::State& state) {
|
||||
BatchedBenchmark<VecT>(
|
||||
state,
|
||||
/* prepare_vec = */ [](VecT* vec) { vec->resize(Size); },
|
||||
/* test_vec = */ [](VecT* vec) { vec->clear(); });
|
||||
}
|
||||
BENCHMARK_OPERATION(BM_Clear);
|
||||
|
||||
} // namespace
|
||||
|
|
55
absl/container/inlined_vector_exception_safety_test.cc
Normal file
55
absl/container/inlined_vector_exception_safety_test.cc
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2019 The Abseil Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/internal/exception_safety_testing.h"
|
||||
#include "absl/container/inlined_vector.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t kInlined = 4;
|
||||
constexpr size_t kSmallSize = kInlined / 2;
|
||||
constexpr size_t kLargeSize = kInlined * 2;
|
||||
|
||||
using Thrower = testing::ThrowingValue<>;
|
||||
using ThrowerAlloc = testing::ThrowingAllocator<Thrower>;
|
||||
|
||||
template <typename Allocator = std::allocator<Thrower>>
|
||||
using InlVec = absl::InlinedVector<Thrower, kInlined, Allocator>;
|
||||
|
||||
TEST(InlinedVector, DefaultConstructor) {
|
||||
testing::TestThrowingCtor<InlVec<>>();
|
||||
|
||||
testing::TestThrowingCtor<InlVec<ThrowerAlloc>>();
|
||||
}
|
||||
|
||||
TEST(InlinedVector, AllocConstructor) {
|
||||
auto alloc = std::allocator<Thrower>();
|
||||
testing::TestThrowingCtor<InlVec<>>(alloc);
|
||||
|
||||
auto throw_alloc = ThrowerAlloc();
|
||||
testing::TestThrowingCtor<InlVec<ThrowerAlloc>>(throw_alloc);
|
||||
}
|
||||
|
||||
TEST(InlinedVector, Clear) {
|
||||
auto small_vec = InlVec<>(kSmallSize);
|
||||
EXPECT_TRUE(testing::TestNothrowOp([&]() { small_vec.clear(); }));
|
||||
|
||||
auto large_vec = InlVec<>(kLargeSize);
|
||||
EXPECT_TRUE(testing::TestNothrowOp([&]() { large_vec.clear(); }));
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -16,6 +16,7 @@
|
|||
#define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
@ -31,6 +32,33 @@ using IsAtLeastForwardIterator = std::is_convertible<
|
|||
typename std::iterator_traits<Iterator>::iterator_category,
|
||||
std::forward_iterator_tag>;
|
||||
|
||||
template <typename AllocatorType, typename ValueType, typename SizeType>
|
||||
void DestroyElements(AllocatorType alloc, ValueType* destroy_first,
|
||||
SizeType destroy_size) {
|
||||
using AllocatorTraits = std::allocator_traits<AllocatorType>;
|
||||
|
||||
// Destroys `destroy_size` elements from `destroy_first`.
|
||||
//
|
||||
// Destroys the range
|
||||
// [`destroy_first`, `destroy_first + destroy_size`).
|
||||
//
|
||||
// NOTE: We assume destructors do not throw and thus make no attempt to roll
|
||||
// back.
|
||||
for (SizeType i = 0; i < destroy_size; ++i) {
|
||||
AllocatorTraits::destroy(alloc, destroy_first + i);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Overwrite unused memory with `0xab` so we can catch uninitialized usage.
|
||||
//
|
||||
// Cast to `void*` to tell the compiler that we don't care that we might be
|
||||
// scribbling on a vtable pointer.
|
||||
void* memory = reinterpret_cast<void*>(destroy_first);
|
||||
size_t memory_size = sizeof(ValueType) * destroy_size;
|
||||
std::memset(memory, 0xab, memory_size);
|
||||
#endif // NDEBUG
|
||||
}
|
||||
|
||||
template <typename T, size_t N, typename A>
|
||||
class Storage {
|
||||
public:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue