PageRenderTime 25ms CodeModel.GetById 18ms app.highlight 3ms RepoModel.GetById 1ms app.codeStats 1ms

/src/lib/storage/collection/two_way_linked_list.e

http://github.com/tybor/Liberty
Specman e | 658 lines | 573 code | 47 blank | 38 comment | 38 complexity | 9f7b58b6845e81c66c7b6adc6c5a2224 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class TWO_WAY_LINKED_LIST[E_]
  5   --
  6   -- Two way linked list with internal automatic memorization of
  7   -- the last access.
  8   --
  9
 10inherit
 11   COLLECTION[E_]
 12      redefine default_create
 13      end
 14
 15insert
 16   LINKED_COLLECTION[E_]
 17      redefine default_create
 18      end
 19
 20create {ANY}
 21   make, from_collection, manifest_creation, default_create
 22
 23feature {}
 24   default_create
 25      do
 26         make
 27      end
 28
 29feature {TWO_WAY_LINKED_LIST, ITERATOR_ON_TWO_WAY_LINKED_LIST}
 30   first_link: TWO_WAY_LINKED_LIST_NODE[E_]
 31         -- Void when empty or gives access to the first element.
 32
 33feature {TWO_WAY_LINKED_LIST}
 34   last_link: like first_link
 35         -- Void when empty or gives access to the last element.
 36
 37   mem_idx: INTEGER
 38
 39   mem_lnk: like first_link
 40         -- To speed up accessing, `mem_idx' and `mem_lnk' is the
 41         -- memory of the last access done. For example, after
 42         -- item(1), `mem_idx' is 1 and `mem_lnk' is `first_link'.
 43         -- When list is empty, `first_link' is Void as well as
 44         -- `mem_lnk' and `mem_idx' is 0
 45
 46feature {ANY}
 47   make
 48      do
 49         if free_nodes = Void then
 50            -- It is a brand new one:
 51            free_nodes ::= common_free_nodes.fast_reference_at(generating_type)
 52            if free_nodes = Void then
 53               create free_nodes.set_item(Void)
 54               common_free_nodes.add(free_nodes, generating_type)
 55            end
 56         else
 57            clear_count
 58         end
 59         next_generation
 60      ensure
 61         count = 0
 62      end
 63
 64   is_empty: BOOLEAN
 65      do
 66         Result := first_link = Void
 67      end
 68
 69   add_first (element: like item)
 70      do
 71         if first_link = Void then
 72            first_link := new_node(element, Void, Void)
 73            last_link := first_link
 74            upper := 1
 75            mem_idx := 1
 76            mem_lnk := first_link
 77         else
 78            first_link := new_node(element, Void, first_link)
 79            first_link.next.set_previous(first_link)
 80            upper := upper + 1
 81            mem_idx := mem_idx + 1
 82         end
 83         next_generation
 84      ensure then
 85         upper = 1 + old upper
 86      end
 87
 88   add_last (element: like item)
 89      do
 90         if first_link = Void then
 91            first_link := new_node(element, Void, Void)
 92            last_link := first_link
 93            upper := 1
 94            mem_idx := 1
 95            mem_lnk := first_link
 96         else
 97            last_link := new_node(element, last_link, Void)
 98            last_link.previous.set_next(last_link)
 99            upper := upper + 1
100         end
101         next_generation
102      end
103
104   add (element: like item; index: INTEGER)
105      local
106         link: like first_link
107      do
108         if index = 1 then
109            add_first(element)
110         elseif index = upper + 1 then
111            add_last(element)
112         else
113            if index - 1 /= mem_idx then
114               go_item(index - 1)
115            end
116            link := new_node(element, mem_lnk, mem_lnk.next)
117            link.next.set_previous(link)
118            mem_lnk.set_next(link)
119            upper := upper + 1
120         end
121         next_generation
122      end
123
124   remove_first
125      do
126         if upper = 1 then
127            first_link := dispose_node(first_link)
128            check
129               first_link = Void
130            end
131            last_link := Void
132            mem_lnk := Void
133            mem_idx := 0
134            upper := 0
135         else
136            first_link := dispose_node(first_link)
137            first_link.set_previous(Void)
138            upper := upper - 1
139            if mem_idx > 1 then
140               mem_idx := mem_idx - 1
141            else
142               mem_lnk := first_link
143               mem_idx := 1
144            end
145         end
146         next_generation
147      end
148
149   remove (index: INTEGER)
150      local
151         link: like first_link
152      do
153         if index = 1 then
154            remove_first
155         elseif index = upper then
156            remove_last
157         else
158            if index - 1 /= mem_idx then
159               go_item(index - 1)
160            end
161            link := mem_lnk.next
162            mem_lnk.set_next(link.next)
163            link.next.set_previous(mem_lnk)
164            link := dispose_node(link)
165            upper := upper - 1
166         end
167         next_generation
168      end
169
170   first: like item
171      do
172         Result := first_link.item
173      end
174
175   last: like item
176      do
177         Result := last_link.item
178      end
179
180   item (index: INTEGER): E_
181      do
182         if index /= mem_idx then
183            go_item(index)
184         end
185         Result := mem_lnk.item
186      end
187
188   put (element: like item; index: INTEGER)
189      do
190         if index /= mem_idx then
191            go_item(index)
192         end
193         mem_lnk.set_item(element)
194         next_generation
195      end
196
197   count: INTEGER
198      do
199         Result := upper
200      end
201
202   set_all_with (v: like item)
203      do
204         if first_link /= Void then
205            first_link.set_all_with(v)
206         end
207         next_generation
208      end
209
210   copy (other: like Current)
211      do
212         from_collection(other)
213      end
214
215   fast_is_equal (other: like Current): BOOLEAN
216      local
217         lnk1, lnk2: like first_link
218      do
219         if Current = other then
220            Result := True
221         elseif upper = other.upper then
222            from
223               Result := True
224               lnk1 := first_link
225               lnk2 := other.first_link
226            until
227               lnk1 = Void or not Result
228            loop
229               Result := lnk1.item = lnk2.item
230               lnk1 := lnk1.next
231               lnk2 := lnk2.next
232            end
233         end
234      end
235
236   is_equal (other: like Current): BOOLEAN
237      local
238         lnk1, lnk2: like first_link; safe_equal: SAFE_EQUAL[E_]
239      do
240         if Current = other then
241            Result := True
242         elseif upper = other.upper then
243            from
244               Result := True
245               lnk1 := first_link
246               lnk2 := other.first_link
247            until
248               lnk1 = Void or not Result
249            loop
250               Result := safe_equal.test(lnk1.item, lnk2.item)
251               lnk1 := lnk1.next
252               lnk2 := lnk2.next
253            end
254         end
255      end
256
257   index_of (x: like item; start_index: INTEGER): INTEGER
258      local
259         safe_equal: SAFE_EQUAL[E_]
260      do
261         from
262            Result := start_index
263         until
264            Result > upper or else safe_equal.test(x, item(Result))
265         loop
266            Result := Result + 1
267         end
268      end
269
270   reverse_index_of (element: like item; start_index: INTEGER): INTEGER
271      local
272         safe_equal: SAFE_EQUAL[E_]; temporary_idx: like mem_idx; temporary_lnk: like mem_lnk
273      do
274         from
275            if start_index /= mem_idx then
276               go_item(start_index)
277            end
278            temporary_idx := mem_idx
279            temporary_lnk := mem_lnk
280         until
281            temporary_idx < lower or else safe_equal.test(element, temporary_lnk.item)
282         loop
283            temporary_idx := temporary_idx - 1
284            temporary_lnk := temporary_lnk.previous
285         end
286         Result := temporary_idx
287         if temporary_idx >= lower then
288            mem_idx := temporary_idx
289            mem_lnk := temporary_lnk
290         end
291      end
292
293   fast_index_of (x: like item; start_index: INTEGER): INTEGER
294      local
295         u: like upper
296      do
297         from
298            Result := start_index
299            u := upper
300         until
301            Result > u or else x = item(Result)
302         loop
303            Result := Result + 1
304         end
305      end
306
307   fast_reverse_index_of (element: like item; start_index: INTEGER): INTEGER
308      local
309         temporary_idx: like mem_idx; temporary_lnk: like mem_lnk
310      do
311         from
312            if start_index /= mem_idx then
313               go_item(start_index)
314            end
315            temporary_idx := mem_idx
316            temporary_lnk := mem_lnk
317         until
318            temporary_idx < lower or else element = temporary_lnk.item
319         loop
320            temporary_idx := temporary_idx - 1
321            temporary_lnk := temporary_lnk.previous
322         end
323         Result := temporary_idx
324         if temporary_idx >= lower then
325            mem_idx := temporary_idx
326            mem_lnk := temporary_lnk
327         end
328      end
329
330   clear_count, clear_count_and_capacity
331      local
332         lnk: like first_link
333      do
334         if first_link /= Void then
335            from
336               lnk := first_link
337               first_link := Void
338               mem_idx := 0
339               mem_lnk := Void
340               upper := 0
341               last_link := Void
342            until
343               lnk = Void
344            loop
345               lnk := dispose_node(lnk)
346            end
347         end
348         next_generation
349      ensure then
350         upper = 0
351      end
352
353   from_collection (model: TRAVERSABLE[like item])
354      local
355         i, up: INTEGER
356      do
357         if free_nodes = Void then
358            free_nodes ::= common_free_nodes.fast_reference_at(generating_type)
359            if free_nodes = Void then
360               create free_nodes.set_item(Void)
361               common_free_nodes.add(free_nodes, generating_type)
362            end
363         end
364         clear_count
365         from
366            i := model.lower
367            up := model.upper
368         until
369            i > up
370         loop
371            add_last(model.item(i))
372            i := i + 1
373         end
374         next_generation
375      end
376
377   slice (low, up: INTEGER): like Current
378      local
379         lnk: like first_link; i: INTEGER
380      do
381         from
382            create Result.make
383            if mem_idx /= low then
384               go_item(low)
385            end
386            lnk := mem_lnk
387            i := up - low + 1
388         until
389            i = 0
390         loop
391            Result.add_last(lnk.item)
392            lnk := lnk.next
393            i := i - 1
394         end
395      end
396
397   occurrences (element: like item): INTEGER
398      local
399         lnk: like first_link; safe_equal: SAFE_EQUAL[E_]
400      do
401         from
402            lnk := first_link
403         until
404            lnk = Void
405         loop
406            if safe_equal.test(element, lnk.item) then
407               Result := Result + 1
408            end
409            lnk := lnk.next
410         end
411      end
412
413   fast_occurrences (element: like item): INTEGER
414      local
415         lnk: like first_link
416      do
417         from
418            lnk := first_link
419         until
420            lnk = Void
421         loop
422            if element = lnk.item then
423               Result := Result + 1
424            end
425            lnk := lnk.next
426         end
427      end
428
429   force (element: E_; index: INTEGER)
430      local
431         v: like element
432      do
433         from
434         until
435            index <= upper
436         loop
437            add_last(v)
438         end
439         put(element, index)
440      end
441
442   all_default: BOOLEAN
443      local
444         l: like first_link; d: like item
445      do
446         from
447            Result := True
448            l := first_link
449         until
450            not Result or else l = Void
451         loop
452            d := l.item
453            if d /= Void then
454               Result := d.is_default
455            end
456            l := l.next
457         end
458      end
459
460   remove_last
461      local
462         link: like last_link
463      do
464         if upper = 1 then
465            first_link := dispose_node(first_link)
466            check
467               first_link = Void
468            end
469            last_link := Void
470            mem_lnk := Void
471            mem_idx := 0
472            upper := 0
473         else
474            link := last_link
475            last_link := link.previous
476            last_link.set_next(Void)
477            link := dispose_node(link)
478            if mem_idx = upper then
479               mem_idx := 1
480               mem_lnk := first_link
481            end
482            upper := upper - 1
483         end
484         next_generation
485      end
486
487   replace_all (old_value, new_value: like item)
488      local
489         i: INTEGER; safe_equal: SAFE_EQUAL[E_]
490      do
491         from
492            i := lower
493         until
494            i > upper
495         loop
496            if safe_equal.test(item(i), old_value) then
497               put(new_value, i)
498            end
499            i := i + 1
500         end
501      end
502
503   fast_replace_all (old_value, new_value: like item)
504      local
505         i: INTEGER
506      do
507         from
508            i := lower
509         until
510            i > upper
511         loop
512            if item(i) = old_value then
513               put(new_value, i)
514            end
515            i := i + 1
516         end
517      end
518
519   reverse
520      local
521         temp: E_; low: like first_link; high: like first_link; i: INTEGER
522      do
523         from
524            low := first_link
525            high := last_link
526            i := count #// 2
527         invariant
528            i > 0 implies low /= Void and high /= Void
529            i > 0 implies low /= high and low.previous /= high
530         until
531            i = 0
532         loop
533            temp := low.item
534            low.set_item(high.item)
535            high.set_item(temp)
536            low := low.next
537            high := high.previous
538            i := i - 1
539         end
540         next_generation
541      end
542
543   new_iterator: ITERATOR[E_]
544      do
545         create {ITERATOR_ON_TWO_WAY_LINKED_LIST[E_]} Result.make(Current)
546      end
547
548feature {}
549   go_item (index: INTEGER)
550      require
551         valid_index(index)
552         mem_idx /= index
553         mem_idx > 0
554         mem_lnk /= Void
555      do
556         if index > mem_idx then
557            if upper - index < index - mem_idx then
558               from
559                  mem_idx := upper
560                  mem_lnk := last_link
561               until
562                  index = mem_idx
563               loop
564                  mem_lnk := mem_lnk.previous
565                  mem_idx := mem_idx - 1
566               end
567            else
568               from
569               until
570                  index = mem_idx
571               loop
572                  mem_lnk := mem_lnk.next
573                  mem_idx := mem_idx + 1
574               end
575            end
576         elseif mem_idx - index < index - 1 then
577            from
578            until
579               index = mem_idx
580            loop
581               mem_lnk := mem_lnk.previous
582               mem_idx := mem_idx - 1
583            end
584         else
585            from
586               mem_idx := 1
587               mem_lnk := first_link
588            until
589               index = mem_idx
590            loop
591               mem_lnk := mem_lnk.next
592               mem_idx := mem_idx + 1
593            end
594         end
595      ensure
596         mem_idx = index
597         mem_lnk /= Void
598      end
599
600   free_nodes: WEAK_REFERENCE[TWO_WAY_LINKED_LIST_NODE[E_]]
601         -- If any, they are ready to be recycled.
602
603   common_free_nodes: DICTIONARY[WEAK_REFERENCE[ANY_TWO_WAY_LINKED_LIST_NODE], STRING]
604      once
605         create {HASHED_DICTIONARY[WEAK_REFERENCE[ANY_TWO_WAY_LINKED_LIST_NODE], STRING]} Result.make
606      end
607
608   dispose_node (node: TWO_WAY_LINKED_LIST_NODE[E_]): TWO_WAY_LINKED_LIST_NODE[E_]
609         -- Add `node' in the `free_nodes' list.
610      require
611         node /= Void
612      local
613         default_value: E_
614      do
615         Result := node.next
616         node.make(default_value, Void, free_nodes.item)
617         free_nodes.set_item(node)
618      ensure
619         Result = old node.next
620      end
621
622   new_node (e: E_; previous, next: TWO_WAY_LINKED_LIST_NODE[E_]): TWO_WAY_LINKED_LIST_NODE[E_]
623         -- Recycle from `free_nodes' or create a new one.
624      do
625         Result := free_nodes.item
626         if Result = Void then
627            create Result.make(e, previous, next)
628         else
629            free_nodes.set_item(Result.next)
630            Result.make(e, previous, next)
631         end
632      end
633
634invariant
635   empty_status: first_link = Void implies last_link = Void and upper = 0 and mem_idx = 0 and mem_lnk = Void
636   not_empty_status: first_link /= Void implies last_link /= Void and upper > 0 and mem_idx > 0 and mem_lnk /= Void
637
638end -- class TWO_WAY_LINKED_LIST
639--
640-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
641--
642-- Permission is hereby granted, free of charge, to any person obtaining a copy
643-- of this software and associated documentation files (the "Software"), to deal
644-- in the Software without restriction, including without limitation the rights
645-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
646-- copies of the Software, and to permit persons to whom the Software is
647-- furnished to do so, subject to the following conditions:
648--
649-- The above copyright notice and this permission notice shall be included in
650-- all copies or substantial portions of the Software.
651--
652-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
653-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
654-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
655-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
656-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
657-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
658-- THE SOFTWARE.