@@ -335,9 +335,14 @@ static RyanJsonBool_e RyanJsonInternalCompare(RyanJson_t leftJson, RyanJson_t ri
335335 while (1 )
336336 {
337337 // 比较当前节点的类型、值与规模
338- RyanJsonCheckReturnFalse (RyanJsonGetType (leftCurrent ) == RyanJsonGetType (rightCurrent ));
339-
340- switch (RyanJsonGetType (leftCurrent ))
338+ RyanJsonType_e leftType = RyanJsonGetType (leftCurrent );
339+ RyanJsonCheckReturnFalse (leftType == RyanJsonGetType (rightCurrent ));
340+
341+ #if defined(__clang__ )
342+ #pragma clang diagnostic push
343+ #pragma clang diagnostic ignored "-Wcovered-switch-default"
344+ #endif
345+ switch (leftType )
341346 {
342347 case RyanJsonTypeNull : break ;
343348 case RyanJsonTypeBool :
@@ -371,6 +376,9 @@ static RyanJsonBool_e RyanJsonInternalCompare(RyanJson_t leftJson, RyanJson_t ri
371376 case RyanJsonTypeObject : RyanJsonCheckReturnFalse (RyanJsonGetSize (leftCurrent ) == RyanJsonGetSize (rightCurrent )); break ;
372377 default : return RyanJsonFalse ;
373378 }
379+ #if defined(__clang__ )
380+ #pragma clang diagnostic pop
381+ #endif
374382
375383 // 容器节点尝试下沉到子节点继续比较
376384 if (_checkType (leftCurrent , RyanJsonTypeArray ) || _checkType (leftCurrent , RyanJsonTypeObject ))
@@ -407,35 +415,84 @@ static RyanJsonBool_e RyanJsonInternalCompare(RyanJson_t leftJson, RyanJson_t ri
407415 }
408416 }
409417
410- // 同层前进,必要时回溯
418+ // 走到这里说明当前节点对已经比较完成,且若它们是容器,则其子树也已经比较完毕。
419+ // 接下来要在“不使用递归栈”的前提下,找到 DFS 意义上的下一个待比较节点对:
420+ // 1) 优先尝试同父层的下一个兄弟;
421+ // 2) 当前层没有兄弟时,沿内部 parent 回链逐层回溯;
422+ // 3) 一旦回溯到入口 root,说明整棵树已经完全比较结束。
411423 while (1 )
412424 {
425+ // 进入本循环时,leftCurrent/rightCurrent 表示“刚完成比较的节点对”。
426+ // 如果它已经回到入口 root,且前面也没有可继续下沉的子节点,
427+ // 则表示从 root 出发的整棵树都已匹配完成,可以直接返回 True。
413428 if (leftCurrent == leftJson ) { return RyanJsonTrue ; }
414429
415- // 优先定位右侧对应的兄弟节点
430+ // 先看左侧当前节点是否还有同父兄弟。
431+ // 有的话,下一个比较目标就必须切到这个兄弟;右侧则去找“语义上与它对应”的兄弟。
416432 RyanJson_t leftNext = RyanJsonGetNext (leftCurrent );
417433 if (leftNext )
418434 {
419435 RyanJson_t rightNext = NULL ;
420- if (RyanJsonFalse == RyanJsonIsKey (leftNext )) { rightNext = RyanJsonGetNext (rightCurrent ); }
436+ if (RyanJsonFalse == RyanJsonIsKey (leftNext ))
437+ {
438+ // 无 key 节点只会出现在数组路径上,数组比较是严格按顺序进行的,
439+ // 因而右侧可以直接取当前节点的 next 兄弟,不需要额外查找。
440+ rightNext = RyanJsonGetNext (rightCurrent );
441+ }
421442 else
422443 {
423444 RyanJsonCheckAssert (RyanJsonTrue == RyanJsonIsKey (leftNext ));
424445 const char * leftNextKey = RyanJsonGetKey (leftNext );
425446 RyanJson_t rightParent = RyanJsonInternalGetParent (rightCurrent );
426447
427- // 同序快路径:优先尝试右侧当前节点的直接兄弟,未命中再回退到按 key 查找
428- RyanJson_t rightCandidate = RyanJsonGetNext (rightCurrent );
429- if (rightCandidate ) { RyanJsonCheckAssert (RyanJsonTrue == RyanJsonIsKey (rightCandidate )); }
430- if (rightCandidate &&
431- RyanJsonTrue == RyanJsonInternalStrEq (leftNextKey , RyanJsonGetKey (rightCandidate )))
448+ // 对象比较是“同层无序、同 key 对齐”语义,不能像数组那样直接依赖 rightCurrent->next:
449+ // - strict 模式下 key 唯一,按 key 找即可;
450+ // - non-strict 模式下允许重复 key,必须继续保证“同 key 的第 N 次出现”彼此对齐,
451+ // 否则会把后一个重复 key 错配到右侧第一个同名节点,导致 Compare/CompareOnlyKey 语义漂移。
452+ RyanJsonCheckAssert (NULL != rightParent && RyanJsonTrue == RyanJsonIsObject (rightParent ));
453+ #if true == RyanJsonStrictObjectKeyCheck
454+ // strict 模式下 key 唯一,直接按 key 查找即可。
455+ rightNext = RyanJsonGetObjectByKey (rightParent , leftNextKey );
456+ #else
457+ // 非严格模式下允许重复 key,按“同 key + 相同出现序号”精确匹配。
458+ RyanJson_t leftParent = RyanJsonInternalGetParent (leftCurrent );
459+ RyanJsonCheckAssert (NULL != leftParent && RyanJsonTrue == RyanJsonIsObject (leftParent ));
460+
461+ // 先在左父节点里统计 leftNext 是该 key 的第几次出现(0-based)。
462+ // 例如 leftParent 子节点是 a,b,a,c,则第二个 a 的序号是 1。
463+ uint32_t leftSameKeyIndex = 0 ;
464+ RyanJson_t leftScan = RyanJsonGetObjectValue (leftParent );
465+ RyanJsonCheckAssert (NULL != leftScan );
466+ while (leftScan != leftNext )
432467 {
433- rightNext = rightCandidate ;
468+ RyanJsonCheckAssert (RyanJsonTrue == RyanJsonIsKey (leftScan ));
469+ if (RyanJsonTrue == RyanJsonInternalStrEq (leftNextKey , RyanJsonGetKey (leftScan )))
470+ {
471+ leftSameKeyIndex ++ ;
472+ }
473+ leftScan = RyanJsonGetNext (leftScan );
474+ RyanJsonCheckAssert (NULL != leftScan );
434475 }
435- else
476+
477+ // 再在右父节点里找到“同 key 的同序号节点”。
478+ // 这样重复 key 的比较就不是“命中任意一个同名节点”,而是稳定地按出现次序对齐。
479+ uint32_t rightSameKeyIndex = 0 ;
480+ RyanJson_t rightScan = RyanJsonGetObjectValue (rightParent );
481+ while (rightScan )
436482 {
437- rightNext = RyanJsonGetObjectByKey (rightParent , leftNextKey );
483+ RyanJsonCheckAssert (RyanJsonTrue == RyanJsonIsKey (rightScan ));
484+ if (RyanJsonTrue == RyanJsonInternalStrEq (leftNextKey , RyanJsonGetKey (rightScan )))
485+ {
486+ if (rightSameKeyIndex == leftSameKeyIndex )
487+ {
488+ rightNext = rightScan ;
489+ break ;
490+ }
491+ rightSameKeyIndex ++ ;
492+ }
493+ rightScan = RyanJsonGetNext (rightScan );
438494 }
495+ #endif
439496 }
440497
441498 RyanJsonCheckReturnFalse (NULL != rightNext );
@@ -445,9 +502,17 @@ static RyanJsonBool_e RyanJsonInternalCompare(RyanJson_t leftJson, RyanJson_t ri
445502 break ;
446503 }
447504
448- // 无兄弟可比时回溯到父层
505+ // 当前层已没有可比较的兄弟,开始回溯。
506+ // 这里故意不用 RyanJsonGetNext(leftCurrent):
507+ // - 公开语义下,没有兄弟时它会返回 NULL;
508+ // - 但内部链表约定中,“最后一个兄弟节点的 next”挂的是父节点,
509+ // 正是这里做迭代式 DFS 回溯所需要的那条内部回链。
449510 leftCurrent = leftCurrent -> next ;
450511
512+ // leftCurrent 此时已经被抬回父节点,所以这里按“父节点类型”决定右侧如何回溯。
513+ // - array:左右两边始终按相同 sibling 顺序推进,rightCurrent->next 正好也挂回父节点;
514+ // - object:右侧当前节点可能是按 key/序号匹配得到的任意兄弟,未必处在链表尾部,
515+ // 这时不能假设 rightCurrent->next 是父节点,只能显式调用 RyanJsonInternalGetParent。
451516 if (RyanJsonIsArray (leftCurrent )) { rightCurrent = rightCurrent -> next ; }
452517 else
453518 {
0 commit comments