1. # A List is a (potentially infite) immutable list. The immutability is not
  2. # deep; a List may contain Scalar containers that can be assigned to. However,
  3. # it is not possible to shift/unshift/push/pop/splice/bind. A List is also
  4. # Positional, and so may be indexed.
  5. my class List does Iterable does Positional { # declared in BOOTSTRAP
  6. # class List is Cool
  7. # The reified elements in the list so far (that is, those that we already
  8. # have produced the values for).
  9. # has $!reified;
  10. #
  11. # Object that reifies the rest of the list. We don't just inline it into
  12. # the List class itself, because a STORE on Array can clear things and
  13. # upset an ongoing iteration. (An easy way to create such a case is to
  14. # assign an array with lazy parts into itself.)
  15. # has $!todo;
  16. # The object that goes into $!todo.
  17. class Reifier {
  18. # Our copy of the reified elements in the list so far.
  19. has $!reified;
  20. # The current iterator, if any, that we're working our way through in
  21. # order to lazily reify values. Must be depleted before $!future is
  22. # considered.
  23. has Iterator $!current-iter;
  24. # The (possibly lazy) values we've not yet incorporated into the list. The
  25. # only thing we can't simply copy from $!future into $!reified is a Slip
  26. # (and so the only reason to have a $!future is that there is at least one
  27. # Slip).
  28. has $!future;
  29. # The reification target (what .reify-* will .push to). Exists so we can
  30. # share the reification code between List/Array. List just uses its own
  31. # $!reified buffer; the Array one shoves stuff into Scalar containers
  32. # first.
  33. has $!reification-target;
  34. method reify-at-least(int $elems) {
  35. nqp::stmts(
  36. nqp::if(
  37. ($!current-iter.DEFINITE
  38. && nqp::eqaddr(
  39. $!current-iter.push-at-least(
  40. $!reification-target,
  41. nqp::sub_i($elems,nqp::elems($!reified))
  42. ),
  43. IterationEnd
  44. )),
  45. $!current-iter := Iterator
  46. ),
  47. # there is a future
  48. nqp::if(
  49. $!future.DEFINITE,
  50. # still need and can get something from the future
  51. nqp::stmts(
  52. nqp::while(
  53. (nqp::islt_i(nqp::elems($!reified),$elems)
  54. && nqp::elems($!future)),
  55. nqp::if(
  56. (nqp::istype((my $current := nqp::shift($!future)),Slip)
  57. && nqp::isconcrete($current)),
  58. nqp::stmts(
  59. (my $iter := $current.iterator),
  60. nqp::unless(
  61. nqp::eqaddr(
  62. $iter.push-at-least(
  63. $!reification-target,
  64. nqp::sub_i($elems,nqp::elems($!reified))
  65. ),
  66. IterationEnd
  67. ),
  68. # The iterator produced enough values to fill the need,
  69. # but did not reach its end. We save it for next time.
  70. # We know we'll exit the loop, since the < $elems check
  71. # must be False (unless the iterator broke contract).
  72. ($!current-iter := $iter)
  73. )
  74. ),
  75. $!reification-target.push($current)
  76. )
  77. ),
  78. # that was the future
  79. nqp::unless(
  80. nqp::elems($!future),
  81. ($!future := Mu)
  82. )
  83. )
  84. ),
  85. nqp::elems($!reified)
  86. )
  87. }
  88. method reify-until-lazy() {
  89. nqp::stmts(
  90. nqp::if(
  91. ($!current-iter.DEFINITE
  92. && nqp::eqaddr(
  93. $!current-iter.push-until-lazy($!reification-target),
  94. IterationEnd
  95. )
  96. ),
  97. $!current-iter := Iterator
  98. ),
  99. nqp::if(
  100. ($!future.DEFINITE && nqp::not_i($!current-iter.DEFINITE)),
  101. nqp::stmts(
  102. nqp::while(
  103. nqp::elems($!future),
  104. nqp::if(
  105. (nqp::istype((my $current := nqp::shift($!future)),Slip)
  106. && nqp::isconcrete($current)),
  107. nqp::unless(
  108. nqp::eqaddr(
  109. (my $iter := $current.iterator).push-until-lazy(
  110. $!reification-target),
  111. IterationEnd
  112. ),
  113. nqp::stmts(
  114. ($!current-iter := $iter),
  115. last
  116. )
  117. ),
  118. $!reification-target.push($current)
  119. )
  120. ),
  121. nqp::unless(
  122. nqp::elems($!future),
  123. $!future := Mu
  124. )
  125. )
  126. ),
  127. nqp::elems($!reified)
  128. )
  129. }
  130. method reify-all() {
  131. nqp::stmts(
  132. nqp::if(
  133. $!current-iter.DEFINITE,
  134. nqp::stmts(
  135. $!current-iter.push-all($!reification-target),
  136. $!current-iter := Iterator
  137. )
  138. ),
  139. nqp::if(
  140. $!future.DEFINITE,
  141. nqp::stmts(
  142. nqp::while(
  143. nqp::elems($!future),
  144. nqp::if(
  145. (nqp::istype((my $current := nqp::shift($!future)),Slip)
  146. && nqp::isconcrete($current)),
  147. $current.iterator.push-all($!reification-target),
  148. $!reification-target.push($current)
  149. )
  150. ),
  151. ($!future := Mu)
  152. )
  153. ),
  154. nqp::elems($!reified)
  155. )
  156. }
  157. method fully-reified() {
  158. !($!current-iter.DEFINITE || $!future.DEFINITE)
  159. }
  160. method is-lazy() {
  161. nqp::if(
  162. $!current-iter.DEFINITE,
  163. $!current-iter.is-lazy
  164. )
  165. }
  166. }
  167. method from-iterator(List:U: Iterator $iter) {
  168. nqp::stmts(
  169. (my \buffer := nqp::create(IterationBuffer)),
  170. nqp::bindattr(
  171. (my \result := nqp::create(self)),List,'$!reified',buffer),
  172. nqp::bindattr(
  173. (my \todo := nqp::create(Reifier)),Reifier,'$!reified',buffer),
  174. nqp::bindattr(todo,Reifier,'$!current-iter',$iter),
  175. # since Array has its own from-iterator, we don't need to
  176. # call reification-target, because it is the same as buffer
  177. nqp::bindattr(todo,Reifier,'$!reification-target',buffer),
  178. nqp::p6bindattrinvres(result,List,'$!todo',todo)
  179. )
  180. }
  181. method from-slurpy(|) {
  182. my \result := nqp::create(self);
  183. my Mu \vm-tuple := nqp::captureposarg(nqp::usecapture,1);
  184. nqp::if(
  185. nqp::isgt_i(nqp::elems(vm-tuple),0),
  186. nqp::stmts(
  187. nqp::bindattr(result,List,'$!reified',
  188. my \buffer := nqp::create(IterationBuffer)),
  189. nqp::bindattr(result,List,'$!todo',
  190. my \todo := nqp::create(List::Reifier)),
  191. nqp::bindattr(todo,List::Reifier,'$!reified',
  192. buffer),
  193. nqp::bindattr(todo,List::Reifier,'$!reification-target',
  194. result.reification-target),
  195. nqp::bindattr(todo,List::Reifier,'$!future',vm-tuple)
  196. )
  197. );
  198. result
  199. }
  200. method from-slurpy-onearg(|) {
  201. my Mu \vm-tuple := nqp::captureposarg(nqp::usecapture, 1);
  202. my $result;
  203. my $buffer;
  204. my $todo;
  205. my $consider;
  206. nqp::if(
  207. nqp::isgt_i(nqp::elems(vm-tuple),1),
  208. nqp::stmts( # handle as slurpy
  209. nqp::bindattr(($result := nqp::create(self)),List,'$!reified',
  210. $buffer := nqp::create(IterationBuffer)),
  211. nqp::bindattr($result,List,'$!todo',
  212. $todo := nqp::create(List::Reifier)),
  213. nqp::bindattr($todo,List::Reifier,'$!reified',
  214. $buffer),
  215. nqp::bindattr($todo,List::Reifier,'$!reification-target',
  216. $result.reification-target),
  217. nqp::bindattr($todo,List::Reifier,'$!future',vm-tuple),
  218. $result
  219. ),
  220. nqp::if(
  221. nqp::iseq_i(nqp::elems(vm-tuple),1),
  222. nqp::if( # single arg semantics active
  223. nqp::istype(($consider := nqp::atpos(vm-tuple,0)),Seq),
  224. nqp::if( # a single Seq
  225. nqp::istype(self,Array),
  226. $consider.cache,
  227. $consider
  228. ),
  229. nqp::stmts( # something else
  230. nqp::bindattr(($result := nqp::create(self)),List,'$!reified',
  231. $buffer := nqp::create(IterationBuffer)),
  232. nqp::bindattr($result,List,'$!todo',
  233. $todo := nqp::create(List::Reifier)),
  234. nqp::bindattr($todo,List::Reifier,'$!reified',
  235. $buffer),
  236. nqp::bindattr($todo,List::Reifier,'$!reification-target',
  237. $result.reification-target),
  238. nqp::if(
  239. nqp::iscont($consider)
  240. || nqp::not_i(nqp::istype($consider,Iterable))
  241. || nqp::not_i(nqp::p6definite($consider)),
  242. nqp::bindattr($todo,List::Reifier,'$!future',
  243. vm-tuple),
  244. nqp::bindattr($todo,List::Reifier,'$!future',
  245. nqp::list($consider.list.Slip))
  246. ),
  247. $result
  248. )
  249. ),
  250. nqp::create(self) # no args, so just a bare object
  251. )
  252. )
  253. }
  254. method from-slurpy-flat(|) {
  255. nqp::if(
  256. (my int $elems = nqp::elems(
  257. (my Mu $vm-tuple := nqp::captureposarg(nqp::usecapture,1))
  258. )),
  259. nqp::stmts(
  260. (my $future := nqp::setelems(nqp::create(IterationBuffer),$elems)),
  261. (my int $i = -1),
  262. (my int $b = 0),
  263. nqp::while(
  264. nqp::islt_i($i = nqp::add_i($i,1),$elems),
  265. nqp::if(
  266. nqp::iscont(my $consider := nqp::atpos($vm-tuple,$i)),
  267. nqp::bindpos($future,$i,$consider),
  268. nqp::if(
  269. (nqp::istype($consider,Iterable) && $consider.DEFINITE),
  270. nqp::if(
  271. nqp::istype($consider,PositionalBindFailover),
  272. nqp::bindpos($future,$i,$consider.cache.flat.Slip),
  273. nqp::bindpos($future,$i,$consider.flat.Slip)
  274. ),
  275. nqp::stmts(
  276. nqp::bindpos($future,$i,$consider),
  277. ($b = nqp::add_i($b,1))
  278. )
  279. )
  280. )
  281. ),
  282. nqp::if(
  283. nqp::iseq_i($b,$elems),
  284. # we already reified everything
  285. nqp::p6bindattrinvres(nqp::create(self),List,'$!reified',$future),
  286. # need full fledged List with a $todo
  287. nqp::stmts(
  288. (my $result :=
  289. nqp::p6bindattrinvres(nqp::create(self),List,'$!reified',
  290. (my $buffer := nqp::create(IterationBuffer))
  291. )
  292. ),
  293. nqp::bindattr($result,List,'$!todo',
  294. (my $todo := nqp::create(List::Reifier))
  295. ),
  296. nqp::bindattr($todo,List::Reifier,'$!reified',
  297. $buffer
  298. ),
  299. nqp::bindattr($todo,List::Reifier,'$!reification-target',
  300. $result.reification-target
  301. ),
  302. nqp::bindattr($todo,List::Reifier,'$!future',
  303. $future
  304. ),
  305. $result
  306. )
  307. )
  308. ),
  309. # no args, an empty list suffices
  310. nqp::create(self)
  311. )
  312. }
  313. method new(**@things) {
  314. my \list = nqp::create(self);
  315. my \iterbuffer = nqp::create(IterationBuffer);
  316. nqp::bindattr(list, List, '$!reified', iterbuffer);
  317. my int $elems = +@things; # reify
  318. my int $i = -1;
  319. my $reified := nqp::getattr(@things,List,'$!reified');
  320. nqp::while( # doesn't sink
  321. nqp::islt_i($i = nqp::add_i($i,1),$elems),
  322. nqp::bindpos(iterbuffer,$i,(nqp::atpos($reified,$i)))
  323. );
  324. list
  325. }
  326. multi method Bool(List:D:) {
  327. nqp::p6bool(
  328. nqp::unless(
  329. ($!reified.DEFINITE && nqp::elems($!reified)),
  330. ($!todo.DEFINITE && $!todo.reify-at-least(1))
  331. )
  332. )
  333. }
  334. multi method Int(List:D:) { self.elems }
  335. multi method end(List:D:) { self.elems - 1 }
  336. multi method Numeric(List:D:) { self.elems }
  337. multi method Str(List:D:) { self.join(' ') }
  338. # Pretend we're a Match assuming we're a list of Matches
  339. method to() { self.elems ?? self[self.end].to !! Nil }
  340. method from() { self.elems ?? self[0].from !! Nil }
  341. method sum() is nodal {
  342. nqp::if(
  343. self.is-lazy,
  344. Failure.new(X::Cannot::Lazy.new(:action('.sum'))),
  345. nqp::if(
  346. $!reified.DEFINITE && (my int $elems = self.elems), # reifies
  347. nqp::stmts(
  348. (my $list := $!reified),
  349. (my $sum = nqp::ifnull(nqp::atpos($list,0),0)),
  350. (my int $i),
  351. nqp::while(
  352. nqp::islt_i($i = nqp::add_i($i,1),$elems),
  353. ($sum = $sum + nqp::ifnull(nqp::atpos($list,$i),0))
  354. ),
  355. $sum
  356. ),
  357. 0
  358. )
  359. )
  360. }
  361. proto method fmt(|) { * }
  362. multi method fmt() {
  363. nqp::if(
  364. (my int $elems = self.elems), # reifies
  365. nqp::stmts(
  366. (my $list := $!reified),
  367. (my $strings := nqp::setelems(nqp::list_s,$elems)),
  368. (my int $i = -1),
  369. nqp::while(
  370. nqp::islt_i(($i = nqp::add_i($i,1)),$elems),
  371. nqp::bindpos_s($strings,$i,nqp::atpos($list,$i).Str)
  372. ),
  373. nqp::p6box_s(nqp::join(' ',$strings))
  374. ),
  375. ''
  376. )
  377. }
  378. multi method fmt(Str(Cool) $format) {
  379. nqp::if(
  380. nqp::iseq_s($format,'%s'),
  381. self.fmt,
  382. self.fmt($format,' ')
  383. )
  384. }
  385. multi method fmt(Str(Cool) $format, $separator) {
  386. nqp::if(
  387. nqp::iseq_s($format,'%s') && nqp::iseq_s($separator,' '),
  388. self.fmt,
  389. nqp::if(
  390. (my int $elems = self.elems), # reifies
  391. nqp::stmts(
  392. (my $list := $!reified),
  393. (my $strings := nqp::setelems(nqp::list_s,$elems)),
  394. (my int $i = -1),
  395. nqp::if(
  396. nqp::iseq_i( # only one % in format?
  397. nqp::elems(nqp::split('%',$format)),
  398. 2
  399. ) && nqp::iseq_i( # only one %s in format
  400. nqp::elems(my $parts := nqp::split('%s',$format)),
  401. 2
  402. ),
  403. nqp::while( # only a single %s
  404. nqp::islt_i(($i = nqp::add_i($i,1)),$elems),
  405. nqp::bindpos_s($strings,$i,
  406. nqp::join(nqp::atpos($list,$i).Str,$parts)
  407. )
  408. ),
  409. nqp::while( # something else
  410. nqp::islt_i(($i = nqp::add_i($i,1)),$elems),
  411. nqp::bindpos_s($strings,$i,
  412. nqp::atpos($list,$i).fmt($format)
  413. )
  414. )
  415. ),
  416. nqp::p6box_s(nqp::join($separator,$strings))
  417. ),
  418. ''
  419. )
  420. )
  421. }
  422. multi method elems(List:D:) is nodal {
  423. nqp::if(
  424. $!todo.DEFINITE,
  425. nqp::stmts(
  426. $!todo.reify-until-lazy,
  427. nqp::if(
  428. $!todo.fully-reified,
  429. nqp::stmts(
  430. ($!todo := nqp::null),
  431. nqp::elems($!reified)
  432. ),
  433. Failure.new(X::Cannot::Lazy.new(:action('.elems')))
  434. )
  435. ),
  436. nqp::if(
  437. $!reified.DEFINITE,
  438. nqp::elems($!reified),
  439. 0
  440. )
  441. )
  442. }
  443. multi method AT-POS(List:D: Int:D $Ipos) is raw {
  444. nqp::if(
  445. nqp::islt_i((my int $pos = nqp::unbox_i($Ipos)),0),
  446. Failure.new(X::OutOfRange.new(
  447. :what($*INDEX // 'Index'), :got($pos), :range<0..^Inf>)),
  448. nqp::if(
  449. $!reified.DEFINITE,
  450. nqp::if(
  451. nqp::islt_i($pos,nqp::elems($!reified)),
  452. nqp::atpos($!reified,$pos),
  453. nqp::if(
  454. ($!todo.DEFINITE && $!todo.reify-at-least(nqp::add_i($pos,1))),
  455. nqp::ifnull(nqp::atpos($!reified,$pos),Nil),
  456. Nil
  457. )
  458. ),
  459. Nil
  460. )
  461. )
  462. }
  463. multi method AT-POS(List:D: int $pos) is raw {
  464. nqp::if(
  465. nqp::islt_i($pos,0),
  466. Failure.new(X::OutOfRange.new(
  467. :what($*INDEX // 'Index'), :got($pos), :range<0..^Inf>)),
  468. nqp::if(
  469. $!reified.DEFINITE,
  470. nqp::if(
  471. nqp::islt_i($pos,nqp::elems($!reified)),
  472. nqp::atpos($!reified,$pos),
  473. nqp::if(
  474. ($!todo.DEFINITE && $!todo.reify-at-least(nqp::add_i($pos,1))),
  475. nqp::ifnull(nqp::atpos($!reified,$pos),Nil),
  476. Nil
  477. )
  478. ),
  479. Nil
  480. )
  481. )
  482. }
  483. method BIND-POS(List:D: Int:D \pos, \what) is raw {
  484. nqp::iscont(self.AT-POS(pos))
  485. ?? nqp::bindpos($!reified,nqp::unbox_i(pos),what)
  486. !! X::Bind.new.throw
  487. }
  488. multi method EXISTS-POS(List:D: int $pos) {
  489. nqp::p6bool(
  490. nqp::if(
  491. nqp::isge_i($pos,0),
  492. nqp::if(
  493. $!reified.DEFINITE && nqp::islt_i($pos,nqp::elems($!reified)),
  494. nqp::existspos($!reified,$pos),
  495. nqp::if(
  496. $!todo.DEFINITE,
  497. nqp::stmts(
  498. $!todo.reify-at-least(nqp::add_i($pos,1)),
  499. nqp::existspos($!reified,$pos)
  500. )
  501. )
  502. )
  503. )
  504. )
  505. }
  506. multi method EXISTS-POS(List:D: Int:D $pos) {
  507. nqp::p6bool(
  508. nqp::if(
  509. nqp::isge_i($pos,0),
  510. nqp::if(
  511. $!reified.DEFINITE && nqp::islt_i($pos,nqp::elems($!reified)),
  512. nqp::existspos($!reified,$pos),
  513. nqp::if(
  514. $!todo.DEFINITE,
  515. nqp::stmts(
  516. $!todo.reify-at-least(nqp::add_i($pos,1)),
  517. nqp::existspos($!reified,$pos)
  518. )
  519. )
  520. )
  521. )
  522. )
  523. }
  524. method reification-target(List:D:) {
  525. nqp::ifnull(
  526. $!reified,
  527. $!reified := nqp::create(IterationBuffer)
  528. )
  529. }
  530. method iterator(List:D:) {
  531. # something to iterate over in the future
  532. nqp::if(
  533. $!todo.DEFINITE,
  534. class :: does Iterator {
  535. has int $!i;
  536. has $!list;
  537. has $!reified;
  538. has $!todo;
  539. method !SET-SELF(\list) {
  540. $!i = -1;
  541. $!list := list;
  542. $!reified := nqp::getattr(list,List,'$!reified').DEFINITE
  543. # we already have a place to put values in
  544. ?? nqp::getattr(list,List,'$!reified')
  545. # create a place here and there to put values in
  546. !! nqp::bindattr(list,List,'$!reified',
  547. nqp::create(IterationBuffer));
  548. $!todo := nqp::getattr(list, List, '$!todo');
  549. self
  550. }
  551. method new(\list) { nqp::create(self)!SET-SELF(list) }
  552. method pull-one() is raw {
  553. nqp::ifnull(
  554. nqp::atpos($!reified,$!i = nqp::add_i($!i,1)),
  555. $!todo.DEFINITE
  556. ?? nqp::islt_i($!i,$!todo.reify-at-least(nqp::add_i($!i,1)))
  557. ?? nqp::atpos($!reified,$!i)
  558. !! self!done
  559. !! IterationEnd
  560. )
  561. }
  562. method !done() is raw {
  563. $!todo := nqp::bindattr($!list,List,'$!todo',nqp::null);
  564. IterationEnd
  565. }
  566. method push-until-lazy($target) {
  567. if $!todo.DEFINITE {
  568. my int $elems = $!todo.reify-until-lazy;
  569. nqp::while( # doesn't sink
  570. nqp::islt_i($!i = nqp::add_i($!i,1),$elems),
  571. $target.push(nqp::atpos($!reified,$!i))
  572. );
  573. nqp::if(
  574. $!todo.fully-reified,
  575. self!done,
  576. nqp::stmts(
  577. ($!i = $elems - 1),
  578. Mu
  579. )
  580. )
  581. }
  582. else {
  583. my int $elems = nqp::elems($!reified);
  584. nqp::while( # doesn't sink
  585. nqp::islt_i($!i = nqp::add_i($!i,1),$elems),
  586. $target.push(nqp::atpos($!reified,$!i))
  587. );
  588. IterationEnd
  589. }
  590. }
  591. method is-lazy() { $!todo.DEFINITE && $!todo.is-lazy }
  592. }.new(self),
  593. # everything we need is already there
  594. nqp::if(
  595. $!reified.DEFINITE,
  596. Rakudo::Iterator.ReifiedList(self),
  597. Rakudo::Iterator.Empty
  598. )
  599. )
  600. }
  601. multi method ACCEPTS(List:D: $topic) {
  602. unless nqp::istype($topic, Iterable) {
  603. return self unless self.elems;
  604. return self if nqp::istype(self[0], Match);
  605. return False;
  606. }
  607. my $sseq = self;
  608. my $tseq = $topic;
  609. sub tailmatch($s,$t) {
  610. my int $spos = $s;
  611. my int $tpos = $t;
  612. while $spos < $sseq {
  613. # if the next element is Whatever
  614. if nqp::istype($sseq[$spos], HyperWhatever) {
  615. # skip over all of the Whatevers
  616. $spos = $spos + 1
  617. while $spos <= $sseq && nqp::istype($sseq[$spos], HyperWhatever);
  618. # if nothing left, we're done
  619. return True if $spos == $sseq;
  620. # find a target matching our new target
  621. while $tpos < $tseq {
  622. my $result = tailmatch($spos,$tpos);
  623. return True if $result;
  624. $tpos = $tpos + 1
  625. }
  626. # return false if we ran out
  627. return False;
  628. }
  629. elsif $tpos == $tseq or not $sseq[$spos].ACCEPTS($tseq[$tpos] ) {
  630. return False;
  631. }
  632. # skip matching elements
  633. $spos = $spos + 1;
  634. $tpos = $tpos + 1;
  635. }
  636. # If nothing left to match, we're successful.
  637. $tpos >= $tseq;
  638. }
  639. tailmatch(0,0);
  640. }
  641. multi method list(List:D:) { self }
  642. proto method Seq(|) is nodal { * }
  643. multi method Seq(List:D:) { Seq.new(self.iterator) }
  644. method sink(--> Nil) { }
  645. multi method values(List:D:) {
  646. Seq.new(self.iterator)
  647. }
  648. multi method keys(List:D:) {
  649. Seq.new(nqp::if(
  650. self.is-lazy,
  651. nqp::stmts(
  652. (my int $i = -1),
  653. Rakudo::Iterator.Callable( { $i = nqp::add_i($i,1) }, True )
  654. ),
  655. Rakudo::Iterator.IntRange(0, self.elems - 1)
  656. ))
  657. }
  658. multi method kv(List:D:) {
  659. Seq.new(Rakudo::Iterator.KeyValue(self.iterator))
  660. }
  661. multi method pairs(List:D:) {
  662. Seq.new(Rakudo::Iterator.Pair(self.iterator))
  663. }
  664. multi method antipairs(List:D:) {
  665. Seq.new(Rakudo::Iterator.AntiPair(self.iterator))
  666. }
  667. multi method invert(List:D:) {
  668. Seq.new(Rakudo::Iterator.Invert(self.iterator))
  669. }
  670. # Store in List targets containers with in the list. This handles list
  671. # assignments, like ($a, $b) = foo().
  672. proto method STORE(|) { * }
  673. multi method STORE(List:D: Iterable:D \iterable) {
  674. # First pass -- scan lhs containers and pick out scalar versus list
  675. # assignment. This also reifies the RHS values we need, and deconts
  676. # them. The decont is needed so that we can do ($a, $b) = ($b, $a).
  677. my \cv = nqp::list();
  678. my \lhs-iter = self.iterator;
  679. my \rhs-iter = iterable.iterator;
  680. my int $rhs-done;
  681. my Mu $v;
  682. my Mu $c;
  683. my Mu $sub-iter;
  684. my Mu $sc;
  685. nqp::until(
  686. nqp::eqaddr(($c := lhs-iter.pull-one),IterationEnd),
  687. nqp::if( # Container: scalar assignment
  688. nqp::iscont($c),
  689. nqp::stmts(
  690. nqp::push(cv,$c),
  691. nqp::if(
  692. ($rhs-done || ($rhs-done =
  693. nqp::eqaddr(($v := rhs-iter.pull-one),IterationEnd))),
  694. nqp::push(cv,Nil),
  695. nqp::push(cv,nqp::decont($v)),
  696. )
  697. ),
  698. nqp::if( # Whatever: skip assigning value
  699. nqp::istype($c,Whatever),
  700. nqp::if(
  701. (nqp::not_i($rhs-done)
  702. && nqp::eqaddr(rhs-iter.pull-one,IterationEnd)),
  703. ($rhs-done = 1)
  704. ),
  705. nqp::if( # List splice into current lhs
  706. (nqp::istype($c,List) && nqp::not_i(nqp::istype($c,Array))),
  707. nqp::stmts(
  708. ($sub-iter := $c.iterator),
  709. nqp::until(
  710. nqp::eqaddr(($sc := $sub-iter.pull-one),IterationEnd),
  711. nqp::stmts(
  712. nqp::push(cv,$sc);
  713. nqp::if(
  714. ($rhs-done = nqp::eqaddr(
  715. ($v := rhs-iter.pull-one),IterationEnd
  716. )),
  717. nqp::push(cv,Nil),
  718. nqp::push(cv,nqp::decont($v))
  719. )
  720. )
  721. )
  722. ),
  723. nqp::stmts( # Non-container: store entire remaining rhs
  724. nqp::push(cv,$c),
  725. nqp::push(cv,List.from-iterator(rhs-iter)),
  726. ($rhs-done = 1)
  727. )
  728. )
  729. )
  730. )
  731. );
  732. # Second pass, perform the assignments.
  733. nqp::shift(cv) = nqp::shift(cv) while nqp::elems(cv);
  734. self
  735. }
  736. multi method STORE(List:D: Mu \item) {
  737. self.STORE((item,));
  738. }
  739. multi method gist(List:D:) {
  740. self.gistseen('List', {
  741. '(' ~ self.map( -> $elem {
  742. given ++$ {
  743. when 101 { '...' }
  744. when 102 { last }
  745. default { $elem.gist }
  746. }
  747. }).join(' ') ~ ')'
  748. })
  749. }
  750. multi method perl(List:D \SELF:) {
  751. SELF.perlseen('List', {
  752. '$' x nqp::iscont(SELF) ~ '('
  753. ~ (self.elems == 1 ?? self[0].perl ~ ',' !! self.map({.perl}).join(', '))
  754. ~ ' ' x nqp::istrue(self.not && nqp::iscont(SELF)) # add space to avoid `$()`
  755. ~ ')'
  756. })
  757. }
  758. multi method List(List:D:) { self }
  759. multi method Slip(List:D:) {
  760. nqp::if(
  761. $!todo.DEFINITE,
  762. # We're not fully reified, and so have internal mutability still.
  763. # The safe thing to do is to take an iterator of ourself and build
  764. # the Slip out of that.
  765. Slip.from-iterator(self.iterator),
  766. # We're fully reified - and so immutable inside and out! Just make
  767. # a Slip that shares our reified buffer.
  768. nqp::p6bindattrinvres(nqp::create(Slip),List,'$!reified',$!reified)
  769. )
  770. }
  771. multi method Array(List:D:) {
  772. # We need to populate the Array slots with Scalar containers
  773. nqp::if(
  774. $!todo.DEFINITE,
  775. Array.from-iterator(self.iterator),
  776. nqp::if(
  777. $!reified.DEFINITE,
  778. nqp::stmts(
  779. (my int $elems = nqp::elems($!reified)),
  780. (my $array := nqp::setelems(nqp::create(IterationBuffer),$elems)),
  781. (my int $i = -1),
  782. nqp::while(
  783. nqp::islt_i(($i = nqp::add_i($i,1)),$elems),
  784. nqp::bindpos($array, $i,
  785. nqp::assign(
  786. nqp::p6scalarfromdesc(nqp::null),
  787. nqp::atpos($!reified,$i)
  788. )
  789. )
  790. ),
  791. nqp::p6bindattrinvres(nqp::create(Array),List,'$!reified',$array)
  792. ),
  793. nqp::create(Array)
  794. )
  795. )
  796. }
  797. method eager {
  798. nqp::stmts(
  799. nqp::if(
  800. $!todo.DEFINITE,
  801. nqp::stmts(
  802. $!todo.reify-all,
  803. ($!todo := nqp::null)
  804. )
  805. ),
  806. self
  807. )
  808. }
  809. method Capture() {
  810. fail X::Cannot::Lazy.new(:action('create a Capture from'))
  811. if self.is-lazy;
  812. # we have something to work with
  813. if $!reified.DEFINITE && nqp::elems($!reified) -> int $elems {
  814. my $capture := nqp::create(Capture);
  815. my $list := nqp::create(IterationBuffer);
  816. my $hash := nqp::hash;
  817. my int $i = -1;
  818. my $v;
  819. nqp::istype(($v := nqp::atpos($!reified, $i)),Pair)
  820. ?? nqp::bindkey($hash, nqp::unbox_s($v.key), $v.value)
  821. !! nqp::push($list,$v)
  822. while nqp::islt_i($i = nqp::add_i($i,1),$elems);
  823. nqp::bindattr($capture,Capture,'@!list',$list) if nqp::elems($list);
  824. nqp::bindattr($capture,Capture,'%!hash',$hash) if nqp::elems($hash);
  825. $capture
  826. }
  827. # nothing to work with
  828. else {
  829. nqp::create(Capture)
  830. }
  831. }
  832. method FLATTENABLE_LIST() {
  833. nqp::if(
  834. $!todo.DEFINITE,
  835. nqp::stmts(
  836. $!todo.reify-all,
  837. $!reified
  838. ),
  839. nqp::if(
  840. $!reified.DEFINITE,
  841. $!reified,
  842. nqp::bindattr(self,List,'$!reified',nqp::create(IterationBuffer))
  843. )
  844. )
  845. }
  846. method FLATTENABLE_HASH() { nqp::hash() }
  847. method Supply(List:D:) { Supply.from-list(self) }
  848. method CALL-ME(List:U: |c) {
  849. self.new(|c);
  850. }
  851. multi method is-lazy(List:D:) {
  852. nqp::if(
  853. $!todo.DEFINITE,
  854. nqp::stmts(
  855. $!todo.reify-until-lazy,
  856. nqp::if(
  857. $!todo.fully-reified,
  858. nqp::p6bool($!todo := nqp::null),
  859. True
  860. )
  861. )
  862. )
  863. }
  864. proto method pick(|) is nodal { * }
  865. multi method pick(List:D:) {
  866. self.is-lazy
  867. ?? Failure.new(X::Cannot::Lazy.new(:action('.pick from')))
  868. !! (my Int $elems = self.elems)
  869. ?? nqp::atpos($!reified, $elems.rand.floor)
  870. !! Nil
  871. }
  872. multi method pick(List:D: Callable:D $calculate) {
  873. self.is-lazy
  874. ?? Failure.new(X::Cannot::Lazy.new(:action('.pick from')))
  875. !! self.pick( $calculate(self.elems) )
  876. }
  877. multi method pick(List:D: $number is copy) {
  878. fail X::Cannot::Lazy.new(:action('.pick from')) if self.is-lazy;
  879. my Int $elems = self.elems;
  880. return () unless $elems;
  881. $number = nqp::istype($number,Whatever) || $number == Inf
  882. ?? $elems
  883. !! $number.UInt min $elems;
  884. Seq.new(class :: does Iterator {
  885. has $!list;
  886. has Int $!elems;
  887. has int $!number;
  888. method !SET-SELF(\list,$!elems,\number) {
  889. $!list := nqp::clone(nqp::getattr(list,List,'$!reified'));
  890. $!number = number + 1;
  891. self
  892. }
  893. method new(\list,\elems,\number) {
  894. nqp::create(self)!SET-SELF(list,elems,number)
  895. }
  896. method pull-one() {
  897. if ($!number = nqp::sub_i($!number,1)) {
  898. my int $i;
  899. my \tmp = nqp::atpos($!list,$i = $!elems.rand.floor);
  900. nqp::bindpos($!list,$i,
  901. nqp::atpos($!list,nqp::unbox_i(--$!elems))
  902. );
  903. tmp
  904. }
  905. else {
  906. IterationEnd
  907. }
  908. }
  909. method push-all($target --> IterationEnd) {
  910. my int $i;
  911. nqp::while(
  912. ($!number = nqp::sub_i($!number,1)),
  913. nqp::stmts( # doesn't sink
  914. ($target.push(nqp::atpos($!list,$i = $!elems.rand.floor))),
  915. (nqp::bindpos($!list,$i,
  916. nqp::atpos($!list,nqp::unbox_i(--$!elems))))
  917. )
  918. )
  919. }
  920. }.new(self,$elems,$number))
  921. }
  922. proto method roll(|) is nodal { * }
  923. multi method roll() {
  924. self.is-lazy
  925. ?? Failure.new(X::Cannot::Lazy.new(:action('.roll from')))
  926. !! (my Int $elems = self.elems)
  927. ?? nqp::atpos($!reified, $elems.rand.floor)
  928. !! Nil
  929. }
  930. multi method roll(Whatever) {
  931. nqp::if(
  932. self.is-lazy,
  933. X::Cannot::Lazy.new(:action('.roll from')).throw,
  934. Seq.new(nqp::if(
  935. self.elems,
  936. Rakudo::Iterator.Roller(self),
  937. Rakudo::Iterator.Empty
  938. ))
  939. )
  940. }
  941. multi method roll(\number) {
  942. number == Inf
  943. ?? self.roll(*)
  944. !! self.is-lazy
  945. ?? X::Cannot::Lazy.new(:action('.roll from')).throw
  946. !! self.elems # this allocates/reifies
  947. ?? Seq.new(class :: does Iterator {
  948. has $!list;
  949. has Int $!elems;
  950. has int $!todo;
  951. method !SET-SELF(\list,\todo) {
  952. $!list := nqp::getattr(list,List,'$!reified');
  953. $!elems = nqp::elems($!list);
  954. $!todo = todo;
  955. self
  956. }
  957. method new(\list,\todo) {
  958. nqp::create(self)!SET-SELF(list,todo)
  959. }
  960. method pull-one() is raw {
  961. if $!todo {
  962. $!todo = $!todo - 1;
  963. nqp::atpos($!list,$!elems.rand.floor)
  964. }
  965. else {
  966. IterationEnd
  967. }
  968. }
  969. }.new(self,number.Int))
  970. !! Seq.new(Rakudo::Iterator.Empty)
  971. }
  972. method reverse() is nodal {
  973. nqp::if(
  974. self.is-lazy, # reifies
  975. Failure.new(X::Cannot::Lazy.new(:action<reverse>)),
  976. Seq.new(nqp::if(
  977. $!reified,
  978. Rakudo::Iterator.ReifiedListReverse($!reified),
  979. Rakudo::Iterator.Empty
  980. ))
  981. )
  982. }
  983. method rotate(Int(Cool) $rotate = 1) is nodal {
  984. nqp::if(
  985. self.is-lazy, # reifies
  986. Failure.new(X::Cannot::Lazy.new(:action<rotate>)),
  987. nqp::if(
  988. $!reified,
  989. Rakudo::Internals.RotateListToList(
  990. self, $rotate,
  991. nqp::p6bindattrinvres(nqp::create(self),List,'$!reified',
  992. nqp::setelems(
  993. nqp::create(IterationBuffer),nqp::elems($!reified)
  994. )
  995. )
  996. ),
  997. nqp::create(self)
  998. )
  999. )
  1000. }
  1001. proto method combinations(|) is nodal {*}
  1002. multi method combinations() {
  1003. nqp::stmts(
  1004. (my int $elems = self.elems), # reifies
  1005. (my int $i = -1),
  1006. Seq.new(
  1007. Rakudo::Iterator.SequentialIterators(
  1008. Rakudo::Iterator.Callable( {
  1009. nqp::if(
  1010. nqp::islt_i(($i = nqp::add_i($i,1)),$elems),
  1011. Rakudo::Iterator.ListIndexes( # basically .combinations($i)
  1012. self,
  1013. Rakudo::Iterator.Combinations($elems, $i, 1)
  1014. ),
  1015. nqp::if(
  1016. nqp::iseq_i($i,$elems),
  1017. Rakudo::Iterator.OneValue( # last one is self
  1018. nqp::p6bindattrinvres( # but must be a (new) List
  1019. nqp::create(List), # so transplant innards
  1020. List,
  1021. '$!reified',
  1022. nqp::getattr(self,List,'$!reified')
  1023. )
  1024. ),
  1025. IterationEnd
  1026. )
  1027. )
  1028. } )
  1029. )
  1030. )
  1031. )
  1032. }
  1033. multi method combinations(Int() $of) {
  1034. Seq.new(
  1035. Rakudo::Iterator.ListIndexes(
  1036. self, Rakudo::Iterator.Combinations( self.elems, $of, 1)
  1037. )
  1038. )
  1039. }
  1040. multi method combinations(Range:D $ofrange) {
  1041. nqp::stmts(
  1042. (my int $elems = self.elems), # reifies
  1043. $ofrange.int-bounds(my int $i, my int $to),
  1044. ($i = nqp::if(nqp::islt_i($i,0),-1,nqp::sub_i($i,1))),
  1045. nqp::if(nqp::isgt_i($to,$elems),($to = $elems)),
  1046. Seq.new(
  1047. Rakudo::Iterator.SequentialIterators(
  1048. Rakudo::Iterator.Callable( {
  1049. nqp::if(
  1050. nqp::isle_i(($i = nqp::add_i($i,1)),$to),
  1051. Rakudo::Iterator.ListIndexes( # basically .combinations($i)
  1052. self,
  1053. Rakudo::Iterator.Combinations($elems, $i, 1)
  1054. ),
  1055. IterationEnd
  1056. )
  1057. } )
  1058. )
  1059. )
  1060. )
  1061. }
  1062. proto method permutations(|) is nodal {*}
  1063. multi method permutations() {
  1064. Seq.new(
  1065. Rakudo::Iterator.ListIndexes(
  1066. self, Rakudo::Iterator.Permutations( self.elems, 1)
  1067. )
  1068. )
  1069. }
  1070. method join(List:D: Str(Cool) $separator = '') is nodal {
  1071. nqp::stmts(
  1072. nqp::if(
  1073. $!todo.DEFINITE,
  1074. nqp::stmts(
  1075. $!todo.reify-until-lazy,
  1076. nqp::if(
  1077. $!todo.fully-reified,
  1078. ($!todo := nqp::null),
  1079. (my int $infinite = 1)
  1080. )
  1081. )
  1082. ),
  1083. nqp::if(
  1084. $!reified.DEFINITE
  1085. && (my int $elems = nqp::elems($!reified)),
  1086. nqp::stmts( # something to join
  1087. (my $strings :=
  1088. nqp::setelems(nqp::list_s,nqp::add_i($elems,$infinite))),
  1089. (my int $i = -1),
  1090. nqp::while(
  1091. nqp::islt_i(($i = nqp::add_i($i,1)),$elems),
  1092. nqp::bindpos_s($strings,$i,nqp::if(
  1093. nqp::isnull(my $tmp := nqp::atpos($!reified,$i)),
  1094. '',
  1095. nqp::if(
  1096. nqp::isconcrete($tmp) && nqp::istype($tmp,Str),
  1097. $tmp,
  1098. nqp::if(
  1099. nqp::can($tmp,'Str'),
  1100. $tmp.Str,
  1101. nqp::box_s($tmp,Str)
  1102. )
  1103. )
  1104. ))
  1105. ),
  1106. nqp::if($infinite,nqp::bindpos_s($strings,$i,'...')),
  1107. nqp::p6box_s(nqp::join($separator,$strings))
  1108. ),
  1109. nqp::if($infinite,'...','')
  1110. )
  1111. )
  1112. }
  1113. # https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation
  1114. multi method sort(List:D:) {
  1115. nqp::stmts(
  1116. nqp::if(
  1117. $!todo.DEFINITE,
  1118. nqp::stmts(
  1119. $!todo.reify-until-lazy,
  1120. nqp::if(
  1121. $!todo.fully-reified,
  1122. ($!todo := nqp::null),
  1123. X::Cannot::Lazy.new(:action('.sort')).throw
  1124. )
  1125. )
  1126. ),
  1127. Seq.new(
  1128. nqp::if(
  1129. $!reified.DEFINITE,
  1130. Rakudo::Iterator.ReifiedList(
  1131. Rakudo::Internals.MERGESORT-REIFIED-LIST(
  1132. nqp::p6bindattrinvres(
  1133. nqp::create(List),List,'$!reified',
  1134. nqp::clone(nqp::getattr(self,List,'$!reified'))
  1135. )
  1136. )
  1137. ),
  1138. Rakudo::Iterator.Empty
  1139. )
  1140. )
  1141. )
  1142. }
  1143. multi method sort(List:D: &by) {
  1144. nqp::stmts(
  1145. nqp::if(
  1146. $!todo.DEFINITE,
  1147. nqp::stmts(
  1148. $!todo.reify-until-lazy,
  1149. nqp::if(
  1150. $!todo.fully-reified,
  1151. ($!todo := nqp::null),
  1152. X::Cannot::Lazy.new(:action('.sort')).throw
  1153. )
  1154. )
  1155. ),
  1156. Seq.new(
  1157. nqp::if(
  1158. $!reified.DEFINITE,
  1159. Rakudo::Iterator.ReifiedList(
  1160. nqp::if(
  1161. nqp::eqaddr(&by,&infix:<cmp>),
  1162. Rakudo::Internals.MERGESORT-REIFIED-LIST(
  1163. nqp::p6bindattrinvres(nqp::create(List),List,'$!reified',
  1164. nqp::clone(nqp::getattr(self,List,'$!reified')))
  1165. ),
  1166. nqp::if(
  1167. &by.count < 2,
  1168. Rakudo::Internals.MERGESORT-REIFIED-LIST-AS(
  1169. nqp::p6bindattrinvres(nqp::create(List),List,'$!reified',
  1170. nqp::getattr(self,List,'$!reified')),
  1171. &by
  1172. ),
  1173. Rakudo::Internals.MERGESORT-REIFIED-LIST-WITH(
  1174. nqp::p6bindattrinvres(nqp::create(List),List,'$!reified',
  1175. nqp::clone(nqp::getattr(self,List,'$!reified'))),
  1176. &by
  1177. )
  1178. )
  1179. )
  1180. ),
  1181. Rakudo::Iterator.Empty
  1182. )
  1183. )
  1184. )
  1185. }
  1186. method collate {
  1187. self.sort(&[coll]);
  1188. }
  1189. multi method tail(List:D:) is raw {
  1190. nqp::if(
  1191. $!todo.DEFINITE,
  1192. self.Any::tail,
  1193. nqp::if(
  1194. $!reified.DEFINITE && nqp::elems($!reified),
  1195. nqp::atpos($!reified,nqp::sub_i(nqp::elems($!reified),1)),
  1196. Nil
  1197. )
  1198. )
  1199. }
  1200. multi method tail(List:D: $n) {
  1201. nqp::if(
  1202. $!todo.DEFINITE,
  1203. self.Any::tail($n),
  1204. Seq.new(
  1205. nqp::if(
  1206. $!reified.DEFINITE && nqp::elems($!reified),
  1207. nqp::stmts(
  1208. (my $iterator :=
  1209. Rakudo::Iterator.ReifiedList(self))
  1210. .skip-at-least(nqp::elems($!reified) - $n),
  1211. $iterator
  1212. ),
  1213. Rakudo::Iterator.Empty
  1214. )
  1215. )
  1216. )
  1217. }
  1218. method push(|) is nodal {
  1219. X::Immutable.new(:typename<List>,:method<push>).throw
  1220. }
  1221. method append(|) is nodal {
  1222. X::Immutable.new(:typename<List>,:method<append>).throw
  1223. }
  1224. method unshift(|) is nodal {
  1225. X::Immutable.new(:typename<List>,:method<unshift>).throw
  1226. }
  1227. method prepend(|) is nodal {
  1228. X::Immutable.new(:typename<List>,:method<prepend>).throw
  1229. }
  1230. method shift(|) is nodal {
  1231. X::Immutable.new(:typename<List>,:method<shift>).throw
  1232. }
  1233. method pop(|) is nodal {
  1234. X::Immutable.new(:typename<List>, :method<pop>).throw
  1235. }
  1236. }
  1237. # The , operator produces a List.
  1238. proto sub infix:<,>(|) is pure {*}
  1239. multi sub infix:<,>() { nqp::create(List) }
  1240. multi sub infix:<,>(|) {
  1241. # look for a Slip in the parameters
  1242. my \in := nqp::p6argvmarray();
  1243. my int $i = -1;
  1244. my int $elems = nqp::elems(in);
  1245. nqp::while(
  1246. (nqp::islt_i(($i = nqp::add_i($i,1)),$elems)
  1247. && nqp::not_i(nqp::istype(nqp::atpos(in,$i),Slip))),
  1248. nqp::null
  1249. );
  1250. nqp::if(
  1251. nqp::iseq_i($i,$elems), # no Slip seen, so just alias input params
  1252. nqp::p6bindattrinvres(nqp::create(List),List,'$!reified',in),
  1253. nqp::stmts( # Slip seen, first copy non-slippy things
  1254. ($elems = $i),
  1255. ($i = -1),
  1256. (my $reified := nqp::setelems(nqp::create(IterationBuffer),$elems)),
  1257. nqp::while(
  1258. nqp::islt_i(($i = nqp::add_i($i,1)),$elems),
  1259. nqp::bindpos($reified,$i,nqp::shift(in))
  1260. ),
  1261. # now set up the List with a future
  1262. (my $list :=
  1263. nqp::p6bindattrinvres(nqp::create(List),List,'$!reified',$reified)),
  1264. nqp::bindattr($list,List,'$!todo',
  1265. my $todo:= nqp::create(List::Reifier)),
  1266. nqp::bindattr($todo,List::Reifier,'$!reified',$reified),
  1267. nqp::bindattr($todo,List::Reifier,'$!future',in),
  1268. nqp::bindattr($todo,List::Reifier,'$!reification-target',$reified),
  1269. $list
  1270. )
  1271. )
  1272. }
  1273. sub combinations(Int() $n, Int() $k) {
  1274. Seq.new(Rakudo::Iterator.Combinations($n,$k,0))
  1275. }
  1276. sub permutations(Int() $n) {
  1277. Seq.new(Rakudo::Iterator.Permutations($n,0))
  1278. }
  1279. sub list(+l) { l }
  1280. # Use **@list and then .flat it, otherwise we'll end up remembering all the
  1281. # things we flatten, which would be different semantics to .flat which gives
  1282. # back a Seq. We also add an Iterable candidate, to preserve .is-lazy
  1283. # of an Iterable whenever we can.
  1284. proto flat(|) {*}
  1285. multi flat(**@list is raw) { @list.flat }
  1286. multi flat(Iterable \a) { a.flat }
  1287. sub cache(+@l) { @l }
  1288. proto sub infix:<xx>(|) { * }
  1289. multi sub infix:<xx>() { Failure.new("No zero-arg meaning for infix:<xx>") }
  1290. multi sub infix:<xx>(Mu \x) { x }
  1291. multi sub infix:<xx>(&x, Num() $n) {
  1292. infix:<xx>(&x, $n == Inf ?? Whatever !! $n.Int);
  1293. }
  1294. multi sub infix:<xx>(&x, Whatever) {
  1295. Seq.new(Rakudo::Iterator.Callable-xx-Whatever(&x))
  1296. }
  1297. multi sub infix:<xx>(&x, Int $n) {
  1298. my int $todo = $n + 1;
  1299. my Mu $pulled;
  1300. my Mu $list := nqp::create(IterationBuffer);
  1301. nqp::while(
  1302. nqp::isgt_i($todo = nqp::sub_i($todo,1),0),
  1303. nqp::if(
  1304. nqp::istype(($pulled := &x.()),Slip),
  1305. (nqp::push($list,$_) for $pulled),
  1306. nqp::if(
  1307. nqp::istype($pulled,Seq),
  1308. nqp::push($list,$pulled.cache),
  1309. nqp::push($list,nqp::decont($pulled))
  1310. )
  1311. )
  1312. );
  1313. Seq.new(Rakudo::Iterator.ReifiedList($list))
  1314. }
  1315. multi sub infix:<xx>(Mu \x, Num() $n) {
  1316. Seq.new(nqp::if(
  1317. $n == Inf,
  1318. Rakudo::Iterator.UnendingValue(x),
  1319. Rakudo::Iterator.OneValueTimes(x,$n.Int)
  1320. ))
  1321. }
  1322. multi sub infix:<xx>(Mu \x, Whatever) {
  1323. Seq.new(Rakudo::Iterator.UnendingValue(x))
  1324. }
  1325. multi sub infix:<xx>(Mu \x, Int:D $n) is pure {
  1326. Seq.new(Rakudo::Iterator.OneValueTimes(x,$n))
  1327. }
  1328. proto sub reverse(|) { * }
  1329. multi sub reverse(@a) { @a.reverse }
  1330. multi sub reverse(+@a) { @a.reverse }
  1331. sub rotate(@a, Int $n = 1) { @a.rotate($n) }
  1332. sub prefix:<|>(\x) { x.Slip }
  1333. multi sub infix:<cmp>(@a, @b) {
  1334. (@a Zcmp @b).first(&prefix:<?>) || @a <=> @b
  1335. }
  1336. proto sub infix:<X>(|) is pure {*}
  1337. multi sub infix:<X>(+lol, :&with!) {
  1338. Seq.new(Rakudo::Iterator.CrossIterablesOp(lol,&with))
  1339. }
  1340. multi sub infix:<X>(+lol) {
  1341. Seq.new(Rakudo::Iterator.CrossIterablesOp(lol,&infix:<,>))
  1342. }
  1343. my constant &cross := &infix:<X>;
  1344. proto sub infix:<Z>(|) is pure {*}
  1345. multi sub infix:<Z>(+lol, :&with!) {
  1346. Seq.new(Rakudo::Iterator.ZipIterablesOp(lol,&with))
  1347. }
  1348. multi sub infix:<Z>(+lol) {
  1349. Seq.new(Rakudo::Iterator.ZipIterables(lol))
  1350. }
  1351. my constant &zip := &infix:<Z>;
  1352. sub roundrobin(+lol) {
  1353. Seq.new(Rakudo::Iterator.RoundrobinIterables(lol))
  1354. }