Skip to content

Commit 88fdf36

Browse files
committed
Use new string API in value functions
1 parent a0891b8 commit 88fdf36

File tree

5 files changed

+462
-509
lines changed

5 files changed

+462
-509
lines changed

include/scratchcpp/value_functions.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ extern "C"
5454
LIBSCRATCHCPP_EXPORT void value_assign_bool(ValueData *v, bool boolValue);
5555
LIBSCRATCHCPP_EXPORT void value_assign_string(ValueData *v, const std::string &stringValue);
5656
LIBSCRATCHCPP_EXPORT void value_assign_cstring(ValueData *v, const char *stringValue);
57+
LIBSCRATCHCPP_EXPORT void value_assign_stringptr(ValueData *v, const StringPtr *stringValue);
5758
LIBSCRATCHCPP_EXPORT void value_assign_copy(ValueData *v, const ValueData *another);
5859

5960
LIBSCRATCHCPP_EXPORT bool value_isInfinity(const ValueData *v);
@@ -70,16 +71,16 @@ extern "C"
7071
LIBSCRATCHCPP_EXPORT double value_toDouble(const ValueData *v);
7172
LIBSCRATCHCPP_EXPORT bool value_toBool(const ValueData *v);
7273
LIBSCRATCHCPP_EXPORT void value_toString(const ValueData *v, std::string *dst);
73-
LIBSCRATCHCPP_EXPORT char *value_toCString(const ValueData *v);
74+
LIBSCRATCHCPP_EXPORT StringPtr *value_toStringPtr(const ValueData *v);
7475
LIBSCRATCHCPP_EXPORT void value_toUtf16(const ValueData *v, std::u16string *dst);
7576
LIBSCRATCHCPP_EXPORT Rgb value_toRgba(const ValueData *v);
7677

7778
LIBSCRATCHCPP_EXPORT bool value_doubleIsInt(double v);
7879

79-
LIBSCRATCHCPP_EXPORT char *value_doubleToCString(double v);
80-
LIBSCRATCHCPP_EXPORT const char *value_boolToCString(bool v);
81-
LIBSCRATCHCPP_EXPORT double value_stringToDouble(const char *s);
82-
LIBSCRATCHCPP_EXPORT bool value_stringToBool(const char *s);
80+
LIBSCRATCHCPP_EXPORT StringPtr *value_doubleToStringPtr(double v);
81+
LIBSCRATCHCPP_EXPORT const StringPtr *value_boolToStringPtr(bool v);
82+
LIBSCRATCHCPP_EXPORT double value_stringToDouble(const StringPtr *s);
83+
LIBSCRATCHCPP_EXPORT bool value_stringToBool(const StringPtr *s);
8384

8485
LIBSCRATCHCPP_EXPORT void value_add(const ValueData *v1, const ValueData *v2, ValueData *dst);
8586
LIBSCRATCHCPP_EXPORT void value_subtract(const ValueData *v1, const ValueData *v2, ValueData *dst);

include/scratchcpp/valuedata.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
namespace libscratchcpp
1010
{
1111

12+
struct StringPtr;
13+
1214
enum class LIBSCRATCHCPP_EXPORT ValueType
1315
{
1416
Number = 0,
@@ -26,11 +28,10 @@ extern "C"
2628
{
2729
double numberValue;
2830
bool boolValue;
29-
char *stringValue;
31+
StringPtr *stringValue;
3032
};
3133

3234
ValueType type;
33-
size_t stringSize; // allocated size, not length
3435
};
3536
}
3637

src/scratch/value_functions.cpp

Lines changed: 103 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <scratchcpp/string_pool.h>
2+
#include <scratchcpp/stringptr.h>
13
#include <ctgmath>
24
#include <cassert>
35
#include <clocale>
@@ -17,9 +19,8 @@ extern "C"
1719
{
1820
if (v->type == ValueType::String) {
1921
assert(v->stringValue);
20-
free(v->stringValue);
22+
string_pool_free(v->stringValue);
2123
v->stringValue = nullptr;
22-
v->stringSize = 0;
2324
}
2425
}
2526

@@ -61,12 +62,23 @@ extern "C"
6162
/*! Assigns C string to the given value. */
6263
void value_assign_cstring(ValueData *v, const char *stringValue)
6364
{
64-
if (v->type == ValueType::String) {
65-
value_replaceStr(v, stringValue);
66-
} else {
67-
value_free(v);
68-
value_initStr(v, stringValue);
65+
if (v->type != ValueType::String) {
66+
v->stringValue = string_pool_new();
67+
v->type = ValueType::String;
6968
}
69+
70+
string_assign_cstring(v->stringValue, stringValue);
71+
}
72+
73+
/*! Assigns string to the given value. */
74+
void value_assign_stringptr(ValueData *v, const StringPtr *stringValue)
75+
{
76+
if (v->type != ValueType::String) {
77+
v->stringValue = string_pool_new();
78+
v->type = ValueType::String;
79+
}
80+
81+
string_assign(v->stringValue, stringValue);
7082
}
7183

7284
/*! Assigns another value to the given value. */
@@ -80,10 +92,11 @@ extern "C"
8092
v->boolValue = another->boolValue;
8193
} else if (another->type == ValueType::String) {
8294
if (v->type == ValueType::String)
83-
value_replaceStr(v, another->stringValue);
95+
string_assign(v->stringValue, another->stringValue);
8496
else {
85-
value_free(v);
86-
value_initStr(v, another->stringValue);
97+
v->stringValue = string_pool_new();
98+
string_assign(v->stringValue, another->stringValue);
99+
v->type = ValueType::String;
87100
}
88101
}
89102

@@ -99,7 +112,8 @@ extern "C"
99112
case ValueType::Number:
100113
return value_isInf(v->numberValue);
101114
case ValueType::String:
102-
return strcmp(v->stringValue, "Infinity") == 0;
115+
// TODO: Use a custom comparison function
116+
return utf8::utf16to8(std::u16string(v->stringValue->data)) == "Infinity";
103117
default:
104118
return false;
105119
}
@@ -112,7 +126,8 @@ extern "C"
112126
case ValueType::Number:
113127
return value_isNegativeInf(v->numberValue);
114128
case ValueType::String:
115-
return strcmp(v->stringValue, "-Infinity") == 0;
129+
// TODO: Use a custom comparison function
130+
return utf8::utf16to8(std::u16string(v->stringValue->data)) == "-Infinity";
116131
default:
117132
return false;
118133
}
@@ -125,7 +140,8 @@ extern "C"
125140
case ValueType::Number:
126141
return std::isnan(v->numberValue);
127142
case ValueType::String:
128-
return strcmp(v->stringValue, "NaN") == 0;
143+
// TODO: Use a custom comparison function
144+
return utf8::utf16to8(std::u16string(v->stringValue->data)) == "NaN";
129145
default:
130146
return false;
131147
}
@@ -151,7 +167,7 @@ extern "C"
151167
case ValueType::Bool:
152168
return true;
153169
case ValueType::String:
154-
return strlen(v->stringValue) == 0 || value_checkString(v->stringValue) > 0;
170+
return v->stringValue->size == 0 || value_checkString(v->stringValue) > 0;
155171
default:
156172
return false;
157173
}
@@ -245,103 +261,91 @@ extern "C"
245261
/*! Writes the string representation of the given value to dst. */
246262
void value_toString(const ValueData *v, std::string *dst)
247263
{
248-
char *str = value_toCString(v);
249-
dst->assign(str);
250-
free(str);
264+
StringPtr *str = value_toStringPtr(v);
265+
dst->assign(utf8::utf16to8(std::u16string(str->data)));
266+
string_pool_free(str);
251267
}
252268

253269
/*!
254270
* Returns the string representation of the given value.
255271
* \note It is the caller's responsibility to free allocated memory.
256272
*/
257-
char *value_toCString(const ValueData *v)
273+
StringPtr *value_toStringPtr(const ValueData *v)
258274
{
259275
if (v->type == ValueType::String) {
260-
char *ret = (char *)malloc((strlen(v->stringValue) + 1) * sizeof(char));
261-
strcpy(ret, v->stringValue);
276+
StringPtr *ret = string_pool_new();
277+
string_assign(ret, v->stringValue);
262278
return ret;
263279
} else if (v->type == ValueType::Number)
264-
return value_doubleToCString(v->numberValue);
280+
return value_doubleToStringPtr(v->numberValue);
265281
else if (v->type == ValueType::Bool) {
266-
char *ret;
267-
268282
if (v->boolValue) {
269-
ret = (char *)malloc((4 + 1) * sizeof(char));
270-
strcpy(ret, "true");
283+
StringPtr *ret = string_pool_new();
284+
string_assign_cstring(ret, "true");
285+
return ret;
271286
} else {
272-
ret = (char *)malloc((5 + 1) * sizeof(char));
273-
strcpy(ret, "false");
287+
StringPtr *ret = string_pool_new();
288+
string_assign_cstring(ret, "false");
289+
return ret;
274290
}
275-
276-
return ret;
277-
} else {
278-
char *ret = (char *)malloc(sizeof(char));
279-
ret[0] = '\0';
280-
return ret;
281-
}
291+
} else
292+
return string_pool_new();
282293
}
283294

284295
/*! Writes the UTF-16 representation of the given value to dst. */
285296
void value_toUtf16(const libscratchcpp::ValueData *v, std::u16string *dst)
286297
{
287-
std::string s;
288-
value_toString(v, &s);
289-
dst->assign(utf8::utf8to16(s));
298+
StringPtr *str = value_toStringPtr(v);
299+
dst->assign(str->data);
300+
string_pool_free(str);
290301
}
291302

292303
/*! Returns the RGBA quadruplet from the given color value. */
293304
Rgb value_toRgba(const ValueData *v)
294305
{
295306
// https://github.com/scratchfoundation/scratch-vm/blob/112989da0e7306eeb405a5c52616e41c2164af24/src/util/cast.js#L92-L103
296-
char *string = nullptr;
297-
size_t stringLen = 0;
307+
StringPtr *string = nullptr;
298308

299309
if (v->type == ValueType::Number)
300310
return v->numberValue;
301-
else if (v->type == ValueType::String) {
302-
string = value_toCString(v);
303-
stringLen = strlen(string);
304-
} else if (v->type == ValueType::Bool)
311+
else if (v->type == ValueType::String)
312+
string = v->stringValue;
313+
else if (v->type == ValueType::Bool)
305314
return v->boolValue;
306315

307-
if (stringLen > 0 && string[0] == '#') {
316+
if (string->size > 0 && string->data[0] == u'#') {
308317
// https://github.com/scratchfoundation/scratch-vm/blob/a4f095db5e03e072ba222fe721eeeb543c9b9c15/src/util/color.js#L60-L69
309318
// (this implementation avoids regex)
310319

311320
// Handle shorthand hex (e.g., "abc" -> "aabbcc")
312-
char expandedHex[7] = { 0 };
313-
char *ptr;
314-
315-
if (stringLen == 4) {
316-
expandedHex[0] = string[1];
317-
expandedHex[1] = string[1];
318-
expandedHex[2] = string[2];
319-
expandedHex[3] = string[2];
320-
expandedHex[4] = string[3];
321-
expandedHex[5] = string[3];
321+
char16_t expandedHex[7] = { 0 };
322+
char16_t *ptr;
323+
324+
if (string->size == 4) {
325+
expandedHex[0] = string->data[1];
326+
expandedHex[1] = string->data[1];
327+
expandedHex[2] = string->data[2];
328+
expandedHex[3] = string->data[2];
329+
expandedHex[4] = string->data[3];
330+
expandedHex[5] = string->data[3];
322331
ptr = expandedHex;
323-
} else if (stringLen == 7)
324-
ptr = string + 1; // skip '#'
325-
else {
326-
free(string);
332+
} else if (string->size == 7)
333+
ptr = string->data + 1; // skip '#'
334+
else
327335
return rgb(0, 0, 0);
328-
}
329336

330337
// Convert hex components to integers
331338
int r, g, b;
332339

333-
if (std::sscanf(ptr, "%2x%2x%2x", &r, &g, &b) == 3) {
334-
free(string);
335-
return rgb(r, g, b);
336-
}
340+
// TODO: Do not use sscanf()
341+
std::string str = utf8::utf16to8(std::u16string(ptr));
337342

338-
free(string);
339-
} else if (stringLen > 0) {
343+
if (std::sscanf(str.c_str(), "%2x%2x%2x", &r, &g, &b) == 3)
344+
return rgb(r, g, b);
345+
} else if (string->size > 0) {
340346
const double ret = value_stringToDouble(string);
341-
free(string);
342347
return ret;
343-
} else if (string)
344-
free(string);
348+
}
345349

346350
return rgb(0, 0, 0);
347351
}
@@ -359,27 +363,27 @@ extern "C"
359363

360364
/*!
361365
* Converts the given number to string.
362-
* \note It is the caller's responsibility to free allocated memory.
366+
* \note It is the caller's responsibility to free the string.
363367
*/
364-
char *value_doubleToCString(double v)
368+
StringPtr *value_doubleToStringPtr(double v)
365369
{
366370
if (v == 0) {
367-
char *ret = (char *)malloc((1 + 1) * sizeof(char));
368-
strcpy(ret, "0");
371+
StringPtr *ret = string_pool_new();
372+
string_assign_cstring(ret, "0");
369373
return ret;
370374
} else if (std::isinf(v)) {
371375
if (v > 0) {
372-
char *ret = (char *)malloc((8 + 1) * sizeof(char));
373-
strcpy(ret, "Infinity");
376+
StringPtr *ret = string_pool_new();
377+
string_assign_cstring(ret, "Infinity");
374378
return ret;
375379
} else {
376-
char *ret = (char *)malloc((9 + 1) * sizeof(char));
377-
strcpy(ret, "-Infinity");
380+
StringPtr *ret = string_pool_new();
381+
string_assign_cstring(ret, "-Infinity");
378382
return ret;
379383
}
380384
} else if (std::isnan(v)) {
381-
char *ret = (char *)malloc((3 + 1) * sizeof(char));
382-
strcpy(ret, "NaN");
385+
StringPtr *ret = string_pool_new();
386+
string_assign_cstring(ret, "NaN");
383387
return ret;
384388
}
385389

@@ -437,39 +441,47 @@ extern "C"
437441
// Restore old locale
438442
std::setlocale(LC_NUMERIC, oldLocale.c_str());
439443

440-
return buffer;
444+
StringPtr *ret = string_pool_new();
445+
string_assign_cstring(ret, buffer);
446+
free(buffer);
447+
return ret;
441448
}
442449

443450
/*!
444451
* Converts the given boolean to string.
445-
* \note Do not free allocated memory!
452+
* \note Do not free the string!
446453
*/
447-
const char *value_boolToCString(bool v)
454+
const StringPtr *value_boolToStringPtr(bool v)
448455
{
449456
if (v) {
450-
static const char *ret = "true";
451-
return ret;
457+
static const std::u16string str = utf8::utf8to16(std::string("true"));
458+
static const StringPtr ret = { const_cast<char16_t *>(str.c_str()) };
459+
return &ret;
452460
} else {
453-
static const char *ret = "false";
454-
return ret;
461+
static const std::u16string str = utf8::utf8to16(std::string("false"));
462+
static const StringPtr ret = { const_cast<char16_t *>(str.c_str()) };
463+
return &ret;
455464
}
456465
}
457466

458467
/*! Converts the given string to double. */
459-
double value_stringToDouble(const char *s)
468+
double value_stringToDouble(const StringPtr *s)
460469
{
461-
if (strcmp(s, "Infinity") == 0)
470+
// TODO: Use a custom comparison function
471+
if (utf8::utf16to8(std::u16string(s->data)) == "Infinity")
462472
return std::numeric_limits<double>::infinity();
463-
else if (strcmp(s, "-Infinity") == 0)
473+
else if (utf8::utf16to8(std::u16string(s->data)) == "-Infinity")
464474
return -std::numeric_limits<double>::infinity();
465475

466-
return value_stringToDoubleImpl(s);
476+
return value_stringToDoubleImpl(s->data, s->size);
467477
}
468478

469479
/*! Converts the given string to boolean. */
470-
bool value_stringToBool(const char *s)
480+
bool value_stringToBool(const StringPtr *s)
471481
{
472-
return strlen(s) != 0 && !value_stringsEqual(s, "false") && strcmp(s, "0") != 0;
482+
// TODO: Use a custom comparison function
483+
return s->size != 0 && !value_u16StringsEqual(std::u16string(s->data), utf8::utf8to16(std::string("false"))) &&
484+
!value_u16StringsEqual(std::u16string(s->data), utf8::utf8to16(std::string("0")));
473485
}
474486

475487
/* operations */

0 commit comments

Comments
 (0)