1 /*
2 * Copyright 2018 NVIDIA Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*! \file mr/memory_resource.h
18 * \brief A base class for the memory resource system, similar to std::memory_resource,
19 * and related utilities.
20 */
21
22 #pragma once
23
24 #include "detail/config.h"
25 #ifdef THRUST_MR_STD_MR_HEADER
26 # include THRUST_MR_STD_MR_HEADER
27 #endif
28
29 namespace thrust
30 {
31 /*! \brief \p thrust::mr is the namespace containing system agnostic types and functions for \p memory_resource related functionalities.
32 */
33 namespace mr
34 {
35
36 /*! \addtogroup memory_management Memory Management
37 * \addtogroup memory_management_classes Memory Management Classes
38 * \addtogroup memory_resources Memory Resources
39 * \ingroup memory_management
40 * \{
41 */
42
43 /*! \p memory_resource is the base class for all other memory resources.
44 *
45 * \tparam Pointer the pointer type that is allocated and deallocated by the memory resource
46 * derived from this base class. If this is <tt>void *</tt>, this class derives from
47 * <tt>std::pmr::memory_resource</tt>.
48 */
49 template<typename Pointer = void *>
50 class memory_resource
51 {
52 public:
53 /*! Alias for the template parameter.
54 */
55 typedef Pointer pointer;
56
57 /*! Virtual destructor, defaulted when possible.
58 */
~memory_resource()59 virtual ~memory_resource() THRUST_DEFAULT
60
61 /*! Allocates memory of size at least \p bytes and alignment at least \p alignment.
62 *
63 * \param bytes size, in bytes, that is requested from this allocation
64 * \param alignment alignment that is requested from this allocation
65 * \throws thrust::bad_alloc when no memory with requested size and alignment can be allocated.
66 * \returns A pointer to void to the newly allocated memory.
67 */
68 THRUST_NODISCARD
69 pointer allocate(std::size_t bytes, std::size_t alignment = THRUST_MR_DEFAULT_ALIGNMENT)
70 {
71 return do_allocate(bytes, alignment);
72 }
73
74 /*! Deallocates memory pointed to by \p p.
75 *
76 * \param p pointer to be deallocated
77 * \param bytes the size of the allocation. This must be equivalent to the value of \p bytes that
78 * was passed to the allocation function that returned \p p.
79 * \param alignment the alignment of the allocation. This must be equivalent to the value of \p alignment
80 * that was passed to the allocation function that returned \p p.
81 */
82 void deallocate(pointer p, std::size_t bytes, std::size_t alignment = THRUST_MR_DEFAULT_ALIGNMENT)
83 {
84 do_deallocate(p, bytes, alignment);
85 }
86
87 /*! Compares this resource to the other one. The default implementation uses identity comparison,
88 * which is often the right thing to do and doesn't require RTTI involvement.
89 *
90 * \param other the other resource to compare this resource to
91 * \returns whether the two resources are equivalent.
92 */
93 __host__ __device__
is_equal(const memory_resource & other)94 bool is_equal(const memory_resource & other) const THRUST_NOEXCEPT
95 {
96 return do_is_equal(other);
97 }
98
99 /*! Allocates memory of size at least \p bytes and alignment at least \p alignment.
100 *
101 * \param bytes size, in bytes, that is requested from this allocation
102 * \param alignment alignment that is requested from this allocation
103 * \throws thrust::bad_alloc when no memory with requested size and alignment can be allocated.
104 * \returns A pointer to void to the newly allocated memory.
105 */
106 virtual pointer do_allocate(std::size_t bytes, std::size_t alignment) = 0;
107
108 /*! Deallocates memory pointed to by \p p.
109 *
110 * \param p pointer to be deallocated
111 * \param bytes the size of the allocation. This must be equivalent to the value of \p bytes that
112 * was passed to the allocation function that returned \p p.
113 * \param alignment the size of the allocation. This must be equivalent to the value of \p alignment
114 * that was passed to the allocation function that returned \p p.
115 */
116 virtual void do_deallocate(pointer p, std::size_t bytes, std::size_t alignment) = 0;
117
118 /*! Compares this resource to the other one. The default implementation uses identity comparison,
119 * which is often the right thing to do and doesn't require RTTI involvement.
120 *
121 * \param other the other resource to compare this resource to
122 * \returns whether the two resources are equivalent.
123 */
124 __host__ __device__
do_is_equal(const memory_resource & other)125 virtual bool do_is_equal(const memory_resource & other) const THRUST_NOEXCEPT
126 {
127 return this == &other;
128 }
129 };
130
131 /*! The specialization of \p memory_resource for <tt>void *</tt>.
132 */
133 template<>
134 class memory_resource<void *>
135 #ifdef THRUST_STD_MR_NS
136 : THRUST_STD_MR_NS::memory_resource
137 #endif
138 {
139 public:
140 typedef void * pointer;
141
~memory_resource()142 virtual ~memory_resource() THRUST_DEFAULT
143
144 THRUST_NODISCARD
145 pointer allocate(std::size_t bytes, std::size_t alignment = THRUST_MR_DEFAULT_ALIGNMENT)
146 {
147 return do_allocate(bytes, alignment);
148 }
149
150 void deallocate(pointer p, std::size_t bytes, std::size_t alignment = THRUST_MR_DEFAULT_ALIGNMENT)
151 {
152 do_deallocate(p, bytes, alignment);
153 }
154
155 __host__ __device__
is_equal(const memory_resource & other)156 bool is_equal(const memory_resource & other) const THRUST_NOEXCEPT
157 {
158 return do_is_equal(other);
159 }
160
161 virtual pointer do_allocate(std::size_t bytes, std::size_t alignment) = 0;
162 virtual void do_deallocate(pointer p, std::size_t bytes, std::size_t alignment) = 0;
163 __host__ __device__
do_is_equal(const memory_resource & other)164 virtual bool do_is_equal(const memory_resource & other) const THRUST_NOEXCEPT
165 {
166 return this == &other;
167 }
168
169 #ifdef THRUST_STD_MR_NS
170 // the above do_is_equal is a different function than the one from the standard memory resource
171 // can't implement this reasonably without RTTI though; it's reasonable to assume false otherwise
172
do_is_equal(const THRUST_STD_MR_NS::memory_resource & other)173 virtual bool do_is_equal(const THRUST_STD_MR_NS::memory_resource & other) const noexcept override
174 {
175 # ifdef THRUST_HAS_DYNAMIC_CAST
176 auto mr_resource = dynamic_cast<memory_resource<> *>(&other);
177 return mr_resource && do_is_equal(*mr_resource);
178 # else
179 return this == &other;
180 # endif
181 }
182 #endif
183 };
184
185 /*! Compares the memory resources for equality, first by identity, then by \p is_equal.
186 */
187 template<typename Pointer>
188 __host__ __device__
189 bool operator==(const memory_resource<Pointer> & lhs, const memory_resource<Pointer> & rhs) THRUST_NOEXCEPT
190 {
191 return &lhs == &rhs || rhs.is_equal(rhs);
192 }
193
194 /*! Compares the memory resources for inequality, first by identity, then by \p is_equal.
195 */
196 template<typename Pointer>
197 __host__ __device__
198 bool operator!=(const memory_resource<Pointer> & lhs, const memory_resource<Pointer> & rhs) THRUST_NOEXCEPT
199 {
200 return !(lhs == rhs);
201 }
202
203 /*! Returns a global instance of \p MR, created as a function local static variable.
204 *
205 * \tparam MR type of a memory resource to get an instance from. Must be \p DefaultConstructible.
206 * \returns a pointer to a global instance of \p MR.
207 */
208 template<typename MR>
209 __host__
get_global_resource()210 MR * get_global_resource()
211 {
212 static MR resource;
213 return &resource;
214 }
215
216 /*! \}
217 */
218
219 } // end mr
220 } // end thrust
221
222