1/**************************************************************************/
2/* memory.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef MEMORY_H
32#define MEMORY_H
33
34#include "core/error/error_macros.h"
35#include "core/templates/safe_refcount.h"
36
37#include <stddef.h>
38#include <new>
39#include <type_traits>
40
41#ifndef PAD_ALIGN
42#define PAD_ALIGN 16 //must always be greater than this at much
43#endif
44
45class Memory {
46#ifdef DEBUG_ENABLED
47 static SafeNumeric<uint64_t> mem_usage;
48 static SafeNumeric<uint64_t> max_usage;
49#endif
50
51 static SafeNumeric<uint64_t> alloc_count;
52
53public:
54 static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
55 static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false);
56 static void free_static(void *p_ptr, bool p_pad_align = false);
57
58 static uint64_t get_mem_available();
59 static uint64_t get_mem_usage();
60 static uint64_t get_mem_max_usage();
61};
62
63class DefaultAllocator {
64public:
65 _FORCE_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory, false); }
66 _FORCE_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr, false); }
67};
68
69void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
70void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
71
72void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
73
74#ifdef _MSC_VER
75// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291).
76// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete.
77void operator delete(void *p_mem, const char *p_description);
78void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size));
79void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description);
80#endif
81
82#define memalloc(m_size) Memory::alloc_static(m_size)
83#define memrealloc(m_mem, m_size) Memory::realloc_static(m_mem, m_size)
84#define memfree(m_mem) Memory::free_static(m_mem)
85
86_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
87
88template <class T>
89_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
90 postinitialize_handler(p_obj);
91 return p_obj;
92}
93
94#define memnew(m_class) _post_initialize(new ("") m_class)
95
96#define memnew_allocator(m_class, m_allocator) _post_initialize(new (m_allocator::alloc) m_class)
97#define memnew_placement(m_placement, m_class) _post_initialize(new (m_placement) m_class)
98
99_ALWAYS_INLINE_ bool predelete_handler(void *) {
100 return true;
101}
102
103template <class T>
104void memdelete(T *p_class) {
105 if (!predelete_handler(p_class)) {
106 return; // doesn't want to be deleted
107 }
108 if (!std::is_trivially_destructible<T>::value) {
109 p_class->~T();
110 }
111
112 Memory::free_static(p_class, false);
113}
114
115template <class T, class A>
116void memdelete_allocator(T *p_class) {
117 if (!predelete_handler(p_class)) {
118 return; // doesn't want to be deleted
119 }
120 if (!std::is_trivially_destructible<T>::value) {
121 p_class->~T();
122 }
123
124 A::free(p_class);
125}
126
127#define memdelete_notnull(m_v) \
128 { \
129 if (m_v) { \
130 memdelete(m_v); \
131 } \
132 }
133
134#define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
135
136template <typename T>
137T *memnew_arr_template(size_t p_elements) {
138 if (p_elements == 0) {
139 return nullptr;
140 }
141 /** overloading operator new[] cannot be done , because it may not return the real allocated address (it may pad the 'element count' before the actual array). Because of that, it must be done by hand. This is the
142 same strategy used by std::vector, and the Vector class, so it should be safe.*/
143
144 size_t len = sizeof(T) * p_elements;
145 uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true);
146 T *failptr = nullptr; //get rid of a warning
147 ERR_FAIL_NULL_V(mem, failptr);
148 *(mem - 1) = p_elements;
149
150 if (!std::is_trivially_constructible<T>::value) {
151 T *elems = (T *)mem;
152
153 /* call operator new */
154 for (size_t i = 0; i < p_elements; i++) {
155 new (&elems[i]) T;
156 }
157 }
158
159 return (T *)mem;
160}
161
162/**
163 * Wonders of having own array functions, you can actually check the length of
164 * an allocated-with memnew_arr() array
165 */
166
167template <typename T>
168size_t memarr_len(const T *p_class) {
169 uint64_t *ptr = (uint64_t *)p_class;
170 return *(ptr - 1);
171}
172
173template <typename T>
174void memdelete_arr(T *p_class) {
175 uint64_t *ptr = (uint64_t *)p_class;
176
177 if (!std::is_trivially_destructible<T>::value) {
178 uint64_t elem_count = *(ptr - 1);
179
180 for (uint64_t i = 0; i < elem_count; i++) {
181 p_class[i].~T();
182 }
183 }
184
185 Memory::free_static(ptr, true);
186}
187
188struct _GlobalNil {
189 int color = 1;
190 _GlobalNil *right = nullptr;
191 _GlobalNil *left = nullptr;
192 _GlobalNil *parent = nullptr;
193
194 _GlobalNil();
195};
196
197struct _GlobalNilClass {
198 static _GlobalNil _nil;
199};
200
201template <class T>
202class DefaultTypedAllocator {
203public:
204 template <class... Args>
205 _FORCE_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
206 _FORCE_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
207};
208
209#endif // MEMORY_H
210