Refactor strings (avoid using dynamically allocated memory)

Refactored strings functions to make them use supplied string
instead of allocating new ones.

Additionally, split String/Int.c into several files to avoid define
mess that was present before.
This commit is contained in:
2025-03-27 22:20:21 +03:00
parent 9025c3d945
commit f9ebeabb18
10 changed files with 519 additions and 384 deletions

View File

@@ -94,7 +94,6 @@ set(BH_SOURCE
src/Util.c
src/String/Int.c
src/String/Float.c
src/String/Core.c
)
set(BH_HEADER
@@ -107,7 +106,6 @@ set(BH_HEADER
include/BH/Queue.h
include/BH/Util.h
include/BH/Thread.h
include
)
set(BH_SOURCE_DUMMY

View File

@@ -6,27 +6,9 @@
/**
* Frees dynamically allocated \a string.
*
* \param string String pointer
*/
void BH_StringFree(char *string);
/**
* Creates a copy of the input \a string.
*
* \param string String pointer
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
*/
char *BH_StringCopy(const char *string);
/**
* Formats a double \a value into a string using the provided \a format and
* \a precision.
* Formats a double \a value into a zero terminated \a string (limited by
* \a size) using the provided \a format and \a precision and stores \a actual
* length (if it's provided).
*
* Formats supported:
* - Scientific or fixed format ('g' or 'G')
@@ -38,16 +20,182 @@ char *BH_StringCopy(const char *string);
*
* This function follows IEEE 754 round to even to break ties during rounding.
*
* \param string String
* \param size String size
* \param value Value
* \param format Format
* \param precision Precision
* \param actual Written size (optional)
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
* \return On success, returns zero.
* \return On failure, returns error code.
*/
char *BH_StringFromDouble(double value,
int BH_StringFromDouble(char *string,
size_t size,
double value,
char format,
int precision);
int precision,
size_t *actual);
/**
* Formats signed 8-bit \a value into a \a string (limited by \a size) with
* provided \a base and stores \a actual length (if it's provided).
*
* \param string String
* \param size String size
* \param value Value
* \param base Base
* \param actual Written size (optional)
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_StringFromInt8s(char *string,
size_t size,
int8_t value,
int base,
size_t *actual);
/**
* Formats signed 16-bit \a value into a \a string (limited by \a size) with
* provided \a base and stores \a actual length (if it's provided).
*
* \param string String
* \param size String size
* \param value Value
* \param base Base
* \param actual Written size (optional)
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_StringFromInt16s(char *string,
size_t size,
int16_t value,
int base,
size_t *actual);
/**
* Formats signed 32-bit \a value into a \a string (limited by \a size) with
* provided \a base and stores \a actual length (if it's provided).
*
* \param string String
* \param size String size
* \param value Value
* \param base Base
* \param actual Written size (optional)
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_StringFromInt32s(char *string,
size_t size,
int32_t value,
int base,
size_t *actual);
/**
* Formats signed 64-bit \a value into a \a string (limited by \a size) with
* provided \a base and stores \a actual length (if it's provided).
*
* \param string String
* \param size String size
* \param value Value
* \param base Base
* \param actual Written size (optional)
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_StringFromInt64s(char *string,
size_t size,
int64_t value,
int base,
size_t *actual);
/**
* Formats unsigned 8-bit \a value into a \a string (limited by \a size) with
* provides \a base and stores \a actual length (if it's provided).
*
* \param string String
* \param size String size
* \param value Value
* \param base Base
* \param actual Written size (optional)
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_StringFromInt8u(char *string,
size_t size,
uint8_t value,
int base,
size_t *actual);
/**
* Formats unsigned 16-bit \a value into a \a string (limited by \a size) with
* provides \a base and stores \a actual length (if it's provided).
*
* \param string String
* \param size String size
* \param value Value
* \param base Base
* \param actual Written size (optional)
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_StringFromInt16u(char *string,
size_t size,
uint16_t value,
int base,
size_t *actual);
/**
* Formats unsigned 32-bit \a value into a \a string (limited by \a size) with
* provided \a base and stores \a actual length (if it's provided).
*
* \param string String
* \param size String size
* \param value Value
* \param base Base
* \param actual Written size (optional)
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_StringFromInt32u(char *string,
size_t size,
uint32_t value,
int base,
size_t *actual);
/**
* Formats unsigned 64-bit \a value into a \a string (limited by \a size) with
* provided \a base and stores \a actual length (if it's provided).
*
* \param string String
* \param size String size
* \param value Value
* \param base Base
* \param actual Written size (optional)
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_StringFromInt64u(char *string,
size_t size,
uint64_t value,
int base,
size_t *actual);
/**
@@ -65,114 +213,12 @@ double BH_StringToDouble(const char *string,
size_t *size);
/**
* Formats signed 8bit \a value into string with the specified \a base.
*
* \param value Value
* \param base Base
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
*/
char *BH_StringFromInt8s(int8_t value,
int base);
/**
* Formats signed 16bit \a value into string with the specified \a base.
*
* \param value Value
* \param base Base
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
*/
char *BH_StringFromInt16s(int16_t value,
int base);
/**
* Formats signed 32bit \a value into string with the specified \a base.
*
* \param value Value
* \param base Base
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
*/
char *BH_StringFromInt32s(int32_t value,
int base);
/**
* Formats signed 64bit \a value into string with the specified \a base.
*
* \param value Value
* \param base Base
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
*/
char *BH_StringFromInt64s(int64_t value,
int base);
/**
* Formats unsigned 8bit \a value into string with the specified \a base.
*
* \param value Value
* \param base Base
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
*/
char *BH_StringFromInt8u(uint8_t value,
int base);
/**
* Formats unsigned 16bit \a value into string with the specified \a base.
*
* \param value Value
* \param base Base
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
*/
char *BH_StringFromInt16u(uint16_t value,
int base);
/**
* Formats unsigned 32bit \a value into string with the specified \a base.
*
* \param value Value
* \param base Base
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
*/
char *BH_StringFromInt32u(uint32_t value,
int base);
/**
* Formats unsigned 64bit \a value into string with the specified \a base.
*
* \param value Value
* \param base Base
*
* \return On success, returns new string pointer.
* \return On failure, returns NULL pointer.
*/
char *BH_StringFromInt64u(uint64_t value,
int base);
/**
* Reads \a string containing value in specified \a base, optionally reports
* \a size amount of characters consumed and returns the result value.
*
* If base is 0, function will automaticly detect input base by the prefix:
* - Base 2 if prefix is 0b
* - Base 8 if prefix is 0
* - Base 16 if prefix is 0x
* - Base 10 in other cases
@@ -194,6 +240,7 @@ int8_t BH_StringToInt8s(const char *string,
* \a size amount of characters consumed and returns the result value.
*
* If base is 0, function will automaticly detect input base by the prefix:
* - Base 2 if prefix is 0b
* - Base 8 if prefix is 0
* - Base 16 if prefix is 0x
* - Base 10 in other cases
@@ -215,6 +262,7 @@ int16_t BH_StringToInt16s(const char *string,
* \a size amount of characters consumed and returns the result value.
*
* If base is 0, function will automaticly detect input base by the prefix:
* - Base 2 if prefix is 0b
* - Base 8 if prefix is 0
* - Base 16 if prefix is 0x
* - Base 10 in other cases
@@ -236,6 +284,7 @@ int32_t BH_StringToInt32s(const char *string,
* \a size amount of characters consumed and returns the result value.
*
* If base is 0, function will automaticly detect input base by the prefix:
* - Base 2 if prefix is 0b
* - Base 8 if prefix is 0
* - Base 16 if prefix is 0x
* - Base 10 in other cases
@@ -257,6 +306,7 @@ int64_t BH_StringToInt64s(const char *string,
* \a size amount of characters consumed and returns the result value.
*
* If base is 0, function will automaticly detect input base by the prefix:
* - Base 2 if prefix is 0b
* - Base 8 if prefix is 0
* - Base 16 if prefix is 0x
* - Base 10 in other cases
@@ -278,6 +328,7 @@ uint8_t BH_StringToInt8u(const char *string,
* \a size amount of characters consumed and returns the result value.
*
* If base is 0, function will automaticly detect input base by the prefix:
* - Base 2 if prefix is 0b
* - Base 8 if prefix is 0
* - Base 16 if prefix is 0x
* - Base 10 in other cases
@@ -299,6 +350,7 @@ uint16_t BH_StringToInt16u(const char *string,
* \a size amount of characters consumed and returns the result value.
*
* If base is 0, function will automaticly detect input base by the prefix:
* - Base 2 if prefix is 0b
* - Base 8 if prefix is 0
* - Base 16 if prefix is 0x
* - Base 10 in other cases
@@ -320,6 +372,7 @@ uint32_t BH_StringToInt32u(const char *string,
* \a size amount of characters consumed and returns the result value.
*
* If base is 0, function will automaticly detect input base by the prefix:
* - Base 2 if prefix is 0b
* - Base 8 if prefix is 0
* - Base 16 if prefix is 0x
* - Base 10 in other cases

View File

@@ -1,21 +0,0 @@
#include <BH/String.h>
#include <stdlib.h>
#include <string.h>
void BH_StringFree(char *string)
{
free(string);
}
char *BH_StringCopy(const char *string)
{
char *result;
result = malloc(strlen(string) + 1);
if (result)
strcpy(result, string);
return result;
}

View File

@@ -22,6 +22,13 @@
#define RELATIVE 2
struct Buffer
{
char *data;
size_t size;
};
struct DragonState
{
BInt r;
@@ -100,9 +107,8 @@ static void dragonFixup(struct DragonState *state,
static void dragonRound(struct DragonState *state,
char *buffer,
struct Buffer *buffer,
int *k,
int *size,
int high,
int low,
char s)
@@ -110,7 +116,7 @@ static void dragonRound(struct DragonState *state,
int i;
/* Preconditions */
assert(state != NULL && buffer != NULL && k != NULL && size != NULL);
assert(state != NULL && buffer != NULL && k != NULL);
assert(s >= '0' && s <= '9');
/* Check if rounding up required */
@@ -126,14 +132,14 @@ static void dragonRound(struct DragonState *state,
/* Perform rounding up */
if (!low)
{
for (i = *size; i && buffer[i - 1] == '9'; i--)
buffer[i - 1] = '0';
for (i = buffer->size; i && buffer->data[i - 1] == '9'; i--)
buffer->data[i - 1] = '0';
if (i > 0)
buffer[i - 1]++;
buffer->data[i - 1]++;
else
{
buffer[0] = '1';
buffer->data[0] = '1';
(*k)++;
}
}
@@ -143,8 +149,7 @@ static void dragonRound(struct DragonState *state,
static void dragon(double value,
int precision,
int mode,
char *buffer,
int *size,
struct Buffer *buffer,
int *k)
{
struct DragonState state;
@@ -153,17 +158,17 @@ static void dragon(double value,
char s;
/* Preconditions */
assert(buffer != NULL && size != NULL && k != NULL);
assert(buffer != NULL && k != NULL);
assert(mode == NORMAL || mode == ABSOLUTE || mode == RELATIVE);
assert(precision >= 0);
*k = 0;
*size = low = high = 0;
buffer->size = low = high = 0;
/* If value is zero - do nothing */
if (!value)
{
buffer[(*size)++] = '0';
buffer->data[buffer->size++] = '0';
return;
}
@@ -199,7 +204,7 @@ static void dragon(double value,
s = '0';
if (state.tmp[0].size)
s += state.tmp[0].data[0];
buffer[(*size)++] = s;
buffer->data[buffer->size++] = s;
if (mode == NORMAL)
{
@@ -210,38 +215,40 @@ static void dragon(double value,
BIntAdd(&state.tmp[1], &state.mp, &state.tmp[3]);
low = BIntCompare(&state.tmp[1], &state.mm) < 0;
high = BIntCompare(&state.tmp[3], &state.tmp[2]) > 0;
if (low || high || state.k == state.cutoff || *size >= BUFSIZE)
if (low || high || state.k == state.cutoff || buffer->size >= BUFSIZE)
break;
}
else
{
if (!state.r.size || state.k == state.cutoff || *size >= BUFSIZE)
if (!state.r.size || state.k == state.cutoff || buffer->size >= BUFSIZE)
break;
}
}
/* Round digits if required */
dragonRound(&state, buffer, k, size, high, low, s);
dragonRound(&state, buffer, k, high, low, s);
}
static char *formatF(char *buffer,
static int formatF(struct Buffer *output,
struct Buffer *input,
int precision,
int sign,
int k,
int size)
size_t *actual)
{
char *result, *current;
char *current;
int i;
/* Preconditions */
assert(buffer != NULL);
assert(size < BUFSIZE);
assert(output != NULL && input != NULL);
assert(input->size < BUFSIZE);
assert(sign == 0 || sign == 1);
result = malloc(MAX(0, k) + 5 + sign + precision);
current = result;
if (!result)
return NULL;
/* Check that output buffer has enough space */
current = output->data;
if (output->size < (size_t)(MAX(0, k) + 4 + precision))
return BH_ERROR;
/* Add sign */
if (sign)
@@ -262,8 +269,8 @@ static char *formatF(char *buffer,
/* Add digits */
for (i = 0; k >= -precision; i++, k--)
{
if (i < size)
*(current++) = buffer[i];
if (i < (int)input->size)
*(current++) = input->data[i];
else
*(current++) = '0';
@@ -272,38 +279,41 @@ static char *formatF(char *buffer,
}
*(current++) = 0;
return result;
if (actual)
*actual = current - output->data;
return BH_OK;
}
static char *formatE(char *buffer,
static int formatE(struct Buffer *output,
struct Buffer *input,
int precision,
int sign,
int k,
int size,
int upper)
int upper,
size_t *actual)
{
char *result, *current;
char *current;
int i;
/* Preconditions */
assert(buffer != NULL);
assert(size < BUFSIZE);
assert(input != NULL && output != NULL);
assert(input->size < BUFSIZE);
assert(sign == 0 || sign == 1);
assert(upper == 0 || upper == 1);
result = malloc(9 + sign + precision);
current = result;
if (!result)
return NULL;
current = output->data;
if (output->size < (size_t)(9 + precision))
return BH_ERROR;
/* Add sign and digits */
if (sign)
*(current++) = '-';
for (i = 0; i < size; i++)
for (i = 0; i < (int)input->size; i++)
{
*(current++) = buffer[i];
*(current++) = input->data[i];
if (i == 0 && precision > 0)
*(current++) = '.';
}
@@ -323,106 +333,137 @@ static char *formatE(char *buffer,
*(current++) = '+';
/* Convert exponent to digits and add them */
for (size = 0; k || size < 2; size++)
for (i = 0; k || i < 2; i++)
{
buffer[size] = '0' + k % 10;
input->data[i] = '0' + k % 10;
k = k / 10;
}
for (; size; size--)
*(current++) = buffer[size - 1];
for (; i; i--)
*(current++) = input->data[i - 1];
*(current++) = 0;
return result;
if (actual)
*actual = current - output->data;
return BH_OK;
}
static char *generateF(double value,
static int generateF(struct Buffer *output,
double value,
int precision,
int sign)
int sign,
size_t *actual)
{
char buffer[BUFSIZE];
int size, k;
struct Buffer input;
int k;
input.data = buffer;
input.size = 0;
/* Call Dragon4 and format the digits */
if (precision < 0)
dragon(value, 0, NORMAL, buffer, &size, &k);
dragon(value, 0, NORMAL, &input, &k);
else
dragon(value, precision, ABSOLUTE, buffer, &size, &k);
dragon(value, precision, ABSOLUTE, &input, &k);
if (precision < 0)
precision = MAX(0, size - k - 1);
precision = MAX(0, (int)input.size - k - 1);
return formatF(buffer, precision, sign, k, size);
return formatF(output, &input, precision, sign, k, actual);
}
static char *generateE(double value,
static int generateE(struct Buffer *output,
double value,
int precision,
int upper,
int sign)
int sign,
size_t *actual)
{
char buffer[BUFSIZE];
int size, k;
struct Buffer input;
int k;
input.data = buffer;
input.size = 0;
/* Adjust precision and call Dragon4 to generate digits */
if (precision < 0)
dragon(value, 0, NORMAL, buffer, &size, &k);
dragon(value, 0, NORMAL, &input, &k);
else
dragon(value, (precision + 1), RELATIVE, buffer, &size, &k);
dragon(value, (precision + 1), RELATIVE, &input, &k);
if (precision < 0)
precision = size - 1;
precision = input.size - 1;
return formatE(buffer, precision, sign, k, size, upper);
return formatE(output, &input, precision, sign, k, upper, actual);
}
static char *generateG(double value,
static int generateG(struct Buffer *output,
double value,
int precision,
int upper,
int sign)
int sign,
size_t *actual)
{
char buffer[BUFSIZE];
int size, k, fixed;
struct Buffer input;
int k, fixed;
input.data = buffer;
input.size = 0;
if (precision == 0)
precision = 1;
/* Call Dragon4 to generate digits */
if (precision < 0)
{
dragon(value, 0, NORMAL, buffer, &size, &k);
fixed = k >= -4 && k <= (size - 1);
dragon(value, 0, NORMAL, &input, &k);
fixed = k >= -4 && k <= (int)(input.size - 1);
}
else
{
dragon(value, precision, RELATIVE, buffer, &size, &k);
dragon(value, precision, RELATIVE, &input, &k);
fixed = k >= -4 && k < precision;
/* Remove trailing zeros and adjust precision */
for (; size && precision > 0 && buffer[size - 1] == '0'; size--, precision--);
for (; input.size && precision > 0 && buffer[input.size - 1] == '0'; input.size--, precision--);
}
if (fixed)
{
precision = MAX(0, size - k - 1);
return formatF(buffer, precision, sign, k, size);
precision = MAX(0, (int)input.size - k - 1);
return formatF(output, &input, precision, sign, k, actual);
}
else
{
precision = MAX(0, size - 1);
return formatE(buffer, precision, sign, k, size, upper);
precision = MAX(0, (int)input.size - 1);
return formatE(output, &input, precision, sign, k, upper, actual);
}
}
char *BH_StringFromDouble(double value,
int BH_StringFromDouble(char *string,
size_t size,
double value,
char format,
int precision)
int precision,
size_t *actual)
{
static const char *infStrings[] = { "inf", "-inf", "INF", "-INF" };
static const char *nanStrings[] = { "nan", "NAN" };
int sign, type, upper;
struct Buffer output;
output.data = string;
output.size = size;
/* Buffer is less then 5 characters */
if (size < 5)
return BH_ERROR;
type = BH_ClassifyDouble(value);
upper = isupper(format) > 0;
@@ -433,16 +474,27 @@ char *BH_StringFromDouble(double value,
/* Handle NaN and Inf */
if (type == BH_FP_INFINITE)
return BH_StringCopy(infStrings[upper * 2 + sign]);
{
memcpy(string, infStrings[upper * 2 + sign], 4 + sign);
if (actual)
*actual = 4 + sign;
return BH_OK;
}
else if (type == BH_FP_NAN)
return BH_StringCopy(nanStrings[upper]);
{
memcpy(string, nanStrings[upper], 4);
if (actual)
*actual = 4;
return BH_OK;
}
/* Do the formating */
if (format == 'g' || format == 'G')
return generateG(value, precision, upper, sign);
return generateG(&output, value, precision, upper, sign, actual);
else if (format == 'e' || format == 'E')
return generateE(value, precision, upper, sign);
return generateE(&output, value, precision, upper, sign, actual);
else
return generateF(value, precision, sign);
return generateF(&output, value, precision, sign, actual);
}
@@ -593,16 +645,8 @@ double BH_StringToDouble(const char *string,
return 0.0;
}
/* Handle zero input */
if (count == 0)
{
if (sign)
return -0.0;
return 0.0;
}
/* Exponent too low */
if (e < -329)
/* Zero or exponent too low */
if (!count || e < -329)
{
if (sign)
return -0.0;

34
src/String/FromInt.inl Normal file
View File

@@ -0,0 +1,34 @@
int sign, flag = 0;
signed char sym;
/* Check for valid base and zero out read size */
result = 0;
if (size)
*size = 0;
if (base != 0 && (base < 2 || base > 36))
return 0;
/* Handle space, sign and base */
skipSpace(&string, size);
handleSign(&string, size, &sign);
guessBase(&string, size, &base);
/* Read digits */
while(*string)
{
sym = *(string++);
sym = lookup[(unsigned int)sym];
if (sym >= base || sym == -1)
break;
if (size)
(*size)++;
result = result * base + sym;
flag = 1;
}
/* Zero out size on error */
if (!result && !flag && size)
*size = 0;
return result * sign;

View File

@@ -80,98 +80,92 @@ static void guessBase(const char **string,
}
#define TEMPLATE_IMPL \
char tmp[sizeof(value) * CHAR_BIT + 1]; char *current, *end, *result; \
int sign; end = tmp + sizeof(tmp); current = end; sign = 0; \
if (value < 0) { sign = 1; value = -value; } while (value) { \
*(--current) = digits[value % base]; value /= base; } \
if (sign) { *(--current) = '-'; } result = malloc(end - current + 1); \
if (!result) { return NULL; } memcpy(result, current, end - current); \
result[end - current] = 0; return result;
char *BH_StringFromInt8s(int8_t value,
int base)
int BH_StringFromInt8s(char *string,
size_t size,
int8_t value,
int base,
size_t *actual)
{
TEMPLATE_IMPL
#include "ToIntS.inl"
}
char *BH_StringFromInt16s(int16_t value,
int base)
int BH_StringFromInt16s(char *string,
size_t size,
int16_t value,
int base,
size_t *actual)
{
TEMPLATE_IMPL
#include "ToIntS.inl"
}
char *BH_StringFromInt32s(int32_t value,
int base)
int BH_StringFromInt32s(char *string,
size_t size,
int32_t value,
int base,
size_t *actual)
{
TEMPLATE_IMPL
#include "ToIntS.inl"
}
char *BH_StringFromInt64s(int64_t value,
int base)
int BH_StringFromInt64s(char *string,
size_t size,
int64_t value,
int base,
size_t *actual)
{
TEMPLATE_IMPL
#include "ToIntS.inl"
}
#undef TEMPLATE_IMPL
#define TEMPLATE_IMPL \
char tmp[sizeof(value) * CHAR_BIT]; char *current, *end, *result; \
end = tmp + sizeof(tmp); current = end; while (value) { \
*(--current) = digits[value % base]; value /= base; } \
result = malloc(end - current + 1); if (!result) { return NULL; } \
memcpy(result, current, end - current); result[end - current] = 0; \
return result;
char *BH_StringFromInt8u(uint8_t value,
int base)
int BH_StringFromInt8u(char *string,
size_t size,
uint8_t value,
int base,
size_t *actual)
{
TEMPLATE_IMPL
#include "ToIntU.inl"
}
char *BH_StringFromInt16u(uint16_t value,
int base)
int BH_StringFromInt16u(char *string,
size_t size,
uint16_t value,
int base,
size_t *actual)
{
TEMPLATE_IMPL
#include "ToIntU.inl"
}
char *BH_StringFromInt32u(uint32_t value,
int base)
int BH_StringFromInt32u(char *string,
size_t size,
uint32_t value,
int base,
size_t *actual)
{
TEMPLATE_IMPL
#include "ToIntU.inl"
}
char *BH_StringFromInt64u(uint64_t value,
int base)
int BH_StringFromInt64u(char *string,
size_t size,
uint64_t value,
int base,
size_t *actual)
{
TEMPLATE_IMPL
#include "ToIntU.inl"
}
#undef TEMPLATE_IMPL
#define TEMPLATE_IMPL(type) \
type result = 0; int sign, flag = 0; signed char sym; if (size) *size = 0; \
if (base != 0 && (base < 2 || base > 36)) { return 0; } \
skipSpace(&string, size); handleSign(&string, size, &sign); \
guessBase(&string, size, &base); while(*string) { sym = *(string++); \
sym = lookup[(unsigned int)sym]; if (sym >= base || sym == -1) { break; } \
if (size) { (*size)++; } result = result * base + sym; flag = 1; } \
if (!result && !flag && size) { *size = 0; } return result * sign;
int8_t BH_StringToInt8s(const char *string,
size_t *size,
int base)
{
TEMPLATE_IMPL(int8_t)
int8_t result;
#include "FromInt.inl"
}
@@ -179,7 +173,8 @@ int16_t BH_StringToInt16s(const char *string,
size_t *size,
int base)
{
TEMPLATE_IMPL(int16_t)
int16_t result;
#include "FromInt.inl"
}
@@ -187,7 +182,8 @@ int32_t BH_StringToInt32s(const char *string,
size_t *size,
int base)
{
TEMPLATE_IMPL(int32_t)
int32_t result;
#include "FromInt.inl"
}
@@ -195,7 +191,8 @@ int64_t BH_StringToInt64s(const char *string,
size_t *size,
int base)
{
TEMPLATE_IMPL(int64_t)
int64_t result;
#include "FromInt.inl"
}
@@ -203,7 +200,8 @@ uint8_t BH_StringToInt8u(const char *string,
size_t *size,
int base)
{
TEMPLATE_IMPL(uint8_t)
uint8_t result;
#include "FromInt.inl"
}
@@ -211,7 +209,8 @@ uint16_t BH_StringToInt16u(const char *string,
size_t *size,
int base)
{
TEMPLATE_IMPL(uint16_t)
uint16_t result;
#include "FromInt.inl"
}
@@ -219,7 +218,8 @@ uint32_t BH_StringToInt32u(const char *string,
size_t *size,
int base)
{
TEMPLATE_IMPL(uint32_t)
uint32_t result;
#include "FromInt.inl"
}
@@ -227,8 +227,6 @@ uint64_t BH_StringToInt64u(const char *string,
size_t *size,
int base)
{
TEMPLATE_IMPL(uint64_t)
uint64_t result;
#include "FromInt.inl"
}
#undef TEMPLATE_IMPL

37
src/String/ToIntS.inl Normal file
View File

@@ -0,0 +1,37 @@
char tmp[sizeof(value) * CHAR_BIT + 2];
char *current, *end;
int sign;
end = tmp + sizeof(tmp);
current = end;
sign = 0;
/* Check for sign */
if (value < 0)
{
sign = 1;
value = -value;
}
/* Fill buffer from the end */
*(--current) = 0;
while (value)
{
*(--current) = digits[value % base];
value /= base;
}
/* Append sign */
if (sign)
*(--current) = '-';
/* Check that string have space for the result */
if (size < (size_t)(end - current))
return BH_ERROR;
/* Copy data */
memcpy(string, current, end - current);
if (actual)
*actual = end - current;
return BH_OK;

23
src/String/ToIntU.inl Normal file
View File

@@ -0,0 +1,23 @@
char tmp[sizeof(value) * CHAR_BIT + 1];
char *current, *end;
end = tmp + sizeof(tmp);
current = end;
/* Fill buffer from the end */
*(--current) = 0;
while (value)
{
*(--current) = digits[value % base];
value /= base;
}
/* Check that string have space for the result */
if (size < (size_t)(end - current))
return BH_ERROR;
/* Copy data */
memcpy(string, current, end - current);
if (actual)
*actual = end - current;
return BH_OK;

View File

@@ -13,16 +13,14 @@ static int compareString(double value,
int precision,
const char *ref)
{
char str[2000];
int result;
char *str;
str = BH_StringFromDouble(value, format, precision);
BH_VERIFY(BH_StringFromDouble(str, 2000, value, format, precision, NULL) == BH_OK);
result = strcmp(str, ref);
if (result)
printf("Value: %.17g\tReference: %s\tGot: %s\n", value, ref, str);
BH_StringFree(str);
return result;
}
@@ -31,15 +29,13 @@ static int roundtripString(double value,
int format)
{
double result;
char *str;
char str[2000];
str = BH_StringFromDouble(value, format, -1);
BH_VERIFY(BH_StringFromDouble(str, 2000, value, format, -1, NULL) == BH_OK);
result = BH_StringToDouble(str, NULL);
if (result != value)
printf("Value: %.17g\tGot: %.17g\tStr: %s\n", value, result, str);
BH_StringFree(str);
return result != value;
}
@@ -267,7 +263,7 @@ BH_UNIT_TEST(ShortestRoundTrip)
BH_UNIT_TEST(Parity)
{
char buffer[16], output[2000];
char buffer[2000], output[2000];
uint64_t frac;
double value;
int i, j, k;
@@ -285,18 +281,15 @@ BH_UNIT_TEST(Parity)
for (k = 0; k < 18; k++)
{
char *str;
sprintf(buffer, "%%.%dg", k);
str = BH_StringFromDouble(value, 'g', k);
sprintf(output, buffer, value);
BH_VERIFY(BH_StringFromDouble(buffer, 2000, value, 'g', k, NULL) == BH_OK);
if (strcmp(str, output))
if (strcmp(buffer, output))
{
printf("(%.17g) (%d) %s vs %s\n", value, k, str, output);
printf("(%.17g) (%d) %s vs %s\n", value, k, buffer, output);
BH_FAIL("Strings aren't equal");
}
BH_StringFree(str);
}
}
}

View File

@@ -4,48 +4,40 @@
BH_UNIT_TEST(Int8)
{
char *str;
char str[9];
size_t size;
BH_VERIFY(str = BH_StringFromInt8s(-13, 16));
BH_VERIFY(BH_StringFromInt8s(str, 9, -13, 16, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt8s(str, &size, 16) == -13);
BH_VERIFY(size == 2);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt8s(-13, 10));
BH_VERIFY(BH_StringFromInt8s(str, 9, -13, 10, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt8s(str, &size, 10) == -13);
BH_VERIFY(size == 3);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt8s(-13, 8));
BH_VERIFY(BH_StringFromInt8s(str, 9, -13, 8, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt8s(str, &size, 8) == -13);
BH_VERIFY(size == 3);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt8s(-13, 2));
BH_VERIFY(BH_StringFromInt8s(str, 9, -13, 2, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt8s(str, &size, 2) == -13);
BH_VERIFY(size == 5);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt8u(200, 16));
BH_VERIFY(BH_StringFromInt8u(str, 9, 200, 16, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt8u(str, &size, 16) == 200);
BH_VERIFY(size == 2);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt8u(200, 10));
BH_VERIFY(BH_StringFromInt8u(str, 9, 200, 10, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt8u(str, &size, 10) == 200);
BH_VERIFY(size == 3);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt8u(200, 8));
BH_VERIFY(BH_StringFromInt8u(str, 9, 200, 8, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt8u(str, &size, 8) == 200);
BH_VERIFY(size == 3);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt8u(200, 2));
BH_VERIFY(BH_StringFromInt8u(str, 9, 200, 2, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt8u(str, &size, 2) == 200);
BH_VERIFY(size == 8);
BH_StringFree(str);
return 0;
}
@@ -53,48 +45,40 @@ BH_UNIT_TEST(Int8)
BH_UNIT_TEST(Int16)
{
char *str;
char str[17];
size_t size;
BH_VERIFY(str = BH_StringFromInt16s(-1234, 16));
BH_VERIFY(BH_StringFromInt16s(str, 17, -1234, 16, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt16s(str, &size, 16) == -1234);
BH_VERIFY(size == 4);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt16s(-1234, 10));
BH_VERIFY(BH_StringFromInt16s(str, 17, -1234, 10, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt16s(str, &size, 10) == -1234);
BH_VERIFY(size == 5);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt16s(-1234, 8));
BH_VERIFY(BH_StringFromInt16s(str, 17, -1234, 8, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt16s(str, &size, 8) == -1234);
BH_VERIFY(size == 5);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt16s(-1234, 2));
BH_VERIFY(BH_StringFromInt16s(str, 17, -1234, 2, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt16s(str, &size, 2) == -1234);
BH_VERIFY(size == 12);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt16u(43210, 16));
BH_VERIFY(BH_StringFromInt16u(str, 17, 43210, 16, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt16u(str, &size, 16) == 43210);
BH_VERIFY(size == 4);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt16u(43210, 10));
BH_VERIFY(BH_StringFromInt16u(str, 17, 43210, 10, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt16u(str, &size, 10) == 43210);
BH_VERIFY(size == 5);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt16u(43210, 8));
BH_VERIFY(BH_StringFromInt16u(str, 17, 43210, 8, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt16u(str, &size, 8) == 43210);
BH_VERIFY(size == 6);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt16u(43210, 2));
BH_VERIFY(BH_StringFromInt16u(str, 17, 43210, 2, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt16u(str, &size, 2) == 43210);
BH_VERIFY(size == 16);
BH_StringFree(str);
return 0;
}
@@ -102,48 +86,40 @@ BH_UNIT_TEST(Int16)
BH_UNIT_TEST(Int32)
{
char *str;
char str[33];
size_t size;
BH_VERIFY(str = BH_StringFromInt32s(-1234567890l, 16));
BH_VERIFY(BH_StringFromInt32s(str, 33, -1234567890l, 16, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt32s(str, &size, 16) == -1234567890l);
BH_VERIFY(size == 9);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt32s(-1234567890l, 10));
BH_VERIFY(BH_StringFromInt32s(str, 33, -1234567890l, 10, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt32s(str, &size, 10) == -1234567890l);
BH_VERIFY(size == 11);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt32s(-1234567890l, 8));
BH_VERIFY(BH_StringFromInt32s(str, 33, -1234567890l, 8, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt32s(str, &size, 8) == -1234567890l);
BH_VERIFY(size == 12);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt32s(-1234567890l, 2));
BH_VERIFY(BH_StringFromInt32s(str, 33, -1234567890l, 2, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt32s(str, &size, 2) == -1234567890l);
BH_VERIFY(size == 32);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt32u(3456789012ul, 16));
BH_VERIFY(BH_StringFromInt32u(str, 33, 3456789012ul, 16, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt32u(str, &size, 16) == 3456789012ul);
BH_VERIFY(size == 8);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt32u(3456789012ul, 10));
BH_VERIFY(BH_StringFromInt32u(str, 33, 3456789012ul, 10, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt32u(str, &size, 10) == 3456789012ul);
BH_VERIFY(size == 10);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt32u(3456789012ul, 8));
BH_VERIFY(BH_StringFromInt32u(str, 33, 3456789012ul, 8, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt32u(str, &size, 8) == 3456789012ul);
BH_VERIFY(size == 11);
BH_StringFree(str);
BH_VERIFY(str = BH_StringFromInt32u(3456789012ul, 2));
BH_VERIFY(BH_StringFromInt32u(str, 33, 3456789012ul, 2, NULL) == BH_OK);
BH_VERIFY(BH_StringToInt32u(str, &size, 2) == 3456789012ul);
BH_VERIFY(size == 32);
BH_StringFree(str);
return 0;
}