melder_alloc.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /* melder_alloc.cpp
  2. *
  3. * Copyright (C) 1992-2007,2009,2011,2012,2014-2018 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. #include "melder.h"
  19. #include <wctype.h>
  20. #include <assert.h>
  21. static int64 totalNumberOfAllocations = 0, totalNumberOfDeallocations = 0, totalAllocationSize = 0,
  22. totalNumberOfMovingReallocs = 0, totalNumberOfReallocsInSitu = 0;
  23. /*
  24. * The rainy-day fund.
  25. *
  26. * Typically, memory allocation for data is entirely checked by using the normal versions of the allocation routines,
  27. * which will call Melder_error if they are out of memory.
  28. * When data allocation is indeed out of memory,
  29. * the application will present an error message to the user saying that the data could not be created.
  30. *
  31. * By contrast, it is not practical to check the allocation of user interface elements,
  32. * because the application cannot perform correctly if an interface element is missing or incorrect.
  33. * For such situations, the application will typically use the _f versions of the allocation routines,
  34. * which, if out of memory, will free a "rainy-day fund" and retry.
  35. * In this way, the interface element can usually still be allocated;
  36. * the application will present an error message telling the user to save her work and quit the application.
  37. * If the user doesn't do that, the application will crash upon the next failing allocation of a _f routine.
  38. */
  39. #define theRainyDayFund_SIZE 3'000'000
  40. static char *theRainyDayFund = nullptr;
  41. void Melder_alloc_init () {
  42. theRainyDayFund = (char *) malloc (theRainyDayFund_SIZE); // called at application initialization, so cannot fail
  43. assert (theRainyDayFund);
  44. }
  45. /*
  46. The following functions take int64 arguments even on 32-bit machines.
  47. This is because it is easy for the user to request objects that do not fit in memory
  48. on 32-bit machines, in which case an appropriate error message is required.
  49. */
  50. void * _Melder_malloc (int64 size) {
  51. if (size <= 0)
  52. Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" bytes.");
  53. if (sizeof (size_t) < 8 && size > SIZE_MAX)
  54. Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" bytes. Use a 64-bit edition of Praat instead?");
  55. void *result = malloc ((size_t) size); // guarded cast
  56. if (! result)
  57. Melder_throw (U"Out of memory: there is not enough room for another ", Melder_bigInteger (size), U" bytes.");
  58. if (Melder_debug == 34)
  59. Melder_casual (U"Melder_malloc\t", Melder_pointer (result), U"\t", Melder_bigInteger (size), U"\t1");
  60. totalNumberOfAllocations += 1;
  61. totalAllocationSize += size;
  62. return result;
  63. }
  64. void * _Melder_malloc_f (int64 size) {
  65. if (size <= 0)
  66. Melder_fatal (U"(Melder_malloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes.");
  67. if (sizeof (size_t) < 8 && size > SIZE_MAX)
  68. Melder_fatal (U"(Melder_malloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes.");
  69. void *result = malloc ((size_t) size);
  70. if (! result) {
  71. if (theRainyDayFund) { free (theRainyDayFund); theRainyDayFund = nullptr; }
  72. result = malloc ((size_t) size);
  73. if (result) {
  74. Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
  75. } else {
  76. Melder_fatal (U"Out of memory: there is not enough room for another ", Melder_bigInteger (size), U" bytes.");
  77. }
  78. }
  79. totalNumberOfAllocations += 1;
  80. totalAllocationSize += size;
  81. return result;
  82. }
  83. void _Melder_free (void **ptr) noexcept {
  84. if (! *ptr) return;
  85. if (Melder_debug == 34)
  86. Melder_casual (U"Melder_free\t", Melder_pointer (*ptr), U"\t?\t?");
  87. free (*ptr);
  88. *ptr = nullptr;
  89. totalNumberOfDeallocations += 1;
  90. }
  91. void * Melder_realloc (void *ptr, int64 size) {
  92. if (size <= 0)
  93. Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" bytes.");
  94. if (sizeof (size_t) < 8 && size > SIZE_MAX)
  95. Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" bytes. Use a 64-bit edition of Praat instead?");
  96. void *result = realloc (ptr, (size_t) size); // will not show in the statistics...
  97. if (! result)
  98. Melder_throw (U"Out of memory. Could not extend room to ", Melder_bigInteger (size), U" bytes.");
  99. if (! ptr) { // is it like malloc?
  100. if (Melder_debug == 34)
  101. Melder_casual (U"Melder_realloc\t", Melder_pointer (result), U"\t", Melder_bigInteger (size), U"\t1");
  102. totalNumberOfAllocations += 1;
  103. totalAllocationSize += size;
  104. } else if (result != ptr) { // did realloc do a malloc-and-free?
  105. totalNumberOfAllocations += 1;
  106. totalAllocationSize += size;
  107. totalNumberOfDeallocations += 1;
  108. totalNumberOfMovingReallocs += 1;
  109. } else {
  110. totalNumberOfReallocsInSitu += 1;
  111. }
  112. return result;
  113. }
  114. void * Melder_realloc_f (void *ptr, int64 size) {
  115. if (size <= 0)
  116. Melder_fatal (U"(Melder_realloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes.");
  117. if (sizeof (size_t) < 8 && size > SIZE_MAX)
  118. Melder_fatal (U"(Melder_realloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes.");
  119. void *result = realloc (ptr, (size_t) size); // will not show in the statistics...
  120. if (! result) {
  121. if (theRainyDayFund) { free (theRainyDayFund); theRainyDayFund = nullptr; }
  122. result = realloc (ptr, (size_t) size);
  123. if (result) {
  124. Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
  125. } else {
  126. Melder_fatal (U"Out of memory. Could not extend room to ", Melder_bigInteger (size), U" bytes.");
  127. }
  128. }
  129. if (! ptr) { // is it like malloc?
  130. totalNumberOfAllocations += 1;
  131. totalAllocationSize += size;
  132. } else if (result != ptr) { // did realloc do a malloc-and-free?
  133. totalNumberOfAllocations += 1;
  134. totalAllocationSize += size;
  135. totalNumberOfDeallocations += 1;
  136. totalNumberOfMovingReallocs += 1;
  137. } else {
  138. totalNumberOfReallocsInSitu += 1;
  139. }
  140. return result;
  141. }
  142. void * _Melder_calloc (int64 nelem, int64 elsize) {
  143. if (nelem <= 0)
  144. Melder_throw (U"Can never allocate ", Melder_bigInteger (nelem), U" elements.");
  145. if (elsize <= 0)
  146. Melder_throw (U"Can never allocate elements whose size is ", Melder_bigInteger (elsize), U" bytes.");
  147. if ((uint64) nelem > SIZE_MAX / (uint64) elsize) // guarded casts to unsigned
  148. Melder_throw (U"Can never allocate ", Melder_bigInteger (nelem), U" elements whose sizes are ", Melder_bigInteger (elsize), U" bytes each.",
  149. sizeof (size_t) < 8 ? U" Use a 64-bit edition of Praat instead?" : nullptr);
  150. void *result = calloc ((size_t) nelem, (size_t) elsize);
  151. if (! result)
  152. 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.");
  153. if (Melder_debug == 34)
  154. Melder_casual (U"Melder_calloc\t", Melder_pointer (result), U"\t", Melder_bigInteger (nelem), U"\t", Melder_bigInteger (elsize));
  155. totalNumberOfAllocations += 1;
  156. totalAllocationSize += nelem * elsize;
  157. return result;
  158. }
  159. void * _Melder_calloc_f (int64 nelem, int64 elsize) {
  160. if (nelem <= 0)
  161. Melder_fatal (U"(Melder_calloc_f:) Can never allocate ", Melder_bigInteger (nelem), U" elements.");
  162. if (elsize <= 0)
  163. Melder_fatal (U"(Melder_calloc_f:) Can never allocate elements whose size is ", Melder_bigInteger (elsize), U" bytes.");
  164. if ((uint64) nelem > SIZE_MAX / (uint64) elsize)
  165. Melder_fatal (U"(Melder_calloc_f:) Can never allocate ", Melder_bigInteger (nelem), U" elements whose sizes are ", Melder_bigInteger (elsize), U" bytes each.");
  166. void *result = calloc ((size_t) nelem, (size_t) elsize);
  167. if (! result) {
  168. if (theRainyDayFund) { free (theRainyDayFund); theRainyDayFund = nullptr; }
  169. result = calloc ((size_t) nelem, (size_t) elsize);
  170. if (result) {
  171. Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
  172. } else {
  173. Melder_fatal (U"Out of memory: there is not enough room for ", Melder_bigInteger (nelem),
  174. U" more elements whose sizes are ", Melder_bigInteger (elsize), U" bytes each.");
  175. }
  176. }
  177. totalNumberOfAllocations += 1;
  178. totalAllocationSize += nelem * elsize;
  179. return result;
  180. }
  181. char * Melder_strdup (const char *string) {
  182. if (! string) return nullptr;
  183. int64 size = (int64) strlen (string) + 1;
  184. if (sizeof (size_t) < 8 && size > SIZE_MAX)
  185. Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" bytes. Use a 64-bit edition of Praat instead?");
  186. char *result = (char *) malloc ((size_t) size);
  187. if (! result)
  188. Melder_throw (U"Out of memory: there is not enough room to duplicate a text of ", Melder_bigInteger (size - 1), U" characters.");
  189. strcpy (result, string);
  190. if (Melder_debug == 34)
  191. Melder_casual (U"Melder_strdup\t", Melder_pointer (result), U"\t", Melder_bigInteger (size), U"\t", sizeof (char));
  192. totalNumberOfAllocations += 1;
  193. totalAllocationSize += size;
  194. return result;
  195. }
  196. char * Melder_strdup_f (const char *string) {
  197. if (! string) return nullptr;
  198. int64 size = (int64) strlen (string) + 1;
  199. if (sizeof (size_t) < 8 && size > SIZE_MAX)
  200. Melder_fatal (U"(Melder_strdup_f:) Can never allocate ", Melder_bigInteger (size), U" bytes.");
  201. char *result = (char *) malloc ((size_t) size);
  202. if (! result) {
  203. if (theRainyDayFund) { free (theRainyDayFund); theRainyDayFund = nullptr; }
  204. result = (char *) malloc ((size_t) size * sizeof (char));
  205. if (result) {
  206. Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
  207. } else {
  208. Melder_fatal (U"Out of memory: there is not enough room to duplicate a text of ", Melder_bigInteger (size - 1), U" characters.");
  209. }
  210. }
  211. strcpy (result, string);
  212. totalNumberOfAllocations += 1;
  213. totalAllocationSize += size;
  214. return result;
  215. }
  216. autostring32 Melder_dup (conststring32 string /* cattable */) {
  217. if (! string)
  218. return autostring32();
  219. int64 size = (int64) str32len (string) + 1; // guaranteed to be positive
  220. if (sizeof (size_t) < 8 && size > SIZE_MAX / sizeof (char32))
  221. Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" characters. Use a 64-bit edition of Praat instead?");
  222. autostring32 result (size, false); // guarded conversion
  223. str32cpy (result.get(), string);
  224. if (Melder_debug == 34)
  225. Melder_casual (U"Melder_dup\t", Melder_pointer (result.get()), U"\t", Melder_bigInteger (size), U"\t", sizeof (char32));
  226. return result;
  227. }
  228. autostring32 Melder_dup_f (conststring32 string /* cattable */) {
  229. if (! string)
  230. return autostring32();
  231. int64 size = (int64) str32len (string) + 1;
  232. if (sizeof (size_t) < 8 && size > SIZE_MAX / sizeof (char32))
  233. Melder_fatal (U"(Melder_dup_f:) Can never allocate ", Melder_bigInteger (size), U" characters.");
  234. autostring32 result (size, true);
  235. str32cpy (result.get(), string);
  236. return result;
  237. }
  238. int64 Melder_allocationCount () {
  239. return totalNumberOfAllocations;
  240. }
  241. int64 Melder_deallocationCount () {
  242. return totalNumberOfDeallocations;
  243. }
  244. int64 Melder_allocationSize () {
  245. return totalAllocationSize;
  246. }
  247. int64 Melder_reallocationsInSituCount () {
  248. return totalNumberOfReallocsInSitu;
  249. }
  250. int64 Melder_movingReallocationsCount () {
  251. return totalNumberOfMovingReallocs;
  252. }
  253. int Melder_cmp (conststring32 string1, conststring32 string2) {
  254. if (! string1) string1 = U"";
  255. if (! string2) string2 = U"";
  256. return str32cmp (string1, string2);
  257. }
  258. int Melder_cmp_caseInsensitive (conststring32 string1, conststring32 string2) {
  259. if (! string1) string1 = U"";
  260. if (! string2) string2 = U"";
  261. return str32cmp_caseInsensitive (string1, string2);
  262. }
  263. int Melder_ncmp (conststring32 string1, conststring32 string2, integer n) {
  264. if (! string1) string1 = U"";
  265. if (! string2) string2 = U"";
  266. return str32ncmp (string1, string2, n);
  267. }
  268. int Melder_ncmp_caseInsensitive (conststring32 string1, conststring32 string2, integer n) {
  269. if (! string1) string1 = U"";
  270. if (! string2) string2 = U"";
  271. return str32ncmp_caseInsensitive (string1, string2, n);
  272. }
  273. bool Melder_equ_firstCharacterCaseInsensitive (conststring32 string1, conststring32 string2) {
  274. if (! string1) string1 = U"";
  275. if (! string2) string2 = U"";
  276. if (string1 [0] == U'\0')
  277. return string2 [0] == U'\0';
  278. if (Melder_toLowerCase (string1 [0]) != Melder_toLowerCase (string2 [0]))
  279. return false;
  280. return str32equ (string1 + 1, string2 + 1);
  281. }
  282. /* End of file melder_alloc.cpp */