PageRenderTime 28ms CodeModel.GetById 18ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 1ms

/src/lib/storage/internal/avl_tree.e

http://github.com/tybor/Liberty
Specman e | 552 lines | 483 code | 36 blank | 33 comment | 30 complexity | a2ba3fb5ea667d2af0675ee671738bf3 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4deferred class AVL_TREE[E_]
  5   --
  6   -- Definition of a mathematical set of comparable objects. All common
  7   -- operations on mathematical sets are available.
  8   --
  9
 10insert
 11   AVL_CONSTANTS
 12
 13feature {ANY}
 14   debug_string: STRING
 15      do
 16         if root = Void then
 17            Result := once "Void"
 18         else
 19            Result := tagged_out_memory
 20            Result.clear_count
 21            root.out_in_tagged_out_memory
 22         end
 23      end
 24
 25   count: INTEGER
 26
 27feature {ANY} -- Adding and removing:
 28   remove (e: E_)
 29      do
 30         root := do_remove(root, e)
 31      end
 32
 33   fast_remove (e: E_)
 34      do
 35         root := fast_do_remove(root, e)
 36      end
 37
 38feature {}
 39   root: like a_new_node
 40
 41   rebalance: BOOLEAN
 42
 43   item_memory: E_
 44
 45   set_value_and_key (n: like a_new_node)
 46      deferred
 47      end
 48
 49   set_value (n: like a_new_node)
 50      deferred
 51      end
 52
 53   fast_do_insert (n: like a_new_node): like a_new_node
 54      do
 55         if n = Void then
 56            Result := new_node
 57            set_value_and_key(Result)
 58            count := count + 1
 59            map_dirty := True
 60            rebalance := True
 61         elseif item_memory = n.item then
 62            Result := n
 63            set_value(Result)
 64            rebalance := False
 65         elseif ordered(item_memory, n.item) then
 66            n.set_left(fast_do_insert(n.left))
 67            if rebalance then
 68               Result := left_grown(n)
 69            else
 70               Result := n
 71            end
 72         else
 73            check
 74               ordered(n.item, item_memory)
 75            end
 76            n.set_right(fast_do_insert(n.right))
 77            if rebalance then
 78               Result := right_grown(n)
 79            else
 80               Result := n
 81            end
 82         end
 83      ensure
 84         Result /= Void
 85         Result.balance = node_height(Result.right) - node_height(Result.left)
 86         rebalance = (node_height(Result) > old node_height(n))
 87      end
 88
 89   do_insert (n: like a_new_node): like a_new_node
 90      do
 91         if n = Void then
 92            Result := new_node
 93            set_value_and_key(Result)
 94            count := count + 1
 95            map_dirty := True
 96            rebalance := True
 97         elseif ordered(item_memory, n.item) then
 98            n.set_left(do_insert(n.left))
 99            if rebalance then
100               Result := left_grown(n)
101            else
102               Result := n
103            end
104         elseif ordered(n.item, item_memory) then
105            n.set_right(do_insert(n.right))
106            if rebalance then
107               Result := right_grown(n)
108            else
109               Result := n
110            end
111         else
112            check
113               item_memory.is_equal(n.item)
114            end
115            Result := n
116            set_value(Result)
117            rebalance := False
118         end
119      ensure
120         Result /= Void
121         Result.balance = node_height(Result.right) - node_height(Result.left)
122         rebalance = (node_height(Result) > old node_height(n))
123      end
124
125   left_grown (n: like a_new_node): like a_new_node
126      require
127         rebalance
128         n /= Void
129         node_height(n.right) - node_height(n.left) + 1 = n.balance
130      do
131         inspect
132            n.balance
133         when imbalanced_left then
134            if n.left.balance = imbalanced_left then
135               n.set_balance(balanced)
136               n.left.set_balance(balanced)
137            else
138               inspect
139                  n.left.right.balance
140               when imbalanced_left then
141                  n.set_balance(imbalanced_right)
142                  n.left.set_balance(balanced)
143               when balanced then
144                  n.set_balance(balanced)
145                  n.left.set_balance(balanced)
146               when imbalanced_right then
147                  n.set_balance(balanced)
148                  n.left.set_balance(imbalanced_left)
149               end
150               n.left.right.set_balance(balanced)
151               n.set_left(n.left.rotate_left)
152            end
153            Result := n.rotate_right
154            rebalance := False
155         when balanced then
156            n.set_balance(imbalanced_left)
157            Result := n
158         when imbalanced_right then
159            n.set_balance(balanced)
160            Result := n
161            rebalance := False
162         end
163      ensure
164         Result /= Void
165         Result.balance = node_height(Result.right) - node_height(Result.left)
166         rebalance = (node_height(Result) > 1 + old node_height(n.right).max(node_height(n.left) - 1))
167      end
168
169   right_grown (n: like a_new_node): like a_new_node
170      require
171         rebalance
172         n /= Void
173         node_height(n.right) - 1 - node_height(n.left) = n.balance
174      do
175         inspect
176            n.balance
177         when imbalanced_right then
178            if n.right.balance = imbalanced_right then
179               n.set_balance(balanced)
180               n.right.set_balance(balanced)
181            else
182               inspect
183                  n.right.left.balance
184               when imbalanced_right then
185                  n.set_balance(imbalanced_left)
186                  n.right.set_balance(balanced)
187               when balanced then
188                  n.set_balance(balanced)
189                  n.right.set_balance(balanced)
190               when imbalanced_left then
191                  n.set_balance(balanced)
192                  n.right.set_balance(imbalanced_right)
193               end
194               n.right.left.set_balance(balanced)
195               n.set_right(n.right.rotate_right)
196            end
197            Result := n.rotate_left
198            rebalance := False
199         when balanced then
200            n.set_balance(imbalanced_right)
201            Result := n
202         when imbalanced_left then
203            n.set_balance(balanced)
204            Result := n
205            rebalance := False
206         end
207      ensure
208         Result /= Void
209         Result.balance = node_height(Result.right) - node_height(Result.left)
210         rebalance = (node_height(Result) > 1 + old node_height(n.left).max(node_height(n.right) - 1))
211      end
212
213   fast_do_remove (n: like a_new_node; e: E_): like a_new_node
214      do
215         if n = Void then
216            rebalance := False
217         elseif e = n.item then
218            if n.left = Void then
219               Result := n.right
220               exchange_and_discard(n, n)
221            elseif n.right = Void then
222               Result := n.left
223               exchange_and_discard(n, n)
224            else
225               n.set_left(remove_right(n, n.left))
226               if rebalance then
227                  Result := left_shrunk(n)
228               else
229                  Result := n
230               end
231            end
232         elseif ordered(e, n.item) then
233            n.set_left(do_remove(n.left, e))
234            if rebalance then
235               Result := left_shrunk(n)
236            else
237               Result := n
238            end
239         else
240            check
241               ordered(n.item, e)
242            end
243            n.set_right(do_remove(n.right, e))
244            if rebalance then
245               Result := right_shrunk(n)
246            else
247               Result := n
248            end
249         end
250      ensure
251         Result = Void or else Result.balance = node_height(Result.right) - node_height(Result.left)
252         rebalance = (node_height(Result) < old node_height(n))
253      end
254
255   do_remove (n: like a_new_node; e: E_): like a_new_node
256      do
257         if n = Void then
258            rebalance := False
259         elseif ordered(e, n.item) then
260            n.set_left(do_remove(n.left, e))
261            if rebalance then
262               Result := left_shrunk(n)
263            else
264               Result := n
265            end
266         elseif ordered(n.item, e) then
267            n.set_right(do_remove(n.right, e))
268            if rebalance then
269               Result := right_shrunk(n)
270            else
271               Result := n
272            end
273         elseif n.left = Void then
274            Result := n.right
275            exchange_and_discard(n, n)
276         elseif n.right = Void then
277            Result := n.left
278            exchange_and_discard(n, n)
279         else
280            n.set_left(remove_right(n, n.left))
281            if rebalance then
282               Result := left_shrunk(n)
283            else
284               Result := n
285            end
286         end
287      ensure
288         Result = Void or else Result.balance = node_height(Result.right) - node_height(Result.left)
289         rebalance = (node_height(Result) < old node_height(n))
290      end
291
292   remove_right (n1, n2: like a_new_node): like a_new_node
293      require
294         n1 /= Void
295         n2 /= Void
296      do
297         if n2.right = Void then
298            Result := n2.left
299            exchange_and_discard(n1, n2)
300         else
301            n2.set_right(remove_right(n1, n2.right))
302            if rebalance then
303               Result := right_shrunk(n2)
304            else
305               Result := n2
306            end
307         end
308      ensure
309         Result = Void or else Result.balance = node_height(Result.right) - node_height(Result.left)
310         rebalance = (node_height(Result) < old node_height(n2))
311      end
312
313   left_shrunk (n: like a_new_node): like a_new_node
314      require
315         rebalance
316         n /= Void
317         node_height(n.right) - node_height(n.left) - 1 = n.balance
318      do
319         inspect
320            n.balance
321         when imbalanced_left then
322            n.set_balance(balanced)
323            Result := n
324         when balanced then
325            n.set_balance(imbalanced_right)
326            Result := n
327            rebalance := False
328         when imbalanced_right then
329            inspect
330               n.right.balance
331            when imbalanced_left then
332               inspect
333                  n.right.left.balance
334               when imbalanced_left then
335                  n.set_balance(balanced)
336                  n.right.set_balance(imbalanced_right)
337               when balanced then
338                  n.set_balance(balanced)
339                  n.right.set_balance(balanced)
340               when imbalanced_right then
341                  n.set_balance(imbalanced_left)
342                  n.right.set_balance(balanced)
343               end
344               n.right.left.set_balance(balanced)
345               n.set_right(n.right.rotate_right)
346            when balanced then
347               n.set_balance(imbalanced_right)
348               n.right.set_balance(imbalanced_left)
349               rebalance := False
350            when imbalanced_right then
351               n.set_balance(balanced)
352               n.right.set_balance(balanced)
353            end
354            Result := n.rotate_left
355         end
356      ensure
357         Result /= Void
358         Result.balance = node_height(Result.right) - node_height(Result.left)
359         rebalance = (node_height(Result) < 1 + old node_height(n.right).max(node_height(n.left) + 1))
360      end
361
362   right_shrunk (n: like a_new_node): like a_new_node
363      require
364         rebalance
365         n /= Void
366         node_height(n.right) + 1 - node_height(n.left) = n.balance
367      do
368         inspect
369            n.balance
370         when imbalanced_right then
371            n.set_balance(balanced)
372            Result := n
373         when balanced then
374            n.set_balance(imbalanced_left)
375            Result := n
376            rebalance := False
377         when imbalanced_left then
378            inspect
379               n.left.balance
380            when imbalanced_right then
381               inspect
382                  n.left.right.balance
383               when imbalanced_right then
384                  n.set_balance(balanced)
385                  n.left.set_balance(imbalanced_left)
386               when balanced then
387                  n.set_balance(balanced)
388                  n.left.set_balance(balanced)
389               when imbalanced_left then
390                  n.set_balance(imbalanced_right)
391                  n.left.set_balance(balanced)
392               end
393               n.left.right.set_balance(balanced)
394               n.set_left(n.left.rotate_left)
395            when balanced then
396               n.set_balance(imbalanced_left)
397               n.left.set_balance(imbalanced_right)
398               rebalance := False
399            when imbalanced_left then
400               n.set_balance(balanced)
401               n.left.set_balance(balanced)
402            end
403            Result := n.rotate_right
404         end
405      ensure
406         Result /= Void
407         Result.balance = node_height(Result.right) - node_height(Result.left)
408         rebalance = (node_height(Result) < 1 + old node_height(n.left).max(node_height(n.right) + 1))
409      end
410
411   exchange_and_discard (n1, n2: like a_new_node)
412      require
413         n1 /= Void
414         n2 /= Void
415      deferred
416      ensure
417         map_dirty
418         count = old count - 1
419         rebalance
420      end
421
422   clear_nodes (node: like a_new_node)
423      do
424         if node.left /= Void then
425            clear_nodes(node.left)
426         end
427         if node.right /= Void then
428            clear_nodes(node.right)
429         end
430         discard_node(node)
431      end
432
433   node_height (node: like a_new_node): INTEGER
434      do
435         if node /= Void then
436            Result := node.height
437         end
438      end
439
440feature {ANY} -- Looking and searching:
441   has (e: E_): BOOLEAN
442         -- Is element `e' in the set?
443      do
444         Result := root /= Void and then root.has(e)
445      end
446
447   fast_has (e: E_): BOOLEAN
448         -- Is element `e' in the set?
449      do
450         Result := root /= Void and then root.fast_has(e)
451      end
452
453feature {} -- Iterating internals:
454   build_map
455      require
456         build_needed: map_dirty
457      do
458         map.clear_count
459         if count > 0 then
460            root.map_in(map)
461         end
462         map_dirty := False
463      ensure
464         build_done: not map_dirty
465      end
466
467   map: FAST_ARRAY[like a_new_node]
468         -- Elements in a row for iteration. See `build_map'.
469
470   map_dirty: BOOLEAN
471         -- True when the map needs to be built again for the iterators. See
472         -- `build_map'.
473
474feature {}
475   new_node: like a_new_node
476      do
477         if lost_nodes.is_empty then
478            Result := a_new_node
479         else
480            Result := lost_nodes.item
481         end
482      end
483
484   a_new_node: AVL_TREE_NODE[E_]
485      deferred
486      end
487
488   discard_node (n: like a_new_node)
489      require
490         n /= Void
491      do
492         lost_nodes.recycle(n)
493      end
494
495   lost_nodes: RECYCLING_POOL[like a_new_node]
496      local
497         key: FIXED_STRING
498      do
499         Result := lost_nodes_memory
500         if Result = Void then
501            key := generating_type.intern
502            Result ::= lost_nodes_pool.fast_reference_at(key)
503            if Result = Void then
504               create Result.make
505               lost_nodes_pool.add(Result, key)
506            end
507            lost_nodes_memory := Result
508         end
509      end
510
511   lost_nodes_memory: like lost_nodes
512
513   lost_nodes_pool: HASHED_DICTIONARY[RECYCLING_POOL[AVL_TREE_NODE_ANY], FIXED_STRING]
514      once
515         create Result.make
516      end
517
518   ordered (e1, e2: E_): BOOLEAN
519         -- True if [e1, e2] is a correctly ordered sequence; usually, e1 < e2
520      require
521         e1 /= Void
522         e2 /= Void
523      deferred
524      end
525
526invariant
527   map /= Void
528   not map_dirty implies map.count = count
529   count > 0 implies root /= Void and then root.count = count
530   lost_nodes /= Void
531
532end -- class AVL_TREE
533--
534-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
535--
536-- Permission is hereby granted, free of charge, to any person obtaining a copy
537-- of this software and associated documentation files (the "Software"), to deal
538-- in the Software without restriction, including without limitation the rights
539-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
540-- copies of the Software, and to permit persons to whom the Software is
541-- furnished to do so, subject to the following conditions:
542--
543-- The above copyright notice and this permission notice shall be included in
544-- all copies or substantial portions of the Software.
545--
546-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
547-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
548-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
549-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
550-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
551-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
552-- THE SOFTWARE.