From a11ed1e1a283aa8a3182af4f6f3108ebb261ad23 Mon Sep 17 00:00:00 2001 From: Jack Firth Date: Mon, 19 Dec 2022 16:29:55 -0800 Subject: [PATCH 1/6] First pass at generic collection interfaces This is a very rough draft of a generic collection API for Rhombus. --- rhombus/data/collection.rhm | 47 +++++ rhombus/data/list.rhm | 84 ++++++++ rhombus/data/private/array_list.rhm | 184 ++++++++++++++++++ rhombus/data/private/list_builder.rhm | 35 ++++ rhombus/data/private/persistent_list.rhm | 11 ++ .../data/private/regular_immutable_list.rhm | 95 +++++++++ rhombus/data/private/small_lists.rhm | 86 ++++++++ rhombus/data/sequence.rhm | 16 ++ rhombus/private/precondition.rhm | 9 + 9 files changed, 567 insertions(+) create mode 100644 rhombus/data/collection.rhm create mode 100644 rhombus/data/list.rhm create mode 100644 rhombus/data/private/array_list.rhm create mode 100644 rhombus/data/private/list_builder.rhm create mode 100644 rhombus/data/private/persistent_list.rhm create mode 100644 rhombus/data/private/regular_immutable_list.rhm create mode 100644 rhombus/data/private/small_lists.rhm create mode 100644 rhombus/data/sequence.rhm create mode 100644 rhombus/private/precondition.rhm diff --git a/rhombus/data/collection.rhm b/rhombus/data/collection.rhm new file mode 100644 index 000000000..42556a1fe --- /dev/null +++ b/rhombus/data/collection.rhm @@ -0,0 +1,47 @@ +#lang rhombus + + +export: + Collection + ImmutableCollection + MutableCollection + + +import: + rhombus/data/sequence.Sequence + + +interface Collection: + extends Sequence + // read-only property + property size :: Integer + + method isEmpty() :: Boolean: size() == 0 + + method contains(element) :: Boolean: + let iterator = iterate() + fun loop(): + iterator.hasNext() && (iterator.next() == element || loop()) + loop() + + +interface ImmutableCollection: + extends Collection + method add(element) :: ImmutableCollection + method remove(element) :: ImmutableCollection + + +interface MutableCollection: + extends Collection + method add(element) :: Void + + method addAll(elements :: Sequence) :: Void: + let iterator = elements.iterate() + fun loop(): + when iterator.hasNext() + | add(iterator.next()) + loop() + loop() + + method remove(element) :: Void + method clear() :: Void diff --git a/rhombus/data/list.rhm b/rhombus/data/list.rhm new file mode 100644 index 000000000..09ec92b4a --- /dev/null +++ b/rhombus/data/list.rhm @@ -0,0 +1,84 @@ +#lang rhombus + + +export: + List + ImmutableList + MutableList + + +import: + rhombus/data/collection.Collection + rhombus/data/collection.ImmutableCollection + rhombus/data/collection.MutableCollection + rhombus/private/precondition.checkArgument + + +interface List: + extends Collection + + method get(index :: Integer) + method sublist(start :: Integer, end :: Integer) :: List + + method checkIndex(who, index): + checkArgument( + who, + index >= 0 && index < size(), + "index out of bounds", + "index", index, + "size", size()) + + method checkInsertionIndex(who, index): + checkArgument( + who, + index >= 0 && index <= size(), + "index out of bounds", + "index", index, + "size", size()) + + method checkSublistIndicies(who, start, end): + checkArgument( + who, + start >= 0 && start <= size(), + "sublist start index out of bounds", + "start index", start, + "end index", end, + "size", size()) + checkArgument( + who, + end >= 0 && end <= size(), + "sublist end index out of bounds", + "start index", start, + "end index", end, + "size", size()) + checkArgument( + who, + start <= end, + "sublist start index occurs after end index", + "start index", start, + "end index", end, + "size", size()) + + +interface ImmutableList: + extends: + List + ImmutableCollection + + method set(index :: Integer, element) :: ImmutableList + override add(element) :: ImmutableList + override remove(element) :: ImmutableList + method insert(index :: Integer, element) :: ImmutableList + method delete(index :: Integer) :: ImmutableList + override sublist(start :: Integer, end :: Integer) :: ImmutableList + + +interface MutableList: + extends: + List + MutableCollection + + method set(index :: Integer, element) :: Void + method insert(index :: Integer, element) :: Void + method delete(index :: Integer) :: Void + override sublist(start :: Integer, end :: Integer) :: MutableList diff --git a/rhombus/data/private/array_list.rhm b/rhombus/data/private/array_list.rhm new file mode 100644 index 000000000..8b394a62e --- /dev/null +++ b/rhombus/data/private/array_list.rhm @@ -0,0 +1,184 @@ +#lang rhombus + + +export: + ArrayList + + +import: + rhombus/data/list.MutableList + rhombus/data/sequence.Iterator + lib("racket/base.rkt").error + + +class ArrayList(): + implements MutableList + internal PrivateArrayList + + private field storage :: Array = Array() + private field currentSize :: Integer = 0 + + // This field tracks how many structural modifications the list has undergone. Changing an element + // is not a structural modification, but adding or removing an element is. + private field version :: Integer = 0 + + override method iterate(): ArrayListIterator(this) + + override property size(): currentSize + + override method get(index): + checkIndex("List.get", index) + storage[index] + + override method sublist(start, end): + checkSublistIndicies("List.sublist", start, end) + ArraySublist(this, start, end) + + override method set(index, element): + checkIndex("List.set", index) + storage[index] := element + + override method add(element): + version := version + 1 + ensureCapacity(currentSize + 1) + storage[currentSize] := element + currentSize := currentSize + 1 + version := version + 1 + + override method remove(element): + let i = find(element) + unless i == -1 | delete(i) + + override method insert(index :: Integer, element) :: Void: + checkInsertionIndex("List.insert", index) + ensureCapacity(currentSize + 1) + fun loop(i = currentSize): + unless i == index + | storage[i] := storage[i - 1] + loop(i - 1) + loop() + storage[index] := element + currentSize := currentSize + 1 + version := version + 1 + + override method delete(index :: Integer) :: Void: + checkIndex("List.delete", index) + for: + each i: index + 1 .. currentSize + storage[i - 1] := storage[i] + storage[currentSize - 1] := #false + currentSize := currentSize - 1 + version := version + 1 + + override method clear() :: Void: + storage := Array() + currentSize := 0 + version := version + 1 + + private method find(element): + fun loop(i = 0): + cond + | i == currentSize: -1 + | storage[i] == element: i + | ~else: loop(i + 1) + loop() + + method ensureCapacity(requiredSize) :: Void: + when storage.length() < requiredSize + | let newStorage = Array.make(max(storage.length() * 2, requiredSize)) + for: + each: + v: storage + i: 0.. + newStorage[i] := v + storage := newStorage + + +class ArraySublist(backingList :: PrivateArrayList, start :: Integer, mutable end :: Integer): + implements MutableList + + override method iterate(): + ArraySublistIterator(this) + + override property size(): + end - start + + override method contains(element): + find(element) != -1 + + override method get(index): + checkIndex("List.get", index) + backingList.get(index + start) + + override method sublist(start, end): + checkSublistIndicies("List.sublist", start, end) + ArraySublist(backingList, this.start + start, this.start + end) + + override method set(index, element): + checkIndex("List.set", index) + backingList.set(index + start, element) + + override method add(element): + backingList.insert(end, element) + + override method remove(element): + let i = find(element) + unless i == -1 + | delete(i) + + override method insert(index, element): + checkInsertionIndex("List.insert", index) + backingList.insert(index + start, element) + end := end + 1 + + override method delete(index): + checkIndex("List.delete", index) + backingList.delete(index + start) + end := end - 1 + + override method clear(): + let elementsToShift = backingList.currentSize - end + let currentSize = size() + for: + each i: start .. start + elementsToShift + backingList.storage[i] := backingList.storage[i + currentSize] + let newSize = backingList.size - currentSize + for: + each i: newSize .. backingList.currentSize + backingList.storage[i] := #false + backingList.currentSize := newSize + backingList.version := backingList.version + 1 + end := 0 + + private method find(element): + fun loop(i = start): + cond + | i == end: -1 + | backingList.get(i) == element: i - start + | ~else: loop(i + 1) + loop() + + +class ArrayListIterator(backingList :: ArrayList, private version :: Integer = backingList.version): + implements Iterator + + private field index :: Integer: 0 + + override method hasNext(): + when version < backingList.version | error("concurrent modification") + index < backingList.size + + override method next(): + when version < backingList.version | error("concurrent modification") + unless index < backingList.size | error("no such element") + let element = backingList.get(index) + index := index + 1 + element + + +// TODO +class ArraySublistIterator(backingSublist :: ArraySublist) + + +fun max(x, y): + if x < y | y | x diff --git a/rhombus/data/private/list_builder.rhm b/rhombus/data/private/list_builder.rhm new file mode 100644 index 000000000..c6eeaf92e --- /dev/null +++ b/rhombus/data/private/list_builder.rhm @@ -0,0 +1,35 @@ +#lang rhombus + + +export: + ListBuilder + + +import: + rhombus/data/private/array_list.ArrayList + rhombus/data/private/regular_immutable_list.RegularImmutableList + rhombus/data/private/small_lists.SingletonList + rhombus/data/private/small_lists.EmptyList + + +class ListBuilder(): + + private field storage :: ArrayList = ArrayList() + + method add(element): + storage.add(element) + + method addAll(elements): + storage.addAll(elements) + + method build(): + match storage.size + | 0: EmptyList() + | 1: SingletonList(storage[0]) + | n: + let copy = Array.make(n) + for: + each: + i: 0..n + copy[i] := storage.get(i) + RegularImmutableList(copy) diff --git a/rhombus/data/private/persistent_list.rhm b/rhombus/data/private/persistent_list.rhm new file mode 100644 index 000000000..79bcca691 --- /dev/null +++ b/rhombus/data/private/persistent_list.rhm @@ -0,0 +1,11 @@ +#lang rhombus + + +export: + PersistentList + + +class PersistentList() +class PersistentSublist() +class PersistentListIterator() +class PersistentSublistIterator() diff --git a/rhombus/data/private/regular_immutable_list.rhm b/rhombus/data/private/regular_immutable_list.rhm new file mode 100644 index 000000000..833ae7b81 --- /dev/null +++ b/rhombus/data/private/regular_immutable_list.rhm @@ -0,0 +1,95 @@ +#lang rhombus + + +export: + RegularImmutableList + + +import: + rhombus/data/list.ImmutableList + rhombus/data/private/persistent_list.PersistentList + rhombus/data/sequence.Iterator + lib("racket/base").error + + +class RegularImmutableList(storage :: Array): + implements ImmutableList + internal PrivateRegularImmutableList + + override method iterate(): ImmutableListIterator(this) + override property size(): storage.length + override method isEmpty(): #false + + override method get(index): + checkIndex("List.get", index) + storage[index] + + override method sublist(start, end): + checkSublistIndicies("List.sublist", start, end) + RegularImmutableSublist(this, start, end) + + override method add(element): toPersistent().add(element) + override method remove(element): toPersistent().remove(element) + + override method set(index, element): + checkIndex("List.set", index) + toPersistent().set(index, element) + + override method insert(index, element): + checkInsertionIndex("List.insert", index) + toPersistent().insert(index, element) + + override method delete(index): + checkIndex("List.delete", index) + toPersistent().delete(index) + + private method toPersistent(): PersistentList().addAll(this) + + +class RegularImmutableSublist( + backingList :: PrivateRegularImmutableList, start :: Integer, end :: Integer): + + implements ImmutableList + + override method iterate(): ImmutableListIterator(this) + override property size(): end - start + override method isEmpty(): start < end + + override method get(index): + checkIndex("List.get", index) + backingList.storage[start + index] + + override method sublist(start, end): + checkSublistIndicies("List.sublist", start, end) + RegularImmutableSublist(backingList, this.start + start, this.start + end) + + override method add(element): toPersistent().add(element) + override method remove(element): toPersistent().remove(element) + + override method set(index, element): + checkIndex("List.set", index) + toPersistent().set(index, element) + + override method insert(index, element): + checkInsertionIndex("List.insert", index) + toPersistent().insert(index, element) + + override method delete(index): + checkIndex("List.delete", index) + toPersistent().delete(index) + + private method toPersistent(): PersistentList().addAll(this) + + +class ImmutableListIterator(backingList :: ImmutableList): + implements Iterator + + private field index :: Integer: 0 + + override method hasNext(): index < backingList.size + + override method next(): + unless index < backingList.size | error("no such element") + let element = backingList.get(index) + index := index + 1 + element diff --git a/rhombus/data/private/small_lists.rhm b/rhombus/data/private/small_lists.rhm new file mode 100644 index 000000000..c6aad0a57 --- /dev/null +++ b/rhombus/data/private/small_lists.rhm @@ -0,0 +1,86 @@ +#lang rhombus + + +export: + SingletonList + EmptyList + + +import: + rhombus/data/list.ImmutableList + rhombus/data/private/persistent_list.PersistentList + rhombus/data/sequence.Iterator + lib("racket/base.rkt").error + + +class SingletonList(onlyElement): + implements ImmutableList + override method iterate(): SingletonIterator(onlyElement) + override property size(): 1 + override method isEmpty(): #false + override method contains(element): element == onlyElement + + override method get(index): + checkIndex("List.get", index) + onlyElement + + override method sublist(start, end): + checkSublistIndicies("List.sublist", start, end) + if start == end | EmptyList() | this + + override method add(element): PersistentList().add(onlyElement).add(element) + override method remove(element): if element == onlyElement | EmptyList() | this + + override method set(index, element): + checkIndex("List.set", index) + SingletonList(element) + + override method insert(index, element): + checkInsertionIndex("List.insert", index) + if index == 0 + | PersistentList().add(element).add(onlyElement) + | PersistentList().add(onlyElement).add(element) + + override method delete(index): + checkIndex("List.delete", index) + EmptyList() + + +class SingletonIterator(element): + implements Iterator + private field exhausted = #false + override method hasNext(): !exhausted + + override method next(): + when exhausted | error("no such element") + exhausted := #true + element + + +class EmptyList(): + implements ImmutableList + override method iterate(): EmptyIterator() + override property size(): 0 + override method isEmpty(): #true + override method contains(_): #false + override method get(index): checkIndex("List.get", index) + + override method sublist(start, end): + checkSublistIndicies("List.sublist", start, end) + this + + override method add(element): SingletonList(element) + override method remove(_): this + override method set(index, _): checkIndex("List.set", index) + + override method insert(index, element): + checkInsertionIndex("List.insert", index) + add(element) + + override method delete(index): checkIndex("List.delete", index) + + +class EmptyIterator(): + implements Iterator + override method hasNext(): #false + override method next(): error("no such element") diff --git a/rhombus/data/sequence.rhm b/rhombus/data/sequence.rhm new file mode 100644 index 000000000..92982dec2 --- /dev/null +++ b/rhombus/data/sequence.rhm @@ -0,0 +1,16 @@ +#lang rhombus + + +export: + Sequence + Iterator + + +class.together: + + interface Sequence: + method iterate() :: Iterator + + interface Iterator: + method hasNext() :: Boolean + method next() diff --git a/rhombus/private/precondition.rhm b/rhombus/private/precondition.rhm new file mode 100644 index 000000000..850233a51 --- /dev/null +++ b/rhombus/private/precondition.rhm @@ -0,0 +1,9 @@ +#lang racket/base + + +(provide checkArgument) + + +(define (checkArgument who condition message . args) + (unless condition + (apply raise-arguments-error (string->symbol who) message args))) From 19c22e4769e7e41b2a69a6ca657ee47ac932dbd7 Mon Sep 17 00:00:00 2001 From: Jack Firth Date: Mon, 19 Dec 2022 22:07:09 -0800 Subject: [PATCH 2/6] Fix list builder fluent chaining --- rhombus/data/private/list_builder.rhm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rhombus/data/private/list_builder.rhm b/rhombus/data/private/list_builder.rhm index c6eeaf92e..23ba22172 100644 --- a/rhombus/data/private/list_builder.rhm +++ b/rhombus/data/private/list_builder.rhm @@ -18,9 +18,11 @@ class ListBuilder(): method add(element): storage.add(element) + this method addAll(elements): storage.addAll(elements) + this method build(): match storage.size From d5e5febdccb70e94974955d467508726f8cd8be8 Mon Sep 17 00:00:00 2001 From: Jack Firth Date: Mon, 26 Dec 2022 19:58:59 -0800 Subject: [PATCH 3/6] Rename collection interfaces --- rhombus/data/collection.rhm | 14 ++++----- rhombus/data/list.rhm | 30 +++++++++---------- rhombus/data/private/array_list.rhm | 6 ++-- .../data/private/regular_immutable_list.rhm | 10 +++---- rhombus/data/private/small_lists.rhm | 10 +++---- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/rhombus/data/collection.rhm b/rhombus/data/collection.rhm index 42556a1fe..8c9f5a971 100644 --- a/rhombus/data/collection.rhm +++ b/rhombus/data/collection.rhm @@ -3,7 +3,7 @@ export: Collection - ImmutableCollection + CollectionView MutableCollection @@ -11,7 +11,7 @@ import: rhombus/data/sequence.Sequence -interface Collection: +interface CollectionView: extends Sequence // read-only property property size :: Integer @@ -25,14 +25,14 @@ interface Collection: loop() -interface ImmutableCollection: - extends Collection - method add(element) :: ImmutableCollection - method remove(element) :: ImmutableCollection +interface Collection: + extends CollectionView + method add(element) :: Collection + method remove(element) :: Collection interface MutableCollection: - extends Collection + extends CollectionView method add(element) :: Void method addAll(elements :: Sequence) :: Void: diff --git a/rhombus/data/list.rhm b/rhombus/data/list.rhm index 09ec92b4a..8d64d295a 100644 --- a/rhombus/data/list.rhm +++ b/rhombus/data/list.rhm @@ -3,22 +3,22 @@ export: List - ImmutableList + ListView MutableList import: rhombus/data/collection.Collection - rhombus/data/collection.ImmutableCollection + rhombus/data/collection.CollectionView rhombus/data/collection.MutableCollection rhombus/private/precondition.checkArgument -interface List: - extends Collection +interface ListView: + extends CollectionView method get(index :: Integer) - method sublist(start :: Integer, end :: Integer) :: List + method sublist(start :: Integer, end :: Integer) :: ListView method checkIndex(who, index): checkArgument( @@ -60,22 +60,22 @@ interface List: "size", size()) -interface ImmutableList: +interface List: extends: - List - ImmutableCollection + ListView + Collection - method set(index :: Integer, element) :: ImmutableList - override add(element) :: ImmutableList - override remove(element) :: ImmutableList - method insert(index :: Integer, element) :: ImmutableList - method delete(index :: Integer) :: ImmutableList - override sublist(start :: Integer, end :: Integer) :: ImmutableList + method set(index :: Integer, element) :: List + override add(element) :: List + override remove(element) :: List + method insert(index :: Integer, element) :: List + method delete(index :: Integer) :: List + override sublist(start :: Integer, end :: Integer) :: List interface MutableList: extends: - List + ListView MutableCollection method set(index :: Integer, element) :: Void diff --git a/rhombus/data/private/array_list.rhm b/rhombus/data/private/array_list.rhm index 8b394a62e..e28889b89 100644 --- a/rhombus/data/private/array_list.rhm +++ b/rhombus/data/private/array_list.rhm @@ -24,7 +24,7 @@ class ArrayList(): override method iterate(): ArrayListIterator(this) - override property size(): currentSize + override property size: currentSize override method get(index): checkIndex("List.get", index) @@ -100,7 +100,7 @@ class ArraySublist(backingList :: PrivateArrayList, start :: Integer, mutable en override method iterate(): ArraySublistIterator(this) - override property size(): + override property size: end - start override method contains(element): @@ -138,7 +138,7 @@ class ArraySublist(backingList :: PrivateArrayList, start :: Integer, mutable en override method clear(): let elementsToShift = backingList.currentSize - end - let currentSize = size() + let currentSize = size for: each i: start .. start + elementsToShift backingList.storage[i] := backingList.storage[i + currentSize] diff --git a/rhombus/data/private/regular_immutable_list.rhm b/rhombus/data/private/regular_immutable_list.rhm index 833ae7b81..c9d63f40d 100644 --- a/rhombus/data/private/regular_immutable_list.rhm +++ b/rhombus/data/private/regular_immutable_list.rhm @@ -6,18 +6,18 @@ export: import: - rhombus/data/list.ImmutableList + rhombus/data/list.List rhombus/data/private/persistent_list.PersistentList rhombus/data/sequence.Iterator lib("racket/base").error class RegularImmutableList(storage :: Array): - implements ImmutableList + implements List internal PrivateRegularImmutableList override method iterate(): ImmutableListIterator(this) - override property size(): storage.length + override property size: storage.length override method isEmpty(): #false override method get(index): @@ -49,10 +49,10 @@ class RegularImmutableList(storage :: Array): class RegularImmutableSublist( backingList :: PrivateRegularImmutableList, start :: Integer, end :: Integer): - implements ImmutableList + implements List override method iterate(): ImmutableListIterator(this) - override property size(): end - start + override property size: end - start override method isEmpty(): start < end override method get(index): diff --git a/rhombus/data/private/small_lists.rhm b/rhombus/data/private/small_lists.rhm index c6aad0a57..db0a21acd 100644 --- a/rhombus/data/private/small_lists.rhm +++ b/rhombus/data/private/small_lists.rhm @@ -7,16 +7,16 @@ export: import: - rhombus/data/list.ImmutableList + rhombus/data/list.List rhombus/data/private/persistent_list.PersistentList rhombus/data/sequence.Iterator lib("racket/base.rkt").error class SingletonList(onlyElement): - implements ImmutableList + implements List override method iterate(): SingletonIterator(onlyElement) - override property size(): 1 + override property size: 1 override method isEmpty(): #false override method contains(element): element == onlyElement @@ -58,9 +58,9 @@ class SingletonIterator(element): class EmptyList(): - implements ImmutableList + implements List override method iterate(): EmptyIterator() - override property size(): 0 + override property size: 0 override method isEmpty(): #true override method contains(_): #false override method get(index): checkIndex("List.get", index) From 26c04504c820178f99da4d6dfa83a78c4fde3e98 Mon Sep 17 00:00:00 2001 From: Jack Firth Date: Mon, 26 Dec 2022 20:31:27 -0800 Subject: [PATCH 4/6] Add List extensions --- rhombus/data/list.rhm | 83 ++++-------------- rhombus/data/private/array_list.rhm | 2 +- rhombus/data/private/list.rhm | 84 +++++++++++++++++++ rhombus/data/private/list_builder.rhm | 2 +- .../data/private/regular_immutable_list.rhm | 4 +- rhombus/data/private/small_lists.rhm | 2 +- 6 files changed, 104 insertions(+), 73 deletions(-) create mode 100644 rhombus/data/private/list.rhm diff --git a/rhombus/data/list.rhm b/rhombus/data/list.rhm index 8d64d295a..59a270e22 100644 --- a/rhombus/data/list.rhm +++ b/rhombus/data/list.rhm @@ -8,77 +8,24 @@ export: import: - rhombus/data/collection.Collection - rhombus/data/collection.CollectionView - rhombus/data/collection.MutableCollection - rhombus/private/precondition.checkArgument + rhombus/data/private/array_list.ArrayList + rhombus/data/private/list.List + rhombus/data/private/list.ListView + rhombus/data/private/list.MutableList + rhombus/data/private/list_builder.ListBuilder -interface ListView: - extends CollectionView +fun List.builder(): ListBuilder() - method get(index :: Integer) - method sublist(start :: Integer, end :: Integer) :: ListView - method checkIndex(who, index): - checkArgument( - who, - index >= 0 && index < size(), - "index out of bounds", - "index", index, - "size", size()) +// TODO: make this work as List(...) instead of List.of(...) +fun List.of(element, ...): + let builder = List.builder() + for: + each v: Array(element, ...) + builder.add(v) + builder.build() - method checkInsertionIndex(who, index): - checkArgument( - who, - index >= 0 && index <= size(), - "index out of bounds", - "index", index, - "size", size()) - method checkSublistIndicies(who, start, end): - checkArgument( - who, - start >= 0 && start <= size(), - "sublist start index out of bounds", - "start index", start, - "end index", end, - "size", size()) - checkArgument( - who, - end >= 0 && end <= size(), - "sublist end index out of bounds", - "start index", start, - "end index", end, - "size", size()) - checkArgument( - who, - start <= end, - "sublist start index occurs after end index", - "start index", start, - "end index", end, - "size", size()) - - -interface List: - extends: - ListView - Collection - - method set(index :: Integer, element) :: List - override add(element) :: List - override remove(element) :: List - method insert(index :: Integer, element) :: List - method delete(index :: Integer) :: List - override sublist(start :: Integer, end :: Integer) :: List - - -interface MutableList: - extends: - ListView - MutableCollection - - method set(index :: Integer, element) :: Void - method insert(index :: Integer, element) :: Void - method delete(index :: Integer) :: Void - override sublist(start :: Integer, end :: Integer) :: MutableList +// TODO: make this work as MutableList() instead of MutableList.create() +fun MutableList.create(): ArrayList() diff --git a/rhombus/data/private/array_list.rhm b/rhombus/data/private/array_list.rhm index e28889b89..38f5a5b2c 100644 --- a/rhombus/data/private/array_list.rhm +++ b/rhombus/data/private/array_list.rhm @@ -6,7 +6,7 @@ export: import: - rhombus/data/list.MutableList + rhombus/data/private/list.MutableList rhombus/data/sequence.Iterator lib("racket/base.rkt").error diff --git a/rhombus/data/private/list.rhm b/rhombus/data/private/list.rhm new file mode 100644 index 000000000..7e2f76022 --- /dev/null +++ b/rhombus/data/private/list.rhm @@ -0,0 +1,84 @@ +#lang rhombus + + +export: + List + ListView + MutableList + + +import: + rhombus/data/collection.Collection + rhombus/data/collection.CollectionView + rhombus/data/collection.MutableCollection + rhombus/private/precondition.checkArgument + + +interface ListView: + extends CollectionView + + method get(index :: Integer) + method sublist(start :: Integer, end :: Integer) :: ListView + + method checkIndex(who, index): + checkArgument( + who, + index >= 0 && index < size, + "index out of bounds", + "index", index, + "size", size) + + method checkInsertionIndex(who, index): + checkArgument( + who, + index >= 0 && index <= size, + "index out of bounds", + "index", index, + "size", size) + + method checkSublistIndicies(who, start, end): + checkArgument( + who, + start >= 0 && start <= size, + "sublist start index out of bounds", + "start index", start, + "end index", end, + "size", size) + checkArgument( + who, + end >= 0 && end <= size, + "sublist end index out of bounds", + "start index", start, + "end index", end, + "size", size) + checkArgument( + who, + start <= end, + "sublist start index occurs after end index", + "start index", start, + "end index", end, + "size", size) + + +interface List: + extends: + ListView + Collection + + method set(index :: Integer, element) :: List + override add(element) :: List + override remove(element) :: List + method insert(index :: Integer, element) :: List + method delete(index :: Integer) :: List + override sublist(start :: Integer, end :: Integer) :: List + + +interface MutableList: + extends: + ListView + MutableCollection + + method set(index :: Integer, element) :: Void + method insert(index :: Integer, element) :: Void + method delete(index :: Integer) :: Void + override sublist(start :: Integer, end :: Integer) :: MutableList diff --git a/rhombus/data/private/list_builder.rhm b/rhombus/data/private/list_builder.rhm index 23ba22172..0d35edf0e 100644 --- a/rhombus/data/private/list_builder.rhm +++ b/rhombus/data/private/list_builder.rhm @@ -27,7 +27,7 @@ class ListBuilder(): method build(): match storage.size | 0: EmptyList() - | 1: SingletonList(storage[0]) + | 1: SingletonList(storage.get(0)) | n: let copy = Array.make(n) for: diff --git a/rhombus/data/private/regular_immutable_list.rhm b/rhombus/data/private/regular_immutable_list.rhm index c9d63f40d..73fbdf79c 100644 --- a/rhombus/data/private/regular_immutable_list.rhm +++ b/rhombus/data/private/regular_immutable_list.rhm @@ -6,7 +6,7 @@ export: import: - rhombus/data/list.List + rhombus/data/private/list.List rhombus/data/private/persistent_list.PersistentList rhombus/data/sequence.Iterator lib("racket/base").error @@ -81,7 +81,7 @@ class RegularImmutableSublist( private method toPersistent(): PersistentList().addAll(this) -class ImmutableListIterator(backingList :: ImmutableList): +class ImmutableListIterator(backingList :: List): implements Iterator private field index :: Integer: 0 diff --git a/rhombus/data/private/small_lists.rhm b/rhombus/data/private/small_lists.rhm index db0a21acd..9e0236228 100644 --- a/rhombus/data/private/small_lists.rhm +++ b/rhombus/data/private/small_lists.rhm @@ -7,7 +7,7 @@ export: import: - rhombus/data/list.List + rhombus/data/private/list.List rhombus/data/private/persistent_list.PersistentList rhombus/data/sequence.Iterator lib("racket/base.rkt").error From 520aa719e83969adc50eb994f785dacfc8351998 Mon Sep 17 00:00:00 2001 From: Jack Firth Date: Mon, 26 Dec 2022 21:08:59 -0800 Subject: [PATCH 5/6] Add a few list tests and fix a bug --- .../data/private/regular_immutable_list.rhm | 2 +- rhombus/data/tests/list.rhm | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 rhombus/data/tests/list.rhm diff --git a/rhombus/data/private/regular_immutable_list.rhm b/rhombus/data/private/regular_immutable_list.rhm index 73fbdf79c..9540fdbb9 100644 --- a/rhombus/data/private/regular_immutable_list.rhm +++ b/rhombus/data/private/regular_immutable_list.rhm @@ -17,7 +17,7 @@ class RegularImmutableList(storage :: Array): internal PrivateRegularImmutableList override method iterate(): ImmutableListIterator(this) - override property size: storage.length + override property size: storage.length() override method isEmpty(): #false override method get(index): diff --git a/rhombus/data/tests/list.rhm b/rhombus/data/tests/list.rhm new file mode 100644 index 000000000..092a2445d --- /dev/null +++ b/rhombus/data/tests/list.rhm @@ -0,0 +1,51 @@ +#lang rhombus + + +import: + rhombus/data/list.List + rhombus/tests/check.check + + +check: + List.of().size + 0 + +check: + List.of("foo").size + 1 + +check: + List.of("foo", "bar", "baz").size + 3 + +check: + List.of("foo").get(0) + "foo" + +check: + List.of("foo", "bar", "baz").get(0) + "foo" + +check: + List.of("foo", "bar", "baz").get(1) + "bar" + +check: + List.of("foo", "bar", "baz").get(2) + "baz" + +check: + List.of().isEmpty() + #true + +check: + List.of(1, 2, 3).contains(2) + #true + +check: + List.of(1, 2, 3).contains(4) + #false + +check: + List.builder().build().size + 0 From 81d6c25daa0b68a363fc69f3c70a73dca271fca9 Mon Sep 17 00:00:00 2001 From: Alex Knauth Date: Thu, 4 May 2023 15:07:29 -0400 Subject: [PATCH 6/6] import .rkt and check ~is (#302) --- .../data/private/regular_immutable_list.rhm | 2 +- rhombus/data/tests/list.rhm | 23 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/rhombus/data/private/regular_immutable_list.rhm b/rhombus/data/private/regular_immutable_list.rhm index 9540fdbb9..16dcaed2e 100644 --- a/rhombus/data/private/regular_immutable_list.rhm +++ b/rhombus/data/private/regular_immutable_list.rhm @@ -9,7 +9,7 @@ import: rhombus/data/private/list.List rhombus/data/private/persistent_list.PersistentList rhombus/data/sequence.Iterator - lib("racket/base").error + lib("racket/base.rkt").error class RegularImmutableList(storage :: Array): diff --git a/rhombus/data/tests/list.rhm b/rhombus/data/tests/list.rhm index 092a2445d..8df0c53c5 100644 --- a/rhombus/data/tests/list.rhm +++ b/rhombus/data/tests/list.rhm @@ -3,49 +3,48 @@ import: rhombus/data/list.List - rhombus/tests/check.check check: List.of().size - 0 + ~is 0 check: List.of("foo").size - 1 + ~is 1 check: List.of("foo", "bar", "baz").size - 3 + ~is 3 check: List.of("foo").get(0) - "foo" + ~is "foo" check: List.of("foo", "bar", "baz").get(0) - "foo" + ~is "foo" check: List.of("foo", "bar", "baz").get(1) - "bar" + ~is "bar" check: List.of("foo", "bar", "baz").get(2) - "baz" + ~is "baz" check: List.of().isEmpty() - #true + ~is #true check: List.of(1, 2, 3).contains(2) - #true + ~is #true check: List.of(1, 2, 3).contains(4) - #false + ~is #false check: List.builder().build().size - 0 + ~is 0