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