diff options
Diffstat (limited to 'absl/memory')
-rw-r--r-- | absl/memory/BUILD.bazel | 2 | ||||
-rw-r--r-- | absl/memory/CMakeLists.txt | 79 | ||||
-rw-r--r-- | absl/memory/memory.h | 74 | ||||
-rw-r--r-- | absl/memory/memory_exception_safety_test.cc | 13 | ||||
-rw-r--r-- | absl/memory/memory_test.cc | 42 |
5 files changed, 148 insertions, 62 deletions
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel index 46f47b12..89a312ea 100644 --- a/absl/memory/BUILD.bazel +++ b/absl/memory/BUILD.bazel @@ -19,6 +19,7 @@ load( "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", + "ABSL_EXCEPTIONS_FLAG_LINKOPTS", ) package(default_visibility = ["//visibility:public"]) @@ -53,6 +54,7 @@ cc_test( "memory_exception_safety_test.cc", ], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, deps = [ ":memory", "//absl/base:exception_safety_testing", diff --git a/absl/memory/CMakeLists.txt b/absl/memory/CMakeLists.txt index 5958f5c5..4b494dc0 100644 --- a/absl/memory/CMakeLists.txt +++ b/absl/memory/CMakeLists.txt @@ -14,58 +14,45 @@ # limitations under the License. # -list(APPEND MEMORY_PUBLIC_HEADERS - "memory.h" -) - - -absl_header_library( - TARGET - absl_memory - EXPORT_NAME +absl_cc_library( + NAME memory + HDRS + "memory.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + absl::meta + PUBLIC ) -# -## TESTS -# - -# test memory_test -list(APPEND MEMORY_TEST_SRC - "memory_test.cc" - ${MEMORY_PUBLIC_HEADERS} -) -set(MEMORY_TEST_PUBLIC_LIBRARIES absl::base absl::memory) - - - -absl_test( - TARGET +absl_cc_test( + NAME memory_test - SOURCES - ${MEMORY_TEST_SRC} - PUBLIC_LIBRARIES - ${MEMORY_TEST_PUBLIC_LIBRARIES} -) - - -# test memory_exception_safety_test -set(MEMORY_EXCEPTION_SAFETY_TEST_SRC "memory_exception_safety_test.cc") -set(MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES - absl::memory - absl_base_internal_exception_safety_testing + SRCS + "memory_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::memory + absl::base + absl::core_headers + gmock_main ) -absl_test( - TARGET +absl_cc_test( + NAME memory_exception_safety_test - SOURCES - ${MEMORY_EXCEPTION_SAFETY_TEST_SRC} - PUBLIC_LIBRARIES - ${MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS + SRCS + "memory_exception_safety_test.cc" + COPTS + ${ABSL_TEST_COPTS} ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::memory + absl::exception_safety_testing + gmock_main ) - - - diff --git a/absl/memory/memory.h b/absl/memory/memory.h index 54ff2182..34cfb285 100644 --- a/absl/memory/memory.h +++ b/absl/memory/memory.h @@ -34,22 +34,36 @@ #include "absl/meta/type_traits.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { // ----------------------------------------------------------------------------- // Function Template: WrapUnique() // ----------------------------------------------------------------------------- // -// Adopts ownership from a raw pointer and transfers it to the returned -// `std::unique_ptr`, whose type is deduced. DO NOT specify the template type T -// when calling WrapUnique. +// Adopts ownership from a raw pointer and transfers it to the returned +// `std::unique_ptr`, whose type is deduced. Because of this deduction, *do not* +// specify the template type `T` when calling `WrapUnique`. // // Example: // X* NewX(int, int); // auto x = WrapUnique(NewX(1, 2)); // 'x' is std::unique_ptr<X>. // -// `absl::WrapUnique` is useful for capturing the output of a raw pointer -// factory. However, prefer 'absl::make_unique<T>(args...) over +// The purpose of WrapUnique is to automatically deduce the pointer type. If you +// wish to make the type explicit, for readability reasons or because you prefer +// to use a base-class pointer rather than a derived one, just use +// `std::unique_ptr` directly. +// +// Example: +// X* Factory(int, int); +// auto x = std::unique_ptr<X>(Factory(1, 2)); +// - or - +// std::unique_ptr<X> x(Factory(1, 2)); +// +// This has the added advantage of working whether Factory returns a raw +// pointer or a `std::unique_ptr`. +// +// While `absl::WrapUnique` is useful for capturing the output of a raw +// pointer factory, prefer 'absl::make_unique<T>(args...)' over // 'absl::WrapUnique(new T(args...))'. // // auto x = WrapUnique(new X(1, 2)); // works, but nonideal. @@ -84,7 +98,11 @@ struct MakeUniqueResult<T[N]> { } // namespace memory_internal -#if __cplusplus >= 201402L || defined(_MSC_VER) +// gcc 4.8 has __cplusplus at 201301 but doesn't define make_unique. Other +// supported compilers either just define __cplusplus as 201103 but have +// make_unique (msvc), or have make_unique whenever __cplusplus > 201103 (clang) +#if (__cplusplus > 201103L || defined(_MSC_VER)) && \ + !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8) using std::make_unique; #else // ----------------------------------------------------------------------------- @@ -582,7 +600,7 @@ struct allocator_traits { return a.max_size(); } static size_type max_size_impl(char, const Alloc&) { - return std::numeric_limits<size_type>::max() / sizeof(value_type); + return (std::numeric_limits<size_type>::max)() / sizeof(value_type); } template <typename A> @@ -637,7 +655,45 @@ struct default_allocator_is_nothrow : std::true_type {}; struct default_allocator_is_nothrow : std::false_type {}; #endif -} // inline namespace lts_2018_06_20 +namespace memory_internal { +template <typename Allocator, typename Iterator, typename... Args> +void ConstructRange(Allocator& alloc, Iterator first, Iterator last, + const Args&... args) { + for (Iterator cur = first; cur != last; ++cur) { + ABSL_INTERNAL_TRY { + std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur), + args...); + } + ABSL_INTERNAL_CATCH_ANY { + while (cur != first) { + --cur; + std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur)); + } + ABSL_INTERNAL_RETHROW; + } + } +} + +template <typename Allocator, typename Iterator, typename InputIterator> +void CopyRange(Allocator& alloc, Iterator destination, InputIterator first, + InputIterator last) { + for (Iterator cur = destination; first != last; + static_cast<void>(++cur), static_cast<void>(++first)) { + ABSL_INTERNAL_TRY { + std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur), + *first); + } + ABSL_INTERNAL_CATCH_ANY { + while (cur != destination) { + --cur; + std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur)); + } + ABSL_INTERNAL_RETHROW; + } + } +} +} // namespace memory_internal +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_MEMORY_MEMORY_H_ diff --git a/absl/memory/memory_exception_safety_test.cc b/absl/memory/memory_exception_safety_test.cc index dc00f349..9661502d 100644 --- a/absl/memory/memory_exception_safety_test.cc +++ b/absl/memory/memory_exception_safety_test.cc @@ -18,19 +18,22 @@ #include "absl/base/internal/exception_safety_testing.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace { -using Thrower = ::testing::ThrowingValue<>; +constexpr int kLength = 50; +using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>; +using ThrowerStorage = + absl::aligned_storage_t<sizeof(Thrower), alignof(Thrower)>; +using ThrowerList = std::array<ThrowerStorage, kLength>; TEST(MakeUnique, CheckForLeaks) { constexpr int kValue = 321; - constexpr size_t kLength = 10; auto tester = testing::MakeExceptionSafetyTester() .WithInitialValue(Thrower(kValue)) // Ensures make_unique does not modify the input. The real // test, though, is ConstructorTracker checking for leaks. - .WithInvariants(testing::strong_guarantee); + .WithContracts(testing::strong_guarantee); EXPECT_TRUE(tester.Test([](Thrower* thrower) { static_cast<void>(absl::make_unique<Thrower>(*thrower)); @@ -47,5 +50,5 @@ TEST(MakeUnique, CheckForLeaks) { } } // namespace -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc index dee9b486..21fe32f9 100644 --- a/absl/memory/memory_test.cc +++ b/absl/memory/memory_test.cc @@ -69,6 +69,45 @@ TEST(MakeUniqueTest, Basic) { EXPECT_EQ("hi", *p); } +// InitializationVerifier fills in a pattern when allocated so we can +// distinguish between its default and value initialized states (without +// accessing truly uninitialized memory). +struct InitializationVerifier { + static constexpr int kDefaultScalar = 0x43; + static constexpr int kDefaultArray = 0x4B; + + static void* operator new(size_t n) { + void* ret = ::operator new(n); + memset(ret, kDefaultScalar, n); + return ret; + } + + static void* operator new[](size_t n) { + void* ret = ::operator new[](n); + memset(ret, kDefaultArray, n); + return ret; + } + + int a; + int b; +}; + +TEST(Initialization, MakeUnique) { + auto p = absl::make_unique<InitializationVerifier>(); + + EXPECT_EQ(0, p->a); + EXPECT_EQ(0, p->b); +} + +TEST(Initialization, MakeUniqueArray) { + auto p = absl::make_unique<InitializationVerifier[]>(2); + + EXPECT_EQ(0, p[0].a); + EXPECT_EQ(0, p[0].b); + EXPECT_EQ(0, p[1].a); + EXPECT_EQ(0, p[1].b); +} + struct MoveOnly { MoveOnly() = default; explicit MoveOnly(int i1) : ip1{new int{i1}} {} @@ -145,11 +184,10 @@ TEST(Make_UniqueTest, NotAmbiguousWithStdMakeUnique) { explicit TakesStdType(const std::vector<int> &vec) {} }; using absl::make_unique; - make_unique<TakesStdType>(std::vector<int>()); + (void)make_unique<TakesStdType>(std::vector<int>()); } #if 0 -// TODO(billydonahue): Make a proper NC test. // These tests shouldn't compile. TEST(MakeUniqueTestNC, AcceptMoveOnlyLvalue) { auto m = MoveOnly(); |