summaryrefslogtreecommitdiff
path: root/absl/memory
diff options
context:
space:
mode:
Diffstat (limited to 'absl/memory')
-rw-r--r--absl/memory/BUILD.bazel47
-rw-r--r--absl/memory/README.md22
-rw-r--r--absl/memory/memory.h622
-rw-r--r--absl/memory/memory_test.cc590
4 files changed, 1281 insertions, 0 deletions
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel
new file mode 100644
index 00000000..91fc55fc
--- /dev/null
+++ b/absl/memory/BUILD.bazel
@@ -0,0 +1,47 @@
+#
+# Copyright 2017 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
+#
+# http://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.
+#
+
+load(
+ "//absl:copts.bzl",
+ "ABSL_DEFAULT_COPTS",
+ "ABSL_TEST_COPTS",
+)
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "memory",
+ hdrs = ["memory.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = ["//absl/meta:type_traits"],
+)
+
+cc_test(
+ name = "memory_test",
+ srcs = ["memory_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":memory",
+ "//absl/base",
+ "//absl/base:core_headers",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
diff --git a/absl/memory/README.md b/absl/memory/README.md
new file mode 100644
index 00000000..72eddd9c
--- /dev/null
+++ b/absl/memory/README.md
@@ -0,0 +1,22 @@
+# ABSL Memory
+
+This directory contains packages related to abstractions for managing memory
+within objects.
+
+## Library Listing
+
+Only one library target exists within this directory at this time:
+
+* **memory** (`//absl/memory:memory`) provides classes and
+ utility functions for managing memory associated with pointers.
+
+
+## Memory Library File Listing
+
+The following header files are directly included within the
+`absl::memory` library:
+
+### Smart Pointer Management
+
+* `memory.h`
+ <br/>Pointer memory management abstractions for handling unique pointers
diff --git a/absl/memory/memory.h b/absl/memory/memory.h
new file mode 100644
index 00000000..c6799608
--- /dev/null
+++ b/absl/memory/memory.h
@@ -0,0 +1,622 @@
+// Copyright 2017 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
+//
+// http://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.
+//
+// -----------------------------------------------------------------------------
+// File: memory.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains utility functions for managing the creation and
+// conversion of smart pointers. This file is an extension to the C++
+// standard <memory> library header file.
+
+#ifndef ABSL_MEMORY_MEMORY_H_
+#define ABSL_MEMORY_MEMORY_H_
+
+#include <cstddef>
+#include <limits>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// Function Template: WrapUnique()
+// -----------------------------------------------------------------------------
+//
+// Transfers ownership of a raw pointer to a `std::unique_ptr`. The returned
+// value is a `std::unique_ptr` of deduced type.
+//
+// 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
+// 'absl::WrapUnique(new T(args...))'.
+//
+// auto x = WrapUnique(new X(1, 2)); // works, but nonideal.
+// auto x = make_unique<X>(1, 2); // safer, standard, avoids raw 'new'.
+//
+// Note that `absl::WrapUnique(p)` is valid only if `delete p` is a valid
+// expression. In particular, `absl::WrapUnique()` cannot wrap pointers to
+// arrays, functions or void, and it must not be used to capture pointers
+// obtained from array-new expressions (even though that would compile!).
+template <typename T>
+std::unique_ptr<T> WrapUnique(T* ptr) {
+ static_assert(!std::is_array<T>::value, "array types are unsupported");
+ static_assert(std::is_object<T>::value, "non-object types are unsupported");
+ return std::unique_ptr<T>(ptr);
+}
+
+namespace memory_internal {
+
+// Traits to select proper overload and return type for `absl::make_unique<>`.
+template <typename T>
+struct MakeUniqueResult {
+ using scalar = std::unique_ptr<T>;
+};
+template <typename T>
+struct MakeUniqueResult<T[]> {
+ using array = std::unique_ptr<T[]>;
+};
+template <typename T, size_t N>
+struct MakeUniqueResult<T[N]> {
+ using invalid = void;
+};
+
+} // namespace memory_internal
+
+// -----------------------------------------------------------------------------
+// Function Template: make_unique<T>()
+// -----------------------------------------------------------------------------
+//
+// Creates a `std::unique_ptr<>`, while avoiding issues creating temporaries
+// during the construction process. `absl::make_unique<>` also avoids redundant
+// type declarations, by avoiding the need to explicitly use the `new` operator.
+//
+// This implementation of `absl::make_unique<>` is designed for C++11 code and
+// will be replaced in C++14 by the equivalent `std::make_unique<>` abstraction.
+// `absl::make_unique<>` is designed to be 100% compatible with
+// `std::make_unique<>` so that the eventual migration will involve a simple
+// rename operation.
+//
+// For more background on why `std::unique_ptr<T>(new T(a,b))` is problematic,
+// see Herb Sutter's explanation on
+// (Exception-Safe Function Calls)[http://herbsutter.com/gotw/_102/].
+// (In general, reviewers should treat `new T(a,b)` with scrutiny.)
+//
+// Example usage:
+//
+// auto p = make_unique<X>(args...); // 'p' is a std::unique_ptr<X>
+// auto pa = make_unique<X[]>(5); // 'pa' is a std::unique_ptr<X[]>
+//
+// Three overloads of `absl::make_unique` are required:
+//
+// - For non-array T:
+//
+// Allocates a T with `new T(std::forward<Args> args...)`,
+// forwarding all `args` to T's constructor.
+// Returns a `std::unique_ptr<T>` owning that object.
+//
+// - For an array of unknown bounds T[]:
+//
+// `absl::make_unique<>` will allocate an array T of type U[] with
+// `new U[n]()` and return a `std::unique_ptr<U[]>` owning that array.
+//
+// Note that 'U[n]()' is different from 'U[n]', and elements will be
+// value-initialized. Note as well that `std::unique_ptr` will perform its
+// own destruction of the array elements upon leaving scope, even though
+// the array [] does not have a default destructor.
+//
+// NOTE: an array of unknown bounds T[] may still be (and often will be)
+// initialized to have a size, and will still use this overload. E.g:
+//
+// auto my_array = absl::make_unique<int[]>(10);
+//
+// - For an array of known bounds T[N]:
+//
+// `absl::make_unique<>` is deleted (like with `std::make_unique<>`) as
+// this overload is not useful.
+//
+// NOTE: an array of known bounds T[N] is not considered a useful
+// construction, and may cause undefined behavior in templates. E.g:
+//
+// auto my_array = absl::make_unique<int[10]>();
+//
+// In those cases, of course, you can still use the overload above and
+// simply initialize it to its desired size:
+//
+// auto my_array = absl::make_unique<int[]>(10);
+
+// `absl::make_unique` overload for non-array types.
+template <typename T, typename... Args>
+typename memory_internal::MakeUniqueResult<T>::scalar make_unique(
+ Args&&... args) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+// `absl::make_unique` overload for an array T[] of unknown bounds.
+// The array allocation needs to use the `new T[size]` form and cannot take
+// element constructor arguments. The `std::unique_ptr` will manage destructing
+// these array elements.
+template <typename T>
+typename memory_internal::MakeUniqueResult<T>::array make_unique(size_t n) {
+ return std::unique_ptr<T>(new typename absl::remove_extent_t<T>[n]());
+}
+
+// `absl::make_unique` overload for an array T[N] of known bounds.
+// This construction will be rejected.
+template <typename T, typename... Args>
+typename memory_internal::MakeUniqueResult<T>::invalid make_unique(
+ Args&&... /* args */) = delete;
+
+// -----------------------------------------------------------------------------
+// Function Template: RawPtr()
+// -----------------------------------------------------------------------------
+//
+// Extracts the raw pointer from a pointer-like 'ptr'. `absl::RawPtr` is useful
+// within templates that need to handle a complement of raw pointers,
+// `std::nullptr_t`, and smart pointers.
+template <typename T>
+auto RawPtr(T&& ptr) -> decltype(&*ptr) {
+ // ptr is a forwarding reference to support Ts with non-const operators.
+ return (ptr != nullptr) ? &*ptr : nullptr;
+}
+inline std::nullptr_t RawPtr(std::nullptr_t) { return nullptr; }
+
+// -----------------------------------------------------------------------------
+// Function Template: ShareUniquePtr()
+// -----------------------------------------------------------------------------
+//
+// Transforms a `std::unique_ptr` rvalue into a `std::shared_ptr`. The returned
+// value is a `std::shared_ptr` of deduced type and ownership is transferred to
+// the shared pointer.
+//
+// Example:
+//
+// auto up = absl::make_unique<int>(10);
+// auto sp = absl::ShareUniquePtr(std::move(up)); // shared_ptr<int>
+// CHECK_EQ(*sp, 10);
+// CHECK(up == nullptr);
+//
+// Note that this conversion is correct even when T is an array type, although
+// the resulting shared pointer may not be very useful.
+//
+// Implements the resolution of [LWG 2415](http://wg21.link/lwg2415), by which a
+// null shared pointer does not attempt to call the deleter.
+template <typename T, typename D>
+std::shared_ptr<T> ShareUniquePtr(std::unique_ptr<T, D>&& ptr) {
+ return ptr ? std::shared_ptr<T>(std::move(ptr)) : std::shared_ptr<T>();
+}
+
+// -----------------------------------------------------------------------------
+// Function Template: WeakenPtr()
+// -----------------------------------------------------------------------------
+//
+// Creates a weak pointer associated with a given shared pointer. The returned
+// value is a `std::weak_ptr` of deduced type.
+//
+// Example:
+//
+// auto sp = std::make_shared<int>(10);
+// auto wp = absl::WeakenPtr(sp);
+// CHECK_EQ(sp.get(), wp.lock().get());
+// sp.reset();
+// CHECK(wp.lock() == nullptr);
+//
+template <typename T>
+std::weak_ptr<T> WeakenPtr(const std::shared_ptr<T>& ptr) {
+ return std::weak_ptr<T>(ptr);
+}
+
+namespace memory_internal {
+
+// ExtractOr<E, O, D>::type evaluates to E<O> if possible. Otherwise, D.
+template <template <typename> class Extract, typename Obj, typename Default,
+ typename>
+struct ExtractOr {
+ using type = Default;
+};
+
+template <template <typename> class Extract, typename Obj, typename Default>
+struct ExtractOr<Extract, Obj, Default, void_t<Extract<Obj>>> {
+ using type = Extract<Obj>;
+};
+
+template <template <typename> class Extract, typename Obj, typename Default>
+using ExtractOrT = typename ExtractOr<Extract, Obj, Default, void>::type;
+
+// Extractors for the features of allocators.
+template <typename T>
+using GetPointer = typename T::pointer;
+
+template <typename T>
+using GetConstPointer = typename T::const_pointer;
+
+template <typename T>
+using GetVoidPointer = typename T::void_pointer;
+
+template <typename T>
+using GetConstVoidPointer = typename T::const_void_pointer;
+
+template <typename T>
+using GetDifferenceType = typename T::difference_type;
+
+template <typename T>
+using GetSizeType = typename T::size_type;
+
+template <typename T>
+using GetPropagateOnContainerCopyAssignment =
+ typename T::propagate_on_container_copy_assignment;
+
+template <typename T>
+using GetPropagateOnContainerMoveAssignment =
+ typename T::propagate_on_container_move_assignment;
+
+template <typename T>
+using GetPropagateOnContainerSwap = typename T::propagate_on_container_swap;
+
+template <typename T>
+using GetIsAlwaysEqual = typename T::is_always_equal;
+
+template <typename T>
+struct GetFirstArg;
+
+template <template <typename...> class Class, typename T, typename... Args>
+struct GetFirstArg<Class<T, Args...>> {
+ using type = T;
+};
+
+template <typename Ptr, typename = void>
+struct ElementType {
+ using type = typename GetFirstArg<Ptr>::type;
+};
+
+template <typename T>
+struct ElementType<T, void_t<typename T::element_type>> {
+ using type = typename T::element_type;
+};
+
+template <typename T, typename U>
+struct RebindFirstArg;
+
+template <template <typename...> class Class, typename T, typename... Args,
+ typename U>
+struct RebindFirstArg<Class<T, Args...>, U> {
+ using type = Class<U, Args...>;
+};
+
+template <typename T, typename U, typename = void>
+struct RebindPtr {
+ using type = typename RebindFirstArg<T, U>::type;
+};
+
+template <typename T, typename U>
+struct RebindPtr<T, U, void_t<typename T::template rebind<U>>> {
+ using type = typename T::template rebind<U>;
+};
+
+template <typename T, typename U, typename = void>
+struct RebindAlloc {
+ using type = typename RebindFirstArg<T, U>::type;
+};
+
+template <typename T, typename U>
+struct RebindAlloc<T, U, void_t<typename T::template rebind<U>::other>> {
+ using type = typename T::template rebind<U>::other;
+};
+
+} // namespace memory_internal
+
+// -----------------------------------------------------------------------------
+// Class Template: pointer_traits
+// -----------------------------------------------------------------------------
+//
+// An implementation of C++11's std::pointer_traits.
+//
+// Provided for portability on toolchains that have a working C++11 compiler,
+// but the standard library is lacking in C++11 support. For example, some
+// version of the Android NDK.
+//
+
+template <typename Ptr>
+struct pointer_traits {
+ using pointer = Ptr;
+
+ // element_type:
+ // Ptr::element_type if present. Otherwise T if Ptr is a template
+ // instantiation Template<T, Args...>
+ using element_type = typename memory_internal::ElementType<Ptr>::type;
+
+ // difference_type:
+ // Ptr::difference_type if present, otherwise std::ptrdiff_t
+ using difference_type =
+ memory_internal::ExtractOrT<memory_internal::GetDifferenceType, Ptr,
+ std::ptrdiff_t>;
+
+ // rebind:
+ // Ptr::rebind<U> if exists, otherwise Template<U, Args...> if Ptr is a
+ // template instantiation Template<T, Args...>
+ template <typename U>
+ using rebind = typename memory_internal::RebindPtr<Ptr, U>::type;
+
+ // pointer_to:
+ // Calls Ptr::pointer_to(r)
+ static pointer pointer_to(element_type& r) { // NOLINT(runtime/references)
+ return Ptr::pointer_to(r);
+ }
+};
+
+// Specialization for T*.
+template <typename T>
+struct pointer_traits<T*> {
+ using pointer = T*;
+ using element_type = T;
+ using difference_type = std::ptrdiff_t;
+
+ template <typename U>
+ using rebind = U*;
+
+ // pointer_to:
+ // Calls std::addressof(r)
+ static pointer pointer_to(
+ element_type& r) noexcept { // NOLINT(runtime/references)
+ return std::addressof(r);
+ }
+};
+
+// -----------------------------------------------------------------------------
+// Class Template: allocator_traits
+// -----------------------------------------------------------------------------
+//
+// A C++11 compatible implementation of C++17's std::allocator_traits.
+//
+template <typename Alloc>
+struct allocator_traits {
+ using allocator_type = Alloc;
+
+ // value_type:
+ // Alloc::value_type
+ using value_type = typename Alloc::value_type;
+
+ // pointer:
+ // Alloc::pointer if present, otherwise value_type*
+ using pointer = memory_internal::ExtractOrT<memory_internal::GetPointer,
+ Alloc, value_type*>;
+
+ // const_pointer:
+ // Alloc::const_pointer if present, otherwise
+ // absl::pointer_traits<pointer>::rebind<const value_type>
+ using const_pointer =
+ memory_internal::ExtractOrT<memory_internal::GetConstPointer, Alloc,
+ typename absl::pointer_traits<pointer>::
+ template rebind<const value_type>>;
+
+ // void_pointer:
+ // Alloc::void_pointer if present, otherwise
+ // absl::pointer_traits<pointer>::rebind<void>
+ using void_pointer = memory_internal::ExtractOrT<
+ memory_internal::GetVoidPointer, Alloc,
+ typename absl::pointer_traits<pointer>::template rebind<void>>;
+
+ // const_void_pointer:
+ // Alloc::const_void_pointer if present, otherwise
+ // absl::pointer_traits<pointer>::rebind<const void>
+ using const_void_pointer = memory_internal::ExtractOrT<
+ memory_internal::GetConstVoidPointer, Alloc,
+ typename absl::pointer_traits<pointer>::template rebind<const void>>;
+
+ // difference_type:
+ // Alloc::difference_type if present, otherwise
+ // absl::pointer_traits<pointer>::difference_type
+ using difference_type = memory_internal::ExtractOrT<
+ memory_internal::GetDifferenceType, Alloc,
+ typename absl::pointer_traits<pointer>::difference_type>;
+
+ // size_type:
+ // Alloc::size_type if present, otherwise
+ // std::make_unsigned<difference_type>::type
+ using size_type = memory_internal::ExtractOrT<
+ memory_internal::GetSizeType, Alloc,
+ typename std::make_unsigned<difference_type>::type>;
+
+ // propagate_on_container_copy_assignment:
+ // Alloc::propagate_on_container_copy_assignment if present, otherwise
+ // std::false_type
+ using propagate_on_container_copy_assignment = memory_internal::ExtractOrT<
+ memory_internal::GetPropagateOnContainerCopyAssignment, Alloc,
+ std::false_type>;
+
+ // propagate_on_container_move_assignment:
+ // Alloc::propagate_on_container_move_assignment if present, otherwise
+ // std::false_type
+ using propagate_on_container_move_assignment = memory_internal::ExtractOrT<
+ memory_internal::GetPropagateOnContainerMoveAssignment, Alloc,
+ std::false_type>;
+
+ // propagate_on_container_swap:
+ // Alloc::propagate_on_container_swap if present, otherwise std::false_type
+ using propagate_on_container_swap =
+ memory_internal::ExtractOrT<memory_internal::GetPropagateOnContainerSwap,
+ Alloc, std::false_type>;
+
+ // is_always_equal:
+ // Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type
+ using is_always_equal =
+ memory_internal::ExtractOrT<memory_internal::GetIsAlwaysEqual, Alloc,
+ typename std::is_empty<Alloc>::type>;
+
+ // rebind_alloc:
+ // Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc
+ // is Alloc<U, Args>
+ template <typename T>
+ using rebind_alloc = typename memory_internal::RebindAlloc<Alloc, T>::type;
+
+ // rebind_traits:
+ // absl::allocator_traits<rebind_alloc<T>>
+ template <typename T>
+ using rebind_traits = absl::allocator_traits<rebind_alloc<T>>;
+
+ // allocate(Alloc& a, size_type n):
+ // Calls a.allocate(n)
+ static pointer allocate(Alloc& a, // NOLINT(runtime/references)
+ size_type n) {
+ return a.allocate(n);
+ }
+
+ // allocate(Alloc& a, size_type n, const_void_pointer hint):
+ // Calls a.allocate(n, hint) if possible.
+ // If not possible, calls a.allocate(n)
+ static pointer allocate(Alloc& a, size_type n, // NOLINT(runtime/references)
+ const_void_pointer hint) {
+ return allocate_impl(0, a, n, hint);
+ }
+
+ // deallocate(Alloc& a, pointer p, size_type n):
+ // Calls a.deallocate(p, n)
+ static void deallocate(Alloc& a, pointer p, // NOLINT(runtime/references)
+ size_type n) {
+ a.deallocate(p, n);
+ }
+
+ // construct(Alloc& a, T* p, Args&&... args):
+ // Calls a.construct(p, std::forward<Args>(args)...) if possible.
+ // If not possible, calls
+ // ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
+ template <typename T, typename... Args>
+ static void construct(Alloc& a, T* p, // NOLINT(runtime/references)
+ Args&&... args) {
+ construct_impl(0, a, p, std::forward<Args>(args)...);
+ }
+
+ // destroy(Alloc& a, T* p):
+ // Calls a.destroy(p) if possible. If not possible, calls p->~T().
+ template <typename T>
+ static void destroy(Alloc& a, T* p) { // NOLINT(runtime/references)
+ destroy_impl(0, a, p);
+ }
+
+ // max_size(const Alloc& a):
+ // Returns a.max_size() if possible. If not possible, returns
+ // std::numeric_limits<size_type>::max() / sizeof(value_type)
+ static size_type max_size(const Alloc& a) { return max_size_impl(0, a); }
+
+ // select_on_container_copy_construction(const Alloc& a):
+ // Returns a.select_on_container_copy_construction() if possible.
+ // If not possible, returns a.
+ static Alloc select_on_container_copy_construction(const Alloc& a) {
+ return select_on_container_copy_construction_impl(0, a);
+ }
+
+ private:
+ template <typename A>
+ static auto allocate_impl(int, A& a, // NOLINT(runtime/references)
+ size_type n, const_void_pointer hint)
+ -> decltype(a.allocate(n, hint)) {
+ return a.allocate(n, hint);
+ }
+ static pointer allocate_impl(char, Alloc& a, // NOLINT(runtime/references)
+ size_type n, const_void_pointer) {
+ return a.allocate(n);
+ }
+
+ template <typename A, typename... Args>
+ static auto construct_impl(int, A& a, // NOLINT(runtime/references)
+ Args&&... args)
+ -> decltype(a.construct(std::forward<Args>(args)...)) {
+ a.construct(std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename... Args>
+ static void construct_impl(char, Alloc&, T* p, Args&&... args) {
+ ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
+ }
+
+ template <typename A, typename T>
+ static auto destroy_impl(int, A& a, // NOLINT(runtime/references)
+ T* p) -> decltype(a.destroy(p)) {
+ a.destroy(p);
+ }
+ template <typename T>
+ static void destroy_impl(char, Alloc&, T* p) {
+ p->~T();
+ }
+
+ template <typename A>
+ static auto max_size_impl(int, const A& a) -> decltype(a.max_size()) {
+ return a.max_size();
+ }
+ static size_type max_size_impl(char, const Alloc&) {
+ return std::numeric_limits<size_type>::max() / sizeof(value_type);
+ }
+
+ template <typename A>
+ static auto select_on_container_copy_construction_impl(int, const A& a)
+ -> decltype(a.select_on_container_copy_construction()) {
+ return a.select_on_container_copy_construction();
+ }
+ static Alloc select_on_container_copy_construction_impl(char,
+ const Alloc& a) {
+ return a;
+ }
+};
+
+namespace memory_internal {
+
+// This template alias transforms Alloc::is_nothrow into a metafunction with
+// Alloc as a parameter so it can be used with ExtractOrT<>.
+template <typename Alloc>
+using GetIsNothrow = typename Alloc::is_nothrow;
+
+} // namespace memory_internal
+
+// ABSL_ALLOCATOR_NOTHROW is a build time configuration macro for user to
+// specify whether the default allocation function can throw or never throws.
+// If the allocation function never throws, user should define it to a non-zero
+// value (e.g. via `-DABSL_ALLOCATOR_NOTHROW`).
+// If the allocation function can throw, user should leave it undefined or
+// define it to zero.
+//
+// allocator_is_nothrow<Alloc> is a traits class that derives from
+// Alloc::is_nothrow if present, otherwise std::false_type. It's specialized
+// for Alloc = std::allocator<T> for any type T according to the state of
+// ABSL_ALLOCATOR_NOTHROW.
+//
+// default_allocator_is_nothrow is a class that derives from std::true_type
+// when the default allocator (global operator new) never throws, and
+// std::false_type when it can throw. It is a convenience shorthand for writing
+// allocator_is_nothrow<std::allocator<T>> (T can be any type).
+// NOTE: allocator_is_nothrow<std::allocator<T>> is guaranteed to derive from
+// the same type for all T, because users should specialize neither
+// allocator_is_nothrow nor std::allocator.
+template <typename Alloc>
+struct allocator_is_nothrow
+ : memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc,
+ std::false_type> {};
+
+#if ABSL_ALLOCATOR_NOTHROW
+template <typename T>
+struct allocator_is_nothrow<std::allocator<T>> : std::true_type {};
+struct default_allocator_is_nothrow : std::true_type {};
+#else
+struct default_allocator_is_nothrow : std::false_type {};
+#endif
+
+} // namespace absl
+
+#endif // ABSL_MEMORY_MEMORY_H_
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc
new file mode 100644
index 00000000..8a5f5522
--- /dev/null
+++ b/absl/memory/memory_test.cc
@@ -0,0 +1,590 @@
+// Copyright 2017 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
+//
+// http://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.
+
+// Tests for pointer utilities.
+
+#include "absl/memory/memory.h"
+
+#include <sys/types.h>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Return;
+
+// This class creates observable behavior to verify that a destructor has
+// been called, via the instance_count variable.
+class DestructorVerifier {
+ public:
+ DestructorVerifier() { ++instance_count_; }
+ DestructorVerifier(const DestructorVerifier&) = delete;
+ DestructorVerifier& operator=(const DestructorVerifier&) = delete;
+ ~DestructorVerifier() { --instance_count_; }
+
+ // The number of instances of this class currently active.
+ static int instance_count() { return instance_count_; }
+
+ private:
+ // The number of instances of this class currently active.
+ static int instance_count_;
+};
+
+int DestructorVerifier::instance_count_ = 0;
+
+TEST(WrapUniqueTest, WrapUnique) {
+ // Test that the unique_ptr is constructed properly by verifying that the
+ // destructor for its payload gets called at the proper time.
+ {
+ auto dv = new DestructorVerifier;
+ EXPECT_EQ(1, DestructorVerifier::instance_count());
+ std::unique_ptr<DestructorVerifier> ptr = absl::WrapUnique(dv);
+ EXPECT_EQ(1, DestructorVerifier::instance_count());
+ }
+ EXPECT_EQ(0, DestructorVerifier::instance_count());
+}
+TEST(MakeUniqueTest, Basic) {
+ std::unique_ptr<std::string> p = absl::make_unique<std::string>();
+ EXPECT_EQ("", *p);
+ p = absl::make_unique<std::string>("hi");
+ EXPECT_EQ("hi", *p);
+}
+
+struct MoveOnly {
+ MoveOnly() = default;
+ explicit MoveOnly(int i1) : ip1{new int{i1}} {}
+ MoveOnly(int i1, int i2) : ip1{new int{i1}}, ip2{new int{i2}} {}
+ std::unique_ptr<int> ip1;
+ std::unique_ptr<int> ip2;
+};
+
+struct AcceptMoveOnly {
+ explicit AcceptMoveOnly(MoveOnly m) : m_(std::move(m)) {}
+ MoveOnly m_;
+};
+
+TEST(MakeUniqueTest, MoveOnlyTypeAndValue) {
+ using ExpectedType = std::unique_ptr<MoveOnly>;
+ {
+ auto p = absl::make_unique<MoveOnly>();
+ static_assert(std::is_same<decltype(p), ExpectedType>::value,
+ "unexpected return type");
+ EXPECT_TRUE(!p->ip1);
+ EXPECT_TRUE(!p->ip2);
+ }
+ {
+ auto p = absl::make_unique<MoveOnly>(1);
+ static_assert(std::is_same<decltype(p), ExpectedType>::value,
+ "unexpected return type");
+ EXPECT_TRUE(p->ip1 && *p->ip1 == 1);
+ EXPECT_TRUE(!p->ip2);
+ }
+ {
+ auto p = absl::make_unique<MoveOnly>(1, 2);
+ static_assert(std::is_same<decltype(p), ExpectedType>::value,
+ "unexpected return type");
+ EXPECT_TRUE(p->ip1 && *p->ip1 == 1);
+ EXPECT_TRUE(p->ip2 && *p->ip2 == 2);
+ }
+}
+
+TEST(MakeUniqueTest, AcceptMoveOnly) {
+ auto p = absl::make_unique<AcceptMoveOnly>(MoveOnly());
+ p = std::unique_ptr<AcceptMoveOnly>(new AcceptMoveOnly(MoveOnly()));
+}
+
+struct ArrayWatch {
+ void* operator new[](size_t n) {
+ allocs().push_back(n);
+ return ::operator new[](n);
+ }
+ void operator delete[](void* p) {
+ return ::operator delete[](p);
+ }
+ static std::vector<size_t>& allocs() {
+ static auto& v = *new std::vector<size_t>;
+ return v;
+ }
+};
+
+TEST(Make_UniqueTest, Array) {
+ // Ensure state is clean before we start so that these tests
+ // are order-agnostic.
+ ArrayWatch::allocs().clear();
+
+ auto p = absl::make_unique<ArrayWatch[]>(5);
+ static_assert(std::is_same<decltype(p),
+ std::unique_ptr<ArrayWatch[]>>::value,
+ "unexpected return type");
+ EXPECT_THAT(ArrayWatch::allocs(), ElementsAre(5 * sizeof(ArrayWatch)));
+}
+
+#if 0
+// TODO(billydonahue): Make a proper NC test.
+// These tests shouldn't compile.
+TEST(MakeUniqueTestNC, AcceptMoveOnlyLvalue) {
+ auto m = MoveOnly();
+ auto p = absl::make_unique<AcceptMoveOnly>(m);
+}
+TEST(MakeUniqueTestNC, KnownBoundArray) {
+ auto p = absl::make_unique<ArrayWatch[5]>();
+}
+#endif
+
+TEST(RawPtrTest, RawPointer) {
+ int i = 5;
+ EXPECT_EQ(&i, absl::RawPtr(&i));
+}
+
+TEST(RawPtrTest, SmartPointer) {
+ int* o = new int(5);
+ std::unique_ptr<int> p(o);
+ EXPECT_EQ(o, absl::RawPtr(p));
+}
+
+class IntPointerNonConstDeref {
+ public:
+ explicit IntPointerNonConstDeref(int* p) : p_(p) {}
+ friend bool operator!=(const IntPointerNonConstDeref& a, std::nullptr_t) {
+ return a.p_ != nullptr;
+ }
+ int& operator*() { return *p_; }
+
+ private:
+ std::unique_ptr<int> p_;
+};
+
+TEST(RawPtrTest, SmartPointerNonConstDereference) {
+ int* o = new int(5);
+ IntPointerNonConstDeref p(o);
+ EXPECT_EQ(o, absl::RawPtr(p));
+}
+
+TEST(RawPtrTest, NullValuedRawPointer) {
+ int* p = nullptr;
+ EXPECT_EQ(nullptr, absl::RawPtr(p));
+}
+
+TEST(RawPtrTest, NullValuedSmartPointer) {
+ std::unique_ptr<int> p;
+ EXPECT_EQ(nullptr, absl::RawPtr(p));
+}
+
+TEST(RawPtrTest, Nullptr) {
+ auto p = absl::RawPtr(nullptr);
+ EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
+ EXPECT_EQ(nullptr, p);
+}
+
+TEST(RawPtrTest, Null) {
+ auto p = absl::RawPtr(nullptr);
+ EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
+ EXPECT_EQ(nullptr, p);
+}
+
+TEST(RawPtrTest, Zero) {
+ auto p = absl::RawPtr(nullptr);
+ EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
+ EXPECT_EQ(nullptr, p);
+}
+
+TEST(ShareUniquePtrTest, Share) {
+ auto up = absl::make_unique<int>();
+ int* rp = up.get();
+ auto sp = absl::ShareUniquePtr(std::move(up));
+ EXPECT_EQ(sp.get(), rp);
+}
+
+TEST(ShareUniquePtrTest, ShareNull) {
+ struct NeverDie {
+ using pointer = void*;
+ void operator()(pointer) {
+ ASSERT_TRUE(false) << "Deleter should not have been called.";
+ }
+ };
+
+ std::unique_ptr<void, NeverDie> up;
+ auto sp = absl::ShareUniquePtr(std::move(up));
+}
+
+TEST(WeakenPtrTest, Weak) {
+ auto sp = std::make_shared<int>();
+ auto wp = absl::WeakenPtr(sp);
+ EXPECT_EQ(sp.get(), wp.lock().get());
+ sp.reset();
+ EXPECT_TRUE(wp.expired());
+}
+
+// Should not compile.
+/*
+TEST(RawPtrTest, NotAPointer) {
+ absl::RawPtr(1.5);
+}
+*/
+
+template <typename T>
+struct SmartPointer {
+ using difference_type = char;
+};
+
+struct PointerWith {
+ using element_type = int32_t;
+ using difference_type = int16_t;
+ template <typename U>
+ using rebind = SmartPointer<U>;
+
+ static PointerWith pointer_to(
+ element_type& r) { // NOLINT(runtime/references)
+ return PointerWith{&r};
+ }
+
+ element_type* ptr;
+};
+
+template <typename... Args>
+struct PointerWithout {};
+
+TEST(PointerTraits, Types) {
+ using TraitsWith = absl::pointer_traits<PointerWith>;
+ EXPECT_TRUE((std::is_same<TraitsWith::pointer, PointerWith>::value));
+ EXPECT_TRUE((std::is_same<TraitsWith::element_type, int32_t>::value));
+ EXPECT_TRUE((std::is_same<TraitsWith::difference_type, int16_t>::value));
+ EXPECT_TRUE((
+ std::is_same<TraitsWith::rebind<int64_t>, SmartPointer<int64_t>>::value));
+
+ using TraitsWithout = absl::pointer_traits<PointerWithout<double, int>>;
+ EXPECT_TRUE((std::is_same<TraitsWithout::pointer,
+ PointerWithout<double, int>>::value));
+ EXPECT_TRUE((std::is_same<TraitsWithout::element_type, double>::value));
+ EXPECT_TRUE(
+ (std::is_same<TraitsWithout ::difference_type, std::ptrdiff_t>::value));
+ EXPECT_TRUE((std::is_same<TraitsWithout::rebind<int64_t>,
+ PointerWithout<int64_t, int>>::value));
+
+ using TraitsRawPtr = absl::pointer_traits<char*>;
+ EXPECT_TRUE((std::is_same<TraitsRawPtr::pointer, char*>::value));
+ EXPECT_TRUE((std::is_same<TraitsRawPtr::element_type, char>::value));
+ EXPECT_TRUE(
+ (std::is_same<TraitsRawPtr::difference_type, std::ptrdiff_t>::value));
+ EXPECT_TRUE((std::is_same<TraitsRawPtr::rebind<int64_t>, int64_t*>::value));
+}
+
+TEST(PointerTraits, Functions) {
+ int i;
+ EXPECT_EQ(&i, absl::pointer_traits<PointerWith>::pointer_to(i).ptr);
+ EXPECT_EQ(&i, absl::pointer_traits<int*>::pointer_to(i));
+}
+
+TEST(AllocatorTraits, Typedefs) {
+ struct A {
+ struct value_type {};
+ };
+ EXPECT_TRUE((
+ std::is_same<A,
+ typename absl::allocator_traits<A>::allocator_type>::value));
+ EXPECT_TRUE(
+ (std::is_same<A::value_type,
+ typename absl::allocator_traits<A>::value_type>::value));
+
+ struct X {};
+ struct HasPointer {
+ using value_type = X;
+ using pointer = SmartPointer<X>;
+ };
+ EXPECT_TRUE((std::is_same<SmartPointer<X>, typename absl::allocator_traits<
+ HasPointer>::pointer>::value));
+ EXPECT_TRUE(
+ (std::is_same<A::value_type*,
+ typename absl::allocator_traits<A>::pointer>::value));
+
+ EXPECT_TRUE(
+ (std::is_same<
+ SmartPointer<const X>,
+ typename absl::allocator_traits<HasPointer>::const_pointer>::value));
+ EXPECT_TRUE(
+ (std::is_same<const A::value_type*,
+ typename absl::allocator_traits<A>::const_pointer>::value));
+
+ struct HasVoidPointer {
+ using value_type = X;
+ struct void_pointer {};
+ };
+
+ EXPECT_TRUE((std::is_same<HasVoidPointer::void_pointer,
+ typename absl::allocator_traits<
+ HasVoidPointer>::void_pointer>::value));
+ EXPECT_TRUE(
+ (std::is_same<SmartPointer<void>, typename absl::allocator_traits<
+ HasPointer>::void_pointer>::value));
+
+ struct HasConstVoidPointer {
+ using value_type = X;
+ struct const_void_pointer {};
+ };
+
+ EXPECT_TRUE(
+ (std::is_same<HasConstVoidPointer::const_void_pointer,
+ typename absl::allocator_traits<
+ HasConstVoidPointer>::const_void_pointer>::value));
+ EXPECT_TRUE((std::is_same<SmartPointer<const void>,
+ typename absl::allocator_traits<
+ HasPointer>::const_void_pointer>::value));
+
+ struct HasDifferenceType {
+ using value_type = X;
+ using difference_type = int;
+ };
+ EXPECT_TRUE(
+ (std::is_same<int, typename absl::allocator_traits<
+ HasDifferenceType>::difference_type>::value));
+ EXPECT_TRUE((std::is_same<char, typename absl::allocator_traits<
+ HasPointer>::difference_type>::value));
+
+ struct HasSizeType {
+ using value_type = X;
+ using size_type = unsigned int;
+ };
+ EXPECT_TRUE((std::is_same<unsigned int, typename absl::allocator_traits<
+ HasSizeType>::size_type>::value));
+ EXPECT_TRUE((std::is_same<unsigned char, typename absl::allocator_traits<
+ HasPointer>::size_type>::value));
+
+ struct HasPropagateOnCopy {
+ using value_type = X;
+ struct propagate_on_container_copy_assignment {};
+ };
+
+ EXPECT_TRUE(
+ (std::is_same<HasPropagateOnCopy::propagate_on_container_copy_assignment,
+ typename absl::allocator_traits<HasPropagateOnCopy>::
+ propagate_on_container_copy_assignment>::value));
+ EXPECT_TRUE(
+ (std::is_same<std::false_type,
+ typename absl::allocator_traits<
+ A>::propagate_on_container_copy_assignment>::value));
+
+ struct HasPropagateOnMove {
+ using value_type = X;
+ struct propagate_on_container_move_assignment {};
+ };
+
+ EXPECT_TRUE(
+ (std::is_same<HasPropagateOnMove::propagate_on_container_move_assignment,
+ typename absl::allocator_traits<HasPropagateOnMove>::
+ propagate_on_container_move_assignment>::value));
+ EXPECT_TRUE(
+ (std::is_same<std::false_type,
+ typename absl::allocator_traits<
+ A>::propagate_on_container_move_assignment>::value));
+
+ struct HasPropagateOnSwap {
+ using value_type = X;
+ struct propagate_on_container_swap {};
+ };
+
+ EXPECT_TRUE(
+ (std::is_same<HasPropagateOnSwap::propagate_on_container_swap,
+ typename absl::allocator_traits<HasPropagateOnSwap>::
+ propagate_on_container_swap>::value));
+ EXPECT_TRUE(
+ (std::is_same<std::false_type, typename absl::allocator_traits<A>::
+ propagate_on_container_swap>::value));
+
+ struct HasIsAlwaysEqual {
+ using value_type = X;
+ struct is_always_equal {};
+ };
+
+ EXPECT_TRUE((std::is_same<HasIsAlwaysEqual::is_always_equal,
+ typename absl::allocator_traits<
+ HasIsAlwaysEqual>::is_always_equal>::value));
+ EXPECT_TRUE((std::is_same<std::true_type, typename absl::allocator_traits<
+ A>::is_always_equal>::value));
+ struct NonEmpty {
+ using value_type = X;
+ int i;
+ };
+ EXPECT_TRUE(
+ (std::is_same<std::false_type,
+ absl::allocator_traits<NonEmpty>::is_always_equal>::value));
+}
+
+template <typename T>
+struct Rebound {};
+
+struct AllocWithRebind {
+ using value_type = int;
+ template <typename T>
+ struct rebind {
+ using other = Rebound<T>;
+ };
+};
+
+template <typename T, typename U>
+struct AllocWithoutRebind {
+ using value_type = int;
+};
+
+TEST(AllocatorTraits, Rebind) {
+ EXPECT_TRUE(
+ (std::is_same<Rebound<int>,
+ typename absl::allocator_traits<
+ AllocWithRebind>::template rebind_alloc<int>>::value));
+ EXPECT_TRUE(
+ (std::is_same<absl::allocator_traits<Rebound<int>>,
+ typename absl::allocator_traits<
+ AllocWithRebind>::template rebind_traits<int>>::value));
+
+ EXPECT_TRUE(
+ (std::is_same<AllocWithoutRebind<double, char>,
+ typename absl::allocator_traits<AllocWithoutRebind<
+ int, char>>::template rebind_alloc<double>>::value));
+ EXPECT_TRUE(
+ (std::is_same<absl::allocator_traits<AllocWithoutRebind<double, char>>,
+ typename absl::allocator_traits<AllocWithoutRebind<
+ int, char>>::template rebind_traits<double>>::value));
+}
+
+struct TestValue {
+ TestValue() {}
+ explicit TestValue(int* trace) : trace(trace) { ++*trace; }
+ ~TestValue() {
+ if (trace) --*trace;
+ }
+ int* trace = nullptr;
+};
+
+struct MinimalMockAllocator {
+ MinimalMockAllocator() : value(0) {}
+ explicit MinimalMockAllocator(int value) : value(value) {}
+ MinimalMockAllocator(const MinimalMockAllocator& other)
+ : value(other.value) {}
+ using value_type = TestValue;
+ MOCK_METHOD1(allocate, value_type*(size_t));
+ MOCK_METHOD2(deallocate, void(value_type*, size_t));
+
+ int value;
+};
+
+TEST(AllocatorTraits, FunctionsMinimal) {
+ int trace = 0;
+ int hint;
+ TestValue x(&trace);
+ MinimalMockAllocator mock;
+ using Traits = absl::allocator_traits<MinimalMockAllocator>;
+ EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(&x));
+ EXPECT_CALL(mock, deallocate(&x, 7));
+
+ EXPECT_EQ(&x, Traits::allocate(mock, 7));
+ Traits::allocate(mock, 7, static_cast<const void*>(&hint));
+ EXPECT_EQ(&x, Traits::allocate(mock, 7, static_cast<const void*>(&hint)));
+ Traits::deallocate(mock, &x, 7);
+
+ EXPECT_EQ(1, trace);
+ Traits::construct(mock, &x, &trace);
+ EXPECT_EQ(2, trace);
+ Traits::destroy(mock, &x);
+ EXPECT_EQ(1, trace);
+
+ EXPECT_EQ(std::numeric_limits<size_t>::max() / sizeof(TestValue),
+ Traits::max_size(mock));
+
+ EXPECT_EQ(0, mock.value);
+ EXPECT_EQ(0, Traits::select_on_container_copy_construction(mock).value);
+}
+
+struct FullMockAllocator {
+ FullMockAllocator() : value(0) {}
+ explicit FullMockAllocator(int value) : value(value) {}
+ FullMockAllocator(const FullMockAllocator& other) : value(other.value) {}
+ using value_type = TestValue;
+ MOCK_METHOD1(allocate, value_type*(size_t));
+ MOCK_METHOD2(allocate, value_type*(size_t, const void*));
+ MOCK_METHOD2(construct, void(value_type*, int*));
+ MOCK_METHOD1(destroy, void(value_type*));
+ MOCK_CONST_METHOD0(max_size, size_t());
+ MOCK_CONST_METHOD0(select_on_container_copy_construction,
+ FullMockAllocator());
+
+ int value;
+};
+
+TEST(AllocatorTraits, FunctionsFull) {
+ int trace = 0;
+ int hint;
+ TestValue x(&trace), y;
+ FullMockAllocator mock;
+ using Traits = absl::allocator_traits<FullMockAllocator>;
+ EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(&x));
+ EXPECT_CALL(mock, allocate(13, &hint)).WillRepeatedly(Return(&y));
+ EXPECT_CALL(mock, construct(&x, &trace));
+ EXPECT_CALL(mock, destroy(&x));
+ EXPECT_CALL(mock, max_size()).WillRepeatedly(Return(17));
+ EXPECT_CALL(mock, select_on_container_copy_construction())
+ .WillRepeatedly(Return(FullMockAllocator(23)));
+
+ EXPECT_EQ(&x, Traits::allocate(mock, 7));
+ EXPECT_EQ(&y, Traits::allocate(mock, 13, static_cast<const void*>(&hint)));
+
+ EXPECT_EQ(1, trace);
+ Traits::construct(mock, &x, &trace);
+ EXPECT_EQ(1, trace);
+ Traits::destroy(mock, &x);
+ EXPECT_EQ(1, trace);
+
+ EXPECT_EQ(17, Traits::max_size(mock));
+
+ EXPECT_EQ(0, mock.value);
+ EXPECT_EQ(23, Traits::select_on_container_copy_construction(mock).value);
+}
+
+TEST(AllocatorNoThrowTest, DefaultAllocator) {
+#if ABSL_ALLOCATOR_NOTHROW
+ EXPECT_TRUE(absl::default_allocator_is_nothrow::value);
+#else
+ EXPECT_FALSE(absl::default_allocator_is_nothrow::value);
+#endif
+}
+
+TEST(AllocatorNoThrowTest, StdAllocator) {
+#if ABSL_ALLOCATOR_NOTHROW
+ EXPECT_TRUE(absl::allocator_is_nothrow<std::allocator<int>>::value);
+#else
+ EXPECT_FALSE(absl::allocator_is_nothrow<std::allocator<int>>::value);
+#endif
+}
+
+TEST(AllocatorNoThrowTest, CustomAllocator) {
+ struct NoThrowAllocator {
+ using is_nothrow = std::true_type;
+ };
+ struct CanThrowAllocator {
+ using is_nothrow = std::false_type;
+ };
+ struct UnspecifiedAllocator {
+ };
+ EXPECT_TRUE(absl::allocator_is_nothrow<NoThrowAllocator>::value);
+ EXPECT_FALSE(absl::allocator_is_nothrow<CanThrowAllocator>::value);
+ EXPECT_FALSE(absl::allocator_is_nothrow<UnspecifiedAllocator>::value);
+}
+
+} // namespace