Category talk:Wren-seq: Difference between revisions

Content added Content deleted
(→‎Source code: Added Lst.sortPart methods.)
(→‎Source code: Added View class.)
Line 487: Line 487:
// Returns the string representation of the underlying list.
// Returns the string representation of the underlying list.
toString { _stack.toString }
toString { _stack.toString }
}

/* View represents a fixed window into a list and behaves for many purposes like a slice.
However, unlike a slice, it does not create a new list but references the existing one
which saves memory and reduces pressure on the garbage collector.

Indexing of the view always starts at 0, and setting/swapping/sorting elements of
of the view will be reflected in the underlying list and vice versa. However, deletions
from the underlying list may invalidate the view bounds and insertions may 'move' it.
As in the case of the List class, views support negative indices.
*/
class View is Sequence {
// Creates a new View of a list between indices 'start' and 'end' inclusive.
construct new(lst, start, end) {
Lst.isList_(lst)
var c = lst.count
if (c == 0) Fiber.abort("List cannot be empty.")
if (start < 0) start = c + start
if (!(start is Num && start.isInteger && start>= 0 && start < c)) {
Fiber.abort("'start' is out of range.")
}
if (end < 0) end = c + end
if (!(end is Num && end.isInteger && end >= 0 && end < c)) {
Fiber.abort("'end' is out of range.")
}
if (start > end) {
Fiber.abort("'end' cannot be before 'start'.")
}
_lst = lst
_start = start
_end = end
_count = end - start + 1
}

// Self-evident properties
primary { _lst }
start { _start }
end { _end }
count { _count }

// Converts the view to a new independent list.
toList { _lst[_start.._end] }

// Gets or sets the value at index 'i' of the view (zero based).
[i] { (i >= 0) ?_lst[i + _start] : _lst[_count + i + _start] }

[i]=(v) {
if (i >= 0) _lst[i + _start] = v else _lst[_count + i + _start] = v
}

// Returns the index of 'v' in the view or -1 if it does not exist.
indexOf(v) {
for (i in 0..._count) {
if (_lst[i + _start] == v) return i
}
return -1
}

// Returns the last index of 'v' in the view or -1 if it does not exist.
lastIndexOf(v) {
for (i in _count-1..0) {
if (_lst[i + _start] == v) return i
}
return -1
}

// Returns whether or not the view contains the value 'v'
contains(v) { indexOf(v) >= 0 }

// Swaps the elements at indices 'i' and 'j' in the view.
swap(i, j) {
if (i < 0) i = _count + i
if (j < 0) j = _count + j
_lst.swap(i + _start, j + _start)
}

// Sorts the elements of the view in place using 'comparer' and returns it.
sort(comparer) {
Lst.sortPart(_lst, _start, _end, comparer)
return this
}

// Sorts the elements of the view in place using the default comparer and returns it.
sort() {
Lst.sortPart(_lst, _start, _end)
return this
}

// Sets all the elements of the view to the value 'v'.
setAll(v) {
for (i in _start.._end) _lst[i] = v
}

// Checks whether the view bounds are still valid following deletions from the underlying list.
// If false, do not use unless and until the view becomes valid again.
isValid { _end < _lst.count }

// Iteration protocol methods. Note that the indices returned (although not normally exposed)
// are those into the underlying list not the view itself.
iterate(iterator) {
if (!iterator) {
_taken = 1
return _start
}
_taken = _taken + 1
return _taken > _count ? null : _lst.iterate(iterator)
}

iteratorValue(iterator) { _lst.iteratorValue(iterator) }

// Returns the string representation of the view.
toString { "[" + _lst.skip(_start).take(_count).join(", ") + "]" }
}</lang>
}</lang>