PageRenderTime 51ms CodeModel.GetById 24ms app.highlight 13ms RepoModel.GetById 2ms app.codeStats 0ms

/src/lib/storage/low_level/native_array.e

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