diff options
Diffstat (limited to 'absl/container')
-rw-r--r-- | absl/container/BUILD.bazel | 1 | ||||
-rw-r--r-- | absl/container/CMakeLists.txt | 1 | ||||
-rw-r--r-- | absl/container/inlined_vector.h | 6 | ||||
-rw-r--r-- | absl/container/inlined_vector_benchmark.cc | 59 | ||||
-rw-r--r-- | absl/container/inlined_vector_exception_safety_test.cc | 87 | ||||
-rw-r--r-- | absl/container/internal/hashtablez_sampler_test.cc | 2 | ||||
-rw-r--r-- | absl/container/internal/inlined_vector.h | 13 |
7 files changed, 109 insertions, 60 deletions
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index 99a72482467e..331030acd9a6 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -124,6 +124,7 @@ cc_library( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":compressed_tuple", + "//absl/memory", "//absl/meta:type_traits", ], ) diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 526e37af3db2..c75b0a2be7f5 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt @@ -124,6 +124,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} DEPS absl::compressed_tuple + absl::memory absl::type_traits PUBLIC ) diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h index 564c9535129e..c31c319cc2a7 100644 --- a/absl/container/inlined_vector.h +++ b/absl/container/inlined_vector.h @@ -890,7 +890,7 @@ class InlinedVector { template <typename... Args> reference Construct(pointer p, Args&&... args) { - std::allocator_traits<allocator_type>::construct( + absl::allocator_traits<allocator_type>::construct( *storage_.GetAllocPtr(), p, std::forward<Args>(args)...); return *p; } @@ -908,8 +908,8 @@ class InlinedVector { // Destroy [`from`, `to`) in place. void Destroy(pointer from, pointer to) { for (pointer cur = from; cur != to; ++cur) { - std::allocator_traits<allocator_type>::destroy(*storage_.GetAllocPtr(), - cur); + absl::allocator_traits<allocator_type>::destroy(*storage_.GetAllocPtr(), + cur); } #if !defined(NDEBUG) // Overwrite unused memory with `0xab` so we can catch uninitialized usage. diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc index d906997a8d92..b57fc1de9e3b 100644 --- a/absl/container/inlined_vector_benchmark.cc +++ b/absl/container/inlined_vector_benchmark.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <array> #include <string> #include <vector> @@ -373,71 +374,75 @@ 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 kInlinedCapacity = 4; +constexpr size_t kLargeSize = kInlinedCapacity * 2; +constexpr size_t kSmallSize = kInlinedCapacity / 2; constexpr size_t kBatchSize = 100; +template <typename T> +using InlVec = absl::InlinedVector<T, kInlinedCapacity>; + struct TrivialType { size_t val; }; -using TrivialVec = absl::InlinedVector<TrivialType, kInlineElements>; - class NontrivialType { public: - ABSL_ATTRIBUTE_NOINLINE NontrivialType() : val_() {} + ABSL_ATTRIBUTE_NOINLINE NontrivialType() : val_() { + benchmark::DoNotOptimize(*this); + } ABSL_ATTRIBUTE_NOINLINE NontrivialType(const NontrivialType& other) - : val_(other.val_) {} + : val_(other.val_) { + benchmark::DoNotOptimize(*this); + } ABSL_ATTRIBUTE_NOINLINE NontrivialType& operator=( const NontrivialType& other) { val_ = other.val_; + benchmark::DoNotOptimize(*this); return *this; } - ABSL_ATTRIBUTE_NOINLINE ~NontrivialType() noexcept {} + ABSL_ATTRIBUTE_NOINLINE ~NontrivialType() noexcept { + benchmark::DoNotOptimize(*this); + } private: size_t val_; }; -using NontrivialVec = absl::InlinedVector<NontrivialType, kInlineElements>; - -template <typename VecT, typename PrepareVec, typename TestVec> -void BatchedBenchmark(benchmark::State& state, PrepareVec prepare_vec, - TestVec test_vec) { - VecT vectors[kBatchSize]; +template <typename T, typename PrepareVecFn, typename TestVecFn> +void BatchedBenchmark(benchmark::State& state, PrepareVecFn prepare_vec, + TestVecFn test_vec) { + std::array<InlVec<T>, kBatchSize> vector_batch{}; while (state.KeepRunningBatch(kBatchSize)) { // Prepare batch state.PauseTiming(); - for (auto& vec : vectors) { + for (auto& vec : vector_batch) { prepare_vec(&vec); } - benchmark::DoNotOptimize(vectors); + benchmark::DoNotOptimize(vector_batch); state.ResumeTiming(); // Test batch - for (auto& vec : vectors) { + for (auto& vec : vector_batch) { test_vec(&vec); } } } -template <typename VecT, size_t FromSize> +template <typename T, size_t FromSize> void BM_Clear(benchmark::State& state) { - BatchedBenchmark<VecT>( + BatchedBenchmark<T>( state, - /* prepare_vec = */ [](VecT* vec) { vec->resize(FromSize); }, - /* test_vec = */ [](VecT* vec) { vec->clear(); }); + /* prepare_vec = */ [](InlVec<T>* vec) { vec->resize(FromSize); }, + /* test_vec = */ [](InlVec<T>* vec) { vec->clear(); }); } - -BENCHMARK_TEMPLATE(BM_Clear, TrivialVec, kSmallSize); -BENCHMARK_TEMPLATE(BM_Clear, TrivialVec, kLargeSize); - -BENCHMARK_TEMPLATE(BM_Clear, NontrivialVec, kSmallSize); -BENCHMARK_TEMPLATE(BM_Clear, NontrivialVec, kLargeSize); +BENCHMARK_TEMPLATE(BM_Clear, TrivialType, kLargeSize); +BENCHMARK_TEMPLATE(BM_Clear, TrivialType, kSmallSize); +BENCHMARK_TEMPLATE(BM_Clear, NontrivialType, kLargeSize); +BENCHMARK_TEMPLATE(BM_Clear, NontrivialType, kSmallSize); } // namespace diff --git a/absl/container/inlined_vector_exception_safety_test.cc b/absl/container/inlined_vector_exception_safety_test.cc index 0af048b1718a..1aae0b0493ec 100644 --- a/absl/container/inlined_vector_exception_safety_test.cc +++ b/absl/container/inlined_vector_exception_safety_test.cc @@ -20,36 +20,85 @@ namespace { -constexpr size_t kInlined = 4; -constexpr size_t kSmallSize = kInlined / 2; -constexpr size_t kLargeSize = kInlined * 2; +constexpr size_t kInlinedCapacity = 4; +constexpr size_t kLargeSize = kInlinedCapacity * 2; +constexpr size_t kSmallSize = kInlinedCapacity / 2; using Thrower = testing::ThrowingValue<>; -using ThrowerAlloc = testing::ThrowingAllocator<Thrower>; +using MovableThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>; +using ThrowAlloc = testing::ThrowingAllocator<Thrower>; -template <typename Allocator = std::allocator<Thrower>> -using InlVec = absl::InlinedVector<Thrower, kInlined, Allocator>; +using ThrowerVec = absl::InlinedVector<Thrower, kInlinedCapacity>; +using MovableThrowerVec = absl::InlinedVector<MovableThrower, kInlinedCapacity>; -TEST(InlinedVector, DefaultConstructor) { - testing::TestThrowingCtor<InlVec<>>(); +using ThrowAllocThrowerVec = + absl::InlinedVector<Thrower, kInlinedCapacity, ThrowAlloc>; +using ThrowAllocMovableThrowerVec = + absl::InlinedVector<MovableThrower, kInlinedCapacity, ThrowAlloc>; - testing::TestThrowingCtor<InlVec<ThrowerAlloc>>(); +template <typename TheVecT, size_t... TheSizes> +class TestParams { + public: + using VecT = TheVecT; + constexpr static size_t GetSizeAt(size_t i) { return kSizes[1 + i]; } + + private: + constexpr static size_t kSizes[1 + sizeof...(TheSizes)] = {1, TheSizes...}; +}; + +using NoSizeTestParams = + ::testing::Types<TestParams<ThrowerVec>, TestParams<MovableThrowerVec>, + TestParams<ThrowAllocThrowerVec>, + TestParams<ThrowAllocMovableThrowerVec>>; + +using OneSizeTestParams = + ::testing::Types<TestParams<ThrowerVec, kLargeSize>, + TestParams<ThrowerVec, kSmallSize>, + TestParams<MovableThrowerVec, kLargeSize>, + TestParams<MovableThrowerVec, kSmallSize>, + TestParams<ThrowAllocThrowerVec, kLargeSize>, + TestParams<ThrowAllocThrowerVec, kSmallSize>, + TestParams<ThrowAllocMovableThrowerVec, kLargeSize>, + TestParams<ThrowAllocMovableThrowerVec, kSmallSize>>; + +template <typename> +struct NoSizeTest : ::testing::Test {}; +TYPED_TEST_SUITE(NoSizeTest, NoSizeTestParams); + +template <typename> +struct OneSizeTest : ::testing::Test {}; +TYPED_TEST_SUITE(OneSizeTest, OneSizeTestParams); + +// Function that always returns false is correct, but refactoring is required +// for clarity. It's needed to express that, as a contract, certain operations +// should not throw at all. Execution of this function means an exception was +// thrown and thus the test should fail. +// TODO(johnsoncj): Add `testing::NoThrowGuarantee` to the framework +template <typename VecT> +bool NoThrowGuarantee(VecT* /* vec */) { + return false; } -TEST(InlinedVector, AllocConstructor) { - auto alloc = std::allocator<Thrower>(); - testing::TestThrowingCtor<InlVec<>>(alloc); +TYPED_TEST(NoSizeTest, DefaultConstructor) { + using VecT = typename TypeParam::VecT; + using allocator_type = typename VecT::allocator_type; - auto throw_alloc = ThrowerAlloc(); - testing::TestThrowingCtor<InlVec<ThrowerAlloc>>(throw_alloc); + testing::TestThrowingCtor<VecT>(); + + testing::TestThrowingCtor<VecT>(allocator_type{}); } -TEST(InlinedVector, Clear) { - auto small_vec = InlVec<>(kSmallSize); - EXPECT_TRUE(testing::TestNothrowOp([&]() { small_vec.clear(); })); +TYPED_TEST(OneSizeTest, Clear) { + using VecT = typename TypeParam::VecT; + constexpr static auto size = TypeParam::GetSizeAt(0); + + auto tester = testing::MakeExceptionSafetyTester() + .WithInitialValue(VecT(size)) + .WithContracts(NoThrowGuarantee<VecT>); - auto large_vec = InlVec<>(kLargeSize); - EXPECT_TRUE(testing::TestNothrowOp([&]() { large_vec.clear(); })); + EXPECT_TRUE(tester.Test([](VecT* vec) { + vec->clear(); // + })); } } // namespace diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc index d2435ed8a6ad..7f9e8dd21ffc 100644 --- a/absl/container/internal/hashtablez_sampler_test.cc +++ b/absl/container/internal/hashtablez_sampler_test.cc @@ -199,7 +199,7 @@ TEST(HashtablezSamplerTest, Sample) { SetHashtablezSampleParameter(100); int64_t num_sampled = 0; int64_t total = 0; - double sample_rate; + double sample_rate = 0.0; for (int i = 0; i < 1000000; ++i) { HashtablezInfoHandle h = Sample(); ++total; diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index a2b3d24d98e9..79533a41f3d2 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h @@ -22,6 +22,7 @@ #include <utility> #include "absl/container/internal/compressed_tuple.h" +#include "absl/memory/memory.h" #include "absl/meta/type_traits.h" namespace absl { @@ -35,15 +36,7 @@ using IsAtLeastForwardIterator = std::is_convertible< template <typename AllocatorType, typename ValueType, typename SizeType> void DestroyElements(AllocatorType* alloc_ptr, 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. + using AllocatorTraits = absl::allocator_traits<AllocatorType>; for (SizeType i = 0; i < destroy_size; ++i) { AllocatorTraits::destroy(*alloc_ptr, destroy_first + i); } @@ -75,7 +68,7 @@ class Storage { using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; - using AllocatorTraits = std::allocator_traits<allocator_type>; + using AllocatorTraits = absl::allocator_traits<allocator_type>; explicit Storage(const allocator_type& alloc) : metadata_(alloc, /* empty and inlined */ 0) {} |