diff --git a/doc/xml/release.xml b/doc/xml/release.xml
index 39ebd04ba..f859d5ab4 100644
--- a/doc/xml/release.xml
+++ b/doc/xml/release.xml
@@ -23,6 +23,15 @@
Improve performance of string to int conversion. Use strtoll()
instead of sprintf()
for conversion. Also use available integer min/max constants rather than hard-coded values.
+
+
+
+
+
+
+
+ Add uint64
variant type and supporting conversion functions.
+
diff --git a/src/common/type/convert.c b/src/common/type/convert.c
index 1c051d2b5..7237b17ba 100644
--- a/src/common/type/convert.c
+++ b/src/common/type/convert.c
@@ -63,6 +63,31 @@ cvtZToInt64Internal(const char *value, const char *type)
FUNCTION_TEST_RESULT(INT64, result);
}
+/***********************************************************************************************************************************
+Convert zero-terminated string to uint64 and validate result
+***********************************************************************************************************************************/
+static uint64_t
+cvtZToUInt64Internal(const char *value, const char *type)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(CHARP, value);
+ FUNCTION_TEST_PARAM(CHARP, type);
+
+ FUNCTION_TEST_ASSERT(value != NULL);
+ FUNCTION_TEST_ASSERT(type != NULL);
+ FUNCTION_TEST_END();
+
+ // Convert from string
+ errno = 0;
+ char *endPtr = NULL;
+ uint64_t result = strtoull(value, &endPtr, 10);
+
+ // Validate the result
+ cvtZToIntValid(errno, value, endPtr, type);
+
+ FUNCTION_TEST_RESULT(UINT64, result);
+}
+
/***********************************************************************************************************************************
Convert uint64 to zero-terminated string
***********************************************************************************************************************************/
@@ -289,7 +314,7 @@ cvtUIntToZ(unsigned int value, char *buffer, size_t bufferSize)
}
/***********************************************************************************************************************************
-Convert uint64 to zero-terminated string
+Convert uint64 to zero-terminated string and visa versa
***********************************************************************************************************************************/
size_t
cvtUInt64ToZ(uint64_t value, char *buffer, size_t bufferSize)
@@ -309,3 +334,21 @@ cvtUInt64ToZ(uint64_t value, char *buffer, size_t bufferSize)
FUNCTION_TEST_RESULT(SIZE, result);
}
+
+uint64_t
+cvtZToUInt64(const char *value)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(CHARP, value);
+
+ FUNCTION_TEST_ASSERT(value != NULL);
+ FUNCTION_TEST_END();
+
+ uint64_t result = cvtZToUInt64Internal(value, "uint64");
+
+ // Don't allow negative numbers even though strtoull() does
+ if (*value == '-')
+ THROW_FMT(FormatError, "unable to convert string '%s' to uint64", value);
+
+ FUNCTION_TEST_RESULT(UINT64, result);
+}
diff --git a/src/common/type/convert.h b/src/common/type/convert.h
index d5ddabe59..86ac6db8c 100644
--- a/src/common/type/convert.h
+++ b/src/common/type/convert.h
@@ -26,6 +26,7 @@ size_t cvtSizeToZ(size_t value, char *buffer, size_t bufferSize);
size_t cvtUIntToZ(unsigned int value, char *buffer, size_t bufferSize);
size_t cvtUInt64ToZ(uint64_t value, char *buffer, size_t bufferSize);
+uint64_t cvtZToUInt64(const char *value);
size_t cvtBoolToZ(bool value, char *buffer, size_t bufferSize);
diff --git a/src/common/type/variant.c b/src/common/type/variant.c
index aaa4f4dbc..8766fb141 100644
--- a/src/common/type/variant.c
+++ b/src/common/type/variant.c
@@ -1,7 +1,9 @@
/***********************************************************************************************************************************
Variant Data Type
***********************************************************************************************************************************/
+#include
#include
+#include
#include
#include
#include
@@ -34,6 +36,7 @@ static const char *variantTypeName[] =
"KeyValue", // varTypeKeyValue
"String", // varTypeString
"VariantList", // varTypeVariantList
+ "uint64", // varTypeUInt64
};
/***********************************************************************************************************************************
@@ -117,6 +120,12 @@ varDup(const Variant *this)
break;
}
+ case varTypeUInt64:
+ {
+ result = varNewUInt64(varUInt64(this));
+ break;
+ }
+
case varTypeKeyValue:
{
KeyValue *data = kvDup(varKv(this));
@@ -186,6 +195,12 @@ varEq(const Variant *this1, const Variant *this2)
break;
}
+ case varTypeUInt64:
+ {
+ result = varUInt64(this1) == varUInt64(this2);
+ break;
+ }
+
case varTypeString:
{
result = strEq(varStr(this1), varStr(this2));
@@ -278,6 +293,10 @@ varBoolForce(const Variant *this)
result = varInt64(this) != 0;
break;
+ case varTypeUInt64:
+ result = varUInt64(this) != 0;
+ break;
+
case varTypeString:
{
// List of false/true boolean string values. Note that false/true values must be equal.
@@ -306,7 +325,7 @@ varBoolForce(const Variant *this)
}
default:
- THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeBool]);
+ THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeBool]);
}
FUNCTION_TEST_RESULT(BOOL, result);
@@ -382,6 +401,12 @@ varDblForce(const Variant *this)
break;
}
+ case varTypeUInt64:
+ {
+ result = (double)varUInt64(this);
+ break;
+ }
+
case varTypeString:
{
result = cvtZToDouble(strPtr(varStr(this)));
@@ -389,7 +414,7 @@ varDblForce(const Variant *this)
}
default:
- THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeDouble]);
+ THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeDouble]);
}
FUNCTION_TEST_RESULT(DOUBLE, result);
@@ -460,7 +485,21 @@ varIntForce(const Variant *this)
// Make sure the value fits into a normal 32-bit int range since 32-bit platforms are supported
if (resultTest > INT32_MAX || resultTest < INT32_MIN)
THROW_FMT(
- AssertError, "unable to convert %s %" PRId64 " to %s", variantTypeName[this->type], resultTest,
+ FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[this->type], resultTest,
+ variantTypeName[varTypeInt]);
+
+ result = (int)resultTest;
+ break;
+ }
+
+ case varTypeUInt64:
+ {
+ uint64_t resultTest = varUInt64(this);
+
+ // Make sure the value fits into a normal 32-bit int range
+ if (resultTest > INT32_MAX)
+ THROW_FMT(
+ FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[this->type], resultTest,
variantTypeName[varTypeInt]);
result = (int)resultTest;
@@ -474,7 +513,7 @@ varIntForce(const Variant *this)
}
default:
- THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt]);
+ THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt]);
}
FUNCTION_TEST_RESULT(INT, result);
@@ -544,6 +583,23 @@ varInt64Force(const Variant *this)
break;
}
+ case varTypeUInt64:
+ {
+ uint64_t resultTest = varUInt64(this);
+
+ // If max number of unsigned 64-bit integer is greater than max 64-bit signed integer can hold, then error
+ if (resultTest <= INT64_MAX)
+ result = (int64_t)resultTest;
+ else
+ {
+ THROW_FMT(
+ FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[this->type], resultTest,
+ variantTypeName[varTypeInt64]);
+ }
+
+ break;
+ }
+
case varTypeString:
{
result = cvtZToInt64(strPtr(varStr(this)));
@@ -551,12 +607,117 @@ varInt64Force(const Variant *this)
}
default:
- THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt64]);
+ THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt64]);
}
FUNCTION_TEST_RESULT(INT64, result);
}
+/***********************************************************************************************************************************
+New uint64 variant
+***********************************************************************************************************************************/
+Variant *
+varNewUInt64(uint64_t data)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(UINT64, data);
+ FUNCTION_TEST_END();
+
+ FUNCTION_TEST_RESULT(VARIANT, varNewInternal(varTypeUInt64, (void *)&data, sizeof(data)));
+}
+
+/***********************************************************************************************************************************
+Return int64
+***********************************************************************************************************************************/
+uint64_t
+varUInt64(const Variant *this)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(VARIANT, this);
+
+ FUNCTION_TEST_ASSERT(this != NULL);
+ FUNCTION_TEST_END();
+
+ ASSERT(this->type == varTypeUInt64);
+
+ FUNCTION_TEST_RESULT(UINT64, *((uint64_t *)varData(this)));
+}
+
+/***********************************************************************************************************************************
+Return uint64 regardless of variant type
+***********************************************************************************************************************************/
+uint64_t
+varUInt64Force(const Variant *this)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(VARIANT, this);
+
+ FUNCTION_TEST_ASSERT(this != NULL);
+ FUNCTION_TEST_END();
+
+ uint64_t result = 0;
+
+ switch (this->type)
+ {
+ case varTypeBool:
+ {
+ result = varBool(this);
+ break;
+ }
+
+ case varTypeInt:
+ {
+ int resultTest = varInt(this);
+
+ // If integer is a negative number, throw an error since the resulting conversion would be a different number
+ if (resultTest >= 0)
+ result = (uint64_t)resultTest;
+ else
+ {
+ THROW_FMT(
+ FormatError, "unable to convert %s %d to %s", variantTypeName[this->type], resultTest,
+ variantTypeName[varTypeUInt64]);
+ }
+
+ break;
+ }
+
+ case varTypeInt64:
+ {
+ int64_t resultTest = varInt64(this);
+
+ // If integer is a negative number, throw an error since the resulting conversion would be out of bounds
+ if (resultTest >= 0)
+ result = (uint64_t)resultTest;
+ else
+ {
+ THROW_FMT(
+ FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[this->type], resultTest,
+ variantTypeName[varTypeUInt64]);
+ }
+
+ break;
+ }
+
+ case varTypeUInt64:
+ {
+ result = varUInt64(this);
+ break;
+ }
+
+ case varTypeString:
+ {
+ result = cvtZToUInt64(strPtr(varStr(this)));
+ break;
+ }
+
+ default:
+ THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeUInt64]);
+ }
+
+ FUNCTION_TEST_RESULT(UINT64, result);
+}
+
/***********************************************************************************************************************************
New key/value variant
***********************************************************************************************************************************/
@@ -703,6 +864,12 @@ varStrForce(const Variant *this)
break;
}
+ case varTypeUInt64:
+ {
+ result = strNewFmt("%" PRIu64, varUInt64(this));
+ break;
+ }
+
case varTypeString:
{
result = strDup(varStr(this));
@@ -801,6 +968,7 @@ varToLog(const Variant *this, char *buffer, size_t bufferSize)
case varTypeDouble:
case varTypeInt:
case varTypeInt64:
+ case varTypeUInt64:
{
string = varStrForce(this);
break;
@@ -854,6 +1022,7 @@ varFree(Variant *this)
case varTypeDouble:
case varTypeInt:
case varTypeInt64:
+ case varTypeUInt64:
break;
}
diff --git a/src/common/type/variant.h b/src/common/type/variant.h
index f6610ebe4..4aa50ae44 100644
--- a/src/common/type/variant.h
+++ b/src/common/type/variant.h
@@ -23,6 +23,7 @@ typedef enum
varTypeKeyValue,
varTypeString,
varTypeVariantList,
+ varTypeUInt64,
} VariantType;
#include "common/type/keyValue.h"
@@ -56,6 +57,10 @@ Variant *varNewStrZ(const char *data);
String *varStr(const Variant *this);
String *varStrForce(const Variant *this);
+Variant *varNewUInt64(uint64_t data);
+uint64_t varUInt64(const Variant *this);
+uint64_t varUInt64Force(const Variant *this);
+
Variant *varNewVarLst(const VariantList *data);
VariantList *varVarLst(const Variant *this);
diff --git a/test/define.yaml b/test/define.yaml
index 4828ab299..15cdd0c22 100644
--- a/test/define.yaml
+++ b/test/define.yaml
@@ -180,7 +180,7 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: type-variant
- total: 8
+ total: 9
coverage:
common/type/variant: full
diff --git a/test/src/module/common/typeConvertTest.c b/test/src/module/common/typeConvertTest.c
index f61204e26..8bc410677 100644
--- a/test/src/module/common/typeConvertTest.c
+++ b/test/src/module/common/typeConvertTest.c
@@ -120,14 +120,21 @@ testRun()
}
// *****************************************************************************************************************************
- if (testBegin("UInt64ToZ()"))
+ if (testBegin("UInt64ToZ() and cvtZToUInt64()"))
{
char buffer[STACK_TRACE_PARAM_MAX];
TEST_ERROR(cvtUInt64ToZ(9999, buffer, 4), AssertError, "buffer overflow");
- TEST_RESULT_INT(cvtUInt64ToZ(0xFFFFFFFFFFFFFFFF, buffer, STACK_TRACE_PARAM_MAX), 20, "convert int64 to string");
+ TEST_RESULT_INT(cvtUInt64ToZ(0xFFFFFFFFFFFFFFFF, buffer, STACK_TRACE_PARAM_MAX), 20, "convert uint64 to string");
TEST_RESULT_STR(buffer, "18446744073709551615", " check buffer");
+
+ TEST_ERROR(cvtZToUInt64("FEF"), FormatError, "unable to convert string 'FEF' to uint64");
+ TEST_ERROR(cvtZToUInt64(" 10"), FormatError, "unable to convert string ' 10' to uint64"); // number but leading space
+ TEST_ERROR(cvtZToUInt64("10 "), FormatError, "unable to convert string '10 ' to uint64"); // number but trailing space
+ TEST_ERROR(cvtZToUInt64("-1"), FormatError, "unable to convert string '-1' to uint64"); // number but trailing space
+
+ TEST_RESULT_DOUBLE(cvtZToUInt64("18446744073709551615"), 18446744073709551615U, "convert string to uint64");
}
FUNCTION_HARNESS_RESULT_VOID();
diff --git a/test/src/module/common/typeVariantTest.c b/test/src/module/common/typeVariantTest.c
index 30c744c63..059d8360d 100644
--- a/test/src/module/common/typeVariantTest.c
+++ b/test/src/module/common/typeVariantTest.c
@@ -29,8 +29,9 @@ testRun()
TEST_RESULT_BOOL(varBoolForce(varNewBool(false)), false, "force bool to bool");
TEST_RESULT_BOOL(varBoolForce(varNewInt(1)), true, "force int to bool");
TEST_RESULT_BOOL(varBoolForce(varNewInt64(false)), false, "force int64 to bool");
+ TEST_RESULT_BOOL(varBoolForce(varNewUInt64(12)), true, "force uint64 to bool");
- TEST_ERROR(varBoolForce(varNewVarLst(varLstNew())), FormatError, "unable to force VariantList to bool");
+ TEST_ERROR(varBoolForce(varNewVarLst(varLstNew())), AssertError, "unable to force VariantList to bool");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_VOID(varFree(NULL), "ok to free null variant");
@@ -60,11 +61,14 @@ testRun()
TEST_RESULT_DOUBLE(varDblForce(varNewBool(false)), 0, "force bool to double");
TEST_RESULT_DOUBLE(varDblForce(varNewInt(123)), 123, "force int to double");
TEST_RESULT_DOUBLE(varDblForce(varNewInt64(999999999999)), 999999999999, "force int64 to double");
+ TEST_RESULT_DOUBLE(varDblForce(varNewUInt64(9223372036854775807U)), 9223372036854775807U, "force uint64 to double");
TEST_RESULT_DOUBLE(varDblForce(varNewStr(strNew("879.01"))), 879.01, "force String to double");
TEST_RESULT_DOUBLE(varDblForce(varNewStr(strNew("0"))), 0, "force String to double");
+ TEST_RESULT_DOUBLE(
+ varDblForce(varNewUInt64(UINT64_MAX)), 18446744073709551616.0, "force max uint64 to double (it will be rounded)");
TEST_ERROR(varDblForce(varNewStr(strNew("AAA"))), FormatError, "unable to convert string 'AAA' to double");
- TEST_ERROR(varDblForce(varNewVarLst(varLstNew())), FormatError, "unable to force VariantList to double");
+ TEST_ERROR(varDblForce(varNewVarLst(varLstNew())), AssertError, "unable to force VariantList to double");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_DOUBLE(varDbl(varDup(varNewDbl(3.1415))), 3.1415, "dup double");
@@ -84,10 +88,12 @@ testRun()
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_INT(varIntForce(varNewBool(true)), 1, "force bool to int");
- TEST_ERROR(varIntForce(varNewVarLst(varLstNew())), FormatError, "unable to force VariantList to int");
+ TEST_ERROR(varIntForce(varNewVarLst(varLstNew())), AssertError, "unable to force VariantList to int");
TEST_RESULT_INT(varIntForce(varNewInt64(999)), 999, "force int64 to int");
- TEST_ERROR(varIntForce(varNewInt64(2147483648)), AssertError, "unable to convert int64 2147483648 to int");
- TEST_ERROR(varIntForce(varNewInt64(-2147483649)), AssertError, "unable to convert int64 -2147483649 to int");
+ TEST_ERROR(varIntForce(varNewInt64(2147483648)), FormatError, "unable to convert int64 2147483648 to int");
+ TEST_ERROR(varIntForce(varNewInt64(-2147483649)), FormatError, "unable to convert int64 -2147483649 to int");
+ TEST_RESULT_INT(varIntForce(varNewUInt64(12345)), 12345, "force uint64 to int");
+ TEST_ERROR(varIntForce(varNewUInt64(2147483648)), FormatError, "unable to convert uint64 2147483648 to int");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varInt(varNewStrZ("string")), AssertError, "assertion 'this->type == varTypeInt' failed");
@@ -116,11 +122,14 @@ testRun()
TEST_RESULT_INT(varInt64Force(varNewBool(true)), 1, "force bool to int64");
TEST_RESULT_INT(varInt64Force(varNewInt(2147483647)), 2147483647, "force int to int64");
TEST_RESULT_INT(varInt64Force(varNewStrZ("9223372036854775807")), 9223372036854775807L, "force str to int64");
+ TEST_RESULT_INT(varInt64Force(varNewUInt64(9223372036854775807U)), 9223372036854775807L, "force uint64 to int64");
TEST_ERROR(
varInt64Force(varNewStrZ("9223372036854775808")), FormatError,
"unable to convert string '9223372036854775808' to int64");
- TEST_ERROR(varInt64Force(varNewVarLst(varLstNew())), FormatError, "unable to force VariantList to int64");
+ TEST_ERROR(varInt64Force(varNewVarLst(varLstNew())), AssertError, "unable to force VariantList to int64");
+ TEST_ERROR(varInt64Force(varNewUInt64(9223372036854775808U)), FormatError,
+ "unable to convert uint64 9223372036854775808 to int64");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varInt64(varNewStrZ("string")), AssertError, "assertion 'this->type == varTypeInt64' failed");
@@ -136,6 +145,43 @@ testRun()
TEST_RESULT_BOOL(varEq(varNewInt64(444), varNewInt64(123)), false, "int64, int64 not eq");
}
+ // -----------------------------------------------------------------------------------------------------------------------------
+ if (testBegin("uint64"))
+ {
+ Variant *uint64 = varNewUInt64(44);
+ TEST_RESULT_DOUBLE(varUInt64(uint64), 44, "uint64 variant");
+ TEST_RESULT_DOUBLE(varUInt64Force(uint64), 44, "force uint64 to uint64");
+ varFree(uint64);
+
+ // -------------------------------------------------------------------------------------------------------------------------
+ TEST_RESULT_DOUBLE(varUInt64Force(varNewBool(true)), 1, "force bool to uint64");
+ TEST_RESULT_DOUBLE(varUInt64Force(varNewInt(2147483647)), 2147483647, "force int to uint64");
+ TEST_RESULT_DOUBLE(varUInt64Force(varNewInt64(2147483647)), 2147483647, "force int64 to uint64");
+ TEST_RESULT_DOUBLE(varUInt64Force(varNewStrZ("18446744073709551615")), 18446744073709551615U, "force str to uint64");
+ TEST_RESULT_DOUBLE(varUInt64Force(varNewUInt64(18446744073709551615U)), 18446744073709551615U, "force uint64 to uint64");
+
+ TEST_ERROR(
+ varUInt64Force(varNewStrZ("18446744073709551616")), FormatError,
+ "unable to convert string '18446744073709551616' to uint64"); // string value is out of bounds for uint64
+ TEST_ERROR(varUInt64Force(varNewStrZ(" 16")), FormatError,"unable to convert string ' 16' to uint64");
+ TEST_ERROR(varUInt64Force(varNewVarLst(varLstNew())), AssertError, "unable to force VariantList to uint64");
+ TEST_ERROR(varUInt64Force(varNewInt64(-1)), FormatError, "unable to convert int64 -1 to uint64");
+ TEST_ERROR(varUInt64Force(varNewInt(-1)), FormatError, "unable to convert int -1 to uint64");
+
+ // -------------------------------------------------------------------------------------------------------------------------
+ TEST_ERROR(varUInt64(varNewStrZ("string")), AssertError, "assertion 'this->type == varTypeUInt64' failed");
+
+ // -------------------------------------------------------------------------------------------------------------------------
+ TEST_RESULT_DOUBLE(varUInt64(varDup(varNewUInt64(88976))), 88976, "dup uint64");
+
+ // -------------------------------------------------------------------------------------------------------------------------
+ TEST_RESULT_BOOL(varEq(NULL, NULL), true, "null, null eq");
+ TEST_RESULT_BOOL(varEq(NULL, varNewUInt64(123)), false, "null, uint64 not eq");
+
+ TEST_RESULT_BOOL(varEq(varNewUInt64(9223372036854775807L), varNewUInt64(9223372036854775807L)), true, "uint64, uint64 eq");
+ TEST_RESULT_BOOL(varEq(varNewUInt64(444), varNewUInt64(123)), false, "uint64, uint64 not eq");
+ }
+
// -----------------------------------------------------------------------------------------------------------------------------
if (testBegin("keyValue"))
{
@@ -198,6 +244,7 @@ testRun()
TEST_RESULT_STR(strPtr(varStrForce(varNewDbl((double)999999999.123456))), "999999999.123456", "force double to string");
TEST_RESULT_STR(strPtr(varStrForce(varNewBool(true))), "true", "force bool to string");
TEST_RESULT_STR(strPtr(varStrForce(varNewBool(false))), "false", "force bool to string");
+ TEST_RESULT_STR(strPtr(varStrForce(varNewUInt64(18446744073709551615U))), "18446744073709551615", "force uint64 to string");
TEST_ERROR(varStrForce(varNewKv()), FormatError, "unable to force KeyValue to String");