/src/lib/storage/internal/avl_tree.e
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.