mirror of
https://github.com/enso-org/enso.git
synced 2024-11-22 22:10:15 +03:00
Implement sorting for Vector
(#1349)
This commit is contained in:
parent
de817af655
commit
2c12a18b25
@ -102,8 +102,3 @@ Decimal.parse : Text -> Decimal | Nothing
|
||||
Decimal.parse text =
|
||||
Panic.recover (Double.parseDouble [text]) . catch (_ -> Nothing)
|
||||
|
||||
## Compare two numbers.
|
||||
Number.compare_to : Number -> Ordering
|
||||
Number.compare_to that = if this == that then Ordering.Equal else
|
||||
if this > that then Ordering.Greater else Ordering.Less
|
||||
|
||||
|
@ -1,5 +1,9 @@
|
||||
from Base import all
|
||||
|
||||
from Builtins import Less, Equal, Greater
|
||||
|
||||
from Builtins export Less, Equal, Greater
|
||||
|
||||
## Types representing the ordering of values.
|
||||
|
||||
These are intended to be returned from the `compare_to` function, that has a
|
||||
@ -9,8 +13,15 @@ from Base import all
|
||||
`that`. So, if `this` is greater than `that`, you should return `Greater.`
|
||||
type Ordering
|
||||
## An ordering where a compared value is less than another.
|
||||
type Less
|
||||
Less
|
||||
## An ordering where a compared value is equal to another.
|
||||
type Equal
|
||||
Equal
|
||||
## An ordering where a compared value is greater than another.
|
||||
type Greater
|
||||
Greater
|
||||
|
||||
## Converts the ordering to the signed notion of ordering based on integers.
|
||||
to_sign : Integer
|
||||
to_sign = case this of
|
||||
Less -> -1
|
||||
Equal -> 0
|
||||
Greater -> 1
|
||||
|
@ -1,8 +1,6 @@
|
||||
from Builtins import Array
|
||||
from Base import all
|
||||
|
||||
import Base.Data.Vector.Sort
|
||||
|
||||
## Creates a new vector of the given length, initializing elements using
|
||||
the provided constructor function.
|
||||
|
||||
@ -30,7 +28,7 @@ new length constructor =
|
||||
created by:
|
||||
Vector.fill length=50 item=42
|
||||
fill : Number -> Any -> Vector
|
||||
fill length item =
|
||||
fill length ~item =
|
||||
arr = Array.new length
|
||||
0.up_to length . each ix-> arr.set_at ix item
|
||||
Vector arr
|
||||
@ -407,10 +405,7 @@ type Vector
|
||||
rest : Vector | Nothing
|
||||
rest = this.tail
|
||||
|
||||
## PRIVATE
|
||||
Doesn't work yet.
|
||||
|
||||
Sort the Vector.
|
||||
## Sort the Vector.
|
||||
|
||||
Arguments:
|
||||
- `on`: A projection from the element type to the value of that element
|
||||
@ -420,10 +415,26 @@ type Vector
|
||||
- `order`: The order in which the vector elements are sorted.
|
||||
|
||||
By default, elements are sorted in ascending order, using the comparator
|
||||
`>`. A custom comparator may be passed to the sort function.
|
||||
`compare_to`. A custom comparator may be passed to the sort function.
|
||||
|
||||
This implements a stable sort, meaning that items that compare the same
|
||||
will not have their order changed.
|
||||
This is a stable sort, meaning that items that compare the same will not
|
||||
have their order changed by the sorting process.
|
||||
|
||||
The complexities for this sort are:
|
||||
- *Worst-Case Time:* `O(n * log n)`
|
||||
- *Best-Case Time:* `O(n)`
|
||||
- *Average Time:* `O(n * log n)`
|
||||
- *Worst-Case Space:* `O(n)` additional
|
||||
|
||||
? Implementation Note
|
||||
The sort implementation is based upon an adaptive, iterative mergesort
|
||||
that requires far fewer than `n * log(n)` comparisons when the vector
|
||||
is partially sorted. When the vector is randomly ordered, the
|
||||
performance is equivalent to a standard mergesort.
|
||||
|
||||
It takes equal advantage of ascending and descending runs in the array,
|
||||
making it much simpler to merge two or more sorted arrays: simply
|
||||
concatenate them and sort.
|
||||
|
||||
> Example
|
||||
Sorting a vector of numbers.
|
||||
@ -434,7 +445,22 @@ type Vector
|
||||
[Pair 1 2, Pair -1 8].sort (_.first) (order = Sort_Order.Descending)
|
||||
sort : (Any -> Any) -> (Any -> Any -> Ordering) -> Sort_Order -> Vector
|
||||
sort (on = x -> x) (by = (_.compare_to _)) (order = Sort_Order.Ascending) =
|
||||
Sort.run this on by order
|
||||
## Prepare the destination array that will underlie the vector. We do
|
||||
not want to sort in place on the original vector, as `sort` is not
|
||||
intended to be mutable.
|
||||
new_vec_arr = Array.new this.length
|
||||
this.to_array.copy 0 new_vec_arr 0 this.length
|
||||
|
||||
## As we want to account for both custom projections and custom
|
||||
comparisons we need to construct a comparator for internal use that
|
||||
does both.
|
||||
comp_ascending l r = by (on l) (on r)
|
||||
comp_descending l r = by (on r) (on l)
|
||||
compare = if order == Sort_Order.Ascending then comp_ascending else comp_descending
|
||||
|
||||
new_vec_arr.sort compare
|
||||
|
||||
Vector new_vec_arr
|
||||
|
||||
## A builder type for Enso vectors.
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
from Base import all
|
||||
|
||||
# TODO [AA] Implement vector sorting.
|
||||
|
||||
## PRIVATE
|
||||
|
||||
Execute the sort.
|
||||
|
||||
In the use-cases we anticipate for Enso, we can see `sort` being run over
|
||||
both partially-sorted data and random data.
|
||||
|
||||
TODO [AA] Explain why we chose this sort.
|
||||
run : Vector -> (Any -> Any) -> (Any -> Any -> Ordering) -> Sort_Order -> Vector
|
||||
run vec _ _ _ = vec
|
||||
|
@ -40,5 +40,5 @@ from Base.Data.Text.Extensions export Text
|
||||
from Base.Error.Extensions export all
|
||||
from Base.Meta.Enso_Project export all
|
||||
from Base.Polyglot.Java export all
|
||||
from Builtins export all hiding Meta
|
||||
from Builtins export all hiding Meta, Less, Equal, Greater, Ordering
|
||||
|
||||
|
@ -423,7 +423,7 @@ public abstract class MethodResolverNode extends Node {
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
Function resolveMethodOnArray(Context context, UnresolvedSymbol symbol) {
|
||||
return symbol.resolveFor(
|
||||
context.getBuiltins().mutable().constructor(), context.getBuiltins().any());
|
||||
context.getBuiltins().mutable().array(), context.getBuiltins().any());
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
|
@ -0,0 +1,66 @@
|
||||
package org.enso.interpreter.node.expression.builtin.mutable;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.callable.InvokeCallableNode;
|
||||
import org.enso.interpreter.node.callable.InvokeCallableNode.ArgumentsExecutionMode;
|
||||
import org.enso.interpreter.node.callable.InvokeCallableNode.DefaultsExecutionMode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
import org.enso.interpreter.runtime.state.data.EmptyMap;
|
||||
|
||||
@NodeInfo(
|
||||
shortName = "sortComparator",
|
||||
description = "The implementation of the comparator for Array sorting.")
|
||||
public abstract class ComparatorNode extends Node {
|
||||
private @Child InvokeCallableNode invokeNode;
|
||||
|
||||
public static ComparatorNode build() {
|
||||
return ComparatorNodeGen.create();
|
||||
}
|
||||
|
||||
ComparatorNode() {
|
||||
CallArgumentInfo[] callArguments = {new CallArgumentInfo(), new CallArgumentInfo()};
|
||||
invokeNode =
|
||||
InvokeCallableNode.build(
|
||||
callArguments, DefaultsExecutionMode.EXECUTE, ArgumentsExecutionMode.PRE_EXECUTED);
|
||||
}
|
||||
|
||||
abstract int execute(VirtualFrame frame, Object comparator, Object l, Object r);
|
||||
|
||||
@Specialization
|
||||
int execute(
|
||||
VirtualFrame frame,
|
||||
Object comparator,
|
||||
Object l,
|
||||
Object r,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("ctxRef.get().getBuiltins().ordering().newLess()") Atom less,
|
||||
@Cached("ctxRef.get().getBuiltins().ordering().newEqual()") Atom equal,
|
||||
@Cached("ctxRef.get().getBuiltins().ordering().newGreater()") Atom greater) {
|
||||
Stateful result = invokeNode.execute(comparator, frame, EmptyMap.create(), new Object[] {l, r});
|
||||
Object atom = result.getValue();
|
||||
if (atom == less) {
|
||||
return -1;
|
||||
} else if (atom == equal) {
|
||||
return 0;
|
||||
} else if (atom == greater) {
|
||||
return 1;
|
||||
} else {
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
var ordering = ctxRef.get().getBuiltins().ordering().ordering();
|
||||
throw new PanicException(
|
||||
ctxRef.get().getBuiltins().error().makeTypeError(ordering, result.getValue()), this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package org.enso.interpreter.node.expression.builtin.mutable;
|
||||
|
||||
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
|
||||
@BuiltinMethod(type = "Array", name = "copy", description = "Copies one array to another.")
|
||||
public abstract class CopyNode extends Node {
|
||||
|
||||
static CopyNode build() {
|
||||
return CopyNodeGen.create();
|
||||
}
|
||||
|
||||
abstract Object execute(Array _this, long source_index, Array that, long dest_index, long count);
|
||||
|
||||
@Specialization
|
||||
Object doArray(
|
||||
Array _this,
|
||||
long source_index,
|
||||
Array that,
|
||||
long dest_index,
|
||||
long count,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef) {
|
||||
System.arraycopy(
|
||||
_this.getItems(), (int) source_index, that.getItems(), (int) dest_index, (int) count);
|
||||
return ctxRef.get().getBuiltins().nothing().newInstance();
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
package org.enso.interpreter.node.expression.builtin.mutable;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.LoopNode;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.profiles.BranchProfile;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
import org.enso.interpreter.runtime.state.data.EmptyMap;
|
||||
|
||||
@BuiltinMethod(type = "Array", name = "sort", description = "Sorts a mutable array in place.")
|
||||
public abstract class SortNode extends Node {
|
||||
private @Child ComparatorNode comparatorNode = ComparatorNode.build();
|
||||
private final BranchProfile resultProfile = BranchProfile.create();
|
||||
|
||||
abstract Object execute(VirtualFrame frame, Object _this, Object comparator);
|
||||
|
||||
static SortNode build() {
|
||||
return SortNodeGen.create();
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Object doSortFunction(
|
||||
VirtualFrame frame,
|
||||
Array _this,
|
||||
Function comparator,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef) {
|
||||
Comparator<Object> compare = getComparator(comparator, ctxRef);
|
||||
return runSort(compare, _this, ctxRef);
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Object doSortCallable(
|
||||
VirtualFrame frame,
|
||||
Array _this,
|
||||
Object comparator,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef) {
|
||||
Comparator<Object> compare = (l, r) -> comparatorNode.execute(frame, comparator, l, r);
|
||||
return runSort(compare, _this, ctxRef);
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Object doAtomThis(
|
||||
VirtualFrame frame,
|
||||
Atom _this,
|
||||
Object that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("ctxRef.get().getBuiltins().mutable().array()") AtomConstructor array) {
|
||||
return ctxRef.get().getBuiltins().nothing().newInstance();
|
||||
}
|
||||
|
||||
Object runSort(Comparator<Object> compare, Array _this, ContextReference<Context> ctxRef) {
|
||||
doSort(_this.getItems(), compare);
|
||||
LoopNode.reportLoopCount(this, _this.length());
|
||||
return ctxRef.get().getBuiltins().nothing().newInstance();
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
void doSort(Object[] items, Comparator<Object> compare) {
|
||||
Arrays.sort(items, compare);
|
||||
}
|
||||
|
||||
private SortComparator getComparator(Function comp, ContextReference<Context> ctxRef) {
|
||||
return new SortComparator(comp, ctxRef, this);
|
||||
}
|
||||
|
||||
private class SortComparator implements Comparator<Object> {
|
||||
private final Function compFn;
|
||||
private final ContextReference<Context> ctxRef;
|
||||
private final Atom less;
|
||||
private final Atom equal;
|
||||
private final Atom greater;
|
||||
private final SortNode outerThis;
|
||||
|
||||
SortComparator(Function compFn, ContextReference<Context> ctxRef, SortNode outerThis) {
|
||||
this.compFn = compFn;
|
||||
this.ctxRef = ctxRef;
|
||||
this.less = ctxRef.get().getBuiltins().ordering().newLess();
|
||||
this.equal = ctxRef.get().getBuiltins().ordering().newEqual();
|
||||
this.greater = ctxRef.get().getBuiltins().ordering().newGreater();
|
||||
this.outerThis = outerThis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
Object[] args =
|
||||
Function.ArgumentsHelper.buildArguments(
|
||||
compFn, null, EmptyMap.create(), new Object[] {o1, o2});
|
||||
Stateful result = (Stateful) (compFn).getCallTarget().call(args);
|
||||
Object value = result.getValue();
|
||||
return convertResult(value);
|
||||
}
|
||||
|
||||
private int convertResult(Object res) {
|
||||
if (res == less) {
|
||||
return -1;
|
||||
} else if (res == equal) {
|
||||
return 0;
|
||||
} else if (res == greater) {
|
||||
return 1;
|
||||
} else {
|
||||
resultProfile.enter();
|
||||
var ordering = ctxRef.get().getBuiltins().ordering().ordering();
|
||||
throw new PanicException(
|
||||
ctxRef.get().getBuiltins().error().makeTypeError(ordering, res), outerThis);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.builtin.Ordering;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Big_Integer",
|
||||
name = "compare_to",
|
||||
description = "Comparison for big integers.")
|
||||
public abstract class CompareToNode extends Node {
|
||||
|
||||
static CompareToNode build() {
|
||||
return CompareToNodeGen.create();
|
||||
}
|
||||
|
||||
abstract Atom execute(EnsoBigInteger _this, Object that);
|
||||
|
||||
@Specialization
|
||||
Atom doLong(
|
||||
EnsoBigInteger _this,
|
||||
long that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("getOrdering(ctxRef)") Ordering ordering) {
|
||||
return ordering.fromJava(BigIntegerOps.compareTo(_this.getValue(), that));
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Atom doBigInt(
|
||||
EnsoBigInteger _this,
|
||||
EnsoBigInteger that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("getOrdering(ctxRef)") Ordering ordering) {
|
||||
return ordering.fromJava(BigIntegerOps.compareTo(_this.getValue(), that.getValue()));
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Atom doDecimal(
|
||||
EnsoBigInteger _this,
|
||||
double that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("getOrdering(ctxRef)") Ordering ordering) {
|
||||
return ordering.fromJava(BigIntegerOps.compareTo(_this.getValue(), that));
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Atom doOther(
|
||||
EnsoBigInteger _this,
|
||||
Object that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef) {
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
var number = ctxRef.get().getBuiltins().number().getNumber().newInstance();
|
||||
var typeError = ctxRef.get().getBuiltins().error().makeTypeError(that, number);
|
||||
throw new PanicException(typeError, this);
|
||||
}
|
||||
|
||||
Ordering getOrdering(ContextReference<Context> ctxRef) {
|
||||
return ctxRef.get().getBuiltins().ordering();
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package org.enso.interpreter.node.expression.builtin.number.decimal;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.builtin.Ordering;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
|
||||
@BuiltinMethod(type = "Decimal", name = "compare_to", description = "Comparison for decimals.")
|
||||
public abstract class CompareToNode extends Node {
|
||||
|
||||
static CompareToNode build() {
|
||||
return CompareToNodeGen.create();
|
||||
}
|
||||
|
||||
abstract Atom execute(double _this, Object that);
|
||||
|
||||
@Specialization
|
||||
Atom doLong(
|
||||
double _this,
|
||||
long that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("getOrdering(ctxRef)") Ordering ordering) {
|
||||
if (_this == that) {
|
||||
return ordering.newEqual();
|
||||
} else if (_this > that) {
|
||||
return ordering.newGreater();
|
||||
} else {
|
||||
return ordering.newLess();
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Atom doBigInt(
|
||||
double _this,
|
||||
EnsoBigInteger that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("getOrdering(ctxRef)") Ordering ordering) {
|
||||
return ordering.fromJava(BigIntegerOps.compareTo(_this, that.getValue()));
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Atom doDecimal(
|
||||
double _this,
|
||||
double that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("getOrdering(ctxRef)") Ordering ordering) {
|
||||
if (_this == that) {
|
||||
return ordering.newEqual();
|
||||
} else if (_this > that) {
|
||||
return ordering.newGreater();
|
||||
} else {
|
||||
return ordering.newLess();
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Atom doOther(
|
||||
double _this, Object that, @CachedContext(Language.class) ContextReference<Context> ctxRef) {
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
var number = ctxRef.get().getBuiltins().number().getNumber().newInstance();
|
||||
var typeError = ctxRef.get().getBuiltins().error().makeTypeError(that, number);
|
||||
throw new PanicException(typeError, this);
|
||||
}
|
||||
|
||||
Ordering getOrdering(ContextReference<Context> ctxRef) {
|
||||
return ctxRef.get().getBuiltins().ordering();
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.builtin.Ordering;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Small_Integer",
|
||||
name = "compare_to",
|
||||
description = "Comparison for small integers.")
|
||||
public abstract class CompareToNode extends Node {
|
||||
|
||||
static CompareToNode build() {
|
||||
return CompareToNodeGen.create();
|
||||
}
|
||||
|
||||
abstract Atom execute(long _this, Object that);
|
||||
|
||||
@Specialization
|
||||
Atom doLong(
|
||||
long _this,
|
||||
long that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("getOrdering(ctxRef)") Ordering ordering) {
|
||||
if (_this == that) {
|
||||
return ordering.newEqual();
|
||||
} else if (_this > that) {
|
||||
return ordering.newGreater();
|
||||
} else {
|
||||
return ordering.newLess();
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Atom doBigInt(
|
||||
long _this,
|
||||
EnsoBigInteger that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("getOrdering(ctxRef)") Ordering ordering) {
|
||||
return ordering.fromJava(BigIntegerOps.compareTo(_this, that.getValue()));
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Atom doDecimal(
|
||||
long _this,
|
||||
double that,
|
||||
@CachedContext(Language.class) ContextReference<Context> ctxRef,
|
||||
@Cached("getOrdering(ctxRef)") Ordering ordering) {
|
||||
if (_this == that) {
|
||||
return ordering.newEqual();
|
||||
} else if (_this > that) {
|
||||
return ordering.newGreater();
|
||||
} else {
|
||||
return ordering.newLess();
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Atom doOther(
|
||||
long _this, Object that, @CachedContext(Language.class) ContextReference<Context> ctxRef) {
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
var number = ctxRef.get().getBuiltins().number().getNumber().newInstance();
|
||||
var typeError = ctxRef.get().getBuiltins().error().makeTypeError(that, number);
|
||||
throw new PanicException(typeError, this);
|
||||
}
|
||||
|
||||
Ordering getOrdering(ContextReference<Context> ctxRef) {
|
||||
return ctxRef.get().getBuiltins().ordering();
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package org.enso.interpreter.node.expression.builtin.number.utils;
|
||||
import com.fasterxml.jackson.databind.node.BigIntegerNode;
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/** Re-exposes big-integer operations behind a truffle boundary. */
|
||||
@ -204,6 +205,31 @@ public class BigIntegerOps {
|
||||
return BigIntegerOps.compare(a,BigInteger.ZERO) == 0;
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public static int compareTo(long a, BigInteger b) {
|
||||
return -b.signum();
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public static int compareTo(BigInteger a, long b) {
|
||||
return a.signum();
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public static int compareTo(BigInteger a, BigInteger b) {
|
||||
return a.compareTo(b);
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public static int compareTo(BigInteger a, double b) {
|
||||
return (new BigDecimal(a)).compareTo(BigDecimal.valueOf(b));
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public static int compareTo(double a, BigInteger b) {
|
||||
return BigDecimal.valueOf(a).compareTo(new BigDecimal(b));
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public static boolean fitsInLong(BigInteger bigInteger) {
|
||||
return bigInteger.compareTo(MIN_LONG_BIGINT) >= 0 && bigInteger.compareTo(MAX_LONG_BIGINT) <= 0;
|
||||
|
@ -38,22 +38,24 @@ public class Builtins {
|
||||
}
|
||||
}
|
||||
|
||||
private final Module module;
|
||||
private final ModuleScope scope;
|
||||
private final AtomConstructor nothing;
|
||||
private final AtomConstructor any;
|
||||
private final Number number;
|
||||
private final AtomConstructor function;
|
||||
private final AtomConstructor debug;
|
||||
private final AtomConstructor ensoProject;
|
||||
private final Text text;
|
||||
private final Error error;
|
||||
private final AtomConstructor function;
|
||||
private final AtomConstructor nothing;
|
||||
|
||||
private final Bool bool;
|
||||
private final System system;
|
||||
private final Error error;
|
||||
private final Meta meta;
|
||||
private final Module module;
|
||||
private final ModuleScope scope;
|
||||
private final Mutable mutable;
|
||||
private final Number number;
|
||||
private final Ordering ordering;
|
||||
private final Polyglot polyglot;
|
||||
private final Resource resource;
|
||||
private final Meta meta;
|
||||
private final System system;
|
||||
private final Text text;
|
||||
|
||||
/**
|
||||
* Creates an instance with builtin methods installed.
|
||||
@ -62,27 +64,28 @@ public class Builtins {
|
||||
*/
|
||||
public Builtins(Context context) {
|
||||
Language language = context.getLanguage();
|
||||
|
||||
module = Module.empty(QualifiedName.fromString(MODULE_NAME).get());
|
||||
scope = module.compileScope(context);
|
||||
nothing = new AtomConstructor("Nothing", scope).initializeFields();
|
||||
|
||||
any = new AtomConstructor("Any", scope).initializeFields();
|
||||
bool = new Bool(language, scope);
|
||||
error = new Error(language, scope);
|
||||
mutable = new Mutable(language, scope);
|
||||
function = new AtomConstructor("Function", scope).initializeFields();
|
||||
text = new Text(language, scope);
|
||||
debug = new AtomConstructor("Debug", scope).initializeFields();
|
||||
ensoProject =
|
||||
new AtomConstructor("Enso_Project", scope)
|
||||
.initializeFields(
|
||||
new ArgumentDefinition(
|
||||
0, "prim_root_file", ArgumentDefinition.ExecutionMode.EXECUTE));
|
||||
system = new System(language, scope);
|
||||
error = new Error(language, scope);
|
||||
function = new AtomConstructor("Function", scope).initializeFields();
|
||||
meta = new Meta(language, scope);
|
||||
mutable = new Mutable(language, scope);
|
||||
nothing = new AtomConstructor("Nothing", scope).initializeFields();
|
||||
number = new Number(language, scope);
|
||||
ordering = new Ordering(language, scope);
|
||||
polyglot = new Polyglot(language, scope);
|
||||
resource = new Resource(language, scope);
|
||||
meta = new Meta(language, scope);
|
||||
system = new System(language, scope);
|
||||
text = new Text(language, scope);
|
||||
|
||||
AtomConstructor nil = new AtomConstructor("Nil", scope).initializeFields();
|
||||
AtomConstructor cons =
|
||||
@ -243,6 +246,11 @@ public class Builtins {
|
||||
return polyglot;
|
||||
}
|
||||
|
||||
/** @return the container for ordering-related builtins */
|
||||
public Ordering ordering() {
|
||||
return ordering;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the builtin module scope.
|
||||
*
|
||||
|
@ -11,6 +11,7 @@ import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
/** Container for builtin Error types */
|
||||
public class Error {
|
||||
private final AtomConstructor syntaxError;
|
||||
private final AtomConstructor typeError;
|
||||
private final AtomConstructor compileError;
|
||||
private final AtomConstructor inexhaustivePatternMatchError;
|
||||
private final AtomConstructor uninitializedState;
|
||||
@ -34,6 +35,11 @@ public class Error {
|
||||
new AtomConstructor("Syntax_Error", scope)
|
||||
.initializeFields(
|
||||
new ArgumentDefinition(0, "message", ArgumentDefinition.ExecutionMode.EXECUTE));
|
||||
typeError =
|
||||
new AtomConstructor("Type_Error", scope)
|
||||
.initializeFields(
|
||||
new ArgumentDefinition(0, "expected", ArgumentDefinition.ExecutionMode.EXECUTE),
|
||||
new ArgumentDefinition(0, "actual", ArgumentDefinition.ExecutionMode.EXECUTE));
|
||||
compileError =
|
||||
new AtomConstructor("Compile_Error", scope)
|
||||
.initializeFields(
|
||||
@ -78,6 +84,9 @@ public class Error {
|
||||
return syntaxError;
|
||||
}
|
||||
|
||||
/** @return the builtin {@code Type_Error} atom constructor. */
|
||||
public AtomConstructor typeError() { return typeError; }
|
||||
|
||||
/** @return the builtin {@code Compile_Error} atom constructor. */
|
||||
public AtomConstructor compileError() {
|
||||
return compileError;
|
||||
@ -109,6 +118,17 @@ public class Error {
|
||||
return noSuchMethodError.newInstance(target, symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of the runtime representation of a {@code Type_Error}.
|
||||
*
|
||||
* @param expected the expected type
|
||||
* @param actual the actual type
|
||||
* @return a runtime representation of the error.
|
||||
*/
|
||||
public Atom makeTypeError(Object expected, Object actual) {
|
||||
return typeError.newInstance(expected, actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of the runtime representation of a {@code Polyglot_Error}.
|
||||
*
|
||||
|
@ -8,6 +8,7 @@ import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
/** Container for builtin array-related types and functions. */
|
||||
public class Mutable {
|
||||
private final AtomConstructor array;
|
||||
private final AtomConstructor ref;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this class, registering all relevant bindings in the provided scope.
|
||||
@ -28,8 +29,10 @@ public class Mutable {
|
||||
scope.registerMethod(array, "to_array", ToArrayMethodGen.makeFunction(language));
|
||||
scope.registerMethod(array, "at", GetAtMethodGen.makeFunction(language));
|
||||
scope.registerMethod(array, "set_at", SetAtMethodGen.makeFunction(language));
|
||||
scope.registerMethod(array, "copy", CopyMethodGen.makeFunction(language));
|
||||
scope.registerMethod(array, "sort", SortMethodGen.makeFunction(language));
|
||||
|
||||
AtomConstructor ref = new AtomConstructor("Ref", scope).initializeFields();
|
||||
ref = new AtomConstructor("Ref", scope).initializeFields();
|
||||
scope.registerConstructor(ref);
|
||||
scope.registerMethod(ref, "new", NewRefMethodGen.makeFunction(language));
|
||||
scope.registerMethod(ref, "get", GetRefMethodGen.makeFunction(language));
|
||||
@ -37,7 +40,12 @@ public class Mutable {
|
||||
}
|
||||
|
||||
/** @return the Array constructor. */
|
||||
public AtomConstructor constructor() {
|
||||
public AtomConstructor array() {
|
||||
return array;
|
||||
}
|
||||
|
||||
/** @return the Ref constructor. */
|
||||
public AtomConstructor ref() {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +157,11 @@ public class Number {
|
||||
"bit_shift_r",
|
||||
org.enso.interpreter.node.expression.builtin.number.smallInteger.BitShiftRightMethodGen
|
||||
.makeFunction(language));
|
||||
scope.registerMethod(
|
||||
smallInteger,
|
||||
"compare_to",
|
||||
org.enso.interpreter.node.expression.builtin.number.smallInteger.CompareToMethodGen
|
||||
.makeFunction(language));
|
||||
}
|
||||
|
||||
private void registerBigIntegerMethods(Language language, ModuleScope scope) {
|
||||
@ -281,6 +286,11 @@ public class Number {
|
||||
"bit_shift_r",
|
||||
org.enso.interpreter.node.expression.builtin.number.bigInteger.BitShiftRightMethodGen
|
||||
.makeFunction(language));
|
||||
scope.registerMethod(
|
||||
bigInteger,
|
||||
"compare_to",
|
||||
org.enso.interpreter.node.expression.builtin.number.bigInteger.CompareToMethodGen
|
||||
.makeFunction(language));
|
||||
}
|
||||
|
||||
private void registerDecimalMethods(Language language, ModuleScope scope) {
|
||||
@ -360,6 +370,11 @@ public class Number {
|
||||
"ceil",
|
||||
org.enso.interpreter.node.expression.builtin.number.decimal.CeilMethodGen.makeFunction(
|
||||
language));
|
||||
scope.registerMethod(
|
||||
decimal,
|
||||
"compare_to",
|
||||
org.enso.interpreter.node.expression.builtin.number.decimal.CompareToMethodGen.makeFunction(
|
||||
language));
|
||||
}
|
||||
|
||||
/** @return the Int64 atom constructor. */
|
||||
|
@ -0,0 +1,76 @@
|
||||
package org.enso.interpreter.runtime.builtin;
|
||||
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
|
||||
/** A container for builtin ordering types. */
|
||||
public class Ordering {
|
||||
private final AtomConstructor ordering;
|
||||
private final AtomConstructor less;
|
||||
private final AtomConstructor equal;
|
||||
private final AtomConstructor greater;
|
||||
|
||||
public Ordering(Language language, ModuleScope scope) {
|
||||
ordering = new AtomConstructor("Ordering", scope).initializeFields();
|
||||
less = new AtomConstructor("Less", scope).initializeFields();
|
||||
equal = new AtomConstructor("Equal", scope).initializeFields();
|
||||
greater = new AtomConstructor("Greater", scope).initializeFields();
|
||||
scope.registerConstructor(ordering);
|
||||
scope.registerConstructor(less);
|
||||
scope.registerConstructor(equal);
|
||||
scope.registerConstructor(greater);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the java notion of ordering to the Enso notion of ordering.
|
||||
*
|
||||
* @param ord the java ordering
|
||||
* @return the Enso ordering corresponding to {@code ord}
|
||||
*/
|
||||
public Atom fromJava(int ord) {
|
||||
if (ord == 0) {
|
||||
return newEqual();
|
||||
} else if (ord > 0) {
|
||||
return newGreater();
|
||||
} else {
|
||||
return newLess();
|
||||
}
|
||||
}
|
||||
|
||||
/** @return a new instance of Less */
|
||||
public Atom newLess() {
|
||||
return less.newInstance();
|
||||
}
|
||||
|
||||
/** @return a new instance of Equal */
|
||||
public Atom newEqual() {
|
||||
return equal.newInstance();
|
||||
}
|
||||
|
||||
/** @return a new instance of Greater */
|
||||
public Atom newGreater() {
|
||||
return greater.newInstance();
|
||||
}
|
||||
|
||||
/** @return the Ordering constructor. */
|
||||
public AtomConstructor ordering() {
|
||||
return ordering;
|
||||
}
|
||||
|
||||
/** @return the Less constructor */
|
||||
public AtomConstructor less() {
|
||||
return less;
|
||||
}
|
||||
|
||||
/** @return the Equal constructor */
|
||||
public AtomConstructor equal() {
|
||||
return equal;
|
||||
}
|
||||
|
||||
/** @return the Greater constructor */
|
||||
public AtomConstructor greater() {
|
||||
return greater;
|
||||
}
|
||||
}
|
@ -59,10 +59,15 @@ public class Array implements TruffleObject {
|
||||
return items[(int) index];
|
||||
}
|
||||
|
||||
/** @return the size of this array */
|
||||
public int length() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposes the size of this collection through the polyglot API.
|
||||
*
|
||||
* @return
|
||||
* @return the size of this array
|
||||
*/
|
||||
@ExportMessage
|
||||
long getArraySize() {
|
||||
|
@ -702,7 +702,7 @@ class IrToTruffle(
|
||||
|
||||
runtimeConsOpt.map { atomCons =>
|
||||
val any = context.getBuiltins.any
|
||||
val array = context.getBuiltins.mutable.constructor
|
||||
val array = context.getBuiltins.mutable.array
|
||||
val bool = context.getBuiltins.bool
|
||||
val number = context.getBuiltins.number
|
||||
val polyglot = context.getBuiltins.polyglot.getPolyglot
|
||||
|
@ -228,7 +228,7 @@ case object SuspendedArguments extends IRPass {
|
||||
case (arg, typ) =>
|
||||
arg match {
|
||||
case spec: IR.DefinitionArgument.Specified =>
|
||||
if (representsSuspended(typ)) {
|
||||
if (representsSuspended(typ) || spec.suspended) {
|
||||
spec.copy(suspended = true)
|
||||
} else spec.copy(suspended = false)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
|
||||
/** Utils for standard library operations on Time. */
|
||||
public class Time_Utils {
|
||||
|
73
test/Benchmarks/src/Vector.enso
Normal file
73
test/Benchmarks/src/Vector.enso
Normal file
@ -0,0 +1,73 @@
|
||||
from Base import all
|
||||
|
||||
import Test.Bench
|
||||
|
||||
polyglot java import java.util.Random
|
||||
polyglot java import org.enso.base.Time_Utils
|
||||
|
||||
|
||||
|
||||
## Bench Utilities ============================================================
|
||||
|
||||
vector_size = 1000000
|
||||
iter_size = 100
|
||||
num_iterations = 10
|
||||
|
||||
make_sorted_ascending_vec : Integer -> Base.Vector.Vector
|
||||
make_sorted_ascending_vec n = 0.up_to n+1 . to_vector
|
||||
|
||||
make_partially_sorted_vec : Integer -> Base.Vector.Vector
|
||||
make_partially_sorted_vec n =
|
||||
random_gen = Random.new [n].to_array
|
||||
direction = Ref.new Sort_Order.Ascending
|
||||
last_num = Ref.new 0
|
||||
run_length = Ref.new 0
|
||||
Base.Vector.fill n <|
|
||||
case (Ref.get run_length) == 0 of
|
||||
True ->
|
||||
new_direction = if (random_gen.nextDouble []) > 0 then Sort_Order.Ascending else
|
||||
Sort_Order.Descending
|
||||
Ref.put direction new_direction
|
||||
Ref.put run_length (((random_gen.nextLong []) % (n / 10).floor) - 1)
|
||||
num = random_gen.nextInt []
|
||||
Ref.put last_num num
|
||||
num
|
||||
False ->
|
||||
change = ((random_gen.nextInt []).abs) % n
|
||||
num = case Ref.get direction of
|
||||
Sort_Order.Ascending ->
|
||||
num = (Ref.get last_num) + change
|
||||
Ref.put last_num num
|
||||
num
|
||||
Sort_Order.Descending ->
|
||||
num = (Ref.get last_num) - change
|
||||
Ref.put last_num num
|
||||
num
|
||||
Ref.put run_length ((Ref.get run_length) - 1)
|
||||
num
|
||||
|
||||
make_random_vec : Integer -> Base.Vector.Vector
|
||||
make_random_vec n =
|
||||
random_gen = Random.new [n].to_array
|
||||
Base.Vector.fill n (random_gen.nextLong [])
|
||||
|
||||
|
||||
|
||||
# The Benchmarks ==============================================================
|
||||
|
||||
main =
|
||||
sorted_vec = here.make_sorted_ascending_vec here.vector_size
|
||||
partially_sorted_vec = here.make_partially_sorted_vec here.vector_size
|
||||
random_vec = here.make_random_vec here.vector_size
|
||||
projection = x -> x % 10
|
||||
comparator = l -> r -> r.compare_to l
|
||||
|
||||
Bench.measure (sorted_vec.sort) "Already Sorted" here.iter_size here.num_iterations
|
||||
Bench.measure (sorted_vec.sort order=Sort_Order.Descending) "Sorted in Opposite Order" here.iter_size here.num_iterations
|
||||
Bench.measure (partially_sorted_vec.sort) "Sorted Runs Ascending" here.iter_size here.num_iterations
|
||||
Bench.measure (partially_sorted_vec.sort order=Sort_Order.Descending) "Sorted Runs Descending" here.iter_size here.num_iterations
|
||||
Bench.measure (random_vec.sort) "Random Elements Ascending" here.iter_size here.num_iterations
|
||||
Bench.measure (random_vec.sort order=Sort_Order.Descending) "Random Elements Descending" here.iter_size here.num_iterations
|
||||
Bench.measure (random_vec.sort on=projection) "Sorting with a Custom Projection" here.iter_size here.num_iterations
|
||||
Bench.measure (random_vec.sort by=comparator) "Sorting with a Custom Comparison" here.iter_size here.num_iterations
|
||||
|
@ -14,6 +14,6 @@ spec = describe "Noise" <|
|
||||
result-result . should_equal 0
|
||||
it "should allow the user to specify the interval" <|
|
||||
interval = Interval.inclusive -250 250
|
||||
values = 1.up_to 10000 . to_vector . map (_.noise interval)
|
||||
values = 1.up_to 10001 . to_vector . map (_.noise interval)
|
||||
values.all (v -> (v >= -250) && (v <= 250)) . should_be_true
|
||||
|
||||
|
@ -2,6 +2,12 @@ from Base import all
|
||||
|
||||
import Test
|
||||
|
||||
type Test a b
|
||||
|
||||
Test.== that = this.a == that.a
|
||||
Test.compare_to that = if this == that then Ordering.Equal else
|
||||
if this.a > that.a then Ordering.Greater else Ordering.Less
|
||||
|
||||
spec = describe "Vectors" <|
|
||||
it "should allow vector creation with a programmatic constructor" <|
|
||||
Vector.new 100 (ix -> ix + 1) . fold 0 (+) . should_equal 5050
|
||||
@ -115,9 +121,38 @@ spec = describe "Vectors" <|
|
||||
non_empty_vec.rest . should_equal [2, 3, 4, 5]
|
||||
singleton_vec.rest . should_equal []
|
||||
empty_vec.rest . should_equal Nothing
|
||||
# it "should be able to be sorted" <|
|
||||
# it "should have a stable sort" <|
|
||||
# it "should be able to use a custom element projection" <|
|
||||
# it "should be able to use a custom comparator" <|
|
||||
# it "should be able to sort in ascending and descending order" <|
|
||||
|
||||
it "should be able to be sorted" <|
|
||||
empty_vec = []
|
||||
short_vec = [2, 4, 38, -1, -1000, 3671, -32]
|
||||
short_expected = [-1000, -32, -1, 2, 4, 38, 3671]
|
||||
empty_vec.sort . should_equal []
|
||||
short_vec.sort . should_equal short_expected
|
||||
it "should leave the original vector unchanged" <|
|
||||
non_empty_vec = [2, 4, 2, 3, 2, 3]
|
||||
sorted = non_empty_vec.sort
|
||||
non_empty_vec . should_equal [2, 4, 2, 3, 2, 3]
|
||||
sorted . should_equal [2, 2, 2, 3, 3, 4]
|
||||
it "should have a stable sort" <|
|
||||
small_vec = [Test 1 8, Test 1 3, Test -20 0, Test -1 1, Test -1 10, Test 4 0]
|
||||
small_expected = [Test -20 0, Test -1 1, Test -1 10, Test 1 8, Test 1 3, Test 4 0]
|
||||
small_vec.sort . should_equal small_expected
|
||||
it "should be able to use a custom element projection" <|
|
||||
small_vec = [Test 1 8, Test 1 3, Test -20 0, Test -1 1, Test -1 10, Test 4 0]
|
||||
small_expected = [Test -20 0, Test 4 0, Test -1 1, Test 1 3, Test 1 8, Test -1 10]
|
||||
small_vec.sort (on = _.b) . should_equal small_expected
|
||||
it "should be able to use a custom comparator" <|
|
||||
small_vec = [2, 7, -3, 383, -392, 28, -90]
|
||||
small_expected = [383, 28, 7, 2, -3, -90, -392]
|
||||
small_vec.sort (by = l -> r -> r.compare_to l) . should_equal small_expected
|
||||
it "should be able to use a custom comparator and projection" <|
|
||||
small_vec = [Test 1 8, Test 1 3, Test -20 0, Test -1 1, Test -1 10, Test 4 0]
|
||||
small_expected = [Test -1 10, Test 1 8, Test 1 3, Test -1 1, Test -20 0, Test 4 0]
|
||||
small_vec.sort (on = _.b) (by = l -> r -> r.compare_to l) . should_equal small_expected
|
||||
it "should be able to sort in descending order" <|
|
||||
small_vec = [2, 7, -3, 383, -392, 28, -90]
|
||||
small_expected = [383, 28, 7, 2, -3, -90, -392]
|
||||
small_vec.sort order=Sort_Order.Descending . should_equal small_expected
|
||||
it "should be stable in descending order" <|
|
||||
small_vec = [Test 1 8, Test 1 3, Test -20 0, Test -1 1, Test -1 10, Test 4 0]
|
||||
small_expected = [Test 4 0, Test 1 3, Test 1 8, Test -1 10, Test -1 1, Test -20 0]
|
||||
small_vec.sort order=Sort_Order.Descending . should_equal small_expected
|
||||
|
Loading…
Reference in New Issue
Block a user