// <experimental/memory_resource> -*- C++ -*-
-// Copyright (C) 2015-2019 Free Software Foundation, Inc.
+// Copyright (C) 2015-2024 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
#ifndef _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE
#define _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 1
+#pragma GCC system_header
+
+#include <bits/requires_hosted.h> // experimental is currently omitted
+
+#if __cplusplus >= 201402L
+
#include <memory> // align, uses_allocator, __uses_alloc
#include <experimental/utility> // pair, experimental::erased_type
+#include <tuple> // tuple, forward_as_tuple
#include <atomic> // atomic
#include <new> // placement new
#include <cstddef> // max_align_t
-#include <ext/new_allocator.h>
+#include <bits/new_allocator.h>
#include <debug/assertions.h>
-/// @cond
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp> class malloc_allocator;
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace __gnu_cxx
-/// @endcond
namespace std {
_GLIBCXX_BEGIN_NAMESPACE_VERSION
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)));
+ std::forward_as_tuple(std::forward<_Up>(__x)),
+ std::forward_as_tuple(std::forward<_Vp>(__y)));
}
template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
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));
+ std::forward_as_tuple(__pr.first),
+ std::forward_as_tuple(__pr.second));
}
template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
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)));
+ std::forward_as_tuple(std::forward<_Up>(__pr.first)),
+ std::forward_as_tuple(std::forward<_Vp>(__pr.second)));
}
template <typename _Up>
return __val;
}
};
-
- template<typename _Alloc>
- struct __guaranteed_alignment : std::integral_constant<size_t, 1> { };
-
- template<typename _Tp>
- struct __guaranteed_alignment<__gnu_cxx::new_allocator<_Tp>>
- : std::alignment_of<std::max_align_t>::type { };
-
- template<typename _Tp>
- struct __guaranteed_alignment<__gnu_cxx::malloc_allocator<_Tp>>
- : std::alignment_of<std::max_align_t>::type { };
-
-#if _GLIBCXX_USE_ALLOCATOR_NEW
- template<typename _Tp>
- struct __guaranteed_alignment<std::allocator<_Tp>>
- : std::alignment_of<std::max_align_t>::type { };
-#endif
};
/// @endcond
allocator_type get_allocator() const noexcept { return _M_alloc; }
protected:
+#if (defined __sun__ || defined __VXWORKS__) && defined __i386__
+// Cannot use max_align_t on 32-bit Solaris x86, see PR libstdc++/77691
+# define _GLIBCXX_MAX_ALIGN_MATCHES_MALLOC 0
+#elif defined __hpux__ && defined __hppa__ && defined __LP64__
+// Ignore inconsistent long double and malloc alignment (libstdc++/77691)
+# define _GLIBCXX_MAX_ALIGN_MATCHES_MALLOC 0
+#else
+# define _GLIBCXX_MAX_ALIGN_MATCHES_MALLOC 1
+#endif
+
virtual void*
do_allocate(size_t __bytes, size_t __alignment) override
{
- if (__alignment <= __guaranteed_alignment<_Alloc>::value)
+#if _GLIBCXX_MAX_ALIGN_MATCHES_MALLOC
+ if (__alignment == alignof(max_align_t))
+ return _M_allocate<alignof(max_align_t)>(__bytes);
+#endif
+ switch (__alignment)
{
- if (__bytes < __alignment)
- __bytes = __alignment;
+ case 1:
return _M_alloc.allocate(__bytes);
+ case 2:
+ return _M_allocate<2>(__bytes);
+ case 4:
+ return _M_allocate<4>(__bytes);
+ case 8:
+ return _M_allocate<8>(__bytes);
}
-
-
const _AlignMgr __mgr(__bytes, __alignment);
// Assume _M_alloc returns 1-byte aligned memory, so allocate enough
// space to fit a block of the right size and alignment, plus some
}
virtual void
- do_deallocate(void* __p, size_t __bytes, size_t __alignment) noexcept
+ do_deallocate(void* __ptr, size_t __bytes, size_t __alignment) noexcept
override
{
- auto __ptr = static_cast<char*>(__p);
- if (__alignment <= __guaranteed_alignment<_Alloc>::value)
+#if _GLIBCXX_MAX_ALIGN_MATCHES_MALLOC
+ if (__alignment == alignof(max_align_t))
+ return (void) _M_deallocate<alignof(max_align_t)>(__ptr, __bytes);
+#endif
+ switch (__alignment)
{
- if (__bytes < __alignment)
- __bytes = __alignment;
- _M_alloc.deallocate(__ptr, __bytes);
- return;
+ case 1:
+ return (void) _M_alloc.deallocate((char*)__ptr, __bytes);
+ case 2:
+ return (void) _M_deallocate<2>(__ptr, __bytes);
+ case 4:
+ return (void) _M_deallocate<4>(__ptr, __bytes);
+ case 8:
+ return (void) _M_deallocate<8>(__ptr, __bytes);
}
-
const _AlignMgr __mgr(__bytes, __alignment);
- // Use the stored token to retrieve the original pointer to deallocate.
- _M_alloc.deallocate(__mgr._M_unadjust(__ptr), __mgr._M_alloc_size());
+ // Use the stored token to retrieve the original pointer.
+ _M_alloc.deallocate(__mgr._M_unadjust((char*)__ptr),
+ __mgr._M_alloc_size());
}
virtual bool
do_is_equal(const memory_resource& __other) const noexcept override
{
+#if __cpp_rtti
if (auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other))
return _M_alloc == __p->_M_alloc;
+#else
+ if (this == &__other) // Need RTTI to do better than this.
+ return true;
+#endif
return false;
}
private:
+ template<size_t _Num>
+ struct _Aligned_type { alignas(_Num) char __c[_Num]; };
+
+ // Rebind the allocator to the specified type and use it to allocate.
+ template<size_t _Num, typename _Tp = _Aligned_type<_Num>>
+ void*
+ _M_allocate(size_t __bytes)
+ {
+ typename allocator_traits<_Alloc>::template
+ rebind_alloc<_Tp> __a2(_M_alloc);
+ const size_t __n = (__bytes + _Num - 1) / _Num;
+ return __a2.allocate(__n);
+ }
+
+ // Rebind the allocator to the specified type and use it to deallocate.
+ template<size_t _Num, typename _Tp = _Aligned_type<_Num>>
+ void
+ _M_deallocate(void* __ptr, size_t __bytes) noexcept
+ {
+ typename allocator_traits<_Alloc>::template
+ rebind_alloc<_Tp> __a2(_M_alloc);
+ const size_t __n = (__bytes + _Num - 1) / _Num;
+ __a2.deallocate((_Tp*)__ptr, __n);
+ }
+
_Alloc _M_alloc{};
};
inline memory_resource*
new_delete_resource() noexcept
{
- using type = resource_adaptor<__gnu_cxx::new_allocator<char>>;
+ using type = resource_adaptor<std::__new_allocator<char>>;
alignas(type) static unsigned char __buf[sizeof(type)];
static type* __r = new(__buf) type;
return __r;
// The default memory resource
/// @cond undocumented
- inline std::atomic<memory_resource*>&
+ inline auto&
__get_default_resource()
{
+#ifndef _GLIBCXX_HAS_GTHREADS
+ struct type {
+ using value_type = memory_resource*;
+ explicit type(value_type __r) : _M_r(__r) { }
+ value_type _M_r;
+ value_type load() const { return _M_r; }
+ value_type exchange(value_type __r) { return std::__exchange(_M_r, __r); }
+ };
+#else
using type = atomic<memory_resource*>;
+#endif
alignas(type) static unsigned char __buf[sizeof(type)];
static type* __r = new(__buf) type(new_delete_resource());
return *__r;
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
+#endif // C++14
#endif // _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE