Add <experimental/memory_resource>

Reviewers: mclow.lists, EricWF

Subscribers: cfe-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@268829 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/exception b/include/exception
index 686e4ec..537e4e3 100644
--- a/include/exception
+++ b/include/exception
@@ -80,6 +80,10 @@
 #include <__config>
 #include <cstddef>
 #include <type_traits>
+#if defined(_LIBCPP_HAS_NO_EXCEPTIONS)
+#include <cstdio>
+#include <cstdlib>
+#endif
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
@@ -251,4 +255,19 @@
 
 }  // std
 
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Exception>
+_LIBCPP_INLINE_VISIBILITY
+inline void __libcpp_throw(_Exception const& __e) {
+#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
+    throw __e;
+#else
+    _VSTD::fprintf(stderr, "%s\n", __e.what());
+    _VSTD::abort();
+#endif
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
 #endif  // _LIBCPP_EXCEPTION
diff --git a/include/experimental/__config b/include/experimental/__config
index f64a3a9..046a70a 100644
--- a/include/experimental/__config
+++ b/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 } } }
diff --git a/include/experimental/__memory b/include/experimental/__memory
new file mode 100644
index 0000000..229fea6
--- /dev/null
+++ b/include/experimental/__memory
@@ -0,0 +1,90 @@
+// -*- 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 <experimental/utility> // for erased_type
+#include <__functional_base>
+#include <type_traits>
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS
+
+template <
+    class _Tp, class _Alloc
+  , bool = uses_allocator<_Tp, _Alloc>::value
+  , bool = __has_allocator_type<_Tp>::value
+  >
+struct __lfts_uses_allocator : public false_type {};
+
+template <class _Tp, class _Alloc>
+struct __lfts_uses_allocator<_Tp, _Alloc, false, false> : public false_type {};
+
+template <class _Tp, class _Alloc, bool HasAlloc>
+struct __lfts_uses_allocator<_Tp, _Alloc, true, HasAlloc> : public true_type {};
+
+template <class _Tp, class _Alloc>
+struct __lfts_uses_allocator<_Tp, _Alloc, false, true>
+  : public integral_constant<bool
+    , is_convertible<_Alloc, typename _Tp::allocator_type>::value
+      || is_same<erased_type, typename _Tp::allocator_type>::value
+    >
+{};
+
+template <bool _UsesAlloc, class _Tp, class _Alloc, class ..._Args>
+struct __lfts_uses_alloc_ctor_imp
+{
+    static const int value = 0;
+};
+
+template <class _Tp, class _Alloc, class ..._Args>
+struct __lfts_uses_alloc_ctor_imp<true, _Tp, _Alloc, _Args...>
+{
+    static const bool __ic_first
+        = is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value;
+
+    static const bool __ic_second =
+        conditional<
+            __ic_first,
+            false_type,
+            is_constructible<_Tp, _Args..., _Alloc>
+        >::type::value;
+
+    static_assert(__ic_first || __ic_second,
+                  "Request for uses allocator construction is ill-formed");
+
+    static const int value = __ic_first ? 1 : 2;
+};
+
+template <class _Tp, class _Alloc, class ..._Args>
+struct __lfts_uses_alloc_ctor
+  : integral_constant<int,
+        __lfts_uses_alloc_ctor_imp<
+            __lfts_uses_allocator<_Tp, _Alloc>::value
+          , _Tp, _Alloc, _Args...
+        >::value
+    >
+{};
+
+template <class _Tp, class _Alloc, class ..._Args>
+inline _LIBCPP_INLINE_VISIBILITY
+void __lfts_user_alloc_construct(
+    _Tp * __store, const _Alloc & __a, _Args &&... __args)
+{
+    _VSTD::__user_alloc_construct_impl(
+        typename __lfts_uses_alloc_ctor<_Tp, _Alloc, _Args...>::type()
+       , __store, __a, _VSTD::forward<_Args>(__args)...
+       );
+}
+
+_LIBCPP_END_NAMESPACE_LFTS
+
+#endif /* _LIBCPP_EXPERIMENTAL___MEMORY */
diff --git a/include/experimental/memory_resource b/include/experimental/memory_resource
new file mode 100644
index 0000000..f54ef0b
--- /dev/null
+++ b/include/experimental/memory_resource
@@ -0,0 +1,422 @@
+// -*- 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 <limits>
+#include <memory>
+#include <new>
+#include <stdexcept>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <cstddef>
+#include <cstdlib>
+#include <__debug>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
+
+// Round __s up to next multiple of __a.
+inline _LIBCPP_INLINE_VISIBILITY
+size_t __aligned_allocation_size(size_t __s, size_t __a) _NOEXCEPT
+{
+    _LIBCPP_ASSERT(__s + __a > __s, "aligned allocation size overflows");
+    return (__s + __a - 1) & ~(__a - 1);
+}
+
+// 8.5, memory.resource
+class _LIBCPP_TYPE_VIS_ONLY memory_resource
+{
+    static const size_t __max_align = alignof(max_align_t);
+
+// 8.5.2, memory.resource.public
+public:
+    virtual ~memory_resource() = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    void* allocate(size_t __bytes, size_t __align = __max_align)
+        { return do_allocate(__bytes, __align); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void deallocate(void * __p, size_t __bytes, size_t __align = __max_align)
+        { 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, size_t) = 0;
+    virtual void do_deallocate(void*, size_t, size_t) = 0;
+    virtual bool do_is_equal(memory_resource const &) 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 * __new_res) _NOEXCEPT;
+
+// 8.6, memory.polymorphic.allocator.class
+
+// 8.6.1, memory.polymorphic.allocator.overview
+template <class _ValueType>
+class _LIBCPP_TYPE_VIS_ONLY polymorphic_allocator
+{
+public:
+    typedef _ValueType value_type;
+
+    // 8.6.2, memory.polymorphic.allocator.ctor
+    _LIBCPP_INLINE_VISIBILITY
+    polymorphic_allocator() _NOEXCEPT
+      : __res_(_VSTD_LFTS_PMR::get_default_resource())
+    {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    polymorphic_allocator(memory_resource * __r) _NOEXCEPT
+      : __res_(__r)
+    {}
+
+    polymorphic_allocator(polymorphic_allocator const &) = default;
+
+    template <class _Tp>
+    _LIBCPP_INLINE_VISIBILITY
+    polymorphic_allocator(polymorphic_allocator<_Tp> const & __other) _NOEXCEPT
+      : __res_(__other.resource())
+    {}
+
+    polymorphic_allocator &
+    operator=(polymorphic_allocator const &) = default;
+
+    // 8.6.3, memory.polymorphic.allocator.mem
+    _LIBCPP_INLINE_VISIBILITY
+    _ValueType* allocate(size_t __n) {
+        if (__n > max_size()) {
+            __libcpp_throw(length_error(
+                "std::experimental::pmr::polymorphic_allocator<T>::allocate(size_t n)"
+                " 'n' exceeds maximum supported size"));
+        }
+        return static_cast<_ValueType*>(
+            __res_->allocate(__n * sizeof(_ValueType), alignof(_ValueType))
+        );
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void deallocate(_ValueType * __p, size_t __n) _NOEXCEPT {
+        _LIBCPP_ASSERT(__n <= max_size(),
+                       "deallocate called for size which exceeds max_size()");
+        __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType));
+    }
+
+    template <class _Tp, class ..._Ts>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(_Tp* __p, _Ts &&... __args)
+    {
+        _VSTD_LFTS::__lfts_user_alloc_construct(
+            __p, resource(), _VSTD::forward<_Ts>(__args)...
+          );
+    }
+
+    template <class _T1, class _T2, class ..._Args1, class ..._Args2>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2>* __p, piecewise_construct_t,
+                   tuple<_Args1...> __x, tuple<_Args2...> __y)
+    {
+        ::new ((void*)__p) pair<_T1, _T2>(piecewise_construct
+          , __transform_tuple(
+              typename __lfts_uses_alloc_ctor<
+                  _T1, memory_resource*, _Args1...
+              >::type()
+            , _VSTD::move(__x)
+            , typename __make_tuple_indices<sizeof...(_Args1)>::type{}
+          )
+          , __transform_tuple(
+              typename __lfts_uses_alloc_ctor<
+                  _T2, memory_resource*, _Args2...
+              >::type()
+            , _VSTD::move(__y)
+            , typename __make_tuple_indices<sizeof...(_Args2)>::type{}
+          )
+        );
+    }
+
+    template <class _T1, class _T2>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2>* __p) {
+        construct(__p, piecewise_construct, tuple<>(), tuple<>());
+    }
+
+    template <class _T1, class _T2, class _Up, class _Vp>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2> * __p, _Up && __u, _Vp && __v) {
+        construct(__p, piecewise_construct
+          , _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__u))
+          , _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__v)));
+    }
+
+    template <class _T1, class _T2, class _U1, class _U2>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> const & __pr) {
+        construct(__p, piecewise_construct
+            , _VSTD::forward_as_tuple(__pr.first)
+            , _VSTD::forward_as_tuple(__pr.second));
+    }
+
+    template <class _T1, class _T2, class _U1, class _U2>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> && __pr){
+        construct(__p, piecewise_construct
+            , _VSTD::forward_as_tuple(_VSTD::forward<_U1>(__pr.first))
+            , _VSTD::forward_as_tuple(_VSTD::forward<_U2>(__pr.second)));
+    }
+
+    template <class _Tp>
+    _LIBCPP_INLINE_VISIBILITY
+    void destroy(_Tp * __p) _NOEXCEPT
+        { __p->~_Tp(); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    size_t max_size() const _NOEXCEPT
+        { return numeric_limits<size_t>::max() / sizeof(value_type); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    polymorphic_allocator
+    select_on_container_copy_construction() const _NOEXCEPT
+        { return polymorphic_allocator(); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    memory_resource * resource() const _NOEXCEPT
+        { return __res_; }
+
+private:
+    template <class ..._Args, size_t ..._Idx>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple<_Args&&...>
+    __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t,
+                      __tuple_indices<_Idx...>) const
+    {
+        return _VSTD::forward_as_tuple(_VSTD::get<_Idx>(_VSTD::move(__t))...);
+    }
+
+    template <class ..._Args, size_t ..._Idx>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple<allocator_arg_t const&, memory_resource*, _Args&&...>
+    __transform_tuple(integral_constant<int, 1>, tuple<_Args...> && __t,
+                      __tuple_indices<_Idx...>) const
+    {
+        using _Tup = tuple<allocator_arg_t const&, memory_resource*, _Args&&...>;
+        return _Tup(allocator_arg, resource(),
+                    _VSTD::get<_Idx>(_VSTD::move(__t))...);
+    }
+
+    template <class ..._Args, size_t ..._Idx>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple<_Args&&..., memory_resource*>
+    __transform_tuple(integral_constant<int, 2>, tuple<_Args...> && __t,
+                      __tuple_indices<_Idx...>) const
+    {
+        using _Tup = tuple<_Args&&..., memory_resource*>;
+        return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., resource());
+    }
+
+    memory_resource * __res_;
+};
+
+// 8.6.4, memory.polymorphic.allocator.eq
+
+template <class _Tp, class _Up>
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator==(polymorphic_allocator<_Tp> const & __lhs,
+                polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
+{
+    return *__lhs.resource() == *__rhs.resource();
+}
+
+template <class _Tp, class _Up>
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator!=(polymorphic_allocator<_Tp> const & __lhs,
+                polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
+{
+    return !(__lhs == __rhs);
+}
+
+// 8.7, memory.resource.adaptor
+
+// 8.7.1, memory.resource.adaptor.overview
+template <class _CharAlloc>
+class _LIBCPP_TYPE_VIS_ONLY __resource_adaptor_imp
+  : public memory_resource
+{
+    using _CTraits = allocator_traits<_CharAlloc>;
+    static_assert(is_same<typename _CTraits::value_type, char>::value
+               && is_same<typename _CTraits::pointer, char*>::value
+               && is_same<typename _CTraits::void_pointer, void*>::value, "");
+
+    static const size_t _MaxAlign = alignof(max_align_t);
+
+    using _Alloc = typename _CTraits::template rebind_alloc<
+            typename aligned_storage<_MaxAlign, _MaxAlign>::type
+        >;
+
+    using _ValueType = typename _Alloc::value_type;
+
+    _Alloc __alloc_;
+
+public:
+    typedef _CharAlloc allocator_type;
+
+    __resource_adaptor_imp() = default;
+    __resource_adaptor_imp(__resource_adaptor_imp const &) = default;
+    __resource_adaptor_imp(__resource_adaptor_imp &&) = default;
+
+    // 8.7.2, memory.resource.adaptor.ctor
+
+    _LIBCPP_INLINE_VISIBILITY
+    explicit __resource_adaptor_imp(allocator_type const & __a)
+      : __alloc_(__a)
+    {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    explicit __resource_adaptor_imp(allocator_type && __a)
+      : __alloc_(_VSTD::move(__a))
+    {}
+
+    __resource_adaptor_imp &
+    operator=(__resource_adaptor_imp const &) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    allocator_type get_allocator() const
+    { return __alloc_; }
+
+// 8.7.3, memory.resource.adaptor.mem
+protected:
+    virtual void * do_allocate(size_t __bytes, size_t)
+    {
+        if (__bytes > __max_size()) {
+            __libcpp_throw(length_error(
+                "std::experimental::pmr::resource_adaptor<T>::do_allocate(size_t bytes, size_t align)"
+                " 'bytes' exceeds maximum supported size"));
+        }
+        size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
+        return __alloc_.allocate(__s);
+    }
+
+    virtual void do_deallocate(void * __p, size_t __bytes, size_t)
+    {
+        _LIBCPP_ASSERT(__bytes <= __max_size(),
+            "do_deallocate called for size which exceeds the maximum allocation size");
+        size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
+        __alloc_.deallocate((_ValueType*)__p, __s);
+    }
+
+    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT {
+        __resource_adaptor_imp const * __p
+          = dynamic_cast<__resource_adaptor_imp const *>(&__other);
+        return __p  ? __alloc_ == __p->__alloc_ : false;
+    }
+
+private:
+    _LIBCPP_INLINE_VISIBILITY
+    size_t __max_size() const _NOEXCEPT {
+        return numeric_limits<size_t>::max() - _MaxAlign;
+    }
+};
+
+template <class _Alloc>
+using resource_adaptor = __resource_adaptor_imp<
+    typename allocator_traits<_Alloc>::template rebind_alloc<char>
+  >;
+
+_LIBCPP_END_NAMESPACE_LFTS_PMR
+
+#endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */