1 /*
2  * Portions of this file are copyright Rebirth contributors and licensed as
3  * described in COPYING.txt.
4  * Portions of this file are copyright Parallax Software and licensed
5  * according to the Parallax license below.
6  * See COPYING.txt for license details.
7 
8 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
9 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
10 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
11 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
12 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
13 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
14 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
15 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
16 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
17 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
18 */
19 
20 #pragma once
21 
22 #include <stdlib.h>
23 #include <type_traits>
24 
25 #ifdef __cplusplus
26 #include <memory>
27 #include "dxxsconf.h"
28 #include "dsx-ns.h"
29 #include <utility>
30 
31 #define MEM_K 1.5	// Dynamic array growth factor
32 
33 #ifdef DEBUG_BIAS_MEMORY_ALLOCATIONS
34 #include <array>
35 #define DXX_DEBUG_BIAS_MEMORY_ALLOCATION (sizeof(std::array<double, 2>))
36 #else
37 #define DXX_DEBUG_BIAS_MEMORY_ALLOCATION (0)
38 #endif
39 
40 namespace dcx {
41 
42 #ifdef DEBUG_MEMORY_ALLOCATIONS
43 void mem_init(void);
44 
45 void mem_display_blocks();
46 __attribute_alloc_size(1)
47 __attribute_malloc()
48 void *mem_malloc(size_t size, const char *var, const char *file, unsigned line);
49 void * mem_calloc( size_t nmemb, size_t size, const char * var, const char * filename, unsigned line) __attribute_alloc_size(1,2) __attribute_malloc();
50 __attribute_alloc_size(2)
51 void *mem_realloc(void *buffer, size_t size, const char *var, const char *file, unsigned line);
52 extern void mem_free( void * buffer );
53 
54 /* DPH: Changed malloc, etc. to d_malloc. Overloading system calls is very evil and error prone */
55 
56 // Checks to see if any blocks are overwritten
57 void mem_validate_heap();
58 
59 #define mem_calloc(nmemb,size,var,file,line)	((mem_calloc)((size) ? (nmemb) : 0, (size), (var), (file), (line)))
60 
61 #else
62 
63 #ifdef DEBUG_BIAS_MEMORY_ALLOCATIONS
64 #define bias_malloc(SIZE)	({	\
65 		auto p = malloc((SIZE) + DXX_DEBUG_BIAS_MEMORY_ALLOCATION);	\
66 		p ? p + DXX_DEBUG_BIAS_MEMORY_ALLOCATION : p;	\
67 	})
68 /* Bias calloc wastes a bit extra to keep the math simple */
69 #define bias_calloc(NMEMB,SIZE)	({	\
70 		auto p = calloc((NMEMB), (SIZE) + DXX_DEBUG_BIAS_MEMORY_ALLOCATION);	\
71 		p ? p + DXX_DEBUG_BIAS_MEMORY_ALLOCATION : p;	\
72 	})
73 #define bias_realloc(PTR,SIZE)	({	\
74 		auto p = realloc(reinterpret_cast<char *>(PTR) - DXX_DEBUG_BIAS_MEMORY_ALLOCATION, (SIZE) + DXX_DEBUG_BIAS_MEMORY_ALLOCATION);	\
75 		p ? p + DXX_DEBUG_BIAS_MEMORY_ALLOCATION : p;	\
76 	})
77 #define bias_free(PTR)	free(reinterpret_cast<char *>(PTR) - DXX_DEBUG_BIAS_MEMORY_ALLOCATION)
78 #else
79 #define bias_malloc	malloc
80 #define bias_calloc calloc
81 #define bias_realloc realloc
82 #define bias_free free
83 #endif
84 
85 #define mem_malloc(size,var,file,line)	((void)var,(void)file,(void)line,bias_malloc((size)))
86 #define mem_calloc(nmemb,size,var,file,line)	((void)var,(void)file,(void)line,bias_calloc((nmemb),(size)))
87 #define mem_realloc(ptr,size,var,file,line)	((void)var,(void)file,(void)line,bias_realloc((ptr),(size)))
88 #define mem_free	bias_free
89 
90 static inline void mem_init(void)
91 {
92 }
93 #endif
94 
95 template <typename T>
MALLOC(T * & r,std::size_t count,const char * var,const char * file,unsigned line)96 T *MALLOC(T *&r, std::size_t count, const char *var, const char *file, unsigned line)
97 {
98 	static_assert(std::is_pod<T>::value, "MALLOC cannot allocate non-POD");
99 	return r = reinterpret_cast<T *>(mem_malloc(count * sizeof(T), var, file, line));
100 }
101 
102 template <typename T>
CALLOC(T * & r,std::size_t count,const char * var,const char * file,unsigned line)103 T *CALLOC(T *&r, std::size_t count, const char *var, const char *file, unsigned line)
104 {
105 	static_assert(std::is_pod<T>::value, "CALLOC cannot allocate non-POD");
106 	return r = reinterpret_cast<T *>(mem_calloc(count, sizeof(T), var, file, line));
107 }
108 
109 #define d_malloc(size)      mem_malloc((size),"Unknown", __FILE__,__LINE__ )
110 #define d_realloc(ptr,size) mem_realloc((ptr),(size),"Unknown", __FILE__,__LINE__ )
111 template <typename T>
d_free(T * & ptr)112 static inline void d_free(T *&ptr)
113 {
114 	static_assert((std::is_same<T, void>::value || std::is_pod<T>::value), "d_free cannot free non-POD");
115 	mem_free(std::exchange(ptr, nullptr));
116 }
117 
118 template <typename T>
119 class RAIIdmem_deleter
120 {
121 public:
operator()122 	void operator()(T *v) const
123 	{
124 		d_free(v);
125 	}
126 };
127 
128 template <typename T>
129 class RAIIdmem_deleter<T[]> : public RAIIdmem_deleter<T>
130 {
131 public:
132 	typedef T *pointer;
133 };
134 
135 template <typename T>
136 class RAIIdmem : public std::unique_ptr<T, RAIIdmem_deleter<T>>
137 {
138 	typedef std::unique_ptr<T, RAIIdmem_deleter<T>> base_ptr;
139 public:
140 	static_assert(std::is_pod<typename base_ptr::element_type>::value, "RAIIdmem cannot manage non-POD");
141 	DXX_INHERIT_CONSTRUCTORS(RAIIdmem, base_ptr);
142 };
143 
144 /* Disallow C-style arrays of known bound.  Use RAIIdmem<std::array<T, N>>
145  * for this case.
146  */
147 template <typename T, std::size_t N>
148 class RAIIdmem<T[N]>
149 {
150 public:
151 	RAIIdmem() = delete;
152 };
153 
154 template <typename T>
MALLOC(RAIIdmem<T> & r,std::size_t count,const char * var,const char * file,unsigned line)155 RAIIdmem<T> &MALLOC(RAIIdmem<T> &r, std::size_t count, const char *var, const char *file, unsigned line)
156 {
157 	typename RAIIdmem<T>::pointer p;
158 	return r.reset(MALLOC<typename RAIIdmem<T>::element_type>(p, count, var, file, line)), r;
159 }
160 
161 template <typename T>
CALLOC(RAIIdmem<T> & r,std::size_t count,const char * var,const char * file,unsigned line)162 void CALLOC(RAIIdmem<T> &r, std::size_t count, const char *var, const char *file, unsigned line)
163 {
164 	typename RAIIdmem<T>::pointer p;
165 	r.reset(CALLOC<typename RAIIdmem<T>::element_type>(p, count, var, file, line));
166 }
167 
168 #define MALLOC( var, type, count )	(MALLOC<type>(var, (count),#var, __FILE__,__LINE__ ))
169 #define CALLOC( var, type, count )	(CALLOC<type>(var, (count),#var, __FILE__,__LINE__ ))
170 
171 }
172 
173 #endif
174