]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // | |
3 | // (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost | |
4 | // Software License, Version 1.0. (See accompanying file | |
5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // See http://www.boost.org/libs/container for documentation. | |
8 | // | |
9 | ////////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #ifndef BOOST_CONTAINER_PMR_MONOTONIC_BUFFER_RESOURCE_HPP | |
12 | #define BOOST_CONTAINER_PMR_MONOTONIC_BUFFER_RESOURCE_HPP | |
13 | ||
14 | #if defined (_MSC_VER) | |
15 | # pragma once | |
16 | #endif | |
17 | ||
18 | #include <boost/container/detail/config_begin.hpp> | |
19 | #include <boost/container/detail/workaround.hpp> | |
20 | #include <boost/container/detail/auto_link.hpp> | |
21 | #include <boost/container/pmr/memory_resource.hpp> | |
22 | #include <boost/container/detail/block_slist.hpp> | |
23 | ||
24 | #include <cstddef> | |
25 | ||
26 | namespace boost { | |
27 | namespace container { | |
28 | namespace pmr { | |
29 | ||
30 | //! A monotonic_buffer_resource is a special-purpose memory resource intended for | |
31 | //! very fast memory allocations in situations where memory is used to build up a | |
32 | //! few objects and then is released all at once when the memory resource object | |
33 | //! is destroyed. It has the following qualities: | |
34 | //! | |
35 | //! - A call to deallocate has no effect, thus the amount of memory consumed | |
36 | //! increases monotonically until the resource is destroyed. | |
37 | //! | |
38 | //! - The program can supply an initial buffer, which the allocator uses to satisfy | |
39 | //! memory requests. | |
40 | //! | |
41 | //! - When the initial buffer (if any) is exhausted, it obtains additional buffers | |
42 | //! from an upstream memory resource supplied at construction. Each additional | |
43 | //! buffer is larger than the previous one, following a geometric progression. | |
44 | //! | |
45 | //! - It is intended for access from one thread of control at a time. Specifically, | |
46 | //! calls to allocate and deallocate do not synchronize with one another. | |
47 | //! | |
48 | //! - It owns the allocated memory and frees it on destruction, even if deallocate has | |
49 | //! not been called for some of the allocated blocks. | |
50 | class BOOST_CONTAINER_DECL monotonic_buffer_resource | |
51 | : public memory_resource | |
52 | { | |
53 | block_slist m_memory_blocks; | |
54 | void* m_current_buffer; | |
55 | std::size_t m_current_buffer_size; | |
56 | std::size_t m_next_buffer_size; | |
57 | ||
58 | /// @cond | |
59 | void increase_next_buffer(); | |
60 | void increase_next_buffer_at_least_to(std::size_t minimum_size); | |
61 | void *allocate_from_current(std::size_t aligner, std::size_t bytes); | |
62 | /// @endcond | |
63 | ||
64 | public: | |
65 | ||
66 | //! The number of bytes that will be requested by the default in the first call | |
67 | //! to the upstream allocator | |
68 | //! | |
69 | //! <b>Note</b>: Non-standard extension. | |
70 | static const std::size_t initial_next_buffer_size = 32u*sizeof(void*); | |
71 | ||
72 | //! <b>Requires</b>: `upstream` shall be the address of a valid memory resource or `nullptr` | |
73 | //! | |
74 | //! <b>Effects</b>: If `upstream` is not nullptr, sets the internal resource to `upstream`, | |
75 | //! to get_default_resource() otherwise. | |
76 | //! Sets the internal `current_buffer` to `nullptr` and the internal `next_buffer_size` to an | |
77 | //! implementation-defined size. | |
78 | explicit monotonic_buffer_resource(memory_resource* upstream = 0) BOOST_NOEXCEPT; | |
79 | ||
80 | //! <b>Requires</b>: `upstream` shall be the address of a valid memory resource or `nullptr` | |
81 | //! and `initial_size` shall be greater than zero. | |
82 | //! | |
83 | //! <b>Effects</b>: If `upstream` is not nullptr, sets the internal resource to `upstream`, | |
84 | //! to get_default_resource() otherwise. Sets the internal `current_buffer` to `nullptr` and | |
85 | //! `next_buffer_size` to at least `initial_size`. | |
86 | explicit monotonic_buffer_resource(std::size_t initial_size, memory_resource* upstream = 0) BOOST_NOEXCEPT; | |
87 | ||
88 | //! <b>Requires</b>: `upstream` shall be the address of a valid memory resource or `nullptr`, | |
89 | //! `buffer_size` shall be no larger than the number of bytes in buffer. | |
90 | //! | |
91 | //! <b>Effects</b>: If `upstream` is not nullptr, sets the internal resource to `upstream`, | |
92 | //! to get_default_resource() otherwise. Sets the internal `current_buffer` to `buffer`, | |
93 | //! and `next_buffer_size` to `buffer_size` (but not less than an implementation-defined size), | |
94 | //! then increases `next_buffer_size` by an implementation-defined growth factor (which need not be integral). | |
95 | monotonic_buffer_resource(void* buffer, std::size_t buffer_size, memory_resource* upstream = 0) BOOST_NOEXCEPT; | |
96 | ||
97 | #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) | |
98 | monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; | |
99 | monotonic_buffer_resource operator=(const monotonic_buffer_resource&) = delete; | |
100 | #else | |
101 | private: | |
102 | monotonic_buffer_resource (const monotonic_buffer_resource&); | |
103 | monotonic_buffer_resource operator=(const monotonic_buffer_resource&); | |
104 | public: | |
105 | #endif | |
106 | ||
107 | //! <b>Effects</b>: Calls | |
108 | //! `this->release()`. | |
109 | virtual ~monotonic_buffer_resource(); | |
110 | ||
111 | //! <b>Effects</b>: `upstream_resource()->deallocate()` as necessary to release all allocated memory. | |
112 | //! [Note: memory is released back to `upstream_resource()` even if some blocks that were allocated | |
113 | //! from this have not been deallocated from this. - end note] | |
114 | void release() BOOST_NOEXCEPT; | |
115 | ||
116 | //! <b>Returns</b>: The value of | |
117 | //! the internal resource. | |
118 | memory_resource* upstream_resource() const BOOST_NOEXCEPT; | |
119 | ||
120 | //! <b>Returns</b>: | |
121 | //! The number of bytes of storage available for the specified alignment and | |
122 | //! the number of bytes wasted due to the requested alignment. | |
123 | //! | |
124 | //! <b>Note</b>: Non-standard extension. | |
125 | std::size_t remaining_storage(std::size_t alignment, std::size_t &wasted_due_to_alignment) const BOOST_NOEXCEPT; | |
126 | ||
127 | //! <b>Returns</b>: | |
128 | //! The number of bytes of storage available for the specified alignment. | |
129 | //! | |
130 | //! <b>Note</b>: Non-standard extension. | |
131 | std::size_t remaining_storage(std::size_t alignment = 1u) const BOOST_NOEXCEPT; | |
132 | ||
133 | //! <b>Returns</b>: | |
134 | //! The number of bytes of storage available for the specified alignment. | |
135 | //! | |
136 | //! <b>Note</b>: Non-standard extension. | |
137 | const void *current_buffer() const BOOST_NOEXCEPT; | |
138 | ||
139 | //! <b>Returns</b>: | |
140 | //! The number of bytes that will be requested for the next buffer once the | |
141 | //! current one is exhausted. | |
142 | //! | |
143 | //! <b>Note</b>: Non-standard extension. | |
144 | std::size_t next_buffer_size() const BOOST_NOEXCEPT; | |
145 | ||
146 | protected: | |
147 | ||
148 | //! <b>Returns</b>: A pointer to allocated storage with a size of at least `bytes`. The size | |
149 | //! and alignment of the allocated memory shall meet the requirements for a class derived | |
150 | //! from `memory_resource`. | |
151 | //! | |
152 | //! <b>Effects</b>: If the unused space in the internal `current_buffer` can fit a block with the specified | |
153 | //! bytes and alignment, then allocate the return block from the internal `current_buffer`; otherwise sets | |
154 | //! the internal `current_buffer` to `upstream_resource()->allocate(n, m)`, where `n` is not less than | |
155 | //! `max(bytes, next_buffer_size)` and `m` is not less than alignment, and increase | |
156 | //! `next_buffer_size` by an implementation-defined growth factor (which need not be integral), | |
157 | //! then allocate the return block from the newly-allocated internal `current_buffer`. | |
158 | //! | |
159 | //! <b>Throws</b>: Nothing unless `upstream_resource()->allocate()` throws. | |
160 | virtual void* do_allocate(std::size_t bytes, std::size_t alignment); | |
161 | ||
162 | //! <b>Effects</b>: None | |
163 | //! | |
164 | //! <b>Throws</b>: Nothing | |
165 | //! | |
166 | //! <b>Remarks</b>: Memory used by this resource increases monotonically until its destruction. | |
167 | virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_NOEXCEPT; | |
168 | ||
169 | //! <b>Returns</b>: | |
170 | //! `this == dynamic_cast<const monotonic_buffer_resource*>(&other)`. | |
171 | virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT; | |
172 | }; | |
173 | ||
174 | } //namespace pmr { | |
175 | } //namespace container { | |
176 | } //namespace boost { | |
177 | ||
178 | #include <boost/container/detail/config_end.hpp> | |
179 | ||
180 | #endif //BOOST_CONTAINER_PMR_MONOTONIC_BUFFER_RESOURCE_HPP |