PageRenderTime 25ms CodeModel.GetById 13ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 1ms

/src/lib/storage/collection.e

http://github.com/tybor/Liberty
Specman e | 554 lines | 345 code | 42 blank | 167 comment | 3 complexity | 8ffe3a90398515a85cbf9b4fd7d50758 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4deferred class COLLECTION[E_]
  5   --
  6   -- Common abstract definition of a sequenceable collection of objects. Such a collection is traversable
  7   -- using a simple INTEGER index from `lower' to `upper' using `item'. All COLLECTIONs are resizable
  8   -- thanks to `add_last' / `remove_last', `add_first' / `remove_first' as well as `add' / `remove' .
  9   --
 10   -- This abstraction provides feature to view a COLLECTION as a stack (as an example by using `add_last',
 11   -- `last', and `remove_last'). One can also use a COLLECTION as a queue (as an example, by using
 12   -- `add_last', `first' and `remove_first'). See also class QUEUE and STACK.
 13   --
 14   -- The Liberty Eiffel standard library provides five implementations of COLLECTION: ARRAY, FAST_ARRAY,
 15   -- RING_ARRAY, LINKED_LIST and TWO_WAY_LINKED_LIST. Except for creations all implementations have
 16   -- exactly the same behavior. Switching from one implementation to another only change the memory used
 17   -- and the execution time (see header comment of ARRAY, FAST_ARRAY, RING_ARRAY, LINKED_LIST and
 18   -- TWO_WAY_LINKED_LIST for more details).
 19   --
 20
 21inherit
 22   STORABLE
 23      undefine out_in_tagged_out_memory
 24      redefine copy, is_equal
 25      end
 26   TRAVERSABLE[E_]
 27      redefine copy, is_equal
 28      end
 29   SEARCHABLE[E_]
 30      undefine out_in_tagged_out_memory
 31      redefine copy, is_equal
 32      end
 33
 34feature {ANY} -- Accessing:
 35   frozen infix "@" (i: INTEGER): E_
 36         -- The infix notation which is actually just a synonym for `item'.
 37         --
 38         -- See also `item'.
 39      require
 40         valid_index(i)
 41      do
 42         Result := item(i)
 43      ensure
 44         definition: Result = item(i)
 45      end
 46
 47feature {ANY} -- Writing:
 48   put (element: like item; i: INTEGER) assign item
 49         -- Make `element' the item at index `i'.
 50         --
 51         -- See also `lower', `upper', `valid_index', `item', `swap', `force'.
 52      require
 53         valid_index(i)
 54      deferred
 55      ensure
 56         item(i) = element
 57         count = old count
 58      end
 59
 60   swap (i1, i2: INTEGER)
 61         -- Swap item at index `i1' with item at index `i2'.
 62         --
 63         -- See also `item', `put'.
 64      require
 65         valid_index(i1)
 66         valid_index(i2)
 67      local
 68         tmp: like item
 69      do
 70         tmp := item(i1)
 71         put(item(i2), i1)
 72         put(tmp, i2)
 73      ensure
 74         item(i1) = old item(i2)
 75         item(i2) = old item(i1)
 76         count = old count
 77      end
 78
 79   set_all_with (v: like item)
 80         -- Set all items with value `v'.
 81         --
 82         -- See also `set_slice_with'.
 83      deferred
 84      ensure
 85         count = old count
 86      end
 87
 88   set_slice_with (v: like item; lower_index, upper_index: INTEGER)
 89         -- Set all items in range [`lower_index' .. `upper_index'] with `v'.
 90         --
 91         -- See also `set_all_with'.
 92      require
 93         lower_index <= upper_index
 94         valid_index(lower_index)
 95         valid_index(upper_index)
 96      local
 97         i: INTEGER
 98      do
 99         from
100            i := lower_index
101         until
102            i > upper_index
103         loop
104            put(v, i)
105            i := i + 1
106         end
107      ensure
108         count = old count
109      end
110
111   clear_all
112         -- Set every item to its default value. The `count' is not affected.
113         --
114         -- See also `clear', `all_default'.
115      local
116         value: like item
117      do
118         set_all_with(value)
119      ensure
120         stable_upper: upper = old upper
121         stable_lower: lower = old lower
122         all_default
123      end
124
125feature {ANY} -- Adding:
126   add_first (element: like item)
127         -- Add a new item in first position : `count' is increased by
128         -- one and all other items are shifted right.
129         --
130         -- See also `add_last', `first', `last', `add'.
131      deferred
132      ensure
133         first = element
134         count = 1 + old count
135         lower = old lower
136         upper = 1 + old upper
137      end
138
139   add_last (element: like item)
140         -- Add a new item at the end : `count' is increased by one.
141         --
142         -- See also `add_first', `last', `first', `add'.
143      deferred
144      ensure
145         last = element
146         count = 1 + old count
147         lower = old lower
148         upper = 1 + old upper
149      end
150
151   add (element: like item; index: INTEGER)
152         -- Add a new `element' at rank `index' : `count' is increased
153         -- by one and range [`index' .. `upper'] is shifted right by one position.
154         --
155         -- See also `add_first', `add_last', `append_collection'.
156      require
157         index.in_range(lower, upper + 1)
158      deferred
159      ensure
160         item(index) = element
161         count = 1 + old count
162         upper = 1 + old upper
163      end
164
165   append_collection (other: COLLECTION[E_])
166         -- Append `other' to Current.
167         --
168         -- See also `add_last', `add_first', `add'.
169      obsolete "Use `append_traversable' instead."
170      require
171         other /= Void
172      do
173         append_traversable(other)
174      ensure
175         count = other.count + old count
176      end
177
178   append_traversable (other: TRAVERSABLE[E_])
179         -- Append `other' to Current.
180         --
181         -- See also `add_last', `add_first', `add'.
182      require
183         other /= Void
184      local
185         i: INTEGER
186      do
187         from
188            i := other.lower
189         until
190            i > other.upper
191         loop
192            add_last(other.item(i))
193            i := i + 1
194         end
195         -- Note: AFAIK it could also be implemented with other.for_each(agent add_last). Paolo 2011-08-12
196         -- Yes, but it MUST NOT. We are in the standard library and it must work without the GC so don't build useless
197         -- objects. Cad 2015-06-03
198      ensure
199         count = other.count + old count
200      end
201
202feature {ANY} -- Modification:
203   force (element: E_; index: INTEGER)
204         -- Make `element' the item at `index', enlarging the collection if
205         -- necessary (new bounds except `index' are initialized with
206         -- default values).
207         --
208         -- See also `put', `item', `swap'.
209      require
210         index >= lower
211      deferred
212      ensure
213         upper = index.max(old upper)
214         item(index) = element
215      end
216
217   copy (other: like Current)
218         -- Reinitialize by copying all the items of `other'.
219      deferred
220      end
221
222   from_collection (model: TRAVERSABLE[like item])
223         -- Initialize the current object with the contents of `model'.
224      require
225         model /= Void
226         useful_work: model /= Current
227      deferred
228      ensure
229         count = model.count
230      end
231
232feature {ANY} -- Removing:
233   remove_first
234         -- Remove the `first' element of the collection.
235         --
236         -- See also `remove_last', `remove', `remove_head'.
237      require
238         not is_empty
239      deferred
240      ensure
241         count = old count - 1
242         lower = old lower + 1 xor upper = old upper - 1
243      end
244
245   remove_head (n: INTEGER)
246         -- Remove the `n' elements of the collection.
247         --
248         -- See also `remove_tail', `remove', `remove_first'.
249      require
250         n > 0 and n <= count
251      deferred
252      ensure
253         count = old count - n
254         lower = old lower + n xor upper = old upper - n
255      end
256
257   remove (index: INTEGER)
258         -- Remove the item at position `index'. Followings items are shifted left by one position.
259         --
260         -- See also `remove_first', `remove_head', `remove_tail', `remove_last'.
261      require
262         valid_index(index)
263      deferred
264      ensure
265         count = old count - 1
266         upper = old upper - 1
267      end
268
269   remove_last
270         -- Remove the `last' item.
271         --
272         -- See also `remove_first', `remove', `remove_tail'.
273      require
274         not is_empty
275      deferred
276      ensure
277         count = old count - 1
278         upper = old upper - 1
279      end
280
281   remove_tail (n: INTEGER)
282         -- Remove the last `n' item(s).
283         --
284         -- See also `remove_head', `remove', `remove_last'.
285      require
286         n > 0 and n <= count
287      deferred
288      ensure
289         count = old count - n
290         upper = old upper - n
291      end
292
293   clear_count
294         -- Discard all items (`is_empty' is True after that call). If possible, the actual implementation
295         -- supposed to keep its internal storage area in order to refill `Current' in an efficient way.
296         --
297         -- See also `clear_count_and_capacity'.
298      deferred
299      ensure
300         is_empty: count = 0
301      end
302
303   clear_count_and_capacity
304         -- Discard all items (`is_empty' is True after that call). If possible, the actual implementation
305         -- supposed to release its internal storage area for this memory to be used by other objects.
306         --
307         -- See also `clear_count'.
308      deferred
309      ensure
310         is_empty: count = 0
311      end
312
313feature {ANY} -- Looking and Searching:
314   has (x: like item): BOOLEAN
315         -- Look for `x' using `is_equal' for comparison.
316         --
317         -- See also `fast_has', `index_of', `fast_index_of'.
318      do
319         Result := valid_index(first_index_of(x))
320      end
321
322   fast_has (x: like item): BOOLEAN
323         -- Look for `x' using basic `=' for comparison.
324         --
325         -- See also `has', `fast_index_of', `index_of'.
326      do
327         Result := valid_index(fast_first_index_of(x))
328      end
329
330   last_index_of (element: like item): INTEGER
331         -- Using `is_equal' for comparison, gives the index of the last occurrence of `element' at or before
332         -- `upper'. Search is done in reverse direction, which means from the `upper' down to the
333         -- `lower' index . Answer `lower -1' when the search fail.
334         --
335         -- See also `fast_last_index_of', `reverse_index_of', `index_of'.
336      do
337         Result := reverse_index_of(element, upper)
338      end
339
340   fast_last_index_of (element: like item): INTEGER
341         -- Using basic `=' for comparison, gives the index of the last occurrence of `element' at or before
342         -- `upper'. Search is done in reverse direction, which means from the `upper' down to the
343         -- `lower' index . Answer `lower -1' when the search fail.
344         --
345         -- See also `fast_reverse_index_of', `last_index_of'.
346      do
347         Result := fast_reverse_index_of(element, upper)
348      end
349
350feature {ANY} -- Looking and comparison:
351   fast_is_equal (other: like Current): BOOLEAN
352         -- Do both collections have the same `lower', `upper', and items?
353         -- The basic `=' is used for comparison of items.
354         --
355         -- See also `is_equal', `same_items'.
356      deferred
357      ensure
358         Result implies lower = other.lower and upper = other.upper
359      end
360
361   is_equal (other: like Current): BOOLEAN
362         -- Do both collections have the same `lower', `upper', and
363         -- items?
364         -- Feature `is_equal' is used for comparison of items.
365         --
366         -- See also `fast_is_equal', `same_items'.
367      deferred
368      ensure then
369         Result implies lower = other.lower and upper = other.upper
370      end
371
372   is_equal_map (other: like Current): BOOLEAN
373         -- Do both collections have the same `lower', `upper', and
374         -- items?
375         -- Feature `is_equal' is used for comparison of items.
376      obsolete "Use `is_equal' instead."
377      do
378         Result := is_equal(other)
379      end
380
381   all_default: BOOLEAN
382         -- Do all items have their type's default value?
383         -- Note: for non Void items, the test is performed with the `is_default' predicate.
384         --
385         -- See also `clear_all'.
386      deferred
387      end
388
389   same_items (other: COLLECTION[E_]): BOOLEAN
390         -- Do both collections have the same items? The basic `=' is used
391         -- for comparison of items and indices are not considered (for
392         -- example this routine may yield True with `Current' indexed in
393         -- range [1..2] and `other' indexed in range [2..3]).
394         --
395         -- See also `is_equal', `fast_is_equal'.
396      require
397         other /= Void
398      local
399         i, j: INTEGER
400      do
401         if count = other.count then
402            from
403               Result := True
404               i := lower
405               j := other.lower
406            until
407               not Result or else i > upper
408            loop
409               Result := item(i) = other.item(j)
410               i := i + 1
411               j := j + 1
412            end
413         end
414      ensure
415         Result implies count = other.count
416      end
417
418   occurrences (element: like item): INTEGER
419         -- Number of occurrences of `element' using `is_equal' for comparison.
420         --
421         -- See also `fast_occurrences', `index_of'.
422      deferred
423      ensure
424         Result >= 0
425      end
426
427   fast_occurrences (element: like item): INTEGER
428         -- Number of occurrences of `element' using basic `=' for comparison.
429         --
430         -- See also `occurrences', `index_of'.
431      deferred
432      ensure
433         Result >= 0
434      end
435
436feature {ANY} -- Other features:
437   replace_all (old_value, new_value: like item)
438         -- Replace all occurrences of the element `old_value' by `new_value' using `is_equal' for comparison.
439         --
440         -- See also `fast_replace_all', `move'.
441      deferred
442      ensure
443         count = old count
444         not (create {SAFE_EQUAL[E_]}).test(old_value, new_value) implies occurrences(old_value) = 0
445      end
446
447   fast_replace_all (old_value, new_value: like item)
448         -- Replace all occurrences of the element `old_value' by `new_value' using basic `=' for comparison.
449         --
450         -- See also `replace_all', `move'.
451      deferred
452      ensure
453         count = old count
454         old_value /= new_value implies fast_occurrences(old_value) = 0
455      end
456
457   move (lower_index, upper_index, distance: INTEGER)
458         -- Move range `lower_index' .. `upper_index' by `distance' positions.
459         -- Negative distance moves towards lower indices.
460         -- Free places get default values.
461         --
462         -- See also `slice', `replace_all'.
463      require
464         lower_index <= upper_index
465         valid_index(lower_index)
466         valid_index(lower_index + distance)
467         valid_index(upper_index)
468         valid_index(upper_index + distance)
469      local
470         default_value: like item; i: INTEGER
471      do
472         if distance = 0 then
473         elseif distance < 0 then
474            from
475               i := lower_index
476            until
477               i > upper_index
478            loop
479               put(item(i), i + distance)
480               put(default_value, i)
481               i := i + 1
482            end
483         else
484            from
485               i := upper_index
486            until
487               i < lower_index
488            loop
489               put(item(i), i + distance)
490               put(default_value, i)
491               i := i - 1
492            end
493         end
494      ensure
495         count = old count
496      end
497
498   slice (min, max: INTEGER): like Current
499         -- New collection consisting of items at indexes in [`min'..`max'].
500         -- Result has the same dynamic type as `Current'.
501         -- The `lower' index of the `Result' is the same as `lower'.
502         --
503         -- See also `from_collection', `move', `replace_all'.
504      require
505         lower <= min
506         max <= upper
507         min <= max + 1
508      deferred
509      ensure
510         same_dynamic_type(Result)
511         Result.count = max - min + 1
512         Result.lower = lower
513      end
514
515   reverse
516         -- Reverse the order of the elements.
517      deferred
518      ensure
519         count = old count
520      end
521
522feature {} -- Implement manifest generic creation:
523   manifest_semicolon_check: BOOLEAN False
524
525   manifest_put (index: INTEGER; element: like item)
526      require
527         index >= 0
528      deferred
529      end
530
531invariant
532   valid_bounds: lower <= upper + 1
533
534end -- class COLLECTION
535--
536-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
537--
538-- Permission is hereby granted, free of charge, to any person obtaining a copy
539-- of this software and associated documentation files (the "Software"), to deal
540-- in the Software without restriction, including without limitation the rights
541-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
542-- copies of the Software, and to permit persons to whom the Software is
543-- furnished to do so, subject to the following conditions:
544--
545-- The above copyright notice and this permission notice shall be included in
546-- all copies or substantial portions of the Software.
547--
548-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
549-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
550-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
551-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
552-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
553-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
554-- THE SOFTWARE.