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