/src/lib/storage/low_level/native_array.e
Specman e | 842 lines | 664 code | 51 blank | 127 comment | 32 complexity | ad3fadb4ed622917203ceafc7a480f9f MD5 | raw file
1-- This file is part of a Liberty Eiffel library. 2-- See the full copyright at the end. 3-- 4expanded class NATIVE_ARRAY[E_] 5 -- 6 -- This class gives access to the lowest level for arrays. As any low level array, you can 7 -- get high performances with NATIVE_ARRAYs, but you loose most valid bounds checks (as 8 -- you can do in plain C code for example). 9 -- 10 -- Note: this class is the basic support for most of our high-level arrays-like classes: STRING, 11 -- ARRAY, FAST_ARRAY as well as MUTABLE_BIG_INTEGER. Each class using some attribute of some 12 -- NATIVE_ARRAY type needs an attribute named `capacity' with value set to the size of the 13 -- actual NATIVE_ARRAY. Value has to be adjusted after each calloc/realloc/create_from. 14 -- 15 16insert 17 SAFE_EQUAL[E_] 18 19create {ANY} 20 default_create, manifest_creation 21 22feature {ANY} -- Basic features: 23 element_sizeof: INTEGER 24 -- The size in number of bytes for type `E_'. 25 external "built_in" 26 end 27 28 calloc (nb_elements: INTEGER): like Current 29 -- Allocate a new array of `nb_elements' of type `E_'. 30 -- The new array is initialized with default values. 31 require 32 nb_elements > 0 33 external "built_in" 34 ensure 35 Result.is_not_null 36 Result.all_default(nb_elements - 1) 37 end 38 39 item (index: INTEGER): E_ 40 -- To read an `item'. 41 -- Assume that `calloc' is already done and that `index' is the range [0 .. `nb_elements'-1]. 42 require 43 index >= 0 44 external "built_in" 45 end 46 47 put (element: E_; index: INTEGER) 48 -- To write an item. 49 -- Assume that `calloc' is already done and that `index' 50 -- is the range [0 .. `nb_elements'-1]. 51 require 52 index >= 0 53 external "built_in" 54 ensure 55 item(index) = element 56 end 57 58feature {ANY} 59 realloc (old_nb_elts, new_nb_elts: INTEGER): like Current 60 -- Assume Current is a valid NATIVE_ARRAY in range 61 -- [0 .. `old_nb_elts'-1]. Allocate a bigger new array in 62 -- range [0 .. `new_nb_elts'-1]. 63 -- Old range is copied in the new allocated array. 64 -- New items are initialized with default values. 65 require 66 is_not_null 67 old_nb_elts > 0 68 old_nb_elts < new_nb_elts 69 do 70 Result := calloc(new_nb_elts) 71 Result.copy_from(Current, old_nb_elts - 1) 72 ensure 73 Result.is_not_null 74 end 75 76feature {ANY} -- Comparison: 77 memcmp (other: like Current; capacity: INTEGER): BOOLEAN 78 -- True if all elements in range [0 .. `capacity'-1] are identical using `is_equal'. 79 -- Assume Current and `other' are big enough. 80 -- See also `fast_memcmp'. 81 require 82 capacity > 0 implies other.is_not_null 83 local 84 i: INTEGER 85 do 86 from 87 i := capacity - 1 88 until 89 i < 0 or else not safe_equal(item(i), other.item(i)) 90 loop 91 i := i - 1 92 end 93 Result := i < 0 94 end 95 96 slice_memcmp (at: INTEGER; other: like Current; other_lower, other_upper: INTEGER): BOOLEAN 97 -- True if all elements in range [0 .. `other_upper' - `other_lower'] are identical 98 -- to the elements in range [`other_lower' .. `other_upper'] of `other' using 99 -- `is_equal'. Assume `Current' and `other' are big enough. 100 -- See also `slice_fast_memcmp'. 101 require 102 at >= 0 103 other_lower >= 0 104 other_upper >= other_lower - 1 105 other_upper >= other_lower implies other.is_not_null 106 local 107 i: INTEGER 108 do 109 from 110 i := other_upper - other_lower 111 until 112 i < 0 or else not safe_equal(item(at + i), other.item(other_lower + i)) 113 loop 114 i := i - 1 115 end 116 Result := i < 0 117 end 118 119 fast_memcmp (other: like Current; capacity: INTEGER): BOOLEAN 120 -- Same jobs as `memcmp' but uses infix "=" instead of `is_equal'. 121 require 122 capacity > 0 implies other.is_not_null 123 local 124 i: INTEGER 125 do 126 from 127 i := capacity - 1 128 until 129 i < 0 or else item(i) /= other.item(i) 130 loop 131 i := i - 1 132 end 133 Result := i < 0 134 end 135 136 slice_fast_memcmp (at: INTEGER; other: like Current; other_lower, other_upper: INTEGER): BOOLEAN 137 -- Same jobs as `slice_memcmp' but uses infix "=" instead of `is_equal'. 138 require 139 at >= 0 140 other_lower >= 0 141 other_upper >= other_lower - 1 142 other_upper >= other_lower implies other.is_not_null 143 local 144 i: INTEGER 145 do 146 from 147 i := other_upper - other_lower 148 until 149 i < 0 or else item(at + i) /= other.item(other_lower + i) 150 loop 151 i := i - 1 152 end 153 Result := i < 0 154 end 155 156 deep_memcmp (other: like Current; capacity: INTEGER): BOOLEAN 157 -- Same jobs as `memcmp' but uses `is_deep_equal' instead of `is_equal'. 158 require 159 capacity > 0 implies other.is_not_null 160 local 161 i: INTEGER; e1, e2: like item 162 do 163 from 164 i := capacity - 1 165 Result := True 166 until 167 not Result or else i < 0 168 loop 169 e1 := item(i) 170 e2 := other.item(i) 171 if e1 = e2 then 172 elseif e1 /= Void then 173 if e2 /= Void then 174 Result := e1.is_deep_equal(e2) 175 else 176 Result := False 177 end 178 else 179 Result := False 180 end 181 i := i - 1 182 end 183 end 184 185 slice_deep_memcmp (at: INTEGER; other: like Current; other_lower, other_upper: INTEGER): BOOLEAN 186 -- Same jobs as `slice_memcmp' but uses `is_deep_equal' instead of `is_equal'. 187 require 188 at >= 0 189 other_lower >= 0 190 other_upper >= other_lower - 1 191 other_upper >= other_lower implies other.is_not_null 192 local 193 i: INTEGER; e1, e2: like item 194 do 195 from 196 i := other_upper - other_lower 197 Result := True 198 until 199 not Result or else i < 0 200 loop 201 e1 := item(i) 202 e2 := other.item(i) 203 if e1 = e2 then 204 elseif e1 /= Void then 205 if e2 /= Void then 206 Result := e1.is_deep_equal(e2) 207 else 208 Result := False 209 end 210 else 211 Result := False 212 end 213 i := i - 1 214 end 215 end 216 217feature {ANY} -- Searching: 218 first_index_of (element: like item; upper: INTEGER): INTEGER 219 -- Using `is_equal' for comparison, gives the index of the first occurrence of `element' at or after 220 -- `0'. Answer `upper + 1' when the search fail. 221 -- See also `fast_index_of', `reverse_index_of'. 222 require 223 upper >= 0 224 do 225 from 226 check 227 Result = 0 228 end 229 until 230 Result > upper or else safe_equal(element, item(Result)) 231 loop 232 Result := Result + 1 233 end 234 ensure 235 Result.in_range(0, upper + 1) 236 Result <= upper implies safe_equal(element, item(Result)) 237 end 238 239 index_of (element: like item; start_index, upper: INTEGER): INTEGER 240 -- Using `is_equal' for comparison, gives the index of the first occurrence of `element' at or after 241 -- `start_index'. Answer `upper + 1' when the search fail. 242 -- See also `fast_index_of', `reverse_index_of'. 243 require 244 start_index >= 0 245 start_index <= upper 246 do 247 from 248 Result := start_index 249 until 250 Result > upper or else safe_equal(element, item(Result)) 251 loop 252 Result := Result + 1 253 end 254 ensure 255 Result.in_range(start_index, upper + 1) 256 Result <= upper implies safe_equal(element, item(Result)) 257 end 258 259 reverse_index_of (element: like item; upper: INTEGER): INTEGER 260 -- Using `is_equal' for comparison, gives the index of the first occurrence of `element' at or before 261 -- `upper'. Search is done in reverse direction, which means from `upper' down to the 262 -- `0'. Answer `-1' when the search fail. 263 -- See also `fast_reverse_index_of', `index_of'. 264 require 265 upper >= -1 266 do 267 from 268 Result := upper 269 until 270 Result < 0 or else safe_equal(element, item(Result)) 271 loop 272 Result := Result - 1 273 end 274 ensure 275 Result.in_range(-1, upper) 276 Result > 0 implies safe_equal(element, item(Result)) 277 end 278 279 fast_index_of (element: like item; start_index, upper: INTEGER): INTEGER 280 -- Using basic `=' for comparison, gives the index of the first occurrence of `element' at or after 281 -- `start_index'. Answer `upper + 1' when the search fail. 282 -- See also `index_of', `reverse_index_of'. 283 require 284 start_index >= 0 285 start_index <= upper + 1 286 do 287 from 288 Result := start_index 289 until 290 Result > upper or else element = item(Result) 291 loop 292 Result := Result + 1 293 end 294 ensure 295 Result.in_range(start_index, upper + 1) 296 Result <= upper implies element = item(Result) 297 end 298 299 fast_reverse_index_of (element: like item; upper: INTEGER): INTEGER 300 -- Using basic `=' for comparison, gives the index of the first occurrence of `element' at or before 301 -- `upper'. Search is done in reverse direction, which means from `upper' down to the 302 -- `0'. Answer `-1' when the search fail. 303 -- See also `reverse_index_of', `index_of'. 304 require 305 upper >= -1 306 do 307 from 308 Result := upper 309 until 310 Result < 0 or else element = item(Result) 311 loop 312 Result := Result - 1 313 end 314 ensure 315 Result.in_range(-1, upper) 316 Result > 0 implies element = item(Result) 317 end 318 319 fast_first_index_of (element: like item; upper: INTEGER): INTEGER 320 -- Using basic `=' for comparison, gives the index of the first occurrence of `element' at or after 321 -- `0'. Answer `upper + 1' when the search fail. 322 -- See also `fast_index_of', `reverse_index_of'. 323 require 324 upper >= 0 325 do 326 from 327 check 328 Result = 0 329 end 330 until 331 Result > upper or else element = item(Result) 332 loop 333 Result := Result + 1 334 end 335 ensure 336 Result.in_range(0, upper + 1) 337 Result <= upper implies element = item(Result) 338 end 339 340 has (element: like item; upper: INTEGER): BOOLEAN 341 -- Look for `element' using `is_equal' for comparison. 342 -- Also consider `fast_has' to choose the most appropriate. 343 require 344 upper >= -1 345 local 346 i: INTEGER 347 do 348 from 349 i := upper 350 until 351 Result or else i < 0 352 loop 353 Result := safe_equal(element, item(i)) 354 i := i - 1 355 end 356 end 357 358 slice_has (element: like item; lower, upper: INTEGER): BOOLEAN 359 -- Look for `element' using `is_equal' for comparison. 360 -- Also consider `slice_fast_has' to choose the most appropriate. 361 require 362 lower >= 0 363 upper >= lower - 1 364 local 365 i: INTEGER 366 do 367 from 368 i := lower 369 until 370 Result or else i > upper 371 loop 372 Result := safe_equal(element, item(i)) 373 i := i + 1 374 end 375 end 376 377 fast_has (element: like item; upper: INTEGER): BOOLEAN 378 -- Look for `element' using basic `=' for comparison. 379 -- Also consider `has' to choose the most appropriate. 380 require 381 upper >= -1 382 local 383 i: INTEGER 384 do 385 from 386 i := upper 387 until 388 i < 0 or else element = item(i) 389 loop 390 i := i - 1 391 end 392 Result := i >= 0 393 end 394 395 slice_fast_has (element: like item; lower, upper: INTEGER): BOOLEAN 396 -- Look for `element' using `is_equal' for comparison. 397 -- Also consider `slice_fast_has' to choose the most appropriate. 398 require 399 lower >= 0 400 upper >= lower - 1 401 local 402 i: INTEGER 403 do 404 from 405 i := lower 406 until 407 Result or else i > upper 408 loop 409 Result := element = item(i) 410 i := i + 1 411 end 412 end 413 414feature {ANY} -- Removing: 415 remove_first (upper: INTEGER) 416 -- Assume `upper' is a valid index. 417 -- Move range [1 .. `upper'] by 1 position left. 418 require 419 upper >= 0 420 local 421 i: INTEGER 422 do 423 from 424 until 425 i = upper 426 loop 427 put(item(i + 1), i) 428 i := i + 1 429 end 430 end 431 432 remove (index, upper: INTEGER) 433 -- Assume `upper' is a valid index. 434 -- Move range [`index' + 1 .. `upper'] by 1 position left. 435 require 436 index >= 0 437 index <= upper 438 local 439 i: INTEGER 440 do 441 from 442 i := index 443 until 444 i = upper 445 loop 446 put(item(i + 1), i) 447 i := i + 1 448 end 449 end 450 451feature {ANY} -- Replacing: 452 replace_all (old_value, new_value: like item; upper: INTEGER) 453 -- Replace all occurrences of the element `old_value' by `new_value' using `is_equal' for comparison. 454 -- See also `fast_replace_all' to choose the appropriate one. 455 require 456 upper >= -1 457 local 458 i: INTEGER 459 do 460 from 461 i := upper 462 until 463 i < 0 464 loop 465 if safe_equal(old_value, item(i)) then 466 put(new_value, i) 467 end 468 i := i - 1 469 end 470 end 471 472 fast_replace_all (old_value, new_value: like item; upper: INTEGER) 473 -- Replace all occurrences of the element `old_value' by `new_value' 474 -- using basic `=' for comparison. 475 -- See also `replace_all' to choose the appropriate one. 476 require 477 upper >= -1 478 local 479 i: INTEGER 480 do 481 from 482 i := upper 483 until 484 i < 0 485 loop 486 if old_value = item(i) then 487 put(new_value, i) 488 end 489 i := i - 1 490 end 491 end 492 493feature {ANY} -- Adding: 494 copy_at (at: INTEGER; src: like Current; src_capacity: INTEGER) 495 -- Copy range [0 .. `src_capacity - 1'] of `src' to range [`at' .. `at + src_capacity - 1'] of `Current'. 496 -- No subscript checking. 497 require 498 at >= 0 499 src_capacity >= 0 500 local 501 at_idx, src_idx: INTEGER 502 do 503 from 504 src_idx := src_capacity - 1 505 at_idx := at + src_idx 506 until 507 src_idx < 0 508 loop 509 put(src.item(src_idx), at_idx) 510 src_idx := src_idx - 1 511 at_idx := at_idx - 1 512 end 513 end 514 515 slice_copy (at: INTEGER; src: like Current; src_min, src_max: INTEGER) 516 -- Copy range [`src_min' .. `src_max'] of `src' to range [`at' .. `at + src_max - src_min'] of `Current'. 517 -- No subscript checking. 518 --*** NATIVE_ARRAY[CHARACTER/INTEGER_8] are modified byte per byte. Efficiency should be improved here. 519 require 520 at >= 0 521 src_max >= src_min - 1 522 useful_work: src /= Current or at /= src_min 523 external "built_in" 524 end 525 526feature {ANY} -- Other: 527 set_all_with (v: like item; upper: INTEGER) 528 -- Set all elements in range [0 .. `upper'] with value `v'. 529 require 530 upper >= -1 531 do 532 set_slice_with(v, 0, upper) 533 end 534 535 set_slice_with (v: like item; lower, upper: INTEGER) 536 -- Set all elements in range [`lower' .. `upper'] with value `v'. 537 require 538 lower >= 0 539 upper >= lower - 1 540 local 541 i: INTEGER 542 do 543 from 544 i := lower 545 until 546 i > upper 547 loop 548 put(v, i) 549 i := i + 1 550 end 551 end 552 553 clear_all (upper: INTEGER) 554 -- Set all elements in range [0 .. `upper'] with the default value. 555 require 556 upper >= -1 557 local 558 v: E_; i: INTEGER 559 do 560 from 561 i := upper 562 until 563 i < 0 564 loop 565 put(v, i) 566 i := i - 1 567 end 568 ensure 569 all_default(upper) 570 end 571 572 clear (lower, upper: INTEGER) 573 -- Set all elements in range [`lower' .. `upper'] with the default value. 574 require 575 lower >= 0 576 upper >= lower - 1 577 local 578 v: E_; i: INTEGER 579 do 580 from 581 i := lower 582 until 583 i > upper 584 loop 585 put(v, i) 586 i := i + 1 587 end 588 end 589 590 copy_from (model: like Current; upper: INTEGER) 591 -- Assume `upper' is a valid index both in Current and `model'. 592 require 593 upper >= -1 594 do 595 copy_slice_from(model, 0, upper) 596 end 597 598 copy_slice_from (model: like Current; lower, upper: INTEGER) 599 -- Assume `upper' is a valid index both in Current and `model'. 600 require 601 lower >= 0 602 upper >= lower - 1 603 useful_work: model /= Current or else lower > 0 604 do 605 slice_copy(0, model, lower, upper) 606 end 607 608 deep_twin_from (capacity: INTEGER): like Current 609 -- To implement `deep_twin'. Allocate a new array of `capacity' initialized with `deep_twin'. 610 -- Assume `capacity' is valid both in `Current' and `model'. 611 require 612 capacity >= 0 613 local 614 i: INTEGER; element: like item 615 do 616 if capacity > 0 then 617 from 618 Result := calloc(capacity) 619 i := capacity - 1 620 until 621 i < 0 622 loop 623 element := item(i) 624 if element /= Void then 625 element := element.deep_twin 626 end 627 Result.put(element, i) 628 i := i - 1 629 end 630 end 631 end 632 633 move (lower, upper, offset: INTEGER) 634 -- Move range [`lower' .. `upper'] by `offset' positions. 635 -- Freed positions are not initialized to default values. 636 require 637 lower >= 0 638 upper >= lower 639 lower + offset >= 0 640 local 641 i: INTEGER 642 do 643 if offset = 0 then 644 elseif offset < 0 then 645 from 646 i := lower 647 until 648 i > upper 649 loop 650 put(item(i), i + offset) 651 i := i + 1 652 end 653 else 654 from 655 i := upper 656 until 657 i < lower 658 loop 659 put(item(i), i + offset) 660 i := i - 1 661 end 662 end 663 end 664 665 occurrences (element: like item; upper: INTEGER): INTEGER 666 -- Number of occurrences of `element' in range [0 .. `upper'] using `is_equal' for comparison. 667 -- See also `fast_occurrences' to chose the appropriate one. 668 require 669 upper >= -1 670 local 671 i: INTEGER 672 do 673 from 674 i := upper 675 until 676 i < 0 677 loop 678 if safe_equal(element, item(i)) then 679 Result := Result + 1 680 end 681 i := i - 1 682 end 683 end 684 685 slice_occurrences (element: like item; lower, upper: INTEGER): INTEGER 686 -- Number of occurrences of `element' in range [`lower' .. `upper'] using `is_equal' for comparison. 687 -- See also `slice_fast_occurrences' to chose the appropriate one. 688 require 689 lower >= 0 690 upper >= lower - 1 691 local 692 i: INTEGER 693 do 694 from 695 i := lower 696 until 697 i > upper 698 loop 699 if safe_equal(element, item(i)) then 700 Result := Result + 1 701 end 702 i := i + 1 703 end 704 end 705 706 fast_occurrences (element: like item; upper: INTEGER): INTEGER 707 -- Number of occurrences of `element' in range [0 .. `upper'] using basic "=" for comparison. 708 -- See also `occurrences' to chose the appropriate one. 709 require 710 upper >= -1 711 local 712 i: INTEGER 713 do 714 from 715 i := upper 716 until 717 i < 0 718 loop 719 if element = item(i) then 720 Result := Result + 1 721 end 722 i := i - 1 723 end 724 end 725 726 slice_fast_occurrences (element: like item; lower, upper: INTEGER): INTEGER 727 -- Number of occurrences of `element' in range [`lower' .. `upper'] 728 -- using basic "=" for comparison. 729 -- See also `slice_occurrences' to chose the appropriate one. 730 require 731 lower >= 0 732 upper >= lower - 1 733 local 734 i: INTEGER 735 do 736 from 737 i := lower 738 until 739 i > upper 740 loop 741 if element = item(i) then 742 Result := Result + 1 743 end 744 i := i + 1 745 end 746 end 747 748 all_default (upper: INTEGER): BOOLEAN 749 -- Do all items in range [0 .. `upper'] have their type's default value? 750 -- Note: for non Void items, the test is performed with the `is_default' predicate. 751 require 752 upper >= -1 753 do 754 Result := slice_default(0, upper) 755 end 756 757 slice_default (lower, upper: INTEGER): BOOLEAN 758 -- Do all items in range [`lower' .. `upper'] have their type's default value? 759 -- Note: for non Void items, the test is performed with the `is_default' predicate. 760 require 761 lower >= 0 762 upper >= lower - 1 763 local 764 i: INTEGER; v: like item 765 do 766 from 767 Result := True 768 i := lower 769 until 770 i > upper or else not Result 771 loop 772 v := item(i) 773 if v /= Void then 774 Result := v.is_default 775 end 776 i := i + 1 777 end 778 end 779 780feature {ANY} -- Interfacing with other languages: 781 to_external: POINTER 782 -- Gives access to the C pointer on the area of storage. 783 do 784 Result := to_pointer 785 end 786 787 from_pointer (pointer: POINTER): like Current 788 -- Convert `pointer' into Current type. 789 external "built_in" 790 end 791 792 is_not_null: BOOLEAN 793 do 794 Result := to_pointer.is_not_null 795 end 796 797 is_null: BOOLEAN 798 do 799 Result := to_pointer.is_null 800 end 801 802feature {} -- Implement manifest generic creation. 803 manifest_make (needed_capacity: INTEGER) 804 -- Manifest creation (see also `calloc' and `realloc' for creation). 805 do 806 check 807 -- Automatic usage of `calloc'. 808 False 809 end 810 end 811 812 manifest_put (index: INTEGER; element: like item) 813 do 814 check 815 -- Automatic usage of `put'. 816 False 817 end 818 end 819 820 manifest_semicolon_check: BOOLEAN False 821 822end -- class NATIVE_ARRAY 823-- 824-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file. 825-- 826-- Permission is hereby granted, free of charge, to any person obtaining a copy 827-- of this software and associated documentation files (the "Software"), to deal 828-- in the Software without restriction, including without limitation the rights 829-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 830-- copies of the Software, and to permit persons to whom the Software is 831-- furnished to do so, subject to the following conditions: 832-- 833-- The above copyright notice and this permission notice shall be included in 834-- all copies or substantial portions of the Software. 835-- 836-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 837-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 838-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 839-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 840-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 841-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 842-- THE SOFTWARE.