Skip to content

Commit 9c08885

Browse files
committed
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.
1 parent 1fafc7f commit 9c08885

2 files changed

Lines changed: 263 additions & 5 deletions

File tree

lib/mathlib.cpp

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -598,13 +598,107 @@ bool MathLib::isLessEqual(const std::string &first, const std::string &second)
598598
return toDoubleNumber(first) <= toDoubleNumber(second);
599599
}
600600

601-
bool MathLib::isNullValue(const std::string &str)
601+
bool MathLib::isNullValue(const std::string &s)
602602
{
603-
for (size_t i = 0; i < str.size(); i++) {
604-
if (std::isdigit(static_cast<unsigned char>(str[i])) && str[i] != '0') // May not contain digits other than 0
603+
enum {START, PLUSMINUS, LEADING_ZERO, BIN_OR_HEX_PREFIX, DOT, TRAILING_ZERO, TRAILING_F, ZERO, E, E_PLUSMINUS, E_DIGIT} state = START;
604+
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
605+
switch (state) {
606+
case START:
607+
if (*it == '+' || *it == '-')
608+
state = PLUSMINUS;
609+
else if (*it == '0')
610+
state = LEADING_ZERO;
611+
else if (*it == '.')
612+
state = DOT;
613+
else
614+
return isValidSuffix(it, s.end());
615+
break;
616+
case PLUSMINUS:
617+
if (*it == '0')
618+
state = LEADING_ZERO;
619+
else
620+
return false;
621+
break;
622+
case LEADING_ZERO:
623+
if (*it == '0')
624+
state = LEADING_ZERO;
625+
else if (*it == 'b' || *it == 'B')
626+
state = BIN_OR_HEX_PREFIX;
627+
else if (*it == 'x' || *it == 'X')
628+
state = BIN_OR_HEX_PREFIX;
629+
else if (*it == '.')
630+
state = DOT;
631+
else if (*it == 'e' || *it == 'E')
632+
state = E;
633+
else
634+
return isValidSuffix(it, s.end());
635+
break;
636+
case BIN_OR_HEX_PREFIX:
637+
if (*it == '0')
638+
state = ZERO;
639+
else
640+
return false;
641+
break;
642+
case ZERO:
643+
if (*it == '0')
644+
state = ZERO;
645+
else
646+
return isValidSuffix(it, s.end());
647+
break;
648+
case DOT:
649+
if (*it == '0')
650+
state = TRAILING_ZERO;
651+
else if (*it == 'f' || *it == 'F')
652+
state = TRAILING_F;
653+
else if (*it == 'e' || *it == 'E')
654+
state = E;
655+
else
656+
return false;
657+
break;
658+
case E:
659+
if (*it == '+' || *it == '-')
660+
state = E_PLUSMINUS;
661+
else if (isdigit(*it))
662+
state = E_DIGIT;
663+
else
664+
return false;
665+
break;
666+
case E_PLUSMINUS:
667+
if (isdigit(*it))
668+
state = E_DIGIT;
669+
else
670+
return false;
671+
break;
672+
case E_DIGIT:
673+
if (isdigit(*it))
674+
state = E_DIGIT;
675+
else if (*it == 'f' || *it == 'F')
676+
state = TRAILING_F;
677+
else
678+
return false;
679+
break;
680+
case TRAILING_ZERO:
681+
if (*it == '0')
682+
state = TRAILING_ZERO;
683+
else if (*it == 'f' || *it == 'F')
684+
state = TRAILING_F;
685+
else if (*it == 'e' || *it == 'E')
686+
state = E;
687+
else
688+
return false;
689+
break;
690+
default:
605691
return false;
692+
}
606693
}
607-
return !str.empty() && (std::isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-' || str[0] == '+'); // Has to be a number
694+
return state == LEADING_ZERO || state == ZERO || state == DOT || state == E_DIGIT || state == TRAILING_ZERO || state == TRAILING_F;
695+
/*
696+
for (size_t i = 0; i < str.size(); i++) {
697+
if (std::isdigit(static_cast<unsigned char>(str[i])) && str[i] != '0') // May not contain digits other than 0
698+
return false;
699+
}
700+
return !str.empty() && (std::isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-' || str[0] == '+'); // Has to be a number
701+
*/
608702
}
609703

610704
bool MathLib::isOctalDigit(char c)

test/testmathlib.cpp

Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class TestMathLib : public TestFixture {
4545
TEST_CASE(calculate);
4646
TEST_CASE(calculate1);
4747
TEST_CASE(convert);
48-
TEST_CASE(naninf)
48+
TEST_CASE(naninf);
49+
TEST_CASE(isNullValue);
4950
}
5051

5152
void isGreater() const {
@@ -601,6 +602,169 @@ class TestMathLib : public TestFixture {
601602
ASSERT_EQUALS("inf.0", MathLib::divide("3.0", "0.0")); // inf
602603
ASSERT_EQUALS("-inf.0", MathLib::divide("-3.0", "0.0")); // -inf (#5142)
603604
}
605+
606+
void isNullValue() const {
607+
// inter zero value
608+
ASSERT_EQUALS(true, MathLib::isNullValue("0"));
609+
ASSERT_EQUALS(true, MathLib::isNullValue("+0"));
610+
ASSERT_EQUALS(true, MathLib::isNullValue("-0"));
611+
// inter zero value (octal)
612+
ASSERT_EQUALS(true, MathLib::isNullValue("00"));
613+
ASSERT_EQUALS(true, MathLib::isNullValue("+00"));
614+
ASSERT_EQUALS(true, MathLib::isNullValue("-00"));
615+
// inter zero value (hex)
616+
ASSERT_EQUALS(true, MathLib::isNullValue("0x0"));
617+
ASSERT_EQUALS(true, MathLib::isNullValue("+0x0"));
618+
ASSERT_EQUALS(true, MathLib::isNullValue("-0x0"));
619+
// unsigned integer zero value
620+
ASSERT_EQUALS(true, MathLib::isNullValue("0U"));
621+
ASSERT_EQUALS(true, MathLib::isNullValue("+0U"));
622+
ASSERT_EQUALS(true, MathLib::isNullValue("-0U"));
623+
// long integer zero value
624+
ASSERT_EQUALS(true, MathLib::isNullValue("0L"));
625+
ASSERT_EQUALS(true, MathLib::isNullValue("+0L"));
626+
ASSERT_EQUALS(true, MathLib::isNullValue("-0L"));
627+
// unsigned long integer zero value
628+
ASSERT_EQUALS(true, MathLib::isNullValue("0UL"));
629+
ASSERT_EQUALS(true, MathLib::isNullValue("+0UL"));
630+
ASSERT_EQUALS(true, MathLib::isNullValue("-0UL"));
631+
// unsigned long integer zero value
632+
ASSERT_EQUALS(true, MathLib::isNullValue("0LU"));
633+
ASSERT_EQUALS(true, MathLib::isNullValue("+0LU"));
634+
ASSERT_EQUALS(true, MathLib::isNullValue("-0LU"));
635+
// long long integer zero value
636+
ASSERT_EQUALS(true, MathLib::isNullValue("0LL"));
637+
ASSERT_EQUALS(true, MathLib::isNullValue("+0LL"));
638+
ASSERT_EQUALS(true, MathLib::isNullValue("-0LL"));
639+
// long long unsigend zero value
640+
ASSERT_EQUALS(true, MathLib::isNullValue("0LLU"));
641+
ASSERT_EQUALS(true, MathLib::isNullValue("+0LLU"));
642+
ASSERT_EQUALS(true, MathLib::isNullValue("-0LLU"));
643+
// unsigned long long zero value
644+
ASSERT_EQUALS(true, MathLib::isNullValue("0ULL"));
645+
ASSERT_EQUALS(true, MathLib::isNullValue("+0ULL"));
646+
ASSERT_EQUALS(true, MathLib::isNullValue("-0ULL"));
647+
// floating pointer zero value (no trailing zero after dot)
648+
ASSERT_EQUALS(true, MathLib::isNullValue("0."));
649+
ASSERT_EQUALS(true, MathLib::isNullValue("+0."));
650+
ASSERT_EQUALS(true, MathLib::isNullValue("-0."));
651+
// floating pointer zero value (1 trailing zero after dot)
652+
ASSERT_EQUALS(true, MathLib::isNullValue("0.0"));
653+
ASSERT_EQUALS(true, MathLib::isNullValue("+0.0"));
654+
ASSERT_EQUALS(true, MathLib::isNullValue("-0.0"));
655+
// floating pointer zero value (3 trailing zeros after dot)
656+
ASSERT_EQUALS(true, MathLib::isNullValue("0.000"));
657+
ASSERT_EQUALS(true, MathLib::isNullValue("+0.000"));
658+
ASSERT_EQUALS(true, MathLib::isNullValue("-0.000"));
659+
// floating pointer zero value (no trailing zero after dot)
660+
ASSERT_EQUALS(true, MathLib::isNullValue("00."));
661+
ASSERT_EQUALS(true, MathLib::isNullValue("+00."));
662+
ASSERT_EQUALS(true, MathLib::isNullValue("-00."));
663+
// floating pointer zero value (1 trailing zero after dot)
664+
ASSERT_EQUALS(true, MathLib::isNullValue("00.0"));
665+
ASSERT_EQUALS(true, MathLib::isNullValue("+00.0"));
666+
ASSERT_EQUALS(true, MathLib::isNullValue("-00.0"));
667+
// floating pointer zero value (3 trailing zero after dot)
668+
ASSERT_EQUALS(true, MathLib::isNullValue("00.000"));
669+
ASSERT_EQUALS(true, MathLib::isNullValue("+00.000"));
670+
ASSERT_EQUALS(true, MathLib::isNullValue("-00.000"));
671+
// floating pointer zero value (3 trailing zero after dot)
672+
ASSERT_EQUALS(true, MathLib::isNullValue(".000"));
673+
// integer scientific notation
674+
ASSERT_EQUALS(true, MathLib::isNullValue("0E0"));
675+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E0"));
676+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E0"));
677+
// integer scientific notation
678+
ASSERT_EQUALS(true, MathLib::isNullValue("0E1"));
679+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E1"));
680+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E1"));
681+
// integer scientific notation
682+
ASSERT_EQUALS(true, MathLib::isNullValue("0E42"));
683+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E42"));
684+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E42"));
685+
// integer scientific notation
686+
ASSERT_EQUALS(true, MathLib::isNullValue("0E429999"));
687+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E429999"));
688+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E429999"));
689+
// integer scientific notation
690+
ASSERT_EQUALS(true, MathLib::isNullValue("0E+1"));
691+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E+1"));
692+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E+1"));
693+
// integer scientific notation
694+
ASSERT_EQUALS(true, MathLib::isNullValue("0E+42"));
695+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E+42"));
696+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E+42"));
697+
// integer scientific notation
698+
ASSERT_EQUALS(true, MathLib::isNullValue("0E+429999"));
699+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E+429999"));
700+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E+429999"));
701+
// integer scientific notation
702+
ASSERT_EQUALS(true, MathLib::isNullValue("0E-1"));
703+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E-1"));
704+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E-1"));
705+
// integer scientific notation
706+
ASSERT_EQUALS(true, MathLib::isNullValue("0E-42"));
707+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E-42"));
708+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E-42"));
709+
// integer scientific notation
710+
ASSERT_EQUALS(true, MathLib::isNullValue("0E-429999"));
711+
ASSERT_EQUALS(true, MathLib::isNullValue("+0E-429999"));
712+
ASSERT_EQUALS(true, MathLib::isNullValue("-0E-429999"));
713+
// floating point scientific notation
714+
ASSERT_EQUALS(true, MathLib::isNullValue("0.E0"));
715+
ASSERT_EQUALS(true, MathLib::isNullValue("+0.E0"));
716+
ASSERT_EQUALS(true, MathLib::isNullValue("-0.E0"));
717+
// floating point scientific notation
718+
ASSERT_EQUALS(true, MathLib::isNullValue("0.E-0"));
719+
ASSERT_EQUALS(true, MathLib::isNullValue("+0.E-0"));
720+
ASSERT_EQUALS(true, MathLib::isNullValue("-0.E+0"));
721+
// floating point scientific notation
722+
ASSERT_EQUALS(true, MathLib::isNullValue("0.E+0"));
723+
ASSERT_EQUALS(true, MathLib::isNullValue("+0.E+0"));
724+
ASSERT_EQUALS(true, MathLib::isNullValue("-0.E+0"));
725+
// floating point scientific notation
726+
ASSERT_EQUALS(true, MathLib::isNullValue("0.00E-0"));
727+
ASSERT_EQUALS(true, MathLib::isNullValue("+0.00E-0"));
728+
ASSERT_EQUALS(true, MathLib::isNullValue("-0.00E-0"));
729+
// floating point scientific notation
730+
ASSERT_EQUALS(true, MathLib::isNullValue("00000.00E-000000000"));
731+
ASSERT_EQUALS(true, MathLib::isNullValue("+00000.00E-000000000"));
732+
ASSERT_EQUALS(true, MathLib::isNullValue("-00000.00E-000000000"));
733+
// floating point scientific notation (suffix f)
734+
ASSERT_EQUALS(true, MathLib::isNullValue("0.f"));
735+
ASSERT_EQUALS(true, MathLib::isNullValue("+0.f"));
736+
ASSERT_EQUALS(true, MathLib::isNullValue("-0.f"));
737+
// floating point scientific notation (suffix f)
738+
ASSERT_EQUALS(true, MathLib::isNullValue("0.0f"));
739+
ASSERT_EQUALS(true, MathLib::isNullValue("+0.0f"));
740+
ASSERT_EQUALS(true, MathLib::isNullValue("-0.0f"));
741+
// floating point scientific notation (suffix f)
742+
ASSERT_EQUALS(true, MathLib::isNullValue("00.0f"));
743+
ASSERT_EQUALS(true, MathLib::isNullValue("+00.0f"));
744+
ASSERT_EQUALS(true, MathLib::isNullValue("-00.0f"));
745+
// floating point scientific notation (suffix f)
746+
ASSERT_EQUALS(true, MathLib::isNullValue("00.00f"));
747+
ASSERT_EQUALS(true, MathLib::isNullValue("+00.00f"));
748+
ASSERT_EQUALS(true, MathLib::isNullValue("-00.00f"));
749+
// floating point scientific notation (suffix f)
750+
ASSERT_EQUALS(true, MathLib::isNullValue("00.00E+1f"));
751+
ASSERT_EQUALS(true, MathLib::isNullValue("+00.00E+1f"));
752+
ASSERT_EQUALS(true, MathLib::isNullValue("-00.00E+1f"));
753+
754+
// negative testing
755+
ASSERT_EQUALS(false, MathLib::isNullValue("0.1"));
756+
ASSERT_EQUALS(false, MathLib::isNullValue("1.0"));
757+
ASSERT_EQUALS(false, MathLib::isNullValue("0.01"));
758+
ASSERT_EQUALS(false, MathLib::isNullValue("-00.01e-12"));
759+
ASSERT_EQUALS(false, MathLib::isNullValue("-00.01e+12"));
760+
ASSERT_EQUALS(false, MathLib::isNullValue(""));
761+
ASSERT_EQUALS(false, MathLib::isNullValue("x"));
762+
ASSERT_EQUALS(false, MathLib::isNullValue("garbage"));
763+
// suffix LUL is not allowed
764+
ASSERT_EQUALS(false, MathLib::isNullValue("0LUL"));
765+
ASSERT_EQUALS(false, MathLib::isNullValue("+0LUL"));
766+
ASSERT_EQUALS(false, MathLib::isNullValue("-0LUL"));
767+
}
604768
};
605769

606770
REGISTER_TEST(TestMathLib)

0 commit comments

Comments
 (0)