+2018-08-07 Jonathan Wakely <jwakely@redhat.com>
+
+ * config/abi/pre/gnu.ver: Export monotonic_buffer_resource members.
+ * include/std/memory_resource (monotonic_buffer_resource::release):
+ Call _M_release_buffers to free buffers.
+ (monotonic_buffer_resource::do_allocate): Call _M_new_buffer to
+ allocate a new buffer from upstream.
+ (monotonic_buffer_resource::_M_new_buffer): Declare.
+ (monotonic_buffer_resource::_M_release_buffers): Declare.
+ (monotonic_buffer_resource::_Chunk): Replace definition with
+ declaration as opaque type.
+ * src/c++17/memory_resource.cc (monotonic_buffer_resource::_Chunk):
+ Define.
+ (monotonic_buffer_resource::_M_new_buffer): Define.
+ (monotonic_buffer_resource::_M_release_buffers): Define.
+
2018-08-05 François Dumont <fdumont@gcc.gnu.org>
* include/bits/stl_iterator.h: Fix comment.
_ZNSt3pmr20null_memory_resourceEv;
_ZNSt3pmr20get_default_resourceEv;
_ZNSt3pmr20set_default_resourceEPNS_15memory_resourceE;
+ _ZNSt3pmr25monotonic_buffer_resource13_M_new_bufferE[jmy][jmy];
+ _ZNSt3pmr25monotonic_buffer_resource18_M_release_buffersEv;
} GLIBCXX_3.4.25;
void
release() noexcept
{
- _Chunk::release(_M_head, _M_upstream);
+ if (_M_head)
+ _M_release_buffers();
// reset to initial state at contruction:
if ((_M_current_buf = _M_orig_buf))
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))
+ void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail);
+ if (!__p)
{
- _M_current_buf = (char*)_M_current_buf + __bytes;
- _M_avail -= __bytes;
- return __p;
+ _M_new_buffer(__bytes, __alignment);
+ __p = _M_current_buf;
}
-
- 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;
+ _M_current_buf = (char*)_M_current_buf + __bytes;
+ _M_avail -= __bytes;
return __p;
}
{ return this == &__other; }
private:
+ // Update _M_current_buf and _M_avail to refer to a new buffer with
+ // at least the specified size and alignment, allocated from upstream.
+ void
+ _M_new_buffer(size_t __bytes, size_t __alignment);
+
+ // Deallocate all buffers obtained from upstream.
+ void
+ _M_release_buffers() noexcept;
+
static size_t
_S_next_bufsize(size_t __buffer_size) noexcept
{
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);
-
+ class _Chunk;
_Chunk* _M_head = nullptr;
};
get_default_resource() noexcept
{ return default_res.obj.load(); }
+ // Member functions for std::pmr::monotonic_buffer_resource
+
+ // 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 monotonic_buffer_resource::_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*)];
+ };
+
+ void
+ monotonic_buffer_resource::_M_new_buffer(size_t bytes, size_t alignment)
+ {
+ // Need to check this somewhere, so put it here:
+ static_assert(alignof(monotonic_buffer_resource::_Chunk) == 1);
+
+ 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 = p;
+ _M_avail = size;
+ _M_next_bufsiz *= _S_growth_factor;
+ }
+
+ void
+ monotonic_buffer_resource::_M_release_buffers() noexcept
+ {
+ _Chunk::release(_M_head, _M_upstream);
+ }
+
} // namespace pmr
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std