PageRenderTime 21ms CodeModel.GetById 10ms app.highlight 4ms RepoModel.GetById 2ms app.codeStats 0ms

/src/lib/storage/set.e

http://github.com/tybor/Liberty
Specman e | 497 lines | 385 code | 37 blank | 75 comment | 14 complexity | 55bc22865b721fc3431e4d65608404f7 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4deferred class SET[E_]
  5   --
  6   -- Definition of a mathematical set of objects. All common operations on mathematical sets are available.
  7   --
  8   -- Well known implementations are HASHED_SET and AVL_SET.
  9   --
 10
 11inherit
 12   TRAVERSABLE[E_]
 13      redefine is_equal, copy
 14      end
 15
 16insert
 17   SAFE_EQUAL[E_]
 18      undefine out_in_tagged_out_memory
 19      redefine is_equal, copy
 20      end
 21
 22feature {ANY} -- Counting:
 23   is_empty: BOOLEAN
 24         -- Is the set empty?
 25      do
 26         Result := count = 0
 27      end
 28
 29feature {ANY} -- Adding and removing:
 30   add (e: like item)
 31         -- Add new item `e' to the set. The mathematical definition of adding in a set is followed, i.e. the
 32         -- element `e' is added only and only if it is not yet present in the set.
 33         -- As this `add' feature is actually using `is_equal', you may consider to use `fast_add' for expanded
 34         -- objects as well while trying to get the very best performances.
 35      require
 36         e /= Void
 37      deferred
 38      ensure
 39         added: has(e)
 40         not_in_then_added: not old has(e) implies count = old count + 1
 41         in_then_not_added: old has(e) implies count = old count
 42      end
 43
 44   fast_add (e: like item)
 45         -- Same job as `add', but uses basic `=' for comparison.
 46      require
 47         e /= Void
 48      deferred
 49      ensure
 50         added: has(e)
 51         not_in_then_added: not old has(e) implies count = old count + 1
 52         in_then_not_added: old has(e) implies count = old count
 53      end
 54
 55   remove (e: like item)
 56         -- Remove item `e' from the set: the mathematical definition of
 57         -- removing from a set is followed.
 58      require
 59         e /= Void
 60      deferred
 61      ensure
 62         removed: not has(e)
 63         not_in_not_removed: not old has(e) implies count = old count
 64         in_then_removed: old has(e) implies count = old count - 1
 65      end
 66
 67   fast_remove (e: like item)
 68         -- Same job as `remove', but uses basic `=' for comparison.
 69      require
 70         e /= Void
 71      deferred
 72      ensure
 73         removed: not has(e)
 74         not_in_not_removed: not old has(e) implies count = old count
 75         in_then_removed: old has(e) implies count = old count - 1
 76      end
 77
 78   clear_count
 79         -- Empty the current set (`is_empty' is True after that call). If possible, the actual implementation
 80         -- is supposed to keep its internal storage area in order to refill `Current' in an efficient way.
 81         -- See also `clear_count_and_capacity' to select the most appropriate.
 82      deferred
 83      ensure
 84         is_empty: count = 0
 85      end
 86
 87   clear_count_and_capacity
 88         -- Empty the current set (`is_empty' is True after that call). If possible, the actual implementation
 89         -- is supposed to release its internal storage area for this memory to be used by other objects.
 90         -- See also `clear_count' to select the most appropriate.
 91      deferred
 92      ensure
 93         is_empty: count = 0
 94      end
 95
 96feature {ANY} -- Looking and searching:
 97   has (e: like item): BOOLEAN
 98         -- Is element `e' in the set?
 99         -- As this query is actually using `is_equal', you may consider to use `fast_has' for expanded
100         -- objects as well while trying to get the very best performances.
101      require
102         e /= Void
103      deferred
104      ensure
105         Result implies not is_empty
106      end
107
108   fast_has (e: like item): BOOLEAN
109         -- Is element `e' actually stored in the set?
110         -- Warning: this query is using basic `=' for comparison. See also `has' when dealing with reference
111         -- types.
112      require
113         e /= Void
114      deferred
115      ensure
116         Result implies e = reference_at(e)
117      end
118
119   reference_at (e: like item): like item
120         -- Non Void when `e' is in the set. In such a situation, `Result' is the object which is actually
121         -- stored in the `Current' set (see ensure assertion).
122      require
123         e /= Void
124         elements_are_not_expanded: Result = Void
125      deferred
126      ensure
127         has(e) implies Result.is_equal(e)
128      end
129
130feature {ANY} -- To provide iterating facilities:
131   lower: INTEGER 1
132
133   upper: INTEGER
134      do
135         Result := count
136      ensure
137         Result = count
138      end
139
140   item (index: INTEGER): E_
141         -- Item at the corresponding index `i'.
142         --
143         -- See also `lower', `upper', `valid_index'.
144         --
145         -- SETs are intrinsically unordered, so there is no guarantee that `item'(i) after performing an `add'
146         -- or `remove' operation is related in any way to `item'(i) before that operation.
147      deferred
148      ensure
149         has(Result)
150      end
151
152   first: E_
153      do
154         Result := item(lower)
155      end
156
157   last: E_
158      do
159         Result := item(upper)
160      end
161
162   new_iterator: ITERATOR[E_]
163      do
164         create {ITERATOR_ON_SET[E_]} Result.make(Current)
165      end
166
167feature {ANY} -- Mathematical operations:
168   union (other: like Current)
169         -- Make the union of the `Current' set with `other'.
170      require
171         other /= Void
172      local
173         i: INTEGER; e: like item
174      do
175         from
176            i := 1
177         until
178            i > other.count
179         loop
180            e := other.item(i)
181            if not has(e) then
182               add(e)
183            end
184            i := i + 1
185         end
186      ensure
187         count <= old count + other.count
188      end
189
190   fast_union (other: like Current)
191         -- Make the union of the `Current' set with `other'.
192      require
193         other /= Void
194      local
195         i: INTEGER; e: like item
196      do
197         from
198            i := 1
199         until
200            i > other.count
201         loop
202            e := other.item(i)
203            if not fast_has(e) then
204               fast_add(e)
205            end
206            i := i + 1
207         end
208      ensure
209         count <= old count + other.count
210      end
211
212   infix "+" (other: like Current): like Current
213         -- Return the union of the `Current' set with `other'.
214      require
215         other /= Void
216      do
217         Result := twin
218         Result.union(other)
219      ensure
220         Result.count <= count + other.count
221         Current.is_subset_of(Result) and then other.is_subset_of(Result)
222      end
223
224   intersection (other: like Current)
225         -- Make the intersection of the `Current' set with `other'.
226      require
227         other /= Void
228      local
229         i: INTEGER; e: like item
230      do
231         from
232            i := upper
233         until
234            i < lower
235         loop
236            e := item(i)
237            if not other.has(e) then
238               remove(e)
239            end
240            i := i - 1
241         end
242      ensure
243         count <= other.count.min(old count)
244      end
245
246   fast_intersection (other: like Current)
247         -- Make the intersection of the `Current' set with `other'.
248      require
249         other /= Void
250      local
251         i: INTEGER; e: like item
252      do
253         from
254            i := upper
255         until
256            i < lower
257         loop
258            e := item(i)
259            if not other.fast_has(e) then
260               fast_remove(e)
261            end
262            i := i - 1
263         end
264      ensure
265         count <= other.count.min(old count)
266      end
267
268   infix "^" (other: like Current): like Current
269         -- Return the intersection of the `Current' set with `other'.
270      require
271         other /= Void
272      do
273         Result := twin
274         Result.intersection(other)
275      ensure
276         Result.count <= other.count.min(count)
277         Result.is_subset_of(Current) and then Result.is_subset_of(other)
278      end
279
280   minus (other: like Current)
281         -- Make the set `Current' - `other'.
282      require
283         other /= Void
284      local
285         i: INTEGER
286      do
287         if other = Current then
288            clear_count
289         else
290            from
291               i := 1
292            until
293               i > other.count
294            loop
295               remove(other.item(i))
296               i := i + 1
297            end
298         end
299      ensure
300         count <= old count
301      end
302
303   fast_minus (other: like Current)
304         -- Make the set `Current' - `other'.
305      require
306         other /= Void
307      local
308         i: INTEGER
309      do
310         if other = Current then
311            clear_count
312         else
313            from
314               i := 1
315            until
316               i > other.count
317            loop
318               fast_remove(other.item(i))
319               i := i + 1
320            end
321         end
322      ensure
323         count <= old count
324      end
325
326   infix "-" (other: like Current): like Current
327         -- Return  the set `Current' - `other'.
328      require
329         other /= Void
330      do
331         Result := twin
332         Result.minus(other)
333      ensure
334         Result.count <= count
335         Result.is_subset_of(Current)
336      end
337
338feature {ANY} -- Comparison:
339   is_subset_of (other: like Current): BOOLEAN
340         -- Is the `Current' set a subset of `other'?
341      require
342         other /= Void
343      local
344         i: INTEGER
345      do
346         if Current = other then
347            Result := True
348         elseif count <= other.count then
349            from
350               Result := True
351               i := 1
352            until
353               not Result or else i > count
354            loop
355               Result := other.has(item(i))
356               i := i + 1
357            end
358         end
359      ensure
360         Result implies count <= other.count
361      end
362
363   is_disjoint_from (other: like Current): BOOLEAN
364         -- Is the `Current' set disjoint from `other' ?
365      require
366         other /= Void
367      local
368         i: INTEGER
369      do
370         if Current /= other then
371            Result := True
372            i := 1
373            if count <= other.count then
374               from
375               until
376                  not Result or else i > count
377               loop
378                  Result := not other.has(item(i))
379                  i := i + 1
380               end
381            else
382               from
383               until
384                  not Result or else i > other.count
385               loop
386                  Result := not has(other.item(i))
387                  i := i + 1
388               end
389            end
390         end
391      ensure
392         Result = (Current ^ other).is_empty
393      end
394
395   is_equal (other: like Current): BOOLEAN
396         -- Is the `Current' set equal to `other'?
397      local
398         i: INTEGER
399      do
400         if Current = other then
401            Result := True
402         elseif count = other.count then
403            from
404               Result := True
405               i := 1
406            until
407               not Result or else i > count
408            loop
409               Result := other.has(item(i))
410               i := i + 1
411            end
412         end
413      ensure then
414         double_inclusion: Result = (is_subset_of(other) and other.is_subset_of(Current))
415      end
416
417feature {ANY}
418   copy (other: like Current)
419         -- Copy 'other' into the current set
420      local
421         i: INTEGER
422      do
423         -- Note: this naive implementation is OK because node
424         -- recycling is implemented.
425         from
426            make
427            i := 1
428         until
429            i > other.count
430         loop
431            add(other.item(i))
432            i := i + 1
433         end
434      end
435
436   from_collection (model: TRAVERSABLE[like item])
437         -- Add all items of `model'.
438      require
439         model /= Void
440      local
441         i, up: INTEGER
442      do
443         from
444            make
445            up := model.upper
446            i := model.lower
447         until
448            i > up
449         loop
450            add(model.item(i))
451            i := i + 1
452         end
453      end
454
455feature {}
456   make
457         -- Creation of an empty SET.
458      deferred
459      ensure
460         is_empty
461      end
462
463feature {} -- Implement manifest generic creation:
464   manifest_make (needed_capacity: INTEGER)
465         -- Manifest creation of a SET.
466      do
467         make
468      end
469
470   manifest_put (index: INTEGER; element: like item)
471      do
472         add(element)
473      end
474
475   manifest_semicolon_check: BOOLEAN False
476
477end -- class SET
478--
479-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
480--
481-- Permission is hereby granted, free of charge, to any person obtaining a copy
482-- of this software and associated documentation files (the "Software"), to deal
483-- in the Software without restriction, including without limitation the rights
484-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
485-- copies of the Software, and to permit persons to whom the Software is
486-- furnished to do so, subject to the following conditions:
487--
488-- The above copyright notice and this permission notice shall be included in
489-- all copies or substantial portions of the Software.
490--
491-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
492-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
493-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
494-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
495-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
496-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
497-- THE SOFTWARE.