PageRenderTime 23ms CodeModel.GetById 11ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 1ms

/src/lib/storage/collection/array.e

http://github.com/tybor/Liberty
Specman e | 495 lines | 396 code | 43 blank | 56 comment | 26 complexity | dcb44b1da02b7ad7b6fe6d62411c7e89 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class ARRAY[E_]
  5   --
  6   -- General purpose resizable ARRAYs as they are define in the Eiffel language definition.
  7   -- The `lower' bound can be any arbitrary value, even a negative one.
  8   --
  9   -- This implementation uses only one chunk of memory, the `storage' area which is a NATIVE_ARRAY. One must
 10   -- keep in mind that this internal `storage' area is always kept left align. Thus, you can expect good
 11   -- performances while using an ARRAY to modelize a stack behavior with `add_last' / `last' / `remove_last'.
 12   -- Conversely `add_first' and `remove_first' are likely to slow down your program if they are too often
 13   -- used. If the fact that `lower' is always stuck to 0 is not a problem for you, also consider FAST_ARRAY to
 14   -- get better performances.
 15   --
 16
 17inherit
 18   COLLECTION[E_]
 19      redefine default_create
 20      end
 21   ARRAYED_COLLECTION[E_]
 22      redefine default_create
 23      end
 24
 25insert
 26   NATIVE_ARRAY_COLLECTOR[E_]
 27      undefine default_create, out_in_tagged_out_memory
 28      redefine default_create
 29      end
 30
 31create {ANY}
 32   default_create, make, with_capacity, from_collection, manifest_creation
 33
 34feature {}
 35   default_create
 36      do
 37         make(0, -1)
 38      end
 39
 40feature {ANY}
 41   lower: INTEGER
 42         -- Lower index bound.
 43
 44feature {ANY} -- Creation and Modification:
 45   make (min_index, max_index: INTEGER)
 46         -- Prepare the array to hold values for indexes in range
 47         -- [`min_index' .. `max_index']. Set all values to default.
 48         -- When `max_index' = `min_index' - 1, the array `is_empty'.
 49      require
 50         valid_bounds: min_index <= max_index + 1
 51      do
 52         ensure_capacity_and_bounds(max_index - min_index + 1, min_index, max_index)
 53      ensure
 54         lower_set: lower = min_index
 55         upper_set: upper = max_index
 56         items_set: all_default
 57      end
 58
 59   with_capacity (needed_capacity, low: INTEGER)
 60         -- Create an empty array with `capacity' initialized
 61         -- at least to `needed_capacity' and `lower' set to `low'.
 62      require
 63         needed_capacity >= 0
 64      do
 65         ensure_capacity_and_bounds(needed_capacity, low, low - 1)
 66      ensure
 67         is_empty
 68         needed_capacity <= capacity
 69         lower = low
 70      end
 71
 72feature {}
 73   ensure_capacity_and_bounds (needed_capacity, low, up: INTEGER)
 74      require
 75         up >= low - 1
 76         needed_capacity >= up - low + 1
 77      local
 78         value: like item
 79      do
 80         if value = Void and then capacity > 0 then
 81            -- Be sure to release all objects. Useful only if the objects are references.
 82            clear_all
 83         end
 84         lower := low
 85         upper := up
 86         if needed_capacity > 0 then
 87            if capacity < needed_capacity then
 88               storage := storage.calloc(needed_capacity)
 89               capacity := needed_capacity
 90            elseif value /= Void and then up >= low then
 91               -- Ensure the postcondition. Useful only for expanded objects since references were purged above.
 92               clear_all
 93            end
 94         end
 95         next_generation
 96      ensure
 97         needed_capacity <= capacity
 98         lower = low
 99         upper = up
100         all_default
101      end
102
103feature {ANY} -- Modification:
104   resize (min_index, max_index: INTEGER)
105         -- Resize to bounds `min_index' and `max_index'. Do not lose any
106         -- item whose index is in both [`lower' .. `upper'] and
107         -- [`min_index' .. `max_index']. New positions if any are
108         -- initialized with the appropriate default value.
109      require
110         min_index <= max_index + 1
111      local
112         needed, offset, intersize: INTEGER
113      do
114         needed := max_index - min_index + 1
115         if needed > 0 then
116            if needed > capacity then
117               if capacity = 0 then
118                  storage := storage.calloc(needed)
119                  capacity := needed
120               else
121                  storage := storage.realloc(capacity, needed)
122                  capacity := needed
123               end
124            end
125            offset := lower - min_index
126            intersize := max_index.min(upper) - min_index.max(lower) + 1
127            if intersize > 0 then
128               if offset = 0 then
129                  if intersize <= upper - lower then
130                     storage.clear(intersize, upper - lower)
131                  end
132               elseif offset < 0 then
133                  storage.move(-offset, intersize - offset - 1, offset)
134                  storage.clear(intersize, upper - lower)
135               else
136                  storage.move(0, intersize - 1, offset)
137                  storage.clear(0, offset - 1)
138                  if intersize + offset <= upper - lower then
139                     storage.clear(intersize + offset, upper - lower)
140                  end
141               end
142            else
143               storage.clear(0, upper - lower)
144            end
145         elseif upper >= lower then
146            storage.clear(0, upper - lower)
147         end
148         lower := min_index
149         upper := max_index
150         next_generation
151      ensure
152         lower = min_index
153         upper = max_index
154      end
155
156   reindex (new_lower: INTEGER)
157         -- Change indexing to take in account the expected `new_lower'
158         -- index. The `upper' index is translated accordingly.
159      local
160         i: INTEGER
161      do
162         i := new_lower - lower
163         lower := lower + i
164         upper := upper + i
165         next_generation
166      ensure
167         lower = new_lower
168         count = old count
169      end
170
171feature {ANY} -- Implementation of deferred:
172   count: INTEGER
173      do
174         Result := upper - lower + 1
175      end
176
177   is_empty: BOOLEAN
178      do
179         Result := upper < lower
180      end
181
182   subarray (min, max: INTEGER): like Current
183      do
184         Result := slice(min, max)
185         Result.reindex(min)
186      ensure then
187         Result.lower = min
188      end
189
190   item (i: INTEGER): E_
191      do
192         Result := storage.item(i - lower)
193      end
194
195   put (element: like item; i: INTEGER)
196      do
197         storage.put(element, i - lower)
198         next_generation
199      end
200
201   force (element: like item; index: INTEGER)
202      require else
203         True
204      do
205         if upper < index then
206            if index = upper + 1 then
207               add_last(element)
208            else
209               resize(lower, index)
210               put(element, index)
211            end
212         elseif index < lower then
213            resize(index, upper)
214            put(element, index)
215         else
216            put(element, index)
217         end
218      ensure then
219         lower = index.min(old lower)
220      end
221
222   copy (other: like Current)
223      local
224         needed_capacity: INTEGER
225      do
226         lower := other.lower
227         upper := other.upper
228         needed_capacity := upper - lower + 1
229         if capacity < needed_capacity then
230            storage := storage.calloc(needed_capacity)
231            capacity := needed_capacity
232         end
233         if needed_capacity > 0 then
234            storage.copy_from(other.storage, needed_capacity - 1)
235         end
236         next_generation
237      end
238
239   set_all_with (v: like item)
240      do
241         storage.set_all_with(v, upper - lower)
242         next_generation
243      end
244
245   remove_first
246      do
247         storage.remove_first(upper - lower)
248         lower := lower + 1
249         next_generation
250      ensure then
251         upper = old upper
252      end
253
254   remove_head (n: INTEGER)
255      do
256         storage.move(n, upper - lower, -n)
257         lower := lower + n
258         next_generation
259      ensure then
260         upper = old upper
261      end
262
263   remove (index: INTEGER)
264      do
265         storage.remove(index - lower, upper - lower)
266         upper := upper - 1
267         next_generation
268      end
269
270   clear_count, clear_count_and_capacity
271      do
272         upper := lower - 1
273         next_generation
274      ensure then
275         capacity = old capacity
276      end
277
278   add_first (element: like item)
279      do
280         if upper < lower then
281            add_last(element)
282         else
283            add_last(element)
284            move(lower, upper - 1, 1)
285            put(element, lower)
286         end
287      end
288
289   add_last (element: like item)
290      local
291         new_capacity: INTEGER
292      do
293         if capacity < count + 1 then
294            if capacity = 0 then
295               new_capacity := 16
296               storage := storage.calloc(new_capacity)
297               capacity := new_capacity
298            else
299               new_capacity := capacity * 2
300               storage := storage.realloc(capacity, new_capacity)
301               capacity := new_capacity
302            end
303         end
304         upper := upper + 1
305         put(element, upper)
306      end
307
308   from_collection (model: TRAVERSABLE[like item])
309      local
310         i, up: INTEGER
311      do
312         from
313            with_capacity(model.count, model.lower)
314            i := model.lower
315            up := model.upper
316            upper := up
317         until
318            i > up
319         loop
320            put(model.item(i), i)
321            i := i + 1
322         end
323      ensure then
324         lower = model.lower
325         upper = model.upper
326      end
327
328   all_default: BOOLEAN
329      do
330         Result := storage.all_default(upper - lower)
331      end
332
333   occurrences (element: like item): INTEGER
334      do
335         Result := storage.occurrences(element, upper - lower)
336      end
337
338   fast_occurrences (element: like item): INTEGER
339      do
340         Result := storage.fast_occurrences(element, upper - lower)
341      end
342
343   first_index_of (element: like item): INTEGER
344      do
345         if upper >= lower then
346            Result := lower + storage.first_index_of(element, upper - lower)
347         else
348            Result := lower
349         end
350      end
351
352   index_of (element: like item; start_index: INTEGER): INTEGER
353      do
354         if upper >= lower then
355            Result := lower + storage.index_of(element, start_index - lower, upper - lower)
356         else
357            Result := lower
358         end
359      end
360
361   reverse_index_of (element: like item; start_index: INTEGER): INTEGER
362      do
363         if upper >= lower then
364            Result := lower + storage.reverse_index_of(element, start_index - lower)
365         else
366            Result := lower
367         end
368      end
369
370   fast_first_index_of (element: like item): INTEGER
371      do
372         if upper >= lower then
373            Result := lower + storage.fast_first_index_of(element, upper - lower)
374         else
375            Result := lower
376         end
377      end
378
379   fast_index_of (element: like item; start_index: INTEGER): INTEGER
380      do
381         if upper >= lower then
382            Result := lower + storage.fast_index_of(element, start_index - lower, upper - lower)
383         else
384            Result := lower
385         end
386      end
387
388   fast_reverse_index_of (element: like item; start_index: INTEGER): INTEGER
389      do
390         if upper >= lower then
391            Result := lower + storage.fast_reverse_index_of(element, start_index - lower)
392         else
393            Result := lower
394         end
395      end
396
397   fast_is_equal (other: like Current): BOOLEAN
398      do
399         if Current = other then
400            Result := True
401         elseif lower = other.lower and then upper = other.upper then
402            Result := storage.fast_memcmp(other.storage, count)
403         end
404      end
405
406   is_equal (other: like Current): BOOLEAN
407      do
408         if Current = other then
409            Result := True
410         elseif lower = other.lower and then upper = other.upper then
411            Result := storage.memcmp(other.storage, count)
412         end
413      end
414
415   slice (min, max: INTEGER): like Current
416      local
417         null: POINTER
418      do
419         Result := standard_twin
420         Result.set_upper(Result.lower - 1)
421         Result.from_external(null, 0)
422
423         if max >= min then
424            -- Slice not empty
425            Result.make(lower, lower + max - min)
426            Result.storage.slice_copy(0, storage, min - lower, max - lower)
427         else
428            Result.with_capacity(0, lower)
429         end
430      end
431
432   new_iterator: ITERATOR[E_]
433      do
434         create {ITERATOR_ON_TRAVERSABLE[E_]} Result.make(Current)
435      end
436
437feature {} -- Garbage collector tuning (very low-level):
438   mark_native_arrays
439         -- For performance reasons, the unused area of `storage' is always left as it is when
440         -- some elements are removed. No time is lost to clean the released area with a Void
441         -- or a 0 value. (Look for example the `remove_last' implementation.)
442         -- Thus, the unused area of `storage' may contains references of actually unreachable
443         -- objects. The following `mark_native_arrays' actually replace the
444         -- default behavior (the call is automatic) in order to mark only reachable objects.
445      local
446         i: INTEGER
447      do
448         from
449            i := count - 1
450         until
451            i < 0
452         loop
453            mark_item(storage, i)
454            i := i - 1
455         end
456      end
457
458feature {} -- Implement manifest generic creation (very low-level):
459   manifest_make (needed_capacity: INTEGER; initial_lower: INTEGER)
460         -- Manifest creation of an ARRAY[E_] with `lower' set to `initial_lower'.
461      require
462         needed_capacity > 0
463      do
464         make(initial_lower, initial_lower + needed_capacity - 1)
465      end
466
467   manifest_put (index: INTEGER; element: like item)
468      do
469         check
470            index < capacity
471         end
472         storage.put(element, index)
473      end
474
475end -- class ARRAY
476--
477-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
478--
479-- Permission is hereby granted, free of charge, to any person obtaining a copy
480-- of this software and associated documentation files (the "Software"), to deal
481-- in the Software without restriction, including without limitation the rights
482-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
483-- copies of the Software, and to permit persons to whom the Software is
484-- furnished to do so, subject to the following conditions:
485--
486-- The above copyright notice and this permission notice shall be included in
487-- all copies or substantial portions of the Software.
488--
489-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
490-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
491-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
492-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
493-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
494-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
495-- THE SOFTWARE.