* [PATCH] Add initial version of C++17 <memory_resource> header
@ 2018-07-24 21:12 Jonathan Wakely
2018-07-25 11:01 ` Jonathan Wakely
0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Wakely @ 2018-07-24 21:12 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2388 bytes --]
This is missing the synchronized_pool_resource and
unsynchronized_pool_resource classes but is otherwise complete.
This is a new implementation, not based on the existing code in
<experimental/memory_resource>, but memory_resource and
polymorphic_allocator ended up looking almost the same anyway.
The constant_init kluge in src/c++17/memory_resource.cc is apparently
due to Richard Smith and ensures that the objects are constructed during
constant initialiation phase and not destroyed (because the
constant_init destructor doesn't destroy the union member and the
storage is not reused).
* config/abi/pre/gnu.ver: Export new symbols.
* configure: Regenerate.
* include/Makefile.am: Add new <memory_resource> header.
* include/Makefile.in: Regenerate.
* include/precompiled/stdc++.h: Include <memory_resource> for C++17.
* include/std/memory_resource: New header.
(memory_resource, polymorphic_allocator, new_delete_resource)
(null_memory_resource, set_default_resource, get_default_resource)
(pool_options, monotonic_buffer_resource): Define.
* src/Makefile.am: Add c++17 directory.
* src/Makefile.in: Regenerate.
* src/c++11/Makefile.am: Fix comment.
* src/c++17/Makefile.am: Add makefile for new sub-directory.
* src/c++17/Makefile.in: Generate.
* src/c++17/memory_resource.cc: New.
(newdel_res_t, null_res_t, constant_init, newdel_res, null_res)
(default_res, new_delete_resource, null_memory_resource)
(set_default_resource, get_default_resource): Define.
* testsuite/20_util/memory_resource/1.cc: New test.
* testsuite/20_util/memory_resource/2.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/1.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/allocate.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/deallocate.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/release.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/upstream_resource.cc:
New test.
* testsuite/20_util/polymorphic_allocator/1.cc: New test.
* testsuite/20_util/polymorphic_allocator/resource.cc: New test.
* testsuite/20_util/polymorphic_allocator/select.cc: New test.
* testsuite/util/testsuite_allocator.h (__gnu_test::memory_resource):
Define concrete memory resource for testing.
(__gnu_test::default_resource_mgr): Define RAII helper for changing
default resource.
Tested powerpc64le-linux, committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 67217 bytes --]
commit 05c7ae80dbd59fcef5d583eac15181afbc07a116
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue Jul 24 14:19:19 2018 +0100
Add initial version of C++17 <memory_resource> header
This is missing the synchronized_pool_resource and
unsynchronized_pool_resource classes but is otherwise complete.
This is a new implementation, not based on the existing code in
<experimental/memory_resource>, but memory_resource and
polymorphic_allocator ended up looking almost the same anyway.
The constant_init kluge in src/c++17/memory_resource.cc is apparently
due to Richard Smith and ensures that the objects are constructed during
constant initialiation phase and not destroyed (because the
constant_init destructor doesn't destroy the union member and the
storage is not reused).
* config/abi/pre/gnu.ver: Export new symbols.
* configure: Regenerate.
* include/Makefile.am: Add new <memory_resource> header.
* include/Makefile.in: Regenerate.
* include/precompiled/stdc++.h: Include <memory_resource> for C++17.
* include/std/memory_resource: New header.
(memory_resource, polymorphic_allocator, new_delete_resource)
(null_memory_resource, set_default_resource, get_default_resource)
(pool_options, monotonic_buffer_resource): Define.
* src/Makefile.am: Add c++17 directory.
* src/Makefile.in: Regenerate.
* src/c++11/Makefile.am: Fix comment.
* src/c++17/Makefile.am: Add makefile for new sub-directory.
* src/c++17/Makefile.in: Generate.
* src/c++17/memory_resource.cc: New.
(newdel_res_t, null_res_t, constant_init, newdel_res, null_res)
(default_res, new_delete_resource, null_memory_resource)
(set_default_resource, get_default_resource): Define.
* testsuite/20_util/memory_resource/1.cc: New test.
* testsuite/20_util/memory_resource/2.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/1.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/allocate.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/deallocate.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/release.cc: New test.
* testsuite/20_util/monotonic_buffer_resource/upstream_resource.cc:
New test.
* testsuite/20_util/polymorphic_allocator/1.cc: New test.
* testsuite/20_util/polymorphic_allocator/resource.cc: New test.
* testsuite/20_util/polymorphic_allocator/select.cc: New test.
* testsuite/util/testsuite_allocator.h (__gnu_test::memory_resource):
Define concrete memory resource for testing.
(__gnu_test::default_resource_mgr): Define RAII helper for changing
default resource.
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index b09bdef6d09..36459e88b6a 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -2039,6 +2039,11 @@ GLIBCXX_3.4.26 {
_ZNSt7__cxx1118basic_stringstreamI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]Ev;
_ZNSt7__cxx1119basic_[io]stringstreamI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]Ev;
+ _ZNSt3pmr19new_delete_resourceEv;
+ _ZNSt3pmr20null_memory_resourceEv;
+ _ZNSt3pmr20get_default_resourceEv;
+ _ZNSt3pmr20set_default_resourceEPNS_15memory_resourceE;
+
} GLIBCXX_3.4.25;
# Symbols in the support library (libsupc++) have their own tag.
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index d1453a5abce..9daa8856e70 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -54,6 +54,7 @@ std_headers = \
${std_srcdir}/locale \
${std_srcdir}/map \
${std_srcdir}/memory \
+ ${std_srcdir}/memory_resource \
${std_srcdir}/mutex \
${std_srcdir}/numeric \
${std_srcdir}/optional \
diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h
index 80769233eb3..1f537354052 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -128,7 +128,7 @@
// #include <execution>
#include <filesystem>
#include <optional>
-// #include <memory_resource>
+#include <memory_resource>
#include <string_view>
#include <variant>
#endif
diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource
new file mode 100644
index 00000000000..b3f8f7d9477
--- /dev/null
+++ b/libstdc++-v3/include/std/memory_resource
@@ -0,0 +1,510 @@
+// <memory_resource> -*- C++ -*-
+
+// Copyright (C) 2018 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 include/memory_resource
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_MEMORY_RESOURCE
+#define _GLIBCXX_MEMORY_RESOURCE 1
+
+#pragma GCC system_header
+
+#if __cplusplus >= 201703L
+
+#include <bit> // __ceil2, __log2p1
+#include <memory> // align, allocator_arg_t, __uses_alloc
+#include <utility> // pair, index_sequence
+#include <cstddef> // size_t, max_align_t
+#include <debug/assertions.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace pmr
+{
+// #define __cpp_lib_memory_resource 201603
+
+ class memory_resource;
+
+ template<typename _Tp>
+ class polymorphic_allocator;
+
+ // Global memory resources
+ memory_resource* new_delete_resource() noexcept;
+ memory_resource* null_memory_resource() noexcept;
+ memory_resource* set_default_resource(memory_resource* __r) noexcept;
+ memory_resource* get_default_resource() noexcept
+ __attribute__((__returns_nonnull__));
+
+ // Pool resource classes
+ struct pool_options;
+ class synchronized_pool_resource;
+ class unsynchronized_pool_resource;
+ class monotonic_buffer_resource;
+
+ /// Class memory_resource
+ class memory_resource
+ {
+ static constexpr size_t _S_max_align = alignof(max_align_t);
+
+ public:
+ memory_resource() = default;
+ memory_resource(const memory_resource&) = default;
+ virtual ~memory_resource() = default;
+
+ memory_resource& operator=(const memory_resource&) = default;
+
+ [[nodiscard]]
+ void*
+ allocate(size_t __bytes, size_t __alignment = _S_max_align)
+ __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3)))
+ { return do_allocate(__bytes, __alignment); }
+
+ void
+ deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
+ __attribute__((__nonnull__))
+ { return do_deallocate(__p, __bytes, __alignment); }
+
+ bool
+ is_equal(const memory_resource& __other) const noexcept
+ { return do_is_equal(__other); }
+
+ private:
+ 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); }
+
+
+ // C++17 23.12.3 Class template polymorphic_allocator
+ template<typename _Tp>
+ class polymorphic_allocator
+ {
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2975. Missing case for pair construction in polymorphic allocators
+ template<typename _Up>
+ struct __not_pair { using type = void; };
+
+ template<typename _Up1, typename _Up2>
+ struct __not_pair<pair<_Up1, _Up2>> { };
+
+ public:
+ using value_type = _Tp;
+
+ polymorphic_allocator() noexcept
+ : _M_resource(get_default_resource())
+ { }
+
+ polymorphic_allocator(memory_resource* __r) noexcept
+ __attribute__((__nonnull__))
+ : _M_resource(__r)
+ { _GLIBCXX_DEBUG_ASSERT(__r); }
+
+ polymorphic_allocator(const polymorphic_allocator& __other) = default;
+
+ template<typename _Up>
+ polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept
+ : _M_resource(__x.resource())
+ { }
+
+ polymorphic_allocator&
+ operator=(const polymorphic_allocator&) = delete;
+
+ [[nodiscard]]
+ _Tp*
+ allocate(size_t __n)
+ __attribute__((__returns_nonnull__))
+ {
+ if (__n > (numeric_limits<size_t>::max() / sizeof(_Tp)))
+ std::__throw_bad_alloc();
+ return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
+ alignof(_Tp)));
+ }
+
+ void
+ deallocate(_Tp* __p, size_t __n) noexcept
+ __attribute__((__nonnull__))
+ { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
+
+ template<typename _Tp1, typename... _Args>
+ __attribute__((__nonnull__))
+ typename __not_pair<_Tp>::type
+ construct(_Tp1* __p, _Args&&... __args)
+ {
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2969. polymorphic_allocator::construct() shouldn't pass resource()
+ auto __use_tag
+ = __use_alloc<_Tp1, polymorphic_allocator, _Args...>(*this);
+ _S_construct(__use_tag, __p, std::forward<_Args>(__args)...);
+ }
+
+ template<typename _Tp1, typename _Tp2,
+ typename... _Args1, typename... _Args2>
+ __attribute__((__nonnull__))
+ void
+ construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
+ tuple<_Args1...> __x, tuple<_Args2...> __y)
+ {
+ auto __x_tag =
+ __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
+ auto __y_tag =
+ __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this);
+ index_sequence_for<_Args1...> __x_i;
+ index_sequence_for<_Args2...> __y_i;
+
+ ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct,
+ _S_construct_p(__x_tag, __x, __x_i),
+ _S_construct_p(__y_tag, __y, __y_i));
+ }
+
+ template<typename _Tp1, typename _Tp2>
+ __attribute__((__nonnull__))
+ void
+ construct(pair<_Tp1, _Tp2>* __p)
+ { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
+
+ template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
+ __attribute__((__nonnull__))
+ 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>
+ __attribute__((__nonnull__))
+ 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>
+ __attribute__((__nonnull__))
+ 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>
+ __attribute__((__nonnull__))
+ void
+ destroy(_Up* __p)
+ { __p->~_Up(); }
+
+ polymorphic_allocator
+ select_on_container_copy_construction() const noexcept
+ { return polymorphic_allocator(); }
+
+ memory_resource*
+ resource() const noexcept
+ __attribute__((__returns_nonnull__))
+ { return _M_resource; }
+
+ private:
+ using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
+ using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
+
+ template<typename _Tp1, typename... _Args>
+ static void
+ _S_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args)
+ { ::new(__p) _Tp1(std::forward<_Args>(__args)...); }
+
+ template<typename _Tp1, typename... _Args>
+ static void
+ _S_construct(__uses_alloc1_ __ua, _Tp1* __p, _Args&&... __args)
+ {
+ ::new(__p) _Tp1(allocator_arg, *__ua._M_a,
+ std::forward<_Args>(__args)...);
+ }
+
+ template<typename _Tp1, typename... _Args>
+ static void
+ _S_construct(__uses_alloc2_ __ua, _Tp1* __p, _Args&&... __args)
+ { ::new(__p) _Tp1(std::forward<_Args>(__args)..., *__ua._M_a); }
+
+ template<typename _Ind, typename... _Args>
+ static tuple<_Args&&...>
+ _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
+ { return std::move(__t); }
+
+ template<size_t... _Ind, typename... _Args>
+ static tuple<allocator_arg_t, polymorphic_allocator&, _Args&&...>
+ _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
+ tuple<_Args...>& __t)
+ {
+ return {
+ allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))...
+ };
+ }
+
+ template<size_t... _Ind, typename... _Args>
+ static tuple<_Args&&..., polymorphic_allocator&>
+ _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>,
+ tuple<_Args...>& __t)
+ { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; }
+
+ memory_resource* _M_resource;
+ };
+
+ template<typename _Tp1, typename _Tp2>
+ inline bool
+ operator==(const polymorphic_allocator<_Tp1>& __a,
+ const polymorphic_allocator<_Tp2>& __b) noexcept
+ { return *__a.resource() == *__b.resource(); }
+
+ template<typename _Tp1, typename _Tp2>
+ inline bool
+ operator!=(const polymorphic_allocator<_Tp1>& __a,
+ const polymorphic_allocator<_Tp2>& __b) noexcept
+ { return !(__a == __b); }
+
+
+ struct pool_options
+ {
+ size_t max_blocks_per_chunk = 0;
+ size_t largest_required_pool_block = 0;
+ };
+
+ // TODO class synchronized_pool_resource;
+ // TODO class unsynchronized_pool_resource;
+
+ class monotonic_buffer_resource : public memory_resource
+ {
+ public:
+ explicit
+ monotonic_buffer_resource(memory_resource* __upstream) noexcept
+ __attribute__((__nonnull__))
+ : _M_upstream(__upstream)
+ { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); }
+
+ monotonic_buffer_resource(size_t __initial_size,
+ memory_resource* __upstream) noexcept
+ __attribute__((__nonnull__))
+ : _M_next_bufsiz(__initial_size),
+ _M_upstream(__upstream)
+ {
+ _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
+ _GLIBCXX_DEBUG_ASSERT(__initial_size > 0);
+ }
+
+ monotonic_buffer_resource(void* __buffer, size_t __buffer_size,
+ memory_resource* __upstream) noexcept
+ __attribute__((__nonnull__(4)))
+ : _M_current_buf(__buffer), _M_avail(__buffer_size),
+ _M_next_bufsiz(_S_next_bufsize(__buffer_size)),
+ _M_upstream(__upstream),
+ _M_orig_buf(__buffer), _M_orig_size(__buffer_size)
+ {
+ _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
+ _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0);
+ }
+
+ monotonic_buffer_resource() noexcept
+ : monotonic_buffer_resource(get_default_resource())
+ { }
+
+ explicit
+ monotonic_buffer_resource(size_t __initial_size) noexcept
+ : monotonic_buffer_resource(__initial_size, get_default_resource())
+ { }
+
+ monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept
+ : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource())
+ { }
+
+ monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
+
+ virtual ~monotonic_buffer_resource() { release(); }
+
+ monotonic_buffer_resource&
+ operator=(const monotonic_buffer_resource&) = delete;
+
+ void
+ release() noexcept
+ {
+ _Chunk::release(_M_head, _M_upstream);
+
+ // reset to initial state at contruction:
+ if ((_M_current_buf = _M_orig_buf))
+ {
+ _M_avail = _M_orig_size;
+ _M_next_bufsiz = _S_next_bufsize(_M_orig_size);
+ }
+ else
+ {
+ _M_avail = 0;
+ _M_next_bufsiz = _M_orig_size;
+ }
+ }
+
+ memory_resource*
+ upstream_resource() const noexcept
+ __attribute__((__returns_nonnull__))
+ { return _M_upstream; }
+
+ protected:
+ void*
+ do_allocate(size_t __bytes, size_t __alignment) override
+ {
+ if (__bytes == 0)
+ __bytes = 1; // Ensures we don't return the same pointer twice.
+
+ if (auto __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail))
+ {
+ _M_current_buf = (char*)_M_current_buf + __bytes;
+ _M_avail -= __bytes;
+ return __p;
+ }
+
+ const size_t __n = std::max(__bytes, _M_next_bufsiz);
+ const size_t __m = std::max(__alignment, alignof(std::max_align_t));
+ auto [__p, __size] = _Chunk::allocate(_M_upstream, __n, __m, _M_head);
+ _M_current_buf = (char*)__p + __bytes;
+ _M_avail = __size - __bytes;
+ _M_next_bufsiz *= _S_growth_factor;
+ return __p;
+ }
+
+ void
+ do_deallocate(void*, size_t, size_t) override
+ { }
+
+ bool
+ do_is_equal(const memory_resource& __other) const noexcept override
+ { return this == &__other; }
+
+ private:
+ static size_t
+ _S_next_bufsize(size_t __buffer_size) noexcept
+ {
+ if (__buffer_size == 0)
+ __buffer_size = 1;
+ return __buffer_size * _S_growth_factor;
+ }
+
+ static constexpr size_t _S_init_bufsize = 128 * sizeof(void*);
+ static constexpr float _S_growth_factor = 1.5;
+
+ void* _M_current_buf = nullptr;
+ size_t _M_avail = 0;
+ size_t _M_next_bufsiz = _S_init_bufsize;
+
+ // Initial values set at construction and reused by release():
+ memory_resource* const _M_upstream;
+ void* const _M_orig_buf = nullptr;
+ size_t const _M_orig_size = _M_next_bufsiz;
+
+ // Memory allocated by the upstream resource is managed in a linked list
+ // of _Chunk objects. A _Chunk object recording the size and alignment of
+ // the allocated block and a pointer to the previous chunk is placed
+ // at end of the block.
+ class _Chunk
+ {
+ public:
+ // Return the address and size of a block of memory allocated from __r,
+ // of at least __size bytes and aligned to __align.
+ // Add a new _Chunk to the front of the linked list at __head.
+ static pair<void*, size_t>
+ allocate(memory_resource* __r, size_t __size, size_t __align,
+ _Chunk*& __head)
+ {
+ __size = std::__ceil2(__size + sizeof(_Chunk));
+ void* __p = __r->allocate(__size, __align);
+ // Add a chunk defined by (__p, __size, __align) to linked list __head.
+ void* const __back = (char*)__p + __size - sizeof(_Chunk);
+ __head = ::new(__back) _Chunk(__size, __align, __head);
+ return { __p, __size - sizeof(_Chunk) };
+ }
+
+ // Return every chunk in linked list __head to resource __r.
+ static void
+ release(_Chunk*& __head, memory_resource* __r) noexcept
+ {
+ _Chunk* __next = __head;
+ __head = nullptr;
+ while (__next)
+ {
+ _Chunk* __ch = __next;
+ __builtin_memcpy(&__next, __ch->_M_next, sizeof(_Chunk*));
+
+ __glibcxx_assert(__ch->_M_canary != 0);
+ __glibcxx_assert(__ch->_M_canary == (__ch->_M_size|__ch->_M_align));
+
+ if (__ch->_M_canary != (__ch->_M_size | __ch->_M_align))
+ return; // buffer overflow detected!
+
+ size_t __size = (1u << __ch->_M_size);
+ size_t __align = (1u << __ch->_M_align);
+ void* __start = (char*)(__ch + 1) - __size;
+ __r->deallocate(__start, __size, __align);
+ }
+ }
+
+ private:
+ _Chunk(size_t __size, size_t __align, _Chunk* __next) noexcept
+ : _M_size(std::__log2p1(__size) - 1),
+ _M_align(std::__log2p1(__align) - 1)
+ {
+ __builtin_memcpy(_M_next, &__next, sizeof(__next));
+ _M_canary = _M_size | _M_align;
+ }
+
+ unsigned char _M_canary;
+ unsigned char _M_size;
+ unsigned char _M_align;
+ unsigned char _M_next[sizeof(_Chunk*)];
+ };
+ static_assert(alignof(_Chunk) == 1);
+
+ _Chunk* _M_head = nullptr;
+ };
+
+} // namespace pmr
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+#endif // _GLIBCXX_MEMORY_RESOURCE
diff --git a/libstdc++-v3/src/Makefile.am b/libstdc++-v3/src/Makefile.am
index ba30dde8fec..09edcdbc471 100644
--- a/libstdc++-v3/src/Makefile.am
+++ b/libstdc++-v3/src/Makefile.am
@@ -28,7 +28,7 @@ else
filesystem_dir =
endif
-SUBDIRS = c++98 c++11 $(filesystem_dir)
+SUBDIRS = c++98 c++11 c++17 $(filesystem_dir)
# Cross compiler support.
if VTV_CYGMIN
@@ -58,6 +58,7 @@ endif
vpath % $(top_srcdir)/src/c++98
vpath % $(top_srcdir)/src/c++11
+vpath % $(top_srcdir)/src/c++17
if ENABLE_FILESYSTEM_TS
vpath % $(top_srcdir)/src/filesystem
endif
@@ -92,13 +93,15 @@ libstdc___la_LIBADD = \
$(GLIBCXX_LIBS) \
$(top_builddir)/libsupc++/libsupc++convenience.la \
$(top_builddir)/src/c++98/libc++98convenience.la \
- $(top_builddir)/src/c++11/libc++11convenience.la
+ $(top_builddir)/src/c++11/libc++11convenience.la \
+ $(top_builddir)/src/c++17/libc++17convenience.la
libstdc___la_DEPENDENCIES = \
${version_dep} \
$(top_builddir)/libsupc++/libsupc++convenience.la \
$(top_builddir)/src/c++98/libc++98convenience.la \
- $(top_builddir)/src/c++11/libc++11convenience.la
+ $(top_builddir)/src/c++11/libc++11convenience.la \
+ $(top_builddir)/src/c++17/libc++17convenience.la
libstdc___la_LDFLAGS = \
-version-info $(libtool_VERSION) ${version_arg} -lm
@@ -148,8 +151,8 @@ compatibility-condvar.o: compatibility-condvar.cc
# Thus, the shared libs have more compat symbols, which can be found
# segregated in the sources with -D_GLIBCXX_SHARED.
#
-# In the sub-directories of libsupc++, src/c++98, src/c++11, only
-# -prefer-pic objects are generated for the convenience libraries.
+# In the sub-directories of libsupc++, src/c++98, src/c++11, src/c++17,
+# only -prefer-pic objects are generated for the convenience libraries.
#
# In the main src directory, make shared and static objects just for
# the compat libraries. Shared objects are compiled with -prefer-pic
diff --git a/libstdc++-v3/src/c++11/Makefile.am b/libstdc++-v3/src/c++11/Makefile.am
index 91bf6f8d642..a22258782cb 100644
--- a/libstdc++-v3/src/c++11/Makefile.am
+++ b/libstdc++-v3/src/c++11/Makefile.am
@@ -1,4 +1,4 @@
-## Makefile for the C++03 sources of the GNU C++ Standard library.
+## Makefile for the C++11 sources of the GNU C++ Standard library.
##
## Copyright (C) 1997-2018 Free Software Foundation, Inc.
##
diff --git a/libstdc++-v3/src/c++17/Makefile.am b/libstdc++-v3/src/c++17/Makefile.am
new file mode 100644
index 00000000000..21b64b52dc2
--- /dev/null
+++ b/libstdc++-v3/src/c++17/Makefile.am
@@ -0,0 +1,111 @@
+## Makefile for the C++17 sources of the GNU C++ Standard library.
+##
+## Copyright (C) 1997-2018 Free Software Foundation, Inc.
+##
+## This file is part of the libstdc++ version 3 distribution.
+## Process this file with automake to produce Makefile.in.
+
+## 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 $(top_srcdir)/fragment.am
+
+# Convenience library for C++17 runtime.
+noinst_LTLIBRARIES = libc++17convenience.la
+
+headers =
+
+sources = \
+ memory_resource.cc
+
+if ENABLE_DUAL_ABI
+extra_string_inst_sources =
+else
+extra_string_inst_sources =
+endif
+
+if ENABLE_EXTERN_TEMPLATE
+# XTEMPLATE_FLAGS = -fno-implicit-templates
+inst_sources = \
+ $(extra_string_inst_sources)
+else
+# XTEMPLATE_FLAGS =
+inst_sources =
+endif
+
+vpath % $(top_srcdir)/src/c++17
+
+libc__17convenience_la_SOURCES = $(sources) $(inst_sources)
+
+# AM_CXXFLAGS needs to be in each subdirectory so that it can be
+# modified in a per-library or per-sub-library way. Need to manually
+# set this option because CONFIG_CXXFLAGS has to be after
+# OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden
+# as the occasion calls for it.
+AM_CXXFLAGS = \
+ -std=gnu++17 \
+ $(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
+ $(XTEMPLATE_FLAGS) $(VTV_CXXFLAGS) \
+ $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS)
+
+AM_MAKEFLAGS = \
+ "gxx_include_dir=$(gxx_include_dir)"
+
+# Libtool notes
+
+# 1) In general, libtool expects an argument such as `--tag=CXX' when
+# using the C++ compiler, because that will enable the settings
+# detected when C++ support was being configured. However, when no
+# such flag is given in the command line, libtool attempts to figure
+# it out by matching the compiler name in each configuration section
+# against a prefix of the command line. The problem is that, if the
+# compiler name and its initial flags stored in the libtool
+# configuration file don't match those in the command line, libtool
+# can't decide which configuration to use, and it gives up. The
+# correct solution is to add `--tag CXX' to LTCXXCOMPILE and maybe
+# CXXLINK, just after $(LIBTOOL), so that libtool doesn't have to
+# attempt to infer which configuration to use.
+#
+# The second tag argument, `--tag disable-shared` means that libtool
+# only compiles each source once, for static objects. In actuality,
+# glibcxx_lt_pic_flag and glibcxx_compiler_shared_flag are added to
+# the libtool command that is used create the object, which is
+# suitable for shared libraries. The `--tag disable-shared` must be
+# placed after --tag CXX lest things CXX undo the affect of
+# disable-shared.
+
+# 2) Need to explicitly set LTCXXCOMPILE so that EXTRA_CXX_FLAGS is
+# last. (That way, things like -O2 passed down from the toplevel can
+# be overridden by --enable-debug.)
+LTCXXCOMPILE = \
+ $(LIBTOOL) --tag CXX --tag disable-shared \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CXX) $(TOPLEVEL_INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(EXTRA_CXX_FLAGS)
+
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
+
+# 3) We'd have a problem when building the shared libstdc++ object if
+# the rules automake generates would be used. We cannot allow g++ to
+# be used since this would add -lstdc++ to the link line which of
+# course is problematic at this point. So, we get the top-level
+# directory to configure libstdc++-v3 to use gcc as the C++
+# compilation driver.
+CXXLINK = \
+ $(LIBTOOL) --tag CXX --tag disable-shared \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXX) \
+ $(VTV_CXXLINKFLAGS) \
+ $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
diff --git a/libstdc++-v3/src/c++17/Makefile.in b/libstdc++-v3/src/c++17/Makefile.in
new file mode 100644
index 00000000000..40b186e0a77
diff --git a/libstdc++-v3/src/c++17/memory_resource.cc b/libstdc++-v3/src/c++17/memory_resource.cc
new file mode 100644
index 00000000000..dd418c1b1aa
--- /dev/null
+++ b/libstdc++-v3/src/c++17/memory_resource.cc
@@ -0,0 +1,111 @@
+// <memory_resource> implementation -*- C++ -*-
+
+// Copyright (C) 2018 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/>.
+
+#include <memory_resource>
+#include <atomic>
+#include <new>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace pmr
+{
+ namespace
+ {
+ class newdel_res_t final : public memory_resource
+ {
+ void*
+ do_allocate(size_t __bytes, size_t __alignment) override
+ { return ::operator new(__bytes, std::align_val_t(__alignment)); }
+
+ void
+ do_deallocate(void* __p, size_t __bytes, size_t __alignment) noexcept
+ override
+ { ::operator delete(__p, __bytes, std::align_val_t(__alignment)); }
+
+ bool
+ do_is_equal(const memory_resource& __other) const noexcept override
+ { return &__other == this; }
+ };
+
+ class null_res_t final : public memory_resource
+ {
+ void*
+ do_allocate(size_t, size_t) override
+ { std::__throw_bad_alloc(); }
+
+ void
+ do_deallocate(void*, size_t, size_t) noexcept override
+ { }
+
+ bool
+ do_is_equal(const memory_resource& __other) const noexcept override
+ { return &__other == this; }
+ };
+
+ template<typename T>
+ struct constant_init
+ {
+ union {
+ unsigned char unused;
+ T obj;
+ };
+ constexpr constant_init() : obj() { }
+
+ template<typename U>
+ explicit constexpr constant_init(U arg) : obj(arg) { }
+
+ ~constant_init() { /* do nothing, union member is not destroyed */ }
+ };
+
+ constant_init<newdel_res_t> newdel_res{};
+ constant_init<null_res_t> null_res{};
+ constant_init<atomic<memory_resource*>> default_res{&newdel_res.obj};
+ } // namespace
+
+ memory_resource*
+ new_delete_resource() noexcept
+ { return &newdel_res.obj; }
+
+ memory_resource*
+ null_memory_resource() noexcept
+ { return &null_res.obj; }
+
+ memory_resource*
+ set_default_resource(memory_resource* r) noexcept
+ {
+ if (r == nullptr)
+ r = new_delete_resource();
+ return default_res.obj.exchange(r);
+ }
+
+ memory_resource*
+ get_default_resource() noexcept
+ { return default_res.obj.load(); }
+
+} // namespace pmr
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+
diff --git a/libstdc++-v3/testsuite/20_util/memory_resource/1.cc b/libstdc++-v3/testsuite/20_util/memory_resource/1.cc
new file mode 100644
index 00000000000..d848374e71a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/memory_resource/1.cc
@@ -0,0 +1,47 @@
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2018 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_resource>
+
+static_assert(std::is_abstract_v<std::pmr::memory_resource>);
+static_assert(std::is_polymorphic_v<std::pmr::memory_resource>);
+static_assert(!std::is_final_v<std::pmr::memory_resource>);
+
+struct R0 : std::pmr::memory_resource { };
+static_assert(std::is_abstract_v<R0>);
+
+struct R1 : R0 {
+ void* do_allocate(std::size_t, std::size_t) override;
+};
+static_assert(std::is_abstract_v<R1>);
+
+struct R2 : R1 {
+ void do_deallocate(void*, std::size_t, std::size_t) override;
+};
+static_assert(std::is_abstract_v<R2>);
+
+struct R3 : R2 {
+ bool do_is_equal(const std::pmr::memory_resource&) const noexcept override;
+};
+static_assert(!std::is_abstract_v<R3>);
+static_assert(std::is_default_constructible_v<R3>);
+static_assert(std::is_copy_constructible_v<R3>);
+static_assert(std::is_copy_assignable_v<R3>);
+static_assert(std::is_destructible_v<R3>);
diff --git a/libstdc++-v3/testsuite/20_util/memory_resource/2.cc b/libstdc++-v3/testsuite/20_util/memory_resource/2.cc
new file mode 100644
index 00000000000..b99aa49fce1
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/memory_resource/2.cc
@@ -0,0 +1,112 @@
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+// { dg-skip-if "" { *-*-* } { -fno-aligned-new } }
+
+// Copyright (C) 2018 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_resource>
+#include <testsuite_allocator.h>
+
+struct R : std::pmr::memory_resource {
+ void* do_allocate(std::size_t, std::size_t) override;
+ void do_deallocate(void*, std::size_t, std::size_t) override;
+ bool do_is_equal(const std::pmr::memory_resource&) const noexcept override;
+};
+
+bool called = false;
+
+void* R::do_allocate(std::size_t bytes, std::size_t a)
+{
+ called = true;
+ return ::operator new(bytes, std::align_val_t(a));
+}
+
+void R::do_deallocate(void* p, std::size_t bytes, std::size_t a)
+{
+ called = true;
+ ::operator delete(p, bytes, std::align_val_t(a));
+}
+
+bool R::do_is_equal(const std::pmr::memory_resource& r) const noexcept
+{
+ called = true;
+ return this == &r;
+}
+
+void
+test01()
+{
+ R res;
+ called = false;
+ auto p = res.allocate(1, 1);
+ VERIFY( called );
+ called = false;
+ res.deallocate(p, 1, 1);
+ VERIFY( called );
+ called = false;
+ VERIFY( res == res );
+ VERIFY( !called );
+ VERIFY( ! (res != res) );
+ VERIFY( !called );
+
+ struct X { int i = 0; };
+ struct MultipleInheritance : X, R { };
+ MultipleInheritance m;
+ VERIFY( m == m );
+ VERIFY( !called );
+ VERIFY( ! (m != m) );
+ VERIFY( !called );
+ VERIFY( m.is_equal(m) );
+ VERIFY( called );
+ called = false;
+ VERIFY( ! (m == res) );
+ VERIFY( called );
+ called = false;
+ VERIFY( m != res );
+ VERIFY( called );
+ called = false;
+ VERIFY( ! (res == m) );
+ VERIFY( called );
+ called = false;
+ VERIFY( res != m );
+ VERIFY( called );
+ called = false;
+}
+
+void
+test02()
+{
+ __gnu_test::memory_resource r1, r2;
+ VERIFY( r1 == r1 );
+ VERIFY( ! (r1 != r1) );
+ VERIFY( r1.is_equal(r1) );
+ VERIFY( r2 == r2 );
+ VERIFY( r2.is_equal(r2) );
+ VERIFY( ! (r1 == r2) );
+ VERIFY( r1 != r2 );
+ VERIFY( ! r1.is_equal(r2) );
+ VERIFY( ! (r2 == r1) );
+ VERIFY( r2 != r1 );
+ VERIFY( ! r2.is_equal(r1) );
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/1.cc b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/1.cc
new file mode 100644
index 00000000000..77fa38edbd8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/1.cc
@@ -0,0 +1,53 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <memory_resource>
+
+using std::pmr::monotonic_buffer_resource;
+using std::pmr::memory_resource;
+using std::size_t;
+
+static_assert(std::is_base_of_v<memory_resource, monotonic_buffer_resource>);
+static_assert(!std::is_abstract_v<monotonic_buffer_resource>);
+
+static_assert(std::is_default_constructible_v<monotonic_buffer_resource>);
+static_assert(std::is_destructible_v<monotonic_buffer_resource>);
+static_assert(!std::is_copy_constructible_v<monotonic_buffer_resource>);
+static_assert(!std::is_copy_assignable_v<monotonic_buffer_resource>);
+static_assert(!std::is_move_constructible_v<monotonic_buffer_resource>);
+static_assert(!std::is_move_assignable_v<monotonic_buffer_resource>);
+
+static_assert(std::is_constructible_v<monotonic_buffer_resource,
+ memory_resource*>);
+static_assert(std::is_constructible_v<monotonic_buffer_resource,
+ size_t, memory_resource*>);
+static_assert(std::is_constructible_v<monotonic_buffer_resource,
+ void*, size_t, memory_resource*>);
+
+static_assert(std::is_constructible_v<monotonic_buffer_resource,
+ size_t>);
+static_assert(std::is_constructible_v<monotonic_buffer_resource,
+ void*, size_t>);
+
+// Unary constructors are explicit.
+static_assert(!std::is_convertible_v<memory_resource*,
+ monotonic_buffer_resource>);
+static_assert(!std::is_convertible_v<size_t,
+ monotonic_buffer_resource>);
diff --git a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/allocate.cc b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/allocate.cc
new file mode 100644
index 00000000000..d1c2715ef8d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/allocate.cc
@@ -0,0 +1,221 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <memory_resource>
+#include <testsuite_allocator.h>
+
+void
+test01()
+{
+ __gnu_test::memory_resource r;
+
+ // test that it's possible to allocate after each of the constructors
+ {
+ std::pmr::monotonic_buffer_resource mr(&r);
+ auto p = mr.allocate(1024);
+ VERIFY( p != nullptr );
+ auto q = mr.allocate(1024);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+ }
+ VERIFY( r.number_of_active_allocations() == 0 );
+ {
+ std::pmr::monotonic_buffer_resource mr(128, &r);
+ auto p = mr.allocate(1024);
+ VERIFY( p != nullptr );
+ auto q = mr.allocate(1024);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+ }
+ VERIFY( r.number_of_active_allocations() == 0 );
+ {
+ unsigned char buf[64];
+ std::pmr::monotonic_buffer_resource mr((void*)buf, sizeof(buf), &r);
+ auto p = mr.allocate(1024);
+ VERIFY( p != nullptr );
+ auto q = mr.allocate(1024);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+ }
+ VERIFY( r.number_of_active_allocations() == 0 );
+ {
+ std::pmr::monotonic_buffer_resource mr;
+ auto p = mr.allocate(1024);
+ VERIFY( p != nullptr );
+ auto q = mr.allocate(1024);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+ }
+ {
+ std::pmr::monotonic_buffer_resource mr(64);
+ auto p = mr.allocate(1024);
+ VERIFY( p != nullptr );
+ auto q = mr.allocate(1024);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+ }
+ {
+ unsigned char buf[64];
+ std::pmr::monotonic_buffer_resource mr((void*)buf, sizeof(buf));
+ auto p = mr.allocate(1024);
+ VERIFY( p != nullptr );
+ auto q = mr.allocate(1024);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+ }
+}
+
+void
+test02()
+{
+ unsigned char buf[64];
+ std::pmr::monotonic_buffer_resource mr(buf, sizeof(buf));
+
+ auto p = mr.allocate(0);
+ VERIFY( p != nullptr );
+ auto q = mr.allocate(0);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+
+ p = mr.allocate(0, 1);
+ VERIFY( p != nullptr );
+ q = mr.allocate(0, 1);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+}
+
+void
+test03()
+{
+#if __cpp_exceptions
+ {
+ std::pmr::monotonic_buffer_resource mr(std::pmr::null_memory_resource());
+ bool caught = false;
+ try
+ {
+ (void) mr.allocate(1, 1);
+ }
+ catch (const std::bad_alloc&)
+ {
+ caught = true;
+ }
+ VERIFY( caught );
+ }
+ {
+ unsigned char buf[16];
+ std::pmr::monotonic_buffer_resource mr(buf, sizeof(buf),
+ std::pmr::null_memory_resource());
+ (void) mr.allocate(16, 1);
+ bool caught = false;
+ try
+ {
+ (void) mr.allocate(1, 1);
+ }
+ catch (const std::bad_alloc&)
+ {
+ caught = true;
+ }
+ VERIFY( caught );
+ }
+#endif
+}
+
+void
+test04()
+{
+ auto buf = new unsigned char[512];
+ std::pmr::monotonic_buffer_resource mr(buf, 512,
+ std::pmr::null_memory_resource());
+ std::size_t prev_size = 1;
+ void* prev_ptr = mr.allocate(prev_size, 1);
+ for (int i = 0; i < 9; ++i)
+ {
+ std::size_t size = 1 << i;
+ void* ptr = mr.allocate(size, 1);
+ VERIFY( ((char*)ptr - (char*)prev_ptr) == prev_size );
+ prev_ptr = ptr;
+ prev_size = size;
+ }
+}
+
+void
+test05()
+{
+ // test that returned pointer is correctly aligned
+ auto is_aligned = [](void* p, size_t alignment) -> bool {
+ return (reinterpret_cast<std::uintptr_t>(p) % alignment) == 0;
+ };
+
+ auto buf = new unsigned char[2048];
+ std::pmr::monotonic_buffer_resource mr(buf+1, 2047);
+ for (int i = 0; i < 9; ++i)
+ {
+ auto p = mr.allocate(1, 1 << i);
+ VERIFY( is_aligned(p, 1 << i) );
+ // Make next available byte misaligned:
+ (void) mr.allocate(1 << i, 1);
+ }
+}
+
+void
+test06()
+{
+ // check for geometric progression in buffer sizes from upstream
+
+ struct resource : __gnu_test::memory_resource
+ {
+ bool allocated = false;
+ std::size_t last_size = 0;
+
+ void*
+ do_allocate(size_t bytes, size_t align) override
+ {
+ allocated = true;
+ last_size = bytes;
+ return __gnu_test::memory_resource::do_allocate(bytes, align);
+ }
+ };
+
+ resource r;
+ std::pmr::monotonic_buffer_resource mr(32, &r);
+ std::size_t last_size = 0;
+
+ for (int i = 0; i < 100; ++i)
+ {
+ (void) mr.allocate(16);
+ if (r.allocated)
+ {
+ VERIFY(r.last_size >= last_size);
+ last_size = r.last_size;
+ r.allocated = false;
+ }
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+}
diff --git a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/deallocate.cc b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/deallocate.cc
new file mode 100644
index 00000000000..427256d672a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/deallocate.cc
@@ -0,0 +1,103 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <memory_resource>
+#include <testsuite_allocator.h>
+
+struct resource : __gnu_test::memory_resource
+{
+ int allocate_calls = 0;
+ int deallocate_calls = 0;
+
+ void*
+ do_allocate(std::size_t bytes, std::size_t align) override
+ {
+ ++allocate_calls;
+ return __gnu_test::memory_resource::do_allocate(bytes, align);
+ }
+
+ void
+ do_deallocate(void* p, std::size_t bytes, std::size_t align) override
+ {
+ ++deallocate_calls;
+ __gnu_test::memory_resource::do_deallocate(p, bytes, align);
+ }
+};
+
+void
+test01()
+{
+ resource r;
+
+ // test that it's possible to deallocate after each of the constructors
+ {
+ std::pmr::monotonic_buffer_resource mr(&r);
+ auto p = mr.allocate(1024);
+ VERIFY( p != nullptr );
+ const std::uintptr_t pi = reinterpret_cast<std::uintptr_t>(p);
+ mr.deallocate(p, 1024);
+ VERIFY( r.deallocate_calls == 0 );
+ auto q = mr.allocate(1024);
+ VERIFY( q != nullptr );
+ VERIFY( pi != reinterpret_cast<std::uintptr_t>(q) );
+ mr.deallocate(q, 1024);
+ VERIFY( r.deallocate_calls == 0 );
+ }
+ VERIFY( r.deallocate_calls == r.allocate_calls );
+ VERIFY( r.number_of_active_allocations() == 0 );
+ {
+ r.deallocate_calls = r.allocate_calls = 0;
+ std::pmr::monotonic_buffer_resource mr(128, &r);
+ auto p = mr.allocate(64);
+ VERIFY( p != nullptr );
+ const std::uintptr_t pi = reinterpret_cast<std::uintptr_t>(p);
+ mr.deallocate(p, 64);
+ auto q = mr.allocate(1024);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+ VERIFY( pi != reinterpret_cast<std::uintptr_t>(q) );
+ mr.deallocate(q, 1024);
+ VERIFY( r.deallocate_calls == 0 );
+ }
+ VERIFY( r.number_of_active_allocations() == 0 );
+ {
+ r.deallocate_calls = r.allocate_calls = 0;
+ unsigned char buf[64];
+ std::pmr::monotonic_buffer_resource mr((void*)buf, sizeof(buf), &r);
+ auto p = mr.allocate(64);
+ VERIFY( p != nullptr );
+ const std::uintptr_t pi = reinterpret_cast<std::uintptr_t>(p);
+ mr.deallocate(p, 64);
+ auto q = mr.allocate(1024);
+ VERIFY( q != nullptr );
+ VERIFY( p != q );
+ VERIFY( pi != reinterpret_cast<std::uintptr_t>(q) );
+ mr.deallocate(q, 1024);
+ VERIFY( r.deallocate_calls == 0 );
+ }
+ VERIFY( r.deallocate_calls == r.allocate_calls );
+ VERIFY( r.number_of_active_allocations() == 0 );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc
new file mode 100644
index 00000000000..0c7f31789e6
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc
@@ -0,0 +1,172 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <memory_resource>
+#include <testsuite_allocator.h>
+
+struct resource : __gnu_test::memory_resource
+{
+ int allocate_calls = 0;
+ int deallocate_calls = 0;
+
+ void*
+ do_allocate(std::size_t bytes, std::size_t align) override
+ {
+ ++allocate_calls;
+ return __gnu_test::memory_resource::do_allocate(bytes, align);
+ }
+
+ void
+ do_deallocate(void* p, std::size_t bytes, std::size_t align) override
+ {
+ ++deallocate_calls;
+ __gnu_test::memory_resource::do_deallocate(p, bytes, align);
+ }
+};
+
+void
+test01()
+{
+ resource r;
+ std::pmr::monotonic_buffer_resource mbr(&r);
+ auto p = mbr.allocate(10, 16);
+ mbr.deallocate(p, 1, 2);
+ VERIFY( r.deallocate_calls == 0 );
+ p = mbr.allocate(10, 16);
+ p = mbr.allocate(10, 16);
+ p = mbr.allocate(10, 16);
+ p = mbr.allocate(1024, 64);
+ p = mbr.allocate(1024, 64);
+ p = mbr.allocate(128, 8);
+ p = mbr.allocate(128, 8);
+ p = mbr.allocate(128, 8);
+ p = mbr.allocate(128, 8);
+ p = mbr.allocate(128, 8);
+ p = mbr.allocate(128, 8);
+ p = mbr.allocate(128, 8);
+ mbr.deallocate(p, 1, 2);
+ p = mbr.allocate(1024, 16);
+ p = mbr.allocate(1024, 16);
+ mbr.deallocate(p, 1, 2);
+ VERIFY( r.deallocate_calls == 0 );
+ mbr.release();
+ VERIFY( r.deallocate_calls != 0 );
+ VERIFY( r.deallocate_calls == r.allocate_calls );
+ VERIFY( mbr.upstream_resource() == &r );
+ VERIFY( r.number_of_active_allocations() == 0 );
+}
+
+void
+test02()
+{
+ std::pmr::monotonic_buffer_resource mbr; // uses get_default_resource()
+ auto* const upstream = mbr.upstream_resource();
+ resource r;
+ __gnu_test::default_resource_mgr _(&r); // calls set_default_resource(&r)
+ mbr.release();
+ // release() doesn't change upstream resource:
+ VERIFY( mbr.upstream_resource() == upstream );
+}
+
+void
+test03()
+{
+ resource r;
+ __gnu_test::default_resource_mgr _(&r);
+ std::pmr::monotonic_buffer_resource mbr(16);
+ for (int i = 0; i < 100; ++i)
+ (void) mbr.allocate(4, 1);
+ const int allocations = r.allocate_calls;
+ VERIFY( allocations != 0 );
+ mbr.release();
+ VERIFY( r.allocate_calls == r.deallocate_calls );
+ VERIFY( r.number_of_active_allocations() == 0 );
+
+ // next_buffer_size should have been reset to the initial value,
+ // so the allocations from upstream should be the same as before.
+ r.allocate_calls = 0;
+ r.deallocate_calls = 0;
+ for (int i = 0; i < 100; ++i)
+ (void) mbr.allocate(4,1);
+ VERIFY( allocations == r.allocate_calls );
+}
+
+void
+test04()
+{
+ resource r;
+ unsigned char buffer[1024];
+ std::pmr::monotonic_buffer_resource mbr(buffer, sizeof(buffer), &r);
+ void* p = mbr.allocate(800, 16);
+ VERIFY( p == buffer );
+ VERIFY( r.allocate_calls == 0 );
+ p = mbr.allocate(300, 1);
+ VERIFY( p != buffer );
+ VERIFY( r.allocate_calls == 1 );
+ mbr.release();
+ VERIFY( r.deallocate_calls == 1 );
+ VERIFY( mbr.upstream_resource() == &r );
+ VERIFY( r.number_of_active_allocations() == 0 );
+ // initial buffer should be used again now:
+ p = mbr.allocate(1000);
+ VERIFY( p == buffer );
+ VERIFY( r.allocate_calls == 1 );
+}
+
+void
+test05() // LWG 3120
+{
+ char buffer[100];
+ {
+ std::pmr::monotonic_buffer_resource mr(buffer, sizeof(buffer),
+ std::pmr::null_memory_resource());
+ mr.release();
+ (void) mr.allocate(60);
+ }
+
+ {
+ std::pmr::monotonic_buffer_resource mr(buffer, sizeof(buffer),
+ std::pmr::null_memory_resource());
+ (void) mr.allocate(60);
+ mr.release();
+ (void) mr.allocate(60);
+ }
+
+ {
+ resource r;
+ std::pmr::monotonic_buffer_resource mr(&r);
+ for (int i = 0; i < 100; ++i)
+ {
+ (void) mr.allocate(1);
+ mr.release();
+ }
+ VERIFY( r.number_of_active_allocations() == 0 );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+}
diff --git a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/upstream_resource.cc b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/upstream_resource.cc
new file mode 100644
index 00000000000..c09294f4272
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/upstream_resource.cc
@@ -0,0 +1,76 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <memory_resource>
+#include <testsuite_allocator.h>
+
+void
+test01()
+{
+ __gnu_test::memory_resource r;
+ const auto null = std::pmr::null_memory_resource();
+ const auto newdel = std::pmr::new_delete_resource();
+ std::pmr::set_default_resource(null);
+
+ {
+ std::pmr::monotonic_buffer_resource mr(&r);
+ VERIFY( mr.upstream_resource() == &r );
+ __gnu_test::default_resource_mgr _(newdel);
+ VERIFY( mr.upstream_resource() == &r );
+ }
+ {
+ std::pmr::monotonic_buffer_resource mr(128, &r);
+ VERIFY( mr.upstream_resource() == &r );
+ __gnu_test::default_resource_mgr _(newdel);
+ VERIFY( mr.upstream_resource() == &r );
+ }
+ {
+ unsigned char buf[64];
+ std::pmr::monotonic_buffer_resource mr((void*)buf, sizeof(buf), &r);
+ VERIFY( mr.upstream_resource() == &r );
+ __gnu_test::default_resource_mgr _(newdel);
+ VERIFY( mr.upstream_resource() == &r );
+ }
+ {
+ std::pmr::monotonic_buffer_resource mr;
+ VERIFY( mr.upstream_resource() == null );
+ __gnu_test::default_resource_mgr _(newdel);
+ VERIFY( mr.upstream_resource() == null );
+ }
+ {
+ std::pmr::monotonic_buffer_resource mr(64);
+ VERIFY( mr.upstream_resource() == null );
+ __gnu_test::default_resource_mgr _(newdel);
+ VERIFY( mr.upstream_resource() == null );
+ }
+ {
+ unsigned char buf[64];
+ std::pmr::monotonic_buffer_resource mr((void*)buf, sizeof(buf));
+ VERIFY( mr.upstream_resource() == null );
+ __gnu_test::default_resource_mgr _(newdel);
+ VERIFY( mr.upstream_resource() == null );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/polymorphic_allocator/1.cc b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/1.cc
new file mode 100644
index 00000000000..4bc7f79e2b6
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/1.cc
@@ -0,0 +1,36 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <memory_resource>
+
+struct X { int i = 0; };
+
+using test_type = std::pmr::polymorphic_allocator<X>;
+
+static_assert(std::is_default_constructible_v<test_type>);
+static_assert(std::is_destructible_v<test_type>);
+static_assert(std::is_copy_constructible_v<test_type>);
+static_assert(!std::is_copy_assignable_v<test_type>);
+static_assert(std::is_constructible_v<test_type, std::pmr::memory_resource*>);
+
+static_assert(std::is_same_v<test_type::value_type, X>);
+
+static_assert(!std::is_polymorphic_v<test_type>);
+static_assert(!std::is_final_v<test_type>);
diff --git a/libstdc++-v3/testsuite/20_util/polymorphic_allocator/resource.cc b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/resource.cc
new file mode 100644
index 00000000000..01f6ace2d80
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/resource.cc
@@ -0,0 +1,87 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+// { dg-skip-if "" { *-*-* } { -fno-aligned-new } }
+
+#include <memory_resource>
+#include <testsuite_allocator.h>
+
+struct X { int i = 0; };
+
+using test_type = std::pmr::polymorphic_allocator<X>;
+
+void
+test01()
+{
+ __gnu_test::memory_resource r;
+ test_type a(&r), b(&r);
+ VERIFY( a == a );
+ VERIFY( ! (a != a) );
+ VERIFY( a == b );
+ VERIFY( ! (a != b) );
+ VERIFY( a.resource() == &r );
+ VERIFY( a.resource() == b.resource() );
+
+ __gnu_test::memory_resource r2(r);
+ test_type c(&r2);
+ VERIFY( c.resource() == &r2 );
+ VERIFY( c.resource() != a.resource() );
+ VERIFY( c == a );
+}
+
+void
+test02()
+{
+ __gnu_test::memory_resource r1, r2;
+ test_type a(&r1), b(&r2);
+ VERIFY( a == a );
+ VERIFY( b == b );
+ VERIFY( ! (a == b) );
+ VERIFY( ! (b == a) );
+ VERIFY( a != b );
+ VERIFY( b != a );
+ VERIFY( a.resource() == &r1 );
+ VERIFY( a.resource() != b.resource() );
+
+ test_type c;
+ VERIFY( c == c );
+ VERIFY( ! (a == c) );
+ VERIFY( ! (c == a) );
+ VERIFY( ! (b == c) );
+ VERIFY( ! (c == b) );
+ VERIFY( a.resource() != c.resource() );
+ VERIFY( c.resource() == std::pmr::get_default_resource() );
+
+ std::pmr::set_default_resource(&r1);
+ VERIFY( c.resource() != &r1 );
+
+ test_type d;
+ VERIFY( d.resource() == &r1 );
+ VERIFY( d != c );
+ VERIFY( d == a );
+
+ std::pmr::set_default_resource(nullptr);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/polymorphic_allocator/select.cc b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/select.cc
new file mode 100644
index 00000000000..e5790c03223
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/select.cc
@@ -0,0 +1,58 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+// { dg-skip-if "" { *-*-* } { -fno-aligned-new } }
+
+#include <memory_resource>
+#include <testsuite_allocator.h>
+
+struct X { int i = 0; };
+
+using test_type = std::pmr::polymorphic_allocator<X>;
+
+void
+test01()
+{
+ test_type a, b;
+ VERIFY( a.select_on_container_copy_construction() == a );
+ VERIFY( a.select_on_container_copy_construction() == b );
+
+ __gnu_test::memory_resource r;
+ test_type c(&r);
+ VERIFY( c.select_on_container_copy_construction() != c );
+ VERIFY( c.select_on_container_copy_construction() == a );
+}
+
+void
+test02()
+{
+ __gnu_test::memory_resource r;
+ test_type a(&r);
+ VERIFY( a.select_on_container_copy_construction() != a );
+ std::pmr::set_default_resource(&r);
+ VERIFY( a.select_on_container_copy_construction() == a );
+ std::pmr::set_default_resource(nullptr);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h
index 501a81f2276..03679aad8dc 100644
--- a/libstdc++-v3/testsuite/util/testsuite_allocator.h
+++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h
@@ -31,6 +31,10 @@
#include <ext/pointer.h>
#include <ext/alloc_traits.h>
#include <testsuite_hooks.h>
+#if __cplusplus >= 201703L
+# include <memory_resource>
+# include <new>
+#endif
namespace __gnu_test
{
@@ -691,7 +695,161 @@ namespace __gnu_test
using PointerBase_void::PointerBase_void;
typedef Derived pointer;
};
-#endif
+#endif // C++11
+
+#if __cplusplus >= 201703L && __cpp_aligned_new
+ // A concrete memory_resource, with error checking.
+ class memory_resource : public std::pmr::memory_resource
+ {
+ public:
+ memory_resource()
+ : lists(new allocation_lists)
+ { }
+
+ memory_resource(const memory_resource& r) noexcept
+ : lists(r.lists)
+ { lists->refcount++; }
+
+ memory_resource& operator=(const memory_resource&) = delete;
+
+ ~memory_resource()
+ {
+ if (lists->refcount-- == 1)
+ delete lists; // last one out turns out the lights
+ }
+
+ struct bad_size { };
+ struct bad_alignment { };
+ struct bad_address { };
+
+ // Deallocate everything (moving the tracking info to the freed list)
+ void
+ deallocate_everything()
+ {
+ while (lists->active)
+ {
+ auto a = lists->active;
+ // Intentionally virtual dispatch, to inform derived classes:
+ this->do_deallocate(a->p, a->bytes, a->alignment);
+ }
+ }
+
+ // Clear the freed list
+ void
+ forget_freed_allocations()
+ { lists->forget_allocations(lists->freed); }
+
+ // Count how many allocations have been done and not freed.
+ std::size_t
+ number_of_active_allocations() const noexcept
+ {
+ std::size_t n = 0;
+ for (auto a = lists->active; a != nullptr; a = a->next)
+ ++n;
+ return n;
+ }
+
+ protected:
+ void*
+ do_allocate(std::size_t bytes, std::size_t alignment) override
+ {
+ // TODO perform a single allocation and put the allocation struct
+ // in the buffer using placement new? It means deallocation won't
+ // actually return memory to the OS, as it will stay in lists->freed.
+ //
+ // TODO adjust the returned pointer to be minimally aligned?
+ // e.g. if alignment==1 don't return something aligned to 2 bytes.
+ // Maybe not worth it, at least monotonic_buffer_resource will
+ // never ask upstream for anything with small alignment.
+ void* p = ::operator new(bytes, std::align_val_t(alignment));
+ lists->active = new allocation{p, bytes, alignment, lists->active};
+ return p;
+ }
+
+ void
+ do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override
+ {
+ allocation** aptr = &lists->active;
+ while (*aptr)
+ {
+ allocation* a = *aptr;
+ if (p == a->p)
+ {
+ if (bytes != a->bytes)
+ throw bad_size();
+ if (alignment != a->alignment)
+ throw bad_alignment();
+ ::operator delete(p, bytes, std::align_val_t(alignment));
+ *aptr = a->next;
+ a->next = lists->freed;
+ lists->freed = a;
+ return;
+ }
+ aptr = &a->next;
+ }
+ throw bad_address();
+ }
+
+ bool
+ do_is_equal(const std::pmr::memory_resource& r) const noexcept override
+ {
+ // Equality is determined by sharing the same allocation_lists object.
+ if (auto p = dynamic_cast<const memory_resource*>(&r))
+ return p->lists == lists;
+ return false;
+ }
+
+ private:
+ struct allocation
+ {
+ void* p;
+ std::size_t bytes;
+ std::size_t alignment;
+ allocation* next;
+ };
+
+ // Maintain list of allocated blocks and list of freed blocks.
+ // Copies of this memory_resource share the same ref-counted lists.
+ struct allocation_lists
+ {
+ unsigned refcount = 1;
+ allocation* active = nullptr;
+ allocation* freed = nullptr;
+
+ void forget_allocations(allocation*& list)
+ {
+ while (list)
+ {
+ auto p = list;
+ list = list->next;
+ delete p;
+ }
+ }
+
+ ~allocation_lists()
+ {
+ forget_allocations(active); // Anything in this list is a leak!
+ forget_allocations(freed);
+ }
+ };
+
+ allocation_lists* lists;
+ };
+
+ // Set the default resource, and restore the previous one on destruction.
+ struct default_resource_mgr
+ {
+ explicit default_resource_mgr(std::pmr::memory_resource* r)
+ : prev(std::pmr::set_default_resource(r))
+ { }
+
+ ~default_resource_mgr()
+ { std::pmr::set_default_resource(prev); }
+
+ std::pmr::memory_resource* prev;
+ };
+
+#endif // C++17 && aligned-new
} // namespace __gnu_test
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add initial version of C++17 <memory_resource> header
2018-07-24 21:12 [PATCH] Add initial version of C++17 <memory_resource> header Jonathan Wakely
@ 2018-07-25 11:01 ` Jonathan Wakely
2018-07-25 20:23 ` Jonathan Wakely
0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Wakely @ 2018-07-25 11:01 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2586 bytes --]
On 24/07/18 22:12 +0100, Jonathan Wakely wrote:
>This is missing the synchronized_pool_resource and
>unsynchronized_pool_resource classes but is otherwise complete.
>
>This is a new implementation, not based on the existing code in
><experimental/memory_resource>, but memory_resource and
>polymorphic_allocator ended up looking almost the same anyway.
>
>The constant_init kluge in src/c++17/memory_resource.cc is apparently
>due to Richard Smith and ensures that the objects are constructed during
>constant initialiation phase and not destroyed (because the
>constant_init destructor doesn't destroy the union member and the
>storage is not reused).
>
> * config/abi/pre/gnu.ver: Export new symbols.
> * configure: Regenerate.
> * include/Makefile.am: Add new <memory_resource> header.
> * include/Makefile.in: Regenerate.
> * include/precompiled/stdc++.h: Include <memory_resource> for C++17.
> * include/std/memory_resource: New header.
> (memory_resource, polymorphic_allocator, new_delete_resource)
> (null_memory_resource, set_default_resource, get_default_resource)
> (pool_options, monotonic_buffer_resource): Define.
> * src/Makefile.am: Add c++17 directory.
> * src/Makefile.in: Regenerate.
> * src/c++11/Makefile.am: Fix comment.
> * src/c++17/Makefile.am: Add makefile for new sub-directory.
> * src/c++17/Makefile.in: Generate.
> * src/c++17/memory_resource.cc: New.
> (newdel_res_t, null_res_t, constant_init, newdel_res, null_res)
> (default_res, new_delete_resource, null_memory_resource)
> (set_default_resource, get_default_resource): Define.
> * testsuite/20_util/memory_resource/1.cc: New test.
> * testsuite/20_util/memory_resource/2.cc: New test.
> * testsuite/20_util/monotonic_buffer_resource/1.cc: New test.
> * testsuite/20_util/monotonic_buffer_resource/allocate.cc: New test.
> * testsuite/20_util/monotonic_buffer_resource/deallocate.cc: New test.
> * testsuite/20_util/monotonic_buffer_resource/release.cc: New test.
> * testsuite/20_util/monotonic_buffer_resource/upstream_resource.cc:
> New test.
> * testsuite/20_util/polymorphic_allocator/1.cc: New test.
> * testsuite/20_util/polymorphic_allocator/resource.cc: New test.
> * testsuite/20_util/polymorphic_allocator/select.cc: New test.
> * testsuite/util/testsuite_allocator.h (__gnu_test::memory_resource):
> Define concrete memory resource for testing.
> (__gnu_test::default_resource_mgr): Define RAII helper for changing
> default resource.
>
>Tested powerpc64le-linux, committed to trunk.
I missed a change to acinclude.m4 that should have gone with this
patch. Now also committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1477 bytes --]
commit cdaaa2b47d3fa093c741086e86d631d420a93663
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed Jul 25 11:52:19 2018 +0100
Add new src/c++17 directory to list in acinclude.m4
* acinclude.m4 (glibcxx_SUBDIRS): Add src/c++17.
* src/Makefile.am: Add comment.
* src/c++17/Makefile.in: Regenerate.
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index bbf3c8df3e1..6d68e907426 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -49,7 +49,7 @@ AC_DEFUN([GLIBCXX_CONFIGURE], [
# Keep these sync'd with the list in Makefile.am. The first provides an
# expandable list at autoconf time; the second provides an expandable list
# (i.e., shell variable) at configure time.
- m4_define([glibcxx_SUBDIRS],[include libsupc++ src src/c++98 src/c++11 src/filesystem doc po testsuite python])
+ m4_define([glibcxx_SUBDIRS],[include libsupc++ src src/c++98 src/c++11 src/c++17 src/filesystem doc po testsuite python])
SUBDIRS='glibcxx_SUBDIRS'
# These need to be absolute paths, yet at the same time need to
diff --git a/libstdc++-v3/src/Makefile.am b/libstdc++-v3/src/Makefile.am
index 09edcdbc471..9a2fe297ddb 100644
--- a/libstdc++-v3/src/Makefile.am
+++ b/libstdc++-v3/src/Makefile.am
@@ -28,6 +28,7 @@ else
filesystem_dir =
endif
+## Keep this list sync'd with acinclude.m4:GLIBCXX_CONFIGURE.
SUBDIRS = c++98 c++11 c++17 $(filesystem_dir)
# Cross compiler support.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add initial version of C++17 <memory_resource> header
2018-07-25 11:01 ` Jonathan Wakely
@ 2018-07-25 20:23 ` Jonathan Wakely
2018-07-25 23:38 ` Jonathan Wakely
0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Wakely @ 2018-07-25 20:23 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2746 bytes --]
On 25/07/18 12:01 +0100, Jonathan Wakely wrote:
>On 24/07/18 22:12 +0100, Jonathan Wakely wrote:
>>This is missing the synchronized_pool_resource and
>>unsynchronized_pool_resource classes but is otherwise complete.
>>
>>This is a new implementation, not based on the existing code in
>><experimental/memory_resource>, but memory_resource and
>>polymorphic_allocator ended up looking almost the same anyway.
>>
>>The constant_init kluge in src/c++17/memory_resource.cc is apparently
>>due to Richard Smith and ensures that the objects are constructed during
>>constant initialiation phase and not destroyed (because the
>>constant_init destructor doesn't destroy the union member and the
>>storage is not reused).
>>
>> * config/abi/pre/gnu.ver: Export new symbols.
>> * configure: Regenerate.
>> * include/Makefile.am: Add new <memory_resource> header.
>> * include/Makefile.in: Regenerate.
>> * include/precompiled/stdc++.h: Include <memory_resource> for C++17.
>> * include/std/memory_resource: New header.
>> (memory_resource, polymorphic_allocator, new_delete_resource)
>> (null_memory_resource, set_default_resource, get_default_resource)
>> (pool_options, monotonic_buffer_resource): Define.
>> * src/Makefile.am: Add c++17 directory.
>> * src/Makefile.in: Regenerate.
>> * src/c++11/Makefile.am: Fix comment.
>> * src/c++17/Makefile.am: Add makefile for new sub-directory.
>> * src/c++17/Makefile.in: Generate.
>> * src/c++17/memory_resource.cc: New.
>> (newdel_res_t, null_res_t, constant_init, newdel_res, null_res)
>> (default_res, new_delete_resource, null_memory_resource)
>> (set_default_resource, get_default_resource): Define.
>> * testsuite/20_util/memory_resource/1.cc: New test.
>> * testsuite/20_util/memory_resource/2.cc: New test.
>> * testsuite/20_util/monotonic_buffer_resource/1.cc: New test.
>> * testsuite/20_util/monotonic_buffer_resource/allocate.cc: New test.
>> * testsuite/20_util/monotonic_buffer_resource/deallocate.cc: New test.
>> * testsuite/20_util/monotonic_buffer_resource/release.cc: New test.
>> * testsuite/20_util/monotonic_buffer_resource/upstream_resource.cc:
>> New test.
>> * testsuite/20_util/polymorphic_allocator/1.cc: New test.
>> * testsuite/20_util/polymorphic_allocator/resource.cc: New test.
>> * testsuite/20_util/polymorphic_allocator/select.cc: New test.
>> * testsuite/util/testsuite_allocator.h (__gnu_test::memory_resource):
>> Define concrete memory resource for testing.
>> (__gnu_test::default_resource_mgr): Define RAII helper for changing
>> default resource.
>>
>>Tested powerpc64le-linux, committed to trunk.
>
>I missed a change to acinclude.m4 that should have gone with this
>patch. Now also committed to trunk.
One of the tests also needs this fix.
Committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1465 bytes --]
commit 4875590bba5e5b77878264870671071016ab7ca2
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed Jul 25 21:22:19 2018 +0100
PR libstdc++/86676 Do not assume stack buffer is aligned
PR libstdc++/86676
* testsuite/20_util/monotonic_buffer_resource/release.cc: Allow for
buffer being misaligned and so returned pointer not being at start.
diff --git a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc
index 0c7f31789e6..ac70385961d 100644
--- a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc
+++ b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc
@@ -115,10 +115,12 @@ test04()
unsigned char buffer[1024];
std::pmr::monotonic_buffer_resource mbr(buffer, sizeof(buffer), &r);
void* p = mbr.allocate(800, 16);
- VERIFY( p == buffer );
+ VERIFY( p >= buffer && p < (buffer + 16) );
+ void* const p_in_buffer = p;
VERIFY( r.allocate_calls == 0 );
p = mbr.allocate(300, 1);
VERIFY( p != buffer );
+ VERIFY( p != buffer );
VERIFY( r.allocate_calls == 1 );
mbr.release();
VERIFY( r.deallocate_calls == 1 );
@@ -126,7 +128,7 @@ test04()
VERIFY( r.number_of_active_allocations() == 0 );
// initial buffer should be used again now:
p = mbr.allocate(1000);
- VERIFY( p == buffer );
+ VERIFY( p == p_in_buffer );
VERIFY( r.allocate_calls == 1 );
}
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add initial version of C++17 <memory_resource> header
2018-07-25 20:23 ` Jonathan Wakely
@ 2018-07-25 23:38 ` Jonathan Wakely
0 siblings, 0 replies; 4+ messages in thread
From: Jonathan Wakely @ 2018-07-25 23:38 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2922 bytes --]
On 25/07/18 21:23 +0100, Jonathan Wakely wrote:
>On 25/07/18 12:01 +0100, Jonathan Wakely wrote:
>>On 24/07/18 22:12 +0100, Jonathan Wakely wrote:
>>>This is missing the synchronized_pool_resource and
>>>unsynchronized_pool_resource classes but is otherwise complete.
>>>
>>>This is a new implementation, not based on the existing code in
>>><experimental/memory_resource>, but memory_resource and
>>>polymorphic_allocator ended up looking almost the same anyway.
>>>
>>>The constant_init kluge in src/c++17/memory_resource.cc is apparently
>>>due to Richard Smith and ensures that the objects are constructed during
>>>constant initialiation phase and not destroyed (because the
>>>constant_init destructor doesn't destroy the union member and the
>>>storage is not reused).
>>>
>>> * config/abi/pre/gnu.ver: Export new symbols.
>>> * configure: Regenerate.
>>> * include/Makefile.am: Add new <memory_resource> header.
>>> * include/Makefile.in: Regenerate.
>>> * include/precompiled/stdc++.h: Include <memory_resource> for C++17.
>>> * include/std/memory_resource: New header.
>>> (memory_resource, polymorphic_allocator, new_delete_resource)
>>> (null_memory_resource, set_default_resource, get_default_resource)
>>> (pool_options, monotonic_buffer_resource): Define.
>>> * src/Makefile.am: Add c++17 directory.
>>> * src/Makefile.in: Regenerate.
>>> * src/c++11/Makefile.am: Fix comment.
>>> * src/c++17/Makefile.am: Add makefile for new sub-directory.
>>> * src/c++17/Makefile.in: Generate.
>>> * src/c++17/memory_resource.cc: New.
>>> (newdel_res_t, null_res_t, constant_init, newdel_res, null_res)
>>> (default_res, new_delete_resource, null_memory_resource)
>>> (set_default_resource, get_default_resource): Define.
>>> * testsuite/20_util/memory_resource/1.cc: New test.
>>> * testsuite/20_util/memory_resource/2.cc: New test.
>>> * testsuite/20_util/monotonic_buffer_resource/1.cc: New test.
>>> * testsuite/20_util/monotonic_buffer_resource/allocate.cc: New test.
>>> * testsuite/20_util/monotonic_buffer_resource/deallocate.cc: New test.
>>> * testsuite/20_util/monotonic_buffer_resource/release.cc: New test.
>>> * testsuite/20_util/monotonic_buffer_resource/upstream_resource.cc:
>>> New test.
>>> * testsuite/20_util/polymorphic_allocator/1.cc: New test.
>>> * testsuite/20_util/polymorphic_allocator/resource.cc: New test.
>>> * testsuite/20_util/polymorphic_allocator/select.cc: New test.
>>> * testsuite/util/testsuite_allocator.h (__gnu_test::memory_resource):
>>> Define concrete memory resource for testing.
>>> (__gnu_test::default_resource_mgr): Define RAII helper for changing
>>> default resource.
>>>
>>>Tested powerpc64le-linux, committed to trunk.
>>
>>I missed a change to acinclude.m4 that should have gone with this
>>patch. Now also committed to trunk.
>
>One of the tests also needs this fix.
And another correction to the same test.
Tested powerpc-ibm-aix7.2.0.0, committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 995 bytes --]
commit 0dbdb55154fee2af4c02e45a373f5a2dc2985856
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Thu Jul 26 00:35:57 2018 +0100
PR libstdc++/86676 another alignment fix for test
PR libstdc++/86676
* testsuite/20_util/monotonic_buffer_resource/release.cc: Request
same alignment for post-release allocation.
diff --git a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc
index ac70385961d..8aab4692d52 100644
--- a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc
+++ b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/release.cc
@@ -127,7 +127,7 @@ test04()
VERIFY( mbr.upstream_resource() == &r );
VERIFY( r.number_of_active_allocations() == 0 );
// initial buffer should be used again now:
- p = mbr.allocate(1000);
+ p = mbr.allocate(1000, 16);
VERIFY( p == p_in_buffer );
VERIFY( r.allocate_calls == 1 );
}
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2018-07-25 23:38 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-24 21:12 [PATCH] Add initial version of C++17 <memory_resource> header Jonathan Wakely
2018-07-25 11:01 ` Jonathan Wakely
2018-07-25 20:23 ` Jonathan Wakely
2018-07-25 23:38 ` Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).