Commit dfaa3c47 by Jonathan Wakely Committed by Jonathan Wakely

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.

From-SVN: r262953
parent e874029d
2018-07-24 Jonathan Wakely <jwakely@redhat.com>
* 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.
PR libstdc++/86658
* include/bits/stl_algobase.h (__niter_wrap<_Iterator>): Pass unused
parameter by reference, to avoid copying invalid iterators.
......
......@@ -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.
......
......@@ -4965,7 +4965,7 @@ $as_echo "$ac_cv_path_EGREP" >&6; }
# expandable list at autoconf time; the second provides an expandable list
# (i.e., shell variable) at configure time.
SUBDIRS='include libsupc++ src src/c++98 src/c++11 src/filesystem doc po testsuite python'
SUBDIRS='include libsupc++ src src/c++98 src/c++11 src/c++17 src/filesystem doc po testsuite python'
# These need to be absolute paths, yet at the same time need to
# canonicalize only relative paths, because then amd will not unmount
......@@ -81841,7 +81841,7 @@ ac_config_files="$ac_config_files doc/xsl/customization.xsl"
# append it here. Only modify Makefiles that have just been created.
#
# Also, get rid of this simulated-VPATH thing that automake does.
ac_config_files="$ac_config_files include/Makefile libsupc++/Makefile src/Makefile src/c++98/Makefile src/c++11/Makefile src/filesystem/Makefile doc/Makefile po/Makefile testsuite/Makefile python/Makefile"
ac_config_files="$ac_config_files include/Makefile libsupc++/Makefile src/Makefile src/c++98/Makefile src/c++11/Makefile src/c++17/Makefile src/filesystem/Makefile doc/Makefile po/Makefile testsuite/Makefile python/Makefile"
ac_config_commands="$ac_config_commands generate-headers"
......@@ -83076,6 +83076,7 @@ do
"src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
"src/c++98/Makefile") CONFIG_FILES="$CONFIG_FILES src/c++98/Makefile" ;;
"src/c++11/Makefile") CONFIG_FILES="$CONFIG_FILES src/c++11/Makefile" ;;
"src/c++17/Makefile") CONFIG_FILES="$CONFIG_FILES src/c++17/Makefile" ;;
"src/filesystem/Makefile") CONFIG_FILES="$CONFIG_FILES src/filesystem/Makefile" ;;
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
"po/Makefile") CONFIG_FILES="$CONFIG_FILES po/Makefile" ;;
......@@ -84913,6 +84914,17 @@ _EOF
. ${multi_basedir}/config-ml.in
{ ml_norecursion=; unset ml_norecursion;}
;;
"src/c++17/Makefile":F) cat > vpsed$$ << \_EOF
s!`test -f '$<' || echo '$(srcdir)/'`!!
_EOF
sed -f vpsed$$ $ac_file > tmp$$
mv tmp$$ $ac_file
rm vpsed$$
echo 'MULTISUBDIR =' >> $ac_file
ml_norecursion=yes
. ${multi_basedir}/config-ml.in
{ ml_norecursion=; unset ml_norecursion;}
;;
"src/filesystem/Makefile":F) cat > vpsed$$ << \_EOF
s!`test -f '$<' || echo '$(srcdir)/'`!!
_EOF
......@@ -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 \
......
......@@ -347,6 +347,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 \
......
......@@ -128,7 +128,7 @@
// #include <execution>
#include <filesystem>
#include <optional>
// #include <memory_resource>
#include <memory_resource>
#include <string_view>
#include <variant>
#endif
......
......@@ -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
......
......@@ -152,7 +152,7 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS
ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = c++98 c++11 filesystem
DIST_SUBDIRS = c++98 c++11 c++17 filesystem
ABI_TWEAKS_SRCDIR = @ABI_TWEAKS_SRCDIR@
ACLOCAL = @ACLOCAL@
ALLOCATOR_H = @ALLOCATOR_H@
......@@ -379,7 +379,7 @@ WARN_CXXFLAGS = \
AM_CPPFLAGS = $(GLIBCXX_INCLUDES) $(CPPFLAGS)
@ENABLE_FILESYSTEM_TS_FALSE@filesystem_dir =
@ENABLE_FILESYSTEM_TS_TRUE@filesystem_dir = filesystem
SUBDIRS = c++98 c++11 $(filesystem_dir)
SUBDIRS = c++98 c++11 c++17 $(filesystem_dir)
@VTV_CYGMIN_FALSE@toolexeclib_LTLIBRARIES = libstdc++.la
# Cross compiler support.
......@@ -419,13 +419,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
......@@ -440,8 +442,8 @@ libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
# 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
......@@ -900,6 +902,7 @@ uninstall-am: uninstall-toolexeclibLTLIBRARIES
vpath % $(top_srcdir)/src/c++98
vpath % $(top_srcdir)/src/c++11
vpath % $(top_srcdir)/src/c++17
@ENABLE_FILESYSTEM_TS_TRUE@vpath % $(top_srcdir)/src/filesystem
# Use special rules for compatibility-ldbl.cc compilation, as we need to
......
## 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.
##
......
## 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 $@
// <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
// { 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>);
// { 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();
}
// 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>);
// 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();
}
// 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();
}
// 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();
}
// 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();
}
// 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>);
// 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();
}
// 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();
}
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment