Skip to content

Json: implement structural == for JsonObject/JsonValue/JsonArray - #1560

Merged
Mysticial merged 1 commit into
mainfrom
json-structural-equality
Oct 12, 2026
Merged

Mysticial merged 1 commit into
mainfrom
json-structural-equality

Conversation

@Gin890

@Gin890 Gin890 commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator

Resolves the TODO at Common/Cpp/Json/JsonObject.h:22 ("implement == properly. For JsonValue as well.").

What

Replaces the dump()-string comparison with real structural ==/!= for all three JSON types:

  • JsonValue (JsonValue.h, JsonValue.cpp) — type-strict, then compares the payload: primitives directly, and recursively for string/array/object.
  • JsonArray (JsonArray.h) — size, then element-wise.
  • JsonObject (JsonObject.h) — size, then key/value pairs (map iteration order).

JsonValue::operator== is declared as a friend in the header and defined in JsonValue.cpp, because it needs the complete types of JsonArray/JsonObject.

Why

The old JsonObject::operator== did x.dump() == y.dump(): two full JSON serializations (nlohmann round-trip + allocation) per comparison. The new operators do a cheap recursive structural compare.

Semantics

Matches the old dump-based behavior for all well-formed values — type-strict (int 1 != 1.0, since they dump as "1" vs "1.0"), key-order independent. One deliberate correction:

  • null != {}. The old compare treated them as equal because of a pre-existing serialization bug: to_nlohmann() (JsonTools.cpp:31) returns a null nlohmann::json for an empty object, so an empty object dump()s as "null" instead of "{}". The new == correctly treats them as different. (The dump() bug itself is left alone — separate concern, happy to fix in a follow-up.)

Verification

  • g++ -std=c++23 -Wall -Wextra -fsyntax-only clean on all four Json TUs plus a couple of consumer TUs.
  • Standalone test (218 checks): primitives, nesting, key-order invariance, !=, and a cross-check of new vs old equality across ~210 pairs — identical everywhere except the two null/{} cases above, where the new behavior is the correct one.

Replaces the TODO in JsonObject.h where operator== compared dump()
strings (two full JSON serializations and string allocations per
compare). The new operators compare types and contents recursively:
- JsonValue: type-strict, then primitive/pointer payload compare.
- JsonArray: size, then element-wise.
- JsonObject: size, then key/value pairs (std::map iteration order).

Semantics match the old dump-based == for all well-formed values
(int 1 != 1.0, key order irrelevant), with one deliberate fix:
null != {} — the old compare treated them as equal because
to_nlohmann() serializes an empty object as null (pre-existing
dump bug, tracked separately).
@Mysticial
Mysticial merged commit 6beff70 into main Oct 12, 2026
14 checks passed
@Mysticial
Mysticial deleted the json-structural-equality branch October 12, 2026 02:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants