PageRenderTime 34ms CodeModel.GetById 15ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 1ms

/src/lib/storage/map.e

http://github.com/tybor/Liberty
Specman e | 540 lines | 397 code | 38 blank | 105 comment | 17 complexity | 014a6f6a7093df1ba847199e2cbb9e7b MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4deferred class MAP[V_, K_]
  5   --
  6   -- Read-only associative memory. Values of type `V_' are stored using Keys of type `K_'.
  7   --
  8   -- See also DICTIONARY
  9   --
 10
 11inherit
 12   TRAVERSABLE[V_]
 13      rename
 14         new_iterator as new_iterator_on_items,
 15         for_each as for_each_item,
 16         do_all as do_all_items,
 17         for_all as for_all_items,
 18         exists as exists_item,
 19         aggregate as aggregate_items
 20      undefine
 21         copy
 22      redefine
 23         is_equal, out_in_tagged_out_memory
 24      end
 25
 26feature {ANY} -- Counting:
 27   is_empty: BOOLEAN
 28         -- Is it empty?
 29      do
 30         Result := count = 0
 31      end
 32
 33feature {ANY} -- Basic access:
 34   has (k: K_): BOOLEAN
 35         -- Is there a value currently associated with key `k'?
 36         --
 37         -- See also `fast_has', `at'.
 38      require
 39         k /= Void
 40      deferred
 41      end
 42
 43   at (k: K_): V_
 44         -- Return the value associated to key `k'.
 45         --
 46         -- See also `fast_at', `reference_at', `has'.
 47      require
 48         has(k)
 49      deferred
 50      end
 51
 52   frozen infix "@" (k: K_): V_
 53         -- The infix notation which is actually a synonym for `at'.
 54      require
 55         has(k)
 56      do
 57         Result := at(k)
 58      ensure
 59         definition: Result = at(k)
 60      end
 61
 62   reference_at (k: K_): V_
 63         -- Return Void or the value associated with key `k'. Actually, this feature is useful only
 64         -- when the type of values (the type V_) is a reference type, to avoid using `has' just
 65         -- followed by `at' to get the corresponding value with the very best performances.
 66         --
 67         -- See also `fast_reference_at', `at', `has'.
 68      require
 69         k /= Void
 70         values_are_not_expanded: Result = Void
 71      deferred
 72      ensure
 73         has(k) implies Result = at(k)
 74      end
 75
 76   fast_has (k: K_): BOOLEAN
 77         -- Is there a value currently associated with key `k'?
 78         -- Using basic `=' for comparison.
 79         --
 80         -- See also `has', `at', `fast_at'.
 81      require
 82         k /= Void
 83      deferred
 84      end
 85
 86   fast_at (k: K_): V_
 87         -- Return the value associated to key `k' using basic `=' for comparison.
 88         --
 89         -- See also `at', `reference_at', `fast_reference_at'.
 90      require
 91         fast_has(k)
 92      deferred
 93      end
 94
 95   fast_reference_at (k: K_): V_
 96         -- Same work as `reference_at', but basic `=' is used for comparison.
 97         --
 98         -- See also `reference_at', `at', `has'.
 99      require
100         k /= Void
101         values_are_reference: Result = Void
102      deferred
103      ensure
104         fast_has(k) implies Result = fast_at(k)
105      end
106
107feature {ANY} -- Looking and searching some value:
108   occurrences (v: V_): INTEGER
109         -- Number of occurrences using `is_equal' for comparison.
110         --
111         -- See also `fast_occurrences', `fast_has', `has'.
112      local
113         i: INTEGER; safe_equal: SAFE_EQUAL[V_]
114      do
115         from
116            i := lower
117         until
118            i > upper
119         loop
120            if safe_equal.test(v, item(i)) then
121               Result := Result + 1
122            end
123            i := i + 1
124         end
125      ensure
126         Result >= 0
127      end
128
129   fast_occurrences (v: V_): INTEGER
130         -- Number of occurrences using basic `=' for comparison.
131         --
132         -- See also `occurrences', `fast_has', `has'.
133      local
134         i: INTEGER
135      do
136         from
137            i := lower
138         until
139            i > upper
140         loop
141            if v = item(i) then
142               Result := Result + 1
143            end
144            i := i + 1
145         end
146      ensure
147         Result >= 0
148      end
149
150   key_at (v: V_): K_
151         -- Retrieve the key used for value `v' using `is_equal' for comparison.
152         --
153         -- See also `fast_key_at', `at'.
154      require
155         occurrences(v) = 1
156      local
157         i: INTEGER; safe_equal: SAFE_EQUAL[V_]
158      do
159         from
160            i := lower
161         until
162            safe_equal.test(v, item(i))
163         loop
164            i := i + 1
165         end
166         Result := key(i)
167      ensure
168         (create {SAFE_EQUAL[V_]}).test(at(Result), v)
169      end
170
171   fast_key_at (v: V_): K_
172         -- Retrieve the key used for value `v' using `=' for comparison.
173         --
174         -- See also `key_at', `at'.
175      require
176         fast_occurrences(v) = 1
177      local
178         i: INTEGER
179      do
180         from
181            i := lower
182         until
183            v = item(i)
184         loop
185            i := i + 1
186         end
187         Result := key(i)
188      ensure
189         at(Result) = v
190      end
191
192feature {ANY} -- To provide iterating facilities:
193   lower: INTEGER 1
194
195   upper: INTEGER
196      do
197         Result := count
198      ensure
199         count = Result - lower + 1
200      end
201
202   item (index: INTEGER): V_
203      deferred
204      ensure
205         Result = at(key(index))
206      end
207
208   key (index: INTEGER): K_
209      require
210         valid_index(index)
211      deferred
212      ensure
213         at(Result) = item(index)
214      end
215
216   first: V_
217      do
218         Result := item(lower)
219      end
220
221   last: V_
222      do
223         Result := item(upper)
224      end
225
226   new_iterator_on_items: ITERATOR[V_]
227      deferred
228      ensure then
229         Result /= Void
230      end
231
232   new_iterator_on_keys: ITERATOR[K_]
233      deferred
234      ensure
235         Result /= Void
236      end
237
238   new_iterator: ITERATOR[TUPLE[V_, K_]]
239      deferred
240      ensure
241         Result /= Void
242      end
243
244   key_map_in (buffer: COLLECTION[K_])
245         -- Append in `buffer', all available keys (this may be useful to
246         -- speed up the traversal).
247         --
248         -- See also `item_map_in'.
249      require
250         buffer /= Void
251      do
252         buffer.append_traversable(keys)
253      ensure
254         buffer.count = count + old buffer.count
255      end
256
257   item_map_in (buffer: COLLECTION[V_])
258         -- Append in `buffer', all available items (this may be useful to
259         -- speed up the traversal).
260         --
261         -- See also `key_map_in'.
262      require
263         buffer /= Void
264      do
265         buffer.append_traversable(items)
266      ensure
267         buffer.count = count + old buffer.count
268      end
269
270   keys: TRAVERSABLE[K_]
271         -- An iterable of this map keys
272      do
273         if keys_memory = Void then
274            create keys_memory.from_map(Current)
275         end
276         Result := keys_memory
277      ensure
278         Result.count = count
279      end
280
281   items: TRAVERSABLE[V_]
282         -- An iterable of this map values
283         -- Usually returns Current because MAP is TRAVERSABLE.
284      do
285         Result := Current
286      ensure
287         Result.count = count
288      end
289
290feature {ANY}
291   fast_is_equal (other: like Current): BOOLEAN
292         -- Do both dictionaries have the same set of associations?
293         -- Keys are compared with `is_equal' and values are compared
294         -- with the basic = operator.
295         --
296         -- See also `is_equal'.
297      local
298         i: INTEGER; k: K_
299      do
300         if Current = other then
301            Result := True
302         elseif count = other.count then
303            from
304               Result := True
305               i := 1
306            until
307               not Result or else i > count
308            loop
309               k := key(i)
310               if other.has(k) then
311                  if other.at(k) /= item(i) then
312                     Result := False
313                  else
314                     i := i + 1
315                  end
316               else
317                  Result := False
318               end
319            end
320         end
321      ensure
322         Result implies count = other.count
323      end
324
325   is_equal (other: like Current): BOOLEAN
326         -- Do both dictionaries have the same set of associations?
327         -- Both keys and values are compared with `is_equal'.
328         --
329         -- See also `fast_is_equal'.
330      local
331         i: INTEGER; k: K_; safe_equal: SAFE_EQUAL[V_]
332      do
333         if Current = other then
334            Result := True
335         elseif count = other.count then
336            from
337               Result := True
338               i := 1
339            until
340               not Result or else i > count
341            loop
342               k := key(i)
343               if other.has(k) then
344                  if not safe_equal.test(other.at(k), item(i)) then
345                     Result := False
346                  else
347                     i := i + 1
348                  end
349               else
350                  Result := False
351               end
352            end
353         end
354      end
355
356   is_equal_map (other: like Current): BOOLEAN
357         -- Do both collections have the same `lower', `upper', and
358         -- items?
359         -- Feature `is_equal' is used for comparison of items.
360      obsolete "Use `is_equal' instead."
361      do
362         Result := is_equal(other)
363      end
364
365feature {ANY} -- Display support:
366   out_in_tagged_out_memory
367      local
368         i: INTEGER; k: like key; v: like item
369      do
370         tagged_out_memory.extend('{')
371         tagged_out_memory.append(generating_type)
372         tagged_out_memory.append(once ":[")
373         from
374            i := lower
375         until
376            i > upper
377         loop
378            k := key(i)
379            if k = Void then
380               tagged_out_memory.append(once "Void")
381            else
382               k.out_in_tagged_out_memory
383            end
384            tagged_out_memory.extend('=')
385            v := item(i)
386            if v = Void then
387               tagged_out_memory.append(once "Void")
388            else
389               v.out_in_tagged_out_memory
390            end
391            if i < upper then
392               tagged_out_memory.extend(' ')
393            end
394            i := i + 1
395         end
396         tagged_out_memory.append(once "]}")
397      end
398
399feature {ANY} -- Agents based features:
400   for_each (action: PROCEDURE[TUPLE[V_, K_]])
401         -- Apply `action' to every [V_, K_] associations of `Current'.
402         --
403         -- See also `for_all', `exist'.
404      require
405         action /= Void
406      local
407         i: INTEGER; v: V_; k: K_
408      do
409         from
410            i := lower
411         until
412            i > upper
413         loop
414            v := item(i)
415            k := key(i)
416            action.call([v, k])
417            i := i + 1
418         end
419      end
420
421   frozen do_all (action: ROUTINE[TUPLE[V_, K_]])
422         -- Apply `action' to every [V_, K_] associations of `Current'.
423         --
424         -- See also `for_all', `exist'.
425      obsolete "This feature is not secure because it accepts a FUNCTION, the result of which is lost. Plese use `for_each` instead."
426      require
427         action /= Void
428      local
429         p: PROCEDURE[TUPLE[V_, K_]]
430      do
431         if p ?:= action then
432            p ::= action
433         else
434            p := agent (v: V_; k: K_) do action.call([v, k]) end (?, ?)
435         end
436         for_each(p)
437      end
438
439   for_all (test: PREDICATE[TUPLE[V_, K_]]): BOOLEAN
440         -- Do all [V_, K_] associations satisfy `test'?
441         --
442         -- See also `for_each', `exist'.
443      require
444         test /= Void
445      local
446         i: INTEGER; v: V_; k: K_
447      do
448         from
449            Result := True
450            i := lower
451         until
452            not Result or else i > upper
453         loop
454            v := item(i)
455            k := key(i)
456            Result := test.item([v, k])
457            i := i + 1
458         end
459      end
460
461   exists (test: PREDICATE[TUPLE[V_, K_]]): BOOLEAN
462         -- Does at least one [V_, K_] association satisfy `test'?
463         --
464         -- See also `for_all', `for_each'.
465      require
466         test /= Void
467      local
468         i: INTEGER; v: V_; k: K_
469      do
470         from
471            i := lower
472         until
473            Result or else i > upper
474         loop
475            v := item(i)
476            k := key(i)
477            Result := test.item([v, k])
478            i := i + 1
479         end
480      end
481
482   aggregate (action: FUNCTION[TUPLE[V_, V_, K_], V_]; initial: V_): V_
483         -- Aggregate all the elements starting from the initial value.
484         --
485         -- See also `for_each', `for_all', `exists'.
486      require
487         action /= Void
488      local
489         i: INTEGER; v: V_; k: K_
490      do
491         from
492            Result := initial
493            i := lower
494         until
495            i > upper
496         loop
497            v := item(i)
498            k := key(i)
499            Result := action.item([Result, v, k])
500            i := i + 1
501         end
502      end
503
504feature {ANY} -- Other features:
505   internal_key (k: K_): K_
506         -- Retrieve the internal key object which correspond to the existing
507         -- entry `k' (the one memorized into the `Current' dictionary).
508         --
509         -- See also `has', `fast_has'.
510      require
511         has(k)
512      deferred
513      ensure
514         Result.is_equal(k)
515      end
516
517feature {}
518   keys_memory: DICTIONARY_KEY_TRAVERSER[V_, K_]
519
520end -- class MAP
521--
522-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
523--
524-- Permission is hereby granted, free of charge, to any person obtaining a copy
525-- of this software and associated documentation files (the "Software"), to deal
526-- in the Software without restriction, including without limitation the rights
527-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
528-- copies of the Software, and to permit persons to whom the Software is
529-- furnished to do so, subject to the following conditions:
530--
531-- The above copyright notice and this permission notice shall be included in
532-- all copies or substantial portions of the Software.
533--
534-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
535-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
536-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
537-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
538-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
539-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
540-- THE SOFTWARE.