1 /* melder_strings.cpp
2 *
3 * Copyright (C) 2006-2012,2014-2021 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 "../kar/UnicodeData.h"
21 #define FREE_THRESHOLD_BYTES 10000LL
22
23 static int64 totalNumberOfAllocations = 0, totalNumberOfDeallocations = 0, totalAllocationSize = 0, totalDeallocationSize = 0;
24
MelderString16_free(MelderString16 * me)25 void MelderString16_free (MelderString16 *me) {
26 if (! my string) {
27 Melder_assert (my bufferSize == 0); // check class invariant for analyzer
28 return;
29 }
30 Melder_free (my string);
31 if (Melder_debug == 34)
32 Melder_casual (U"from MelderString_free\t", Melder_pointer (my string), U"\t", my bufferSize, U"\t", sizeof (char16));
33 totalNumberOfDeallocations += 1;
34 totalDeallocationSize += my bufferSize * (int64) sizeof (char16);
35 my bufferSize = 0;
36 my length = 0;
37 }
38
MelderString_free(MelderString * me)39 void MelderString_free (MelderString *me) {
40 if (! my string) {
41 Melder_assert (my bufferSize == 0); // check class invariant for analyzer
42 return;
43 }
44 Melder_free (my string);
45 if (Melder_debug == 34)
46 Melder_casual (U"from MelderString_free\t", Melder_pointer (my string), U"\t", my bufferSize, U"\t", sizeof (char32));
47 totalNumberOfDeallocations += 1;
48 totalDeallocationSize += my bufferSize * (int64) sizeof (char32);
49 my bufferSize = 0;
50 my length = 0;
51 }
52
53 template <typename STRING_TYPE, typename CHARACTER_TYPE>
MelderString_expand_(STRING_TYPE * me,int64 sizeNeeded)54 inline static void MelderString_expand_ (STRING_TYPE *me, int64 sizeNeeded) {
55 Melder_assert (my bufferSize >= 0);
56 Melder_assert (sizeNeeded >= 0);
57 sizeNeeded = (int64) (2.0 /*1.618034*/ * sizeNeeded) + 100;
58 Melder_assert (sizeNeeded > 0);
59 if (my string) {
60 totalNumberOfDeallocations += 1;
61 totalDeallocationSize += my bufferSize * (int64) sizeof (CHARACTER_TYPE);
62 }
63 int64 bytesNeeded = sizeNeeded * (int64) sizeof (CHARACTER_TYPE);
64 Melder_assert (bytesNeeded > 0);
65 try {
66 if (Melder_debug == 34)
67 Melder_casual (U"from MelderString_expand\t", Melder_pointer (my string), U"\t", sizeNeeded, U"\t", sizeof (CHARACTER_TYPE));
68 my string = (CHARACTER_TYPE *) Melder_realloc (my string, bytesNeeded);
69 my bufferSize = sizeNeeded;
70 } catch (MelderError) {
71 // my string is still valid, because realloc doesn't free on error
72 // my bufferSize is also still valid
73 my length = 0;
74 throw;
75 }
76 totalNumberOfAllocations += 1;
77 totalAllocationSize += bytesNeeded;
78 }
79
MelderString_expand(MelderString * me,int64 sizeNeeded)80 void MelderString_expand (MelderString *me, int64 sizeNeeded) {
81 MelderString_expand_ <MelderString, char32> (me, sizeNeeded);
82 }
83
MelderString16_empty(MelderString16 * me)84 void MelderString16_empty (MelderString16 *me) {
85 if (my bufferSize * (int64) sizeof (char16) >= FREE_THRESHOLD_BYTES)
86 MelderString16_free (me);
87 int64 sizeNeeded = 1;
88 if (sizeNeeded > my bufferSize)
89 MelderString_expand_ <MelderString16, char16> (me, sizeNeeded);
90 my string [0] = u'\0';
91 my length = 0;
92 }
93
MelderString_empty(MelderString * me)94 void MelderString_empty (MelderString *me) {
95 if (my bufferSize * (int64) sizeof (char32) >= FREE_THRESHOLD_BYTES)
96 MelderString_free (me);
97 int64 sizeNeeded = 1;
98 if (sizeNeeded > my bufferSize)
99 MelderString_expand_ <MelderString, char32> (me, sizeNeeded);
100 my string [0] = U'\0';
101 my length = 0;
102 }
103
MelderString_ncopy(MelderString * me,conststring32 source,int64 n)104 void MelderString_ncopy (MelderString *me, conststring32 source, int64 n) {
105 if (my bufferSize * (int64) sizeof (char32) >= FREE_THRESHOLD_BYTES)
106 MelderString_free (me);
107 if (! source)
108 source = U"";
109 int64 length = str32len (source);
110 if (length > n)
111 length = n;
112 int64 sizeNeeded = length + 1;
113 Melder_assert (sizeNeeded > 0);
114 if (sizeNeeded > my bufferSize)
115 MelderString_expand_ <MelderString, char32> (me, sizeNeeded);
116 str32ncpy (my string, source, length);
117 my string [length] = U'\0';
118 my length = length;
119 }
120
MelderString16_appendCharacter(MelderString16 * me,char32 kar)121 void MelderString16_appendCharacter (MelderString16 *me, char32 kar) {
122 int64 sizeNeeded = my length + 3; // make room for character, potential surrogate character, and null character
123 if (sizeNeeded > my bufferSize)
124 MelderString_expand_ <MelderString16, char16> (me, sizeNeeded);
125 if (kar <= 0x00'FFFF) {
126 my string [my length] = (char16) kar; // guarded cast
127 my length ++;
128 } else if (kar <= 0x10'FFFF) {
129 kar -= 0x01'0000;
130 my string [my length] = (char16) (0x00'D800 | (kar >> 10));
131 my length ++;
132 my string [my length] = (char16) (0x00'DC00 | (kar & 0x00'03FF));
133 my length ++;
134 } else {
135 my string [my length] = UNICODE_REPLACEMENT_CHARACTER;
136 my length ++;
137 }
138 my string [my length] = u'\0';
139 }
140
MelderString_appendCharacter(MelderString * me,char32 character)141 void MelderString_appendCharacter (MelderString *me, char32 character) {
142 int64 sizeNeeded = my length + 2; // make room for character and null character
143 if (sizeNeeded > my bufferSize)
144 MelderString_expand_ <MelderString, char32> (me, sizeNeeded);
145 my string [my length] = character;
146 my length ++;
147 my string [my length] = U'\0';
148 }
149
MelderString_get(MelderString * me,char32 * destination)150 void MelderString_get (MelderString *me, char32 *destination) {
151 if (my string)
152 str32cpy (destination, my string);
153 else
154 destination [0] = U'\0';
155 }
156
MelderString_allocationCount()157 int64 MelderString_allocationCount () {
158 return totalNumberOfAllocations;
159 }
160
MelderString_deallocationCount()161 int64 MelderString_deallocationCount () {
162 return totalNumberOfDeallocations;
163 }
164
MelderString_allocationSize()165 int64 MelderString_allocationSize () {
166 return totalAllocationSize;
167 }
168
MelderString_deallocationSize()169 int64 MelderString_deallocationSize () {
170 return totalDeallocationSize;
171 }
172
173 MelderString MelderCat::_buffers [MelderCat::_k_NUMBER_OF_BUFFERS] { };
174 int MelderCat::_bufferNumber = 0;
175
176 /* End of file melder_strings.cpp */
177