mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 20:16:47 +03:00
Improve Vector (#3232)
This commit is contained in:
parent
f9e78a5caa
commit
cfdb33bc68
@ -19,6 +19,10 @@
|
|||||||
Vector][3224]
|
Vector][3224]
|
||||||
- [Implemented `Duration.time_execution` allowing timing of the execution of an
|
- [Implemented `Duration.time_execution` allowing timing of the execution of an
|
||||||
- expression within the UI][3229]
|
- expression within the UI][3229]
|
||||||
|
- [Improved performance of `Vector.filter` and `Vector.each`; implemented
|
||||||
|
`Vector.filter_with_index`. Made `Vector.at` accept negative indices and
|
||||||
|
ensured it fails with a dataflow error on out of bounds access instead of an
|
||||||
|
internal Java exception.][3232]
|
||||||
|
|
||||||
[3153]: https://github.com/enso-org/enso/pull/3153
|
[3153]: https://github.com/enso-org/enso/pull/3153
|
||||||
[3166]: https://github.com/enso-org/enso/pull/3166
|
[3166]: https://github.com/enso-org/enso/pull/3166
|
||||||
@ -28,6 +32,7 @@
|
|||||||
[3208]: https://github.com/enso-org/enso/pull/3208
|
[3208]: https://github.com/enso-org/enso/pull/3208
|
||||||
[3224]: https://github.com/enso-org/enso/pull/3224
|
[3224]: https://github.com/enso-org/enso/pull/3224
|
||||||
[3229]: https://github.com/enso-org/enso/pull/3229
|
[3229]: https://github.com/enso-org/enso/pull/3229
|
||||||
|
[3232]: https://github.com/enso-org/enso/pull/3232
|
||||||
|
|
||||||
# Enso 2.0.0-alpha.18 (2021-10-12)
|
# Enso 2.0.0-alpha.18 (2021-10-12)
|
||||||
|
|
||||||
|
@ -11,3 +11,15 @@ type Pair
|
|||||||
- first: The first element.
|
- first: The first element.
|
||||||
- second: The second element.
|
- second: The second element.
|
||||||
type Pair first second
|
type Pair first second
|
||||||
|
|
||||||
|
## UNSTABLE
|
||||||
|
|
||||||
|
Applies the provided function to both elements of the pair.
|
||||||
|
|
||||||
|
> Example
|
||||||
|
Adding one to two elements of the pair.
|
||||||
|
|
||||||
|
(Pair 1 2).map (+1) == (Pair 2 3)
|
||||||
|
map : (Any -> Any) -> Pair
|
||||||
|
map fun =
|
||||||
|
Pair (fun this.first) (fun this.second)
|
||||||
|
@ -126,14 +126,41 @@ type Vector
|
|||||||
## Gets an element from the vector at a specified index (0-based).
|
## Gets an element from the vector at a specified index (0-based).
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- index: The location in the vector to get the element from.
|
- index: The location in the vector to get the element from. The index is
|
||||||
|
also allowed be negative, then the elements are indexed from the back
|
||||||
|
of the vector, i.e. -1 will correspond to the last element.
|
||||||
|
|
||||||
> Example
|
> Example
|
||||||
Get the second element of a vector.
|
Get the second element of a vector.
|
||||||
|
|
||||||
[1, 2, 3].at 1
|
[1, 2, 3].at 1 == 2
|
||||||
at : Number -> Any
|
|
||||||
at index = this.to_array.at index
|
> Example
|
||||||
|
Get the last element of a vector.
|
||||||
|
|
||||||
|
[1, 2, 3].at -1 == 3
|
||||||
|
at : Integer -> Any ! Index_Out_Of_Bounds_Error
|
||||||
|
at index =
|
||||||
|
actual_index = if index < 0 then this.length + index else index
|
||||||
|
## TODO [RW] Ideally we do not want an additional check here, but we
|
||||||
|
should catch a Invalid_Array_Index_Error panic. However, such a catch
|
||||||
|
should still properly forward any other panics or dataflow errors
|
||||||
|
which is not fully possible until the approach to handling Panics is
|
||||||
|
improved, as described in the following Pivotal ticket:
|
||||||
|
https://www.pivotaltracker.com/n/projects/2539304/stories/181029230
|
||||||
|
if actual_index>=0 && actual_index<this.length then this.unsafe_at actual_index else
|
||||||
|
Error.throw (Index_Out_Of_Bounds_Error index this.length)
|
||||||
|
|
||||||
|
## ADVANCED
|
||||||
|
UNSTABLE
|
||||||
|
|
||||||
|
An unsafe variant of the `at` operation. It only allows non-negative
|
||||||
|
indices and will panic with a raw Java exception on out-of-bounds access.
|
||||||
|
Thus it should only be used when the access is guaranteed to be within
|
||||||
|
bounds or with additional error handling.
|
||||||
|
unsafe_at : Integer -> Any
|
||||||
|
unsafe_at index =
|
||||||
|
this.to_array.at index
|
||||||
|
|
||||||
## Combines all the elements of the vector, by iteratively applying the
|
## Combines all the elements of the vector, by iteratively applying the
|
||||||
passed function with next elements of the vector.
|
passed function with next elements of the vector.
|
||||||
@ -206,7 +233,7 @@ type Vector
|
|||||||
exists predicate =
|
exists predicate =
|
||||||
len = this.length
|
len = this.length
|
||||||
go idx found = if found || (idx >= len) then found else
|
go idx found = if found || (idx >= len) then found else
|
||||||
@Tail_Call go idx+1 (predicate (this.at idx))
|
@Tail_Call go idx+1 (predicate (this.unsafe_at idx))
|
||||||
go 0 False
|
go 0 False
|
||||||
|
|
||||||
## Returns the first element of the vector that satisfies the predicate or
|
## Returns the first element of the vector that satisfies the predicate or
|
||||||
@ -226,8 +253,8 @@ type Vector
|
|||||||
len = this.length
|
len = this.length
|
||||||
go idx =
|
go idx =
|
||||||
if (idx >= len) then Error.throw Nothing else
|
if (idx >= len) then Error.throw Nothing else
|
||||||
elem = this.at idx
|
elem = this.unsafe_at idx
|
||||||
if (predicate elem) then elem else
|
if predicate elem then elem else
|
||||||
@Tail_Call go idx+1
|
@Tail_Call go idx+1
|
||||||
go 0
|
go 0
|
||||||
|
|
||||||
@ -302,8 +329,88 @@ type Vector
|
|||||||
[1, 2, 3, 4, 5].filter (> 3)
|
[1, 2, 3, 4, 5].filter (> 3)
|
||||||
filter : (Any -> Boolean) -> Vector Any
|
filter : (Any -> Boolean) -> Vector Any
|
||||||
filter predicate =
|
filter predicate =
|
||||||
check acc ix = if predicate ix then acc + [ix] else acc
|
builder = this.fold here.new_builder builder-> elem->
|
||||||
this.fold [] check
|
if predicate elem then builder.append elem else builder
|
||||||
|
builder.to_vector
|
||||||
|
|
||||||
|
## Selects all elements of this vector which satisfy a predicate.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- predicate: A function that takes an index and a list element and
|
||||||
|
returns a boolean value that says whether that value should be included
|
||||||
|
in the result.
|
||||||
|
|
||||||
|
> Example
|
||||||
|
Selecting all elements which are equal to their position in the vector.
|
||||||
|
|
||||||
|
[0, 10, 2, 2].filter (==) == [0, 2]
|
||||||
|
filter_with_index : (Integer -> Any -> Boolean) -> Vector Any
|
||||||
|
filter_with_index predicate =
|
||||||
|
acc = this.fold (Pair here.new_builder 0) acc-> elem->
|
||||||
|
builder = acc.first
|
||||||
|
ix = acc.second
|
||||||
|
new_builder = if predicate ix elem then builder.append elem else builder
|
||||||
|
Pair new_builder ix+1
|
||||||
|
builder = acc.first
|
||||||
|
builder.to_vector
|
||||||
|
|
||||||
|
## Partitions the vector into vectors of elements which satisfy a given
|
||||||
|
predicate and ones that do not.
|
||||||
|
|
||||||
|
Returns a `Pair` whose `first` element is the vector of elements
|
||||||
|
satisfying the predicate and the `second` element is a vector of elements
|
||||||
|
which did not satisfy it.
|
||||||
|
|
||||||
|
The relative order of elements kept in each returned list is the same as
|
||||||
|
in the input vector.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- predicate: A function that takes an element and returns a boolean
|
||||||
|
value.
|
||||||
|
|
||||||
|
> Example
|
||||||
|
Splitting a vector into even and odd elements.
|
||||||
|
|
||||||
|
[1, 2, 3, 4, 5].partition (x -> x % 2 == 0) == (Pair [2, 4] [1, 3, 5])
|
||||||
|
partition : (Any -> Boolean) -> Vector Any
|
||||||
|
partition predicate =
|
||||||
|
acc = this.fold (Pair here.new_builder here.new_builder) acc-> elem->
|
||||||
|
case predicate elem of
|
||||||
|
True ->
|
||||||
|
Pair (acc.first.append elem) acc.second
|
||||||
|
False ->
|
||||||
|
Pair acc.first (acc.second.append elem)
|
||||||
|
acc.map .to_vector
|
||||||
|
|
||||||
|
## Partitions the vector into vectors of elements which satisfy a given
|
||||||
|
predicate and ones that do not.
|
||||||
|
|
||||||
|
Returns a `Pair` whose `first` element is the vector of elements
|
||||||
|
satisfying the predicate and the `second` element is a vector of elements
|
||||||
|
which did not satisfy it.
|
||||||
|
|
||||||
|
The relative order of elements kept in each returned list is the same as
|
||||||
|
in the input vector.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- predicate: A function that takes an index and an element and returns a
|
||||||
|
boolean value.
|
||||||
|
|
||||||
|
> Example
|
||||||
|
Splitting a vector into elements at even and odd positions.
|
||||||
|
|
||||||
|
["a", "b", "c", "d"].partition_with_index (ix -> _ -> ix % 2 == 0) == (Pair ["a", "c"] ["b", "d"])
|
||||||
|
partition_with_index : (Integer -> Any -> Boolean) -> Vector Any
|
||||||
|
partition_with_index predicate =
|
||||||
|
acc = this.fold (Partition_Accumulator here.new_builder here.new_builder 0) acc-> elem->
|
||||||
|
case predicate acc.ix elem of
|
||||||
|
True ->
|
||||||
|
Partition_Accumulator (acc.true_builder.append elem) acc.false_builder acc.ix+1
|
||||||
|
False ->
|
||||||
|
Partition_Accumulator acc.true_builder (acc.false_builder.append elem) acc.ix+1
|
||||||
|
case acc of
|
||||||
|
Partition_Accumulator true_builder false_builder _ ->
|
||||||
|
Pair true_builder.to_vector false_builder.to_vector
|
||||||
|
|
||||||
## Applies a function to each element of the vector, returning the vector of
|
## Applies a function to each element of the vector, returning the vector of
|
||||||
results.
|
results.
|
||||||
@ -318,7 +425,7 @@ type Vector
|
|||||||
[1, 2, 3] . map +1
|
[1, 2, 3] . map +1
|
||||||
map : (Any -> Any) -> Vector Any
|
map : (Any -> Any) -> Vector Any
|
||||||
map function =
|
map function =
|
||||||
here.new this.length i-> function (this.at i)
|
here.new this.length i-> function (this.unsafe_at i)
|
||||||
|
|
||||||
## Applies a function to each element of the vector, returning the vector
|
## Applies a function to each element of the vector, returning the vector
|
||||||
that contains all results concatenated.
|
that contains all results concatenated.
|
||||||
@ -356,7 +463,7 @@ type Vector
|
|||||||
|
|
||||||
[1, 2, 3].map_with_index (+)
|
[1, 2, 3].map_with_index (+)
|
||||||
map_with_index : (Integer -> Any -> Any) -> Vector Any
|
map_with_index : (Integer -> Any -> Any) -> Vector Any
|
||||||
map_with_index function = here.new this.length i-> function i (this.at i)
|
map_with_index function = here.new this.length i-> function i (this.unsafe_at i)
|
||||||
|
|
||||||
## Applies a function to each element of the vector.
|
## Applies a function to each element of the vector.
|
||||||
|
|
||||||
@ -372,8 +479,8 @@ type Vector
|
|||||||
[1, 2, 3, 4, 5] . each IO.println
|
[1, 2, 3, 4, 5] . each IO.println
|
||||||
each : (Any -> Any) -> Nothing
|
each : (Any -> Any) -> Nothing
|
||||||
each f =
|
each f =
|
||||||
this.map f
|
0.up_to this.length . each ix->
|
||||||
Nothing
|
f (this.unsafe_at ix)
|
||||||
|
|
||||||
## Reverses the vector, returning a vector with the same elements, but in
|
## Reverses the vector, returning a vector with the same elements, but in
|
||||||
the opposite order.
|
the opposite order.
|
||||||
@ -383,7 +490,7 @@ type Vector
|
|||||||
|
|
||||||
[1, 2].reverse
|
[1, 2].reverse
|
||||||
reverse : Vector Any
|
reverse : Vector Any
|
||||||
reverse = here.new this.length (i -> this.at (this.length - (1 + i)))
|
reverse = here.new this.length (i -> this.unsafe_at (this.length - (1 + i)))
|
||||||
|
|
||||||
## Generates a human-readable text representation of the vector.
|
## Generates a human-readable text representation of the vector.
|
||||||
|
|
||||||
@ -392,12 +499,30 @@ type Vector
|
|||||||
|
|
||||||
[1, 2, 3].to_text == "[1, 2, 3]"
|
[1, 2, 3].to_text == "[1, 2, 3]"
|
||||||
to_text : Text
|
to_text : Text
|
||||||
to_text =
|
to_text = this.map .to_text . join ", " "[" "]"
|
||||||
if this.length == 0 then "[]" else
|
|
||||||
if this.length == 1 then "[" + (this.at 0 . to_text) + "]" else
|
## UNSTABLE
|
||||||
folder = str -> ix -> str + ", " + (this.at ix).to_text
|
Generates a human-readable text representation of the vector, keeping its
|
||||||
tail_elems = 1.up_to this.length . fold "" folder
|
length limited.
|
||||||
"[" + (this.at 0 . to_text) + tail_elems + "]"
|
|
||||||
|
Arguments:
|
||||||
|
- max_entries: The maximum number of entries that are displayed. If the
|
||||||
|
vector contains more elements, the number of hidden elements is also
|
||||||
|
displayed.
|
||||||
|
|
||||||
|
> Example
|
||||||
|
Convert a large vector of numbers to a short text.
|
||||||
|
|
||||||
|
(0.up_to 100).to_vector.short_display_text max_entries=2 == "[0, 1 and 98 more elements]"
|
||||||
|
short_display_text : Integer -> Text
|
||||||
|
short_display_text max_entries=10 =
|
||||||
|
if max_entries < 1 then Error.throw <| Illegal_Argument_Error "The `max_entries` parameter must be positive." else
|
||||||
|
prefix = this.take_start max_entries
|
||||||
|
if prefix.length == this.length then this.to_text else
|
||||||
|
remaining_count = this.length - prefix.length
|
||||||
|
remaining_text = if remaining_count == 1 then "and 1 more element" else
|
||||||
|
"and " + remaining_count.to_text + " more elements"
|
||||||
|
prefix.map .to_text . join ", " "[" " "+remaining_text+"]"
|
||||||
|
|
||||||
## Checks whether this vector is equal to `that`.
|
## Checks whether this vector is equal to `that`.
|
||||||
|
|
||||||
@ -413,7 +538,7 @@ type Vector
|
|||||||
[1, 2, 3] == [2, 3, 4]
|
[1, 2, 3] == [2, 3, 4]
|
||||||
== : Vector -> Boolean
|
== : Vector -> Boolean
|
||||||
== that =
|
== that =
|
||||||
eq_at i = this.at i == that.at i
|
eq_at i = this.unsafe_at i == that.unsafe_at i
|
||||||
if this.length == that.length then 0.up_to this.length . all eq_at else False
|
if this.length == that.length then 0.up_to this.length . all eq_at else False
|
||||||
|
|
||||||
## Concatenates two vectors, resulting in a new vector, containing all the
|
## Concatenates two vectors, resulting in a new vector, containing all the
|
||||||
@ -431,9 +556,9 @@ type Vector
|
|||||||
this_len = this.length
|
this_len = this.length
|
||||||
arr = Array.new (this_len + that.length)
|
arr = Array.new (this_len + that.length)
|
||||||
0.up_to this_len . each i->
|
0.up_to this_len . each i->
|
||||||
arr.set_at i (this.at i)
|
arr.set_at i (this.unsafe_at i)
|
||||||
this.length.up_to arr.length . each i->
|
this.length.up_to arr.length . each i->
|
||||||
arr.set_at i (that.at i-this_len)
|
arr.set_at i (that.unsafe_at i-this_len)
|
||||||
Vector arr
|
Vector arr
|
||||||
|
|
||||||
## Add `element` to the beginning of `this` vector.
|
## Add `element` to the beginning of `this` vector.
|
||||||
@ -464,17 +589,19 @@ type Vector
|
|||||||
interspersing them with `separator`.
|
interspersing them with `separator`.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- separator: The text to use to join the textual elements of the vector.
|
- separator (optional): The text to use to join the textual elements of the vector.
|
||||||
|
- prefix (optional): The prefix to add at the beginning.
|
||||||
|
- suffix (optional): The suffix to add at the end.
|
||||||
|
|
||||||
> Example
|
> Example
|
||||||
Join the elements of the vector together as a string.
|
Join the elements of the vector together as a string.
|
||||||
|
|
||||||
["foo", "bar", "baz"].join ", "
|
["foo", "bar", "baz"].join ", "
|
||||||
join : String -> Text
|
join : Text -> Text
|
||||||
join separator =
|
join separator="" prefix="" suffix="" =
|
||||||
if this.length == 0 then "" else
|
if this.length == 0 then prefix+suffix else
|
||||||
if this.length == 1 then this.at 0 else
|
if this.length == 1 then prefix + this.unsafe_at 0 + suffix else
|
||||||
this.at 0 + (1.up_to this.length . fold "" acc-> i-> acc + separator + this.at i)
|
prefix + this.unsafe_at 0 + (1.up_to this.length . fold "" acc-> i-> acc + separator + this.unsafe_at i) + suffix
|
||||||
|
|
||||||
## Creates a new vector with the first `count` elements in `this` removed.
|
## Creates a new vector with the first `count` elements in `this` removed.
|
||||||
|
|
||||||
@ -487,7 +614,7 @@ type Vector
|
|||||||
[1, 2, 3, 4, 5].drop_start 1
|
[1, 2, 3, 4, 5].drop_start 1
|
||||||
drop_start : Integer -> Vector Any
|
drop_start : Integer -> Vector Any
|
||||||
drop_start count = if count >= this.length then here.new 0 (x -> x) else
|
drop_start count = if count >= this.length then here.new 0 (x -> x) else
|
||||||
here.new (this.length - count) (i -> this.at i+count)
|
here.new (this.length - count) (i -> this.unsafe_at i+count)
|
||||||
|
|
||||||
## Creates a new vector with the last `count` elements in `this` removed.
|
## Creates a new vector with the last `count` elements in `this` removed.
|
||||||
|
|
||||||
@ -554,7 +681,7 @@ type Vector
|
|||||||
zip : Vector Any -> (Any -> Any -> Any) -> Vector Any
|
zip : Vector Any -> (Any -> Any -> Any) -> Vector Any
|
||||||
zip that function=[_,_] =
|
zip that function=[_,_] =
|
||||||
len = Math.min this.length that.length
|
len = Math.min this.length that.length
|
||||||
here.new len i-> function (this.at i) (that.at i)
|
here.new len i-> function (this.unsafe_at i) (that.unsafe_at i)
|
||||||
|
|
||||||
## Extend `this` vector to the length of `n` appending elements `elem` to
|
## Extend `this` vector to the length of `n` appending elements `elem` to
|
||||||
the end.
|
the end.
|
||||||
@ -597,7 +724,7 @@ type Vector
|
|||||||
|
|
||||||
[1, 2, 3, 4].head
|
[1, 2, 3, 4].head
|
||||||
head : Any ! Empty_Error
|
head : Any ! Empty_Error
|
||||||
head = if this.length >= 1 then this.at 0 else Error.throw Empty_Error
|
head = if this.length >= 1 then this.unsafe_at 0 else Error.throw Empty_Error
|
||||||
|
|
||||||
## Get all elements in the vector except the first.
|
## Get all elements in the vector except the first.
|
||||||
|
|
||||||
@ -626,7 +753,7 @@ type Vector
|
|||||||
|
|
||||||
[1, 2, 3, 4].last
|
[1, 2, 3, 4].last
|
||||||
last : Vector ! Empty_Error
|
last : Vector ! Empty_Error
|
||||||
last = if this.length >= 1 then (this.take_end 1).at 0 else
|
last = if this.length >= 1 then this.unsafe_at (this.length-1) else
|
||||||
Error.throw Empty_Error
|
Error.throw Empty_Error
|
||||||
|
|
||||||
## Get the first element from the vector, or an `Empty_Error` if the vector
|
## Get the first element from the vector, or an `Empty_Error` if the vector
|
||||||
@ -649,7 +776,7 @@ type Vector
|
|||||||
|
|
||||||
[1, 2, 3, 4].second
|
[1, 2, 3, 4].second
|
||||||
second : Vector ! Singleton_Error
|
second : Vector ! Singleton_Error
|
||||||
second = if this.length >= 2 then this.at 1 else
|
second = if this.length >= 2 then this.unsafe_at 1 else
|
||||||
Error.throw (Singleton_Error this)
|
Error.throw (Singleton_Error this)
|
||||||
|
|
||||||
## Get all elements in the vector except the first.
|
## Get all elements in the vector except the first.
|
||||||
@ -813,13 +940,12 @@ type Builder
|
|||||||
Construct a vector using a builder that contains the items 1 to 10.
|
Construct a vector using a builder that contains the items 1 to 10.
|
||||||
|
|
||||||
example_new_builder =
|
example_new_builder =
|
||||||
builder = Vector.new_builder
|
do_build builder start stop =
|
||||||
do_build start stop =
|
new_builder = builder.append start
|
||||||
builder.append start
|
if start >= stop then new_builder else
|
||||||
if start >= stop then Nothing else
|
@Tail_Call do_build new_builder start+1 stop
|
||||||
@Tail_Call do_build start+1 stop
|
builder = do_build Vector.new_builder 1 10
|
||||||
do_build 1 10
|
builder.to_vector
|
||||||
builder.to_vector
|
|
||||||
type Builder to_array length
|
type Builder to_array length
|
||||||
|
|
||||||
## Creates a new builder.
|
## Creates a new builder.
|
||||||
@ -841,7 +967,33 @@ type Builder
|
|||||||
capacity : Integer
|
capacity : Integer
|
||||||
capacity = this.to_array.length
|
capacity = this.to_array.length
|
||||||
|
|
||||||
## Appends a new element into this builder.
|
## Appends a new element into this builder and returns it, propagating any
|
||||||
|
errors that the provided element could have contained.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- item: The item to append to the vector builder.
|
||||||
|
|
||||||
|
> Example
|
||||||
|
Append two items.
|
||||||
|
|
||||||
|
builder = Vector.new_builder
|
||||||
|
builder . append 10 . append 20
|
||||||
|
append : Any ! Error -> Builder ! Error
|
||||||
|
append item = case item of
|
||||||
|
_ ->
|
||||||
|
this.unsafe_append item
|
||||||
|
this
|
||||||
|
|
||||||
|
## PRIVATE
|
||||||
|
Appends a new element into this builder.
|
||||||
|
|
||||||
|
? Propagating Dataflow Errors
|
||||||
|
Since this is an imperative operation which returns Nothing, if the
|
||||||
|
item to be appended contained a dataflow error, the operation will fail
|
||||||
|
and unless its result is inspected, the error can very easily be
|
||||||
|
ignored. To avoid this, prefer to use the `append` operation and
|
||||||
|
consume the returned builder which will contain any dataflow errors if
|
||||||
|
they need to be propagated.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- item: The item to append to the vector builder.
|
- item: The item to append to the vector builder.
|
||||||
@ -849,9 +1001,9 @@ type Builder
|
|||||||
> Example
|
> Example
|
||||||
Append an item to a vector builder.
|
Append an item to a vector builder.
|
||||||
|
|
||||||
Vector.new_builder.append 10
|
Vector.new_builder.unsafe_append 10
|
||||||
append : Any -> Nothing
|
unsafe_append : Any -> Nothing
|
||||||
append item = case this.capacity > this.length of
|
unsafe_append item = case this.capacity > this.length of
|
||||||
True ->
|
True ->
|
||||||
this.to_array.set_at this.length item
|
this.to_array.set_at this.length item
|
||||||
Unsafe.set_atom_field this 1 (this.length + 1)
|
Unsafe.set_atom_field this 1 (this.length + 1)
|
||||||
@ -940,6 +1092,8 @@ Singleton_Error.to_display_text : Text
|
|||||||
Singleton_Error.to_display_text =
|
Singleton_Error.to_display_text =
|
||||||
"The vector " + this.vec.to_text + " has only one element."
|
"The vector " + this.vec.to_text + " has only one element."
|
||||||
|
|
||||||
|
## PRIVATE
|
||||||
|
type Partition_Accumulator true_builder false_builder ix
|
||||||
|
|
||||||
## UNSTABLE
|
## UNSTABLE
|
||||||
|
|
||||||
|
@ -12,3 +12,15 @@ type Illegal_State_Error
|
|||||||
performed.
|
performed.
|
||||||
- cause: (optional) another error that is the cause of this one.
|
- cause: (optional) another error that is the cause of this one.
|
||||||
type Illegal_State_Error message cause=Nothing
|
type Illegal_State_Error message cause=Nothing
|
||||||
|
|
||||||
|
type Illegal_Argument_Error
|
||||||
|
|
||||||
|
## UNSTABLE
|
||||||
|
|
||||||
|
A generic error that indicates that the provided argument is not valid
|
||||||
|
for the operation.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- message: the error message explaining why the argument is illegal.
|
||||||
|
- cause: (optional) another error that is the cause of this one.
|
||||||
|
type Illegal_Argument_Error message cause=Nothing
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.mutable;
|
package org.enso.interpreter.node.expression.builtin.mutable;
|
||||||
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import org.enso.interpreter.Language;
|
||||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||||
|
import org.enso.interpreter.runtime.builtin.Builtins;
|
||||||
import org.enso.interpreter.runtime.data.Array;
|
import org.enso.interpreter.runtime.data.Array;
|
||||||
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
|
|
||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "Array",
|
type = "Array",
|
||||||
@ -11,6 +14,11 @@ import org.enso.interpreter.runtime.data.Array;
|
|||||||
public class GetAtNode extends Node {
|
public class GetAtNode extends Node {
|
||||||
|
|
||||||
Object execute(Array _this, long index) {
|
Object execute(Array _this, long index) {
|
||||||
return _this.getItems()[(int) index];
|
try {
|
||||||
|
return _this.getItems()[(int) index];
|
||||||
|
} catch (IndexOutOfBoundsException exception) {
|
||||||
|
Builtins builtins = lookupContextReference(Language.class).get().getBuiltins();
|
||||||
|
throw new PanicException(builtins.error().makeInvalidArrayIndexError(_this, index), this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.mutable;
|
package org.enso.interpreter.node.expression.builtin.mutable;
|
||||||
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import org.enso.interpreter.Language;
|
||||||
import org.enso.interpreter.dsl.AcceptsError;
|
import org.enso.interpreter.dsl.AcceptsError;
|
||||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||||
|
import org.enso.interpreter.runtime.builtin.Builtins;
|
||||||
import org.enso.interpreter.runtime.data.Array;
|
import org.enso.interpreter.runtime.data.Array;
|
||||||
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
|
|
||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "Array",
|
type = "Array",
|
||||||
@ -12,7 +15,12 @@ import org.enso.interpreter.runtime.data.Array;
|
|||||||
public class SetAtNode extends Node {
|
public class SetAtNode extends Node {
|
||||||
|
|
||||||
Object execute(Array _this, long index, @AcceptsError Object value) {
|
Object execute(Array _this, long index, @AcceptsError Object value) {
|
||||||
_this.getItems()[(int) index] = value;
|
try {
|
||||||
return _this;
|
_this.getItems()[(int) index] = value;
|
||||||
|
return _this;
|
||||||
|
} catch (IndexOutOfBoundsException exception) {
|
||||||
|
Builtins builtins = lookupContextReference(Language.class).get().getBuiltins();
|
||||||
|
throw new PanicException(builtins.error().makeInvalidArrayIndexError(_this, index), this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -889,6 +889,10 @@ type Array
|
|||||||
Arguments:
|
Arguments:
|
||||||
- index: The index to get the element from.
|
- index: The index to get the element from.
|
||||||
|
|
||||||
|
? Safety
|
||||||
|
If index < 0 or index >= this.length, then this operation will result
|
||||||
|
in an Invalid_Array_Index_Error exception.
|
||||||
|
|
||||||
> Example
|
> Example
|
||||||
Get the element at index 1.
|
Get the element at index 1.
|
||||||
|
|
||||||
@ -907,8 +911,8 @@ type Array
|
|||||||
programming style in Enso.
|
programming style in Enso.
|
||||||
|
|
||||||
? Safety
|
? Safety
|
||||||
If index >= this.length, then this operation will result in an
|
If index < 0 or index >= this.length, then this operation will result
|
||||||
Invalid_Array_Index_Error exception.
|
in an Invalid_Array_Index_Error exception.
|
||||||
set_at : Integer -> Any -> Array
|
set_at : Integer -> Any -> Array
|
||||||
set_at index value = @Builtin_Method "Array.set_at"
|
set_at index value = @Builtin_Method "Array.set_at"
|
||||||
|
|
||||||
|
@ -6,68 +6,25 @@ polyglot java import java.util.Random
|
|||||||
polyglot java import org.enso.base.Time_Utils
|
polyglot java import org.enso.base.Time_Utils
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Bench Utilities ============================================================
|
## Bench Utilities ============================================================
|
||||||
|
|
||||||
vector_size = 1000000
|
vector_size = 1000000
|
||||||
iter_size = 100
|
iter_size = 100
|
||||||
num_iterations = 10
|
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
|
|
||||||
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 : Integer -> Base.Vector.Vector
|
||||||
make_random_vec n =
|
make_random_vec n =
|
||||||
random_gen = Random.new n
|
random_gen = Random.new n
|
||||||
Base.Vector.fill n random_gen.nextLong
|
Base.Vector.fill n random_gen.nextLong
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# The Benchmarks ==============================================================
|
# The Benchmarks ==============================================================
|
||||||
|
|
||||||
main =
|
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
|
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 (random_vec.filter (x -> x % 3 == 1)) "Filter" 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
|
|
||||||
|
|
||||||
|
stateful_fun x =
|
||||||
|
s = State.get Number
|
||||||
|
State.put s+x
|
||||||
|
Bench.measure (State.run Number 0 <| random_vec.each stateful_fun) "Each" here.iter_size here.num_iterations
|
||||||
|
68
test/Benchmarks/src/Vector_Sort.enso
Normal file
68
test/Benchmarks/src/Vector_Sort.enso
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
from Standard.Base import all
|
||||||
|
|
||||||
|
import Standard.Test.Bench
|
||||||
|
|
||||||
|
import project.Vector as Vector_Utils
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
# 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 = Vector_Utils.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
|
@ -10,3 +10,19 @@ spec = Test.group "Arrays" <|
|
|||||||
as_vec = json.into (Vector.Vector Number)
|
as_vec = json.into (Vector.Vector Number)
|
||||||
as_vec.should_equal <| Vector.fill 100 0
|
as_vec.should_equal <| Vector.fill 100 0
|
||||||
|
|
||||||
|
Test.specify "should allow accessing elements"
|
||||||
|
arr = [1, 2, 3] . to_array
|
||||||
|
arr.at 0 . should_equal 1
|
||||||
|
arr.at 2 . should_equal 3
|
||||||
|
|
||||||
|
Test.specify "should allow setting elements"
|
||||||
|
arr = [1, 2, 3] . to_array
|
||||||
|
arr.set_at 1 10
|
||||||
|
arr.at 1 . should_equal 10
|
||||||
|
Vector.from_array arr . should_equal [1, 10, 3]
|
||||||
|
|
||||||
|
Test.specify "should panic on out of bounds access"
|
||||||
|
arr = [1, 2, 3] . to_array
|
||||||
|
Test.expect_panic_with (arr.at -1) Invalid_Array_Index_Error
|
||||||
|
Test.expect_panic_with (arr.at 3) Invalid_Array_Index_Error
|
||||||
|
Test.expect_panic_with (arr.set_at 3 100) Invalid_Array_Index_Error
|
||||||
|
@ -26,8 +26,23 @@ spec = Test.group "Vectors" <|
|
|||||||
built . should_equal [1, 2, 3, 4, 5]
|
built . should_equal [1, 2, 3, 4, 5]
|
||||||
|
|
||||||
Test.specify "should allow accessing elements" <|
|
Test.specify "should allow accessing elements" <|
|
||||||
|
[1,2,3].at 0 . should_equal 1
|
||||||
[1,2,3].at 2 . should_equal 3
|
[1,2,3].at 2 . should_equal 3
|
||||||
|
|
||||||
|
Test.specify "should allow to store dataflow errors and raise them on access" <|
|
||||||
|
vec = [Error.throw (My_Error "foo"), "bar"]
|
||||||
|
vec.at 1 . should_equal "bar"
|
||||||
|
vec.at 0 . should_fail_with My_Error
|
||||||
|
|
||||||
|
Test.specify "should allow accessing elements with negative indices" <|
|
||||||
|
[1,2,3].at -1 . should_equal 3
|
||||||
|
[1,2,3].at -2 . should_equal 2
|
||||||
|
[1,2,3].at -3 . should_equal 1
|
||||||
|
|
||||||
|
Test.specify "should return a dataflow error when accessing elements out of bounds" <|
|
||||||
|
[1,2,3].at -4 . should_fail_with Vector.Index_Out_Of_Bounds_Error
|
||||||
|
[1,2,3].at 3 . should_fail_with Vector.Index_Out_Of_Bounds_Error
|
||||||
|
|
||||||
Test.specify "should have a well-defined length" <|
|
Test.specify "should have a well-defined length" <|
|
||||||
[1,2,3].length . should_equal 3
|
[1,2,3].length . should_equal 3
|
||||||
|
|
||||||
@ -77,9 +92,25 @@ spec = Test.group "Vectors" <|
|
|||||||
|
|
||||||
Test.specify "should filter elements" <|
|
Test.specify "should filter elements" <|
|
||||||
vec = [1, 2, 3, 4, 5]
|
vec = [1, 2, 3, 4, 5]
|
||||||
vec.filter (ix -> ix > 3) . should_equal [4, 5]
|
vec.filter (x -> x > 3) . should_equal [4, 5]
|
||||||
vec.filter (ix -> ix == 1) . should_equal [1]
|
vec.filter (x -> x == 1) . should_equal [1]
|
||||||
vec.filter (ix -> ix < 0) . should_equal []
|
vec.filter (x -> x < 0) . should_equal []
|
||||||
|
vec.filter (x -> if x == 2 then Error.throw <| My_Error "foo" else True) . should_fail_with My_Error
|
||||||
|
|
||||||
|
Test.specify "should filter elements with indices" <|
|
||||||
|
[0, 10, 2, 2].filter_with_index (==) . should_equal [0, 2]
|
||||||
|
([1, 2, 3, 4].filter_with_index ix-> _-> ix < 2) . should_equal [1, 2]
|
||||||
|
([1, 2, 3, 4].filter_with_index ix-> _-> if ix == 1 then Error.throw <| My_Error "foo" else True) . should_fail_with My_Error
|
||||||
|
|
||||||
|
Test.specify "should partition elements" <|
|
||||||
|
[1, 2, 3, 4, 5].partition (x -> x % 2 == 0) . should_equal <| Pair [2, 4] [1, 3, 5]
|
||||||
|
([1, 2, 3, 4].partition x-> if x == 1 then Error.throw <| My_Error "foo" else True) . should_fail_with My_Error
|
||||||
|
["a", "b", "c", "d"].partition_with_index (ix -> _ -> ix % 2 == 0) == (Pair ["a", "c"] ["b", "d"])
|
||||||
|
["a", "b", "c", "d"].partition_with_index (ix -> _ -> if ix % 2 == 0 then Error.throw <| My_Error "foo" else True) . should_fail_with My_Error
|
||||||
|
|
||||||
|
Test.specify "should allow to join a vector of text elements to form a single text" <|
|
||||||
|
["a", "b", "c"].join . should_equal "abc"
|
||||||
|
["a", "b", "c"].join ";" "{" "}" . should_equal "{a;b;c}"
|
||||||
|
|
||||||
Test.specify "should allow mapping an operation, returning a new vector" <|
|
Test.specify "should allow mapping an operation, returning a new vector" <|
|
||||||
vec = [1, 2, 3, 4]
|
vec = [1, 2, 3, 4]
|
||||||
@ -105,6 +136,18 @@ spec = Test.group "Vectors" <|
|
|||||||
[].to_text.should_equal "[]"
|
[].to_text.should_equal "[]"
|
||||||
[1,2,3].to_text.should_equal "[1, 2, 3]"
|
[1,2,3].to_text.should_equal "[1, 2, 3]"
|
||||||
[Nothing].to_text.should_equal "[Nothing]"
|
[Nothing].to_text.should_equal "[Nothing]"
|
||||||
|
['a'].to_text . should_equal "['a']"
|
||||||
|
|
||||||
|
Test.specify "should allow to generate a short text representation for display" <|
|
||||||
|
[].short_display_text max_entries=3 . should_equal "[]"
|
||||||
|
[1].short_display_text max_entries=3 . should_equal "[1]"
|
||||||
|
[1, 2].short_display_text max_entries=3 . should_equal "[1, 2]"
|
||||||
|
[1, 2, 3].short_display_text max_entries=3 . should_equal "[1, 2, 3]"
|
||||||
|
[1, 2, 3, 4].short_display_text max_entries=3 . should_equal "[1, 2, 3 and 1 more element]"
|
||||||
|
[1, 2, 3, 4, 5, 6].short_display_text max_entries=3 . should_equal "[1, 2, 3 and 3 more elements]"
|
||||||
|
(0.up_to 100).to_vector.short_display_text max_entries=2 . should_equal "[0, 1 and 98 more elements]"
|
||||||
|
|
||||||
|
[].short_display_text max_entries=0 . should_fail_with Illegal_Argument_Error
|
||||||
|
|
||||||
Test.specify "should define equality" <|
|
Test.specify "should define equality" <|
|
||||||
[1,2,3]==[1,2] . should_be_false
|
[1,2,3]==[1,2] . should_be_false
|
||||||
|
Loading…
Reference in New Issue
Block a user