PageRenderTime 63ms CodeModel.GetById 29ms app.highlight 15ms RepoModel.GetById 2ms app.codeStats 1ms

/src/lib/storage/collection/ring_array.e

http://github.com/tybor/Liberty
Specman e | 902 lines | 762 code | 57 blank | 83 comment | 67 complexity | 1d2cac95c4c5bd4d22388fe491d8132c MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class RING_ARRAY[E_]
  5   --
  6   -- The main purpose of the RING_ARRAY implementation is to allow efficient manipulation of the queue
  7   -- concept (i.e. using for example `add_last' / `first' / `remove_first'). Actually, the RING_ARRAY
  8   -- implementation provides very good performance for all of the following features: `add_last', `last',
  9   -- `remove_last', `add_first', `first', `remove_first'.
 10   -- Furthermore, the RING_ARRAY implementation also has a common point with traditional ARRAY: the `lower'
 11   -- bound can be any arbitrary value, even a negative one.
 12   -- As ARRAY or FAST_ARRAY, the RING_ARRAY uses only one chunk of memory, the `storage' area which is a
 13   -- NATIVE_ARRAY. This internal `storage' area is used in a circular way (no left- or right-alignment),
 14   -- hence the very good performances for using it as a queue. Finally, if you have to perform many insertions
 15   -- in the middle of your COLLECTION, do not expect good performance with a RING_ARRAY, but consider
 16   -- LINKED_LIST or TWO_WAY_LINKED_LIST.
 17   --
 18
 19inherit
 20   COLLECTION[E_]
 21      redefine default_create
 22      end
 23
 24insert
 25   ARRAYED_COLLECTION[E_]
 26      redefine first, to_external, default_create
 27      end
 28   NATIVE_ARRAY_COLLECTOR[E_]
 29      undefine out_in_tagged_out_memory
 30      redefine default_create
 31      end
 32
 33create {ANY}
 34   make, with_capacity, from_collection, manifest_creation, default_create
 35
 36feature {}
 37   default_create
 38      do
 39         make(0, -1)
 40      end
 41
 42feature {ANY}
 43   lower: INTEGER
 44         -- Lower index bound
 45
 46feature {ANY} -- Creation and Modification:
 47   make (min_index, max_index: INTEGER)
 48         -- Prepare the array to hold values for indexes in range
 49         -- [`min_index' .. `max_index']. Set all values to default.
 50         -- When `max_index' = `min_index' - 1, the array `is_empty'.
 51      require
 52         valid_bounds: min_index <= max_index + 1
 53      local
 54         needed: INTEGER
 55      do
 56         lower := min_index
 57         upper := max_index
 58         needed := max_index - min_index + 1
 59         storage_lower := 0
 60         if needed > 0 then
 61            if capacity < needed then
 62               storage := storage.calloc(needed)
 63               capacity := needed
 64            else
 65               clear_all
 66            end
 67         end
 68         next_generation
 69      ensure
 70         left_aligned: storage_lower = 0
 71         lower_set: lower = min_index
 72         upper_set: upper = max_index
 73         items_set: all_default
 74      end
 75
 76   with_capacity (needed_capacity, low: INTEGER)
 77         -- Create an empty array with `capacity' initialized
 78         -- at least to `needed_capacity' and `lower' set to `low'.
 79      require
 80         needed_capacity >= 0
 81      do
 82         if capacity < needed_capacity then
 83            storage := storage.calloc(needed_capacity)
 84            capacity := needed_capacity
 85         end
 86         lower := low
 87         upper := low - 1
 88         storage_lower := 0
 89         next_generation
 90      ensure
 91         left_aligned: storage_lower = 0
 92         empty: is_empty
 93         big_enough: needed_capacity <= capacity
 94         lower_set: lower = low
 95      end
 96
 97feature {ANY} -- Modification:
 98   resize (min_index, max_index: INTEGER)
 99         -- Resize to bounds `min_index' and `max_index'. Do not lose any
100         -- item whose index is in both [`lower' .. `upper'] and
101         -- [`min_index' .. `max_index']. New positions if any are
102         -- initialized with the appropriate default value.
103      require
104         min_index <= max_index + 1
105      local
106         bubble, old_wrap, needed, inter_max, inter_min: INTEGER
107      do
108         needed := max_index - min_index + 1
109         if needed > 0 then
110            bubble := needed - capacity
111            if needed > capacity then
112               old_wrap := wrap_point
113               if capacity = 0 then
114                  storage := storage.calloc(needed)
115               else
116                  storage := storage.realloc(capacity, needed)
117               end
118               capacity := needed
119            end
120            inter_max := max_index.min(upper)
121            inter_min := min_index.max(lower)
122            if inter_max >= inter_min then
123               if old_wrap.in_range(inter_min, inter_max) then
124                  if bubble > 0 then
125                     -- A bubble was created inside the data. Update upper to acknowledge this (preconditions
126                     -- will fail if we don't)
127                     upper := upper + bubble
128                     squeeze_bubble(inter_min, inter_max + bubble, old_wrap, bubble)
129                     -- Upper is written below, no need to re-adjust
130                  end
131               end
132               storage_lower := storage_lower - lower + min_index
133               if storage_lower < 0 then
134                  storage_lower := storage_lower + capacity
135               elseif storage_lower >= capacity then
136                  storage_lower := storage_lower - capacity
137               end
138               lower := min_index
139               upper := max_index
140               if inter_min > lower then
141                  clear_slice(lower, inter_min - 1)
142               end
143               if inter_max < upper then
144                  clear_slice(inter_max + 1, upper)
145               end
146            else
147               lower := min_index
148               upper := max_index
149               clear_all
150            end
151         else
152            lower := min_index
153            upper := max_index
154         end
155         next_generation
156      ensure
157         lower = min_index
158         upper = max_index
159      end
160
161   reindex (new_lower: INTEGER)
162         -- Change indexing to take in account the expected `new_lower'
163         -- index. The `upper' index is translated accordingly.
164      do
165         upper := upper + new_lower - lower
166         lower := new_lower
167      ensure
168         lower = new_lower
169         count = old count
170      end
171
172feature {ANY} -- Implementation of deferred:
173   count: INTEGER
174      do
175         Result := upper - lower + 1
176      end
177
178   is_empty: BOOLEAN
179      do
180         Result := upper < lower -- *** Is there a better implementation ? *** Dom march  30th 2006 ***
181      end
182
183   subarray (min, max: INTEGER): like Current
184      do
185         Result := slice(min, max)
186         Result.reindex(min)
187      ensure then
188         Result.lower = min
189      end
190
191   item (i: INTEGER): E_
192      do
193         Result := storage.item(storage_index(i))
194      end
195
196   put (element: like item; i: INTEGER)
197      do
198         storage.put(element, storage_index(i))
199         next_generation
200      end
201
202   force (element: like item; index: INTEGER)
203      require else
204         True
205      do
206         if upper < index then
207            if index = upper + 1 then
208               add_last(element)
209            else
210               resize(lower, index)
211               put(element, index)
212            end
213         elseif index < lower then
214            if index = lower - 1 then
215               add_first(element)
216               reindex(lower - 1)
217            else
218               resize(index, upper)
219               put(element, index)
220            end
221         else
222            put(element, index)
223         end
224      ensure then
225         lower = index.min(old lower)
226      end
227
228   copy (other: like Current)
229      local
230         needed_capacity, o_s_u: INTEGER
231      do
232         storage_lower := 0
233         lower := other.lower
234         upper := other.upper
235         needed_capacity := upper - lower + 1
236         if capacity < needed_capacity then
237            storage := storage.calloc(needed_capacity)
238            capacity := needed_capacity
239         end
240         if needed_capacity > 0 then
241            o_s_u := other.storage_upper
242            if o_s_u >= other.storage_lower then
243               storage.slice_copy(0, other.storage, other.storage_lower, o_s_u)
244            else
245               storage.slice_copy(0, other.storage, other.storage_lower, other.capacity - 1)
246               storage.slice_copy(other.capacity - other.storage_lower, other.storage, 0, o_s_u)
247            end
248         end
249         next_generation
250      end
251
252   set_all_with (v: like item)
253      local
254         s_u: INTEGER
255      do
256         if is_empty then
257         else
258            s_u := storage_upper
259            if storage_lower <= s_u then
260               storage.set_slice_with(v, storage_lower, s_u)
261            else
262               storage.set_all_with(v, s_u)
263               storage.set_slice_with(v, storage_lower, capacity - 1)
264            end
265         end
266         next_generation
267      end
268
269   remove_first
270      do
271         lower := lower + 1
272         storage_lower := storage_lower + 1
273         if storage_lower = capacity then
274            storage_lower := 0
275         end
276         next_generation
277      ensure then
278         upper = old upper
279      end
280
281   remove_head (n: INTEGER)
282      local
283         i: INTEGER
284      do
285         from
286            i := n
287         until
288            i = 0
289         loop
290            remove_first
291            i := i - 1
292         end
293         next_generation
294      ensure then
295         upper = old upper
296      end
297
298   remove (index: INTEGER)
299      do
300         if index /= upper then
301            if index /= lower then
302               squeeze_bubble(lower, upper, index, 1)
303            else
304               storage_lower := storage_lower + 1
305               if storage_lower = capacity then
306                  storage_lower := 0
307               end
308            end
309         end
310         upper := upper - 1
311         next_generation
312      end
313
314   clear_count
315      do
316         upper := lower - 1
317         next_generation
318      ensure then
319         capacity = old capacity
320      end
321
322   clear_count_and_capacity
323      local
324         null_storage: like storage
325      do
326         upper := lower - 1
327         storage := null_storage
328         capacity := 0
329         next_generation
330      ensure then
331         capacity = 0
332      end
333
334   add_first (element: like item)
335      do
336         make_space_for_one
337         upper := upper + 1
338         storage_lower := storage_lower - 1
339         if storage_lower < 0 then
340            storage_lower := storage_lower + capacity
341         end
342         storage.put(element, storage_lower)
343         next_generation
344      end
345
346   add_last (element: like item)
347      do
348         make_space_for_one
349         upper := upper + 1
350         put(element, upper)
351      end
352
353   from_collection (model: TRAVERSABLE[like item])
354      local
355         i, up: INTEGER
356      do
357         from
358            with_capacity(model.count, model.lower)
359            i := model.lower
360            up := model.upper
361         until
362            i > up
363         loop
364            add_last(model.item(i))
365            i := i + 1
366         end
367         next_generation
368      ensure then
369         lower = model.lower
370         upper = model.upper
371      end
372
373   all_default: BOOLEAN
374      local
375         s_u: INTEGER
376      do
377         if is_empty then
378            Result := True
379         else
380            s_u := storage_upper
381            if storage_lower <= s_u then
382               Result := storage.slice_default(storage_lower, s_u)
383            else
384               Result := storage.all_default(s_u) and then storage.slice_default(storage_lower, capacity - 1)
385            end
386         end
387      end
388
389   occurrences (element: like item): INTEGER
390      local
391         s_u: INTEGER
392      do
393         if is_empty then
394         else
395            s_u := storage_upper
396            if storage_lower <= s_u then
397               Result := storage.slice_occurrences(element, storage_lower, s_u)
398            else
399               Result := storage.occurrences(element, s_u) + storage.slice_occurrences(element, storage_lower, capacity - 1)
400            end
401         end
402      end
403
404   fast_occurrences (element: like item): INTEGER
405      local
406         s_u: INTEGER
407      do
408         if is_empty then
409         else
410            s_u := storage_upper
411            if storage_lower <= s_u then
412               Result := storage.slice_fast_occurrences(element, storage_lower, s_u)
413            else
414               Result := storage.fast_occurrences(element, s_u) + storage.slice_fast_occurrences(element, storage_lower, capacity - 1)
415            end
416         end
417      end
418
419   first_index_of (element: like item): INTEGER
420      local
421         s_u: INTEGER
422      do
423         if is_empty then
424            Result := upper + 1
425         else
426            s_u := storage_upper
427            if storage_lower <= s_u then
428               Result := storage.index_of(element, storage_lower, s_u) + lower - storage_lower
429            else
430               Result := storage.index_of(element, storage_lower, capacity - 1)
431               if Result = capacity then
432                  Result := storage.first_index_of(element, s_u) + upper - s_u
433               else
434                  Result := Result + lower - storage_lower
435               end
436            end
437         end
438      end
439
440   index_of (element: like item; start_index: INTEGER): INTEGER
441      local
442         s_start_index, s_u: INTEGER
443      do
444         if is_empty then
445            Result := upper + 1
446         else
447            s_u := storage_upper
448            s_start_index := storage_index(start_index)
449            if s_start_index <= s_u then
450               Result := storage.index_of(element, s_start_index, s_u) + lower - storage_lower
451            else
452               Result := storage.index_of(element, s_start_index, capacity - 1)
453               if Result = capacity then
454                  Result := storage.first_index_of(element, s_u) + upper - s_u
455               else
456                  Result := Result + lower - storage_lower
457               end
458            end
459         end
460      end
461
462   reverse_index_of (element: like item; start_index: INTEGER): INTEGER
463      local
464         safe_equal: SAFE_EQUAL[E_]
465      do
466         from
467            Result := start_index
468         until
469            Result < lower or else safe_equal.test(item(Result), element)
470         loop
471            Result := Result - 1
472         end
473      end
474
475   fast_first_index_of (element: like item): INTEGER
476      local
477         s_u: INTEGER
478      do
479         if is_empty then
480            Result := upper + 1
481         else
482            s_u := storage_upper
483            if storage_lower <= s_u then
484               Result := storage.fast_index_of(element, storage_lower, s_u) + lower - storage_lower
485            else
486               Result := storage.fast_index_of(element, storage_lower, capacity - 1)
487               if Result = capacity then
488                  Result := storage.fast_first_index_of(element, s_u) + upper - s_u
489               else
490                  Result := Result + lower - storage_lower
491               end
492            end
493         end
494      end
495
496   fast_index_of (element: like item; start_index: INTEGER): INTEGER
497      local
498         s_start_index, s_u: INTEGER
499      do
500         if is_empty then
501            Result := upper + 1
502         else
503            s_u := storage_upper
504            s_start_index := storage_index(start_index)
505            if s_start_index <= s_u then
506               Result := storage.fast_index_of(element, s_start_index, s_u) + lower - storage_lower
507            else
508               Result := storage.fast_index_of(element, s_start_index, capacity - 1)
509               if Result = capacity then
510                  Result := storage.fast_first_index_of(element, s_u) + upper - s_u
511               else
512                  Result := Result + lower - storage_lower
513               end
514            end
515         end
516      end
517
518   fast_reverse_index_of (element: like item; start_index: INTEGER): INTEGER
519      do
520         from
521            Result := start_index
522         until
523            Result < lower or else item(Result) = element
524         loop
525            Result := Result - 1
526         end
527      end
528
529   fast_is_equal (other: like Current): BOOLEAN
530      local
531         wp, owp: INTEGER
532      do
533         if Current = other then
534            Result := True
535         elseif lower = other.lower and then upper = other.upper then
536            wp := wrap_point
537            owp := other.wrap_point
538            if wp < owp then
539               Result := other.slices_are_equal(Current, owp, wp)
540            else
541               Result := slices_are_equal(other, wp, owp)
542            end
543         end
544      end
545
546   is_equal (other: like Current): BOOLEAN
547      local
548         wp, owp: INTEGER
549      do
550         if Current = other then
551            Result := True
552         elseif lower = other.lower and then upper = other.upper then
553            wp := wrap_point
554            owp := other.wrap_point
555            if wp < owp then
556               Result := other.slices_are_equal_map(Current, owp, wp)
557            else
558               Result := slices_are_equal_map(other, wp, owp)
559            end
560         end
561      end
562
563   slice (min, max: INTEGER): like Current
564      local
565         storage_min, storage_max: INTEGER
566      do
567         create Result.make(lower, lower + max - min)
568         if max >= min then
569            storage_min := storage_index(min)
570            storage_max := storage_index(max)
571            if storage_max >= storage_min then
572               Result.storage.slice_copy(0, storage, storage_min, storage_max)
573            else
574               Result.storage.slice_copy(0, storage, storage_min, capacity - 1)
575               Result.storage.slice_copy(capacity - storage_min, storage, 0, storage_max)
576            end
577         end
578      end
579
580   new_iterator: ITERATOR[E_]
581      do
582         create {ITERATOR_ON_TRAVERSABLE[E_]} Result.make(Current)
583      end
584
585   first: like item
586      do
587         Result := storage.item(storage_lower)
588      end
589
590feature {}
591   make_space_for_one
592         -- Make sure `storage' is big enough to hold at least one
593         -- more element.
594      local
595         old_capacity, s_u, wp: INTEGER
596      do
597         if capacity < count + 1 then
598            if capacity = 0 then
599               capacity := 16
600               storage := storage.calloc(capacity)
601            else
602               wp := wrap_point
603               s_u := storage_upper
604               old_capacity := capacity
605               capacity := 2 * capacity
606               storage := storage.realloc(old_capacity, capacity)
607               if s_u < storage_lower then
608                  -- A bubble was created inside the data. Update upper to acknowledge this (preconditions
609                  -- will fail if we don't)
610                  upper := upper + capacity - old_capacity
611                  squeeze_bubble(lower, upper, wp, capacity - old_capacity)
612                  -- Update upper
613                  upper := upper - capacity + old_capacity
614               end
615            end
616         end
617         next_generation
618      end
619
620   clear_slice (min, max: INTEGER)
621      require
622         valid_index(min)
623         valid_index(max)
624      local
625         s_min, s_max: INTEGER
626      do
627         if max >= min then
628            s_min := storage_index(min)
629            s_max := storage_index(max)
630            if s_max >= s_min then
631               storage.clear(s_min, s_max)
632            else
633               storage.clear(s_min, capacity - 1)
634               storage.clear(0, s_max)
635            end
636         end
637         next_generation
638      end
639
640   squeeze_bubble (min, max, pos, length: INTEGER)
641      require
642         valid_index(min)
643         valid_index(max)
644         pos.in_range(min + 1, max - length)
645         length > 0
646      do
647         if pos - min <= max - pos - length then
648            move(min, pos - 1, length)
649            storage_lower := storage_lower + length
650            if storage_lower >= capacity then
651               storage_lower := storage_lower - capacity
652            end
653         else
654            move(pos + length, max, -length)
655         end
656         next_generation
657      end
658
659   unwrap
660      local
661         bottom, top, free, old_bound, overlap: INTEGER; tmp: like storage
662      do
663         if is_wrapped then
664            bottom := wrap_point - lower
665            top := upper - wrap_point + 1
666            free := capacity - count
667            if free >= bottom then
668               old_bound := upper
669               upper := upper + bottom
670               move(lower, old_bound, bottom)
671               storage_lower := 0
672               upper := old_bound
673            elseif free >= top then
674               old_bound := lower
675               lower := lower - top
676               storage_lower := storage_lower - top
677               move(old_bound, upper, -top)
678               lower := old_bound
679            elseif bottom <= top then
680               overlap := bottom - free
681               tmp := tmp.calloc(overlap)
682               tmp.slice_copy(0, storage, storage_lower, storage_lower + overlap - 1)
683               old_bound := upper
684               lower := lower + overlap
685               storage_lower := storage_lower + overlap
686               upper := upper + bottom
687               move(lower, old_bound, bottom)
688               upper := old_bound
689               storage.slice_copy(0, tmp, 0, overlap - 1)
690               lower := lower - overlap
691               storage_lower := 0
692            else
693               overlap := top - free
694               tmp := tmp.calloc(overlap)
695               tmp.slice_copy(0, storage, storage_upper - overlap + 1, storage_upper)
696               old_bound := lower
697               lower := lower - top
698               storage_lower := storage_lower - top
699               upper := upper - overlap
700               move(old_bound, upper, -top)
701               lower := old_bound
702               storage.slice_copy(storage_upper + 1, tmp, 0, overlap - 1)
703               upper := upper + overlap
704            end
705         end
706         next_generation
707      ensure
708         not is_wrapped
709         is_equal(old twin)
710      end
711
712feature {ANY}
713   to_external: POINTER
714         -- Gives C access into the internal `storage' of the ARRAY.
715         -- Result is pointing the element at index `lower'.
716         --
717         -- NOTE: do not free/realloc the Result. Any operation that changes
718         --       `lower' or `upper' can make this pointer useless (because the
719         --       array has wrapped or its beginning in the storage has moved),
720         --       and operations that change `capacity' can make it invalid
721         --       (because new memory has been allocated and the old memory has
722         --       been freed)
723      do
724         unwrap
725         Result := storage.to_pointer + storage_lower * storage.element_sizeof
726      ensure then
727         not is_wrapped
728      end
729
730   is_wrapped: BOOLEAN
731      do
732         Result := storage_lower + count > capacity
733      ensure
734         Result = (not is_empty and then storage_lower > storage_upper)
735      end
736
737feature {RING_ARRAY}
738   storage_lower: INTEGER
739         -- Index of `first' in `storage'
740         -- This would always be 0 for regular arrays.
741
742   storage_upper: INTEGER
743         -- Index of `last' in `storage'
744      require
745         not is_empty
746      do
747         Result := storage_index(upper)
748      ensure
749         in_storage(Result)
750      end
751
752   storage_index (i: INTEGER): INTEGER
753         -- Index in `storage' corresponding to index `i' in `Current'
754      require
755         valid_index(i)
756      do
757         Result := i - lower + storage_lower
758         if Result >= capacity then
759            Result := Result - capacity
760         end
761      ensure
762         in_storage(Result)
763      end
764
765   in_storage (index: INTEGER): BOOLEAN
766      do
767         Result := index.in_range(0, capacity - 1)
768      ensure
769         Result = (0 <= index and index < capacity)
770      end
771
772   wrap_point: INTEGER
773         -- Index in Current (seen as a COLLECTION) such that for any
774         -- `valid_index'es i and j, if i < wrap_point and j >=
775         -- wrap_point then storage_index(i) > storage_index(j)
776         --
777         -- This can happen because of the circular nature of the
778         -- array. `wrap_point' is not a `valid_index' if and only if
779         -- there is no such point (i.e. the array doesn't wrap).
780      do
781         Result := capacity + lower - storage_lower
782      ensure
783         capacity > 0 implies Result > lower
784         valid_index(Result) = is_wrapped
785      end
786
787   slices_are_equal (other: like Current; wp, owp: INTEGER): BOOLEAN
788      require
789         wp >= owp
790         lower = other.lower
791         upper = other.upper
792      local
793         oswp: INTEGER
794      do
795         if owp > upper then
796            Result := storage.slice_fast_memcmp(storage_lower, other.storage, other.storage_lower, other.storage_upper)
797         elseif wp > upper or else wp = owp then
798            Result := storage.slice_fast_memcmp(storage_lower, other.storage, other.storage_lower, other.capacity - 1) and then storage.slice_fast_memcmp(storage_index(owp), other.storage, 0, other.storage_upper)
799         else
800            oswp := other.storage_index(wp)
801            Result := storage.slice_fast_memcmp(storage_lower, other.storage, other.storage_lower, other.capacity - 1) and then storage.slice_fast_memcmp(storage_index(owp), other.storage, 0, oswp - 1) and then storage.slice_fast_memcmp(0, other.storage, oswp, other.storage_upper)
802         end
803      end
804
805   slices_are_equal_map (other: like Current; wp, owp: INTEGER): BOOLEAN
806      require
807         wp >= owp
808         lower = other.lower
809         upper = other.upper
810      local
811         oswp: INTEGER
812      do
813         if owp > upper then
814            Result := storage.slice_memcmp(storage_lower, other.storage, other.storage_lower, other.storage_upper)
815         elseif wp > upper or else wp = owp then
816            Result := storage.slice_memcmp(storage_lower, other.storage, other.storage_lower, other.capacity - 1) and then storage.slice_memcmp(storage_index(owp), other.storage, 0, other.storage_upper)
817         else
818            oswp := other.storage_index(wp)
819            Result := storage.slice_memcmp(storage_lower, other.storage, other.storage_lower, other.capacity - 1) and then storage.slice_memcmp(storage_index(owp), other.storage, 0, oswp - 1) and then storage.slice_memcmp(0, other.storage, oswp, other.storage_upper)
820         end
821      end
822
823feature {} -- Garbage collector tuning (very low-level):
824   mark_native_arrays
825         -- For performance reasons, the unused area of `storage' is always left as it is when
826         -- some elements are removed. No time is lost to clean the released area with a Void
827         -- or a 0 value. (Look for example the `remove_last' implementation.)
828         -- Thus, the unused area of `storage' may contains references of actually unreachable
829         -- objects. The following `mark_native_arrays' actually replace the
830         -- default behavior (the call is automatic) in order to mark only reachable objects.
831      local
832         i: INTEGER
833      do
834         if not is_empty then
835            if is_wrapped then
836               from
837                  i := capacity - 1
838               until
839                  i < storage_lower
840               loop
841                  mark_item(storage, i)
842                  i := i - 1
843               end
844               from
845                  i := storage_upper
846               until
847                  i < 0
848               loop
849                  mark_item(storage, i)
850                  i := i - 1
851               end
852            else
853               from
854                  i := storage_upper
855               until
856                  i < storage_lower
857               loop
858                  mark_item(storage, i)
859                  i := i - 1
860               end
861            end
862         end
863      end
864
865feature {} -- Implement manifest generic creation (very low-level):
866   manifest_make (needed_capacity: INTEGER; initial_lower: INTEGER)
867         -- Manifest creation of a RING_ARRAY `lower' set to `initial_lower'.
868      do
869         make(initial_lower, initial_lower + needed_capacity - 1)
870      end
871
872   manifest_put (index: INTEGER; element: like item)
873      do
874         storage.put(element, index)
875      ensure
876         item(index + lower) = element
877      end
878
879invariant
880   is_empty or in_storage(storage_lower)
881
882end -- class RING_ARRAY
883--
884-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
885--
886-- Permission is hereby granted, free of charge, to any person obtaining a copy
887-- of this software and associated documentation files (the "Software"), to deal
888-- in the Software without restriction, including without limitation the rights
889-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
890-- copies of the Software, and to permit persons to whom the Software is
891-- furnished to do so, subject to the following conditions:
892--
893-- The above copyright notice and this permission notice shall be included in
894-- all copies or substantial portions of the Software.
895--
896-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
897-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
898-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
899-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
900-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
901-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
902-- THE SOFTWARE.