/src/lib/storage/collection/two_way_linked_list.e
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.