Skip to content

Commit

Permalink
Export of internal Abseil changes.
Browse files Browse the repository at this point in the history
--
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
  • Loading branch information
Abseil Team authored and Bara Kopi committed May 10, 2019
1 parent 27c2f6e commit 0cbdc77
Show file tree
Hide file tree
Showing 18 changed files with 422 additions and 36 deletions.
2 changes: 1 addition & 1 deletion absl/base/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ cc_test(

cc_test(
name = "low_level_alloc_test",
size = "small",
size = "medium",
srcs = ["internal/low_level_alloc_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
Expand Down
12 changes: 12 additions & 0 deletions absl/container/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
16 changes: 16 additions & 0 deletions absl/container/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 12 additions & 8 deletions absl/container/inlined_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()`
Expand Down
74 changes: 71 additions & 3 deletions absl/container/inlined_vector_benchmark.cc
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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 {
Expand Down Expand Up @@ -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 changes: 55 additions & 0 deletions absl/container/inlined_vector_exception_safety_test.cc
Original file line number Diff line number Diff line change
@@ -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
28 changes: 28 additions & 0 deletions absl/container/internal/inlined_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_

#include <cstddef>
#include <cstring>
#include <iterator>
#include <memory>
#include <utility>
Expand All @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions absl/debugging/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ cc_test(
"//conditions:default": [],
}),
linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
tags = ["notsan"],
deps = [
":leak_check_api_enabled_for_testing",
"//absl/base",
Expand All @@ -256,6 +257,7 @@ cc_test(
srcs = ["leak_check_test.cc"],
copts = ["-UABSL_EXPECT_LEAK_SANITIZER"],
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["noasan"],
deps = [
":leak_check_api_disabled_for_testing",
"//absl/base", # for raw_logging
Expand All @@ -271,6 +273,7 @@ cc_test(
name = "disabled_leak_check_test",
srcs = ["leak_check_fail_test.cc"],
linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
tags = ["notsan"],
deps = [
":leak_check_api_enabled_for_testing",
":leak_check_disable",
Expand Down
2 changes: 1 addition & 1 deletion absl/hash/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ cc_library(
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":city",
"//absl/base:core_headers",
"//absl/base:endian",
"//absl/container:fixed_array",
"//absl/hash:city",
"//absl/meta:type_traits",
"//absl/numeric:int128",
"//absl/strings",
Expand Down
4 changes: 2 additions & 2 deletions absl/strings/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ cc_test(

cc_test(
name = "numbers_test",
size = "small",
size = "medium",
srcs = [
"internal/numbers_test_common.h",
"numbers_test.cc",
Expand Down Expand Up @@ -628,7 +628,7 @@ cc_test(

cc_test(
name = "str_format_convert_test",
size = "small",
size = "medium",
srcs = ["internal/str_format/convert_test.cc"],
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
Expand Down
15 changes: 10 additions & 5 deletions absl/strings/str_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
// * A `ParsedFormat` instance, which encapsulates a specific, pre-compiled
// format string for a specific set of type(s), and which can be passed
// between API boundaries. (The `FormatSpec` type should not be used
// directly.)
// directly except as an argument type for wrapper functions.)
//
// The `str_format` library provides the ability to output its format strings to
// arbitrary sink types:
Expand Down Expand Up @@ -157,10 +157,15 @@ class FormatCountCapture {
// FormatSpec
//
// The `FormatSpec` type defines the makeup of a format string within the
// `str_format` library. You should not need to use or manipulate this type
// directly. A `FormatSpec` is a variadic class template that is evaluated at
// compile-time, according to the format string and arguments that are passed
// to it.
// `str_format` library. It is a variadic class template that is evaluated at
// compile-time, according to the format string and arguments that are passed to
// it.
//
// You should not need to manipulate this type directly. You should only name it
// if you are writing wrapper functions which accept format arguments that will
// be provided unmodified to functions in this library. Such a wrapper function
// might be a class method that provides format arguments and/or internally uses
// the result of formatting.
//
// For a `FormatSpec` to be valid at compile-time, it must be provided as
// either:
Expand Down
Loading

0 comments on commit 0cbdc77

Please sign in to comment.