PageRenderTime 50ms CodeModel.GetById 15ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 1ms

/src/lib/string/string.e

http://github.com/tybor/Liberty
Specman e | 1040 lines | 809 code | 60 blank | 171 comment | 46 complexity | 43c542c8b99e5dcd8def1b6e3267f30d MD5 | raw file
   1-- This file is part of a Liberty Eiffel library.
   2-- See the full copyright at the end.
   3--
   4class STRING
   5   --
   6   -- Resizable character STRINGs indexed from `1' to `count'.
   7   --
   8
   9inherit
  10   NATIVELY_STORED_STRING
  11
  12create {ANY}
  13   with_capacity, make, copy, make_empty, make_filled, from_external, from_external_copy,
  14   from_external_sized, from_external_sized_copy, make_from_string
  15
  16feature {ANY} -- Creation / Modification:
  17   make, with_capacity (needed_capacity: INTEGER)
  18         -- Initialize the string to have at least `needed_capacity' characters of storage.
  19      require
  20         non_negative_size: needed_capacity >= 0
  21      do
  22         storage_lower := 0
  23         if needed_capacity > 0 then
  24            ensure_capacity(needed_capacity)
  25         end
  26         count := 0
  27         next_generation
  28      ensure
  29         needed_capacity <= capacity
  30         empty_string: count = 0
  31      end
  32
  33   make_empty
  34         -- Create an empty string.
  35      do
  36         make(0)
  37      end
  38
  39   make_filled (c: CHARACTER; n: INTEGER)
  40         -- Initialize string with `n' copies of `c'.
  41      require
  42         valid_count: n >= 0
  43      do
  44         make(n)
  45         count := n
  46         fill_with(c)
  47         next_generation
  48      ensure
  49         count_set: count = n
  50         filled: occurrences(c) = count
  51      end
  52
  53   make_from_string (model: ABSTRACT_STRING)
  54         -- Initialize from the characters of `model'.
  55      require
  56         model /= Void
  57      local
  58         c: INTEGER
  59      do
  60         storage_lower := 0
  61         c := model.count
  62         count := c
  63         if c > 0 then
  64            ensure_capacity(c)
  65            slice_copy(0, model, model.lower, model.upper)
  66         end
  67         next_generation
  68      ensure
  69         count = model.count
  70      end
  71
  72feature {ANY}
  73   hash_code: INTEGER
  74      do
  75         Result := computed_hash_code
  76      end
  77
  78feature {ANY} -- Modification:
  79   resize (new_count: INTEGER)
  80         -- Resize Current. When `new_count' is greater than
  81         -- `count', new positions are initialized with the
  82         -- default value of type CHARACTER ('%U').
  83      require
  84         new_count >= 0
  85      do
  86         if new_count <= count then
  87         elseif capacity < new_count + storage_lower then
  88            ensure_capacity(new_count + storage_lower)
  89         else
  90            storage.clear(count + storage_lower, new_count + storage_lower - 1)
  91         end
  92         count := new_count
  93      ensure
  94         count = new_count
  95         capacity >= old capacity
  96      end
  97
  98   clear_count, wipe_out
  99         -- Discard all characters so that `is_empty' is True after that call.
 100         -- The internal `capacity' is not changed by this call (i.e. the internal `storage' memory
 101         -- neither released nor shrunk).
 102         --
 103         -- See also `clear_count_and_capacity'.
 104      do
 105         storage_lower := 0
 106         count := 0
 107      ensure
 108         is_empty: count = 0
 109                   capacity = old capacity
 110                   storage_lower = 0
 111      end
 112
 113   clear_count_and_capacity
 114         -- Discard all characters (`is_empty' is True after that call). The internal `capacity' may also be
 115         -- reduced after this call.
 116         --
 117         -- See also `clear_count'.
 118      local
 119         null_storage: like storage
 120      do
 121         count := 0
 122         capacity := 0
 123         storage_lower := 0
 124         storage := null_storage
 125      ensure
 126         is_empty: count = 0
 127                   capacity = 0
 128                   storage_lower = 0
 129                   storage.is_null
 130      end
 131
 132   copy (other: like Current)
 133         -- Copy `other' onto Current.
 134         --
 135         -- See also `copy_substring'.
 136      local
 137         c: INTEGER
 138      do
 139         if other /= Current then
 140            storage_lower := 0
 141            c := other.count
 142            if c > 0 then
 143               ensure_capacity(c)
 144               storage.copy_slice_from(other.storage, other.storage_lower, other.storage_lower + c - 1)
 145            end
 146            count := c
 147         end
 148      ensure then
 149         count = other.count
 150      end
 151
 152   copy_substring (s: ABSTRACT_STRING; start_index, end_index: INTEGER)
 153         -- Copy the substring from `s' from `start_index' to `end_index'
 154         -- to Current.
 155         --
 156         -- See also `copy'.
 157      require
 158         string_not_void: s /= Void
 159         valid_start_index: 1 <= start_index
 160         valid_end_index: end_index <= s.count
 161         meaningful_interval: start_index <= end_index + 1
 162      local
 163         c: INTEGER
 164      do
 165         c := end_index - start_index + 1
 166         if c > 0 then
 167            ensure_capacity(c)
 168            slice_copy(0, s, start_index, end_index)
 169         end
 170         count := c
 171      end
 172
 173   fill_with (c: CHARACTER)
 174         -- Replace every character with `c'.
 175      do
 176         storage_lower := 0
 177         storage.set_all_with(c, count - 1)
 178      ensure
 179         occurrences(c) = count
 180      end
 181
 182   replace_all (old_character, new_character: like item)
 183         -- Replace all occurrences of the element `old_character' by `new_character'.
 184      do
 185         storage.fast_replace_all(old_character, new_character, count + storage_lower - 1)
 186      ensure
 187         count = old count
 188         old_character /= new_character implies occurrences(old_character) = 0
 189      end
 190
 191   append, append_string (s: ABSTRACT_STRING)
 192         -- Append a copy of 's' to `Current'.
 193         --
 194         -- See also `add_last', `add_first', `prepend', '+'.
 195      require
 196         s_not_void: s /= Void
 197      local
 198         needed_capacity: INTEGER
 199      do
 200         -- Note: pre-computing needed capacity may be costly for ROPEs. Consider moving it into the NATIVELY_STORED_STRING-specific part of the feature.
 201         needed_capacity := count + s.count + storage_lower
 202         ensure_capacity(needed_capacity)
 203         slice_copy(upper, s, s.lower, s.upper)
 204         count := needed_capacity - storage_lower
 205      end
 206
 207   append_substring (s: ABSTRACT_STRING; start_index, end_index: INTEGER)
 208         -- Append the substring from `s' from `start_index' to `end_index'
 209         -- to Current.
 210      require
 211         string_not_void: s /= Void
 212         valid_start_index: 1 <= start_index
 213         valid_end_index: end_index <= s.count
 214         meaningful_interval: start_index <= end_index + 1
 215      local
 216         needed_capacity: INTEGER
 217      do
 218         needed_capacity := count + storage_lower + end_index - start_index + 1
 219         ensure_capacity(needed_capacity)
 220         slice_copy(upper, s, start_index, end_index)
 221         count := needed_capacity
 222      end
 223
 224   prepend (other: ABSTRACT_STRING)
 225         -- Prepend `other' to `Current'.
 226         --
 227         -- See also `append'.
 228      require
 229         other /= Void
 230      local
 231         d, i, j: INTEGER
 232      do
 233         if other = Current then --| **** TODO -- this fixes TEST_ALG09 using a quick and dirty special case :-(
 234            ensure_capacity(count * 2 + storage_lower)
 235            slice_copy(count, Current, lower, upper)
 236            count := count * 2
 237         else
 238            i := count
 239            j := other.count
 240            d := storage_lower - j
 241            if d < 0 then
 242               -- the string to be prepended is bigger than the unused space available in the buffer before the beginning of the string.
 243               ensure_capacity(i + j)
 244            end
 245            if i = 0 or else d = 0 then
 246               storage_lower := 0
 247            elseif d > 0 then
 248               storage_lower := d
 249            else
 250               storage.move(storage_lower, storage_lower + i - 1, -d)
 251               storage_lower := 0
 252            end
 253            slice_copy(0, other, other.lower, other.upper)
 254            count := i + j
 255         end
 256      ensure
 257         (old other.twin + old twin).is_equal(Current)
 258      end
 259
 260   insert_string (s: ABSTRACT_STRING; i: INTEGER)
 261         -- Insert `s' at index `i', shifting characters from index `i'
 262         -- to `count' rightwards.
 263      require
 264         string_not_void: s /= Void
 265         valid_insertion_index: lower <= i and i <= upper + 1
 266      local
 267         j, k, dk: INTEGER
 268      do
 269         j := count
 270         k := s.count
 271         count := j + k
 272         dk := k - storage_lower
 273         if dk <= 0 then
 274            storage.move(storage_lower, i - lower + storage_lower, -k)
 275            storage_lower := -dk
 276            slice_copy(i - lower, s, s.lower, s.upper)
 277         else
 278            ensure_capacity(count)
 279            if storage_lower > 0 then
 280               storage.move(storage_lower, i + storage_lower - lower, -storage_lower)
 281            end
 282            if i <= j then
 283               storage.move(i + storage_lower - lower, j + storage_lower - lower, dk)
 284            end
 285            storage_lower := 0
 286            slice_copy(i - lower, s, s.lower, s.upper)
 287         end
 288      end
 289
 290   replace_substring (s: ABSTRACT_STRING; start_index, end_index: INTEGER)
 291         -- Replace the substring from `start_index' to `end_index',
 292         -- inclusive, with `s'.
 293      require
 294         string_not_void: s /= Void
 295         valid_start_index: lower <= start_index
 296         valid_end_index: end_index <= upper
 297         meaningful_interval: start_index <= end_index + 1
 298      local
 299         remove_len, insert_len, difference, old_upper: INTEGER
 300      do
 301         remove_len := end_index - start_index + 1
 302         insert_len := s.count
 303         difference := insert_len - remove_len
 304         if difference > 0 then
 305            if storage_lower >= difference then
 306               storage.move(storage_lower, start_index, -difference)
 307               storage_lower := storage_lower - difference
 308            else
 309               old_upper := upper
 310               ensure_capacity(count + difference)
 311               if end_index < old_upper then
 312                  -- something to move?
 313                  storage.move(storage_lower + end_index + 1 - lower, storage_lower + old_upper - lower, difference)
 314               end
 315            end
 316         elseif difference < 0 then
 317            if end_index < upper then
 318               -- something to move?
 319               storage.move(storage_lower + end_index + 1 - lower, storage_lower + upper - lower, difference)
 320            end
 321         end
 322         count := count + difference
 323         slice_copy(start_index - lower, s, s.lower, s.upper)
 324      end
 325
 326   put (c: CHARACTER; i: INTEGER)
 327         -- Put `c' at index `i'.
 328         --
 329         -- See also `item', `lower', `upper', `swap'.
 330      require
 331         valid_index: valid_index(i)
 332      do
 333         storage.put(c, storage_lower + i - lower)
 334      ensure
 335         item(i) = c
 336      end
 337
 338   swap (i1, i2: INTEGER)
 339         -- Swap two characters.
 340         --
 341         -- See also `item', `put'.
 342      require
 343         valid_index(i1)
 344         valid_index(i2)
 345      local
 346         tmp: CHARACTER
 347      do
 348         tmp := item(i1)
 349         put(item(i2), i1)
 350         put(tmp, i2)
 351      ensure
 352         item(i1) = old item(i2)
 353         item(i2) = old item(i1)
 354      end
 355
 356   insert_character (c: CHARACTER; i: INTEGER)
 357         -- Inserts `c' at index `i', shifting characters from
 358         -- position 'i' to `count' rightwards.
 359      require
 360         valid_insertion_index: lower <= i and i <= upper + 1
 361      do
 362         if storage_lower > 0 and then i <= upper then
 363            if i > lower then
 364               storage.move(storage_lower, storage_lower + i - lower, -1)
 365            end
 366            storage_lower := storage_lower - 1
 367         else
 368            ensure_capacity(count + storage_lower + 1)
 369            if i <= upper then
 370               storage.move(storage_lower - lower + i, storage_lower - lower + upper, 1)
 371            end
 372         end
 373         storage.put(c, storage_lower + i - lower)
 374         count := count + 1
 375      ensure
 376         item(i) = c
 377         count = old count + 1
 378      end
 379
 380   shrink (min_index, max_index: INTEGER)
 381         -- Keep only the slice [`min_index' .. `max_index'] or nothing
 382         -- when the slice is empty.
 383      require
 384         lower <= min_index
 385         max_index <= upper
 386         min_index <= max_index + 1
 387      do
 388         if max_index < min_index then
 389            count := 0
 390         elseif min_index = 1 then
 391            count := max_index
 392         else
 393            storage_lower := storage_lower + min_index - lower
 394            count := max_index - min_index + 1
 395         end
 396      ensure
 397         count = max_index - min_index + 1
 398      end
 399
 400   remove (i: INTEGER)
 401         -- Remove character at position `i'.
 402         --
 403         -- See also `remove_head', `remove_between', `remove_suffix', `remove_prefix'.
 404      require
 405         valid_removal_index: valid_index(i)
 406      do
 407         remove_between(i, i)
 408      ensure
 409         count = old count - 1
 410      end
 411
 412   add_first, precede (c: CHARACTER)
 413         -- Add `c' at first position.
 414         --
 415         -- See also `add_last'.
 416      do
 417         insert_character(c, lower)
 418      ensure
 419         count = 1 + old count
 420         item(lower) = c
 421      end
 422
 423   add_last, append_character, extend (c: CHARACTER)
 424         -- Append `c' to string.
 425         --
 426         -- See also `add_first'.
 427      do
 428         insert_character(c, upper + 1)
 429      ensure
 430         count = 1 + old count
 431         item(upper) = c
 432      end
 433
 434   to_lower
 435         -- Convert all characters to lower case.
 436         --
 437         -- See also `to_upper', `as_lower', `as_upper'.
 438      local
 439         i: INTEGER
 440      do
 441         from
 442            i := 1
 443         until
 444            i > count
 445         loop
 446            put(item(i).to_lower, i)
 447            i := i + 1
 448         end
 449      end
 450
 451   to_upper
 452         -- Convert all characters to upper case.
 453         --
 454         -- See also `to_lower', `as_upper', `as_lower'.
 455      local
 456         i: INTEGER
 457      do
 458         from
 459            i := 1
 460         until
 461            i > count
 462         loop
 463            put(item(i).to_upper, i)
 464            i := i + 1
 465         end
 466      end
 467
 468   keep_head (n: INTEGER)
 469         -- Remove all characters except for the first `n'.
 470         -- Do nothing if `n' >= `count'.
 471         --
 472         -- See also `keep_tail', `remove_head', `remove_tail'.
 473      require
 474         n_non_negative: n >= 0
 475      do
 476         if n < count then
 477            remove_tail(count - n)
 478         end
 479      ensure
 480         count = n.min(old count)
 481      end
 482
 483   keep_tail (n: INTEGER)
 484         -- Remove all characters except for the last `n'.
 485         -- Do nothing if `n' >= `count'.
 486         --
 487         -- See also `keep_head', `remove_tail', `remove_head'.
 488      require
 489         n_non_negative: n >= 0
 490      do
 491         if n < count then
 492            remove_head(count - n)
 493         end
 494      ensure
 495         count = n.min(old count)
 496      end
 497
 498   remove_first
 499         -- Remove the `first' item.
 500         --
 501         -- See also `remove_head', `remove_last', `remove'.
 502      require
 503         not is_empty
 504      do
 505         storage_lower := storage_lower + 1
 506         count := count - 1
 507      ensure
 508         count = old count - 1
 509      end
 510
 511   remove_head (n: INTEGER)
 512         -- Remove `n' first characters. If `n' >= `count', remove all.
 513         --
 514         -- See also `remove_tail', `remove', `remove_the_first'.
 515      require
 516         n_non_negative: n >= 0
 517      do
 518         if n >= count then
 519            storage_lower := 0
 520            count := 0
 521         else
 522            storage_lower := storage_lower + n
 523            count := count - n
 524         end
 525      ensure
 526         count = (old count - n).max(0)
 527      end
 528
 529   remove_last
 530         -- Remove the `last' item.
 531         --
 532         -- See also `remove_tail', `remove_first', `remove'.
 533      require
 534         not is_empty
 535      do
 536         count := count - 1
 537      ensure
 538         count = old count - 1
 539      end
 540
 541   remove_tail (n: INTEGER)
 542         -- Remove `n' last characters. If `n' >= `count', remove all.
 543         --
 544         -- See also `remove_head', `remove', `remove_the_last'.
 545      require
 546         n_non_negative: n >= 0
 547      do
 548         if n >= count then
 549            storage_lower := 0
 550            count := 0
 551         else
 552            count := count - n
 553         end
 554      ensure
 555         count = (old count - n).max(0)
 556      end
 557
 558   remove_substring, remove_between (start_index, end_index: INTEGER)
 559         -- Remove all characters from `strt_index' to `end_index' inclusive.
 560      require
 561         valid_start_index: 1 <= start_index
 562         valid_end_index: end_index <= count
 563         meaningful_interval: start_index <= end_index + 1
 564      local
 565         i, len: INTEGER
 566      do
 567         len := end_index - start_index + 1
 568         if len > 0 then
 569            from
 570               i := end_index + 1
 571            until
 572               i > count
 573            loop
 574               put(item(i), i - len)
 575               i := i + 1
 576            end
 577            count := count - len
 578         end
 579      ensure
 580         count = old count - (end_index - start_index + 1)
 581      end
 582
 583   remove_suffix (s: ABSTRACT_STRING)
 584         -- Remove the suffix `s' of current string.
 585         --
 586         -- See also `remove_prefix', `remove_tail', `remove'.
 587      require
 588         has_suffix(s)
 589      do
 590         remove_tail(s.count)
 591      ensure
 592         (old Current.twin).is_equal(Current + old s.twin)
 593      end
 594
 595   remove_prefix (s: ABSTRACT_STRING)
 596         -- Remove the prefix `s' of current string.
 597         --
 598         -- See also `remove_suffix', `remove_head', `remove'.
 599      require
 600         has_prefix(s)
 601      do
 602         remove_head(s.count)
 603      ensure
 604         (old s.twin + Current).is_equal(old Current.twin)
 605      end
 606
 607   left_adjust
 608         -- Remove leading blanks.
 609         --
 610         -- See also `remove_head', `first'.
 611      local
 612         i: INTEGER
 613      do
 614         from
 615            i := 1
 616         until
 617            i > count or else not item(i).is_separator -- i.e. not a blank like ' '
 618         loop
 619            i := i + 1
 620         end
 621         remove_head(i - 1)
 622      ensure
 623         stripped: is_empty or else not first.is_separator
 624      end
 625
 626   right_adjust
 627         -- Remove trailing blanks.
 628         --
 629         -- See also `remove_tail', `last'.
 630      do
 631         from
 632         until
 633            count = 0 or else not item(count).is_separator
 634         loop
 635            count := count - 1
 636         end
 637      ensure
 638         stripped: is_empty or else not last.is_separator
 639      end
 640
 641feature {ANY} -- Other features:
 642   substring (start_index, end_index: INTEGER): like Current
 643      local
 644         new_count: INTEGER
 645         new_store: like storage
 646      do
 647         new_count := end_index - start_index + 1
 648         new_store := new_store.calloc(new_count + 1)
 649         new_store.slice_copy(0, storage, storage_lower + start_index - lower, storage_lower + end_index - lower)
 650
 651         Result := standard_twin
 652         Result.from_external_sized(new_store.to_external, new_count)
 653      end
 654
 655   extend_multiple (c: CHARACTER; n: INTEGER)
 656         -- Extend Current with `n' times character `c'.
 657      require
 658         n >= 0
 659      local
 660         i: INTEGER
 661      do
 662         from
 663            i := n
 664         until
 665            i = 0
 666         loop
 667            add_last(c)
 668            i := i - 1
 669         end
 670      ensure
 671         count = n + old count
 672      end
 673
 674  precede_multiple (c: CHARACTER; n: INTEGER)
 675          -- Prepend `n' times character `c' to Current.
 676
 677      local
 678          old_upper, new_storage_lower: INTEGER
 679      do
 680          -- Note: This command once had this precondition: "require n >= 0" As you
 681          -- can see this implementation does not actually need it.  In fact this
 682          -- command will not fail if n is negative. Perhaps it is a vestigial
 683          -- precondition when there were no NATURAL type. When n is not positive
 684          -- this command does not make any change. Paolo
 685          -- 2011-09-04
 686          if n > 0 then
 687                  old_upper := upper
 688                  if old_upper < lower then
 689                          check count = 0 end
 690                                  storage_lower := 0
 691                                  extend_multiple(c, n)
 692                          else
 693                                  if n > storage_lower then
 694                  new_storage_lower := 0
 695                  count := count + storage_lower
 696                  extend_multiple('%U', n - storage_lower)
 697               else
 698                  new_storage_lower := storage_lower - n
 699                  count := count + n
 700               end
 701               storage.move(storage_lower, storage_lower + old_upper - lower, n)
 702               storage.set_slice_with(c, new_storage_lower, new_storage_lower + n - 1)
 703               storage_lower:= new_storage_lower
 704               next_generation
 705            end
 706         end
 707      ensure
 708         count = n.max(0) + old count
 709                 not_changed_when_n_is_not_positive: n < 1 implies Current ~ old twin
 710      end
 711
 712   extend_to_count (c: CHARACTER; needed_count: INTEGER)
 713         -- Extend Current with `c' until `needed_count' is reached.
 714         -- Do nothing if `needed_count' is already greater or equal
 715         -- to `count'.
 716      require
 717         needed_count >= 0
 718      local
 719         needed: INTEGER
 720      do
 721         from
 722            needed := needed_count - count
 723         until
 724            needed <= 0
 725         loop
 726            add_last(c)
 727            needed := needed - 1
 728         end
 729      ensure
 730         count >= needed_count
 731      end
 732
 733   precede_to_count (c: CHARACTER; needed_count: INTEGER)
 734         -- Prepend `c' to Current until `needed_count' is reached.
 735         -- Do nothing if `needed_count' is already greater or equal
 736         -- to `count'.
 737      require
 738         needed_count >= 0
 739      local
 740         needed: INTEGER
 741      do
 742         from
 743            needed := needed_count - count
 744         until
 745            needed <= 0
 746         loop
 747            add_first(c)
 748            needed := needed - 1
 749         end
 750      ensure
 751         count >= needed_count
 752      end
 753
 754   reverse
 755         -- Reverse the string.
 756      local
 757         i1, i2: INTEGER
 758      do
 759         from
 760            i1 := 1
 761            i2 := count
 762         until
 763            i1 >= i2
 764         loop
 765            swap(i1, i2)
 766            i1 := i1 + 1
 767            i2 := i2 - 1
 768         end
 769      end
 770
 771   remove_all_occurrences (ch: CHARACTER)
 772         -- Remove all occurrences of `ch'.
 773         --
 774         -- See also `occurrences', `remove'.
 775      local
 776         i, j: INTEGER
 777      do
 778         from
 779            i := 1
 780            j := 1
 781         until
 782            i > count
 783         loop
 784            if item(i) /= ch then
 785               put(item(i), j)
 786               j := j + 1
 787            end
 788            i := i + 1
 789         end
 790         count := j - 1
 791      ensure
 792         count = old count - old occurrences(ch)
 793      end
 794
 795feature {ANY} -- Testing and Conversion:
 796   to_hexadecimal
 797         -- Convert Current bit sequence into the corresponding
 798         -- hexadecimal notation.
 799      require
 800         is_bit
 801      local
 802         i, k, new_count: INTEGER; value: INTEGER
 803      do
 804         from
 805            i := 1
 806            k := count #\\ 4
 807            if k > 0 then
 808               new_count := 1
 809            end
 810         until
 811            k = 0
 812         loop
 813            value := value * 2 + item(i).value
 814            i := i + 1
 815            k := k - 1
 816         end
 817         if new_count > 0 then
 818            put(value.hexadecimal_digit, new_count)
 819         end
 820         from
 821         until
 822            i > count
 823         loop
 824            from
 825               value := item(i).value
 826               i := i + 1
 827               k := 3
 828            until
 829               k = 0
 830            loop
 831               value := value * 2 + item(i).value
 832               i := i + 1
 833               k := k - 1
 834            end
 835            new_count := new_count + 1
 836            put(value.hexadecimal_digit, new_count)
 837         end
 838         count := new_count
 839      end
 840
 841feature {ANY} -- Other features:
 842   extend_unless (ch: CHARACTER)
 843         -- Extend `Current' (using `extend') with `ch' unless `ch'
 844         -- already the `last' character.
 845      do
 846         if count = 0 or else item(count) /= ch then
 847            add_last(ch)
 848         end
 849      ensure
 850         last = ch
 851         count >= old count
 852      end
 853
 854   intern: FIXED_STRING
 855         -- A shared version of this string.
 856      local
 857         strings: FAST_ARRAY[FIXED_STRING]
 858         i: INTEGER
 859      do
 860         strings := interned.reference_at(hash_code)
 861         if strings = Void then
 862            create strings.with_capacity(4)
 863            interned.add(strings, hash_code)
 864         end
 865         from
 866            i := strings.lower
 867         until
 868            Result /= Void or else i > strings.upper
 869         loop
 870            if strings.item(i).same_as(Current) then
 871               Result := strings.item(i)
 872            end
 873            i := i + 1
 874         end
 875         if Result = Void then
 876            create Result.make_from_string(Current)
 877            Result.do_intern(strings)
 878         end
 879      end
 880
 881feature {ANY} -- Interfacing with C string:
 882   to_external: POINTER
 883         -- Gives C access to the internal `storage' (may be dangerous).
 884         -- To be compatible with C, a null character is added at the end
 885         -- of the internal `storage'. This extra null character is not
 886         -- part of the Eiffel STRING.
 887      do
 888         if count + storage_lower = capacity then
 889            add_last('%U')
 890            count := count - 1
 891         elseif storage.item(count + storage_lower) /= '%U' then
 892            storage.put('%U', count + storage_lower)
 893         end
 894         Result := storage.to_pointer + storage_lower
 895      end
 896
 897   from_external (p: POINTER)
 898         -- Internal `storage' is set using `p' (may be dangerous because
 899         -- the external C string `p' is not duplicated). Assume `p' has a
 900         -- null character at the end in order to compute the Eiffel
 901         -- `count'. This extra null character is not part of the Eiffel
 902         -- STRING. Also consider `from_external_copy' to choose the most
 903         -- appropriate.
 904      require
 905         p.is_not_null
 906      do
 907         storage_lower := 0
 908         from
 909            storage := storage.from_pointer(p)
 910            count := 0
 911         until
 912            storage.item(count) = '%U'
 913         loop
 914            count := count + 1
 915         end
 916         capacity := count + 1
 917         if storage_signature_count > 0 then
 918            has_storage_signature := False
 919         end
 920         next_generation
 921      ensure
 922         capacity = count + 1
 923         p = to_external
 924      end
 925
 926   from_external_copy (p: POINTER)
 927         -- Internal `storage' is set using a copy of `p'. Assume `p' has a
 928         -- null character at the end in order to compute the Eiffel
 929         -- `count'. This extra null character is not part of the Eiffel
 930         -- STRING. Also consider `from_external' to choose the most
 931         -- appropriate.
 932      require
 933         p.is_not_null
 934      local
 935         s: like storage; i: INTEGER
 936      do
 937         storage_lower := 0
 938         from
 939            s := s.from_pointer(p)
 940            count := 0
 941         until
 942            s.item(i) = '%U'
 943         loop
 944            add_last(s.item(i))
 945            i := i + 1
 946         end
 947         next_generation
 948      end
 949
 950   from_external_sized (p: POINTER; size: INTEGER)
 951         -- Internal `storage' is set using `p' (may be dangerous because
 952         -- the external C string `p' is not duplicated). The 'count' of
 953         -- characters of the string is set to 'size'.
 954         -- Also consider `from_external_sized_copy' to choose the most
 955         -- appropriate.
 956      require
 957         p.is_not_null
 958         size >= 0
 959      do
 960         storage_lower := 0
 961         storage := storage.from_pointer(p)
 962         count := size
 963         capacity := size
 964         if storage_signature_count > 0 then
 965            has_storage_signature := False
 966         end
 967         next_generation
 968      ensure
 969         count = size
 970         capacity = size
 971         p = storage.to_pointer -- caution: to_external will add a trailing null
 972      end
 973
 974   from_external_sized_copy (p: POINTER; size: INTEGER)
 975         -- Internal `storage' is set using a copy of `p'.
 976         -- 'size' characters are copied, setting then 'count' to 'size'.
 977         -- Also consider `from_external' to choose the most appropriate.
 978      require
 979         p.is_not_null
 980         size >= 0
 981      local
 982         s: like storage
 983      do
 984         storage_lower := 0
 985         from
 986            ensure_capacity(size)
 987            s := s.from_pointer(p)
 988            count := 0
 989         until
 990            count = size
 991         loop
 992            storage.put(s.item(count), count)
 993            count := count + 1
 994         end
 995         next_generation
 996      ensure
 997         count = size
 998      end
 999
1000feature {RECYCLING_POOL, STRING_RECYCLING_POOL}
1001   recycle
1002      do
1003         clear_count
1004      end
1005
1006feature {}
1007   slice_copy (at: INTEGER; source: ABSTRACT_STRING; start_index, end_index: INTEGER)
1008      do
1009         if end_index >= start_index then
1010            source.copy_slice_to_native(start_index, end_index, storage, at + storage_lower)
1011         end
1012      end
1013
1014invariant
1015   0 <= count
1016   count <= capacity
1017   capacity > 0 implies storage.is_not_null
1018   storage_lower >= 0
1019
1020end -- class STRING
1021--
1022-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
1023--
1024-- Permission is hereby granted, free of charge, to any person obtaining a copy
1025-- of this software and associated documentation files (the "Software"), to deal
1026-- in the Software without restriction, including without limitation the rights
1027-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1028-- copies of the Software, and to permit persons to whom the Software is
1029-- furnished to do so, subject to the following conditions:
1030--
1031-- The above copyright notice and this permission notice shall be included in
1032-- all copies or substantial portions of the Software.
1033--
1034-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1035-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1036-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1037-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1038-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1039-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1040-- THE SOFTWARE.