Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions src/TinyJSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4679,6 +4679,11 @@ namespace TinyJSON
return false;
}

bool TJValue::is_numeric(bool /*strict*/) const
{
return false;
}

const TJCHAR* TJValue::dump(formatting formatting, const TJCHAR* indent) const
{
free_last_dump();
Expand Down Expand Up @@ -5087,6 +5092,63 @@ namespace TinyJSON
return true;
}

bool TJValueString::is_numeric(bool strict) const
{
if (strict)
{
return false;
}

const TJCHAR* s = raw_value();
if (!s || *s == TJ_NULL_TERMINATOR)
{
return false;
}

bool has_digit = false;
bool has_decimal = false;
bool has_exponent = false;

if (*s == '+' || *s == '-')
{
s++;
}

while (*s != TJ_NULL_TERMINATOR)
{
if (std::isdigit(static_cast<unsigned char>(*s)))
{
has_digit = true;
}
else if (*s == '.')
{
if (has_decimal || has_exponent)
{
return false;
}
has_decimal = true;
}
else if (*s == 'e' || *s == 'E')
{
if (has_exponent || !has_digit)
{
return false;
}
has_exponent = true;
if (*(s + 1) == '+' || *(s + 1) == '-')
{
s++;
}
}
else
{
return false;
}
s++;
}
return has_digit;
}

void TJValueString::free_value()
{
if (nullptr != _value)
Expand Down Expand Up @@ -5173,6 +5235,11 @@ namespace TinyJSON
return !_is_true;
}

bool TJValueBoolean::is_numeric(bool /*strict*/) const
{
return false;
}

///////////////////////////////////////
/// TJValue null
TJValueNull::TJValueNull(const parse_options& options) :
Expand Down Expand Up @@ -5234,6 +5301,11 @@ namespace TinyJSON
return true;
}

bool TJValueNull::is_numeric(bool /*strict*/) const
{
return false;
}

///////////////////////////////////////
/// TJValueObject
TJValueObject::TJValueObject(const parse_options& options) :
Expand Down Expand Up @@ -5839,6 +5911,11 @@ namespace TinyJSON
return true;
}

bool TJValueObject::is_numeric(bool /*strict*/) const
{
return false;
}

unsigned int TJValueObject::get_number_of_items() const
{
if (_members == nullptr)
Expand Down Expand Up @@ -6310,6 +6387,11 @@ namespace TinyJSON
return true;
}

bool TJValueArray::is_numeric(bool /*strict*/) const
{
return false;
}

unsigned int TJValueArray::get_number_of_items() const
{
if (_values == nullptr)
Expand Down Expand Up @@ -6630,6 +6712,11 @@ namespace TinyJSON
return true;
}

bool TJValueNumber::is_numeric(bool /*strict*/) const
{
return true;
}

long double TJValueNumber::get_float() const
{
auto value_float = dynamic_cast<const TinyJSON::TJValueNumberFloat*>(this);
Expand Down Expand Up @@ -7185,6 +7272,11 @@ namespace TinyJSON
return true;
}

bool TJValueComment::is_numeric(bool /*strict*/) const
{
return false;
}

const TJCHAR* TJValueComment::raw_value() const
{
return _value == nullptr ? TJCHARPREFIX("") : _value;
Expand Down
8 changes: 8 additions & 0 deletions src/TinyJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ class TJDictionary;
virtual bool is_false() const;
virtual bool is_null() const;
virtual bool is_comment() const;
virtual bool is_numeric(bool strict = false) const;

const TJCHAR* dump(formatting formatting = formatting::indented, const TJCHAR* indent = TJCHARPREFIX(" ")) const;
const TJCHAR* dump_string() const;
Expand Down Expand Up @@ -960,6 +961,7 @@ class TJDictionary;
/// </summary>
/// <returns></returns>
unsigned int get_number_of_elements() const;
bool is_numeric(bool strict = false) const override;

/// <summary>
/// Try and get a string value, if it does not exist, then we return null.
Expand Down Expand Up @@ -1551,6 +1553,7 @@ class TJDictionary;
TJValue* element_at(int idx) const;

bool is_array() const override;
bool is_numeric(bool strict = false) const override;

void add(const TJValue* value);
void add_boolean(bool value);
Expand Down Expand Up @@ -1690,6 +1693,7 @@ class TJDictionary;
virtual ~TJValueString();

bool is_string() const override;
bool is_numeric(bool strict = false) const override;

const TJCHAR* raw_value() const;

Expand Down Expand Up @@ -1727,6 +1731,7 @@ class TJDictionary;

bool is_true() const override;
bool is_false() const override;
bool is_numeric(bool strict = false) const override;

protected:
/// <summary>
Expand All @@ -1752,6 +1757,7 @@ class TJDictionary;
virtual ~TJValueNull() = default;

bool is_null() const override;
bool is_numeric(bool strict = false) const override;

protected:
/// <summary>
Expand All @@ -1775,6 +1781,7 @@ class TJDictionary;

public:
bool is_number() const override;
bool is_numeric(bool strict = false) const override;

long double get_float() const;
long long get_number() const;
Expand Down Expand Up @@ -1882,6 +1889,7 @@ class TJDictionary;
virtual ~TJValueComment();

bool is_comment() const override;
bool is_numeric(bool strict = false) const override;

const TJCHAR* raw_value() const;

Expand Down
80 changes: 80 additions & 0 deletions tests/testtinyjsonis_numeric.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Licensed to Florent Guelfucci under one or more agreements.
// Florent Guelfucci licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#include <gtest/gtest.h>
#define TJ_USE_CHAR 1
#include "../src/TinyJSON.h"

using namespace TinyJSON;

TEST(TestIsNumeric, NumericValue) {
auto* num = TJ::parse("123");
ASSERT_NE(nullptr, num);
EXPECT_TRUE(num->is_numeric(false));
EXPECT_TRUE(num->is_numeric(true));
delete num;
}

TEST(TestIsNumeric, NumericString) {
auto* num_str = TJ::parse("\"123\"");
ASSERT_NE(nullptr, num_str);
EXPECT_TRUE(num_str->is_numeric(false));
EXPECT_FALSE(num_str->is_numeric(true));
delete num_str;
}

TEST(TestIsNumeric, FloatNumericString) {
auto* float_str = TJ::parse("\"12.34\"");
ASSERT_NE(nullptr, float_str);
EXPECT_TRUE(float_str->is_numeric(false));
EXPECT_FALSE(float_str->is_numeric(true));
delete float_str;
}

TEST(TestIsNumeric, ScientificNumericString) {
auto* sci_str = TJ::parse("\"-0.5e10\"");
ASSERT_NE(nullptr, sci_str);
EXPECT_TRUE(sci_str->is_numeric(false));
EXPECT_FALSE(sci_str->is_numeric(true));
delete sci_str;
}

TEST(TestIsNumeric, NonNumericString) {
auto* alpha_str = TJ::parse("\"abc\"");
ASSERT_NE(nullptr, alpha_str);
EXPECT_FALSE(alpha_str->is_numeric(false));
EXPECT_FALSE(alpha_str->is_numeric(true));
delete alpha_str;
}

TEST(TestIsNumeric, BooleanValue) {
auto* boolean = TJ::parse("true");
ASSERT_NE(nullptr, boolean);
EXPECT_FALSE(boolean->is_numeric(false));
EXPECT_FALSE(boolean->is_numeric(true));
delete boolean;
}

TEST(TestIsNumeric, NullValue) {
auto* nul = TJ::parse("null");
ASSERT_NE(nullptr, nul);
EXPECT_FALSE(nul->is_numeric(false));
EXPECT_FALSE(nul->is_numeric(true));
delete nul;
}

TEST(TestIsNumeric, ObjectValue) {
auto* obj = TJ::parse("{}");
ASSERT_NE(nullptr, obj);
EXPECT_FALSE(obj->is_numeric(false));
EXPECT_FALSE(obj->is_numeric(true));
delete obj;
}

TEST(TestIsNumeric, ArrayValue) {
auto* arr = TJ::parse("[]");
ASSERT_NE(nullptr, arr);
EXPECT_FALSE(arr->is_numeric(false));
EXPECT_FALSE(arr->is_numeric(true));
delete arr;
}
Loading