"A [[Range]] of adjacent [[Enumerable]] values generated by two endpoints: [[first]] and [[last]]. The range includes both endpoints, and all values falling _between_ the endpoints." by ("Gavin") see (`class Measure`, `interface Enumerable`) final class Span<Element>(first, last) extends Range<Element>() given Element satisfies Enumerable<Element> { "The start of the range." shared actual Element first; "The end of the range." shared actual Element last; shared actual String string => first.string + ".." + last.string; shared actual Boolean increasing = last.offsetSign(first)>=0; shared actual Boolean decreasing => !increasing; "Determines if the range is of recursive values, that is, if successors wrap back on themselves. All recursive ranges are [[increasing]]." Boolean recursive = first.offsetSign(first.successor)>0 && last.predecessor.offsetSign(last)>0; Element next(Element x) => increasing then x.successor else x.predecessor; Element nextStep(Element x, Integer step) => increasing then x.neighbour(step) else x.neighbour(-step); Element fromFirst(Integer offset) => increasing then first.neighbour(offset) else first.neighbour(-offset); Boolean afterLast(Element x) => increasing then x.offsetSign(last)>0 else x.offsetSign(last)<0; Boolean beforeLast(Element x) => increasing then x.offsetSign(last)<0 else x.offsetSign(last)>0; Boolean beforeFirst(Element x) => increasing then x.offsetSign(first)<0 else x.offsetSign(first)>0; Boolean afterFirst(Element x) => increasing then x.offsetSign(first)>0 else x.offsetSign(first)<0; "The nonzero number of elements in the range." shared actual Integer size => last.offset(first).magnitude+1; shared actual Boolean longerThan(Integer length) { if (length<1) { return true; } else if (recursive) { return size>length; } else { return beforeLast(fromFirst(length-1)); } } shared actual Boolean shorterThan(Integer length) { if (length<1) { return true; } else if (recursive) { return size<length; } else { return afterLast(fromFirst(length-1)); } } "The index of the end of the range." shared actual Integer lastIndex => size-1; "The rest of the range, without the start of the range." shared actual Element[] rest => first==last then [] else next(first)..last; "This range in reverse, with [[first]] and [[last]] interchanged. For any two range endpoints, `x` and `y`: `(x..y).reversed == y..x` except for [[recursive]] ranges, where the elements are evaluated and collected into a new sequence." //TODO: we should have a way to produce a decreasing // recursive range shared actual [Element+] reversed => recursive then super.reversed else last..first; "The element of the range that occurs [[index]] values after the start of the range." shared actual Element? getFromFirst(Integer index) { if (index<0) { return null; } else if (recursive) { return index<size then fromFirst(index); } else { value result = fromFirst(index); return !afterLast(result) then result; } } "An iterator for the elements of the range. The returned iterator produces elements from [[first]] and continues producing elements until it reaches an element whose `offset` from [[last] is zero." shared actual Iterator<Element> iterator() { object iterator satisfies Iterator<Element> { variable Element|Finished current = first; shared actual Element|Finished next() { if (!is Finished c=current) { if (c.offset(last) != 0) { value result = c; this.current = outer.next(c); return result; } else { value result = c; this.current = finished; return result; } } else { return current; } } string => "(``outer.string``).iterator()"; } return iterator; } shared actual {Element+} by(Integer step) { "step size must be greater than zero" assert (step > 0); return step == 1 then this else By(step); } shared actual Span<Element> shifted(Integer shift) { if (shift==0) { return this; } else { value start = first.neighbour(shift); value end = last.neighbour(shift); return Span(start,end); } } shared actual Integer count(Boolean selecting(Element element)) { variable value element = first; variable value count = 0; while (containsElement(element)) { if (selecting(element)) { count++; } element = next(element); } return count; } "Determines if this range includes the given object." shared actual Boolean contains(Object element) { if (is Element element) { return containsElement(element); } else { return false; } } "Determines if this range includes the given value." shared actual Boolean occurs(Anything element) { if (is Element element) { return containsElement(element); } else { return false; } } "Determines if the range includes the given value." shared actual Boolean containsElement(Element x) => recursive then x.offset(first) <= last.offset(first) else !afterLast(x) && !beforeFirst(x); shared actual Boolean includes(List<Anything> sublist) { if (sublist.empty) { return true; } if (is Range<Element> sublist) { return includesRange(sublist); } else { return super.includes(sublist); /*if (is Element start = sublist.first) { if (decreasing then start>first || start<last else start<first || start>last) { return false; } variable value current=start; for (element in sublist) { if (exists element) { if (element!=current || decreasing then current<last else current>last) { return false; } current = next(current); } else { return false; } } else { return true; } } else { return false; }*/ } } shared actual Boolean includesRange(Range<Element> sublist) { switch (sublist) case (is Span<Element>) { if (recursive) { return sublist.first.offset(first)<size && sublist.last.offset(first)<size; } else { return increasing == sublist.increasing && !sublist.afterFirst(first) && !sublist.beforeLast(last); } } case (is Measure<Element>) { if (decreasing) { return false; } else { value offset = sublist.first.offset(first); return offset >= 0 && offset + sublist.size <= size; } } } shared actual Boolean equals(Object that) { if (is Span<Object> that) { //optimize for another Span return that.first==first && that.last==last; } else if (is Measure<Object> that) { return increasing && that.first == first && that.size == size; } else { //it might be another sort of List return super.equals(that); } } class By(Integer step) satisfies {Element+} { size => 1 + (outer.size-1) / step; first => outer.first; string => "(``outer.string`` by ``step``)"; shared actual Iterator<Element> iterator() { if (recursive) { object iterator satisfies Iterator<Element> { variable value count = 0; variable value current = first; shared actual Element|Finished next() { if (++count>size) { return finished; } else { value result = current; current = current.neighbour(step); return result; } } string => "``outer.string``.iterator()"; } return iterator; } else { object iterator satisfies Iterator<Element> { variable value current = first; shared actual Element|Finished next() { if (containsElement(current)) { value result = current; current = nextStep(current, step); return result; } else { return finished; } } string => "``outer.string``.iterator()"; } return iterator; } } } shared actual [Element*] measure(Integer from, Integer length) => length<=0 then [] else span(from, from+length-1); shared actual [Element*] span(Integer from, Integer to) { if (from<=to) { if (to<0 || !longerThan(from)) { return []; } else { return (this[from] else first)..(this[to] else last); } } else { if (from<0 || !longerThan(to)) { return []; } else { value range = (this[to] else first)..(this[from] else last); return range.reversed; } } } shared actual [Element*] spanFrom(Integer from) { if (from<=0) { return this; } else if (longerThan(from)) { assert (exists first = this[from]); return first..last; } else { return []; } } shared actual [Element*] spanTo(Integer to) { if (to<0) { return []; } else if (longerThan(to+1)) { assert (exists last = this[to]); return first..last; } else { return this; } } } "Produces a [[Range]] of adjacent [[Enumerable]] values generated by two endpoints: [[first]] and [[last]]. The range includes both endpoints, and all values falling _between_ the endpoints. - For a recursive enumerable type, a value falls between the endpoints if its [[offset|Enumerable.offset]] from `first` is less than the offset of `last` from `first`. - For a linear enumerable type, a value falls between the endpoints if the [[sign of its offset|Enumerable.offsetSign]] from `first` is the same as the sign of the offset of `last` from `first` and the sign of its offset from `last` is the opposite of the sign of the offset of `last` from `first`. More precisely, if `x`, `first`, and `last` are of `Enumerable` type `X`, then `x in first..last` if and only if: - `X` is recursive and `x.offset(first)<last.offset(first)`, or - `X` is linear and `x.offsetSign(first)==last.offsetSign(first)` and `x.offsetSign(last)==-last.offsetSign(first)`. For a linear enumerable type, a range is either [[increasing|Range.increasing]] or [[decreasing|Range.decreasing]]: - in an increasing range, a value occurs before its [[successor|Ordinal.successor]] and after its [[predecessor|Ordinal.predecessor]], but - in a decreasing range, a value occurs after its `successor` and before its `predecessor`. The direction of the range depends upon the sign of the offset of `last` from `first`: - if `last.offsetSign(first)>=0` the range is increasing, but - if `last.offsetSign(first)<0`, the range is decreasing. A range for a recursive enumerable type is always increasing. The _span operator_ `..` is an abbreviation for `span()`: for (i in min..max) { ... } if (char in 'A'..'Z') { ... } The span operator accepts the first and last values of the range. It may produce an increasing range: 0..5 // [0, 1, 2, 3, 4, 5] 0..0 // [0] Or it may produce a decreasing range: 5..0 // [5, 4, 3, 2, 1, 0] 0..-5 // [0, -1, -2, -3, -4, -5]" shared Range<Element> span<Element> (Element first, Element last) given Element satisfies Enumerable<Element> => Span(first, last);