diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index e11a5a393..3dd2c42df 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -2282,7 +2282,7 @@ - + True True diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index a9ef17e2d..601133576 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -2976,7 +2976,7 @@ ripple\json - + ripple\json\tests diff --git a/src/ripple/json/impl/json_value.cpp b/src/ripple/json/impl/json_value.cpp index f0e9ce749..b3d6f160b 100644 --- a/src/ripple/json/impl/json_value.cpp +++ b/src/ripple/json/impl/json_value.cpp @@ -443,77 +443,61 @@ Value::type () const return type_; } - -int -Value::compare ( const Value& other ) +static +int integerCmp (Int i, UInt ui) { - /* - int typeDelta = other.type_ - type_; - switch ( type_ ) - { - case nullValue: + // All negative numbers are less than all unsigned numbers. + if (i < 0) + return -1; - return other.type_ == type_; - case intValue: - if ( other.type_.isNumeric() - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue, - break; - case arrayValue: - delete value_.array_; - break; - case objectValue: - delete value_.map_; - default: - JSON_ASSERT_UNREACHABLE; - } - */ - return 0; // unreachable + // All unsigned numbers with bit 0 set are too big for signed integers. + if (ui & 0x8000) + return 1; + + // Now we can safely compare. + return (i < ui) ? -1 : (i == ui) ? 0 : 1; } -bool -Value::operator < ( const Value& other ) const +bool operator < (const Value& x, const Value& y) { - int typeDelta = type_ - other.type_; + if (auto signum = x.type_ - y.type_) + { + if (x.type_ == intValue && y.type_ == uintValue) + signum = integerCmp (x.value_.int_, y.value_.uint_); + else if (x.type_ == uintValue && y.type_ == intValue) + signum = - integerCmp (y.value_.int_, x.value_.uint_); + return signum < 0; + } - if ( typeDelta ) - return typeDelta < 0 ? true : false; - - switch ( type_ ) + switch (x.type_) { case nullValue: return false; case intValue: - return value_.int_ < other.value_.int_; + return x.value_.int_ < y.value_.int_; case uintValue: - return value_.uint_ < other.value_.uint_; + return x.value_.uint_ < y.value_.uint_; case realValue: - return value_.real_ < other.value_.real_; + return x.value_.real_ < y.value_.real_; case booleanValue: - return value_.bool_ < other.value_.bool_; + return x.value_.bool_ < y.value_.bool_; case stringValue: - return ( value_.string_ == 0 && other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp ( value_.string_, other.value_.string_ ) < 0 ); + return (x.value_.string_ == 0 && y.value_.string_) + || (y.value_.string_ && x.value_.string_ && + strcmp (x.value_.string_, y.value_.string_) < 0); case arrayValue: case objectValue: { - int delta = int ( value_.map_->size () - other.value_.map_->size () ); + if (int signum = int (x.value_.map_->size ()) - y.value_.map_->size ()) + return signum < 0; - if ( delta ) - return delta < 0; - - return (*value_.map_) < (*other.value_.map_); + return *x.value_.map_ < *y.value_.map_; } default: @@ -523,63 +507,43 @@ Value::operator < ( const Value& other ) const return 0; // unreachable } -bool -Value::operator <= ( const Value& other ) const +bool operator== (const Value& x, const Value& y) { - return ! (other > *this); -} - -bool -Value::operator >= ( const Value& other ) const -{ - return ! (*this < other); -} - -bool -Value::operator > ( const Value& other ) const -{ - return other < *this; -} - -bool -Value::operator == ( const Value& other ) const -{ - //if ( type_ != other.type_ ) - // GCC 2.95.3 says: - // attempt to take address of bit-field structure member `Json::Value::type_' - // Beats me, but a temp solves the problem. - int temp = other.type_; - - if ( type_ != temp ) + if (x.type_ != y.type_) + { + if (x.type_ == intValue && y.type_ == uintValue) + return ! integerCmp (x.value_.int_, y.value_.uint_); + if (x.type_ == uintValue && y.type_ == intValue) + return ! integerCmp (y.value_.int_, x.value_.uint_); return false; + } - switch ( type_ ) + switch (x.type_) { case nullValue: return true; case intValue: - return value_.int_ == other.value_.int_; + return x.value_.int_ == y.value_.int_; case uintValue: - return value_.uint_ == other.value_.uint_; + return x.value_.uint_ == y.value_.uint_; case realValue: - return value_.real_ == other.value_.real_; + return x.value_.real_ == y.value_.real_; case booleanValue: - return value_.bool_ == other.value_.bool_; + return x.value_.bool_ == y.value_.bool_; case stringValue: - return ( value_.string_ == other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp ( value_.string_, other.value_.string_ ) == 0 ); + return x.value_.string_ == y.value_.string_ + || (y.value_.string_ && x.value_.string_ && + ! strcmp (x.value_.string_, y.value_.string_)); case arrayValue: case objectValue: - return value_.map_->size () == other.value_.map_->size () - && (*value_.map_) == (*other.value_.map_); + return x.value_.map_->size () == y.value_.map_->size () + && *x.value_.map_ == *y.value_.map_; default: JSON_ASSERT_UNREACHABLE; @@ -588,12 +552,6 @@ Value::operator == ( const Value& other ) const return 0; // unreachable } -bool -Value::operator != ( const Value& other ) const -{ - return ! ( *this == other ); -} - const char* Value::asCString () const { diff --git a/src/ripple/json/json_value.h b/src/ripple/json/json_value.h index 3d23f679d..d3420bdb0 100644 --- a/src/ripple/json/json_value.h +++ b/src/ripple/json/json_value.h @@ -89,6 +89,18 @@ private: const char* str_; }; +inline bool operator!= (StaticString x, StaticString y) +{ + // TODO(tom): could I use x != y here because StaticStrings are supposed to + // be unique? + return strcmp (x, y); +} + +inline bool operator== (StaticString x, StaticString y) +{ + return ! (x != y); +} + inline bool operator== (std::string const& x, StaticString y) { return x == y.c_str(); @@ -234,16 +246,6 @@ public: ValueType type () const; - bool operator < ( const Value& other ) const; - bool operator <= ( const Value& other ) const; - bool operator >= ( const Value& other ) const; - bool operator > ( const Value& other ) const; - - bool operator == ( const Value& other ) const; - bool operator != ( const Value& other ) const; - - int compare ( const Value& other ); - const char* asCString () const; std::string asString () const; Int asInt () const; @@ -369,6 +371,9 @@ public: iterator begin (); iterator end (); + friend bool operator== (const Value&, const Value&); + friend bool operator< (const Value&, const Value&); + private: Value& resolveReference ( const char* key, bool isStatic ); @@ -387,6 +392,34 @@ private: int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. }; +bool operator== (const Value&, const Value&); + +inline +bool operator!= (const Value& x, const Value& y) +{ + return ! (x == y); +} + +bool operator< (const Value&, const Value&); + +inline +bool operator<= (const Value& x, const Value& y) +{ + return ! (y < x); +} + +inline +bool operator> (const Value& x, const Value& y) +{ + return y < x; +} + +inline +bool operator>= (const Value& x, const Value& y) +{ + return ! (x < y); +} + /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. * * - makeMemberName() and releaseMemberName() are called to respectively duplicate and diff --git a/src/ripple/json/tests/JsonCpp.test.cpp b/src/ripple/json/tests/json_value.test.cpp similarity index 70% rename from src/ripple/json/tests/JsonCpp.test.cpp rename to src/ripple/json/tests/json_value.test.cpp index 6bea69457..3f21f4f50 100644 --- a/src/ripple/json/tests/JsonCpp.test.cpp +++ b/src/ripple/json/tests/json_value.test.cpp @@ -25,7 +25,7 @@ namespace ripple { -class JsonCpp_test : public beast::unit_test::suite +class json_value_test : public beast::unit_test::suite { public: void test_bad_json () @@ -139,15 +139,72 @@ public: pass (); } + void + test_comparisons() + { + Json::Value a, b; + auto testEquals = [&] (std::string const& name) { + expect (a == b, "a == b " + name); + expect (a <= b, "a <= b " + name); + expect (a >= b, "a >= b " + name); + + expect (! (a != b), "! (a != b) " + name); + expect (! (a < b), "! (a < b) " + name); + expect (! (a > b), "! (a > b) " + name); + + expect (b == a, "b == a " + name); + expect (b <= a, "b <= a " + name); + expect (b >= a, "b >= a " + name); + + expect (! (b != a), "! (b != a) " + name); + expect (! (b < a), "! (b < a) " + name); + expect (! (b > a), "! (b > a) " + name); + }; + + auto testGreaterThan = [&] (std::string const& name) { + expect (! (a == b), "! (a == b) " + name); + expect (! (a <= b), "! (a <= b) " + name); + expect (a >= b, "a >= b " + name); + + expect (a != b, "a != b " + name); + expect (! (a < b), "! (a < b) " + name); + expect (a > b, "a > b " + name); + + expect (! (b == a), "! (b == a) " + name); + expect (b <= a, "b <= a " + name); + expect (! (b >= a), "! (b >= a) " + name); + + expect (b != a, "b != a " + name); + expect (b < a, "b < a " + name); + expect (! (b > a), "! (b > a) " + name); + }; + + a["a"] = Json::UInt (0); + b["a"] = Json::Int (0); + testEquals ("zero"); + + b["a"] = Json::Int (-1); + testGreaterThan ("negative"); + + Json::Int big = std::numeric_limits::max(); + Json::UInt bigger = big; + bigger++; + + a["a"] = bigger; + b["a"] = big; + testGreaterThan ("big"); + } + void run () { test_bad_json (); test_edge_cases (); test_copy (); test_move (); + test_comparisons (); } }; -BEAST_DEFINE_TESTSUITE(JsonCpp,json,ripple); +BEAST_DEFINE_TESTSUITE(json_value, json, ripple); } // ripple diff --git a/src/ripple/unity/json.cpp b/src/ripple/unity/json.cpp index 84eb25925..9908d89d1 100644 --- a/src/ripple/unity/json.cpp +++ b/src/ripple/unity/json.cpp @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include #include