///|
/// A mutable one-dimensional tick view over a shared numeric buffer.
/// Locations and preset results retain their source buffer and stride.
pub struct TickValues {
priv buffer : TickBuffer
priv start : Int32
priv stride : Int64
priv length : Int32
}
///|
priv enum TickBuffer {
Float64(Array[Double])
Integer64(Array[Int64])
}
///|
fn TickBuffer::length(self : TickBuffer) -> Int32 {
match self {
Float64(values) => values.length()
Integer64(values) => values.length()
}
}
///|
/// Borrow Int64 storage. Fractional assignments truncate; nonfinite or overflow
/// assignments raise DataError. Views and copies retain the storage type.
pub fn TickValues::from_int64_array(values : Array[Int64]) -> TickValues {
{ buffer: Integer64(values), start: 0, stride: 1L, length: values.length(), }
}
///|
fn TickValues::is_int64(self : TickValues) -> Bool {
self.buffer is Integer64(_)
}
///|
fn tick_integer_value(value : Double) -> Int64 raise @core.DataError {
if value.is_nan() ||
value.is_inf() ||
value < -9223372036854775808.0 ||
value >= 9223372036854775808.0 {
raise @core.DataError::InvalidTicks(
message="tick value cannot be assigned to an Int64 buffer",
)
}
value.to_int64()
}
///|
fn TickValues::with_endpoints(
self : TickValues,
prepend : Bool,
append : Bool,
) -> TickValues raise @core.DataError {
if self.is_int64() {
let integers : Array[Int64] = []
if prepend {
integers.push(1L)
}
for index in 0.. Int64 raise @core.DataError {
let index = self.buffer_index(index)
match self.buffer {
Integer64(values) => values[index]
Float64(_) =>
raise @core.DataError::InvalidTicks(
message="tick buffer is not Int64 storage",
)
}
}
///|
/// Borrow the current shape of an array without copying its values.
pub fn TickValues::from_array(values : Array[Double]) -> TickValues {
tick_values_view(values, 0, 1, values.length())
}
///|
fn tick_values_view(
buffer : Array[Double],
start : Int32,
stride : Int32,
length : Int32,
) -> TickValues {
{ buffer: Float64(buffer), start, stride: Int64::from_int(stride), length, }
}
///|
pub fn TickValues::length(self : TickValues) -> Int32 {
self.length
}
///|
fn TickValues::buffer_index(
self : TickValues,
index : Int32,
) -> Int32 raise @core.DataError {
let index = if index < 0 { self.length + index } else { index }
if index < 0 || index >= self.length {
raise @core.DataError::InvalidTicks(
message="tick view index is out of bounds",
)
}
let position = Int64::from_int(self.start) +
Int64::from_int(index) * self.stride
if position < 0L || position >= Int64::from_int(self.buffer.length()) {
raise @core.DataError::InvalidTicks(
message="tick view buffer shape has changed",
)
}
position.to_int()
}
///|
/// Borrow a strided portion of this view, retaining its original buffer.
/// A negative start counts from the end; a negative stride reverses direction.
pub fn TickValues::view(
self : TickValues,
start : Int32,
stride : Int32,
length : Int32,
) -> TickValues raise @core.DataError {
if length < 0 {
raise @core.DataError::InvalidTicks(
message="tick view length must be nonnegative",
)
}
if length == 0 {
return { buffer: self.buffer, start: 0, stride: 1L, length: 0, }
}
let start = if start < 0 { self.length + start } else { start }
let end = Int64::from_int(start) +
Int64::from_int(stride) * Int64::from_int(length - 1)
if start < 0 ||
start >= self.length ||
end < 0L ||
end >= Int64::from_int(self.length) {
raise @core.DataError::InvalidTicks(
message="tick view extends beyond its parent",
)
}
let buffer_start = self.buffer_index(start)
ignore(self.buffer_index(end.to_int()))
let buffer_stride = if length == 1 {
0L
} else {
self.stride * Int64::from_int(stride)
}
{ buffer: self.buffer, start: buffer_start, stride: buffer_stride, length, }
}
///|
/// Read an element, with negative indices counted from the view's end.
pub fn TickValues::get(
self : TickValues,
index : Int32,
) -> Double raise @core.DataError {
let index = self.buffer_index(index)
match self.buffer {
Float64(values) => values[index]
Integer64(values) => values[index].to_double()
}
}
///|
pub fn TickValues::set(
self : TickValues,
index : Int32,
value : Double,
) -> Unit raise @core.DataError {
let index = self.buffer_index(index)
match self.buffer {
Float64(values) => values[index] = value
Integer64(values) => values[index] = tick_integer_value(value)
}
}
///|
/// Materialize an independent array containing every view element.
pub fn TickValues::to_array(
self : TickValues,
) -> Array[Double] raise @core.DataError {
let result = Array(capacity=self.length)
for index in 0.. TickValues raise @core.DataError {
match self.buffer {
Float64(_) => TickValues::from_array(self.to_array())
Integer64(values) => {
let copied : Array[Int64] = []
for index in 0.. TickValues raise @core.DataError {
if mask.length() != self.length {
raise @core.DataError::InvalidTicks(
message="tick selection mask shape differs from its view",
)
}
match self.buffer {
Integer64(_) => {
let selected : Array[Int64] = []
for index in 0.. {
let selected : Array[Double] = []
for index in 0.. Array[Double] raise @core.DataError {
let length = Int32::min(self.length, 100000)
let result = Array(capacity=length)
for index in 0..