Add <experimental/memory_resource>

Reviewers: mclow.lists, EricWF

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D20007

llvm-svn: 268829
diff --git a/libcxx/src/experimental/memory_resource.cpp b/libcxx/src/experimental/memory_resource.cpp
new file mode 100644
index 0000000..fe338e0
--- /dev/null
+++ b/libcxx/src/experimental/memory_resource.cpp
@@ -0,0 +1,129 @@
+//===------------------------ 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"
+
+#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
+#include "atomic"
+#else
+#include "mutex"
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
+
+// memory_resource
+
+//memory_resource::~memory_resource() {}
+
+// new_delete_resource()
+
+class _LIBCPP_TYPE_VIS_ONLY __new_delete_memory_resource_imp
+    : public memory_resource
+{
+public:
+    ~__new_delete_memory_resource_imp() = default;
+
+protected:
+    virtual void* do_allocate(size_t __size, size_t __align)
+        { return __allocate(__size); }
+
+    virtual void do_deallocate(void * __p, size_t, size_t)
+        { __deallocate(__p); }
+
+    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
+        { return &__other == this; }
+};
+
+// null_memory_resource()
+
+class _LIBCPP_TYPE_VIS_ONLY __null_memory_resource_imp
+    : public memory_resource
+{
+public:
+    ~__null_memory_resource_imp() = default;
+
+protected:
+    virtual void* do_allocate(size_t, size_t) {
+#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
+        throw std::bad_alloc();
+#else
+        abort();
+#endif
+    }
+    virtual void do_deallocate(void *, size_t, size_t) {}
+    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
+    { return &__other == this; }
+};
+
+union ResourceInitHelper {
+  struct {
+    __new_delete_memory_resource_imp new_delete_res;
+    __null_memory_resource_imp       null_res;
+  } resources;
+  char dummy;
+  _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {}
+  ~ResourceInitHelper() {}
+};
+// When compiled in C++14 this initialization should be a constant expression.
+// Only in C++11 is "init_priority" needed to ensure initialization order.
+ResourceInitHelper res_init __attribute__((init_priority (101)));
+
+memory_resource * new_delete_resource() _NOEXCEPT {
+    return &res_init.resources.new_delete_res;
+}
+
+memory_resource * null_memory_resource() _NOEXCEPT {
+    return &res_init.resources.null_res;
+}
+
+// default_memory_resource()
+
+static memory_resource *
+__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT
+{
+#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
+    static atomic<memory_resource*> __res =
+        ATOMIC_VAR_INIT(&res_init.resources.new_delete_res);
+    if (set) {
+        new_res = new_res ? new_res : new_delete_resource();
+        // TODO: Can a weaker ordering be used?
+        return _VSTD::atomic_exchange_explicit(
+            &__res, new_res, memory_order::memory_order_acq_rel);
+    }
+    else {
+        return _VSTD::atomic_load_explicit(
+            &__res, memory_order::memory_order_acquire);
+    }
+#else
+    static memory_resource * res = &res_init.resources.new_delete_res;
+    static mutex res_lock;
+    if (set) {
+        new_res = new_res ? new_res : new_delete_resource();
+        lock_guard<mutex> guard(res_lock);
+        memory_resource * old_res = res;
+        res = new_res;
+        return old_res;
+    } else {
+        lock_guard<mutex> guard(res_lock);
+        return res;
+    }
+#endif
+}
+
+memory_resource * get_default_resource() _NOEXCEPT
+{
+    return __default_memory_resource();
+}
+
+memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT
+{
+    return __default_memory_resource(true, __new_res);
+}
+
+_LIBCPP_END_NAMESPACE_LFTS_PMR
\ No newline at end of file