diff --git a/src/core.c/Rakudo/Sorting.pm6 b/src/core.c/Rakudo/Sorting.pm6 index bf167b5f1de..24703c9ffa2 100644 --- a/src/core.c/Rakudo/Sorting.pm6 +++ b/src/core.c/Rakudo/Sorting.pm6 @@ -377,6 +377,9 @@ my class Rakudo::Sorting { ) ) } +#- start of generated part of sorting strarray logic -------------------------- +#- Generated on 2022-02-17T16:35:04+01:00 by ./tools/build/makeNATIVE_SORTING.raku +#- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE # https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation # Sort a native str array (or nqp::list_s) and return the result. @@ -430,11 +433,11 @@ my class Rakudo::Sorting { ) ), nqp::stmts( - (nqp::bindpos_s($B,$k,nqp::atpos_s($A,$i))), + nqp::bindpos_s($B,$k,nqp::atpos_s($A,$i)), ++$i ), nqp::stmts( - (nqp::bindpos_s($B,$k,nqp::atpos_s($A,$j))), + nqp::bindpos_s($B,$k,nqp::atpos_s($A,$j)), ++$j ) ) @@ -465,6 +468,12 @@ my class Rakudo::Sorting { ) ) } +#- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE +#- end of generated part of sorting strarray logic ---------------------------- + +#- start of generated part of sorting intarray logic -------------------------- +#- Generated on 2022-02-17T16:35:04+01:00 by ./tools/build/makeNATIVE_SORTING.raku +#- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE # https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation # Sort a native int array (or nqp::list_i) and return the result. @@ -518,11 +527,11 @@ my class Rakudo::Sorting { ) ), nqp::stmts( - (nqp::bindpos_i($B,$k,nqp::atpos_i($A,$i))), + nqp::bindpos_i($B,$k,nqp::atpos_i($A,$i)), ++$i ), nqp::stmts( - (nqp::bindpos_i($B,$k,nqp::atpos_i($A,$j))), + nqp::bindpos_i($B,$k,nqp::atpos_i($A,$j)), ++$j ) ) @@ -553,6 +562,12 @@ my class Rakudo::Sorting { ) ) } +#- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE +#- end of generated part of sorting intarray logic ---------------------------- + +#- start of generated part of sorting uintarray logic -------------------------- +#- Generated on 2022-02-17T16:35:04+01:00 by ./tools/build/makeNATIVE_SORTING.raku +#- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE # https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation # Sort a native uint array (or nqp::list_i) and return the result. @@ -641,6 +656,12 @@ my class Rakudo::Sorting { ) ) } +#- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE +#- end of generated part of sorting uintarray logic ---------------------------- + +#- start of generated part of sorting numarray logic -------------------------- +#- Generated on 2022-02-17T16:35:04+01:00 by ./tools/build/makeNATIVE_SORTING.raku +#- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE # https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation # Sort a native num array (or nqp::list_n) and return the result. @@ -694,11 +715,11 @@ my class Rakudo::Sorting { ) ), nqp::stmts( - (nqp::bindpos_n($B,$k,nqp::atpos_n($A,$i))), + nqp::bindpos_n($B,$k,nqp::atpos_n($A,$i)), ++$i ), nqp::stmts( - (nqp::bindpos_n($B,$k,nqp::atpos_n($A,$j))), + nqp::bindpos_n($B,$k,nqp::atpos_n($A,$j)), ++$j ) ) @@ -729,6 +750,8 @@ my class Rakudo::Sorting { ) ) } +#- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE +#- end of generated part of sorting numarray logic ---------------------------- } # vim: expandtab shiftwidth=4 diff --git a/tools/build/makeNATIVE_SORTING.raku b/tools/build/makeNATIVE_SORTING.raku new file mode 100755 index 00000000000..dca71f91e42 --- /dev/null +++ b/tools/build/makeNATIVE_SORTING.raku @@ -0,0 +1,166 @@ +#!/usr/bin/env raku + +# This script reads the Rakudo/Sorting.pm6 file, generates the +# logic to sort a native str, int, uint num array in place, and +# writes it back to the file. + +# always use highest version of Raku +use v6.*; + +my $generator = $*PROGRAM-NAME; +my $generated = DateTime.now.gist.subst(/\.\d+/,''); +my $start = '#- start of generated part of sorting '; +my $idpos = $start.chars; +my $idchars = 3; +my $end = '#- end of generated part of sorting '; + +# slurp the whole file and set up writing to it +my $filename = "src/core.c/Rakudo/Sorting.pm6"; +my @lines = $filename.IO.lines; +$*OUT = $filename.IO.open(:w); + +my %type_mapper = ( + int => ( :base_postfix, + :postfix, + :type, + ).Map, + num => ( :base_postfix, + :postfix, + :type, + ).Map, + str => ( :base_postfix, + :postfix, + :type, + ).Map, + uint => ( :base_postfix, + :postfix, + :type, + ).Map, +); + + +# for all the lines in the source that don't need special handling +while @lines { + my $line := @lines.shift; + + # nothing to do yet + unless $line.starts-with($start) { + say $line; + next; + } + + # found header, check validity and set up mapper + my $type = $line.substr($idpos,$idchars); + $type = "uint" if $type eq "uin"; + die "Don't know how to handle $type" + unless my %mapper := %type_mapper{$type}; + + say $start ~ $type ~ "array logic --------------------------"; + say "#- Generated on $generated by $generator"; + say "#- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE"; + + # skip the old version of the code + while @lines { + last if @lines.shift.starts-with($end); + } + # spurt the code + say Q:to/SOURCE/.subst(/ '#' (\w+) '#' /, -> $/ { %mapper{$0} }, :g).chomp; + + # https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation + # Sort a native #type# array (or nqp::list_#base_postfix#) and return the result. + # Uses the given #type# array as one of the buffers for performance reasons. + # Please nqp::clone first if you want to keep the original intact. + method MERGESORT-#type#(Mu \sortable) { + nqp::if( + nqp::isgt_i((my int $n = nqp::elems(sortable)),2), + + # $A has the items to sort; $B is a work array + nqp::stmts( + (my Mu $A := sortable), + (my Mu $B := nqp::setelems(nqp::create(nqp::what(sortable)),$n)), + + # Each 1-element run in $A is already "sorted" + # Make successively longer sorted runs of length 2, 4, 8, 16... + # until $A is wholly sorted + (my int $width = 1), + nqp::while( + nqp::islt_i($width,$n), + nqp::stmts( + (my int $l = 0), + + # $A is full of runs of length $width + nqp::while( + nqp::islt_i($l,$n), + + nqp::stmts( + (my int $left = $l), + (my int $right = nqp::add_i($l,$width)), + nqp::if(nqp::isge_i($right,$n),($right = $n)), + (my int $end = + nqp::add_i($l,nqp::add_i($width,$width))), + nqp::if(nqp::isge_i($end,$n),($end = $n)), + + (my int $i = $left), + (my int $j = $right), + (my int $k = nqp::sub_i($left,1)), + + # Merge two runs: $A[i .. i+width-1] and + # $A[i+width .. i+2*width-1] + # to $B or copy $A[i..n-1] to $B[] ( if(i+width >= n) ) + nqp::while( + nqp::islt_i(++$k,$end), + nqp::if( + nqp::islt_i($i,$right) && ( + nqp::isge_i($j,$end) + || nqp::islt_#base_postfix#( + nqp::atpos_#postfix#($A,$i), + nqp::atpos_#postfix#($A,$j) + ) + ), + nqp::stmts( + nqp::bindpos_#postfix#($B,$k,nqp::atpos_#postfix#($A,$i)), + ++$i + ), + nqp::stmts( + nqp::bindpos_#postfix#($B,$k,nqp::atpos_#postfix#($A,$j)), + ++$j + ) + ) + ), + ($l = nqp::add_i($l,nqp::add_i($width,$width))) + ) + ), + + # Now work array $B is full of runs of length 2*width. + # Copy array B to array A for next iteration. A more + # efficient implementation would swap the roles of A and B. + (my Mu $temp := $B),($B := $A),($A := $temp), # swap + # Now array $A is full of runs of length 2*width. + + ($width = nqp::add_i($width,$width)) + ) + ), + $A + ), + nqp::stmts( # 2 elements or less + (my \result := nqp::clone(sortable)), + nqp::unless( + nqp::islt_i($n,2) + || nqp::isle_#base_postfix#(nqp::atpos_#postfix#(result,0),nqp::atpos_#postfix#(result,1)), + nqp::push_#base_postfix#(result,nqp::shift_#base_postfix#(result)) + ), + result + ) + ) + } +SOURCE + + # we're done for this role + say "#- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE"; + say $end ~ $type ~ "array logic ----------------------------"; +} + +# close the file properly +$*OUT.close; + +# vim: expandtab sw=4