1. # This file implements the following set operators:
  2. # (+) baggy addition (ASCII)
  3. # ⊎ baggy addition
  4. proto sub infix:<(+)>(|) is pure {*}
  5. multi sub infix:<(+)>() { bag() }
  6. multi sub infix:<(+)>(Bag:D $a) { $a }
  7. multi sub infix:<(+)>(Mix:D $a) { $a }
  8. multi sub infix:<(+)>(MixHash:D $a) { $a.Mix }
  9. multi sub infix:<(+)>(Any $a) { $a.Bag }
  10. multi sub infix:<(+)>(Setty:D $a, QuantHash:D $b) {
  11. nqp::if(
  12. (my $araw := $a.RAW-HASH) && nqp::elems($araw),
  13. nqp::if( # elems on left
  14. (my $braw := $b.RAW-HASH) && nqp::elems($braw),
  15. nqp::stmts( # elems on both sides
  16. (my $elems := Rakudo::QuantHash.SET-BAGGIFY($araw)),
  17. nqp::create(nqp::if(nqp::istype($b,Mixy),Mix,Bag)).SET-SELF(
  18. nqp::if(
  19. nqp::istype($b,Mixy),
  20. Rakudo::QuantHash.ADD-MIX-TO-MIX($elems, $braw),
  21. nqp::if(
  22. nqp::istype($b,Baggy),
  23. Rakudo::QuantHash.ADD-BAG-TO-BAG($elems, $braw),
  24. Rakudo::QuantHash.ADD-SET-TO-BAG($elems, $braw)
  25. )
  26. )
  27. )
  28. ),
  29. nqp::if(nqp::istype($b,Mixy),$a.Mix,$a.Bag) # no elems on right
  30. ),
  31. nqp::if(nqp::istype($b,Mixy),$b.Mix,$b.Bag) # no elems left/either
  32. )
  33. }
  34. multi sub infix:<(+)>(Setty:D $a, Map:D $b) {
  35. nqp::if(
  36. (my $araw := $a.RAW-HASH) && nqp::elems($araw),
  37. nqp::if( # elems on left
  38. (my $braw := nqp::getattr(nqp::decont($b),Map,'$!storage'))
  39. && nqp::elems($braw),
  40. nqp::create(Bag).SET-SELF( # elems on both sides
  41. Rakudo::QuantHash.ADD-MAP-TO-BAG(
  42. Rakudo::QuantHash.SET-BAGGIFY($araw), $b
  43. )
  44. ),
  45. $a.Bag # no elems on right
  46. ),
  47. $b.Bag # no elems left/either
  48. )
  49. }
  50. multi sub infix:<(+)>(Mixy:D $a, QuantHash:D $b) {
  51. nqp::if(
  52. (my $araw := $a.RAW-HASH) && nqp::elems($araw),
  53. nqp::if( # elems on left
  54. (my $braw := $b.RAW-HASH) && nqp::elems($braw),
  55. nqp::stmts( # elems on both sides
  56. (my $elems := Rakudo::QuantHash.BAGGY-CLONE($araw)),
  57. nqp::create(Mix).SET-SELF(
  58. nqp::if(
  59. nqp::istype($b,Baggy),
  60. Rakudo::QuantHash.ADD-MIX-TO-MIX($elems, $braw),
  61. Rakudo::QuantHash.ADD-SET-TO-MIX($elems, $braw)
  62. )
  63. )
  64. ),
  65. $a.Mix # no elems on right
  66. ),
  67. $b.Mix # no elems left/either
  68. )
  69. }
  70. multi sub infix:<(+)>(Baggy:D $a, QuantHash:D $b) {
  71. nqp::if(
  72. (my $araw := $a.RAW-HASH) && nqp::elems($araw),
  73. nqp::if( # elems on left
  74. (my $braw := $b.RAW-HASH) && nqp::elems($braw),
  75. nqp::stmts( # elems on both sides
  76. (my $elems := Rakudo::QuantHash.BAGGY-CLONE($araw)),
  77. nqp::create(nqp::if(nqp::istype($b,Mixy),Mix,Bag)).SET-SELF(
  78. nqp::if(
  79. nqp::istype($b,Mixy),
  80. Rakudo::QuantHash.ADD-MIX-TO-MIX($elems, $braw),
  81. nqp::if(
  82. nqp::istype($b,Baggy),
  83. Rakudo::QuantHash.ADD-BAG-TO-BAG($elems, $braw),
  84. Rakudo::QuantHash.ADD-SET-TO-BAG($elems, $braw)
  85. )
  86. )
  87. )
  88. ),
  89. nqp::if(nqp::istype($b,Mixy),$a.Mix,$a.Bag) # no elems on right
  90. ),
  91. nqp::if(nqp::istype($b,Mixy),$b.Mix,$b.Bag) # no elems left/either
  92. )
  93. }
  94. multi sub infix:<(+)>(Map:D $a, Map:D $b) {
  95. nqp::if(
  96. (my $araw := nqp::getattr(nqp::decont($b),Map,'$!storage'))
  97. && nqp::elems($araw),
  98. nqp::if( # elems on left
  99. (my $braw := nqp::getattr(nqp::decont($b),Map,'$!storage'))
  100. && nqp::elems($braw),
  101. nqp::create(Bag).SET-SELF( # elems on both sides
  102. Rakudo::QuantHash.ADD-MAP-TO-BAG(
  103. Rakudo::QuantHash.COERCE-MAP-TO-BAG($a), $b
  104. )
  105. ),
  106. $a.Bag # no elems on right
  107. ),
  108. $b.Bag # no elems left/either
  109. )
  110. }
  111. multi sub infix:<(+)>(Iterable:D $a, Iterable:D $b) {
  112. nqp::create(Bag).SET-SELF(
  113. Rakudo::QuantHash.ADD-PAIRS-TO-BAG(
  114. Rakudo::QuantHash.ADD-PAIRS-TO-BAG(
  115. nqp::create(Rakudo::Internals::IterationSet),
  116. $a.iterator
  117. ),
  118. $b.iterator
  119. )
  120. )
  121. }
  122. multi sub infix:<(+)>(Any $, Failure:D $b) { $b.throw }
  123. multi sub infix:<(+)>(Failure:D $a, Any $) { $a.throw }
  124. multi sub infix:<(+)>(Any $a, Any $b) {
  125. nqp::if(
  126. nqp::istype($a,Mixy) || nqp::istype($b,Mixy),
  127. infix:<(+)>($a.Mix, $b.Mix),
  128. infix:<(+)>($a.Bag, $b.Bag)
  129. )
  130. }
  131. multi sub infix:<(+)>(**@p) {
  132. my $result = @p.shift;
  133. $result = $result (+) @p.shift while @p;
  134. $result
  135. }
  136. # U+228E MULTISET UNION
  137. my constant &infix:<⊎> := &infix:<(+)>;