@@ -45,8 +45,10 @@ MC_EXEC_DEFINE_EXEC_METHOD(Arrays, Split, 4)
4545MC_EXEC_DEFINE_EXEC_METHOD(Arrays, SplitByRow, 2 )
4646MC_EXEC_DEFINE_EXEC_METHOD(Arrays, SplitByColumn, 2 )
4747MC_EXEC_DEFINE_EXEC_METHOD(Arrays, SplitAsSet, 3 )
48- MC_EXEC_DEFINE_EXEC_METHOD(Arrays, Union, 2 )
49- MC_EXEC_DEFINE_EXEC_METHOD(Arrays, Intersect, 2 )
48+ MC_EXEC_DEFINE_EXEC_METHOD(Arrays, Union, 3 )
49+ MC_EXEC_DEFINE_EXEC_METHOD(Arrays, Intersect, 3 )
50+ MC_EXEC_DEFINE_EXEC_METHOD(Arrays, UnionRecursive, 3 )
51+ MC_EXEC_DEFINE_EXEC_METHOD(Arrays, IntersectRecursive, 3 )
5052MC_EXEC_DEFINE_EVAL_METHOD(Arrays, ArrayEncode, 2 )
5153MC_EXEC_DEFINE_EVAL_METHOD(Arrays, ArrayDecode, 2 )
5254MC_EXEC_DEFINE_EVAL_METHOD(Arrays, MatrixMultiply, 3 )
@@ -560,117 +562,173 @@ void MCArraysExecSplitAsSet(MCExecContext& ctxt, MCStringRef p_string, MCStringR
560562
561563// //////////////////////////////////////////////////////////////////////////////
562564
563- void MCArraysDoUnion (MCExecContext& ctxt, MCArrayRef p_dst_array, MCArrayRef p_src_array, bool p_recursive)
565+ //
566+ // Semantics of 'union tLeft with tRight [recursively]'
567+ //
568+ // repeat for each key tKey in tRight
569+ // if tKey is not among the keys of tLeft then
570+ // put tRight[tKey] into tLeft[tKey]
571+ // else if tRecursive then
572+ // union tLeft[tKey] with tRight[tKey] recursively
573+ // end if
574+ // end repeat
575+ //
576+
577+ void MCArraysDoUnion (MCExecContext& ctxt, MCValueRef p_dst, MCValueRef p_src, bool p_recursive, MCValueRef& r_result)
564578{
565- MCNameRef t_key;
566- MCValueRef t_src_value;
567- MCValueRef t_dst_value;
568- uintptr_t t_iterator;
569- t_iterator = 0 ;
579+ if (!MCValueIsArray (p_src))
580+ {
581+ r_result = MCValueRetain (p_dst);
582+ return ;
583+ }
584+
585+ if (!MCValueIsArray (p_dst))
586+ {
587+ r_result = MCValueRetain (p_src);
588+ return ;
589+
590+ }
591+
592+ MCArrayRef t_src_array;
593+ t_src_array = (MCArrayRef)p_src;
594+
595+ MCArrayRef t_dst_array;
596+ t_dst_array = (MCArrayRef)p_dst;
570597
571- bool t_is_array;
598+ MCAutoArrayRef t_result;
599+ if (!MCArrayMutableCopy (t_dst_array, &t_result))
600+ return ;
601+
602+ MCNameRef t_key;
603+ MCValueRef t_src_value;
604+ MCValueRef t_dst_value;
605+ uintptr_t t_iterator;
606+ t_iterator = 0 ;
572607
573- while (MCArrayIterate (p_src_array , t_iterator, t_key, t_src_value))
608+ while (MCArrayIterate (t_src_array , t_iterator, t_key, t_src_value))
574609 {
575- if (MCArrayFetchValue (p_dst_array, ctxt . GetCaseSensitive (), t_key, t_dst_value))
610+ bool t_key_exists;
611+ t_key_exists = MCArrayFetchValue (t_dst_array, ctxt . GetCaseSensitive (), t_key, t_dst_value);
612+
613+ if (t_key_exists && !p_recursive)
614+ continue ;
615+
616+ MCAutoValueRef t_recursive_result;
617+ if (!t_key_exists)
576618 {
577- if (p_recursive && MCValueIsArray (t_dst_value) && MCValueIsArray (t_src_value))
578- {
579- // AL-2015-02-23: [[ Bug 14658 ]] Ensure recursive set operations are
580- // performed on mutable copies of sub-arrays.
581- MCAutoArrayRef t_dst_subarray;
582- if (!MCArrayMutableCopy ((MCArrayRef)t_dst_value, &t_dst_subarray))
583- return ;
584-
585- MCArraysExecUnionRecursive (ctxt, *t_dst_subarray, (MCArrayRef)t_src_value);
586-
587- if (!MCArrayStoreValue (p_dst_array, ctxt . GetCaseSensitive (), t_key, *t_dst_subarray))
588- return ;
589-
590- if (ctxt . HasError ())
591- return ;
592- }
593- continue ;
619+ t_recursive_result = t_src_value;
620+ }
621+ else if (p_recursive)
622+ {
623+ MCArraysDoUnion (ctxt, t_dst_value, t_src_value, true , &t_recursive_result);
624+
625+ if (ctxt . HasError ())
626+ return ;
594627 }
595628
596- if (!MCArrayStoreValue (p_dst_array , ctxt . GetCaseSensitive (), t_key, MCValueRetain (t_src_value) ))
597- {
598- ctxt . Throw ();
599- return ;
600- }
629+ if (!MCArrayStoreValue (*t_result , ctxt . GetCaseSensitive (), t_key, *t_recursive_result ))
630+ {
631+ ctxt . Throw ();
632+ return ;
633+ }
601634 }
635+
636+ r_result = MCValueRetain (*t_result);
602637}
603638
604- void MCArraysDoIntersect (MCExecContext& ctxt, MCArrayRef p_dst_array, MCArrayRef p_src_array, bool p_recursive)
639+ //
640+ // Semantics of 'intersect tLeft with tRight [recursively]'
641+ //
642+ // repeat for each key tKey in tLeft
643+ // if tKey is not among the keys of tRight then
644+ // delete variable tLeft[tKey]
645+ // else if tRecursive then
646+ // intersect tLeft[tKey] with tRight[tKey] recursively
647+ // end if
648+ // end repeat
649+ //
650+
651+ void MCArraysDoIntersect (MCExecContext& ctxt, MCValueRef p_dst, MCValueRef p_src, bool p_recursive, MCValueRef& r_result)
605652{
606- MCNameRef t_key;
607- MCValueRef t_src_value;
608- MCValueRef t_dst_value;
609- MCAutoArrayRef t_orig_dst_array;
610- uintptr_t t_iterator;
611- t_iterator = 0 ;
612-
613- bool t_is_array;
653+ if (!MCValueIsArray (p_dst))
654+ {
655+ r_result = MCValueRetain (p_dst);
656+ return ;
657+
658+ }
614659
615- // TS-2015-19-18: [[ Bug 15948 ]] Take a copy of p_dst_array and iterate through
616- // the copy so that we are not removing values from the same array. Otherwise
617- // the array may be rehashed during the MCArrayRemoveValue() call and break the
618- // iteration sequence.
619- if (!MCArrayCopy (p_dst_array, &t_orig_dst_array)) {
660+ if (!MCValueIsArray (p_src))
661+ {
662+ r_result = MCValueRetain (kMCEmptyString );
620663 return ;
621664 }
622665
623- // Loop through the copy of the array, not the one that we will be removing entries
624- // from.
625- while (MCArrayIterate (*t_orig_dst_array, t_iterator, t_key, t_dst_value))
666+ MCArrayRef t_dst_array;
667+ t_dst_array = (MCArrayRef)p_dst;
668+
669+ MCArrayRef t_src_array;
670+ t_src_array = (MCArrayRef)p_src;
671+
672+ MCAutoArrayRef t_result;
673+ if (!MCArrayMutableCopy (t_dst_array, &t_result))
674+ return ;
675+
676+ MCNameRef t_key;
677+ MCValueRef t_src_value;
678+ MCValueRef t_dst_value;
679+ uintptr_t t_iterator;
680+ t_iterator = 0 ;
681+
682+ while (MCArrayIterate (t_dst_array, t_iterator, t_key, t_dst_value))
626683 {
627- if (MCArrayFetchValue (p_src_array, ctxt . GetCaseSensitive (), t_key, t_src_value))
684+ bool t_key_exists;
685+ t_key_exists = MCArrayFetchValue (t_src_array, ctxt . GetCaseSensitive (), t_key, t_src_value);
686+
687+ if (t_key_exists && !p_recursive)
688+ continue ;
689+
690+ if (!t_key_exists)
628691 {
629- if (p_recursive && MCValueIsArray (t_dst_value) && MCValueIsArray (t_src_value ))
692+ if (! MCArrayRemoveValue (*t_result, ctxt . GetCaseSensitive (), t_key ))
630693 {
631- // AL-2015-02-23: [[ Bug 14658 ]] Ensure recursive set operations are
632- // performed on mutable copies of sub-arrays.
633- MCAutoArrayRef t_dst_subarray;
634- if (!MCArrayMutableCopy ((MCArrayRef)t_dst_value, &t_dst_subarray))
635- return ;
636-
637- MCArraysExecIntersectRecursive (ctxt, *t_dst_subarray, (MCArrayRef)t_src_value);
638-
639- if (!MCArrayStoreValue (p_dst_array, ctxt . GetCaseSensitive (), t_key, *t_dst_subarray))
640- return ;
641-
642- if (ctxt . HasError ())
643- return ;
694+ ctxt . Throw ();
695+ return ;
644696 }
645- continue ;
646697 }
647-
648- if (!MCArrayRemoveValue (p_dst_array, ctxt . GetCaseSensitive (), t_key))
649- {
650- ctxt . Throw ();
651- return ;
652- }
698+ else if (p_recursive)
699+ {
700+ MCAutoValueRef t_recursive_result;
701+ MCArraysDoIntersect (ctxt, t_dst_value, t_src_value, true , &t_recursive_result);
702+
703+ if (ctxt . HasError ())
704+ return ;
705+
706+ if (!MCArrayStoreValue (*t_result, ctxt . GetCaseSensitive (), t_key, *t_recursive_result))
707+ return ;
708+ }
653709 }
710+
711+ r_result = MCValueRetain (*t_result);
654712}
655713
656- void MCArraysExecUnion (MCExecContext& ctxt, MCArrayRef p_dst_array, MCArrayRef p_src_array )
714+ void MCArraysExecUnion (MCExecContext& ctxt, MCValueRef p_dst, MCValueRef p_src, MCValueRef& r_result )
657715{
658- MCArraysDoUnion (ctxt, p_dst_array, p_src_array , false );
716+ MCArraysDoUnion (ctxt, p_dst, p_src , false , r_result );
659717}
660718
661- void MCArraysExecIntersect (MCExecContext& ctxt, MCArrayRef p_dst_array, MCArrayRef p_src_array )
719+ void MCArraysExecIntersect (MCExecContext& ctxt, MCValueRef p_dst, MCValueRef p_src, MCValueRef& r_result )
662720{
663- MCArraysDoIntersect (ctxt, p_dst_array, p_src_array , false );
721+ MCArraysDoIntersect (ctxt, p_dst, p_src , false , r_result );
664722}
665723
666- void MCArraysExecUnionRecursive (MCExecContext& ctxt, MCArrayRef p_dst_array, MCArrayRef p_src_array )
724+ void MCArraysExecUnionRecursive (MCExecContext& ctxt, MCValueRef p_dst, MCValueRef p_src, MCValueRef& r_result )
667725{
668- MCArraysDoUnion (ctxt, p_dst_array, p_src_array , true );
726+ MCArraysDoUnion (ctxt, p_dst, p_src , true , r_result );
669727}
670728
671- void MCArraysExecIntersectRecursive (MCExecContext& ctxt, MCArrayRef p_dst_array, MCArrayRef p_src_array )
729+ void MCArraysExecIntersectRecursive (MCExecContext& ctxt, MCValueRef p_dst, MCValueRef p_src, MCValueRef& r_result )
672730{
673- MCArraysDoIntersect (ctxt, p_dst_array, p_src_array , true );
731+ MCArraysDoIntersect (ctxt, p_dst, p_src , true , r_result );
674732}
675733
676734// //////////////////////////////////////////////////////////////////////////////
0 commit comments