1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-10-30 23:37:45 +02:00

Add unsigned int Variant type.

This is better than using (unsigned int)varUInt64() because bounds checking is performed.
This commit is contained in:
David Steele
2019-04-19 11:22:43 -04:00
parent c45ae5f221
commit 1adcbc5c91
5 changed files with 369 additions and 53 deletions

View File

@@ -13,6 +13,13 @@
<release-list>
<release date="XXXX-XX-XX" version="2.14dev" title="UNDER DEVELOPMENT">
<release-core-list>
<release-development-list>
<release-item>
<p>Add <code>unsigned int</code> <code>Variant</code> type.</p>
</release-item>
</release-development-list>
</release-core-list>
</release>
<release date="2019-04-18" version="2.13" title="Bug Fixes">

View File

@@ -29,8 +29,7 @@ Information about the variant
***********************************************************************************************************************************/
struct Variant
{
unsigned int type:3; // Variant Type
MemContext *memContext; // Mem context
VARIANT_COMMON
};
typedef struct VariantBool
@@ -75,6 +74,13 @@ typedef struct VariantString
MemContext *memContext;
} VariantString;
typedef struct VariantUInt
{
VARIANT_COMMON
VARIANT_UINT_COMMON
MemContext *memContext;
} VariantUInt;
typedef struct VariantUInt64
{
VARIANT_COMMON
@@ -100,8 +106,9 @@ static const char *variantTypeName[] =
"int64", // varTypeInt64
"KeyValue", // varTypeKeyValue
"String", // varTypeString
"VariantList", // varTypeVariantList
"unsigned int", // varTypeUInt
"uint64", // varTypeUInt64
"VariantList", // varTypeVariantList
};
/***********************************************************************************************************************************
@@ -144,12 +151,6 @@ varDup(const Variant *this)
break;
}
case varTypeUInt64:
{
result = varNewUInt64(varUInt64(this));
break;
}
case varTypeKeyValue:
{
VariantKeyValue *keyValue = memNew(sizeof(VariantKeyValue));
@@ -167,6 +168,18 @@ varDup(const Variant *this)
break;
}
case varTypeUInt:
{
result = varNewUInt(varUInt(this));
break;
}
case varTypeUInt64:
{
result = varNewUInt64(varUInt64(this));
break;
}
case varTypeVariantList:
{
result = varNewVarLst(varVarLst(this));
@@ -223,18 +236,24 @@ varEq(const Variant *this1, const Variant *this2)
break;
}
case varTypeUInt64:
{
result = varUInt64(this1) == varUInt64(this2);
break;
}
case varTypeString:
{
result = strEq(varStr(this1), varStr(this2));
break;
}
case varTypeUInt:
{
result = varUInt(this1) == varUInt(this2);
break;
}
case varTypeUInt64:
{
result = varUInt64(this1) == varUInt64(this2);
break;
}
case varTypeKeyValue:
case varTypeVariantList:
THROW_FMT(AssertError, "unable to test equality for %s", variantTypeName[this1->type]);
@@ -326,10 +345,6 @@ 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.
@@ -357,7 +372,17 @@ varBoolForce(const Variant *this)
break;
}
default:
case varTypeUInt:
result = varUInt(this) != 0;
break;
case varTypeUInt64:
result = varUInt64(this) != 0;
break;
case varTypeDouble:
case varTypeKeyValue:
case varTypeVariantList:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeBool]);
}
@@ -439,19 +464,26 @@ varDblForce(const Variant *this)
break;
}
case varTypeUInt64:
{
result = (double)varUInt64(this);
break;
}
case varTypeString:
{
result = cvtZToDouble(strPtr(varStr(this)));
break;
}
default:
case varTypeUInt:
{
result = (double)varUInt(this);
break;
}
case varTypeUInt64:
{
result = (double)varUInt64(this);
break;
}
case varTypeKeyValue:
case varTypeVariantList:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeDouble]);
}
@@ -535,6 +567,26 @@ varIntForce(const Variant *this)
break;
}
case varTypeString:
{
result = cvtZToInt(strPtr(varStr(this)));
break;
}
case varTypeUInt:
{
unsigned int resultTest = varUInt(this);
// Make sure the value fits into a normal 32-bit int range
if (resultTest > INT32_MAX)
THROW_FMT(
FormatError, "unable to convert %s %u to %s", variantTypeName[this->type], resultTest,
variantTypeName[varTypeInt]);
result = (int)resultTest;
break;
}
case varTypeUInt64:
{
uint64_t resultTest = varUInt64(this);
@@ -549,13 +601,9 @@ varIntForce(const Variant *this)
break;
}
case varTypeString:
{
result = cvtZToInt(strPtr(varStr(this)));
break;
}
default:
case varTypeDouble:
case varTypeKeyValue:
case varTypeVariantList:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt]);
}
@@ -631,6 +679,19 @@ varInt64Force(const Variant *this)
break;
}
case varTypeString:
{
result = cvtZToInt64(strPtr(varStr(this)));
break;
}
case varTypeUInt:
{
result = varUInt(this);
break;
}
case varTypeUInt64:
{
uint64_t resultTest = varUInt64(this);
@@ -648,14 +709,139 @@ varInt64Force(const Variant *this)
break;
}
case varTypeString:
case varTypeDouble:
case varTypeKeyValue:
case varTypeVariantList:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt64]);
}
FUNCTION_TEST_RETURN(result);
}
/***********************************************************************************************************************************
New unsigned int variant
***********************************************************************************************************************************/
Variant *
varNewUInt(unsigned int data)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UINT, data);
FUNCTION_TEST_END();
// Allocate memory for the variant and set the type and data
VariantUInt *this = memNew(sizeof(VariantUInt));
this->memContext = memContextCurrent();
this->type = varTypeUInt;
this->data = data;
FUNCTION_TEST_RETURN((Variant *)this);
}
/***********************************************************************************************************************************
Return unsigned int
***********************************************************************************************************************************/
unsigned int
varUInt(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(this->type == varTypeUInt);
FUNCTION_TEST_RETURN(((VariantUInt *)this)->data);
}
/***********************************************************************************************************************************
Return unsigned int regardless of variant type
***********************************************************************************************************************************/
unsigned int
varUIntForce(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_END();
ASSERT(this != NULL);
unsigned int result = 0;
switch (this->type)
{
case varTypeBool:
{
result = cvtZToInt64(strPtr(varStr(this)));
result = varBool(this);
break;
}
default:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt64]);
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 = (unsigned int)resultTest;
else
{
THROW_FMT(
FormatError, "unable to convert %s %d to %s", variantTypeName[this->type], resultTest,
variantTypeName[varTypeUInt]);
}
break;
}
case varTypeInt64:
{
int64_t resultTest = varInt64(this);
// If integer is a negative number or too large, throw an error since the resulting conversion would be out of bounds
if (resultTest >= 0 && resultTest <= UINT_MAX)
result = (unsigned int)resultTest;
else
{
THROW_FMT(
FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[this->type], resultTest,
variantTypeName[varTypeUInt]);
}
break;
}
case varTypeUInt:
{
result = varUInt(this);
break;
}
case varTypeUInt64:
{
uint64_t resultTest = varUInt64(this);
// If integer is too large, throw an error since the resulting conversion would be out of bounds
if (resultTest <= UINT_MAX)
result = (unsigned int)resultTest;
else
{
THROW_FMT(
FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[this->type], resultTest,
variantTypeName[varTypeUInt]);
}
break;
}
case varTypeString:
{
result = cvtZToUInt(strPtr(varStr(this)));
break;
}
case varTypeDouble:
case varTypeKeyValue:
case varTypeVariantList:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeUInt]);
}
FUNCTION_TEST_RETURN(result);
@@ -752,19 +938,27 @@ varUInt64Force(const Variant *this)
break;
}
case varTypeUInt64:
{
result = varUInt64(this);
break;
}
case varTypeString:
{
result = cvtZToUInt64(strPtr(varStr(this)));
break;
}
default:
case varTypeUInt:
{
result = varUInt(this);
break;
}
case varTypeUInt64:
{
result = varUInt64(this);
break;
}
case varTypeDouble:
case varTypeKeyValue:
case varTypeVariantList:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeUInt64]);
}
@@ -916,18 +1110,24 @@ varStrForce(const Variant *this)
break;
}
case varTypeUInt64:
{
result = strNewFmt("%" PRIu64, varUInt64(this));
break;
}
case varTypeString:
{
result = strDup(varStr(this));
break;
}
case varTypeUInt:
{
result = strNewFmt("%u", varUInt(this));
break;
}
case varTypeUInt64:
{
result = strNewFmt("%" PRIu64, varUInt64(this));
break;
}
case varTypeKeyValue:
case varTypeVariantList:
THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeString]);
@@ -1014,6 +1214,7 @@ varToLog(const Variant *this)
case varTypeDouble:
case varTypeInt:
case varTypeInt64:
case varTypeUInt:
case varTypeUInt64:
{
result = strNewFmt("{%s}", strPtr(varStrForce(this)));
@@ -1081,6 +1282,12 @@ varFree(Variant *this)
break;
}
case varTypeUInt:
{
memContextSwitch(((VariantUInt *)this)->memContext);
break;
}
case varTypeUInt64:
{
memContextSwitch(((VariantUInt64 *)this)->memContext);

View File

@@ -36,8 +36,9 @@ typedef enum
varTypeInt64,
varTypeKeyValue,
varTypeString,
varTypeVariantList,
varTypeUInt,
varTypeUInt64,
varTypeVariantList,
} VariantType;
#include "common/type/keyValue.h"
@@ -71,6 +72,10 @@ Variant *varNewStrZ(const char *data);
const String *varStr(const Variant *this);
String *varStrForce(const Variant *this);
Variant *varNewUInt(unsigned int data);
unsigned int varUInt(const Variant *this);
unsigned int varUIntForce(const Variant *this);
Variant *varNewUInt64(uint64_t data);
uint64_t varUInt64(const Variant *this);
uint64_t varUInt64Force(const Variant *this);
@@ -138,6 +143,15 @@ typedef struct VariantStringConst
const VARIANT_STRING_COMMON
} VariantStringConst;
#define VARIANT_UINT_COMMON \
unsigned int data; /* unsigned integer data */
typedef struct VariantUIntConst
{
VARIANT_COMMON
const VARIANT_UINT_COMMON
} VariantUIntConst;
#define VARIANT_UINT64_COMMON \
uint64_t data; /* 64-bit unsigned integer data */
@@ -193,6 +207,10 @@ By convention all variant constant identifiers are appended with _VAR.
#define VARIANT_STRDEF_STATIC(name, dataParam) \
static const Variant *name = VARSTRDEF(dataParam)
// Create a UInt Variant constant inline from an unsigned int
#define VARUINT(dataParam) \
((const Variant *)&(const VariantUIntConst){.type = varTypeUInt, .data = dataParam})
// Create a UInt64 Variant constant inline from a uint64_t
#define VARUINT64(dataParam) \
((const Variant *)&(const VariantUInt64Const){.type = varTypeUInt64, .data = dataParam})

View File

@@ -170,7 +170,7 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: type-variant
total: 12
total: 13
coverage:
common/type/variant: full

View File

@@ -14,6 +14,11 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("bool"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantBoolConst), 8, "check VariantBoolConst size");
TEST_RESULT_UINT(sizeof(VariantBool), TEST_64BIT() ? 16 : 12, "check VariantBool size");
// -------------------------------------------------------------------------------------------------------------------------
Variant *boolean = varNewBool(false);
TEST_RESULT_INT(varType(boolean), varTypeBool, "get bool type");
varFree(boolean);
@@ -28,6 +33,7 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_BOOL(varBoolForce(VARBOOL(false)), false, "force bool to bool");
TEST_RESULT_BOOL(varBoolForce(VARINT(1)), true, "force int to bool");
TEST_RESULT_BOOL(varBoolForce(VARUINT(0)), false, "force uint to bool");
TEST_RESULT_BOOL(varBoolForce(VARINT64(false)), false, "force int64 to bool");
TEST_RESULT_BOOL(varBoolForce(VARUINT64(12)), true, "force uint64 to bool");
@@ -49,6 +55,10 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("double"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantDoubleConst), TEST_64BIT() ? 16 : 12, "check VariantDoubleConst size");
TEST_RESULT_UINT(sizeof(VariantDouble), TEST_64BIT() ? 24 : 16, "check VariantDouble size");
Variant *var = varNewDbl(44.44);
TEST_RESULT_DOUBLE(varDbl(var), 44.44, "double variant");
varFree(var);
@@ -62,6 +72,7 @@ testRun(void)
TEST_RESULT_DOUBLE(varDblForce(VARINT(123)), 123, "force int to double");
TEST_RESULT_DOUBLE(varDblForce(VARINT64(999999999999)), 999999999999, "force int64 to double");
TEST_RESULT_DOUBLE(varDblForce(VARUINT64(9223372036854775807U)), 9223372036854775807U, "force uint64 to double");
TEST_RESULT_DOUBLE(varDblForce(VARUINT(992)), 992, "force uint to double");
TEST_RESULT_DOUBLE(varDblForce(VARSTRDEF("879.01")), 879.01, "force String to double");
TEST_RESULT_DOUBLE(varDblForce(VARSTRDEF("0")), 0, "force String to double");
TEST_RESULT_DOUBLE(
@@ -81,6 +92,11 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("int"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantIntConst), 8, "check VariantIntConst size");
TEST_RESULT_UINT(sizeof(VariantInt), TEST_64BIT() ? 16 : 12, "check VariantInt size");
// -------------------------------------------------------------------------------------------------------------------------
Variant *integer = varNewInt(44);
TEST_RESULT_INT(varInt(integer), 44, "int variant");
TEST_RESULT_INT(varIntForce(integer), 44, "force int to int");
@@ -92,6 +108,8 @@ testRun(void)
TEST_RESULT_INT(varIntForce(VARINT64(999)), 999, "force int64 to int");
TEST_ERROR(varIntForce(VARINT64(2147483648)), FormatError, "unable to convert int64 2147483648 to int");
TEST_ERROR(varIntForce(VARINT64(-2147483649)), FormatError, "unable to convert int64 -2147483649 to int");
TEST_RESULT_INT(varIntForce(VARUINT(54321)), 54321, "force uint to int");
TEST_ERROR(varIntForce(VARUINT(2147483648)), FormatError, "unable to convert unsigned int 2147483648 to int");
TEST_RESULT_INT(varIntForce(VARUINT64(12345)), 12345, "force uint64 to int");
TEST_ERROR(varIntForce(VARUINT64(2147483648)), FormatError, "unable to convert uint64 2147483648 to int");
@@ -113,6 +131,11 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("int64"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantInt64Const), TEST_64BIT() ? 16 : 12, "check VariantInt64Const size");
TEST_RESULT_UINT(sizeof(VariantInt64), TEST_64BIT() ? 24 : 16, "check VariantInt64 size");
// -------------------------------------------------------------------------------------------------------------------------
Variant *integer = varNewInt64(44);
TEST_RESULT_INT(varInt64(integer), 44, "int64 variant");
TEST_RESULT_INT(varInt64Force(integer), 44, "force int64 to int64");
@@ -121,6 +144,7 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_INT(varInt64Force(varNewBool(true)), 1, "force bool to int64");
TEST_RESULT_INT(varInt64Force(VARINT(2147483647)), 2147483647, "force int to int64");
TEST_RESULT_INT(varInt64Force(VARUINT(4294967295)), 4294967295, "force uint to int64");
TEST_RESULT_INT(varInt64Force(varNewStrZ("9223372036854775807")), 9223372036854775807L, "force str to int64");
TEST_RESULT_INT(varInt64Force(VARUINT64(9223372036854775807U)), 9223372036854775807L, "force uint64 to int64");
@@ -145,9 +169,55 @@ testRun(void)
TEST_RESULT_BOOL(varEq(VARINT64(444), VARINT64(123)), false, "int64, int64 not eq");
}
// *****************************************************************************************************************************
if (testBegin("unsigned int"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantUIntConst), 8, "check VariantUIntConst size");
TEST_RESULT_UINT(sizeof(VariantUInt), TEST_64BIT() ? 16 : 12, "check VariantUInt size");
// -------------------------------------------------------------------------------------------------------------------------
Variant *unsignedint = varNewUInt(787);
TEST_RESULT_DOUBLE(varUInt(unsignedint), 787, "uint variant");
TEST_RESULT_DOUBLE(varUIntForce(unsignedint), 787, "force uint to uint");
varFree(unsignedint);
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_DOUBLE(varUIntForce(varNewBool(true)), 1, "force bool to uint");
TEST_RESULT_DOUBLE(varUIntForce(VARINT(2147483647)), 2147483647, "force int to uint");
TEST_RESULT_DOUBLE(varUIntForce(VARINT64(2147483647)), 2147483647, "force int64 to uint");
TEST_RESULT_DOUBLE(varUIntForce(varNewStrZ("4294967295")), 4294967295, "force str to uint");
TEST_RESULT_DOUBLE(varUIntForce(VARUINT64(4294967295U)), 4294967295U, "force uint64 to uint");
TEST_ERROR(
varUIntForce(varNewStrZ("4294967296")), FormatError,
"unable to convert base 10 string '4294967296' to unsigned int"); // string value is out of bounds for uint
TEST_ERROR(varUIntForce(varNewStrZ(" 16")), FormatError,"unable to convert base 10 string ' 16' to unsigned int");
TEST_ERROR(varUIntForce(varNewVarLst(varLstNew())), AssertError, "unable to force VariantList to unsigned int");
TEST_ERROR(varUIntForce(VARINT64(4294967296L)), FormatError, "unable to convert int64 4294967296 to unsigned int");
TEST_ERROR(varUIntForce(VARUINT64(4294967296U)), FormatError, "unable to convert uint64 4294967296 to unsigned int");
TEST_ERROR(varUIntForce(VARINT64(-1)), FormatError, "unable to convert int64 -1 to unsigned int");
TEST_ERROR(varUIntForce(VARINT(-1)), FormatError, "unable to convert int -1 to unsigned int");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varUInt(varNewStrZ("string")), AssertError, "assertion 'this->type == varTypeUInt' failed");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_DOUBLE(varUInt(varDup(VARUINT(88976))), 88976, "dup uint");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_BOOL(varEq(VARUINT(9999), VARUINT(9999)), true, "uint, uint eq");
TEST_RESULT_BOOL(varEq(VARUINT(444), VARUINT(123)), false, "uint, uint not eq");
}
// *****************************************************************************************************************************
if (testBegin("uint64"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantUInt64Const), TEST_64BIT() ? 16 : 12, "check VariantUInt64Const size");
TEST_RESULT_UINT(sizeof(VariantUInt64), TEST_64BIT() ? 24 : 16, "check VariantUInt64 size");
// -------------------------------------------------------------------------------------------------------------------------
Variant *uint64 = varNewUInt64(44);
TEST_RESULT_DOUBLE(varUInt64(uint64), 44, "uint64 variant");
TEST_RESULT_DOUBLE(varUInt64Force(uint64), 44, "force uint64 to uint64");
@@ -156,6 +226,7 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_DOUBLE(varUInt64Force(varNewBool(true)), 1, "force bool to uint64");
TEST_RESULT_DOUBLE(varUInt64Force(VARINT(2147483647)), 2147483647, "force int to uint64");
TEST_RESULT_INT(varUInt64Force(VARUINT(4294967295)), 4294967295, "force uint to uint64");
TEST_RESULT_DOUBLE(varUInt64Force(VARINT64(2147483647)), 2147483647, "force int64 to uint64");
TEST_RESULT_DOUBLE(varUInt64Force(varNewStrZ("18446744073709551615")), 18446744073709551615U, "force str to uint64");
TEST_RESULT_DOUBLE(varUInt64Force(VARUINT64(18446744073709551615U)), 18446744073709551615U, "force uint64 to uint64");
@@ -185,6 +256,10 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("keyValue"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantKeyValue), TEST_64BIT() ? 24 : 12, "check VariantKeyValue size");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varKv(VARINT(66)), AssertError, "assertion 'this->type == varTypeKeyValue' failed");
// -------------------------------------------------------------------------------------------------------------------------
@@ -211,6 +286,11 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("String"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantStringConst), TEST_64BIT() ? 16 : 8, "check VariantStringConst size");
TEST_RESULT_UINT(sizeof(VariantString), TEST_64BIT() ? 24 : 12, "check VariantString size");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_PTR(strPtr(varStr(varNewStr(NULL))), NULL, "new null str");
// -------------------------------------------------------------------------------------------------------------------------
@@ -270,6 +350,10 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("VariantList"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantVariantList), TEST_64BIT() ? 24 : 12, "check VariantVariantList size");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varVarLst(VARINT(66)), AssertError, "assertion 'this->type == varTypeVariantList' failed");
// -------------------------------------------------------------------------------------------------------------------------