1. my class SetHash does Setty {
  2. #--- selector methods
  3. multi method grab(SetHash:D:) {
  4. nqp::if(
  5. $!elems,
  6. nqp::stmts(
  7. (my $object := nqp::iterval(
  8. my $iter := Rakudo::QuantHash.ROLL($!elems)
  9. )),
  10. nqp::deletekey($!elems,nqp::iterkey_s($iter)),
  11. $object
  12. ),
  13. Nil
  14. )
  15. }
  16. multi method grab(SetHash:D: Callable:D $calculate) {
  17. self.grab($calculate(self.elems))
  18. }
  19. multi method grab(SetHash:D: Whatever) {
  20. self.grab(Inf)
  21. }
  22. multi method grab(SetHash:D: $count) {
  23. Seq.new(class :: does Rakudo::QuantHash::Pairs {
  24. method pull-one() is raw {
  25. nqp::if(
  26. nqp::elems($!picked),
  27. nqp::stmts(
  28. (my $object := nqp::atkey(
  29. $!elems,
  30. (my $key := nqp::pop_s($!picked))
  31. )),
  32. nqp::deletekey($!elems,$key),
  33. $object
  34. ),
  35. IterationEnd
  36. )
  37. }
  38. }.new($!elems, $count))
  39. }
  40. multi method grabpairs(SetHash:D:) {
  41. Pair.new(self.grab,True)
  42. }
  43. multi method grabpairs(SetHash:D: Callable:D $calculate) {
  44. self.grabpairs($calculate(self.elems))
  45. }
  46. multi method grabpairs(SetHash:D: Whatever) {
  47. self.grabpairs(Inf)
  48. }
  49. multi method grabpairs(SetHash:D: $count) {
  50. Seq.new(class :: does Rakudo::QuantHash::Pairs {
  51. method pull-one() is raw {
  52. nqp::if(
  53. nqp::elems($!picked),
  54. nqp::stmts(
  55. (my $object := nqp::atkey(
  56. $!elems,
  57. (my $key := nqp::pop_s($!picked))
  58. )),
  59. nqp::deletekey($!elems,$key),
  60. Pair.new($object,True)
  61. ),
  62. IterationEnd
  63. )
  64. }
  65. }.new($!elems, $count))
  66. }
  67. #--- iterator methods
  68. sub proxy(Mu \iter,Mu \elems) is raw {
  69. # We are only sure that the key exists when the Proxy
  70. # is made, but we cannot be sure of its existence when
  71. # either the FETCH or STORE block is executed. So we
  72. # still need to check for existence, and handle the case
  73. # where we need to (re-create) the key and value. The
  74. # logic is therefore basically the same as in AT-KEY,
  75. # except for tests for allocated storage and .WHICH
  76. # processing.
  77. nqp::stmts(
  78. # save object for potential recreation
  79. (my $object := nqp::iterval(iter)),
  80. Proxy.new(
  81. FETCH => {
  82. nqp::p6bool(nqp::existskey(elems,nqp::iterkey_s(iter)))
  83. },
  84. STORE => -> $, $value {
  85. nqp::stmts(
  86. nqp::if(
  87. $value,
  88. nqp::bindkey(elems,nqp::iterkey_s(iter),$object),
  89. nqp::deletekey(elems,nqp::iterkey_s(iter))
  90. ),
  91. $value.Bool
  92. )
  93. }
  94. )
  95. )
  96. }
  97. method iterator(SetHash:D:) {
  98. class :: does Rakudo::Iterator::Mappy {
  99. method pull-one() {
  100. nqp::if(
  101. $!iter,
  102. Pair.new(
  103. nqp::iterval(nqp::shift($!iter)),
  104. proxy($!iter,$!hash)
  105. ),
  106. IterationEnd
  107. )
  108. }
  109. }.new($!elems)
  110. }
  111. multi method kv(SetHash:D:) {
  112. Seq.new(class :: does Rakudo::QuantHash::Quanty-kv {
  113. method pull-one() is raw {
  114. nqp::if(
  115. $!on,
  116. nqp::stmts(
  117. ($!on = 0),
  118. proxy($!iter,$!elems)
  119. ),
  120. nqp::if(
  121. $!iter,
  122. nqp::stmts(
  123. ($!on = 1),
  124. nqp::iterval(nqp::shift($!iter))
  125. ),
  126. IterationEnd
  127. )
  128. )
  129. }
  130. method push-all($target --> IterationEnd) {
  131. nqp::while(
  132. $!iter,
  133. nqp::stmts( # doesn't sink
  134. $target.push(nqp::iterval(nqp::shift($!iter))),
  135. $target.push(True)
  136. )
  137. )
  138. }
  139. }.new(self))
  140. }
  141. multi method values(SetHash:D:) {
  142. Seq.new(class :: does Rakudo::Iterator::Mappy {
  143. method pull-one() {
  144. nqp::if(
  145. $!iter,
  146. proxy(nqp::shift($!iter),$!hash),
  147. IterationEnd
  148. )
  149. }
  150. }.new($!elems))
  151. }
  152. #--- coercion methods
  153. multi method Set(SetHash:D: :$view) {
  154. nqp::if(
  155. $!elems && nqp::elems($!elems),
  156. nqp::create(Set).SET-SELF(nqp::if($view,$!elems,nqp::clone($!elems))),
  157. nqp::create(Set)
  158. )
  159. }
  160. multi method SetHash(SetHash:D:) { self }
  161. method clone() {
  162. nqp::if(
  163. $!elems && nqp::elems($!elems),
  164. nqp::create(self).SET-SELF(nqp::clone($!elems)),
  165. nqp::create(self)
  166. )
  167. }
  168. #--- interface methods
  169. method STORE(*@pairs --> SetHash:D) {
  170. nqp::if(
  171. (my $iterator := @pairs.iterator).is-lazy,
  172. Failure.new(X::Cannot::Lazy.new(:action<initialize>,:what(self.^name))),
  173. self.SET-SELF(
  174. Rakudo::QuantHash.ADD-PAIRS-TO-SET(
  175. nqp::create(Rakudo::Internals::IterationSet), $iterator
  176. )
  177. )
  178. )
  179. }
  180. multi method AT-KEY(SetHash:D: \k --> Bool:D) is raw {
  181. Proxy.new(
  182. FETCH => {
  183. nqp::p6bool($!elems && nqp::existskey($!elems,k.WHICH))
  184. },
  185. STORE => -> $, $value {
  186. nqp::stmts(
  187. nqp::if(
  188. $value,
  189. nqp::stmts(
  190. nqp::unless(
  191. $!elems,
  192. # XXX for some reason, $!elems := nqp::create(...) doesn't work
  193. # Type check failed in binding; expected NQPMu but got Rakudo::Internals::IterationSet
  194. nqp::bindattr(self,::?CLASS,'$!elems',
  195. nqp::create(Rakudo::Internals::IterationSet))
  196. ),
  197. nqp::bindkey($!elems,k.WHICH,nqp::decont(k))
  198. ),
  199. $!elems && nqp::deletekey($!elems,k.WHICH)
  200. ),
  201. $value.Bool
  202. )
  203. }
  204. )
  205. }
  206. multi method DELETE-KEY(SetHash:D: \k --> Bool:D) {
  207. nqp::p6bool(
  208. nqp::if(
  209. $!elems && nqp::existskey($!elems,(my $which := k.WHICH)),
  210. nqp::stmts(
  211. nqp::deletekey($!elems,$which),
  212. 1
  213. )
  214. )
  215. )
  216. }
  217. }