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