PageRenderTime 22ms CodeModel.GetById 14ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lib/storage/collection/fast_array.e

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