-
-
Notifications
You must be signed in to change notification settings - Fork 372
/
set_intersection.pm6
145 lines (137 loc) Β· 4.9 KB
/
set_intersection.pm6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# This file implements the following set operators:
# (&) intersection (ASCII)
# β© intersection
proto sub infix:<(&)>(|) is pure {*}
multi sub infix:<(&)>() { set() }
multi sub infix:<(&)>(QuantHash:D $a) { $a } # Set/Bag/Mix
multi sub infix:<(&)>(Any $a) { $a.Set } # also for Iterable/Map
multi sub infix:<(&)>(Setty:D $a, Setty:D $b) {
nqp::if(
(my $araw := $a.RAW-HASH) && nqp::elems($araw)
&& (my $braw := $b.RAW-HASH) && nqp::elems($braw),
nqp::stmts( # both have elems
nqp::if(
nqp::islt_i(nqp::elems($araw),nqp::elems($braw)),
nqp::stmts( # $a smallest, iterate over it
(my $iter := nqp::iterator($araw)),
(my $base := $braw)
),
nqp::stmts( # $b smallest, iterate over that
($iter := nqp::iterator($braw)),
($base := $araw)
)
),
(my $elems := nqp::create(Rakudo::Internals::IterationSet)),
nqp::while(
$iter,
nqp::if( # bind if in both
nqp::existskey($base,nqp::iterkey_s(nqp::shift($iter))),
nqp::bindkey($elems,nqp::iterkey_s($iter),nqp::iterval($iter))
)
),
nqp::create($a.WHAT).SET-SELF($elems)
),
nqp::if( # one/neither has elems
nqp::istype($a,Set), set(), nqp::create(SetHash)
)
)
}
multi sub infix:<(&)>(Setty:D $a, Baggy:D $b) {
Rakudo::QuantHash.INTERSECT-BAGGIES($a.Baggy, $b, Bag)
}
multi sub infix:<(&)>(Baggy:D $a, Setty:D $b) {
Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b.Bag, Bag)
}
multi sub infix:<(&)>(Setty:D $a, Mixy:D $b) {
Rakudo::QuantHash.INTERSECT-BAGGIES($a.Mixy, $b, Mix)
}
multi sub infix:<(&)>(Mixy:D $a, Setty:D $b) {
Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b.Mix, Mix)
}
multi sub infix:<(&)>(Baggy:D $a, Baggy:D $b) {
Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b, Bag)
}
multi sub infix:<(&)>(Mixy:D $a, Baggy:D $b) {
Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b, Mix)
}
multi sub infix:<(&)>(Baggy:D $a, Mixy:D $b) {
Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b, Mix)
}
multi sub infix:<(&)>(Mixy:D $a, Mixy:D $b) {
Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b, Mix)
}
multi sub infix:<(&)>(Baggy:D $a, Any:D $b) {
nqp::if(
nqp::istype((my $bbag := $b.Bag),Bag),
Rakudo::QuantHash.INTERSECT-BAGGIES($a, $bbag, Bag),
$bbag.throw
)
}
multi sub infix:<(&)>(Any:D $a, Baggy:D $b) {
infix:<(&)>($b.Bag, $a)
}
multi sub infix:<(&)>(Mixy:D $a, Any:D $b) {
nqp::if(
nqp::istype((my $bmix := $b.Mix),Mix),
Rakudo::QuantHash.INTERSECT-BAGGIES($a, $bmix, Mix),
$bmix.throw
)
}
multi sub infix:<(&)>(Any:D $a, Mixy:D $b) {
infix:<(&)>($b.Mix, $a)
}
multi sub infix:<(&)>(Map:D $a, Map:D $b) {
nqp::if(
nqp::eqaddr($a.keyof,Str(Any)) && nqp::eqaddr($b.keyof,Str(Any)),
nqp::if( # both ordinary Str hashes
nqp::elems(
my \araw := nqp::getattr(nqp::decont($a),Map,'$!storage')
) && nqp::elems(
my \braw := nqp::getattr(nqp::decont($b),Map,'$!storage')
),
nqp::stmts( # both are initialized
nqp::if(
nqp::islt_i(nqp::elems(araw),nqp::elems(braw)),
nqp::stmts( # $a smallest, iterate over it
(my $iter := nqp::iterator(araw)),
(my $base := braw)
),
nqp::stmts( # $b smallest, iterate over that
($iter := nqp::iterator(braw)),
($base := araw)
)
),
(my $elems := nqp::create(Rakudo::Internals::IterationSet)),
nqp::while(
$iter,
nqp::if( # create if in both
nqp::existskey(
$base,
nqp::iterkey_s(nqp::shift($iter))
),
nqp::bindkey(
$elems,nqp::iterkey_s($iter).WHICH,nqp::iterkey_s($iter))
)
),
nqp::create(Set).SET-SELF($elems)
),
set() # one/neither has elems
),
infix:<(&)>($a.Set, $b.Set) # object hash(es), coerce!
)
}
multi sub infix:<(&)>(Any $, Failure:D $b) { $b.throw }
multi sub infix:<(&)>(Failure:D $a, Any $) { $a.throw }
# Note that we cannot create a Setty:D,Any candidate because that will result
# in an ambiguous dispatch, so we need to hack a check for Setty in here.
multi sub infix:<(&)>(Any $a, Any $b) {
infix:<(&)>(nqp::istype($a,Setty) ?? $a !! $a.Set,$b.Set)
}
multi sub infix:<(&)>(**@p) {
my $result = @p.shift;
$result = $result (&) @p.shift while @p;
$result
}
# U+2229 INTERSECTION
my constant &infix:<β©> := &infix:<(&)>;
# vim: ft=perl6 expandtab sw=4