Ocean
base/Memory.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_BASE_MEMORY_H
9 #define META_OCEAN_BASE_MEMORY_H
10 
11 #include "ocean/base/Base.h"
12 #include "ocean/base/Worker.h"
13 
14 namespace Ocean
15 {
16 
17 /**
18  * This class implements an object able to allocate memory.
19  * @ingroup base
20  */
21 class Memory
22 {
23  public:
24 
25  /**
26  * Creates a new object without any allocated memory.
27  */
28  Memory() = default;
29 
30  /**
31  * Move constructor.
32  * @param memory The memory object to be moved
33  */
34  inline Memory(Memory&& memory) noexcept;
35 
36  /**
37  * Creates a new object and allocates a specified amount of memory.
38  * This function allows to allocated memory with a specific byte alignment, so that the start address of the memory is a multiple of the specified alignment.
39  * @param size The size of the memory to be allocated in bytes, with range [0, infinity)
40  * @param alignment The memory byte alignment of the allocated memory, in bytes, with range [1, infinity)
41  */
42  explicit inline Memory(const size_t size, const size_t alignment = size_t(1));
43 
44  /**
45  * Creates a new object and uses externally allocated writable memory.
46  * This object will not be the owner of the memory, ensure that the external memory exists as long as this object exists.
47  * @param useData The external allocated memory which will be used, must be valid
48  * @param size The size of the external allocated memory, in bytes, with range [1, infinity)
49  */
50  inline Memory(void* useData, const size_t size);
51 
52  /**
53  * Creates a new object and uses externally allocated read-only memory.
54  * This object will not be the owner of the memory, ensure that the external memory exists as long as this object exists.
55  * @param useData The external allocated memory which will be used, must be valid
56  * @param size The size of the external allocated memory, in bytes, with range [1, infinity)
57  */
58  inline Memory(const void* useData, const size_t size);
59 
60  /**
61  * Releases the object and frees the memory if it holds any memory.
62  */
63  inline ~Memory();
64 
65  /**
66  * Returns the pointer to the read-only memory which is allocated by this object.
67  * @return The memory allocated by this object, nullptr if no memory is allocated
68  */
69  [[nodiscard]] inline const void* constdata() const;
70 
71  /**
72  * Returns the pointer to the writable memory which is allocated by this object.
73  * @return The memory allocated by this object, nullptr if no memory is allocated
74  */
75  [[nodiscard]] inline void* data();
76 
77  /**
78  * Returns the pointer to the read-only memory which is allocated by this object.
79  * @param checkAlignment True, to apply an assert checking the byte alignment of the specified data type
80  * @return The memory allocated by this object, nullptr if no memory is allocated
81  * @tparam T The data type of the returning pointer
82  */
83  template <typename T>
84  [[nodiscard]] inline const T* constdata(const bool checkAlignment = true) const;
85 
86  /**
87  * Returns the pointer to the writable memory which is allocated by this object.
88  * @param checkAlignment True, to apply an assert checking the byte alignment of the specified data type
89  * @return The memory allocated by this object, nullptr if no memory is allocated
90  * @tparam T The data type of the returning pointer
91  */
92  template <typename T>
93  [[nodiscard]] inline T* data(const bool checkAlignment = true);
94 
95  /**
96  * Returns whether a specified memory range is entirely enclosed inside the memory managed by this object.
97  * @param start The (inclusive) pointer to the start of the memory range to be checked, must be valid
98  * @param size The size of the memory range to be checked, in bytes, with range [0, infinity)
99  * @return True, if so or if 'size == 0'
100  */
101  [[nodiscard]] inline bool isInside(const void* const start, const size_t size) const;
102 
103  /**
104  * Returns whether a specified memory range is entirely enclosed inside the memory managed by this object.
105  * @param start The (inclusive) pointer to the start of the memory range to be checked, must be valid
106  * @param end The (exclusive) pointer to the first byte after the memory range to be checked, must be valid, with range [start, infinity)
107  * @return True, if so or if 'start == end'
108  */
109  [[nodiscard]] inline bool isInside(const void* const start, const void* const end) const;
110 
111  /**
112  * Explicitly frees (releases) the memory before this object is released.
113  */
114  inline void free();
115 
116  /**
117  * Returns the size of the memory in bytes.
118  * @return The memory's size in bytes, with range [0, infinity)
119  */
120  [[nodiscard]] inline size_t size() const;
121 
122  /**
123  * Returns whether this object owns the memory.
124  * @return True, if the memory is owned; False, if the memory is owned externally
125  */
126  [[nodiscard]] inline bool isOwner() const;
127 
128  /**
129  * Returns whether this object provides read-only memory only.
130  * @return True, if the memory is read-only; False, if the memory is writable
131  */
132  [[nodiscard]] inline bool isReadOnly() const;
133 
134  /**
135  * Returns whether this object holds any memory.
136  * @return True, if so
137  */
138  [[nodiscard]] inline bool isNull() const;
139 
140  /**
141  * Returns whether this object holds any memory.
142  * @return True, if so
143  */
144  [[nodiscard]] explicit inline operator bool() const;
145 
146  /**
147  * Move operator.
148  * @param memory The memory object to be moved
149  */
150  inline Memory& operator=(Memory&& memory) noexcept;
151 
152  /**
153  * Creates a new object and allocates enough memory necessary for 'elements' of type T.
154  * @param elements The number of elements of type T for which the new object will allocate memory, with range [0, infinity)
155  * @return The new memory object
156  * @tparam T The data type of the each element
157  */
158  template <typename T>
159  [[nodiscard]] static inline Memory create(const size_t elements);
160 
161  /**
162  * Copies a block of memory using a worker object to speed up the process.
163  * @param target The target memory receiving the memory
164  * @param source The source memory block
165  * @param size Number of bytes to be copied
166  * @param worker Optional worker object
167  */
168  static inline void memcpy(void* target, const void* source, const unsigned int size, Worker* worker = nullptr);
169 
170  /**
171  * Sets the value of a given memory block using a worker object to speed up the process.
172  * @param data Memory block to be set
173  * @param value The value to be set, only the first byte will be used as value
174  * @param size Number of bytes to be set
175  * @param worker Optional worker object
176  */
177  static inline void memset(void* data, const int value, const unsigned int size, Worker* worker = nullptr);
178 
179  protected:
180 
181  /**
182  * The disabled copy constructor.
183  * @param memory The memory object that would be copied
184  */
185  Memory(const Memory& memory) = delete;
186 
187  /**
188  * The disabled assign operator.
189  * @param memory The memory object that would be assigned
190  */
191  Memory& operator=(const Memory& memory) = delete;
192 
193  /**
194  * Copies a subset of the a memory block.
195  * @param target The target memory
196  * @param source The source memory
197  * @param firstByte First byte to be copied
198  * @param numberBytes Number of bytes to be copied
199  */
200  static inline void memcpySubset(uint8_t* target, const uint8_t* source, const unsigned int firstByte, const unsigned int numberBytes);
201 
202  /**
203  * Sets a subset of a given memory block.
204  * @param data Memory block to be set
205  * @param value the value to be set
206  * @param firstByte First byte to be set
207  * @param numberBytes Number of bytes to be set
208  */
209  static inline void memsetSubset(uint8_t* data, const int value, const unsigned int firstByte, const unsigned int numberBytes);
210 
211  protected:
212 
213  /// The pointer to the memory which is allocated and owned by this object, this pointer is pointing to the memory which needs to be freed when disposing the memory object.
214  void* allocatedData_ = nullptr;
215 
216  /// The pointer to the read-only aligned memory which is reported to be the actual memory pointer, this memory pointer must not be freed when disposing the memory object.
217  const void* constAlignedData_ = nullptr;
218 
219  /// The pointer to the writable aligned memory which is reported to be the actual memory pointer, this memory pointer must not be freed when disposing the memory object.
220  void* alignedData_ = nullptr;
221 
222  /// The size of the actual usable memory in bytes, with range [0, infinity)
223  size_t size_ = 0;
224 };
225 
226 inline Memory::Memory(Memory&& memory) noexcept :
227  Memory()
228 {
229  *this = std::move(memory);
230 }
231 
232 inline Memory::Memory(const size_t size, const size_t alignment) :
233  Memory()
234 {
235  ocean_assert(alignment >= size_t(1));
236 
237  if (size != size_t(0))
238  {
239  static_assert(sizeof(uint8_t) == 1, "Invalid data type!");
240 
241  allocatedData_ = malloc(size + alignment);
242  ocean_assert(allocatedData_ != nullptr);
243 
244  if (allocatedData_ != nullptr)
245  {
246  const size_t alignmentOffset = (alignment - (size_t(allocatedData_) % alignment)) % alignment;
247 
248  ocean_assert(alignmentOffset < alignment);
249  ocean_assert((size_t(allocatedData_) + alignmentOffset) % alignment == size_t(0));
250 
251  alignedData_ = (void*)(((uint8_t*)allocatedData_) + alignmentOffset);
252  ocean_assert(alignedData_ >= allocatedData_);
253 
254  constAlignedData_ = (const void*)(alignedData_);
255 
256  size_ = size;
257  }
258 
259  ocean_assert(isOwner());
260  ocean_assert(!isReadOnly());
261  }
262 }
263 
264 inline Memory::Memory(void* useData, const size_t size) :
265  alignedData_(useData),
266  size_(size)
267 {
268  ocean_assert(useData != nullptr);
269  ocean_assert(size > 0);
270 
271  constAlignedData_ = (const void*)(alignedData_);
272 
273  ocean_assert(allocatedData_ == nullptr);
274 
275  ocean_assert(!isOwner());
276  ocean_assert(!isReadOnly());
277 }
278 
279 inline Memory::Memory(const void* useData, const size_t size) :
280  constAlignedData_(useData),
281  size_(size)
282 {
283  ocean_assert(useData != nullptr);
284  ocean_assert(size > 0);
285 
286  ocean_assert(allocatedData_ == nullptr);
287  ocean_assert(alignedData_ == nullptr);
288 
289  ocean_assert(!isOwner());
290  ocean_assert(isReadOnly());
291 }
292 
294 {
295  free();
296 }
297 
298 inline const void* Memory::constdata() const
299 {
300  return constAlignedData_;
301 }
302 
303 inline void* Memory::data()
304 {
305  return alignedData_;
306 }
307 
308 template<typename T>
309 inline const T* Memory::constdata(const bool checkAlignment) const
310 {
311  if (checkAlignment)
312  {
313  ocean_assert((size_t(constAlignedData_) % sizeof(T)) == 0);
314  }
315 
316  return reinterpret_cast<const T*>(constAlignedData_);
317 }
318 
319 template<typename T>
320 inline T* Memory::data(const bool checkAlignment)
321 {
322  if (checkAlignment)
323  {
324  ocean_assert((size_t(alignedData_) % sizeof(T)) == 0);
325  }
326 
327  return reinterpret_cast<T*>(alignedData_);
328 }
329 
330 inline bool Memory::isInside(const void* const start, const size_t size) const
331 {
332  ocean_assert(start != nullptr);
333 
334  if (size == 0)
335  {
336  return true;
337  }
338 
339  if (constAlignedData_ == nullptr)
340  {
341  return false;
342  }
343 
344  const uint8_t* const start_u8 = (const uint8_t*)(start);
345  const uint8_t* const constAlignedData_u8 = (const uint8_t*)(constAlignedData_);
346 
347  return start_u8 >= constAlignedData_u8 && start_u8 + size <= constAlignedData_u8 + size_;
348 }
349 
350 inline bool Memory::isInside(const void* const start, const void* const end) const
351 {
352  ocean_assert(start != nullptr && end != nullptr);
353  ocean_assert(start <= end);
354 
355  if (start == end)
356  {
357  return true;
358  }
359 
360  if (constAlignedData_ == nullptr)
361  {
362  return false;
363  }
364 
365  const void* const constAlignedDataEnd = (const void*)((const uint8_t*)(constAlignedData_) + size_);
366 
367  return start >= constAlignedData_ && end <= constAlignedDataEnd && start < end;
368 }
369 
370 inline void Memory::free()
371 {
372  if (allocatedData_ != nullptr)
373  {
374  ocean_assert(alignedData_ != nullptr);
375 
377 
378  allocatedData_ = nullptr;
379  }
380 
381  constAlignedData_ = nullptr;
382  alignedData_ = nullptr;
383  size_ = size_t(0);
384 }
385 
386 inline size_t Memory::size() const
387 {
388  return size_;
389 }
390 
391 inline bool Memory::isOwner() const
392 {
393  return allocatedData_ != nullptr;
394 }
395 
396 inline bool Memory::isReadOnly() const
397 {
398  return alignedData_ == nullptr;
399 }
400 
401 inline bool Memory::isNull() const
402 {
403  ocean_assert((constAlignedData_ == nullptr && size_ == size_t(0)) || (constAlignedData_ != nullptr && size_ != size_t(0)));
404 
405  return constAlignedData_ == nullptr;
406 }
407 
408 inline Memory::operator bool() const
409 {
410  ocean_assert((constAlignedData_ == nullptr && size_ == size_t(0)) || (constAlignedData_ != nullptr && size_ != size_t(0)));
411 
412  return constAlignedData_ != nullptr;
413 }
414 
415 inline Memory& Memory::operator=(Memory&& memory) noexcept
416 {
417  if (this != &memory)
418  {
419  free();
420 
421  allocatedData_ = memory.allocatedData_;
422  constAlignedData_ = memory.constAlignedData_;
423  alignedData_ = memory.alignedData_;
424  size_ = memory.size_;
425 
426  memory.allocatedData_ = nullptr;
427  memory.constAlignedData_ = nullptr;
428  memory.alignedData_ = nullptr;
429  memory.size_ = size_t(0);
430  }
431 
432  return *this;
433 }
434 
435 template <typename T>
436 inline Memory Memory::create(const size_t elements)
437 {
438  return Memory(sizeof(T) * elements, sizeof(T) /* we fore the data-type specific alignment */);
439 }
440 
441 inline void Memory::memcpy(void* target, const void* source, const unsigned int size, Worker* worker)
442 {
443  if (worker)
444  {
445  worker->executeFunction(Worker::Function::createStatic(&Memory::memcpySubset, (uint8_t*)target, (const uint8_t*)source, 0u, 0u), 0u, size, 2u, 3u, 1024u);
446  }
447  else
448  {
449  ::memcpy(target, source, size);
450  }
451 }
452 
453 inline void Memory::memset(void* data, const int value, const unsigned int size, Worker* worker)
454 {
455  if (worker)
456  {
457  worker->executeFunction(Worker::Function::createStatic(&Memory::memsetSubset, (uint8_t*)data, value, 0u, 0u), 0u, size, 2u, 3u, 1024u);
458  }
459  else
460  {
461  ::memset(data, value, size);
462  }
463 }
464 
465 inline void Memory::memcpySubset(uint8_t* target, const uint8_t* source, const unsigned int firstByte, const unsigned int numberBytes)
466 {
467  ocean_assert(target != nullptr);
468  ocean_assert(source != nullptr);
469 
470  ::memcpy(target + firstByte, source + firstByte, numberBytes);
471 }
472 
473 inline void Memory::memsetSubset(uint8_t* data, const int value, const unsigned int firstByte, const unsigned int numberBytes)
474 {
475  ocean_assert(data != nullptr);
476 
477  ::memset(data + firstByte, value, numberBytes);
478 }
479 
480 }
481 
482 #endif // META_OCEAN_BASE_MEMORY_H
static Caller< void > createStatic(typename StaticFunctionPointerMaker< void, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass >::Type function)
Creates a new caller container for a static function with no function parameter.
Definition: Caller.h:2876
This class implements an object able to allocate memory.
Definition: base/Memory.h:22
bool isReadOnly() const
Returns whether this object provides read-only memory only.
Definition: base/Memory.h:396
static Memory create(const size_t elements)
Creates a new object and allocates enough memory necessary for 'elements' of type T.
Definition: base/Memory.h:436
bool isOwner() const
Returns whether this object owns the memory.
Definition: base/Memory.h:391
Memory(const Memory &memory)=delete
The disabled copy constructor.
bool isInside(const void *const start, const size_t size) const
Returns whether a specified memory range is entirely enclosed inside the memory managed by this objec...
Definition: base/Memory.h:330
size_t size() const
Returns the size of the memory in bytes.
Definition: base/Memory.h:386
static void memcpySubset(uint8_t *target, const uint8_t *source, const unsigned int firstByte, const unsigned int numberBytes)
Copies a subset of the a memory block.
Definition: base/Memory.h:465
void * allocatedData_
The pointer to the memory which is allocated and owned by this object, this pointer is pointing to th...
Definition: base/Memory.h:214
bool isNull() const
Returns whether this object holds any memory.
Definition: base/Memory.h:401
static void memset(void *data, const int value, const unsigned int size, Worker *worker=nullptr)
Sets the value of a given memory block using a worker object to speed up the process.
Definition: base/Memory.h:453
size_t size_
The size of the actual usable memory in bytes, with range [0, infinity)
Definition: base/Memory.h:223
const void * constAlignedData_
The pointer to the read-only aligned memory which is reported to be the actual memory pointer,...
Definition: base/Memory.h:217
Memory & operator=(Memory &&memory) noexcept
Move operator.
Definition: base/Memory.h:415
Memory()=default
Creates a new object without any allocated memory.
void * data()
Returns the pointer to the writable memory which is allocated by this object.
Definition: base/Memory.h:303
static void memcpy(void *target, const void *source, const unsigned int size, Worker *worker=nullptr)
Copies a block of memory using a worker object to speed up the process.
Definition: base/Memory.h:441
static void memsetSubset(uint8_t *data, const int value, const unsigned int firstByte, const unsigned int numberBytes)
Sets a subset of a given memory block.
Definition: base/Memory.h:473
const void * constdata() const
Returns the pointer to the read-only memory which is allocated by this object.
Definition: base/Memory.h:298
~Memory()
Releases the object and frees the memory if it holds any memory.
Definition: base/Memory.h:293
void * alignedData_
The pointer to the writable aligned memory which is reported to be the actual memory pointer,...
Definition: base/Memory.h:220
void free()
Explicitly frees (releases) the memory before this object is released.
Definition: base/Memory.h:370
Memory & operator=(const Memory &memory)=delete
The disabled assign operator.
This class implements a worker able to distribute function calls over different threads.
Definition: Worker.h:33
bool executeFunction(const Function &function, const unsigned int first, const unsigned int size, const unsigned int firstIndex=(unsigned int)(-1), const unsigned int sizeIndex=(unsigned int)(-1), const unsigned int minimalIterations=1u, const unsigned int threadIndex=(unsigned int)(-1))
Executes a callback function separable by two function parameters.
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15