PageRenderTime 114ms CodeModel.GetById 20ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 82ms

/src/lib/storage/low_level/fixed_array.e

http://github.com/tybor/Liberty
Specman e | 713 lines | 556 code | 51 blank | 106 comment | 27 complexity | 153f0ef8859532a3f17847eac54071b0 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4expanded class FIXED_ARRAY[E_]
  5
  6insert
  7   SAFE_EQUAL[E_]
  8   TRAVERSABLE[E_]
  9
 10creation {ANY}
 11   default_create
 12
 13feature {FIXED_ARRAY}
 14   elements: NATIVE_ARRAY[E_]
 15
 16   capacity: INTEGER
 17         -- The number of slots this array holds
 18
 19feature {FIXED_ARRAY}
 20   do_calloc (c: like capacity) is
 21      require
 22         c >= 0
 23      do
 24         elements := elements.calloc(c)
 25         capacity := c
 26      ensure
 27         capacity = c
 28      end
 29
 30   do_realloc (e: like elements; c: like capacity) is
 31      require
 32         c >= 0
 33      do
 34         elements := e.realloc(capacity, c)
 35         capacity := c
 36      ensure
 37         capacity = c
 38      end
 39
 40feature {ANY} -- Basic features:
 41   element_sizeof: INTEGER is
 42         -- The size in number of bytes for type `E_'.
 43      do
 44         Result := elements.element_sizeof
 45      end
 46
 47   calloc (nb_elements: INTEGER): like Current is
 48         -- Allocate a new array of `nb_elements' of type `E_'.
 49         -- The new array is initialized with default values.
 50      require
 51         nb_elements > 0
 52      do
 53         Result.do_calloc(nb_elements)
 54      ensure
 55         Result.capacity = nb_elements
 56         Result.all_default
 57      end
 58
 59   item (index: INTEGER): E_ is
 60         -- To read an `item'.
 61         -- Assume that `calloc' is already done and that `index' is the range [0 .. `capacity'-1].
 62      require
 63         index >= 0 and then index < capacity
 64      do
 65         Result := elements.item(index)
 66      end
 67
 68   put (element: E_; index: INTEGER) is
 69         -- To write an item.
 70         -- Assume that `calloc' is already done and that `index'
 71         -- is the range [0 .. `capacity'-1].
 72      require
 73         index >= 0 and then index < capacity
 74      do
 75         elements.put(element, index)
 76      ensure
 77         item(index) = element
 78      end
 79
 80   lower: INTEGER is 0
 81
 82   upper: INTEGER is
 83      do
 84         Result := capacity - 1
 85      end
 86
 87   count: INTEGER is
 88      do
 89         Result := capacity
 90      end
 91
 92feature {ANY}
 93   realloc (new_nb_elts: INTEGER): like Current is
 94         -- Assume Current is a valid NATIVE_ARRAY in range
 95         -- [0 .. `capacity'-1]. Allocate a bigger new array in
 96         -- range [0 .. `new_nb_elts'-1].
 97         -- Old range is copied in the new allocated array.
 98         -- New items are initialized with default values.
 99      require
100         new_nb_elts > capacity
101      do
102         Result.do_realloc(elements, new_nb_elts)
103      ensure
104         Result.capacity = new_nb_elts
105      end
106
107feature {ANY} -- Comparison:
108   memcmp (other: like Current): BOOLEAN is
109         -- True if all elements in range [0 .. `capacity'-1] are identical using `is_equal'.
110         -- See also `fast_memcmp'.
111      require
112         other.capacity = capacity
113      local
114         i: INTEGER
115      do
116         from
117            i := capacity - 1
118         until
119            i < 0 or else not safe_equal(item(i), other.item(i))
120         loop
121            i := i - 1
122         end
123         Result := i < 0
124      end
125
126   slice_memcmp (at: INTEGER; other: like Current; other_low, other_up: INTEGER): BOOLEAN is
127         -- True if all elements in range [`at' .. `at' + `other_up' - `other_low'] are identical
128         -- to the elements in range [`other_low' .. `other_up'] of `other' using
129         -- `is_equal'. Assume `Current' and `other' are big enough.
130         -- See also `slice_fast_memcmp'.
131      require
132         at >= 0
133         other_low >= 0
134         other_up >= other_low - 1
135         other_up < other.capacity
136      local
137         i: INTEGER
138      do
139         from
140            i := other_up - other_low
141         until
142            i < 0 or else not safe_equal(item(at + i), other.item(other_low + i))
143         loop
144            i := i - 1
145         end
146         Result := i < 0
147      end
148
149   fast_memcmp (other: like Current): BOOLEAN is
150         -- Same jobs as `memcmp' but uses infix "=" instead of `is_equal'.
151      require
152         other.capacity = capacity
153      local
154         i: INTEGER
155      do
156         from
157            i := capacity - 1
158         until
159            i < 0 or else item(i) /= other.item(i)
160         loop
161            i := i - 1
162         end
163         Result := i < 0
164      end
165
166   slice_fast_memcmp (at: INTEGER; other: like Current; other_low, other_up: INTEGER): BOOLEAN is
167         -- Same jobs as `slice_memcmp' but uses infix "=" instead of `is_equal'.
168      require
169         at >= 0
170         other_low >= 0
171         other_up >= other_low - 1
172         other_up < other.capacity
173      local
174         i: INTEGER
175      do
176         from
177            i := other_up - other_low
178         until
179            i < 0 or else item(at + i) /= other.item(other_low + i)
180         loop
181            i := i - 1
182         end
183         Result := i < 0
184      end
185
186   deep_memcmp (other: like Current; nb_elements: INTEGER): BOOLEAN is
187         -- Same jobs as `memcmp' but uses `is_deep_equal' instead of `is_equal'.
188      local
189         i: INTEGER; e1, e2: like item
190      do
191         from
192            i := nb_elements - 1
193            Result := True
194         until
195            not Result or else i < 0
196         loop
197            e1 := item(i)
198            e2 := other.item(i)
199            if e1 = e2 then
200            elseif e1 /= Void then
201               if e2 /= Void then
202                  Result := e1.is_deep_equal(e2)
203               else
204                  Result := False
205               end
206            else
207               Result := False
208            end
209            i := i - 1
210         end
211      end
212
213   slice_deep_memcmp (at: INTEGER; other: like Current; other_low, other_up: INTEGER): BOOLEAN is
214         -- Same jobs as `slice_memcmp' but uses `is_deep_equal' instead of `is_equal'.
215      require
216         at >= 0
217         other_low >= 0
218         other_up >= other_low - 1
219         other_up < other.capacity
220      local
221         i: INTEGER; e1, e2: like item
222      do
223         from
224            i := other_up - other_low
225            Result := True
226         until
227            not Result or else i < 0
228         loop
229            e1 := item(i)
230            e2 := other.item(i)
231            if e1 = e2 then
232            elseif e1 /= Void then
233               if e2 /= Void then
234                  Result := e1.is_deep_equal(e2)
235               else
236                  Result := False
237               end
238            else
239               Result := False
240            end
241            i := i - 1
242         end
243      end
244
245feature {ANY} -- Searching:
246   first_index_of (element: like item): INTEGER is
247         -- Using `is_equal' for comparison, gives the index of the first occurrence of `element' at or after
248         -- `0'. Answer `-1' when the search fail.
249         -- See also `fast_index_of', `reverse_index_of'.
250      do
251         Result := index_of(element, 0)
252      ensure
253         Result.in_range(-1, capacity - 1)
254         Result /= -1 implies safe_equal(element, item(Result))
255      end
256
257   index_of (element: like item; start_index: INTEGER): INTEGER is
258         -- Using `is_equal' for comparison, gives the index of the first occurrence of `element' at or after
259         -- `start_index'. Answer `-1' when the search fail.
260         -- See also `fast_index_of', `reverse_index_of'.
261      require
262         start_index >= 0
263         start_index < capacity
264      do
265         from
266            Result := start_index
267         until
268            Result >= capacity or else safe_equal(element, item(Result))
269         loop
270            Result := Result + 1
271         end
272         if Result >= capacity then
273            Result := -1
274         end
275      ensure
276         Result.in_range(-1, capacity - 1)
277         Result /= -1 implies safe_equal(element, item(Result))
278      end
279
280   reverse_index_of (element: like item): INTEGER is
281         -- Using `is_equal' for comparison, gives the index of the first occurrence of `element' at or before
282         -- `capacity'-1. Search is done in reverse direction, which means from `up' down to the
283         -- `0'. Answer `-1' when the search fail.
284         -- See also `fast_reverse_index_of', `index_of'.
285      do
286         from
287            Result := capacity - 1
288         until
289            Result < 0 or else safe_equal(element, item(Result))
290         loop
291            Result := Result - 1
292         end
293      ensure
294         Result.in_range(-1, capacity - 1)
295         Result /= -1 implies safe_equal(element, item(Result))
296      end
297
298   fast_first_index_of (element: like item): INTEGER is
299         -- Using basic `=' for comparison, gives the index of the first occurrence of `element' at or after
300         -- `0'. Answer `-1' when the search fail.
301         -- See also `fast_index_of', `reverse_index_of'.
302      do
303         Result := fast_index_of(element, 0)
304      ensure
305         Result.in_range(-1, capacity - 1)
306         Result /= -1 implies element = item(Result)
307      end
308
309   fast_index_of (element: like item; start_index: INTEGER): INTEGER is
310         -- Using basic `=' for comparison, gives the index of the first occurrence of `element' at or after
311         -- `start_index'. Answer `-1' when the search fail.
312         -- See also `index_of', `reverse_index_of'.
313      require
314         start_index >= 0
315         start_index < capacity
316      do
317         from
318            Result := start_index
319         until
320            Result >= capacity or else element = item(Result)
321         loop
322            Result := Result + 1
323         end
324         if Result >= capacity then
325            Result := -1
326         end
327      ensure
328         Result.in_range(start_index, capacity - 1)
329         Result /= -1 implies element = item(Result)
330      end
331
332   fast_reverse_index_of (element: like item): INTEGER is
333         -- Using basic `=' for comparison, gives the index of the first occurrence of `element' at or before
334         -- `capacity'-1. Search is done in reverse direction, which means from `up' down to the
335         -- `0'. Answer `-1' when the search fail.
336         -- See also `reverse_index_of', `index_of'.
337      do
338         from
339            Result := capacity - 1
340         until
341            Result < 0 or else element = item(Result)
342         loop
343            Result := Result - 1
344         end
345      ensure
346         Result.in_range(-1, capacity - 1)
347         Result /= -1 implies element = item(Result)
348      end
349
350   has (element: like item): BOOLEAN is
351         -- Look for `element' using `is_equal' for comparison.
352         -- Also consider `fast_has' to choose the most appropriate.
353      local
354         i: INTEGER
355      do
356         from
357            i := capacity - 1
358         until
359            Result or else i < 0
360         loop
361            Result := safe_equal(element, item(i))
362            i := i - 1
363         end
364      end
365
366   fast_has (element: like item): BOOLEAN is
367         -- Look for `element' using basic `=' for comparison.
368         -- Also consider `has' to choose the most appropriate.
369      local
370         i: INTEGER
371      do
372         from
373            i := capacity - 1
374         until
375            Result or else i < 0
376         loop
377            Result := element = item(i)
378            i := i - 1
379         end
380      end
381
382feature {ANY} -- Removing:
383   remove_first is
384         -- Move range [1 .. `capacity'-1] by 1 position left.
385      require
386         capacity > 0
387      do
388         remove(0)
389      end
390
391   remove (index: INTEGER) is
392         -- Move range [`index' + 1 .. `capacity' - 1] by 1 position left.
393         -- The last element is set to the default value.
394      require
395         index >= 0
396         index < capacity
397      local
398         i: INTEGER; e: E_
399      do
400         from
401            i := index
402         until
403            i = capacity - 1
404         loop
405            put(item(i + 1), i)
406            i := i + 1
407         end
408         put(e, i)
409      end
410
411feature {ANY} -- Replacing:
412   replace_all (old_value, new_value: like item) is
413         -- Replace all occurrences of the element `old_value' by `new_value' using `is_equal' for comparison.
414         -- See also `fast_replace_all' to choose the apropriate one.
415      local
416         i: INTEGER
417      do
418         from
419            i := capacity - 1
420         until
421            i < 0
422         loop
423            if safe_equal(old_value, item(i)) then
424               put(new_value, i)
425            end
426            i := i - 1
427         end
428      end
429
430   fast_replace_all (old_value, new_value: like item) is
431         -- Replace all occurrences of the element `old_value' by `new_value'
432         -- using basic `=' for comparison.
433         -- See also `replace_all' to choose the apropriate one.
434      local
435         i: INTEGER
436      do
437         from
438            i := capacity - 1
439         until
440            i < 0
441         loop
442            if old_value = item(i) then
443               put(new_value, i)
444            end
445            i := i - 1
446         end
447      end
448
449feature {ANY} -- Adding:
450   copy_at (at: INTEGER; src: like Current) is
451         -- Copy range [0 .. `src.capacity - 1'] of `src' to range [`at' .. `at + src.capacity - 1'] of `Current'.
452         -- No subscript checking.
453      require
454         at >= 0
455         src.capacity >= 0
456         at + src.capacity <= capacity
457      do
458         slice_copy(at, src, 0, src.capacity-1)
459      end
460
461   slice_copy (at: INTEGER; src: like Current; src_min, src_max: INTEGER) is
462         -- Copy range [`src_min' .. `src_max'] of `src' to range [`at' .. `at + src_max - src_min'] of `Current'.
463         -- No subscript checking.
464         --*** NATIVE_ARRAY[CHARACTER/INTEGER_8] are modified byte per byte. Efficiency should be improved here.
465      require
466         at >= 0
467         src_max >= src_min - 1
468         at + src_max - src_min < capacity
469         useful_work: src /= Current or at /= src_min
470      do
471         elements.slice_copy(at, src.elements, src_min, src_max)
472      end
473
474feature {ANY} -- Other:
475   set_all_with (v: like item) is
476         -- Set all elements in range [0 .. `capacity'-1] with value `v'.
477      do
478         set_slice_with(v, 0, capacity - 1)
479      end
480
481   set_slice_with (v: like item; low, up: INTEGER) is
482         -- Set all elements in range [`low' .. `up'] with value `v'.
483      require
484         low >= 0
485         up >= low - 1
486         up < capacity
487      local
488         i: INTEGER
489      do
490         from
491            i := low
492         until
493            i > up
494         loop
495            put(v, i)
496            i := i + 1
497         end
498      end
499
500   clear_all is
501         -- Set all elements in range [0 .. `capacity'-1] with the default value.
502      local
503         e: E_
504      do
505         set_all_with(e)
506      ensure
507         all_default
508      end
509
510   clear_slice (low, up: INTEGER) is
511         -- Set all elements in range [`low' .. `up'] with the default value.
512      require
513         low >= 0
514         up >= low - 1
515         up < capacity
516      local
517         e: E_
518      do
519         set_slice_with(e, low, up)
520      end
521
522   copy_from (src: like Current) is
523      require
524         src.capacity = capacity
525      do
526         copy_at(0, src)
527      end
528
529   deep_twin_from: like Current is
530         -- To implement `deep_twin'. Allocate a new array of `capacity' initialized  with `deep_twin'.
531      local
532         i: INTEGER; element: like item
533      do
534         if capacity > 0 then
535            from
536               Result := calloc(capacity)
537               i := capacity - 1
538            until
539               i < 0
540            loop
541               element := item(i)
542               if element /= Void then
543                  element := element.deep_twin
544               end
545               Result.put(element, i)
546               i := i - 1
547            end
548         end
549      end
550
551   move (low, up, offset: INTEGER) is
552         -- Move range [`low' .. `up'] by `offset' positions.
553         -- Freed positions are not initialized to default values.
554      require
555         low >= 0
556         up >= low
557         low + offset >= 0
558         up + offset < capacity
559      local
560         i: INTEGER
561      do
562         if offset = 0 then
563         elseif offset < 0 then
564            from
565               i := low
566            until
567               i > up
568            loop
569               put(item(i), i + offset)
570               i := i + 1
571            end
572         else
573            from
574               i := up
575            until
576               i < low
577            loop
578               put(item(i), i + offset)
579               i := i - 1
580            end
581         end
582      end
583
584   occurrences (element: like item): INTEGER is
585         -- Number of occurrences of `element' in range [0 .. `capacity'-1] using `is_equal' for comparison.
586         -- See also `fast_occurrences' to chose the apropriate one.
587      do
588         Result := slice_occurrences(element, 0, capacity - 1)
589      end
590
591   slice_occurrences (element: like item; low, up: INTEGER): INTEGER is
592         -- Number of occurrences of `element' in range [`low' .. `up'] using `is_equal' for comparison.
593         -- See also `slice_fast_occurrences' to chose the apropriate one.
594      require
595         low >= 0
596         up >= low - 1
597         up < capacity
598      local
599         i: INTEGER
600      do
601         from
602            i := low
603         until
604            i > up
605         loop
606            if safe_equal(element, item(i)) then
607               Result := Result + 1
608            end
609            i := i + 1
610         end
611      end
612
613   fast_occurrences (element: like item): INTEGER is
614         -- Number of occurrences of `element' in range [0 .. `capacity'-1] using basic "=" for comparison.
615         -- See also `occurrences' to chose the apropriate one.
616      do
617         Result := slice_fast_occurrences(element, 0, capacity - 1)
618      end
619
620   slice_fast_occurrences (element: like item; low, up: INTEGER): INTEGER is
621         -- Number of occurrences of `element' in range [`low' .. `up']
622         -- using basic "=" for comparison.
623         -- See also `slice_occurrences' to chose the apropriate one.
624      require
625         low >= 0
626         up >= low - 1
627         up < capacity
628      local
629         i: INTEGER
630      do
631         from
632            i := low
633         until
634            i > up
635         loop
636            if element = item(i) then
637               Result := Result + 1
638            end
639            i := i + 1
640         end
641      end
642
643   all_default: BOOLEAN is
644         -- Do all items in range [0 .. `capacity'-1] have their type's default value?
645         -- Note: for non Void items, the test is performed with the `is_default' predicate.
646      do
647         Result := slice_default(0, capacity - 1)
648      end
649
650   slice_default (low, up: INTEGER): BOOLEAN is
651         -- Do all items in range [`low' .. `up'] have their type's default value?
652         -- Note: for non Void items, the test is performed with the `is_default' predicate.
653      require
654         low >= 0
655         up >= low - 1
656         up < capacity
657      local
658         i: INTEGER; v: like item
659      do
660         from
661            Result := True
662            i := low
663         until
664            i > up or else not Result
665         loop
666            v := item(i)
667            if v /= Void then
668               Result := v.is_default
669            end
670            i := i + 1
671         end
672      end
673
674feature {ANY} -- Interfacing with other languages:
675   to_external: POINTER is
676         -- Gives access to the C pointer on the area of storage.
677      do
678         Result := elements.to_pointer
679      end
680
681   from_pointer (pointer: POINTER; nb_elements: INTEGER): like Current is
682         -- Convert `pointer' into Current type.
683      do
684         elements := elements.from_pointer(pointer)
685         capacity := nb_elements
686      ensure
687         Result.capacity = nb_elements
688      end
689
690invariant
691   capacity >= 0
692
693end
694--
695-- Copyright (c) 2009 by all the people cited in the AUTHORS file.
696--
697-- Permission is hereby granted, free of charge, to any person obtaining a copy
698-- of this software and associated documentation files (the "Software"), to deal
699-- in the Software without restriction, including without limitation the rights
700-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
701-- copies of the Software, and to permit persons to whom the Software is
702-- furnished to do so, subject to the following conditions:
703--
704-- The above copyright notice and this permission notice shall be included in
705-- all copies or substantial portions of the Software.
706--
707-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
708-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
709-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
710-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
711-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
712-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
713-- THE SOFTWARE.