1. my role Baggy does QuantHash {
  2. # A Bag/BagHash/Mix/MixHash consists of a single hash with Pairs.
  3. # The keys of the hash, are the .WHICH strings of the original object key.
  4. # The values are Pairs containing the original object key and value.
  5. has Rakudo::Internals::IterationSet $!elems; # key.WHICH => (key,value)
  6. # The Baggy role takes care of all mutable and immutable aspects that are
  7. # shared between Bag,BagHash,Mix,MixHash. Any specific behaviour for
  8. # mutable and immutable aspects of Mix/MixHash need to live in Mixy.
  9. # Immutables aspects of Bag/Mix, need to live to Bag/Mix respectively.
  10. #--- interface methods
  11. multi method ACCEPTS(Baggy:U: \other --> Bool:D) {
  12. other.^does(self)
  13. }
  14. multi method ACCEPTS(Baggy:D: Baggy:D \other --> Bool:D) {
  15. nqp::p6bool(
  16. nqp::unless(
  17. nqp::eqaddr(self,other),
  18. nqp::if( # not same object
  19. (my $araw := $!elems),
  20. nqp::if( # something on left
  21. (my $braw := other.RAW-HASH),
  22. nqp::if( # something on both sides
  23. nqp::iseq_i(nqp::elems($araw),nqp::elems($braw)),
  24. nqp::stmts( # same size
  25. (my $iter := nqp::iterator($araw)),
  26. nqp::while(
  27. $iter,
  28. nqp::unless(
  29. nqp::getattr(
  30. nqp::ifnull(
  31. nqp::atkey($braw,nqp::iterkey_s(nqp::shift($iter))),
  32. BEGIN nqp::p6bindattrinvres( # virtual Pair with 0
  33. nqp::create(Pair),Pair,'$!value',0)
  34. ),Pair,'$!value')
  35. == nqp::getattr(nqp::iterval($iter),Pair,'$!value'),
  36. return False # missing/different: we're done
  37. )
  38. ),
  39. True # all keys identical/same value
  40. )
  41. )
  42. ),
  43. # true -> both empty
  44. nqp::isfalse(
  45. ($braw := other.RAW-HASH) && nqp::elems($braw)
  46. )
  47. )
  48. )
  49. )
  50. }
  51. multi method ACCEPTS(Baggy:D: Mu \other --> Bool:D) {
  52. self.ACCEPTS(other.Bag)
  53. }
  54. multi method AT-KEY(Baggy:D: \k) { # exception: ro version for Bag/Mix
  55. nqp::if(
  56. $!elems,
  57. nqp::getattr(
  58. nqp::ifnull(
  59. nqp::atkey($!elems,k.WHICH),
  60. BEGIN nqp::p6bindattrinvres(nqp::create(Pair),Pair,'$!value',0)
  61. ),
  62. Pair,
  63. '$!value'
  64. ),
  65. 0
  66. )
  67. }
  68. multi method DELETE-KEY(Baggy:D: \k) {
  69. nqp::if(
  70. $!elems && nqp::existskey($!elems,(my $which := k.WHICH)),
  71. nqp::stmts(
  72. (my $value :=
  73. nqp::getattr(nqp::atkey($!elems,$which),Pair,'$!value')),
  74. nqp::deletekey($!elems,$which),
  75. $value
  76. ),
  77. 0
  78. )
  79. }
  80. multi method EXISTS-KEY(Baggy:D: \k) {
  81. nqp::p6bool(
  82. $!elems && nqp::existskey($!elems,k.WHICH)
  83. )
  84. }
  85. #--- object creation methods
  86. # helper sub to create Bag from iterator, check for laziness
  87. sub create-from-iterator(\type, \iterator --> Baggy:D) {
  88. nqp::if(
  89. iterator.is-lazy,
  90. Failure.new(X::Cannot::Lazy.new(:action<coerce>,:what(type.^name))),
  91. nqp::create(type).SET-SELF(
  92. Rakudo::QuantHash.ADD-ITERATOR-TO-BAG(
  93. nqp::create(Rakudo::Internals::IterationSet), iterator
  94. )
  95. )
  96. )
  97. }
  98. multi method new(Baggy:_: --> Baggy:D) { nqp::create(self) }
  99. multi method new(Baggy:_: \value --> Baggy:D) {
  100. nqp::if(
  101. nqp::istype(value,Iterable) && nqp::not_i(nqp::iscont(value)),
  102. create-from-iterator(self, value.iterator),
  103. nqp::stmts(
  104. nqp::bindkey(
  105. (my $elems := nqp::create(Rakudo::Internals::IterationSet)),
  106. value.WHICH,
  107. Pair.new(value,1)
  108. ),
  109. nqp::create(self).SET-SELF($elems)
  110. )
  111. )
  112. }
  113. multi method new(Baggy:_: **@args) {
  114. create-from-iterator(self, @args.iterator)
  115. }
  116. method new-from-pairs(Baggy:_: *@pairs --> Baggy:D) {
  117. nqp::if(
  118. (my $iterator := @pairs.iterator).is-lazy,
  119. Failure.new(X::Cannot::Lazy.new(:action<coerce>,:what(self.^name))),
  120. nqp::create(self).SET-SELF(
  121. Rakudo::QuantHash.ADD-PAIRS-TO-BAG(
  122. nqp::create(Rakudo::Internals::IterationSet),$iterator
  123. )
  124. )
  125. )
  126. }
  127. #--- iterator methods
  128. multi method iterator(Baggy:D:) {
  129. Rakudo::Iterator.Mappy-values($!elems)
  130. }
  131. multi method keys(Baggy:D:) {
  132. Seq.new(class :: does Rakudo::Iterator::Mappy {
  133. method pull-one() {
  134. $!iter
  135. ?? nqp::getattr(nqp::iterval(nqp::shift($!iter)),Pair,'$!key')
  136. !! IterationEnd
  137. }
  138. method push-all($target --> IterationEnd) {
  139. nqp::while( # doesn't sink
  140. $!iter,
  141. $target.push(
  142. nqp::getattr(nqp::iterval(nqp::shift($!iter)),Pair,'$!key')
  143. )
  144. )
  145. }
  146. }.new($!elems))
  147. }
  148. multi method kv(Baggy:D:) {
  149. Seq.new(Rakudo::Iterator.Mappy-kv-from-pairs($!elems))
  150. }
  151. multi method values(Baggy:D:) {
  152. Seq.new(class :: does Rakudo::Iterator::Mappy {
  153. method pull-one() is raw {
  154. nqp::if(
  155. $!iter,
  156. nqp::getattr(nqp::iterval(nqp::shift($!iter)),Pair,'$!value'),
  157. IterationEnd
  158. )
  159. }
  160. method push-all($target --> IterationEnd) {
  161. nqp::while( # doesn't sink
  162. $!iter,
  163. $target.push(
  164. nqp::getattr(
  165. nqp::iterval(nqp::shift($!iter)),
  166. Pair,
  167. '$!value'
  168. )
  169. )
  170. )
  171. }
  172. }.new($!elems))
  173. }
  174. multi method antipairs(Baggy:D:) {
  175. Seq.new(class :: does Rakudo::Iterator::Mappy {
  176. method pull-one() {
  177. nqp::if(
  178. $!iter,
  179. nqp::iterval(nqp::shift($!iter)).antipair,
  180. IterationEnd
  181. )
  182. }
  183. method push-all($target --> IterationEnd) {
  184. nqp::while(
  185. $!iter,
  186. $target.push(nqp::iterval(nqp::shift($!iter)).antipair),
  187. )
  188. }
  189. }.new($!elems))
  190. }
  191. proto method kxxv(|) {*}
  192. multi method kxxv(Baggy:D:) {
  193. Seq.new(class :: does Rakudo::Iterator::Mappy {
  194. has Mu $!key;
  195. has int $!times;
  196. method pull-one() is raw {
  197. nqp::if(
  198. $!times,
  199. nqp::stmts(
  200. ($!times = nqp::sub_i($!times,1)),
  201. $!key
  202. ),
  203. nqp::if(
  204. $!iter,
  205. nqp::stmts(
  206. ($!key := nqp::getattr(
  207. (my $pair := nqp::iterval(nqp::shift($!iter))),
  208. Pair,
  209. '$!key'
  210. )),
  211. ($!times =
  212. nqp::sub_i(nqp::getattr($pair,Pair,'$!value'),1)),
  213. $!key
  214. ),
  215. IterationEnd
  216. )
  217. )
  218. }
  219. method skip-one() { # the default skip-one, too difficult to handle
  220. nqp::not_i(nqp::eqaddr(self.pull-one,IterationEnd))
  221. }
  222. method push-all($target --> IterationEnd) {
  223. nqp::while(
  224. $!iter,
  225. nqp::stmts(
  226. ($!key := nqp::getattr(
  227. (my $pair := nqp::iterval(nqp::shift($!iter))),
  228. Pair,
  229. '$!key'
  230. )),
  231. ($!times =
  232. nqp::add_i(nqp::getattr($pair,Pair,'$!value'),1)),
  233. nqp::while( # doesn't sink
  234. ($!times = nqp::sub_i($!times,1)),
  235. $target.push($!key)
  236. )
  237. )
  238. )
  239. }
  240. }.new($!elems))
  241. }
  242. multi method invert(Baggy:D:) {
  243. Seq.new(Rakudo::Iterator.Invert(Rakudo::Iterator.Mappy-values($!elems)))
  244. }
  245. #--- introspection methods
  246. multi method elems(Baggy:D: --> Int:D) {
  247. nqp::istrue($!elems) && nqp::elems($!elems)
  248. }
  249. multi method Bool(Baggy:D: --> Bool:D) {
  250. nqp::p6bool($!elems && nqp::elems($!elems))
  251. }
  252. method HASHIFY(\type) {
  253. nqp::stmts(
  254. (my $hash := Hash.^parameterize(type,Any).new),
  255. (my $descriptor := nqp::getattr($hash,Hash,'$!descriptor')),
  256. nqp::if(
  257. $!elems && nqp::elems($!elems),
  258. nqp::stmts(
  259. (my $storage := nqp::clone($!elems)),
  260. (my $iter := nqp::iterator($storage)),
  261. nqp::while(
  262. $iter,
  263. nqp::bindkey(
  264. $storage,
  265. nqp::iterkey_s(nqp::shift($iter)),
  266. nqp::p6bindattrinvres(
  267. nqp::clone(nqp::iterval($iter)),
  268. Pair,
  269. '$!value',
  270. (nqp::p6scalarfromdesc($descriptor) =
  271. nqp::getattr(nqp::iterval($iter),Pair,'$!value'))
  272. )
  273. )
  274. ),
  275. nqp::bindattr($hash,Map,'$!storage',$storage)
  276. )
  277. ),
  278. $hash
  279. )
  280. }
  281. multi method hash(Baggy:D: --> Hash:D) { self.HASHIFY(Any) }
  282. multi method Hash(Baggy:D: --> Hash:D) { self.HASHIFY(UInt) }
  283. method default(Baggy:D: --> 0) { }
  284. multi method Str(Baggy:D: --> Str:D) {
  285. nqp::join(' ',Rakudo::QuantHash.RAW-VALUES-MAP(self, {
  286. nqp::if(
  287. (my $value := nqp::getattr($_,Pair,'$!value')) == 1,
  288. nqp::getattr($_,Pair,'$!key').gist,
  289. "{nqp::getattr($_,Pair,'$!key').gist}($value)"
  290. )
  291. }))
  292. }
  293. multi method gist(Baggy:D: --> Str:D) {
  294. nqp::concat(
  295. nqp::concat(
  296. nqp::concat(self.^name,'('),
  297. nqp::join(', ',
  298. Rakudo::Sorting.MERGESORT-str(
  299. Rakudo::QuantHash.RAW-VALUES-MAP(self, {
  300. nqp::if(
  301. (my $value := nqp::getattr($_,Pair,'$!value')) == 1,
  302. nqp::getattr($_,Pair,'$!key').gist,
  303. "{nqp::getattr($_,Pair,'$!key').gist}($value)"
  304. )
  305. })
  306. )
  307. )
  308. ),
  309. ')',
  310. )
  311. }
  312. multi method perl(Baggy:D: --> Str:D) {
  313. nqp::if(
  314. $!elems && nqp::elems($!elems),
  315. nqp::concat(
  316. nqp::concat(
  317. '(',
  318. nqp::join(',',
  319. Rakudo::QuantHash.RAW-VALUES-MAP(self, {
  320. nqp::if(
  321. (my $value := nqp::getattr($_,Pair,'$!value')) == 1,
  322. nqp::getattr($_,Pair,'$!key').perl,
  323. "{nqp::getattr($_,Pair,'$!key').perl}=>$value"
  324. )
  325. })
  326. )
  327. ),
  328. nqp::concat(').',self.^name)
  329. ),
  330. nqp::if(
  331. nqp::istype(self,Bag),
  332. 'bag()',
  333. nqp::if(
  334. nqp::istype(self,Mix),
  335. 'mix()',
  336. nqp::concat('().',self.^name)
  337. )
  338. )
  339. )
  340. }
  341. #--- selection methods
  342. proto method grabpairs (|) {*}
  343. multi method grabpairs(Baggy:D:) {
  344. nqp::if(
  345. $!elems && nqp::elems($!elems),
  346. nqp::stmts(
  347. (my $iter := Rakudo::QuantHash.ROLL($!elems)),
  348. (my $pair := nqp::iterval($iter)),
  349. nqp::deletekey($!elems,nqp::iterkey_s($iter)),
  350. $pair
  351. ),
  352. Nil
  353. )
  354. }
  355. multi method grabpairs(Baggy:D: Callable:D $calculate) {
  356. self.grabpairs( $calculate(self.elems) )
  357. }
  358. multi method grabpairs(Baggy:D: Whatever $) {
  359. self.grabpairs(Inf)
  360. }
  361. multi method grabpairs(Baggy:D: $count) {
  362. Seq.new(class :: does Rakudo::QuantHash::Pairs {
  363. method pull-one() is raw {
  364. nqp::if(
  365. nqp::elems($!picked),
  366. nqp::stmts(
  367. (my $pair := nqp::atkey(
  368. $!elems,
  369. (my $key := nqp::pop_s($!picked))
  370. )),
  371. nqp::deletekey($!elems,$key),
  372. $pair
  373. ),
  374. IterationEnd
  375. )
  376. }
  377. }.new($!elems, $count))
  378. }
  379. proto method pickpairs(|) {*}
  380. multi method pickpairs(Baggy:D:) {
  381. nqp::if(
  382. $!elems && nqp::elems($!elems),
  383. nqp::iterval(Rakudo::QuantHash.ROLL($!elems)),
  384. Nil
  385. )
  386. }
  387. multi method pickpairs(Baggy:D: Callable:D $calculate) {
  388. self.pickpairs( $calculate(self.total) )
  389. }
  390. multi method pickpairs(Baggy:D: Whatever $) {
  391. self.pickpairs(Inf)
  392. }
  393. multi method pickpairs(Baggy:D: $count) {
  394. Seq.new(class :: does Rakudo::QuantHash::Pairs {
  395. method pull-one() is raw {
  396. nqp::if(
  397. nqp::elems($!picked),
  398. nqp::atkey($!elems,nqp::pop_s($!picked)),
  399. IterationEnd
  400. )
  401. }
  402. }.new($!elems, $count))
  403. }
  404. proto method grab(|) {*}
  405. multi method grab(Baggy:D: |c) {
  406. X::Immutable.new( method => 'grab', typename => self.^name ).throw;
  407. }
  408. proto method pick(|) {*}
  409. multi method pick(Baggy:D:) { self.roll }
  410. multi method pick(Baggy:D: Callable:D $calculate) {
  411. self.pick( $calculate(self.total) )
  412. }
  413. multi method pick(Baggy:D: Whatever) { self.pick(Inf) }
  414. multi method pick(Baggy:D: $count) {
  415. Seq.new(
  416. (my $total := self.total) < 1
  417. || (my $todo := $count == Inf ?? $total !! $count.Int) < 1
  418. ?? Rakudo::Iterator.Empty # nothing to do
  419. !! class :: does Iterator {
  420. has $!raw; # the IterationSet of the Baggy
  421. has $!weights; # clone of raw, but with just the weights
  422. has $!todo; # number of draws to do
  423. has $!total; # total number of draws possible
  424. # Return the .WHICH key of a randomly picked object. Updates
  425. # the weight of the picked object and the total number of draws
  426. # still possible.
  427. method BAG-PICK() {
  428. nqp::stmts(
  429. (my Int $rand := $!total.rand.Int),
  430. (my Int $seen := 0),
  431. (my $iter := nqp::iterator($!weights)),
  432. nqp::while(
  433. $iter && nqp::isle_I(
  434. ($seen := nqp::add_I(
  435. $seen,
  436. nqp::iterval(nqp::shift($iter)),
  437. Int
  438. )),
  439. $rand
  440. ),
  441. nqp::null
  442. ),
  443. nqp::bindkey( # $iter now contains picked one
  444. $!weights,
  445. nqp::iterkey_s($iter),
  446. nqp::sub_I(nqp::iterval($iter),1,Int)
  447. ),
  448. ($!total := nqp::sub_I($!total,1,Int)),
  449. nqp::iterkey_s($iter)
  450. )
  451. }
  452. method SET-SELF(\raw, \todo, \total) {
  453. nqp::stmts(
  454. ($!weights := nqp::clone($!raw := raw)),
  455. (my $iter := nqp::iterator($!weights)),
  456. nqp::while(
  457. $iter,
  458. nqp::bindkey(
  459. $!weights,
  460. nqp::iterkey_s(nqp::shift($iter)),
  461. nqp::getattr(nqp::iterval($iter),Pair,'$!value')
  462. )
  463. ),
  464. ($!todo := nqp::if(todo > total,total,todo)),
  465. ($!total := total),
  466. self
  467. )
  468. }
  469. method new(\raw, \todo, \total) {
  470. nqp::create(self).SET-SELF(raw, todo, total)
  471. }
  472. method pull-one() is raw {
  473. nqp::if(
  474. $!todo,
  475. nqp::stmts(
  476. ($!todo := nqp::sub_I($!todo,1,Int)),
  477. nqp::getattr(nqp::atkey($!raw,self.BAG-PICK),Pair,'$!key')
  478. ),
  479. IterationEnd
  480. )
  481. }
  482. method skip-one() {
  483. nqp::if(
  484. $!todo,
  485. nqp::stmts(
  486. ($!todo := nqp::sub_I($!todo,1,Int)),
  487. self.BAG-PICK
  488. )
  489. )
  490. }
  491. method push-all($target --> IterationEnd) {
  492. nqp::stmts(
  493. (my $todo = $!todo),
  494. nqp::while(
  495. $todo,
  496. nqp::stmts(
  497. --$todo,
  498. $target.push(nqp::getattr(
  499. nqp::atkey($!raw,self.BAG-PICK),
  500. Pair,
  501. '$!key'
  502. ))
  503. )
  504. ),
  505. ($!todo := nqp::decont($todo))
  506. )
  507. }
  508. method count-only() { $!todo - 1 }
  509. method bool-only(--> True) { }
  510. method sink-all() { $!todo := 0 }
  511. }.new($!elems, $todo, nqp::ifnull($total,self.total))
  512. )
  513. }
  514. proto method roll(|) {*}
  515. multi method roll(Baggy:D:) {
  516. nqp::if(
  517. $!elems && (my $total := self.total),
  518. nqp::getattr(
  519. nqp::iterval(Rakudo::QuantHash.BAG-ROLL($!elems,$total)),
  520. Pair,
  521. '$!key'
  522. ),
  523. Nil
  524. )
  525. }
  526. multi method roll(Baggy:D: Whatever) {
  527. Seq.new(nqp::if(
  528. $!elems && (my $total := self.total),
  529. Rakudo::Iterator.Callable( {
  530. nqp::getattr(
  531. nqp::iterval(Rakudo::QuantHash.BAG-ROLL($!elems, $total)),
  532. Pair,
  533. '$!key'
  534. )
  535. }, True ),
  536. Rakudo::Iterator.Empty
  537. ))
  538. }
  539. multi method roll(Baggy:D: Callable:D $calculate) {
  540. nqp::if(
  541. (my $total := self.total),
  542. self.roll($calculate($total)),
  543. Seq.new(Rakudo::Iterator.Empty)
  544. )
  545. }
  546. multi method roll(Baggy:D: $count) {
  547. nqp::if(
  548. $count == Inf,
  549. self.roll(*), # let Whatever handle it
  550. Seq.new(nqp::if( # something else as count
  551. (my $todo = $count.Int) < 1, # also handles NaN
  552. Rakudo::Iterator.Empty, # nothing to do
  553. nqp::if(
  554. $!elems && (my $total := self.total) && ++$todo,
  555. Rakudo::Iterator.Callable( { # need to do a number of times
  556. nqp::if(
  557. --$todo,
  558. nqp::getattr(
  559. nqp::iterval(Rakudo::QuantHash.BAG-ROLL($!elems, $total)),
  560. Pair,
  561. '$!key'
  562. ),
  563. IterationEnd
  564. )
  565. }),
  566. Rakudo::Iterator.Empty # nothing to roll for
  567. )
  568. ))
  569. )
  570. }
  571. #--- classification method
  572. proto method classify-list(|) {*}
  573. multi method classify-list( &test, \list) {
  574. fail X::Cannot::Lazy.new(:action<classify>) if list.is-lazy;
  575. my \iter = (nqp::istype(list, Iterable) ?? list !! list.list).iterator;
  576. while (my $value := iter.pull-one) !=:= IterationEnd {
  577. my $tested := test($value);
  578. if nqp::istype($tested, Iterable) { # multi-level classify
  579. X::Invalid::ComputedValue.new(
  580. :name<mapper>,
  581. :method<classify-list>,
  582. :value<an Iterable item>,
  583. :reason(self.^name ~ ' cannot be nested and so does not '
  584. ~ 'support multi-level classification'),
  585. ).throw;
  586. }
  587. else {
  588. ++self{$tested};
  589. }
  590. }
  591. self;
  592. }
  593. multi method classify-list( %test, |c ) {
  594. self.classify-list( { %test{$^a} }, |c );
  595. }
  596. multi method classify-list( @test, |c ) {
  597. self.classify-list( { @test[$^a] }, |c );
  598. }
  599. multi method classify-list(&test, **@list, |c) {
  600. self.classify-list(&test, @list, |c);
  601. }
  602. proto method categorize-list(|) {*}
  603. multi method categorize-list( &test, \list ) {
  604. fail X::Cannot::Lazy.new(:action<categorize>) if list.is-lazy;
  605. my \iter = (nqp::istype(list, Iterable) ?? list !! list.list).iterator;
  606. my $value := iter.pull-one;
  607. unless $value =:= IterationEnd {
  608. my $tested := test($value);
  609. # multi-level categorize
  610. if nqp::istype($tested[0],Iterable) {
  611. X::Invalid::ComputedValue.new(
  612. :name<mapper>,
  613. :method<categorize-list>,
  614. :value<a nested Iterable item>,
  615. :reason(self.^name ~ ' cannot be nested and so does not '
  616. ~ 'support multi-level categorization'),
  617. ).throw;
  618. }
  619. # simple categorize
  620. else {
  621. loop {
  622. ++self{$_} for @$tested;
  623. last if ($value := iter.pull-one) =:= IterationEnd;
  624. nqp::istype(($tested := test($value))[0], Iterable)
  625. and X::Invalid::ComputedValue.new(
  626. :name<mapper>,
  627. :method<categorize-list>,
  628. :value('an item with different number of elements '
  629. ~ 'in it than previous items'),
  630. :reason('all values need to have the same number '
  631. ~ 'of elements. Mixed-level classification is '
  632. ~ 'not supported.'),
  633. ).throw;
  634. };
  635. }
  636. }
  637. self;
  638. }
  639. multi method categorize-list( %test, |c ) {
  640. self.categorize-list( { %test{$^a} }, |c );
  641. }
  642. multi method categorize-list( @test, |c ) {
  643. self.categorize-list( { @test[$^a] }, |c );
  644. }
  645. multi method categorize-list( &test, **@list, |c ) {
  646. self.categorize-list( &test, @list, |c );
  647. }
  648. #--- coercion methods
  649. sub SETIFY(\raw, \type) {
  650. nqp::if(
  651. raw && nqp::elems(raw),
  652. nqp::stmts(
  653. (my $elems := nqp::clone(raw)),
  654. (my $iter := nqp::iterator($elems)),
  655. nqp::while(
  656. $iter,
  657. nqp::bindkey(
  658. $elems,
  659. nqp::iterkey_s(nqp::shift($iter)),
  660. nqp::getattr(nqp::iterval($iter),Pair,'$!key'),
  661. )
  662. ),
  663. nqp::create(type).SET-SELF($elems)
  664. ),
  665. nqp::if(
  666. nqp::eqaddr(type,Set),
  667. set(),
  668. nqp::create(type)
  669. )
  670. )
  671. }
  672. multi method Set(Baggy:D:) { SETIFY($!elems,Set) }
  673. multi method SetHash(Baggy:D:) { SETIFY($!elems,SetHash) }
  674. sub MIXIFY(\raw, \type) {
  675. nqp::if(
  676. raw && nqp::elems(raw),
  677. nqp::create(type).SET-SELF(Rakudo::QuantHash.BAGGY-CLONE(raw)),
  678. nqp::if(
  679. nqp::istype(type,Mix),
  680. mix(),
  681. nqp::create(MixHash)
  682. )
  683. )
  684. }
  685. multi method Mix(Baggy:D:) { MIXIFY($!elems, Mix) }
  686. multi method MixHash(Baggy:D:) { MIXIFY($!elems, MixHash) }
  687. method RAW-HASH() is raw { $!elems }
  688. }
  689. multi sub infix:<eqv>(Baggy:D \a, Baggy:D \b --> Bool:D) {
  690. nqp::p6bool(
  691. nqp::eqaddr(a,b) || (nqp::eqaddr(a.WHAT,b.WHAT) && a.ACCEPTS(b))
  692. )
  693. }