diff --git a/language/src/ceylon/language/Range.ceylon b/language/src/ceylon/language/Range.ceylon index 004477144bd..11f758b3ea6 100644 --- a/language/src/ceylon/language/Range.ceylon +++ b/language/src/ceylon/language/Range.ceylon @@ -88,4 +88,66 @@ class Range() "Returns the range itself, since a range cannot contain duplicate elements." shared actual Range distinct => this; + + shared actual + Set union + (Collection collection) + => switch (collection) + case (Range) Union(this, collection) + case (Union) Union(this, *collection.ranges) + else super.union(collection); + } + +class Union(ranges) + satisfies Set + given Element satisfies Enumerable { + + shared Range+ ranges; + + function small(Range r) + => r.increasing then r.first else r.last; + function large(Range r) + => r.increasing then r.last else r.first; + + function before(Element x, Element y) + => x.offsetSign(y)<0; + + value minval = ranges.fold(small(ranges.first), + (p, r) => let (q=small(r)) + if (before(p,q)) then p else q); + value maxval = ranges.fold(large(ranges.first), + (p, r) => let (q=large(r)) + if (before(p,q)) then q else p); + + iterator() => object satisfies Iterator { + variable value current = minval; + shared actual Element|Finished next() { + if (before(maxval, current)) { + return finished; + } + value result = current; + while (!before(maxval, current)) { + current = current.successor; + if (current in outer) { + break; + } + } + return result; + } + }; + + contains(Object element) => ranges.any((r) => element in r); + + shared actual + Set union + (Collection collection) + => switch (collection) + case (Range) Union(*ranges.withTrailing(collection)) + case (Union) Union(*ranges.append(collection.ranges)) + else super.union(collection); + + equals(Object that) => (super of Set).equals(that); + hash => (super of Set).hash; + +} \ No newline at end of file diff --git a/language/test/lists.ceylon b/language/test/lists.ceylon index f0a61247742..194744bc13f 100644 --- a/language/test/lists.ceylon +++ b/language/test/lists.ceylon @@ -184,9 +184,6 @@ shared void lists() { mappedArraySequence(); - check((1..2)|(4..5) == set{1,2,4,5}, "union"); - check((1..3)&(3..5) == set{3}, "intersection"); - } shared void mappedArraySequence() { diff --git a/language/test/range.ceylon b/language/test/range.ceylon index 67ab11e5ab8..3f841dc9b27 100644 --- a/language/test/range.ceylon +++ b/language/test/range.ceylon @@ -61,4 +61,11 @@ shared void testRange() { check((1..3)[1...]==2..3, "range span from"); check((1..3)[1:1]==2..2, "range measure"); + check(2 in (1..2)|(4..5), "range union"); + check(!3 in (1..2)|(4..5), "range union"); + check(4 in (1..2)|(4..5), "range union"); + + check((1..2)|(4..5) == set{1,2,4,5}, "range union"); + check((1..3)&(3..5) == set{3}, "range intersection"); + } \ No newline at end of file diff --git a/language/test/sequences.ceylon b/language/test/sequences.ceylon index 37fa2d6e15b..eaf2d06bc5c 100644 --- a/language/test/sequences.ceylon +++ b/language/test/sequences.ceylon @@ -576,4 +576,11 @@ shared void sequences() { assert (is String[4] split); check(split == ["foo", "bar", "baz", "qux"], "tuple()"); + check(2 in [1,2]|[4,5], "sequence union"); + check(!3 in [1,2]|[4,5], "sequence union"); + check(4 in [1,2]|[4,5], "sequence union"); + + check([1,2]|[4,5] == set{1,2,4,5}, "sequence union"); + check([1,2,3]&[3,4,5] == set{3}, "sequence intersection"); + }