1 /* melder_alloc.cpp
2 *
3 * Copyright (C) 1992-2007,2009,2011,2012,2014-2020 Paul Boersma
4 *
5 * This code is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * This code is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this work. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "melder.h"
20 #include <wctype.h>
21 #include <assert.h>
22
23 static int64 totalNumberOfAllocations = 0, totalNumberOfDeallocations = 0, totalAllocationSize = 0,
24 totalNumberOfMovingReallocs = 0, totalNumberOfReallocsInSitu = 0;
25
26 /*
27 * The rainy-day fund.
28 *
29 * Typically, memory allocation for data is entirely checked by using the normal versions of the allocation routines,
30 * which will call Melder_error if they are out of memory.
31 * When data allocation is indeed out of memory,
32 * the application will present an error message to the user saying that the data could not be created.
33 *
34 * By contrast, it is not practical to check the allocation of user interface elements,
35 * because the application cannot perform correctly if an interface element is missing or incorrect.
36 * For such situations, the application will typically use the _f versions of the allocation routines,
37 * which, if out of memory, will free a "rainy-day fund" and retry.
38 * In this way, the interface element can usually still be allocated;
39 * the application will present an error message telling the user to save her work and quit the application.
40 * If the user doesn't do that, the application will crash upon the next failing allocation of a _f routine.
41 */
42
43 #define theRainyDayFund_SIZE 3'000'000
44 static char *theRainyDayFund = nullptr;
45
Melder_alloc_init()46 void Melder_alloc_init () {
47 theRainyDayFund = (char *) malloc (theRainyDayFund_SIZE); // called at application initialization, so cannot fail
48 assert (theRainyDayFund);
49 }
50
51 /*
52 The following functions take int64 arguments even on 32-bit machines.
53 This is because it is easy for the user to request objects that do not fit in memory
54 on 32-bit machines, in which case an appropriate error message is required.
55 */
56
_Melder_malloc(int64 size)57 void * _Melder_malloc (int64 size) {
58 if (size <= 0)
59 Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" bytes.");
60 if (sizeof (size_t) < 8 && size > SIZE_MAX)
61 Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" bytes. Use a 64-bit edition of Praat instead?");
62 void *result = malloc ((size_t) size); // guarded cast
63 if (! result)
64 Melder_throw (U"Out of memory: there is not enough room for another ", Melder_bigInteger (size), U" bytes.");
65 if (Melder_debug == 34)
66 Melder_casual (U"Melder_malloc\t", Melder_pointer (result), U"\t", Melder_bigInteger (size), U"\t1");
67 totalNumberOfAllocations += 1;
68 totalAllocationSize += size;
69 return result;
70 }
71
_Melder_malloc_f(int64 size)72 void * _Melder_malloc_f (int64 size) {
73 if (size <= 0)
74 Melder_fatal (U"(Melder_malloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes.");
75 if (sizeof (size_t) < 8 && size > SIZE_MAX)
76 Melder_fatal (U"(Melder_malloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes.");
77 void *result = malloc ((size_t) size);
78 if (! result) {
79 if (theRainyDayFund) {
80 free (theRainyDayFund);
81 theRainyDayFund = nullptr;
82 }
83 result = malloc ((size_t) size);
84 if (result)
85 Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
86 else
87 Melder_fatal (U"Out of memory: there is not enough room for another ", Melder_bigInteger (size), U" bytes.");
88 }
89 totalNumberOfAllocations += 1;
90 totalAllocationSize += size;
91 return result;
92 }
93
_Melder_free(void ** ptr)94 void _Melder_free (void **ptr) noexcept {
95 if (! *ptr)
96 return;
97 if (Melder_debug == 34)
98 Melder_casual (U"Melder_free\t", Melder_pointer (*ptr), U"\t?\t?");
99 free (*ptr);
100 *ptr = nullptr;
101 totalNumberOfDeallocations += 1;
102 }
103
Melder_realloc(void * ptr,int64 size)104 void * Melder_realloc (void *ptr, int64 size) {
105 if (size <= 0)
106 Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" bytes.");
107 if (sizeof (size_t) < 8 && size > SIZE_MAX)
108 Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" bytes. Use a 64-bit edition of Praat instead?");
109 void *result = realloc (ptr, (size_t) size); // will not show in the statistics...
110 if (! result)
111 Melder_throw (U"Out of memory. Could not extend room to ", Melder_bigInteger (size), U" bytes.");
112 if (! ptr) { // is it like malloc?
113 if (Melder_debug == 34)
114 Melder_casual (U"Melder_realloc\t", Melder_pointer (result), U"\t", Melder_bigInteger (size), U"\t1");
115 totalNumberOfAllocations += 1;
116 totalAllocationSize += size;
117 } else if (result != ptr) { // did realloc do a malloc-and-free?
118 totalNumberOfAllocations += 1;
119 totalAllocationSize += size;
120 totalNumberOfDeallocations += 1;
121 totalNumberOfMovingReallocs += 1;
122 } else {
123 totalNumberOfReallocsInSitu += 1;
124 }
125 return result;
126 }
127
Melder_realloc_f(void * ptr,int64 size)128 void * Melder_realloc_f (void *ptr, int64 size) {
129 if (size <= 0)
130 Melder_fatal (U"(Melder_realloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes.");
131 if (sizeof (size_t) < 8 && size > SIZE_MAX)
132 Melder_fatal (U"(Melder_realloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes.");
133 void *result = realloc (ptr, (size_t) size); // will not show in the statistics...
134 if (! result) {
135 if (theRainyDayFund) {
136 free (theRainyDayFund);
137 theRainyDayFund = nullptr;
138 }
139 result = realloc (ptr, (size_t) size);
140 if (result)
141 Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
142 else
143 Melder_fatal (U"Out of memory. Could not extend room to ", Melder_bigInteger (size), U" bytes.");
144 }
145 if (! ptr) { // is it like malloc?
146 totalNumberOfAllocations += 1;
147 totalAllocationSize += size;
148 } else if (result != ptr) { // did realloc do a malloc-and-free?
149 totalNumberOfAllocations += 1;
150 totalAllocationSize += size;
151 totalNumberOfDeallocations += 1;
152 totalNumberOfMovingReallocs += 1;
153 } else {
154 totalNumberOfReallocsInSitu += 1;
155 }
156 return result;
157 }
158
_Melder_calloc(int64 nelem,int64 elsize)159 void * _Melder_calloc (int64 nelem, int64 elsize) {
160 if (nelem <= 0)
161 Melder_throw (U"Can never allocate ", Melder_bigInteger (nelem), U" elements.");
162 if (elsize <= 0)
163 Melder_throw (U"Can never allocate elements whose size is ", Melder_bigInteger (elsize), U" bytes.");
164 if ((uint64) nelem > SIZE_MAX / (uint64) elsize) // guarded casts to unsigned
165 Melder_throw (U"Can never allocate ", Melder_bigInteger (nelem), U" elements whose sizes are ", Melder_bigInteger (elsize), U" bytes each.",
166 sizeof (size_t) < 8 ? U" Use a 64-bit edition of Praat instead?" : nullptr);
167 void *result = calloc ((size_t) nelem, (size_t) elsize);
168 if (! result)
169 Melder_throw (U"Out of memory: there is not enough room for ", Melder_bigInteger (nelem), U" more elements whose sizes are ", elsize, U" bytes each.");
170 if (Melder_debug == 34)
171 Melder_casual (U"Melder_calloc\t", Melder_pointer (result), U"\t", Melder_bigInteger (nelem), U"\t", Melder_bigInteger (elsize));
172 totalNumberOfAllocations += 1;
173 totalAllocationSize += nelem * elsize;
174 return result;
175 }
176
_Melder_calloc_f(int64 nelem,int64 elsize)177 void * _Melder_calloc_f (int64 nelem, int64 elsize) {
178 if (nelem <= 0)
179 Melder_fatal (U"(Melder_calloc_f:) Can never allocate ", Melder_bigInteger (nelem), U" elements.");
180 if (elsize <= 0)
181 Melder_fatal (U"(Melder_calloc_f:) Can never allocate elements whose size is ", Melder_bigInteger (elsize), U" bytes.");
182 if ((uint64) nelem > SIZE_MAX / (uint64) elsize)
183 Melder_fatal (U"(Melder_calloc_f:) Can never allocate ", Melder_bigInteger (nelem), U" elements whose sizes are ", Melder_bigInteger (elsize), U" bytes each.");
184 void *result = calloc ((size_t) nelem, (size_t) elsize);
185 if (! result) {
186 if (theRainyDayFund) {
187 free (theRainyDayFund);
188 theRainyDayFund = nullptr;
189 }
190 result = calloc ((size_t) nelem, (size_t) elsize);
191 if (result)
192 Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
193 else
194 Melder_fatal (U"Out of memory: there is not enough room for ", Melder_bigInteger (nelem),
195 U" more elements whose sizes are ", Melder_bigInteger (elsize), U" bytes each.");
196 }
197 totalNumberOfAllocations += 1;
198 totalAllocationSize += nelem * elsize;
199 return result;
200 }
201
Melder_dup(conststring32 string)202 autostring32 Melder_dup (conststring32 string /* cattable */) {
203 if (! string)
204 return autostring32();
205 int64 size = (int64) str32len (string) + 1; // guaranteed to be positive
206 if (sizeof (size_t) < 8 && size > SIZE_MAX / sizeof (char32))
207 Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" characters. Use a 64-bit edition of Praat instead?");
208 autostring32 result (size, false); // guarded conversion
209 str32cpy (result.get(), string);
210 if (Melder_debug == 34)
211 Melder_casual (U"Melder_dup\t", Melder_pointer (result.get()), U"\t", Melder_bigInteger (size), U"\t", sizeof (char32));
212 return result;
213 }
214
Melder_dup_f(conststring32 string)215 autostring32 Melder_dup_f (conststring32 string /* cattable */) {
216 if (! string)
217 return autostring32();
218 int64 size = (int64) str32len (string) + 1;
219 if (sizeof (size_t) < 8 && size > SIZE_MAX / sizeof (char32))
220 Melder_fatal (U"(Melder_dup_f:) Can never allocate ", Melder_bigInteger (size), U" characters.");
221 autostring32 result (size, true);
222 str32cpy (result.get(), string);
223 return result;
224 }
225
Melder_allocationCount()226 int64 Melder_allocationCount () {
227 return totalNumberOfAllocations;
228 }
229
Melder_deallocationCount()230 int64 Melder_deallocationCount () {
231 return totalNumberOfDeallocations;
232 }
233
Melder_allocationSize()234 int64 Melder_allocationSize () {
235 return totalAllocationSize;
236 }
237
Melder_reallocationsInSituCount()238 int64 Melder_reallocationsInSituCount () {
239 return totalNumberOfReallocsInSitu;
240 }
241
Melder_movingReallocationsCount()242 int64 Melder_movingReallocationsCount () {
243 return totalNumberOfMovingReallocs;
244 }
245
Melder_cmp(conststring32 string1,conststring32 string2)246 int Melder_cmp (conststring32 string1, conststring32 string2) {
247 if (! string1) string1 = U"";
248 if (! string2) string2 = U"";
249 return str32cmp (string1, string2);
250 }
251
Melder_cmp_caseInsensitive(conststring32 string1,conststring32 string2)252 int Melder_cmp_caseInsensitive (conststring32 string1, conststring32 string2) {
253 if (! string1) string1 = U"";
254 if (! string2) string2 = U"";
255 return str32cmp_caseInsensitive (string1, string2);
256 }
257
Melder_ncmp(conststring32 string1,conststring32 string2,integer n)258 int Melder_ncmp (conststring32 string1, conststring32 string2, integer n) {
259 if (! string1) string1 = U"";
260 if (! string2) string2 = U"";
261 return str32ncmp (string1, string2, n);
262 }
263
Melder_ncmp_caseInsensitive(conststring32 string1,conststring32 string2,integer n)264 int Melder_ncmp_caseInsensitive (conststring32 string1, conststring32 string2, integer n) {
265 if (! string1) string1 = U"";
266 if (! string2) string2 = U"";
267 return str32ncmp_caseInsensitive (string1, string2, n);
268 }
269
Melder_equ_firstCharacterCaseInsensitive(conststring32 string1,conststring32 string2)270 bool Melder_equ_firstCharacterCaseInsensitive (conststring32 string1, conststring32 string2) {
271 if (! string1) string1 = U"";
272 if (! string2) string2 = U"";
273 if (string1 [0] == U'\0')
274 return string2 [0] == U'\0';
275 if (Melder_toLowerCase (string1 [0]) != Melder_toLowerCase (string2 [0]))
276 return false;
277 return str32equ (string1 + 1, string2 + 1);
278 }
279
280 #pragma mark - Generic memory functions for vectors and matrices
281
282 namespace MelderArray { // reopen
283 int64 allocationCount = 0, deallocationCount = 0;
284 int64 cellAllocationCount = 0, cellDeallocationCount = 0;
285 }
286
MelderArray_allocationCount()287 int64 MelderArray_allocationCount () { return MelderArray :: allocationCount; }
MelderArray_deallocationCount()288 int64 MelderArray_deallocationCount () { return MelderArray :: deallocationCount; }
MelderArray_cellAllocationCount()289 int64 MelderArray_cellAllocationCount () { return MelderArray :: cellAllocationCount; }
MelderArray_cellDeallocationCount()290 int64 MelderArray_cellDeallocationCount () { return MelderArray :: cellDeallocationCount; }
291
_alloc_generic(integer cellSize,integer numberOfCells,kInitializationType initializationType)292 byte * MelderArray:: _alloc_generic (integer cellSize, integer numberOfCells, kInitializationType initializationType) {
293 try {
294 if (numberOfCells <= 0)
295 return nullptr; // not an error
296 byte *result = ( initializationType == kInitializationType :: ZERO ?
297 reinterpret_cast <byte *> (_Melder_calloc (numberOfCells, cellSize)) :
298 reinterpret_cast <byte *> (_Melder_malloc (numberOfCells * cellSize)) );
299 MelderArray::allocationCount += 1;
300 MelderArray::cellAllocationCount += numberOfCells;
301 return result;
302 } catch (MelderError) {
303 Melder_throw (U"Tensor of ", numberOfCells, U" cells not created.");
304 }
305 }
306
_free_generic(byte * cells,integer numberOfCells)307 void MelderArray:: _free_generic (byte *cells, integer numberOfCells) noexcept {
308 if (! cells)
309 return; // not an error
310 Melder_free (cells);
311 MelderArray::deallocationCount += 1;
312 MelderArray::cellDeallocationCount += numberOfCells;
313 }
314
315 /* End of file melder_alloc.cpp */
316