Implement C++ LFTSv1 polymorphic memory resources
authorFan You <youfan.noey@gmail.com>
Fri, 13 Nov 2015 10:00:59 +0000 (10:00 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 13 Nov 2015 10:00:59 +0000 (10:00 +0000)
2015-11-13  Fan You  <youfan.noey@gmail.com>

* include/Makefile.am: Add new headers.
* include/Makefile.in: Regenerate.
* include/bits/uses_allocator.h (__erased_type): Define.
(__uses_allocator_helper): Check for __erased_type.
* include/experimental/memory_resource: New.
* include/experimental/utlity: New.
* testsuite/experimental/type_erased_allocator/1.cc: New.
* testsuite/experimental/type_erased_allocator/1_neg.cc: New.
* testsuite/experimental/type_erased_allocator/2.cc: New.
* testsuite/experimental/type_erased_allocator/uses_allocator.cc: New.

From-SVN: r230294

libstdc++-v3/ChangeLog
libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/bits/uses_allocator.h
libstdc++-v3/include/experimental/memory_resource [new file with mode: 0644]
libstdc++-v3/include/experimental/utility [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/type_erased_allocator/1_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/type_erased_allocator/2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/type_erased_allocator/uses_allocator.cc [new file with mode: 0644]

index e1cc38ff1ef650abd922294dc90c89873f7d2a5e..f52bfef65d5622e92d9a5629320958de83d400ca 100644 (file)
@@ -1,3 +1,16 @@
+2015-11-13  Fan You  <youfan.noey@gmail.com>
+
+       * include/Makefile.am: Add new headers.
+       * include/Makefile.in: Regenerate.
+       * include/bits/uses_allocator.h (__erased_type): Define.
+       (__uses_allocator_helper): Check for __erased_type.
+       * include/experimental/memory_resource: New.
+       * include/experimental/utlity: New.
+       * testsuite/experimental/type_erased_allocator/1.cc: New.
+       * testsuite/experimental/type_erased_allocator/1_neg.cc: New.
+       * testsuite/experimental/type_erased_allocator/2.cc: New.
+       * testsuite/experimental/type_erased_allocator/uses_allocator.cc: New.
+
 2015-11-12  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libstdc++/56158
index 2dc0d01241ac79576de7b6c558d83482b91ae759..ee9b6d8c246292c195114e50c96a6286f8766bfd 100644 (file)
@@ -656,6 +656,7 @@ experimental_headers = \
        ${experimental_srcdir}/list \
        ${experimental_srcdir}/map \
        ${experimental_srcdir}/memory \
+       ${experimental_srcdir}/memory_resource \
        ${experimental_srcdir}/numeric \
        ${experimental_srcdir}/optional \
        ${experimental_srcdir}/propagate_const \
@@ -668,6 +669,7 @@ experimental_headers = \
        ${experimental_srcdir}/type_traits \
        ${experimental_srcdir}/unordered_map \
        ${experimental_srcdir}/unordered_set \
+       ${experimental_srcdir}/utility \
        ${experimental_srcdir}/vector \
        ${experimental_filesystem_headers}
 
index d545484a5680c6f89a10bf8ccc2d393307c817ab..482fdb406a79d0e547831037aa3e07683cd810e9 100644 (file)
@@ -945,6 +945,7 @@ experimental_headers = \
        ${experimental_srcdir}/list \
        ${experimental_srcdir}/map \
        ${experimental_srcdir}/memory \
+       ${experimental_srcdir}/memory_resource \
        ${experimental_srcdir}/numeric \
        ${experimental_srcdir}/optional \
        ${experimental_srcdir}/propagate_const \
@@ -957,6 +958,7 @@ experimental_headers = \
        ${experimental_srcdir}/type_traits \
        ${experimental_srcdir}/unordered_map \
        ${experimental_srcdir}/unordered_set \
+       ${experimental_srcdir}/utility \
        ${experimental_srcdir}/vector \
        ${experimental_filesystem_headers}
 
index a0f084d9aa9ec6cd2109b640ff89f142ac4ee3d3..f7566a2e522d54448091832cc2bb084c1c7d5b5b 100644 (file)
@@ -35,6 +35,12 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+  struct __erased_type { };
+
+  template<typename _Alloc, typename _Tp>
+    using __is_erased_or_convertible
+      = __or_<is_same<_Tp, __erased_type>, is_convertible<_Alloc, _Tp>>;
+
   /// [allocator.tag]
   struct allocator_arg_t { explicit allocator_arg_t() = default; };
 
@@ -47,7 +53,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp, typename _Alloc>
     struct __uses_allocator_helper<_Tp, _Alloc,
                                   __void_t<typename _Tp::allocator_type>>
-    : is_convertible<_Alloc, typename _Tp::allocator_type>::type
+    : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type
     { };
 
   /// [allocator.uses.trait]
diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource
new file mode 100644 (file)
index 0000000..5c8cbd6
--- /dev/null
@@ -0,0 +1,383 @@
+// <experimental/memory_resource> -*- C++ -*-
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file experimental/memory_resource
+ *  This is a TS C++ Library header.
+ */
+
+#ifndef _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE
+#define _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 1
+
+#include <memory>
+#include <new>
+#include <atomic>
+#include <cstddef>
+#include <bits/alloc_traits.h>
+
+namespace std {
+namespace experimental {
+inline namespace fundamentals_v2 {
+namespace pmr {
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  class memory_resource;
+
+  template <typename _Tp>
+    class polymorphic_allocator;
+
+  template <typename _Alloc>
+    class __resource_adaptor_imp;
+
+  template <typename _Alloc>
+    using resource_adaptor = __resource_adaptor_imp<
+      typename allocator_traits<_Alloc>::template rebind_alloc<char>>;
+
+  template <typename _Tp>
+    struct __uses_allocator_construction_helper;
+
+  // Global memory resources
+  memory_resource* new_delete_resource() noexcept;
+  memory_resource* null_memory_resource() noexcept;
+
+  // The default memory resource
+  memory_resource* get_default_resource() noexcept;
+  memory_resource* set_default_resource(memory_resource* __r) noexcept;
+
+  // Standard memory resources
+
+  // 8.5 Class memory_resource
+  class memory_resource
+  {
+    static constexpr size_t _S_max_align = alignof(max_align_t);
+
+  public:
+    virtual ~memory_resource() { }
+
+    void*
+    allocate(size_t __bytes, size_t __alignment = _S_max_align)
+    { return do_allocate(__bytes, __alignment); }
+
+    void
+    deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
+    { return do_deallocate(__p, __bytes, __alignment); }
+
+    bool
+    is_equal(const memory_resource& __other) const noexcept
+    { return do_is_equal(__other); }
+
+  protected:
+    virtual void*
+    do_allocate(size_t __bytes, size_t __alignment) = 0;
+
+    virtual void
+    do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
+
+    virtual bool
+    do_is_equal(const memory_resource& __other) const noexcept = 0;
+  };
+
+  inline bool
+  operator==(const memory_resource& __a,
+            const memory_resource& __b) noexcept
+  { return &__a == &__b || __a.is_equal(__b); }
+
+  inline bool
+  operator!=(const memory_resource& __a,
+            const memory_resource& __b) noexcept
+  { return !(__a == __b); }
+
+
+  // 8.6 Class template polymorphic_allocator
+  template <class _Tp>
+    class polymorphic_allocator
+    {
+      using __uses_alloc1_ = __uses_alloc1<memory_resource*>;
+      using __uses_alloc2_ = __uses_alloc2<memory_resource*>;
+
+      template<typename _Tp1, typename... _Args>
+       void
+       _M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args)
+       { ::new(__p) _Tp1(std::forward<_Args>(__args)...); }
+
+      template<typename _Tp1, typename... _Args>
+       void
+       _M_construct(__uses_alloc1_, _Tp1* __p, _Args&&...  __args)
+       { ::new(__p) _Tp1(allocator_arg, this->resource(),
+                         std::forward<_Args>(__args)...); }
+
+      template<typename _Tp1, typename... _Args>
+       void
+       _M_construct(__uses_alloc2_, _Tp1* __p, _Args&&...  __args)
+       { ::new(__p) _Tp1(std::forward<_Args>(__args)...,
+                         this->resource()); }
+
+    public:
+      using value_type = _Tp;
+
+      polymorphic_allocator() noexcept
+      : _M_resource(get_default_resource())
+      { }
+
+      polymorphic_allocator(memory_resource* __r)
+      : _M_resource(__r)
+      { _GLIBCXX_DEBUG_ASSERT(__r); }
+
+      polymorphic_allocator(const polymorphic_allocator& __other) = default;
+
+      template <typename _Up>
+       polymorphic_allocator(const polymorphic_allocator<_Up>&
+                             __other) noexcept
+       : _M_resource(__other.resource())
+       { }
+
+      polymorphic_allocator&
+       operator=(const polymorphic_allocator& __rhs) = default;
+
+      _Tp* allocate(size_t __n)
+      { return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
+                                                      alignof(_Tp))); }
+
+      void deallocate(_Tp* __p, size_t __n)
+      { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
+
+      template <typename _Tp1, typename... _Args> //used here
+       void construct(_Tp1* __p, _Args&&... __args)
+       {
+         auto __use_tag = __use_alloc<_Tp1, memory_resource*,
+              _Args...>(this->resource());
+         _M_construct(__use_tag, __p, std::forward<_Args>(__args)...);
+       }
+
+      // Specializations for pair using piecewise construction
+      template <typename _Tp1, typename _Tp2,
+              typename... _Args1, typename... _Args2>
+       void construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
+                      tuple<_Args1...> __x,
+                      tuple<_Args2...> __y)
+       {
+         auto __x_use_tag =
+           __use_alloc<_Tp1, memory_resource*, _Args1...>(this->resource());
+         auto __y_use_tag =
+           __use_alloc<_Tp2, memory_resource*, _Args2...>(this->resource());
+
+         ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct,
+                                          _M_construct_p(__x_use_tag, __x),
+                                          _M_construct_p(__y_use_tag, __y));
+       }
+
+      template <typename _Tp1, typename _Tp2>
+       void construct(pair<_Tp1,_Tp2>* __p)
+       { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
+
+      template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
+       void construct(pair<_Tp1,_Tp2>* __p, _Up&& __x, _Vp&& __y)
+       { this->construct(__p, piecewise_construct,
+                         forward_as_tuple(std::forward<_Up>(__x)),
+                         forward_as_tuple(std::forward<_Vp>(__y))); }
+
+      template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
+       void construct(pair<_Tp1,_Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
+       { this->construct(__p, piecewise_construct, forward_as_tuple(__pr.first),
+                         forward_as_tuple(__pr.second)); }
+
+      template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
+       void construct(pair<_Tp1,_Tp2>* __p, pair<_Up, _Vp>&& __pr)
+       { this->construct(__p, piecewise_construct,
+                         forward_as_tuple(std::forward<_Up>(__pr.first)),
+                         forward_as_tuple(std::forward<_Vp>(__pr.second))); }
+
+      template <typename _Up>
+       void destroy(_Up* __p)
+       { __p->~_Up(); }
+
+      // Return a default-constructed allocator (no allocator propagation)
+      polymorphic_allocator select_on_container_copy_construction() const
+      { return polymorphic_allocator(); }
+
+      memory_resource* resource() const
+      { return _M_resource; }
+
+    private:
+      template<typename _Tuple>
+       _Tuple&&
+       _M_construct_p(__uses_alloc0, _Tuple& __t)
+       { return std::move(__t); }
+
+      template<typename... _Args>
+       decltype(auto)
+       _M_construct_p(__uses_alloc1_ __ua, tuple<_Args...>& __t)
+       { return tuple_cat(make_tuple(allocator_arg, *(__ua._M_a)),
+                          std::move(__t)); }
+
+      template<typename... _Args>
+       decltype(auto)
+       _M_construct_p(__uses_alloc2_ __ua, tuple<_Args...>& __t)
+       { return tuple_cat(std::move(__t), make_tuple(*(__ua._M_a))); }
+
+      memory_resource* _M_resource;
+    };
+
+  template <class _Tp1, class _Tp2>
+    bool operator==(const polymorphic_allocator<_Tp1>& __a,
+                   const polymorphic_allocator<_Tp2>& __b) noexcept
+    { return *__a.resource() == *__b.resource(); }
+
+  template <class _Tp1, class _Tp2>
+    bool operator!=(const polymorphic_allocator<_Tp1>& __a,
+                   const polymorphic_allocator<_Tp2>& __b) noexcept
+    { return !(__a == __b); }
+
+  // 8.7.1 __resource_adaptor_imp
+  template <typename _Alloc>
+    class __resource_adaptor_imp : public memory_resource
+    {
+    public:
+      using allocator_type = _Alloc;
+
+      __resource_adaptor_imp() = default;
+      __resource_adaptor_imp(const __resource_adaptor_imp&) = default;
+      __resource_adaptor_imp(__resource_adaptor_imp&&) = default;
+
+      explicit __resource_adaptor_imp(const _Alloc& __a2)
+      : _M_alloc(__a2)
+      { }
+
+      explicit __resource_adaptor_imp(_Alloc&& __a2)
+      : _M_alloc(std::move(__a2))
+      { }
+
+      __resource_adaptor_imp&
+      operator=(const __resource_adaptor_imp&) = default;
+
+      allocator_type get_allocator() const { return _M_alloc; }
+
+    protected:
+      virtual void*
+      do_allocate(size_t __bytes, size_t __alignment)
+      {
+       using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>;
+       size_t __new_size = _S_aligned_size(__bytes,
+                                           _S_supported(__alignment) ?
+                                           __alignment : _S_max_align);
+       return _Aligned_alloc().allocate(__new_size);
+      }
+
+      virtual void
+      do_deallocate(void* __p, size_t __bytes, size_t __alignment)
+      {
+       using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>;
+       size_t __new_size = _S_aligned_size(__bytes,
+                                           _S_supported(__alignment) ?
+                                           __alignment : _S_max_align);
+       _Aligned_alloc().deallocate(static_cast<typename
+                                   _Aligned_alloc::pointer>(__p),
+                                   __new_size);
+      }
+
+      virtual bool
+      do_is_equal(const memory_resource& __other) const noexcept
+      {
+       auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other);
+       return __p ? (_M_alloc == __p->_M_alloc) : false;
+      }
+
+    private:
+      // Calculate Aligned Size
+      // Returns a size that is larger than or equal to __size and divided by
+      // __alignment, where __alignment is required to be the power of 2.
+      static size_t
+      _S_aligned_size(size_t __size, size_t __alignment)
+      { return ((__size - 1)|(__alignment - 1)) + 1; }
+
+      // Determine whether alignment meets one of those preconditions:
+      // 1. Equals to Zero
+      // 2. Is power of two
+      static bool
+      _S_supported (size_t __x)
+      { return ((__x != 0) && !(__x & (__x - 1))); }
+
+      _Alloc _M_alloc;
+    };
+
+  // Global memory resources
+  inline std::atomic<memory_resource*>&
+  __get_default_resource()
+  {
+    static atomic<memory_resource*> _S_default_resource(new_delete_resource());
+    return _S_default_resource;
+  }
+
+  inline memory_resource*
+  new_delete_resource() noexcept
+  {
+    static resource_adaptor<std::allocator<char>> __r;
+    return static_cast<memory_resource*>(&__r);
+  }
+
+  template <typename _Alloc>
+    class __null_memory_resource : private memory_resource
+    {
+    protected:
+      void*
+      do_allocate(size_t __bytes, size_t __alignment)
+      { std::__throw_bad_alloc(); }
+
+      void
+      do_deallocate(void* __p, size_t __bytes, size_t __alignment)
+      { }
+
+      bool
+      do_is_equal(const memory_resource& __other) const noexcept
+      { }
+
+      friend memory_resource* null_memory_resource() noexcept;
+    };
+
+  inline memory_resource*
+  null_memory_resource() noexcept
+  {
+    static __null_memory_resource<void> __r;
+    return static_cast<memory_resource*>(&__r);
+  }
+
+  // The default memory resource
+  inline memory_resource*
+  get_default_resource() noexcept
+  { return __get_default_resource().load(); }
+
+  inline memory_resource*
+  set_default_resource(memory_resource* __r) noexcept
+  {
+    if (__r == nullptr)
+      __r = new_delete_resource();
+    return __get_default_resource().exchange(__r);
+  }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace pmr
+} // namespace fundamentals_v2
+} // namespace experimental
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/experimental/utility b/libstdc++-v3/include/experimental/utility
new file mode 100644 (file)
index 0000000..b1aacee
--- /dev/null
@@ -0,0 +1,48 @@
+// <experimental/utility> -*- C++ -*-
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file experimental/utility
+ *  This is a TS C++ Library header.
+ */
+
+#ifndef _GLIBCXX_EXPERIMENTAL_UTILITY
+#define _GLIBCXX_EXPERIMENTAL_UTILITY 1
+
+#include <utility>
+#include <bits/uses_allocator.h>
+
+namespace std {
+namespace experimental {
+inline namespace fundamentals_v2 {
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  // 3.1.2, erased-type placeholder
+  using erased_type = std::__erased_type;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace fundamentals_v2
+} // namespace experimental
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc b/libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc
new file mode 100644 (file)
index 0000000..9545edf
--- /dev/null
@@ -0,0 +1,147 @@
+// { dg-options "-std=gnu++14" }
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <memory>
+#include <experimental/memory_resource>
+#include <vector>
+#include <bits/uses_allocator.h>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using std::experimental::pmr::polymorphic_allocator;
+using std::experimental::pmr::memory_resource;
+using std::experimental::pmr::new_delete_resource;
+using std::experimental::pmr::get_default_resource;
+using std::experimental::pmr::set_default_resource;
+
+struct A
+{
+  A() { ++ctor_count; }
+  ~A() { ++dtor_count; }
+  static int ctor_count;
+  static int dtor_count;
+};
+int A::ctor_count = 0;
+int A::dtor_count = 0;
+
+struct CountedResource : public memory_resource
+{
+public:
+  CountedResource() = default;
+  ~ CountedResource() = default;
+
+  static size_t get_alloc_count()  { return alloc_count;  }
+  static size_t get_dalloc_count() { return dalloc_count; }
+
+  static size_t  alloc_count;
+  static size_t  dalloc_count;
+protected:
+  void* do_allocate(size_t bytes, size_t alignment)
+  {
+    alloc_count += bytes;
+    if (auto ptr = std::malloc(bytes)) {
+      return ptr;
+    }
+    throw std::bad_alloc();
+  }
+
+  void do_deallocate(void *p, size_t bytes, size_t alignment)
+  {
+    dalloc_count += bytes;
+    free(p);
+  }
+
+  bool do_is_equal(const memory_resource& __other) const noexcept
+  { return this == &__other; }
+};
+  size_t  CountedResource::alloc_count  = 0;
+  size_t  CountedResource::dalloc_count = 0;
+
+void clear()
+{
+  CountedResource::alloc_count  = 0;
+  CountedResource::dalloc_count = 0;
+  A::ctor_count = 0;
+  A::dtor_count = 0;
+}
+
+// memory resource
+void test01()
+{
+  memory_resource* r = new_delete_resource();
+  VERIFY(get_default_resource() == r);
+  void *p = get_default_resource()->allocate(5);
+  VERIFY(p);
+  get_default_resource()->deallocate(p, 5);
+
+  clear();
+  CountedResource* cr = new CountedResource();
+  set_default_resource(cr);
+  VERIFY(get_default_resource() == cr);
+  void *pc = get_default_resource()->allocate(5);
+  VERIFY(pc);
+  get_default_resource()->deallocate(pc, 5);
+  VERIFY(CountedResource::get_alloc_count()  == 5);
+  VERIFY(CountedResource::get_dalloc_count() == 5);
+}
+
+// polymorphic_allocator
+void test02()
+{
+  clear();
+  {
+    CountedResource cr;
+    polymorphic_allocator<A> pa(&cr);
+    std::vector<A, polymorphic_allocator<A>> v(5, A(), pa);
+  }
+  VERIFY(A::ctor_count == 1);
+  VERIFY(A::dtor_count == 6);
+  VERIFY(CountedResource::get_alloc_count()  == 5);
+  VERIFY(CountedResource::get_dalloc_count() == 5);
+}
+
+void test03() {
+  clear();
+  CountedResource cr;
+  polymorphic_allocator<A> pa(&cr);
+  A* p = pa.allocate(1);
+  pa.construct(p);
+  pa.destroy(p);
+  pa.deallocate(p, 1);
+  VERIFY(A::ctor_count == 1);
+  VERIFY(A::dtor_count == 1);
+  VERIFY(CountedResource::get_alloc_count()  == 1);
+  VERIFY(CountedResource::get_dalloc_count() == 1);
+}
+
+void test04() {
+  polymorphic_allocator<A> pa1(get_default_resource());
+  polymorphic_allocator<A> pa2(get_default_resource());
+  VERIFY(pa1 == pa2);
+  polymorphic_allocator<A> pa3 = pa2.select_on_container_copy_construction();
+  VERIFY(pa1 == pa3);
+}
+
+int main() {
+  test01();
+  test02();
+  test03();
+  test04();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/experimental/type_erased_allocator/1_neg.cc b/libstdc++-v3/testsuite/experimental/type_erased_allocator/1_neg.cc
new file mode 100644 (file)
index 0000000..b85e0ea
--- /dev/null
@@ -0,0 +1,37 @@
+// { dg-do run { xfail *-*-* } }
+// { dg-options "-std=gnu++14" }
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <experimental/memory_resource>
+#include <bits/uses_allocator.h>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using std::experimental::pmr::polymorphic_allocator;
+using std::experimental::pmr::null_memory_resource;
+using std::experimental::pmr::memory_resource;
+
+void test01() {
+  memory_resource* r = null_memory_resource();
+  auto p = r->allocate(1);
+}
+
+int main() {
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/experimental/type_erased_allocator/2.cc b/libstdc++-v3/testsuite/experimental/type_erased_allocator/2.cc
new file mode 100644 (file)
index 0000000..014c357
--- /dev/null
@@ -0,0 +1,202 @@
+// { dg-options "-std=gnu++14" }
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <memory>
+#include <experimental/memory_resource>
+#include <experimental/utility>
+#include <bits/uses_allocator.h>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using std::experimental::pmr::polymorphic_allocator;
+using std::experimental::pmr::memory_resource;
+using std::experimental::pmr::new_delete_resource;
+using std::experimental::pmr::get_default_resource;
+using std::experimental::pmr::set_default_resource;
+using std::allocator_arg_t;
+
+enum CtorType { Default, Copy, Move, Other, Tuple, Piecewise_Default, Piecewise_Copy};
+
+// type that takes a memory_resource before other ctor args
+struct A
+{
+  using allocator_type = std::experimental::erased_type;
+
+  CtorType type;
+  memory_resource* alloc = nullptr;
+
+  A() : type(Default) { }
+  A(allocator_arg_t, memory_resource* a) : type(Default), alloc(a) { }
+  A(const A&) : type(Copy) { }
+  A(allocator_arg_t, memory_resource* a, const A&) : type(Copy), alloc(a) { }
+  A(A&&) : type (Move) { }
+  A(allocator_arg_t, memory_resource* a, A&&) : type (Move), alloc(a) { }
+  A(int) : type(Other) { }
+  A(allocator_arg_t, memory_resource* a, int) : type(Other), alloc(a) { }
+};
+
+// type that takes a memory_resource after other ctor args
+struct B
+{
+  using allocator_type = std::experimental::erased_type;
+
+  CtorType type;
+  memory_resource* alloc = nullptr;
+
+  B() : type(Default) { }
+  B(memory_resource* a) : type(Default), alloc(a) { }
+  B(const B&) : type(Copy) { }
+  B(const B&, memory_resource* a) : type(Copy), alloc(a) { }
+  B(B&&) : type (Move) { }
+  B(B&&, memory_resource* a) : type(Move), alloc(a) { }
+  B(int) : type(Other) { }
+  B(int, memory_resource* a) : type(Other), alloc(a) { }
+};
+
+// type that takes no memory_resource
+struct C
+{
+  CtorType type;
+  C() : type(Default) { }
+  C(const C&) : type(Copy) { }
+  C(C&&) : type(Move) { }
+  C(int) : type(Other) { }
+};
+
+// test construct for type that
+// uses memory_resource* as allocator
+template<typename A>
+void test_uses_alloc() {
+  polymorphic_allocator<A> pa;
+  A* p = pa.allocate(1);
+  A a;
+
+  pa.construct(p);
+  VERIFY(p->alloc == get_default_resource());
+  VERIFY(p->type == Default);
+  pa.destroy(p);
+
+  pa.construct(p, a);
+  VERIFY(p->type == Copy);
+  pa.destroy(p);
+
+  pa.construct(p, A());
+  VERIFY(p->type == Move);
+  pa.destroy(p);
+
+  pa.construct(p, 1);
+  VERIFY(p->type == Other);
+  pa.destroy(p);
+
+  pa.deallocate(p, 1);
+}
+
+// test construct for type that not using allocator
+template <typename C>
+void test_non_alloc() {
+  polymorphic_allocator<C> pa;
+  C* p = pa.allocate(1);
+  C b;
+
+  pa.construct(p);
+  VERIFY(p->type == Default);
+  pa.destroy(p);
+
+  pa.construct(p, b);
+  VERIFY(p->type == Copy);
+  pa.destroy(p);
+
+  pa.construct(p, C());
+  VERIFY(p->type == Move);
+  pa.destroy(p);
+
+  pa.construct(p, 1);
+  VERIFY(p->type == Other);
+  pa.destroy(p);
+
+  pa.deallocate(p, 1);
+}
+
+// test piecewise_construct
+template <typename A, typename B>
+void test_pair() {
+  polymorphic_allocator<std::pair<A, B>> pa;
+  std::pair<A, B>* p = pa.allocate(1);
+  std::tuple<> t;
+
+  // construct(pair<T1, T2>* p, piecewise_construct_t, tuple<...>, tuple<...>)
+  pa.construct(p, std::piecewise_construct, t, t);
+  VERIFY(p->first.type == Default);
+  VERIFY(p->second.type == Default);
+  pa.destroy(p);
+
+  // construct(pair<T1, T2>* __p)
+  pa.construct(p);
+  VERIFY(p->first.type == Default);
+  VERIFY(p->second.type == Default);
+  pa.destroy(p);
+
+  // construct(pair<T1, T2>* p, U&& x, V&& y)
+  A a; B b;
+  pa.construct(p, a, b);
+  VERIFY(p->first.type == Copy);
+  VERIFY(p->second.type == Copy);
+  pa.destroy(p);
+
+  pa.construct(p, A(), B());
+  VERIFY(p->first.type == Move);
+  VERIFY(p->second.type == Move);
+  auto pp = *p;
+  pa.destroy(p);
+
+  // construct(pair<T1, T2>* p, const pair<U, V>& x)
+  pa.construct(p, pp);
+  VERIFY(p->first.type == Copy);
+  VERIFY(p->second.type == Copy);
+  pa.destroy(p);
+
+  // construct(pair<T1, T2>* p, pair<U, V>&& x)
+  pa.construct(p, std::move(pp));
+  VERIFY(p->first.type == Move);
+  VERIFY(p->second.type == Move);
+  pa.destroy(p);
+  pa.deallocate(p, 1);
+}
+
+void test01() {
+  test_uses_alloc<A>();
+  test_uses_alloc<B>();
+  test_non_alloc<C>();
+}
+
+void test02() {
+  test_pair<A, A>();
+  test_pair<A, B>();
+  test_pair<A, C>();
+  test_pair<B, B>();
+  test_pair<B, A>();
+  test_pair<B, C>();
+  test_pair<C, C>();
+}
+
+
+int main() {
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/experimental/type_erased_allocator/uses_allocator.cc b/libstdc++-v3/testsuite/experimental/type_erased_allocator/uses_allocator.cc
new file mode 100644 (file)
index 0000000..fc8acf1
--- /dev/null
@@ -0,0 +1,22 @@
+#include <bits/uses_allocator.h>
+#include <vector>
+#include <experimental/utility>
+#include <memory>
+
+using std::vector;
+using std::allocator;
+using std::uses_allocator;
+
+struct A {
+  using allocator_type = std::experimental::erased_type;
+};
+
+void test01() {
+    static_assert(uses_allocator<vector<int>, allocator<int>>());
+    static_assert(uses_allocator<A, allocator<A>>());
+}
+
+int main() {
+  test01();
+  return 0;
+}