MathLib:IsNullValue(): using a Finite State Machine to determine a string value contains a numeric NULL value. The NULL value can be Integer, Binary, Hex, Octal. The corresponding unit test cases are also included.

This commit is contained in:
orbitcowboy 2014-04-11 01:27:05 +02:00
parent 1fafc7f4dc
commit 9c08885caf
2 changed files with 263 additions and 5 deletions

View File

@ -598,13 +598,107 @@ bool MathLib::isLessEqual(const std::string &first, const std::string &second)
return toDoubleNumber(first) <= toDoubleNumber(second); return toDoubleNumber(first) <= toDoubleNumber(second);
} }
bool MathLib::isNullValue(const std::string &str) bool MathLib::isNullValue(const std::string &s)
{ {
for (size_t i = 0; i < str.size(); i++) { enum {START, PLUSMINUS, LEADING_ZERO, BIN_OR_HEX_PREFIX, DOT, TRAILING_ZERO, TRAILING_F, ZERO, E, E_PLUSMINUS, E_DIGIT} state = START;
if (std::isdigit(static_cast<unsigned char>(str[i])) && str[i] != '0') // May not contain digits other than 0 for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
switch (state) {
case START:
if (*it == '+' || *it == '-')
state = PLUSMINUS;
else if (*it == '0')
state = LEADING_ZERO;
else if (*it == '.')
state = DOT;
else
return isValidSuffix(it, s.end());
break;
case PLUSMINUS:
if (*it == '0')
state = LEADING_ZERO;
else
return false;
break;
case LEADING_ZERO:
if (*it == '0')
state = LEADING_ZERO;
else if (*it == 'b' || *it == 'B')
state = BIN_OR_HEX_PREFIX;
else if (*it == 'x' || *it == 'X')
state = BIN_OR_HEX_PREFIX;
else if (*it == '.')
state = DOT;
else if (*it == 'e' || *it == 'E')
state = E;
else
return isValidSuffix(it, s.end());
break;
case BIN_OR_HEX_PREFIX:
if (*it == '0')
state = ZERO;
else
return false;
break;
case ZERO:
if (*it == '0')
state = ZERO;
else
return isValidSuffix(it, s.end());
break;
case DOT:
if (*it == '0')
state = TRAILING_ZERO;
else if (*it == 'f' || *it == 'F')
state = TRAILING_F;
else if (*it == 'e' || *it == 'E')
state = E;
else
return false;
break;
case E:
if (*it == '+' || *it == '-')
state = E_PLUSMINUS;
else if (isdigit(*it))
state = E_DIGIT;
else
return false;
break;
case E_PLUSMINUS:
if (isdigit(*it))
state = E_DIGIT;
else
return false;
break;
case E_DIGIT:
if (isdigit(*it))
state = E_DIGIT;
else if (*it == 'f' || *it == 'F')
state = TRAILING_F;
else
return false;
break;
case TRAILING_ZERO:
if (*it == '0')
state = TRAILING_ZERO;
else if (*it == 'f' || *it == 'F')
state = TRAILING_F;
else if (*it == 'e' || *it == 'E')
state = E;
else
return false;
break;
default:
return false; return false;
}
} }
return !str.empty() && (std::isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-' || str[0] == '+'); // Has to be a number return state == LEADING_ZERO || state == ZERO || state == DOT || state == E_DIGIT || state == TRAILING_ZERO || state == TRAILING_F;
/*
for (size_t i = 0; i < str.size(); i++) {
if (std::isdigit(static_cast<unsigned char>(str[i])) && str[i] != '0') // May not contain digits other than 0
return false;
}
return !str.empty() && (std::isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-' || str[0] == '+'); // Has to be a number
*/
} }
bool MathLib::isOctalDigit(char c) bool MathLib::isOctalDigit(char c)

View File

@ -45,7 +45,8 @@ private:
TEST_CASE(calculate); TEST_CASE(calculate);
TEST_CASE(calculate1); TEST_CASE(calculate1);
TEST_CASE(convert); TEST_CASE(convert);
TEST_CASE(naninf) TEST_CASE(naninf);
TEST_CASE(isNullValue);
} }
void isGreater() const { void isGreater() const {
@ -601,6 +602,169 @@ private:
ASSERT_EQUALS("inf.0", MathLib::divide("3.0", "0.0")); // inf ASSERT_EQUALS("inf.0", MathLib::divide("3.0", "0.0")); // inf
ASSERT_EQUALS("-inf.0", MathLib::divide("-3.0", "0.0")); // -inf (#5142) ASSERT_EQUALS("-inf.0", MathLib::divide("-3.0", "0.0")); // -inf (#5142)
} }
void isNullValue() const {
// inter zero value
ASSERT_EQUALS(true, MathLib::isNullValue("0"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0"));
// inter zero value (octal)
ASSERT_EQUALS(true, MathLib::isNullValue("00"));
ASSERT_EQUALS(true, MathLib::isNullValue("+00"));
ASSERT_EQUALS(true, MathLib::isNullValue("-00"));
// inter zero value (hex)
ASSERT_EQUALS(true, MathLib::isNullValue("0x0"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0x0"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0x0"));
// unsigned integer zero value
ASSERT_EQUALS(true, MathLib::isNullValue("0U"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0U"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0U"));
// long integer zero value
ASSERT_EQUALS(true, MathLib::isNullValue("0L"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0L"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0L"));
// unsigned long integer zero value
ASSERT_EQUALS(true, MathLib::isNullValue("0UL"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0UL"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0UL"));
// unsigned long integer zero value
ASSERT_EQUALS(true, MathLib::isNullValue("0LU"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0LU"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0LU"));
// long long integer zero value
ASSERT_EQUALS(true, MathLib::isNullValue("0LL"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0LL"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0LL"));
// long long unsigend zero value
ASSERT_EQUALS(true, MathLib::isNullValue("0LLU"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0LLU"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0LLU"));
// unsigned long long zero value
ASSERT_EQUALS(true, MathLib::isNullValue("0ULL"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0ULL"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0ULL"));
// floating pointer zero value (no trailing zero after dot)
ASSERT_EQUALS(true, MathLib::isNullValue("0."));
ASSERT_EQUALS(true, MathLib::isNullValue("+0."));
ASSERT_EQUALS(true, MathLib::isNullValue("-0."));
// floating pointer zero value (1 trailing zero after dot)
ASSERT_EQUALS(true, MathLib::isNullValue("0.0"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0.0"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0.0"));
// floating pointer zero value (3 trailing zeros after dot)
ASSERT_EQUALS(true, MathLib::isNullValue("0.000"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0.000"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0.000"));
// floating pointer zero value (no trailing zero after dot)
ASSERT_EQUALS(true, MathLib::isNullValue("00."));
ASSERT_EQUALS(true, MathLib::isNullValue("+00."));
ASSERT_EQUALS(true, MathLib::isNullValue("-00."));
// floating pointer zero value (1 trailing zero after dot)
ASSERT_EQUALS(true, MathLib::isNullValue("00.0"));
ASSERT_EQUALS(true, MathLib::isNullValue("+00.0"));
ASSERT_EQUALS(true, MathLib::isNullValue("-00.0"));
// floating pointer zero value (3 trailing zero after dot)
ASSERT_EQUALS(true, MathLib::isNullValue("00.000"));
ASSERT_EQUALS(true, MathLib::isNullValue("+00.000"));
ASSERT_EQUALS(true, MathLib::isNullValue("-00.000"));
// floating pointer zero value (3 trailing zero after dot)
ASSERT_EQUALS(true, MathLib::isNullValue(".000"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E0"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E0"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E0"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E1"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E1"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E1"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E42"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E42"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E42"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E429999"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E429999"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E429999"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E+1"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E+1"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E+1"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E+42"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E+42"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E+42"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E+429999"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E+429999"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E+429999"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E-1"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E-1"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E-1"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E-42"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E-42"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E-42"));
// integer scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0E-429999"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0E-429999"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0E-429999"));
// floating point scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0.E0"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0.E0"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0.E0"));
// floating point scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0.E-0"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0.E-0"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0.E+0"));
// floating point scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0.E+0"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0.E+0"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0.E+0"));
// floating point scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("0.00E-0"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0.00E-0"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0.00E-0"));
// floating point scientific notation
ASSERT_EQUALS(true, MathLib::isNullValue("00000.00E-000000000"));
ASSERT_EQUALS(true, MathLib::isNullValue("+00000.00E-000000000"));
ASSERT_EQUALS(true, MathLib::isNullValue("-00000.00E-000000000"));
// floating point scientific notation (suffix f)
ASSERT_EQUALS(true, MathLib::isNullValue("0.f"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0.f"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0.f"));
// floating point scientific notation (suffix f)
ASSERT_EQUALS(true, MathLib::isNullValue("0.0f"));
ASSERT_EQUALS(true, MathLib::isNullValue("+0.0f"));
ASSERT_EQUALS(true, MathLib::isNullValue("-0.0f"));
// floating point scientific notation (suffix f)
ASSERT_EQUALS(true, MathLib::isNullValue("00.0f"));
ASSERT_EQUALS(true, MathLib::isNullValue("+00.0f"));
ASSERT_EQUALS(true, MathLib::isNullValue("-00.0f"));
// floating point scientific notation (suffix f)
ASSERT_EQUALS(true, MathLib::isNullValue("00.00f"));
ASSERT_EQUALS(true, MathLib::isNullValue("+00.00f"));
ASSERT_EQUALS(true, MathLib::isNullValue("-00.00f"));
// floating point scientific notation (suffix f)
ASSERT_EQUALS(true, MathLib::isNullValue("00.00E+1f"));
ASSERT_EQUALS(true, MathLib::isNullValue("+00.00E+1f"));
ASSERT_EQUALS(true, MathLib::isNullValue("-00.00E+1f"));
// negative testing
ASSERT_EQUALS(false, MathLib::isNullValue("0.1"));
ASSERT_EQUALS(false, MathLib::isNullValue("1.0"));
ASSERT_EQUALS(false, MathLib::isNullValue("0.01"));
ASSERT_EQUALS(false, MathLib::isNullValue("-00.01e-12"));
ASSERT_EQUALS(false, MathLib::isNullValue("-00.01e+12"));
ASSERT_EQUALS(false, MathLib::isNullValue(""));
ASSERT_EQUALS(false, MathLib::isNullValue("x"));
ASSERT_EQUALS(false, MathLib::isNullValue("garbage"));
// suffix LUL is not allowed
ASSERT_EQUALS(false, MathLib::isNullValue("0LUL"));
ASSERT_EQUALS(false, MathLib::isNullValue("+0LUL"));
ASSERT_EQUALS(false, MathLib::isNullValue("-0LUL"));
}
}; };
REGISTER_TEST(TestMathLib) REGISTER_TEST(TestMathLib)