1 package frost.collections
2
3 ====================================================================================================
4 A read-only view of a collection of elements. A `CollectionView`'s elements are accessed via its
5 [iterator] property.
6
7 @see CollectionWriter
8 @see Collection
9 @see ListView
10 ====================================================================================================
11 interface CollectionView<T> : Iterable<T> {
12 ================================================================================================
13 The number of elements in the collection.
14 ================================================================================================
15 property count:Int
16
17 function get_count():Int
18
19 ================================================================================================
20 Returns the first element in the collection in iteration order.
21 ================================================================================================
22 property first:T
23
24 @default
25 function get_first():T {
26 return iterator.next()
27 }
28
29 ================================================================================================
30 Returns the string concatenation of all of the items in this collection, in iteration order.
31 Equivalent to `join("")`.
32
33 @see join(String)
34 ================================================================================================
35 @default
36 function join():String {
37 return join("")
38 }
39
40 ================================================================================================
41 Converts all of the items in this collection to strings and concatenates them in iteration
42 order, with the given separator between them. For instance, `[1, 2, 3].join("|")` returns
43 `"1|2|3"`.
44
45 @param separator the delimiter string
46 @see join()
47 ================================================================================================
48 @default
49 function join(separator:String):String {
50 if count = 0 {
51 return ""
52 }
53 var first := true
54 def result := MutableString()
55 for v in self {
56 if first {
57 first := false
58 }
59 else {
60 result.append(separator)
61 }
62 -- FIXME cast shouldn't be necessary
63 if v->Object? !== null {
64 result.append(v)
65 }
66 else {
67 result.append("<null>")
68 }
69 }
70 return result.finish()
71 }
72
73 ================================================================================================
74 Successively applies a binary function to 'fold' the elements in the list down to a single
75 value. For instance, if we have a collection of [Int64]s and fold using the binary function
76 [Int64.+(Int64)], as in:
77
78 -- testcase CollectionViewFold(PrintLine)
79 [1, 2, 3, 4, 5].fold(Int.+)
80
81 this would add the first (in iteration order) and second elements of the collection together,
82 and then add the sum of the first two elements to the third, and so forth until all of the
83 elements of the collection had been added together. This would result in the sum of all of the
84 elements in the collection.
85
86 Similarly, we could fold using [Int64.max(Int64)] to find the biggest number in the list,
87 [Int64.*(Int64)] to get the product of all of the numbers in the list, etc.
88
89 If the list has only a single element in the list, the result of `fold` is this single element
90 and the function `f` is never called. This variant of `fold` may not be called on an empty list
91 because the result would be undefined.
92
93 @param f a binary function to combine elements of the collection
94 @returns the result of combining the entire collection
95 @see fold((T, T)=>(T), T)
96 ================================================================================================
97 @pre(count > 0)
98 @default
99 @priority(1)
100 function fold(f:(T, T)=>(T)):T {
101 -- FIXME type declaration shouldn't be necessary
102 def i:Iterator<T> := iterator
103 var result := i.next()
104 while !i.done {
105 result := f(result, i.next())
106 }
107 return result
108 }
109
110 ================================================================================================
111 As [fold((T, T)=>(T))], but for methods instead of functions.
112 ================================================================================================
113 @pre(count > 0)
114 @default
115 method fold(f:(T, T)=&>(T)):T {
116 -- FIXME type declaration shouldn't be necessary
117 def i:Iterator<T> := iterator
118 var result := i.next()
119 while !i.done {
120 result := f(result, i.next())
121 }
122 return result
123 }
124
125 ================================================================================================
126 As [fold((T, T)=>(T))], but additionally takes a starting value for the fold operation. The
127 starting value is folded into the first element of the list, the result is then folded into the
128 second element, etc. This allows `fold` to be well-defined even on an empty list: folding an
129 empty list simply returns the start value.
130
131 @param f a binary function to combine elements of the collection
132 @param start the starting value for the fold
133 @see fold((T, T)=>(T))
134 ================================================================================================
135 @default
136 @priority(1)
137 function fold(f:(T, T)=>(T), start:T):T {
138 var result := start
139 for v in self {
140 result := f(result, v)
141 }
142 return result
143 }
144
145 ================================================================================================
146 As [fold((T, T)=>(T), T)], but for methods instead of functions.
147 ================================================================================================
148 @default
149 method fold(f:(T, T)=&>(T), start:T):T {
150 var result := start
151 for v in self {
152 result := f(result, v)
153 }
154 return result
155 }
156
157 ================================================================================================
158 Calls the method `m` on each element of the collection in iteration order. For instance, to
159 display every element in a collection you could write:
160
161 -- testcase CollectionViewApply
162 collection.apply(Console.printLine)
163
164 @param m a method to call on each element
165 ================================================================================================
166 @default
167 method apply(m:(T)=&>()) {
168 for v in self {
169 m(v)
170 }
171 }
172
173 ================================================================================================
174 Returns an array containing the result of calling `f` on every element in this collection. For
175 example,
176
177 -- testcase CollectionViewMap(Simple)
178 Console.printLine(Int[1 ... 5].map(2.*))
179
180 applies the function `2.*` to the integers from 1 to 5. This displays `[2, 4, 6, 8, 10]`.
181 ================================================================================================
182 @default
183 @priority(1)
184 function map<U>(f:(T)=>(U)):Array<U> {
185 def result := Array<U>(count)
186 for v in self {
187 result.add(f(v))
188 }
189 return result
190 }
191
192 ================================================================================================
193 As [map((T)=>(U))], but for methods instead of functions.
194 ================================================================================================
195 @default
196 method map<U>(f:(T)=&>(U)):Array<U> {
197 def result := Array<U>(count)
198 for v in self {
199 result.add(f(v))
200 }
201 return result
202 }
203 }
204