This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] libstdc++/70940 Start fixing polymorphic memory resources


This fixes the first errors noted in the PR, so that resource_adaptor
doesn't rely on anything that isn't guaranteed by the Allocator
requirements, and __null_memory_resource::do_is_equal doesn't have a
missing return.

More work is needed to solve the alignment bugs, which I'll work on
soon.

Tested x86_64-linux, committed to trunk.

I'll backport these fixes to gcc-6 as well once they're complete.


commit 0b7946fb5b97b6c0beffb1326e3e455a12b8b99f
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed May 4 12:23:15 2016 +0100

    libstdc++/70940 Start fixing polymorphic memory resources
    
    	PR libstdc++/70940
    	* include/experimental/memory_resource
    	(__resource_adaptor_imp::do_allocate): Do not default-construct
    	rebound allocator.
    	(__resource_adaptor_imp::do_deallocate): Likewise. Use
    	allocator_traits to get pointer type.
    	(__null_memory_resource::do_allocate): Remove unused parameters.
    	(__null_memory_resource::do_deallocate): Likewise.
    	(__null_memory_resource::do_is_equal): Likewise. Add return statement.
    	* testsuite/experimental/type_erased_allocator/1.cc: Combine with ...
    	* testsuite/experimental/type_erased_allocator/1_neg.cc: This, and
    	move to ...
    	* testsuite/experimental/memory_resource/1.cc: Here.
    	* testsuite/experimental/memory_resource/null_memory_resource.cc: New.
    	* testsuite/experimental/memory_resource/resource_adaptor.cc: New.

diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource
index ccdf5e6..ea8afb8 100644
--- a/libstdc++-v3/include/experimental/memory_resource
+++ b/libstdc++-v3/include/experimental/memory_resource
@@ -282,7 +282,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	size_t __new_size = _S_aligned_size(__bytes,
 					    _S_supported(__alignment) ?
 					    __alignment : _S_max_align);
-	return _Aligned_alloc().allocate(__new_size);
+	return _Aligned_alloc(_M_alloc).allocate(__new_size);
       }
 
       virtual void
@@ -292,9 +292,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	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);
+	using _Ptr = typename allocator_traits<_Aligned_alloc>::pointer;
+	_Aligned_alloc(_M_alloc).deallocate(static_cast<_Ptr>(__p),
+					    __new_size);
       }
 
       virtual bool
@@ -306,8 +306,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     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.
+      // Returns a size that is larger than or equal to __size and divisible
+      // 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; }
@@ -342,16 +342,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
     protected:
       void*
-      do_allocate(size_t __bytes, size_t __alignment)
+      do_allocate(size_t, size_t)
       { std::__throw_bad_alloc(); }
 
       void
-      do_deallocate(void* __p, size_t __bytes, size_t __alignment)
+      do_deallocate(void*, size_t, size_t) noexcept
       { }
 
       bool
       do_is_equal(const memory_resource& __other) const noexcept
-      { }
+      { return this == &__other; }
 
       friend memory_resource* null_memory_resource() noexcept;
     };
diff --git a/libstdc++-v3/testsuite/experimental/memory_resource/1.cc b/libstdc++-v3/testsuite/experimental/memory_resource/1.cc
new file mode 100644
index 0000000..38cbd27
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/memory_resource/1.cc
@@ -0,0 +1,161 @@
+// { dg-options "-std=gnu++14" }
+
+// Copyright (C) 2015-2016 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 <vector>
+#include <cstdlib>
+#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;
+    std::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()
+{
+  bool test __attribute((unused)) = false;
+
+  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()
+{
+  bool test __attribute((unused)) = false;
+
+  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()
+{
+  bool test __attribute((unused)) = false;
+
+  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()
+{
+  bool test __attribute((unused)) = false;
+
+  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();
+}
diff --git a/libstdc++-v3/testsuite/experimental/memory_resource/null_memory_resource.cc b/libstdc++-v3/testsuite/experimental/memory_resource/null_memory_resource.cc
new file mode 100644
index 0000000..c84436a
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/memory_resource/null_memory_resource.cc
@@ -0,0 +1,52 @@
+// { dg-options "-std=gnu++14" }
+
+// Copyright (C) 2016 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 <testsuite_hooks.h>
+
+using std::experimental::pmr::memory_resource;
+using std::experimental::pmr::null_memory_resource;
+using std::experimental::pmr::new_delete_resource;
+
+// null_memory_resource
+void
+test06()
+{
+  bool test __attribute((unused)) = false;
+
+  memory_resource* r = null_memory_resource();
+  bool caught = false;
+
+  void* p = nullptr;
+  try {
+    p = r->allocate(1);
+  } catch (const std::bad_alloc&) {
+    caught = true;
+  }
+  VERIFY( caught );
+
+  VERIFY( *r == *r );
+  VERIFY( r->is_equal(*r) );
+  VERIFY( !r->is_equal(*new_delete_resource()) );
+}
+
+int main()
+{
+  test06();
+}
diff --git a/libstdc++-v3/testsuite/experimental/memory_resource/resource_adaptor.cc b/libstdc++-v3/testsuite/experimental/memory_resource/resource_adaptor.cc
new file mode 100644
index 0000000..299bb72
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/memory_resource/resource_adaptor.cc
@@ -0,0 +1,87 @@
+// { dg-options "-std=gnu++14" }
+
+// Copyright (C) 2016 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 <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using std::experimental::pmr::memory_resource;
+using std::experimental::pmr::resource_adaptor;
+
+template<typename T>
+  struct Allocator : __gnu_test::SimpleAllocator<T>
+  {
+    Allocator(int) { } // not default constructible
+
+    template<typename U>
+      Allocator(const Allocator<U>&) { }
+  };
+
+template<typename T>
+  bool aligned(void* p)
+  {
+    return (reinterpret_cast<std::uintptr_t>(p) % alignof(T)) == 0;
+  }
+
+// resource_adaptor
+void
+test05()
+{
+  bool test __attribute((unused)) = false;
+  using std::max_align_t;
+  using std::uintptr_t;
+  void* p = nullptr;
+
+  Allocator<int> a1(1), a2(2); // minimal interface allocators
+  resource_adaptor<decltype(a1)> r1(a1), r2(a2);
+  VERIFY( r1 == r1 );
+  VERIFY( r1 == r2 );
+  p = r1.allocate(1);
+  VERIFY( aligned<max_align_t>(p) );
+  r1.deallocate(p, 1);
+  p = r1.allocate(1, alignof(short));
+  VERIFY( aligned<short>(p) );
+  r1.deallocate(p, 1, alignof(short));
+  p = r1.allocate(1, alignof(long));
+  VERIFY( aligned<long>(p) );
+  r1.deallocate(p, 1, alignof(long));
+
+  __gnu_test::uneq_allocator<double> a3(3), a4(4); // non-equal allocators
+  resource_adaptor<decltype(a3)> r3(a3), r4(a4);
+  VERIFY( r3 == r3 );
+  VERIFY( r4 == r4 );
+  VERIFY( r3 != r4 );
+  p = r3.allocate(1);
+  VERIFY( aligned<max_align_t>(p) );
+  r3.deallocate(p, 1);
+  p = r3.allocate(1, alignof(short));
+  VERIFY( aligned<short>(p) );
+  r3.deallocate(p, 1, alignof(short));
+  p = r3.allocate(1, alignof(long));
+  VERIFY( aligned<long>(p) );
+  r3.deallocate(p, 1, alignof(long));
+
+  // TODO test with an allocator that doesn't use new or malloc, so
+  // returns pointers that are not suitably aligned for any type.
+}
+
+int main()
+{
+  test05();
+}
diff --git a/libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc b/libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc
deleted file mode 100644
index 924d728..0000000
--- a/libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// { dg-options "-std=gnu++14" }
-
-// Copyright (C) 2015-2016 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 <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
deleted file mode 100644
index ce45dbf..0000000
--- a/libstdc++-v3/testsuite/experimental/type_erased_allocator/1_neg.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// { dg-do run { xfail *-*-* } }
-// { dg-options "-std=gnu++14" }
-
-// Copyright (C) 2015-2016 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 <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();
-}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]