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_POOL_RESOURCE_HPP
12 #define BOOST_CONTAINER_POOL_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/pmr/memory_resource.hpp>
21 #include <boost/container/detail/block_list.hpp>
22 #include <boost/container/pmr/pool_options.hpp>
23 
24 #include <cstddef>
25 
26 namespace boost {
27 namespace container {
28 namespace pmr {
29 
30 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
31 
32 class pool_data_t;
33 
34 static const std::size_t pool_options_minimum_max_blocks_per_chunk = 1u;
35 static const std::size_t pool_options_default_max_blocks_per_chunk = 32u;
36 static const std::size_t pool_options_minimum_largest_required_pool_block =
37    memory_resource::max_align > 2*sizeof(void*) ? memory_resource::max_align : 2*sizeof(void*);
38 static const std::size_t pool_options_default_largest_required_pool_block =
39    pool_options_minimum_largest_required_pool_block > 4096u
40       ? pool_options_minimum_largest_required_pool_block : 4096u;
41 
42 #endif   //BOOST_CONTAINER_DOXYGEN_INVOKED
43 
44 class pool_resource
45 {
46    typedef block_list_base<> block_list_base_t;
47 
48    pool_options m_options;
49    memory_resource&   m_upstream;
50    block_list_base_t  m_oversized_list;
51    pool_data_t *m_pool_data;
52    std::size_t  m_pool_count;
53 
54    static void priv_limit_option(std::size_t &val, std::size_t min, std::size_t max);
55    static std::size_t priv_pool_index(std::size_t block_size);
56    static std::size_t priv_pool_block(std::size_t index);
57 
58    void priv_fix_options();
59    void priv_init_pools();
60    void priv_constructor_body();
61 
62    public:
63 
64    //! <b>Requires</b>: `upstream` is the address of a valid memory resource.
65    //!
66    //! <b>Effects</b>: Constructs a pool resource object that will obtain memory
67    //!   from upstream whenever the pool resource is unable to satisfy a memory
68    //!   request from its own internal data structures. The resulting object will hold
69    //!   a copy of upstream, but will not own the resource to which upstream points.
70    //!   [ Note: The intention is that calls to upstream->allocate() will be
71    //!   substantially fewer than calls to this->allocate() in most cases. - end note
72    //!   The behavior of the pooling mechanism is tuned according to the value of
73    //!   the opts argument.
74    //!
75    //! <b>Throws</b>: Nothing unless upstream->allocate() throws. It is unspecified if
76    //!   or under what conditions this constructor calls upstream->allocate().
77    pool_resource(const pool_options& opts, memory_resource* upstream) BOOST_NOEXCEPT;
78 
79    //! <b>Effects</b>: Same as
80    //!   `pool_resource(pool_options(), get_default_resource())`.
81    pool_resource() BOOST_NOEXCEPT;
82 
83    //! <b>Effects</b>: Same as
84    //!   `pool_resource(pool_options(), upstream)`.
85    explicit pool_resource(memory_resource* upstream) BOOST_NOEXCEPT;
86 
87    //! <b>Effects</b>: Same as
88    //!   `pool_resource(opts, get_default_resource())`.
89    explicit pool_resource(const pool_options& opts) BOOST_NOEXCEPT;
90 
91    #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
92    pool_resource(const pool_resource&) = delete;
93    pool_resource operator=(const pool_resource&) = delete;
94    #else
95    private:
96    pool_resource          (const pool_resource&);
97    pool_resource operator=(const pool_resource&);
98    public:
99    #endif
100 
101    //! <b>Effects</b>: Calls
102    //!   `this->release()`.
103    virtual ~pool_resource();
104 
105    //! <b>Effects</b>: Calls Calls `upstream_resource()->deallocate()` as necessary
106    //!   to release all allocated memory. [ Note: memory is released back to
107    //!   `upstream_resource()` even if deallocate has not been called for some
108    //!   of the allocated blocks. - end note ]
109    void release();
110 
111    //! <b>Returns</b>: The value of the upstream argument provided to the
112    //!   constructor of this object.
113    memory_resource* upstream_resource() const;
114 
115    //! <b>Returns</b>: The options that control the pooling behavior of this resource.
116    //!   The values in the returned struct may differ from those supplied to the pool
117    //!   resource constructor in that values of zero will be replaced with
118    //!   implementation-defined defaults and sizes may be rounded to unspecified granularity.
119    pool_options options() const;
120 
121    public:  //public so that [un]synchronized_pool_resource can use them
122 
123    //! <b>Returns</b>: A pointer to allocated storage with a size of at least `bytes`.
124    //!   The size and alignment of the allocated memory shall meet the requirements for
125    //!   a class derived from `memory_resource`.
126    //!
127    //! <b>Effects</b>: If the pool selected for a block of size bytes is unable to
128    //!   satisfy the memory request from its own internal data structures, it will call
129    //!   `upstream_resource()->allocate()` to obtain more memory. If `bytes` is larger
130    //!   than that which the largest pool can handle, then memory will be allocated
131    //!   using `upstream_resource()->allocate()`.
132    //!
133    //! <b>Throws</b>: Nothing unless `upstream_resource()->allocate()` throws.
134    virtual void* do_allocate(std::size_t bytes, std::size_t alignment);
135 
136    //! <b>Effects</b>: Return the memory at p to the pool. It is unspecified if or under
137    //!   what circumstances this operation will result in a call to
138    //!   `upstream_resource()->deallocate()`.
139    //!
140    //! <b>Throws</b>: Nothing.
141    virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment);
142 
143    //! <b>Returns</b>:
144    //!   `this == dynamic_cast<const pool_resource*>(&other)`.
145    virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT;
146 
147    //Non-standard observers
148    public:
149    //! <b>Returns</b>: The number of pools that will be used in the pool resource.
150    //!
151    //! <b>Note</b>: Non-standard extension.
152    std::size_t pool_count() const;
153 
154    //! <b>Returns</b>: The index of the pool that will be used to serve the allocation of `bytes`.
155    //!   from the pool specified by `pool_index`. Returns `pool_count()` if `bytes` is bigger
156    //!   than `options().largest_required_pool_block` (no pool will be used to serve this).
157    //!
158    //! <b>Note</b>: Non-standard extension.
159    std::size_t pool_index(std::size_t bytes) const;
160 
161    //! <b>Requires</b>: `pool_idx < pool_index()`
162    //!
163    //! <b>Returns</b>: The number blocks that will be allocated in the next chunk
164    //!   from the pool specified by `pool_idx`.
165    //!
166    //! <b>Note</b>: Non-standard extension.
167    std::size_t pool_next_blocks_per_chunk(std::size_t pool_idx) const;
168 
169    //! <b>Requires</b>: `pool_idx < pool_index()`
170    //!
171    //! <b>Returns</b>: The number of bytes of the block that the specified `pool_idx` pool manages.
172    //!
173    //! <b>Note</b>: Non-standard extension.
174    std::size_t pool_block(std::size_t pool_idx) const;
175 
176    //! <b>Requires</b>: `pool_idx < pool_index()`
177    //!
178    //! <b>Returns</b>: The number of blocks that the specified `pool_idx` pool has cached
179    //!   and will be served without calling the upstream_allocator.
180    //!
181    //! <b>Note</b>: Non-standard extension.
182    std::size_t pool_cached_blocks(std::size_t pool_idx) const;
183 };
184 
185 }  //namespace pmr {
186 }  //namespace container {
187 }  //namespace boost {
188 
189 #include <boost/container/detail/config_end.hpp>
190 
191 #endif   //BOOST_CONTAINER_POOL_RESOURCE_HPP
192