# Copyright (c) 2023 Yuki Kimoto
# MIT License
class Sort {
use Comparator::Int;
use Comparator::Long;
use Comparator::Float;
use Comparator::Double;
use Comparator::String;
use Comparator;
use Fn;
use Array;
static method sort_byte : void ($array : byte[], $comparator : Comparator::Int, $offset = 0 : int, $length = -1 : int) {
unless ($array) {
die "The \$array must be defined";
}
unless ($comparator) {
die "The \$comparator must be defined";
}
unless ($offset >= 0) {
die "The \$offset must be greater than or equal to 0";
}
my $array_length = @$array;
if ($length < 0) {
$length = $array_length - $offset;
}
unless ($offset + $length <= $array_length) {
die "The \$offset + the \$length must be less than or equal to the length of the \$array";
}
if ($length == 0) {
return;
}
my $b = new byte[$length];
Sort->_sort_byte_merge_sort($array, $b, $offset, $offset + $length - 1, $length - 1, $comparator);
}
static method sort_byte_asc : void ($array : byte[], $offset = 0 : int, $length = -1 : int) {
&sort_byte($array, method : int ($a : int, $b : int) { return $a <=> $b; }, $offset, $length);
}
static method sort_byte_desc : void ($array : byte[], $offset = 0 : int, $length = -1 : int) {
&sort_byte($array, method : int ($a : int, $b : int) { return $b <=> $a; }, $offset, $length);
}
static method sort_double : void ($array : double[], $comparator : Comparator::Double, $offset = 0 : int, $length = -1 : int) {
unless ($array) {
die "The \$array must be defined";
}
unless ($comparator) {
die "The \$comparator must be defined";
}
unless ($offset >= 0) {
die "The \$offset must be greater than or equal to 0";
}
my $array_length = @$array;
if ($length < 0) {
$length = $array_length - $offset;
}
unless ($offset + $length <= $array_length) {
die "The \$offset + the \$length must be less than or equal to the length of the \$array";
}
if ($length == 0) {
return;
}
my $b = new double[$length];
Sort->_sort_double_merge_sort($array, $b, $offset, $offset + $length - 1, $length - 1, $comparator);
}
static method sort_double_asc : void ($array : double[], $offset = 0 : int, $length = -1 : int) {
&sort_double($array, method : int ($a : double, $b : double) { return $a <=> $b; }, $offset, $length);
}
static method sort_double_desc : void ($array : double[], $offset = 0 : int, $length = -1 : int) {
&sort_double($array, method : int ($a : double, $b : double) { return $b <=> $a; }, $offset, $length);
}
static method sort_float : void ($array : float[], $comparator : Comparator::Float, $offset = 0 : int, $length = -1 : int) {
unless ($array) {
die "The \$array must be defined";
}
unless ($comparator) {
die "The \$comparator must be defined";
}
unless ($offset >= 0) {
die "The \$offset must be greater than or equal to 0";
}
my $array_length = @$array;
if ($length < 0) {
$length = $array_length - $offset;
}
unless ($offset + $length <= $array_length) {
die "The \$offset + the \$length must be less than or equal to the length of the \$array";
}
if ($length == 0) {
return;
}
my $b = new float[$length];
Sort->_sort_float_merge_sort($array, $b, $offset, $offset + $length - 1, $length - 1, $comparator);
}
static method sort_float_asc : void ($array : float[], $offset = 0 : int, $length = -1 : int) {
&sort_float($array, method : int ($a : float, $b : float) { return $a <=> $b; }, $offset, $length);
}
static method sort_float_desc : void ($array : float[], $offset = 0 : int, $length = -1 : int) {
&sort_float($array, method : int ($a : float, $b : float) { return $b <=> $a; }, $offset, $length);
}
static method sort_int : void ($array : int[], $comparator : Comparator::Int, $offset = 0 : int, $length = -1 : int) {
unless ($array) {
die "The \$array must be defined";
}
unless ($comparator) {
die "The \$comparator must be defined";
}
unless ($offset >= 0) {
die "The \$offset must be greater than or equal to 0";
}
my $array_length = @$array;
if ($length < 0) {
$length = $array_length - $offset;
}
unless ($offset + $length <= $array_length) {
die "The \$offset + the \$length must be less than or equal to the length of the \$array";
}
if ($length == 0) {
return;
}
my $b = new int[$length];
Sort->_sort_int_merge_sort($array, $b, $offset, $offset + $length - 1, $length - 1, $comparator);
}
static method sort_int_asc : void ($array : int[], $offset = 0 : int, $length = -1 : int) {
&sort_int($array, method : int ($a : int, $b : int) { return $a <=> $b; }, $offset, $length);
}
static method sort_int_desc : void ($array : int[], $offset = 0 : int, $length = -1 : int) {
&sort_int($array, method : int ($a : int, $b : int) { return $b <=> $a; }, $offset, $length);
}
static method sort_long : void ($array : long[], $comparator : Comparator::Long, $offset = 0 : int, $length = -1 : int) {
unless ($array) {
die "The \$array must be defined";
}
unless ($comparator) {
die "The \$comparator must be defined";
}
unless ($offset >= 0) {
die "The \$offset must be greater than or equal to 0";
}
my $array_length = @$array;
if ($length < 0) {
$length = $array_length - $offset;
}
unless ($offset + $length <= $array_length) {
die "The \$offset + the \$length must be less than or equal to the length of the \$array";
}
if ($length == 0) {
return;
}
my $b = new long[$length];
Sort->_sort_long_merge_sort($array, $b, $offset, $offset + $length - 1, $length - 1, $comparator);
}
static method sort_long_asc : void ($array : long[], $offset = 0 : int, $length = -1 : int) {
&sort_long($array, method : int ($a : long, $b : long) { return $a <=> $b; }, $offset, $length);
}
static method sort_long_desc : void ($array : long[], $offset = 0 : int, $length = -1 : int) {
&sort_long($array, method : int ($a : long, $b : long) { return $b <=> $a; }, $offset, $length);
}
static method sort_object : void ($array : object[], $comparator : Comparator, $offset = 0 : int, $length = -1 : int) {
unless ($array) {
die "The \$array must be defined";
}
unless ($comparator) {
die "The \$comparator must be defined";
}
unless ($offset >= 0) {
die "The \$offset must be greater than or equal to 0";
}
my $array_length = @$array;
if ($length < 0) {
$length = $array_length - $offset;
}
unless ($offset + $length <= $array_length) {
die "The \$offset + the \$length must be less than or equal to the length of the \$array";
}
if ($length == 0) {
return;
}
my $b = Array->new_proto($array, $length);
Sort->_sort_object_merge_sort($array, $b, $offset, $offset + $length - 1, $length - 1, $comparator);
}
static method sort_short : void ($array : short[], $comparator : Comparator::Int, $offset = 0 : int, $length = -1 : int) {
unless ($array) {
die "The \$array must be defined";
}
unless ($comparator) {
die "The \$comparator must be defined";
}
unless ($offset >= 0) {
die "The \$offset must be greater than or equal to 0";
}
my $array_length = @$array;
if ($length < 0) {
$length = $array_length - $offset;
}
unless ($offset + $length <= $array_length) {
die "The \$offset + the \$length must be less than or equal to the length of the \$array";
}
if ($length == 0) {
return;
}
my $b = new short[$length];
Sort->_sort_short_merge_sort($array, $b, $offset, $offset + $length - 1, $length - 1, $comparator);
}
static method sort_short_asc : void ($array : short[], $offset = 0 : int, $length = -1 : int) {
&sort_short($array, method : int ($a : int, $b : int) { return $a <=> $b; }, $offset, $length);
}
static method sort_short_desc : void ($array : short[], $offset = 0 : int, $length = -1 : int) {
&sort_short($array, method : int ($a : int, $b : int) { return $b <=> $a; }, $offset, $length);
}
static method sort_string : void ($array : string[], $comparator : Comparator::String, $offset = 0 : int, $length = -1 : int) {
unless ($array) {
die "The \$array must be defined";
}
unless ($comparator) {
die "The \$comparator must be defined";
}
unless ($offset >= 0) {
die "The \$offset must be greater than or equal to 0";
}
my $array_length = @$array;
if ($length < 0) {
$length = $array_length - $offset;
}
unless ($offset + $length <= $array_length) {
die "The \$offset + the \$length must be less than or equal to the length of the \$array";
}
if ($length == 0) {
return;
}
my $b = new string[$length];
Sort->_sort_string_merge_sort($array, $b, $offset, $offset + $length - 1, $length - 1, $comparator);
}
static method sort_string_asc : void ($array : string[], $offset = 0 : int, $length = -1 : int) {
&sort_string($array, method : int ($a : string, $b : string) { return $a cmp $b; }, $offset, $length);
}
static method sort_string_desc : void ($array : string[], $offset = 0 : int, $length = -1 : int) {
&sort_string($array, method : int ($a : string, $b : string) { return $b cmp $a; }, $offset, $length);
}
precompile private static method _sort_byte_merge : void($a : byte[], $b : byte[], $left : int, $mid : int, $right : int, $n : int, $comparator : Comparator::Int) {
my $i = $left;
my $j = $mid + 1;
my $k = 0;
while ($i <= $mid && $j <= $right) {
$i = $left;
$j = $mid + 1;
$k = 0;
while ($i <= $mid && $j <= $right) {
if ($comparator->($a->[$i], $a->[$j]) <= 0) {
$b->[$k] = $a->[$i];
$i++;
} else {
$b->[$k] = $a->[$j];
$j++;
}
$k++;
}
if ($i == $mid + 1) {
while ($j <= $right) {
$b->[$k] = $a->[$j];
$j++;
$k++;
}
} else {
while($i <= $mid) {
$b->[$k] = $a->[$i];
$i++;
$k++;
}
}
}
for ($i = 0; $i < $k; $i++) {
$a->[$i + $left] = $b->[$i];
}
}
private static method _sort_byte_merge_sort : void($a : byte[], $b : byte[], $left : int, $right : int, $n : int, $comparator : Comparator::Int){
if ($left >= $right) {
return;
}
my $mid = ($left + $right) / 2;
Sort->_sort_byte_merge_sort($a, $b, $left, $mid, $n, $comparator);
Sort->_sort_byte_merge_sort($a, $b, $mid + 1, $right, $n, $comparator);
Sort->_sort_byte_merge($a, $b, $left, $mid, $right, $n, $comparator);
}
precompile private static method _sort_double_merge : void($a : double[], $b : double[], $left : int, $mid : int, $right : int, $n : int, $comparator : Comparator::Double) {
my $i = $left;
my $j = $mid + 1;
my $k = 0;
while ($i <= $mid && $j <= $right) {
$i = $left;
$j = $mid + 1;
$k = 0;
while ($i <= $mid && $j <= $right) {
if ($comparator->($a->[$i], $a->[$j]) <= 0) {
$b->[$k] = $a->[$i];
$i++;
} else {
$b->[$k] = $a->[$j];
$j++;
}
$k++;
}
if ($i == $mid + 1) {
while ($j <= $right) {
$b->[$k] = $a->[$j];
$j++;
$k++;
}
} else {
while($i <= $mid) {
$b->[$k] = $a->[$i];
$i++;
$k++;
}
}
}
for ($i = 0; $i < $k; $i++) {
$a->[$i + $left] = $b->[$i];
}
}
private static method _sort_double_merge_sort : void($a : double[], $b : double[], $left : int, $right : int, $n : int, $comparator : Comparator::Double){
if ($left >= $right) {
return;
}
my $mid = ($left + $right) / 2;
Sort->_sort_double_merge_sort($a, $b, $left, $mid, $n, $comparator);
Sort->_sort_double_merge_sort($a, $b, $mid + 1, $right, $n, $comparator);
Sort->_sort_double_merge($a, $b, $left, $mid, $right, $n, $comparator);
}
precompile private static method _sort_float_merge : void($a : float[], $b : float[], $left : int, $mid : int, $right : int, $n : int, $comparator : Comparator::Float) {
my $i = $left;
my $j = $mid + 1;
my $k = 0;
while ($i <= $mid && $j <= $right) {
$i = $left;
$j = $mid + 1;
$k = 0;
while ($i <= $mid && $j <= $right) {
if ($comparator->($a->[$i], $a->[$j]) <= 0) {
$b->[$k] = $a->[$i];
$i++;
} else {
$b->[$k] = $a->[$j];
$j++;
}
$k++;
}
if ($i == $mid + 1) {
while ($j <= $right) {
$b->[$k] = $a->[$j];
$j++;
$k++;
}
} else {
while($i <= $mid) {
$b->[$k] = $a->[$i];
$i++;
$k++;
}
}
}
for ($i = 0; $i < $k; $i++) {
$a->[$i + $left] = $b->[$i];
}
}
private static method _sort_float_merge_sort : void($a : float[], $b : float[], $left : int, $right : int, $n : int, $comparator : Comparator::Float){
if ($left >= $right) {
return;
}
my $mid = ($left + $right) / 2;
Sort->_sort_float_merge_sort($a, $b, $left, $mid, $n, $comparator);
Sort->_sort_float_merge_sort($a, $b, $mid + 1, $right, $n, $comparator);
Sort->_sort_float_merge($a, $b, $left, $mid, $right, $n, $comparator);
}
precompile private static method _sort_int_merge : void($a : int[], $b : int[], $left : int, $mid : int, $right : int, $n : int, $comparator : Comparator::Int) {
my $i = $left;
my $j = $mid + 1;
my $k = 0;
while ($i <= $mid && $j <= $right) {
$i = $left;
$j = $mid + 1;
$k = 0;
while ($i <= $mid && $j <= $right) {
if ($comparator->($a->[$i], $a->[$j]) <= 0) {
$b->[$k] = $a->[$i];
$i++;
} else {
$b->[$k] = $a->[$j];
$j++;
}
$k++;
}
if ($i == $mid + 1) {
while ($j <= $right) {
$b->[$k] = $a->[$j];
$j++;
$k++;
}
} else {
while($i <= $mid) {
$b->[$k] = $a->[$i];
$i++;
$k++;
}
}
}
for ($i = 0; $i < $k; $i++) {
$a->[$i + $left] = $b->[$i];
}
}
private static method _sort_int_merge_sort : void($a : int[], $b : int[], $left : int, $right : int, $n : int, $comparator : Comparator::Int){
if ($left >= $right) {
return;
}
my $mid = ($left + $right) / 2;
Sort->_sort_int_merge_sort($a, $b, $left, $mid, $n, $comparator);
Sort->_sort_int_merge_sort($a, $b, $mid + 1, $right, $n, $comparator);
Sort->_sort_int_merge($a, $b, $left, $mid, $right, $n, $comparator);
}
precompile private static method _sort_long_merge : void($a : long[], $b : long[], $left : int, $mid : int, $right : int, $n : int, $comparator : Comparator::Long) {
my $i = $left;
my $j = $mid + 1;
my $k = 0;
while ($i <= $mid && $j <= $right) {
$i = $left;
$j = $mid + 1;
$k = 0;
while ($i <= $mid && $j <= $right) {
if ($comparator->($a->[$i], $a->[$j]) <= 0) {
$b->[$k] = $a->[$i];
$i++;
} else {
$b->[$k] = $a->[$j];
$j++;
}
$k++;
}
if ($i == $mid + 1) {
while ($j <= $right) {
$b->[$k] = $a->[$j];
$j++;
$k++;
}
} else {
while($i <= $mid) {
$b->[$k] = $a->[$i];
$i++;
$k++;
}
}
}
for ($i = 0; $i < $k; $i++) {
$a->[$i + $left] = $b->[$i];
}
}
private static method _sort_long_merge_sort : void($a : long[], $b : long[], $left : int, $right : int, $n : int, $comparator : Comparator::Long){
if ($left >= $right) {
return;
}
my $mid = ($left + $right) / 2;
Sort->_sort_long_merge_sort($a, $b, $left, $mid, $n, $comparator);
Sort->_sort_long_merge_sort($a, $b, $mid + 1, $right, $n, $comparator);
Sort->_sort_long_merge($a, $b, $left, $mid, $right, $n, $comparator);
}
precompile private static method _sort_object_merge : void($a : object[], $b : object[], $left : int, $mid : int, $right : int, $n : int, $comparator : Comparator) {
my $i = $left;
my $j = $mid + 1;
my $k = 0;
while ($i <= $mid && $j <= $right) {
$i = $left;
$j = $mid + 1;
$k = 0;
while ($i <= $mid && $j <= $right) {
if ($comparator->($a->[$i], $a->[$j]) <= 0) {
$b->[$k] = $a->[$i];
$i++;
} else {
$b->[$k] = $a->[$j];
$j++;
}
$k++;
}
if ($i == $mid + 1) {
while ($j <= $right) {
$b->[$k] = $a->[$j];
$j++;
$k++;
}
} else {
while($i <= $mid) {
$b->[$k] = $a->[$i];
$i++;
$k++;
}
}
}
for ($i = 0; $i < $k; $i++) {
$a->[$i + $left] = $b->[$i];
}
}
private static method _sort_object_merge_sort : void($a : object[], $b : object[], $left : int, $right : int, $n : int, $comparator : Comparator){
if ($left >= $right) {
return;
}
my $mid = ($left + $right) / 2;
Sort->_sort_object_merge_sort($a, $b, $left, $mid, $n, $comparator);
Sort->_sort_object_merge_sort($a, $b, $mid + 1, $right, $n, $comparator);
Sort->_sort_object_merge($a, $b, $left, $mid, $right, $n, $comparator);
}
precompile private static method _sort_short_merge : void($a : short[], $b : short[], $left : int, $mid : int, $right : int, $n : int, $comparator : Comparator::Int) {
my $i = $left;
my $j = $mid + 1;
my $k = 0;
while ($i <= $mid && $j <= $right) {
$i = $left;
$j = $mid + 1;
$k = 0;
while ($i <= $mid && $j <= $right) {
if ($comparator->($a->[$i], $a->[$j]) <= 0) {
$b->[$k] = $a->[$i];
$i++;
} else {
$b->[$k] = $a->[$j];
$j++;
}
$k++;
}
if ($i == $mid + 1) {
while ($j <= $right) {
$b->[$k] = $a->[$j];
$j++;
$k++;
}
} else {
while($i <= $mid) {
$b->[$k] = $a->[$i];
$i++;
$k++;
}
}
}
for ($i = 0; $i < $k; $i++) {
$a->[$i + $left] = $b->[$i];
}
}
private static method _sort_short_merge_sort : void($a : short[], $b : short[], $left : int, $right : int, $n : int, $comparator : Comparator::Int){
if ($left >= $right) {
return;
}
my $mid = ($left + $right) / 2;
Sort->_sort_short_merge_sort($a, $b, $left, $mid, $n, $comparator);
Sort->_sort_short_merge_sort($a, $b, $mid + 1, $right, $n, $comparator);
Sort->_sort_short_merge($a, $b, $left, $mid, $right, $n, $comparator);
}
precompile private static method _sort_string_merge : void($a : string[], $b : string[], $left : int, $mid : int, $right : int, $n : int, $comparator : Comparator::String) {
my $i = $left;
my $j = $mid + 1;
my $k = 0;
while ($i <= $mid && $j <= $right) {
$i = $left;
$j = $mid + 1;
$k = 0;
while ($i <= $mid && $j <= $right) {
if ($comparator->($a->[$i], $a->[$j]) <= 0) {
$b->[$k] = $a->[$i];
$i++;
} else {
$b->[$k] = $a->[$j];
$j++;
}
$k++;
}
if ($i == $mid + 1) {
while ($j <= $right) {
$b->[$k] = $a->[$j];
$j++;
$k++;
}
} else {
while($i <= $mid) {
$b->[$k] = $a->[$i];
$i++;
$k++;
}
}
}
for ($i = 0; $i < $k; $i++) {
$a->[$i + $left] = $b->[$i];
}
}
private static method _sort_string_merge_sort : void($a : string[], $b : string[], $left : int, $right : int, $n : int, $comparator : Comparator::String){
if ($left >= $right) {
return;
}
my $mid = ($left + $right) / 2;
Sort->_sort_string_merge_sort($a, $b, $left, $mid, $n, $comparator);
Sort->_sort_string_merge_sort($a, $b, $mid + 1, $right, $n, $comparator);
Sort->_sort_string_merge($a, $b, $left, $mid, $right, $n, $comparator);
}
}