# This file implements the following set operators: # (==) set equality (ASCII) # ≡ is identical to # ≢ is not identical to proto sub infix:<<(==)>>($, $, *% --> Bool:D) is pure {*} multi sub infix:<<(==)>>(Setty:D $a, Setty:D $b --> Bool:D) { nqp::unless( nqp::eqaddr($a,$b), nqp::stmts( # A and B not same object (my \araw := $a.RAW-HASH), (my \braw := $b.RAW-HASH), nqp::if( araw && braw, nqp::if( # A and B both allocated nqp::isne_i(nqp::elems(araw),nqp::elems(braw)), (return False), # not same number of elems nqp::stmts( # same number of elems in A and B (my \iter := nqp::iterator(araw)), nqp::while( # have something to iterate over iter, nqp::unless( nqp::existskey(braw,nqp::iterkey_s(nqp::shift(iter))), return False # elem in A doesn't exist in B ) ) ) ), nqp::if( # A and B not both allocated (araw && nqp::elems(araw)) || (braw && nqp::elems(braw)), return False # allocated side contains elements ) ) ) ); True } multi sub infix:<<(==)>>(Setty:D $a, Mixy:D $b --> Bool:D) { $a.Mix (==) $b } multi sub infix:<<(==)>>(Setty:D $a, Baggy:D $b --> Bool:D) { $a.Bag (==) $b } multi sub infix:<<(==)>>(Setty:D $a, Any \b --> Bool:D) { $a (==) b.Set } multi sub infix:<<(==)>>(Mixy:D $a, Mixy:D $b --> Bool:D) { Rakudo::QuantHash.MIX-IS-EQUAL($a, $b) } multi sub infix:<<(==)>>(Mixy:D $a, Baggy:D $b --> Bool:D) { Rakudo::QuantHash.MIX-IS-EQUAL($a, $b) } multi sub infix:<<(==)>>(Mixy:D $a, Setty:D $b --> Bool:D) { $a (==) $b.Mix } multi sub infix:<<(==)>>(Mixy:D $a, Any \b --> Bool:D) { $a (==) b.Mix } multi sub infix:<<(==)>>(Baggy:D $a, Mixy:D $b --> Bool:D) { Rakudo::QuantHash.MIX-IS-EQUAL($a, $b) } multi sub infix:<<(==)>>(Baggy:D $a, Baggy:D $b --> Bool:D) { Rakudo::QuantHash.MIX-IS-EQUAL($a, $b) } multi sub infix:<<(==)>>(Baggy:D $a, Setty:D $b --> Bool:D) { $a (==) $b.Bag } multi sub infix:<<(==)>>(Baggy:D $a, Any \b --> Bool:D) { $a (==) b.Bag } multi sub infix:<<(==)>>(Map:D \a, Map:D \b --> Bool:D) { nqp::unless( nqp::eqaddr(nqp::decont(a),nqp::decont(b)), nqp::if( # A and B are different nqp::isne_i( nqp::elems(my \araw := nqp::getattr(nqp::decont(a),Map,'$!storage')), nqp::elems(my \braw := nqp::getattr(nqp::decont(b),Map,'$!storage')) ), (return False), # different number of elements nqp::if( # same size nqp::istype(a,Hash::Object) || nqp::istype(b,Hash::Object), (return a.Set (==) b.Set), # either is objectHash, so coerce nqp::stmts( # both are normal Maps (my \iter := nqp::iterator(araw)), nqp::while( iter, nqp::unless( nqp::iseq_i( nqp::istrue(nqp::iterval(nqp::shift(iter))), nqp::istrue(nqp::atkey(braw,nqp::iterkey_s(iter))) ), (return False) # elem in A hasn't got same validity in B ) ) ) ) ) ); True } multi sub infix:<<(==)>>(Iterable:D \a, Map:D \b --> Bool:D) { my \iterator := a.iterator; my \braw := nqp::getattr(nqp::decont(b),Map,'$!storage'); return False # can never find all values if nqp::istype(iterator,PredictiveIterator) && iterator.count-only < nqp::elems(braw); my $key; my $seen := nqp::hash; nqp::if( nqp::istype(b,Hash::Object), nqp::until( # object hash nqp::eqaddr((my \object := iterator.pull-one),IterationEnd), nqp::if( nqp::istrue( nqp::getattr( nqp::ifnull( nqp::atkey(braw,$key := object.WHICH), BEGIN # provide virtual value 0 nqp::p6bindattrinvres(nqp::create(Pair),Pair,'$!value',0) ), Pair, '$!value' ) ), nqp::bindkey($seen,$key,1), (return False) # not seen or not true ) ), nqp::until( # normal Map nqp::eqaddr(($key := iterator.pull-one),IterationEnd), nqp::if( nqp::istrue(nqp::atkey(braw,$key)), nqp::bindkey($seen,$key,1), (return False) # not seen or not true ) ) ); nqp::hllbool(nqp::iseq_i(nqp::elems($seen),nqp::elems(braw))) } multi sub infix:<<(==)>>(Any \a, Mixy:D $b --> Bool:D) { a.Mix (==) $b } multi sub infix:<<(==)>>(Any \a, Baggy:D $b --> Bool:D) { a.Bag (==) $b } multi sub infix:<<(==)>>(Any \a, Setty:D $b --> Bool:D) { a.Set (==) $b } multi sub infix:<<(==)>>(Failure:D $a, Any) { $a.throw } multi sub infix:<<(==)>>(Any, Failure:D $b) { $b.throw } multi sub infix:<<(==)>>(Any \a, Any \b --> Bool:D) { a.Set (==) b.Set } # U+2261 IDENTICAL TO my constant &infix:<≡> := &infix:<<(==)>>; # U+2262 NOT IDENTICAL TO proto sub infix:<≢>($, $, *%) is pure {*} multi sub infix:<≢>(\a, \b --> Bool:D) { not a (==) b } # vim: expandtab sw=4