EricWF updated this revision to Diff 30304.
EricWF added a comment.

I changed the lifetime of the global resources. The global resources are no 
longer destroyed during program termination. This should prevent issues where 
other static destructors require memory resources.


http://reviews.llvm.org/D11397

Files:
  include/experimental/__config
  include/experimental/__memory
  include/experimental/memory_resource
  src/memory_resource.cpp
  src/support/atomic_support.h
  test/libcxx/experimental/memory/memory.resource.synop/version.pass.cpp
  
test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap_comp.pass.cpp
  test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp
  
test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp
  
test/std/experimental/memory/memory.resource.global/null_memory_resource.pass.cpp
  test/std/experimental/memory/memory.resource.synop/nothing_to_do.pass.cpp
  test/std/experimental/memory/memory.resource/construct.fail.cpp
  
test/std/experimental/memory/memory.resource/memory.resource.eq/equality.pass.cpp
  
test/std/experimental/memory/memory.resource/memory.resource.overview/nothing_to_do.pass.cpp
  
test/std/experimental/memory/memory.resource/memory.resource.priv/tested_elsewhere.pass.cpp
  
test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp
  
test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp
  
test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp
  
test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp
  test/support/test_memory_resource.hpp

Index: test/support/test_memory_resource.hpp
===================================================================
--- /dev/null
+++ test/support/test_memory_resource.hpp
@@ -0,0 +1,296 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SUPPORT_TEST_MEMORY_RESOURCE_HPP
+#define SUPPORT_TEST_MEMORY_RESOURCE_HPP
+
+#include <experimental/memory_resource>
+#include <memory>
+#include <type_traits>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+
+#define DISALLOW_COPY(Type) \
+  Type(Type const&) = delete; \
+  Type& operator=(Type const&) = delete
+
+constexpr size_t MaxAlignV = std::alignment_of<std::max_align_t>::value;
+
+struct ResourceCounter {
+    int alive = 0;
+    int alloc_count = 0;
+    int dealloc_count = 0;
+    int is_equal_count = 0;
+
+    std::size_t alive_size;
+    std::size_t allocated_size;
+    std::size_t deallocated_size;
+
+    std::size_t last_size = 0;
+    std::size_t last_align = 0;
+    void * last_pointer = 0;
+
+    std::size_t last_alloc_size = 0;
+    std::size_t last_alloc_align = 0;
+    void * last_alloc_pointer = nullptr;
+
+    std::size_t last_dealloc_size = 0;
+    std::size_t last_dealloc_align = 0;
+    void * last_dealloc_pointer = nullptr;
+
+    ResourceCounter() {}
+
+    void countAlloc(void* p, size_t s, size_t a) {
+        ++alive;
+        ++alloc_count;
+        alive_size += s;
+        allocated_size += s;
+        last_pointer = last_alloc_pointer = p;
+        last_size = last_alloc_size = s;
+        last_align = last_alloc_align = a;
+    }
+
+    bool checkAlloc(void* p, size_t s, size_t a = MaxAlignV) const {
+        return p == last_alloc_pointer &&
+               s == last_alloc_size &&
+               a == last_alloc_align;
+    }
+
+    void countDealloc(void* p, size_t s, size_t a) {
+        --alive;
+        ++dealloc_count;
+        alive_size -= s;
+        deallocated_size += s;
+        last_pointer = last_dealloc_pointer = p;
+        last_size = last_dealloc_size = s;
+        last_align = last_dealloc_align = a;
+    }
+
+    bool checkDealloc(void* p, size_t s, size_t a = MaxAlignV) const {
+        return p == last_dealloc_pointer &&
+               s == last_dealloc_size &&
+               a == last_dealloc_align;
+    }
+
+    void countIsEqual() {
+        ++is_equal_count;
+    }
+
+    bool checkIsEqualCalledEq(int n) const {
+        return is_equal_count == n;
+    }
+
+    void reset() {
+        std::memset(this, 0, sizeof(*this));
+    }
+
+private:
+    DISALLOW_COPY(ResourceCounter);
+};
+
+struct NullProvider : ResourceCounter {
+
+    NullProvider() {}
+
+    void* allocate(size_t s, size_t a) {
+        countAlloc(nullptr, s, a);
+        return nullptr;
+    }
+
+    void deallocate(void* p, size_t s, size_t a) {
+        countDealloc(p, s, a);
+    }
+
+    void reset() {
+        ResourceCounter::reset();
+    }
+
+private:
+    DISALLOW_COPY(NullProvider);
+};
+
+struct MallocProvider : ResourceCounter {
+
+    MallocProvider() {}
+
+    void* allocate(size_t s, size_t a) {
+        void* p =  std::malloc(s);
+        countAlloc(p, s, a);
+        return p;
+    }
+
+    void deallocate(void* p, size_t s, size_t a) {
+        countDealloc(p, s, a);
+        std::free(p);
+    }
+
+    void reset() {
+        ResourceCounter::reset();
+    }
+private:
+    DISALLOW_COPY(MallocProvider);
+};
+
+struct NewDeleteProvider : ResourceCounter {
+    NewDeleteProvider() {}
+
+    void* allocate(size_t s, size_t a) {
+        void* p =  ::operator new(s);
+        countAlloc(p, s, a);
+        return p;
+    }
+
+    void deallocate(void* p, size_t s, size_t a) {
+        countDealloc(p, s, a);
+        ::operator delete(p);
+    }
+
+    void reset() {
+        ResourceCounter::reset();
+    }
+private:
+    DISALLOW_COPY(NewDeleteProvider);
+};
+
+template <size_t Size = 4096 * 10> // 10 pages worth of memory.
+struct BufferProvider : ResourceCounter {
+    char buffer[Size];
+    void* next = &buffer;
+    size_t space = Size;
+
+    BufferProvider() {}
+
+    void* allocate(size_t s, size_t a) {
+        void* ret = std::align(s, a, next, space);
+        countAlloc(ret, s, a);
+        if (ret == nullptr) throw std::bad_alloc();
+        return ret;
+    }
+
+    void deallocate(void* p, size_t s, size_t a) {
+        countDealloc(p, s, a);
+    }
+
+    void reset() {
+        next = &buffer;
+        space = Size;
+        ResourceCounter::reset();
+    }
+private:
+    DISALLOW_COPY(BufferProvider);
+};
+
+struct TestException {};
+
+struct AllocThrowsProvider : ResourceCounter {
+
+    AllocThrowsProvider() {}
+
+    void* allocate(size_t s, size_t a) {
+        throw TestException();
+    }
+
+    void deallocate(void* p, size_t s, size_t a) {
+        countDealloc(p, s, a);
+    }
+
+    void reset() {
+        ResourceCounter::reset();
+    }
+
+private:
+    DISALLOW_COPY(AllocThrowsProvider);
+};
+
+template <class ProviderT, int = 0>
+class TestResourceImp : public std::experimental::pmr::memory_resource
+{
+public:
+    static int resource_alive;
+    static int resource_constructed;
+    static int resource_destructed;
+
+    static void resetStatics() {
+        assert(resource_alive == 0);
+        resource_alive = 0;
+        resource_constructed = 0;
+        resource_destructed = 0;
+    }
+
+    using memory_resource = std::experimental::pmr::memory_resource;
+    using Provider = ProviderT;
+
+    int value;
+
+    explicit TestResourceImp(int val = 0) : value(val) {
+        ++resource_alive;
+        ++resource_constructed;
+    }
+
+    ~TestResourceImp() noexcept {
+        --resource_alive;
+        ++resource_destructed;
+    }
+
+    void reset() { P.reset(); }
+    Provider& getProvider() { return P; }
+
+protected:
+    virtual void * do_allocate(std::size_t s, std::size_t a) {
+        return P.allocate(s, a);
+    }
+
+    virtual void do_deallocate(void * p, std::size_t s, std::size_t a) {
+        P.deallocate(p, s, a);
+    }
+
+    virtual bool do_is_equal(memory_resource const & other) const noexcept {
+        P.countIsEqual();
+        TestResourceImp const * o = dynamic_cast<TestResourceImp const *>(&other);
+        return o && o->value == value;
+    }
+private:
+    mutable Provider P;
+    DISALLOW_COPY(TestResourceImp);
+};
+
+template <class Provider, int N>
+int TestResourceImp<Provider, N>::resource_alive = 0;
+
+template <class Provider, int N>
+int TestResourceImp<Provider, N>::resource_constructed = 0;
+
+template <class Provider, int N>
+int TestResourceImp<Provider, N>::resource_destructed = 0;
+
+using NullResource  = TestResourceImp<NullProvider, 0>;
+using NullResource1 = TestResourceImp<NullProvider, 1>;
+using NullResource2 = TestResourceImp<NullProvider, 2>;
+
+using MallocResource  = TestResourceImp<MallocProvider, 0>;
+using MallocResource1 = TestResourceImp<MallocProvider, 1>;
+using MallocResource2 = TestResourceImp<MallocProvider, 2>;
+
+using NewDeleteResource  = TestResourceImp<NewDeleteProvider, 0>;
+using NewDeleteResource1 = TestResourceImp<NewDeleteProvider, 1>;
+using NewDeleteResource2 = TestResourceImp<NewDeleteProvider, 2>;
+
+using BufferResource  = TestResourceImp<BufferProvider<>, 0>;
+using BufferResource1 = TestResourceImp<BufferProvider<>, 1>;
+using BufferResource2 = TestResourceImp<BufferProvider<>, 2>;
+
+using TestResource = BufferResource;
+using TestResource1 = BufferResource1;
+using TestResource2 = BufferResource2;
+
+using AllocThrowsResource = TestResourceImp<AllocThrowsProvider, 0>;
+
+
+#endif /* SUPPORT_TEST_MEMORY_RESOURCE_HPP */
Index: test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp
@@ -0,0 +1,119 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//------------------------------------------------------------------------------
+// TESTING virtual bool is_equal(memory_resource const &) const noexcept
+//
+// Concerns:
+//   A) 'memory_resource' provides a function 'is_equal' with the required
+//      signature.
+//   B) 'is_equal' is noexcept.
+//   C) 'do_is_equal' is called using the same arguments passed to 'is_equal'
+//      and the resulting value is returned.
+//   D) 'do_is_equal' is called on the LHS object and not the RHS object.
+//
+// Plan:
+//  1) Check A and B by calling 'is_equal' within a noexcept expression and
+//     asserting that the expression is noexcept.
+//
+//  2) For two different types 'T1' and 'T2' that derive from 'memory_resource'
+//     create objects of those types 't1' and 't2'. Create 'memory_resource'
+//     pointers, 'p1' and 'p2' from 't1' and 't2'.
+//
+//     2a) Check that 'p1.is_equal(p2)' returns false and calls only 'p1.do_is_equal(p2)'.
+//         Check that 'p2.is_equal(p1)' returns false and calls only 'p2.do_is_equal(p1)'.
+//
+//  3) For a type 'T' that derives from 'memory_resource' create objects 't1'
+//     and 't2' with different values so that they will not compare equal.
+//     Create 'memory_resource' pointers 'p1' and 'p2' from 't1' and 't2'.
+//
+//     3a) Check that 'p1.is_equal(p2)' returns false and calls only 'p1.do_is_equal(p2)'.
+//         Check that 'p2.is_equal(p1)' returns false and calls only 'p2.do_is_equal(p1)'.
+//
+//  4) For a type 'T' that derives from 'memory_resource' create objects 't1'
+//     and 't2' with the same values so that they will compare equal.
+//     Create 'memory_resource' pointers 'p1' and 'p2' from 't1' and 't2'.
+//
+//     4a) Check that 'p1.is_equal(p2)' returns true and calls only 'p1.do_is_equal(p2)'.
+//         Check that 'p2.is_equal(p1)' returns true and calls only 'p2.do_is_equal(p1)'.
+
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+#include "test_memory_resource.hpp"
+
+using std::experimental::pmr::memory_resource;
+
+int main()
+{
+    {
+        memory_resource const* r1 = nullptr;
+        memory_resource const* r2 = nullptr;
+        static_assert(
+            noexcept(r1->is_equal(*r2))
+          , "is_equal must be noexcept"
+          );
+    }
+    {
+        TestResource1 R1(1);
+        auto& P1 = R1.getProvider();
+        memory_resource const& M1 = R1;
+
+        TestResource2 R2(1);
+        auto& P2 = R2.getProvider();
+        memory_resource const& M2 = R2;
+
+        assert(M1.is_equal(M2) == false);
+        assert(P1.checkIsEqualCalledEq(1));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert(M2.is_equal(M1) == false);
+        assert(P2.checkIsEqualCalledEq(1));
+        assert(P1.checkIsEqualCalledEq(1));
+    }
+    {
+        TestResource1 R1(1);
+        auto& P1 = R1.getProvider();
+        memory_resource const& M1 = R1;
+
+        TestResource1 R2(2);
+        auto& P2 = R2.getProvider();
+        memory_resource const& M2 = R2;
+
+        assert(M1.is_equal(M2) == false);
+        assert(P1.checkIsEqualCalledEq(1));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert(M2.is_equal(M1) == false);
+        assert(P2.checkIsEqualCalledEq(1));
+        assert(P1.checkIsEqualCalledEq(1));
+    }
+    {
+        TestResource1 R1(1);
+        auto& P1 = R1.getProvider();
+        memory_resource const& M1 = R1;
+
+        TestResource1 R2(1);
+        auto& P2 = R2.getProvider();
+        memory_resource const& M2 = R2;
+
+        assert(M1.is_equal(M2) == true);
+        assert(P1.checkIsEqualCalledEq(1));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert(M2.is_equal(M1) == true);
+        assert(P2.checkIsEqualCalledEq(1));
+        assert(P1.checkIsEqualCalledEq(1));
+    }
+}
Index: test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//------------------------------------------------------------------------------
+// TESTING virtual ~memory_resource()
+//
+// Concerns:
+//  A) 'memory_resource' is destructible.
+//  B) The destructor is implicitly marked noexcept.
+//  C) The destructor is marked virtual.
+//
+// Plan:
+//  1) Use type traits to check concerns A, B and C.
+//
+//  2) To check concerns A and C at runtime dynamically create an object of
+//     a type that is derived from 'memory_resource'. Then delete that object
+//     using a pointer to 'memory_resource' and ensure that the derived classes
+//     destructor was invoked.
+
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+using std::experimental::pmr::memory_resource;
+
+int main()
+{
+    static_assert(
+        std::has_virtual_destructor<memory_resource>::value
+      , "Must have virtual destructor"
+      );
+    static_assert(
+        std::is_nothrow_destructible<memory_resource>::value,
+        "Must be nothrow destructible"
+      );
+    static_assert(
+        std::is_abstract<memory_resource>::value
+      , "Must be abstract"
+      );
+    // Check that the destructor of `TestResource` is called when
+    // it is deleted as a pointer to `memory_resource`
+    {
+        using RT = TestResource;
+        memory_resource* M = new RT(42);
+        assert(RT::resource_alive == 1);
+        assert(RT::resource_constructed == 1);
+        assert(RT::resource_destructed == 0);
+
+        delete M;
+
+        assert(RT::resource_alive == 0);
+        assert(RT::resource_constructed == 1);
+        assert(RT::resource_destructed == 1);
+    }
+}
Index: test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//------------------------------------------------------------------------------
+// TESTING void * memory_resource::deallocate(void *, size_t, size_t = max_align)
+//
+// Concerns:
+//  A) 'memory_resource' contains a member 'deallocate' with the required
+//     signature, including the default alignment parameter.
+//  B) The return type of 'deallocate' is 'void'.
+//  C) 'deallocate' is not marked as 'noexcept'.
+//  D) Invoking 'deallocate' invokes 'do_deallocate' with the same arguments.
+//
+// Plan:
+//  1) Check concerns A and B by calling 'deallocate' within a decltype expression
+//     and check that the return type is 'void'.
+//
+//  2) Check concerns A and C by calling 'deallocate' within a noexcept expression
+//     and check that the expression is not noexcept.
+//
+//  3) Check concern A and C by creating a pointer, 'res', of type
+//     'memory_resource' which points to an instance of 'TestResource'.
+//
+//     3a) Call 'res->deallocate(p, s, a)' for some 'p', 's' and 'a'. Check that
+//         'NullResource::do_deallocate' was called with the same arguments.
+//
+//     3b) Call 'res->deallocate(p, s)' for some 'p' and 's'. Check that
+//         'NullResource::do_deallocate' was called with the same arguments
+//         and an alignment of 'MaxAlignV'
+
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+using std::experimental::pmr::memory_resource;
+
+int main()
+{
+    NullResource R(42);
+    auto& P = R.getProvider();
+    memory_resource& M = R;
+    {
+        static_assert(
+            std::is_same<decltype(M.deallocate(nullptr, 0, 0)), void>::value
+          , "Must be void"
+          );
+        static_assert(
+            std::is_same<decltype(M.deallocate(nullptr, 0)), void>::value
+          , "Must be void"
+          );
+    }
+    {
+        static_assert(
+            ! noexcept(M.deallocate(nullptr, 0, 0))
+          , "Must not be noexcept."
+          );
+        static_assert(
+            ! noexcept(M.deallocate(nullptr, 0))
+          , "Must not be noexcept."
+          );
+    }
+    {
+        int s = 100;
+        int a = 64;
+        void* p = reinterpret_cast<void*>(640);
+        M.deallocate(p, s, a);
+        assert(P.dealloc_count == 1);
+        assert(P.checkDealloc(p, s, a));
+
+        s = 128;
+        a = MaxAlignV;
+        p = reinterpret_cast<void*>(12800);
+        M.deallocate(p, s);
+        assert(P.dealloc_count == 2);
+        assert(P.checkDealloc(p, s, a));
+    }
+}
Index: test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//------------------------------------------------------------------------------
+// TESTING void * memory_resource::allocate(size_t, size_t = max_align)
+//
+// Concerns:
+//  A) 'memory_resource' contains a member 'allocate' with the required
+//     signature, including the default alignment parameter.
+//  B) The return type of 'allocate' is 'void*'.
+//  C) 'allocate' is not marked as 'noexcept'.
+//  D) Invoking 'allocate' invokes 'do_allocate' with the same arguments.
+//  E) If 'do_allocate' throws then 'allocate' propagates that exception.
+//
+// Plan:
+//  1) Check concerns A and B by calling 'allocate' within a decltype expression
+//     and check that the return type is 'void*'.
+//
+//  2) Check concerns A and C by calling 'allocate' within a noexcept expression
+//     and check that the expression is not noexcept.
+//
+//  3) Check concern A and C by creating a pointer, 'res', of type
+//     'memory_resource' which points to an instance of 'TestResource'.
+//
+//     3a) Allocate memory of size 's' and alignment 'a' using 'res.allocate(s, a)'
+//         and store it into a pointer 'p'. Check that 'TestResource::do_allocate'
+//         was called with 's' and 'a' and that it returned 'p'.
+//
+//     3c) Allocate memory of size 's' using 'res->allocate(s)' without
+//         specifying alignment and store it into pointer 'p'. Check that
+//         'TestResource::do_allocate' was called with 's' and
+//         the max alignment and returned 'p'.
+//
+//  4) Check concern E by creating a 'memory_resource' pointer 'p1' which points
+//     to an object of type 'AllocThrowsResource'. Call 'p1->allocate(...)' and
+//     check that the expected exception is thrown through 'allocate'.
+
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+using std::experimental::pmr::memory_resource;
+
+int main()
+{
+    TestResource R(42);
+    auto& P = R.getProvider();
+    memory_resource& M = R;
+    {
+        static_assert(
+            std::is_same<decltype(M.allocate(0, 0)), void*>::value
+          , "Must be void*"
+          );
+        static_assert(
+            std::is_same<decltype(M.allocate(0)), void*>::value
+          , "Must be void*"
+          );
+    }
+    {
+        static_assert(
+            ! noexcept(M.allocate(0, 0))
+          , "Must not be noexcept."
+          );
+        static_assert(
+            ! noexcept(M.allocate(0))
+          , "Must not be noexcept."
+          );
+    }
+    {
+        int s = 42;
+        int a = 64;
+        void* p = M.allocate(s, a);
+        assert(P.alloc_count == 1);
+        assert(P.checkAlloc(p, s, a));
+
+        s = 128;
+        a = MaxAlignV;
+        p = M.allocate(s);
+        assert(P.alloc_count == 2);
+        assert(P.checkAlloc(p, s, a));
+    }
+    {
+        AllocThrowsResource R2;
+        memory_resource& M2 = R2;
+        try {
+            M2.allocate(42);
+            assert(false);
+        } catch (TestException const&) {
+            // do nothing.
+        } catch (...) {
+            assert(false);
+        }
+    }
+}
Index: test/std/experimental/memory/memory.resource/memory.resource.priv/tested_elsewhere.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource/memory.resource.priv/tested_elsewhere.pass.cpp
@@ -0,0 +1,10 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int main () {}
Index: test/std/experimental/memory/memory.resource/memory.resource.overview/nothing_to_do.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource/memory.resource.overview/nothing_to_do.pass.cpp
@@ -0,0 +1,10 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int main () {}
Index: test/std/experimental/memory/memory.resource/memory.resource.eq/equality.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource/memory.resource.eq/equality.pass.cpp
@@ -0,0 +1,126 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//------------------------------------------------------------------------------
+// TESTING bool operator==(memory_resource const&, memory_resource const&) noexcept;
+//         bool operator!=(memory_resource const&, memory_resource const&) noexcept;
+//
+// Concerns:
+//   A) The equality operators are properly marked noexcept.
+//   B) The equality operators do not call `is_equal` if '&LHS == &RHS'.
+//   C) The equality operators call 'LHS.is_equal(RHS)' if '&LHS != &RHS'.
+//
+// Plan:
+//  1) Check concern A by calling the equality operators within a noexcept
+//     expression. Assert that the operators are marked noexcept.
+//
+//  2) Check concern B by calling the equality operators with the same object
+//     on both sides. Assert that the objects are "equal" and that 'is_equal'
+//     is never called.
+//
+//  3) Check concern C by calling the equality operators with different and
+//     UNEQUAL objects on either side. Assert that 'is_equal' is called on the
+//     LHS object and not the RHS object. Assert that the objects don't compare equal.
+//
+//  4) Check concern C by calling the equality operators with different and
+//     EQUAL objects on either side. Assert that 'is_equal' is called on the
+//     LHS object and not the RHS object. Assert that the objects compare equal.
+
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+using std::experimental::pmr::memory_resource;
+
+int main()
+{
+    // Plan Part 1
+    {
+        memory_resource const* r1 = nullptr;
+        memory_resource const* r2 = nullptr;
+        static_assert(
+            noexcept(*r1 == *r2)
+          , "operator==(...) must be noexcept"
+          );
+        static_assert(
+            noexcept(*r1 != *r2)
+          , "operator!=(...) must be noexcept"
+          );
+    }
+    // Plan Part 2
+    {
+        TestResource1 R1(1);
+        auto& P1 = R1.getProvider();
+        memory_resource const& M1 = R1;
+        memory_resource const& M2 = R1;
+
+        assert(M1 == M2);
+        assert((M1 != M2) == false);
+        assert(P1.checkIsEqualCalledEq(0));
+    }
+    // Plan Part 3
+    {
+        TestResource1 R1(1);
+        auto& P1 = R1.getProvider();
+        memory_resource const& M1 = R1;
+
+        TestResource1 R2(2);
+        auto& P2 = R2.getProvider();
+        memory_resource const& M2 = R2;
+
+        assert((M1 == M2) == false);
+        assert(P1.checkIsEqualCalledEq(1));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert(M1 != M2);
+        assert(P1.checkIsEqualCalledEq(2));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert((M2 == M1) == false);
+        assert(P1.checkIsEqualCalledEq(2));
+        assert(P2.checkIsEqualCalledEq(1));
+
+        assert(M2 != M1);
+        assert(P1.checkIsEqualCalledEq(2));
+        assert(P2.checkIsEqualCalledEq(2));
+    }
+    // Plan Part 4
+    {
+        TestResource1 R1(1);
+        auto& P1 = R1.getProvider();
+        memory_resource const& M1 = R1;
+
+        TestResource1 R2(1);
+        auto& P2 = R2.getProvider();
+        memory_resource const& M2 = R2;
+
+        assert(M1 == M2);
+        assert(P1.checkIsEqualCalledEq(1));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert((M1 != M2) == false);
+        assert(P1.checkIsEqualCalledEq(2));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert(M2 == M1);
+        assert(P1.checkIsEqualCalledEq(2));
+        assert(P2.checkIsEqualCalledEq(1));
+
+        assert((M2 != M1) == false);
+        assert(P1.checkIsEqualCalledEq(2));
+        assert(P2.checkIsEqualCalledEq(2));
+    }
+}
Index: test/std/experimental/memory/memory.resource/construct.fail.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource/construct.fail.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// Check that memory_resource is not constructible because it is a abstract
+// class.
+
+#include <experimental/memory_resource>
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    ex::memory_resource m; // expected-error {{variable type 'ex::memory_resource' is an abstract class}}
+    // expected-note@experimental/memory_resource:* {{unimplemented pure virtual method 'do_allocate' in 'memory_resource'}}
+    // expected-note@experimental/memory_resource:* {{unimplemented pure virtual method 'do_deallocate' in 'memory_resource'}}
+    // expected-note@experimental/memory_resource:* {{unimplemented pure virtual method 'do_is_equal' in 'memory_resource'}}
+}
Index: test/std/experimental/memory/memory.resource.synop/nothing_to_do.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.synop/nothing_to_do.pass.cpp
@@ -0,0 +1,13 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int main()
+{
+}
Index: test/std/experimental/memory/memory.resource.global/null_memory_resource.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.global/null_memory_resource.pass.cpp
@@ -0,0 +1,114 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//-----------------------------------------------------------------------------
+// TESTING memory_resource * null_memory_resource() noexcept
+//
+// Concerns:
+//  A) 'null_memory_resource()' returns a non-null pointer to a 'memory_resource' 'M'.
+//  B) 'null_memory_resource()' always returns the same pointer.
+//  C) 'M.allocate(...)' always throws bad_alloc.
+//  D) 'M.deallocate(...)' does nothing.
+//  E) 'M' only compares equal to itself. 'M.is_equal(Other)' will not invoke
+//     'Other.is_equal(M)'.
+//  F) 'null_memory_resource()' is marked noexcept.
+//
+// Plan:
+//   1) Check concerns A, B and E by getting two pointers 'p1' and 'p2' from
+//      calling 'null_memory_resource()' twice. Check that these pointers
+//      have the same address and are not null.
+//
+//  2) Check concern C by calling 'M.alloc(...)' for a couple of different
+//     sizes and alignments. Check that 'bad_alloc' is always thrown.
+//
+//  3) Check concern D by calling 'M.deallocate(...)' for various pointers,
+//     sizes and alignment. Make sure nothing happens (???)
+//
+//  4) Check concern E by comparing 'M' to other 'memory_resource' objects
+//     with different base classes. Check that 'M.is_equal(Other)' is always
+//     false and it does not invoke 'Other.is_equal(M)'.
+//
+//  5) Check concern F by calling 'null_memory_resource()' inside a noexcept
+//     expression and check that the expression returns true.
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+using namespace std::experimental::pmr;
+
+void checkThrows(memory_resource& M, size_t size, size_t align) {
+    try {
+        M.allocate(size, align);
+        assert(false);
+    } catch (std::bad_alloc const&) {
+        // do nothing
+    } catch (...) {
+        assert(false);
+    }
+    try {
+        M.allocate(size);
+        assert(false);
+    } catch (std::bad_alloc const&) {
+        // do nothing
+    } catch (...) {
+        assert(false);
+    }
+}
+
+int main()
+{
+    { // Plan Part 1
+        memory_resource* p1 = null_memory_resource();
+        assert(p1 != nullptr);
+        assert(p1->is_equal(*p1));
+
+        memory_resource* p2 = null_memory_resource();
+        assert(p2 != nullptr);
+        assert(p1 == p2);
+        assert(p1->is_equal(*p2));
+        assert(p2->is_equal(*p1));
+    }
+    { // Plan part 2
+        memory_resource& M = *null_memory_resource();
+        checkThrows(M, 100, 16);
+        checkThrows(M, 0, 0);
+        checkThrows(M, (size_t)-1, (size_t)-1);
+    }
+    { // Plan part 3
+        memory_resource& M = *null_memory_resource();
+        // Test zero values.
+        M.deallocate(nullptr, 0, 0);
+        M.deallocate(reinterpret_cast<void*>(42), 0, 0);
+        M.deallocate(nullptr, 100, 16);
+        M.deallocate(reinterpret_cast<void*>(42), 100, 16);
+        M.deallocate(nullptr, (size_t)-1, (size_t)-1);
+        M.deallocate(reinterpret_cast<void*>(42), (size_t)-1, (size_t)-1);
+    }
+    { // Plan part 4
+        memory_resource const& M = *null_memory_resource();
+        TestResource R;
+        auto& P = R.getProvider();
+        memory_resource const& O = R;
+
+        assert(M.is_equal(O) == false);
+        assert(P.checkIsEqualCalledEq(0));
+    }
+    { // Plan part 5
+        static_assert(
+            noexcept(null_memory_resource())
+          , "null_memory_resource() must be noexcept"
+          );
+    }
+}
Index: test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//-----------------------------------------------------------------------------
+// TESTING memory_resource * new_delete_resource() noexcept
+//
+// Concerns:
+//  A) 'new_delete_memory_resource()' returns a non-null pointer to a 'memory_resource' 'M'.
+//  B) 'new_delete_memory_resource()' always returns the same pointer.
+//  C) 'M.allocate(s, a)' calls '::operator new(s)' and returns that pointer.
+//  D) 'M.deallocate(p, s, a)' calls '::operator delete(p)'.
+//  E) 'M' only compares equal to itself. 'M.is_equal(Other)' will not invoke
+//     'Other.is_equal(M)'.
+//  F) 'new_delete_resource()' is marked as 'noexcept'.
+//
+// Plan:
+//   1) Check concerns A, B and E by getting two pointers 'p1' and 'p2' from
+//      calling 'new_deletee_memory_resource()' twice. Check that these pointers
+//      have the same address and are not null.
+//
+//  2) Check concerns C and D by performing an allocation and deallocation with
+//     'M'. Use 'globalMemCounter' to check that 'new' and 'delete' were invoked
+//     by those operations with the correct arguments.
+//
+//  3) Check concern E by comparing 'M' to other 'memory_resource' objects
+//     with different base classes. Check that 'M.is_equal(Other)' is always
+//     false and it does not invoke 'Other.is_equal(M)'.
+//
+//  4) Check concern F by calling 'new_delete_resource()' in a noexcept expression
+//     and check that the expression returns true.
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+#include "count_new.hpp"
+
+using namespace std::experimental::pmr;
+
+int main()
+{
+    { // Plan Part 1
+        memory_resource* p1 = new_delete_resource();
+        assert(p1 != nullptr);
+        assert(p1->is_equal(*p1));
+
+        memory_resource* p2 = new_delete_resource();
+        assert(p2 != nullptr);
+        assert(p1 == p2);
+        assert(p1->is_equal(*p2));
+        assert(p2->is_equal(*p1));
+    }
+    { // Plan part 2
+        MemCounter& G = globalMemCounter;
+        memory_resource& M = *new_delete_resource();
+        void* p = M.allocate(1024);
+        assert(p != nullptr);
+        assert(G.checkOutstandingNewEq(1));
+        assert(G.checkLastNewSizeEq(1024));
+
+        M.deallocate(p, 1024);
+        assert(G.checkOutstandingNewEq(0));
+        assert(G.checkDeleteCalledEq(1));
+    }
+    { // Plan part 3
+        memory_resource const& M = *new_delete_resource();
+        TestResource R;
+        auto& P = R.getProvider();
+        memory_resource const& O = R;
+
+        assert(M.is_equal(O) == false);
+        assert(P.checkIsEqualCalledEq(0));
+    }
+    { // Plan Part 4
+        static_assert(
+            noexcept(new_delete_resource())
+          , "new_delete_resource() must be noexcept"
+          );
+    }
+}
Index: test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//-----------------------------------------------------------------------------
+// TESTING memory_resource * get_default_resource() noexcept;
+//         memory_resource * set_default_resource(memory_resource*) noexcept;
+//
+// Concerns:
+//  A) 'get_default_resource()' returns a non-null memory_resource pointer.
+//  B) 'get_default_resource()' returns the value set by the last call to
+//     'set_default_resource(...)' and 'new_delete_resource()' if no call
+//     to 'set_default_resource(...)' has occurred.
+//  C) 'set_default_resource(...)' returns the previous value of the default
+//     resource.
+//  D) 'set_default_resource(T* p)' for a non-null 'p' sets the default resource
+//     to be 'p'.
+//  E) 'set_default_resource(null)' sets the default resource to
+//     'new_delete_resource()'.
+//  F) 'get_default_resource' and 'set_default_resource' are noexcept.
+//
+// Plan:
+//  1) Check concerns A and B in the following manner.
+//
+//     1a) Create a pointer 'p' from the return value of 'get_default_resource()'.
+//         Check that 'p' is not null and is the same as 'new_delete_resource()'.
+//     1b) Call 'get_default_resource()' again and check that it returns a pointer
+//         that is equal to 'p'
+//
+//  2) Check concerns A, B, C and D in the following manner:
+//
+//     2a) Create a TestResource 't' that derives from memory resource.
+//     2b) Call 'set_default_resource(&t)' and check that the returned
+//         value is the same as 'new_delete_resource()'.
+//     2c) Create a pointer 'p' from the return valeu of 'get_default_resource()'
+//         Check that 'p == &t'.
+//     2d) Call 'get_default_resource()' again and check that the same value
+//         is returned.
+//
+//  3) Check concerns A, B, C and E in the following manner:
+//
+//     3a) Call 'set_default_resource(nullptr)' and check that the returned
+//         value is the same as 't' from 2a.
+//     3b) Create a pointer 'p' from the return value of 'get_default_resource()'
+//         and check that 'p' is the same as 'new_delete_resource()'.
+//     3c) Call 'get_default_resource()' again and check that the same value
+//         is returned.
+//
+//  4) Check concern F by calling 'get_default_resource()' and
+//     'set_default_resource()' in a noexcept expression and assert
+//      that the expression is noexcept.
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+using namespace std::experimental::pmr;
+
+int main() {
+    TestResource R;
+    { // Test Part 1
+        memory_resource* p = get_default_resource();
+        assert(p != nullptr);
+        assert(p == new_delete_resource());
+        assert(p == get_default_resource());
+    }
+    { // Test Part 2
+        memory_resource *expect = &R;
+        memory_resource *old = set_default_resource(expect);
+        assert(old != nullptr);
+        assert(old == new_delete_resource());
+
+        memory_resource *p = get_default_resource();
+        assert(p != nullptr);
+        assert(p == expect);
+        assert(p == get_default_resource());
+    }
+    { // Test Part 3
+        memory_resource* old = set_default_resource(nullptr);
+        assert(old == &R);
+        memory_resource* p = get_default_resource();
+        assert(p != nullptr);
+        assert(p == new_delete_resource());
+        assert(p == get_default_resource());
+    }
+    { // Test Part 4
+        static_assert(
+            noexcept(get_default_resource())
+          , "get_default_resource() must be noexcept"
+          );
+        static_assert(
+            noexcept(set_default_resource(nullptr))
+          , "set_default_resource() must be noexcept"
+          );
+    }
+}
Index: test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap_comp.pass.cpp
===================================================================
--- test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap_comp.pass.cpp
+++ test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap_comp.pass.cpp
@@ -42,6 +42,7 @@
     std::make_heap(ia, ia+N, std::greater<int>());
     assert(std::is_heap(ia, ia+N, std::greater<int>()));
     }
+    }
 
 //  Ascending
     {
Index: test/libcxx/experimental/memory/memory.resource.synop/version.pass.cpp
===================================================================
--- /dev/null
+++ test/libcxx/experimental/memory/memory.resource.synop/version.pass.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+#include <experimental/memory_resource>
+
+#ifndef _LIBCPP_VERSION
+#error _LIBCPP_VERSION not defined
+#endif
+
+int main()
+{
+}
Index: src/support/atomic_support.h
===================================================================
--- src/support/atomic_support.h
+++ src/support/atomic_support.h
@@ -31,8 +31,8 @@
 
 namespace {
 
-#if defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS)
-
+//#if defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS)
+#if 1
 enum __libcpp_atomic_order {
     _AO_Relaxed = __ATOMIC_RELAXED,
     _AO_Consume = __ATOMIC_CONSUME,
@@ -73,6 +73,13 @@
     return __atomic_add_fetch(__val, __a, __order);
 }
 
+template <class _ValueType, class _ValueType2>
+inline _LIBCPP_INLINE_VISIBILITY
+_ValueType __libcpp_atomic_exchange(_ValueType* __val, _ValueType2 __new, int __order = _AO_Seq)
+{
+    return __atomic_exchange_n(__val, __new, __order);
+};
+
 template <class _ValueType>
 inline _LIBCPP_INLINE_VISIBILITY
 bool __libcpp_atomic_compare_exchange(_ValueType* __val,
@@ -119,6 +126,15 @@
     return *__val += __a;
 }
 
+template <class _ValueType, class _ValueType2>
+inline _LIBCPP_INLINE_VISIBILITY
+_ValueType __libcpp_atomic_exchange(_ValueType* __val, _ValueType2 __new, int = 0)
+{
+    _ValueType __tmp = *__val;
+    *__val = __new;
+    return __tmp;
+};
+
 template <class _ValueType>
 inline _LIBCPP_INLINE_VISIBILITY
 bool __libcpp_atomic_compare_exchange(_ValueType* __val,
Index: src/memory_resource.cpp
===================================================================
--- /dev/null
+++ src/memory_resource.cpp
@@ -0,0 +1,127 @@
+//===------------------------ memory_resource.cpp -------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "experimental/memory_resource"
+#include "limits"
+#include "cstdlib"
+
+#include "support/atomic_support.h"
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
+
+////////////////////////////////////////////////////////////////////////////////
+memory_resource::~memory_resource()
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+class _LIBCPP_HIDDEN __new_delete_memory_resource_imp
+    : public memory_resource
+{
+public:
+    ~__new_delete_memory_resource_imp();
+protected:
+    virtual void* do_allocate(size_t __size, size_t __align);
+    virtual void do_deallocate(void * __p, size_t __size, size_t __align);
+    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT;
+};
+
+__new_delete_memory_resource_imp::~__new_delete_memory_resource_imp()
+{
+}
+
+void * __new_delete_memory_resource_imp::do_allocate(size_t s, size_t)
+{
+    return ::operator new(s);
+}
+
+void __new_delete_memory_resource_imp::do_deallocate(void * p, size_t, size_t)
+{
+    return ::operator delete(p);
+}
+
+bool __new_delete_memory_resource_imp::do_is_equal(
+    memory_resource const & other) const _NOEXCEPT
+{
+    return this ==
+            dynamic_cast<__new_delete_memory_resource_imp const *>(&other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+ class _LIBCPP_HIDDEN __null_memory_resource_imp
+    : public memory_resource
+{
+public:
+    ~__null_memory_resource_imp();
+protected:
+    virtual void* do_allocate(size_t, size_t);
+    virtual void do_deallocate(void *, size_t, size_t);
+    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT;
+};
+
+__null_memory_resource_imp::~__null_memory_resource_imp()
+{
+}
+
+void* __null_memory_resource_imp::do_allocate(size_t, size_t)
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+    throw bad_alloc();
+#else
+    abort();
+#endif
+}
+
+void __null_memory_resource_imp::do_deallocate(void *, size_t, size_t)
+{
+}
+
+bool __null_memory_resource_imp::do_is_equal(
+    memory_resource const & __other) const _NOEXCEPT
+{
+    return &__other == static_cast<memory_resource const *>(this);
+}
+///////////////////////////////////////////////////////////////////////////////
+
+_ALIGNAS_TYPE(__new_delete_memory_resource_imp)
+static char __nd_res_buf[sizeof(__new_delete_memory_resource_imp)];
+
+_ALIGNAS_TYPE(__null_memory_resource_imp)
+static char __null_res_buf[sizeof(__null_memory_resource_imp)];
+
+memory_resource * new_delete_resource() _NOEXCEPT {
+    static memory_resource* resource =
+        ::new ((void*)&__nd_res_buf) __new_delete_memory_resource_imp();
+    return resource;
+}
+
+memory_resource * null_memory_resource() _NOEXCEPT {
+    static memory_resource* resource =
+        ::new ((void*)&__null_res_buf) __null_memory_resource_imp();
+    return resource;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static memory_resource** __default_resource() {
+    static memory_resource* ptr =  new_delete_resource() ;
+    return &ptr;
+}
+
+memory_resource* get_default_resource() _NOEXCEPT
+{
+    return __libcpp_atomic_load(__default_resource(), _AO_Aquire);
+}
+
+memory_resource * set_default_resource(memory_resource * new_res) _NOEXCEPT
+{
+    new_res = new_res ? new_res : new_delete_resource();
+    return __libcpp_atomic_exchange(__default_resource(), new_res, _AO_Acq_Rel);
+}
+
+_LIBCPP_END_NAMESPACE_LFTS_PMR
Index: include/experimental/memory_resource
===================================================================
--- /dev/null
+++ include/experimental/memory_resource
@@ -0,0 +1,148 @@
+// -*- C++ -*-
+//===------------------------ memory_resource -----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE
+#define _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE
+
+/**
+    experimental/memory_resource synopsis
+
+// C++1y
+
+namespace std {
+namespace experimental {
+inline namespace fundamentals_v1 {
+namespace pmr {
+
+  class memory_resource;
+
+  bool operator==(const memory_resource& a,
+                  const memory_resource& b) noexcept;
+  bool operator!=(const memory_resource& a,
+                  const memory_resource& b) noexcept;
+
+  template <class Tp> class polymorphic_allocator;
+
+  template <class T1, class T2>
+  bool operator==(const polymorphic_allocator<T1>& a,
+                  const polymorphic_allocator<T2>& b) noexcept;
+  template <class T1, class T2>
+  bool operator!=(const polymorphic_allocator<T1>& a,
+                  const polymorphic_allocator<T2>& b) noexcept;
+
+  // The name resource_adaptor_imp is for exposition only.
+  template <class Allocator> class resource_adaptor_imp;
+
+  template <class Allocator>
+    using resource_adaptor = resource_adaptor_imp<
+      allocator_traits<Allocator>::rebind_alloc<char>>;
+
+  // Global memory resources
+  memory_resource* new_delete_resource() noexcept;
+  memory_resource* null_memory_resource() noexcept;
+
+  // The default memory resource
+  memory_resource* set_default_resource(memory_resource* r) noexcept;
+  memory_resource* get_default_resource() noexcept;
+
+  // Standard memory resources
+  struct pool_options;
+  class synchronized_pool_resource;
+  class unsynchronized_pool_resource;
+  class monotonic_buffer_resource;
+
+} // namespace pmr
+} // namespace fundamentals_v1
+} // namespace experimental
+} // namespace std
+
+ */
+
+#include <experimental/__config>
+#include <experimental/__memory>
+#include <new>
+#include <cstddef>
+
+#include <__debug>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
+
+// 8.5, memory.resource
+class _LIBCPP_TYPE_VIS_ONLY memory_resource
+{
+    static const  size_t __max_align =
+        alignment_of<max_align_t>::value;
+
+// 8.5.2, memory.resource.public
+public:
+    virtual ~memory_resource();
+
+    _LIBCPP_INLINE_VISIBILITY
+    void* allocate(size_t __bytes, size_t __align = __max_align) {
+        _LIBCPP_ASSERT(__align != 0, "can't be zero");
+        _LIBCPP_ASSERT(__is_power2(__align), "alignment must be power of two");
+        void * const __ret = do_allocate(__bytes, __align);
+        _LIBCPP_ASSERT(
+            __alignment_offset(__ret, __max_align < __align ? __max_align : __align) == 0
+          , "Incorrect alignment");
+        return __ret;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void deallocate(void * __p, size_t __bytes, size_t __align = __max_align) {
+        _LIBCPP_ASSERT(__is_power2(__align), "alignment must be power of two");
+        _LIBCPP_ASSERT(
+            __alignment_offset(__p, __max_align < __align ? __max_align : __align) == 0
+          , "Incorrect alignment");
+        do_deallocate(__p, __bytes, __align);
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool is_equal(memory_resource const & __other) const _NOEXCEPT {
+        return do_is_equal(__other);
+    }
+
+// 8.5.3, memory.resource.priv
+protected:
+    virtual void* do_allocate(size_t __bytes, size_t __align) = 0;
+    virtual void do_deallocate(void * __p, size_t __bytes, size_t __align) = 0;
+    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT = 0;
+};
+
+// 8.5.4, memory.resource.eq
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator==(
+    memory_resource const & __lhs
+  , memory_resource const & __rhs) _NOEXCEPT
+{
+    return &__lhs == &__rhs || __lhs.is_equal(__rhs);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator!=(
+    memory_resource const & __lhs
+  , memory_resource const & __rhs) _NOEXCEPT
+{
+    return !(__lhs == __rhs);
+}
+
+_LIBCPP_FUNC_VIS memory_resource* new_delete_resource() _NOEXCEPT;
+_LIBCPP_FUNC_VIS memory_resource* null_memory_resource() _NOEXCEPT;
+_LIBCPP_FUNC_VIS memory_resource* get_default_resource() _NOEXCEPT;
+_LIBCPP_FUNC_VIS memory_resource* set_default_resource(memory_resource*) _NOEXCEPT;
+
+_LIBCPP_END_NAMESPACE_LFTS_PMR
+
+#endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */
Index: include/experimental/__memory
===================================================================
--- /dev/null
+++ include/experimental/__memory
@@ -0,0 +1,39 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_EXPERIMENTAL___MEMORY
+#define _LIBCPP_EXPERIMENTAL___MEMORY
+
+#include <experimental/__config>
+
+#include <cstddef>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS
+
+inline _LIBCPP_INLINE_VISIBILITY
+size_t __is_power2(size_t __bc)
+{
+    return  __bc == 1 || __bc == 2 || (__bc && !(__bc & (__bc - 1)));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+size_t __alignment_offset(void * __p, size_t __a) _NOEXCEPT
+{
+    static_assert(sizeof(size_t) == sizeof(void*), "must be same");
+    return (__a - reinterpret_cast<size_t>(__p)) & (__a - 1);
+}
+
+_LIBCPP_END_NAMESPACE_LFTS
+
+#endif /* _LIBCPP_EXPERIMENTAL___MEMORY */
Index: include/experimental/__config
===================================================================
--- include/experimental/__config
+++ include/experimental/__config
@@ -25,6 +25,10 @@
 #define _LIBCPP_END_NAMESPACE_LFTS  } } }
 #define _VSTD_LFTS _VSTD_EXPERIMENTAL::fundamentals_v1
 
+#define _LIBCPP_BEGIN_NAMESPACE_LFTS_PMR _LIBCPP_BEGIN_NAMESPACE_LFTS namespace pmr {
+#define _LIBCPP_END_NAMESPACE_LFTS_PMR _LIBCPP_END_NAMESPACE_LFTS }
+#define _VSTD_LFTS_PMR _VSTD_LFTS::pmr
+
 #define _LIBCPP_BEGIN_NAMESPACE_CHRONO_LFTS _LIBCPP_BEGIN_NAMESPACE_STD        \
   namespace chrono { namespace experimental { inline namespace fundamentals_v1 {
 #define _LIBCPP_END_NAMESPACE_CHRONO_LFTS _LIBCPP_END_NAMESPACE_STD } } }
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to