1. my role Mixy does Baggy {
  2. multi method hash(Mixy:D: --> Hash:D) { self.HASHIFY(Any) }
  3. multi method Hash(Mixy:D: --> Hash:D) { self.HASHIFY(Real) }
  4. multi method kxxv(Mixy:D:) {
  5. Failure.new(".kxxv is not supported on a {self.^name}")
  6. }
  7. multi method grab(Mixy:D: $count?) {
  8. Failure.new(".grab is not supported on a {self.^name}")
  9. }
  10. multi method pick(Mixy:D: $count?) {
  11. Failure.new(".pick is not supported on a {self.^name}")
  12. }
  13. multi method roll(Mixy:D:) {
  14. nqp::if(
  15. (my $raw := self.RAW-HASH) && (my $total := self!total-positive),
  16. nqp::getattr(
  17. nqp::iterval(Rakudo::QuantHash.MIX-ROLL($raw, $total)),
  18. Pair,
  19. '$!key'
  20. ),
  21. Nil
  22. )
  23. }
  24. multi method roll(Mixy:D: Whatever) {
  25. Seq.new(nqp::if(
  26. (my $raw := self.RAW-HASH) && (my $total := self!total-positive),
  27. Rakudo::Iterator.Callable( {
  28. nqp::getattr(
  29. nqp::iterval(Rakudo::QuantHash.MIX-ROLL($raw, $total)),
  30. Pair,
  31. '$!key'
  32. )
  33. }, True ),
  34. Rakudo::Iterator.Empty
  35. ))
  36. }
  37. multi method roll(Mixy:D: Callable:D $calculate) {
  38. nqp::if(
  39. (my $total := self!total-positive),
  40. self.roll($calculate($total)),
  41. EmptySeq
  42. )
  43. }
  44. multi method roll(Mixy:D: $count) {
  45. nqp::if(
  46. $count == Inf,
  47. self.roll(*), # let Whatever handle it
  48. Seq.new(nqp::if( # something else as count
  49. (my $todo = $count.Int) < 1, # also handles NaN
  50. Rakudo::Iterator.Empty, # nothing to do
  51. nqp::if(
  52. (my $raw := self.RAW-HASH)
  53. && (my $total := self!total-positive)
  54. && ++$todo,
  55. Rakudo::Iterator.Callable( { # need to do a number of times
  56. nqp::if(
  57. --$todo,
  58. nqp::getattr(
  59. nqp::iterval(Rakudo::QuantHash.MIX-ROLL($raw, $total)),
  60. Pair,
  61. '$!key'
  62. ),
  63. IterationEnd
  64. )
  65. }),
  66. Rakudo::Iterator.Empty # nothing to roll for
  67. )
  68. ))
  69. )
  70. }
  71. #--- object creation methods
  72. method new-from-pairs(Mixy:_: *@pairs --> Mixy:D) {
  73. nqp::if(
  74. (my $iterator := @pairs.iterator).is-lazy,
  75. Failure.new(X::Cannot::Lazy.new(:action<coerce>,:what(self.^name))),
  76. nqp::create(self).SET-SELF(
  77. Rakudo::QuantHash.ADD-PAIRS-TO-MIX(
  78. nqp::create(Rakudo::Internals::IterationSet),$iterator
  79. )
  80. )
  81. )
  82. }
  83. #--- coercion methods
  84. sub SETIFY(\mixy, \type) {
  85. nqp::if(
  86. (my $raw := mixy.RAW-HASH) && nqp::elems($raw),
  87. nqp::stmts(
  88. (my $elems := nqp::clone($raw)),
  89. (my $iter := nqp::iterator($elems)),
  90. nqp::while(
  91. $iter,
  92. nqp::if(
  93. nqp::getattr(
  94. nqp::iterval(nqp::shift($iter)),
  95. Pair,
  96. '$!value'
  97. ) < 0,
  98. nqp::deletekey($elems,nqp::iterkey_s($iter)),
  99. nqp::bindkey(
  100. $elems,
  101. nqp::iterkey_s($iter),
  102. nqp::getattr(nqp::iterval($iter),Pair,'$!key')
  103. )
  104. )
  105. ),
  106. nqp::create(type).SET-SELF($elems)
  107. ),
  108. nqp::if(
  109. nqp::eqaddr(type,Set),
  110. set(),
  111. nqp::create(type)
  112. )
  113. )
  114. }
  115. multi method Set(Mixy:D:) { SETIFY(self,Set) }
  116. multi method SetHash(Mixy:D:) { SETIFY(self,SetHash) }
  117. sub BAGGIFY(\mixy, \type) {
  118. nqp::if(
  119. (my $raw := mixy.RAW-HASH) && nqp::elems($raw),
  120. nqp::stmts( # something to coerce
  121. (my $elems := nqp::clone($raw)),
  122. (my $iter := nqp::iterator($elems)),
  123. nqp::while(
  124. $iter,
  125. nqp::if(
  126. (my $value := nqp::getattr(
  127. nqp::iterval(nqp::shift($iter)),
  128. Pair,
  129. '$!value'
  130. ).Int) > 0, # .Int also deconts
  131. nqp::bindkey( # ok to keep value.Int
  132. $elems,
  133. nqp::iterkey_s($iter),
  134. nqp::p6bindattrinvres(
  135. nqp::iterval($iter),Pair,'$!value',$value)
  136. ),
  137. nqp::deletekey($elems,nqp::iterkey_s($iter))
  138. )
  139. ),
  140. nqp::create(type).SET-SELF($elems),
  141. ),
  142. nqp::if( # nothing to coerce
  143. nqp::istype(type,Bag),
  144. bag(),
  145. nqp::create(BagHash)
  146. )
  147. )
  148. }
  149. multi method Bag(Baggy:D:) { BAGGIFY(self, Bag) }
  150. multi method BagHash(Baggy:D:) { BAGGIFY(self, BagHash) }
  151. }