PageRenderTime 32ms CodeModel.GetById 21ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/src/wrappers/common/library/c_array.e

http://github.com/tybor/Liberty
Specman e | 773 lines | 501 code | 68 blank | 204 comment | 26 complexity | f13aaa683b4048563f1c78f737cbe859 MD5 | raw file
  1note
  2   description:
  3      "."
  4   copyright:
  5      "[
  6               Copyright (C) 2006-2017: Paolo Redaelli
  7
  8               This library is free software; you can redistribute it and/or
  9               modify it under the terms of the GNU Lesser General Public License
 10               as published by the Free Software Foundation; either version 2.1 of
 11               the License, or (at your option) any later version.
 12
 13               This library is distributed in the hope that it will be useful, but
 14               WITHOUT ANY WARRANTY; without even the implied warranty of
 15               MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 16               Lesser General Public License for more details.
 17
 18               You should have received a copy of the GNU Lesser General Public
 19               License along with this library; if not, write to the Free Software
 20               Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 21               02110-1301 USA
 22         ]"
 23
 24deferred class C_ARRAY[ITEM_ -> C_STRUCT]
 25   -- An array of wrapped item which is also a wrapper to a C array
 26   -- of pointers of item's struct. For example a C_ARRAY[GTK_BUTTON]
 27   -- wraps a GtkButton** array.
 28
 29inherit
 30   WRAPPER_COLLECTION[ITEM_]
 31
 32insert
 33   EXCEPTIONS
 34      -- creation with_capacity, from_collection, from_external_array
 35      undefine copy, fill_tagged_out_memory, is_equal, out_in_tagged_out_memory
 36      end
 37
 38feature {} -- Creation
 39   from_external_array (an_array: POINTER; a_length: INTEGER)
 40      require
 41         array_not_null: an_array.is_not_null
 42         positive_length: a_length > 0
 43      do
 44         upper := a_length - 1
 45         capacity := a_length
 46         storage := storage.from_pointer(an_array)
 47      end
 48
 49   with_capacity (a_capacity: INTEGER)
 50      require
 51         positive_capacity: a_capacity > 0
 52      do
 53         capacity := a_capacity
 54         upper := -1
 55         storage := storage.calloc(a_capacity)
 56      end
 57
 58feature {ANY}
 59   item (i: INTEGER_32): ITEM_
 60      local
 61         ptr: POINTER
 62      do
 63         ptr := storage.item(i)
 64         if ptr.is_not_null then
 65            Result := wrapper(ptr)
 66         end
 67      end
 68
 69   first: ITEM_
 70      do
 71         Result := item(lower)
 72      end
 73
 74   last: ITEM_
 75      do
 76         Result := item(upper)
 77      end
 78
 79feature {ANY} -- Writing:
 80   put (element: like item; i: INTEGER)
 81      do
 82         if element /= Void then
 83            storage.put(element.handle, i)
 84         else
 85            storage.put(default_pointer, i)
 86         end
 87      end
 88
 89   set_all_with (v: like item)
 90      local
 91         i: INTEGER
 92      do
 93         from
 94            i := lower
 95         until
 96            i > upper
 97         loop
 98            put(v, i)
 99            i := i + 1
100         end
101      end
102
103feature {ANY} -- Adding:
104   add_first (element: like item)
105         -- Performance: O(count), not counting the eventual reallocation.
106      local
107         i, j: INTEGER
108      do
109         if count = capacity then
110            capacity := capacity * 2
111            storage := storage.realloc(count, capacity)
112         end
113         from
114            i := upper
115            j := i + 1
116         until
117            i = lower
118         loop
119            storage.put(storage.item(i), j)
120            j := i
121            i := i - 1
122         end
123
124         storage.put(null_or(element), lower)
125         upper := upper + 1
126      end
127
128   add_last (element: like item)
129         -- Performance: O(1), not counting the eventual reallocation.
130      do
131         if count = capacity then
132            capacity := capacity * 2
133            storage := storage.realloc(count, capacity)
134         end
135         check
136            count = upper + 1
137         end
138         -- because the next put command relies on this assumption.
139         storage.put(null_or(element), count)
140         upper := upper + 1
141      end
142
143   add (element: like item; index: INTEGER)
144         -- Performance: O(count-index), not counting the eventual reallocation
145      local
146         i, j: INTEGER
147      do
148         -- Add a new `element' at rank `index' : `count' is increased by one
149         -- and range [`index' .. `upper'] is shifted right by one position.
150         if count = capacity then
151            capacity := capacity * 2
152            storage := storage.realloc(count, capacity)
153         end
154
155         from
156            i := upper
157            j := upper + 1
158         until
159            i < index
160         loop
161            storage.put(storage.item(i), j)
162            j := i
163            i := i - 1
164         end
165
166         storage.put(null_or(element), index)
167         upper := upper + 1
168      end
169
170feature {ANY} -- Modification:
171   copy (other: like Current)
172      local
173         i: INTEGER
174      do
175         if other /= Void then
176            capacity := other.capacity
177            upper := other.upper
178            storage := storage.calloc(other.capacity)
179            from
180               i := lower
181            until
182               i > upper
183            loop
184               put(other.item(i), i)
185               i := i + 1
186            end
187         end
188      end
189
190   force (element: ITEM_; index: INTEGER)
191      do
192         -- Make `element' the item at `index', enlarging the collection if
193         -- necessary (new bounds except `index' are initialized with default
194         -- values).
195         if index > upper then
196            upper := index
197            if index > capacity then
198               debug
199                  print(once "C_ARRAY.force: storage enlarged using realloc%N")
200               end
201               storage := storage.realloc(count, index)
202            end
203         end
204
205         put(element, index)
206      end
207
208   from_collection (model: COLLECTION[like item])
209      local
210         i: ITERATOR[like item]
211      do
212         -- FIXME: signature should be model: TRAVERSABLE, once SE2.3 is out
213         with_capacity(model.count)
214         from
215            i := model.new_iterator
216            i.start
217         until
218            i.is_off
219         loop
220            add_last(i.item)
221            i.next
222         end
223      end
224
225feature {ANY} -- Removing:
226   remove_first
227         -- Performance: O(count)
228      local
229         i, j: INTEGER
230      do
231         -- Remove the `first' element of the collection.
232         from
233            i := lower
234            j := lower + 1
235         until
236            j > upper
237         loop
238            storage.put(storage.item(j), i)
239            i := j
240            j := j + 1
241         end
242
243         upper := upper - 1
244      end
245
246   remove_head (n: INTEGER)
247         -- Performance: O(upper-n)
248      local
249         i, j: INTEGER
250      do
251         -- Remove the `n' elements of the collection.
252         from
253            i := lower
254            j := lower + n
255         until
256            j > upper
257         loop
258            storage.put(storage.item(j), i)
259            i := i + 1
260            j := j + 1
261         end
262
263         upper := upper - n
264      end
265
266   remove (index: INTEGER)
267         -- Performance: O(count)
268      local
269         i, j: INTEGER
270      do
271         -- Remove the item at position `index'. Followings items are shifted
272         -- left by one position.
273         from
274            i := index
275            j := index + 1
276         until
277            j >= upper
278         loop
279            storage.put(storage.item(j), i)
280            i := j
281            j := j + 1
282         end
283
284         upper := upper - 1
285      end
286
287   remove_last
288         -- Performance: O(1)
289      do
290         -- Remove the `last' item.
291         storage.put(default_pointer, upper)
292         upper := upper - 1
293      end
294
295   remove_tail (n: INTEGER)
296         -- Performance: O(n)
297      local
298         i, j: INTEGER
299      do
300         -- Remove the last `n' item(s).
301         -- 0 1 2 3 4 5 6 7 8 9  (0,9 c=10)
302         -- 0 1 2 3 4 5 6 x x x  (n=3)
303         from
304            i := upper - n + 1
305         until
306            i > upper
307         loop
308            storage.put(default_pointer, i)
309            i := i + 1
310         end
311
312         upper := upper - n
313      end
314
315   clear_count
316      local
317         i: INTEGER
318      do
319         -- Discard all items (`is_empty' is True after that call). If
320         -- possible, the actual implementation is supposed to keep
321         -- its internal storage area in order to refill `Current' in
322         -- an efficient way.
323         from
324            i := lower
325         until
326            i > upper
327         loop
328            storage.put(default_pointer, i)
329            i := i + 1
330         end
331
332         upper := lower
333      end
334
335   clear_count_and_capacity
336         -- Instead of releasing the memory, it is reallocated with
337         -- with 2 elements.
338      do
339         -- Discard all items (`is_empty' is True after that call). If possible,
340         -- the actual implementation is supposed to release its internal
341         -- storage area for this memory to be used by other objects.
342         storage := storage.realloc(count, 2)
343         upper := lower
344      end
345
346feature {ANY} -- Looking and Searching:
347   first_index_of (element: like item): INTEGER
348      do
349         Result := index_of(element, lower)
350      end
351
352   index_of (element: like item; start_index: INTEGER): INTEGER
353      do
354         -- Using `is_equal' for comparison, gives the index of the
355         -- first occurrence of `element' at or after
356         -- `start_index'. Answer `upper + 1' when `element' when the
357         -- search fail.
358         if element = Void then
359            from
360               Result := lower -- start_index
361            until
362               item(Result) = Void or else Result > upper
363            loop
364               Result := Result + 1
365            end
366         else
367            from
368               Result := lower -- start_index
369            until
370               item(Result).is_equal(element) or else Result > upper
371            loop
372               Result := Result + 1
373            end
374         end
375      end
376
377   reverse_index_of (element: like item; start_index: INTEGER): INTEGER
378      do
379         -- Using `is_equal' for comparison, gives the index of the
380         -- first occurrence of `element' at or before
381         -- `start_index'. Search is done in reverse direction, which
382         -- means from the `start_index' down to the `lower'
383         -- index. Answer `lower -1' when the search fail.
384         if element = Void then
385            from
386               Result := start_index
387            until
388               item(Result) = Void or else Result < lower
389            loop
390               Result := Result - 1
391            end
392         else
393            from
394               Result := start_index
395            until
396               item(Result).is_equal(element) or else Result < lower
397            loop
398               Result := Result - 1
399            end
400         end
401      end
402
403   fast_first_index_of (element: like item): INTEGER
404         -- Note: comparison is done using the address of the wrapped
405         -- structure.
406      do
407         Result := fast_index_of(element, lower)
408      end
409
410   fast_index_of (element: like item; start_index: INTEGER): INTEGER
411         -- Note: comparison is done using the address of the wrapped
412         -- structure.
413      local
414         element_ptr: POINTER
415      do
416         -- Using basic `=' for comparison, gives the index of the
417         -- first occurrence of `element' at or after
418         -- `start_index'. Answer `upper + 1' when `element' when the
419         -- search fail.
420         element_ptr := null_or(element)
421         from
422            Result := lower
423         until
424            storage.item(Result) = element_ptr or else Result > upper
425         loop
426            Result := Result + 1
427         end
428      end
429
430   fast_reverse_index_of (element: like item; start_index: INTEGER): INTEGER
431         -- Note: comparison is done using the address of the wrapped
432         -- structure
433      local
434         element_ptr: POINTER
435      do
436         -- Using basic `=' comparison, gives the index of the first
437         -- occurrence of `element' at or before `start_index'. Search
438         -- is done in reverse direction, which means from the
439         -- `start_index' down to the `lower' index . Answer `lower
440         -- -1' when the search fail.
441         element_ptr := null_or(element)
442         -- from Result:=start_index
443
444         from
445            Result := lower
446         until
447            storage.item(Result) = element_ptr or else Result > upper
448         loop
449            Result := Result - 1
450         end
451      end
452
453feature {ANY} -- Looking and comparison:
454   is_equal (other: like Current): BOOLEAN
455         -- Do both collections have the same `lower', `upper', and items?
456         -- The basic `=' is used for comparison of items.
457         -- Complexity: O(count)
458      local
459         i: INTEGER
460      do
461         if other = Void then
462            Result := False
463         elseif lower /= other.lower or upper /= other.upper then
464            Result := False
465         else
466            from
467               i := lower
468            until
469               Result = True or else i > upper
470            loop
471               Result := Current.storage.item(i) = other.storage.item(i)
472               i := i + 1
473            end
474         end
475      end
476
477   all_default: BOOLEAN
478         -- Do all items have their type's default value?  Note: for
479         -- non Void items, the test is performed with the
480         -- `is_default' predicate.
481         -- See also `clear_all'.
482      local
483         i: INTEGER
484      do
485         from
486            i := lower
487         until
488            Result = False or else i > upper
489         loop
490            Result := storage.item(i).is_null
491            i := i + 1
492         end
493      end
494
495   occurrences (element: like item): INTEGER
496      local
497         i: ITERATOR[ITEM_]
498      do
499         -- Number of occurrences of `element' using `is_equal' for comparison.
500         if element /= Void then
501            from
502               i := new_iterator
503               i.start
504            until
505               i.is_off
506            loop
507               if element.is_equal(i.item) then
508                  Result := Result + 1
509               end
510               i.next
511            end
512         else
513            from
514               i := new_iterator
515               i.start
516            until
517               i.is_off
518            loop
519               if i.item = Void then
520                  Result := Result + 1
521               end
522               i.next
523            end
524         end
525      end
526
527   fast_occurrences (element: like item): INTEGER
528         -- Number of occurrences of `element' using basic its handle
529         -- (or default_pointer) for comparison.
530      local
531         ep: POINTER; i: INTEGER
532      do
533         ep := null_or(element)
534         from
535            i := lower
536         until
537            i > upper
538         loop
539            if storage.item(i) = ep then
540               Result := Result + 1
541            end
542            i := i + 1
543         end
544      end
545
546feature {ANY}
547   -- Agents based features:
548   -- for_each (action: ROUTINE[TUPLE[ITEM_]])
549   -- do
550   --                   -- Apply `action' to every item of `Current'.
551   --                   --
552   --                   -- See also `for_all', `exists'.
553   --           require
554   --                   action /= Void
555   --           local
556   --                   i: INTEGER
557   --           do
558   --                   from
559   --                           i := lower
560   --                   until
561   --                           i > upper
562   --                   loop
563   --                           action.call([item(i)])
564   --                           i := i + 1
565   -- end
566   -- end
567   -- for_all (test: PREDICATE[TUPLE[ITEM_]]): BOOLEAN
568   --           do
569   --                   -- Do all items satisfy `test'?
570   --                   --
571   --                   -- See also `for_each', `exists'.
572   --           require
573   --                   test /= Void
574   --           local
575   --                   i: INTEGER
576   --           do
577   --                   from
578   --                           Result := True
579   --                           i := lower
580   --                   until
581   --                           not Result or else i > upper
582   --                   loop
583   --                           Result := test.item([item(i)])
584   --                           i := i + 1
585   -- end
586   --           end
587   -- exists (test: PREDICATE[TUPLE[ITEM_]]): BOOLEAN
588   --           do
589   --                   -- Does at least one item satisfy `test'?
590   --                   --
591   --                   -- See also `for_each', `for_all'.
592   --           require
593   --                   test /= Void
594   --           local
595   --                   i: INTEGER
596   --           do
597   --                   from
598   --                           i := lower
599   --                   until
600   --                           Result or else i > upper
601   --                   loop
602   --                           Result := test.item([item(i)])
603   --                           i := i + 1
604   -- end
605   -- end
606
607
608feature {ANY} -- Other features:
609   replace_all (old_value, new_value: like item)
610      obsolete "Unimplemented!"
611      do
612         --                     -- Replace all occurrences of the element `old_value' by `new_value' using `is_equal' for comparison.
613         --                     --
614         --                     -- See also `fast_replace_all', `move'.
615         --             deferred
616         --             ensure
617         --                     count = old count
618         --                     not (create {SAFE_EQUAL[ITEM_]}).test(old_value, new_value) implies occurrences(old_value) = 0
619      end
620
621   fast_replace_all (old_value, new_value: like item)
622      obsolete "Unimplemented!"
623      do
624         --                     -- Replace all occurrences of the element `old_value' by `new_value' using basic `=' for comparison.
625         --                     --
626         --                     -- See also `replace_all', `move'.
627         --             deferred
628         --             ensure
629         --                     count = old count
630         --                     old_value /= new_value implies fast_occurrences(old_value) = 0
631      end
632      --        move (lower_index, upper_index, distance: INTEGER)
633      --                do
634      --                        -- Move range `lower_index' .. `upper_index' by `distance' positions.
635      --                        --      Negative distance moves towards lower indices.
636      --                        -- Free places get default values.
637      --                        --
638      --                        -- See also `slice', `replace_all'.
639      --                require
640      --                        lower_index <= upper_index
641      --                        valid_index(lower_index)
642      --                        valid_index(lower_index + distance)
643      --                        valid_index(upper_index)
644      --                        valid_index(upper_index + distance)
645      --                local
646      --                        default_value: like item; i: INTEGER
647      --                do
648      --                        if distance = 0 then
649      --                        elseif distance < 0 then
650      --                                from
651      --                                        i := lower_index
652      --                                until
653      --                                        i > upper_index
654      --                                loop
655      --                                        put(item(i), i + distance)
656      --                                        put(default_value, i)
657      --                                        i := i + 1
658      -- end
659      --                        else
660      --                                from
661      --                                        i := upper_index
662      --                                until
663      --                                        i < lower_index
664      --                                loop
665      --                                        put(item(i), i + distance)
666      --                                        put(default_value, i)
667      --                                        i := i - 1
668      --        end
669      --        end
670      --                ensure
671      --                        count = old count
672      --        end
673
674   slice (min, max: INTEGER): like Current
675      obsolete "Unimplemented!"
676      do
677         --                     -- New collection consisting of items at indexes in [`min'..`max'].
678         --                     -- Result has the same dynamic type as `Current'.
679         --                     -- The `lower' index of the `Result' is the same as `lower'.
680         --                     --
681         --                     -- See also `from_collection', `move', `replace_all'.
682         --             require
683         --                     lower <= min
684         --                     max <= upper
685         --                     min <= max + 1
686         --             deferred
687         --             ensure
688         --                     same_dynamic_type(Result)
689         --                     Result.count = max - min + 1
690         --                     Result.lower = lower
691      end
692
693   reverse
694      obsolete "Unimplemented!"
695      do
696         --                     -- Reverse the order of the elements.
697         --             deferred
698         --             ensure
699         --                     count = old count
700      end
701
702feature {ANY} -- struct_size: INTEGER
703   count: INTEGER
704      do
705         Result := upper - lower + 1
706      end
707
708   upper: INTEGER
709
710   lower: INTEGER 0
711
712   is_empty: BOOLEAN
713      do
714         Result := upper = -1 or else storage.is_null
715      end
716
717   new_iterator: ITERATOR[ITEM_]
718      do
719         create {ITERATOR_ON_C_ARRAY[ITEM_]} Result.from_array(Current)
720      end
721
722   as_c_array: NATIVE_ARRAY[POINTER]
723      do
724         Result := storage
725      end
726
727feature {C_ARRAY, WRAPPER_HANDLER} -- Implementation
728   storage: NATIVE_ARRAY[POINTER]
729
730   capacity: INTEGER
731
732feature {} -- Implement manifest generic creation (very low-level):
733   manifest_make (needed_capacity: INTEGER)
734         -- Manifest creation of a LLVM_TYPE_ARRAY
735      require
736         needed_capacity > 0
737      do
738         with_capacity(needed_capacity)
739         upper := needed_capacity - 1
740      end
741
742   manifest_put (index: INTEGER_32; element: ITEM_)
743      do
744         put(element, index)
745      end
746
747feature {ANY} -- TODO: unimplemented
748   clear_all
749      do
750         not_yet_implemented
751      end
752
753   fast_has (an_item: ITEM_): BOOLEAN
754      do
755         not_yet_implemented
756      end
757
758   has (an_item: ITEM_): BOOLEAN
759      do
760         not_yet_implemented
761      end
762
763   swap (i1, i2: INTEGER)
764      do
765         not_yet_implemented
766      end
767
768   append_collection (another: COLLECTION[ITEM_])
769      do
770         not_yet_implemented
771      end
772
773end -- class C_ARRAY