/[eiffelstudio]/FreeELKS/trunk/library/kernel/string.e
ViewVC logotype

Contents of /FreeELKS/trunk/library/kernel/string.e

Parent Directory Parent Directory | Revision Log Revision Log


Revision 91424 - (show annotations)
Tue Oct 26 18:39:32 2004 UTC (15 years, 3 months ago) by manus_eiffel
File size: 55463 byte(s)
Initial revision

1 indexing
2
3 description: "[
4 Sequences of characters, accessible through integer indices
5 in a contiguous range.
6 ]"
7
8 status: "See notice at end of class"
9 date: "$Date$"
10 revision: "$Revision$"
11
12 class STRING inherit
13
14 INDEXABLE [CHARACTER, INTEGER]
15 redefine
16 copy, is_equal, out, prune_all,
17 changeable_comparison_criterion
18 end
19
20 RESIZABLE [CHARACTER]
21 redefine
22 copy, is_equal, out,
23 changeable_comparison_criterion
24 end
25
26 HASHABLE
27 redefine
28 copy, is_equal, out
29 end
30
31 COMPARABLE
32 redefine
33 copy, is_equal, out
34 end
35
36 TO_SPECIAL [CHARACTER]
37 redefine
38 copy, is_equal, out,
39 item, infix "@", put, valid_index
40 end
41
42 STRING_HANDLER
43 redefine
44 copy, is_equal, out
45 end
46
47 MISMATCH_CORRECTOR
48 redefine
49 copy, is_equal, out, correct_mismatch
50 end
51
52 create
53 make,
54 make_empty,
55 make_filled,
56 make_from_string,
57 make_from_c
58
59 feature -- Initialization
60
61 make (n: INTEGER) is
62 -- Allocate space for at least `n' characters.
63 require
64 non_negative_size: n >= 0
65 do
66 count := 0
67 internal_hash_code := 0
68 if n = 0 then
69 area := empty_area
70 else
71 make_area (n + 1)
72 end
73 ensure
74 empty_string: count = 0
75 area_allocated: capacity >= n
76 end
77
78 make_empty is
79 -- Create empty string.
80 do
81 make (0)
82 ensure
83 empty: count = 0
84 area_allocated: capacity >= 0
85 end
86
87 make_filled (c: CHARACTER; n: INTEGER) is
88 -- Create string of length `n' filled with `c'.
89 require
90 valid_count: n >= 0
91 do
92 make (n)
93 fill_character (c)
94 ensure
95 count_set: count = n
96 area_allocated: capacity >= n
97 filled: occurrences (c) = count
98 end
99
100 make_from_string (s: STRING) is
101 -- Initialize from the characters of `s'.
102 -- (Useful in proper descendants of class STRING,
103 -- to initialize a string-like object from a manifest string.)
104 require
105 string_exists: s /= Void
106 do
107 if Current /= s then
108 area := s.area.twin
109 count := s.count
110 internal_hash_code := 0
111 end
112 ensure
113 not_shared_implementation: Current /= s implies not shared_with (s)
114 initialized: same_string (s)
115 end
116
117 make_from_c (c_string: POINTER) is
118 -- Initialize from contents of `c_string',
119 -- a string created by some external C function
120 require
121 c_string_exists: c_string /= default_pointer
122 local
123 length: INTEGER
124 do
125 length := str_len (c_string)
126 make_area (length + 1)
127 area.base_address.memory_copy (c_string, length)
128 count := length
129 internal_hash_code := 0
130 end
131
132 from_c (c_string: POINTER) is
133 -- Reset contents of string from contents of `c_string',
134 -- a string created by some external C function.
135 require
136 c_string_exists: c_string /= default_pointer
137 local
138 length: INTEGER
139 do
140 length := str_len (c_string)
141 if safe_capacity < length then
142 make_area (length + 1)
143 end
144 area.base_address.memory_copy (c_string, length)
145 count := length
146 internal_hash_code := 0
147 ensure
148 no_zero_byte: not has ('%/0/')
149 -- characters: for all i in 1..count, item (i) equals
150 -- ASCII character at address c_string + (i - 1)
151 -- correct_count: the ASCII character at address c_string + count
152 -- is NULL
153 end
154
155 from_c_substring (c_string: POINTER; start_pos, end_pos: INTEGER) is
156 -- Reset contents of string from substring of `c_string',
157 -- a string created by some external C function.
158 require
159 c_string_exists: c_string /= default_pointer
160 start_position_big_enough: start_pos >= 1
161 end_position_big_enough: start_pos <= end_pos + 1
162 local
163 length: INTEGER
164 do
165 length := end_pos - start_pos + 1
166 if safe_capacity < length then
167 make_area (length + 1)
168 end
169 -- Make `area' the substring of `c_string'
170 -- from `start_pos' .. `end_pos'.
171 area.base_address.memory_copy (c_string + (start_pos - 1), end_pos - start_pos + 1)
172 count := length
173 internal_hash_code := 0
174 ensure
175 valid_count: count = end_pos - start_pos + 1
176 -- characters: for all i in 1..count, item (i) equals
177 -- ASCII character at address c_string + (i - 1)
178 end
179
180 adapt (s: STRING): like Current is
181 -- Object of a type conforming to the type of `s',
182 -- initialized with attributes from `s'
183 do
184 Result := new_string (0)
185 Result.share (s)
186 end
187
188 remake (n: INTEGER) is
189 -- Allocate space for at least `n' characters.
190 obsolete
191 "Use `make' instead"
192 require
193 non_negative_size: n >= 0
194 do
195 make (n)
196 ensure
197 empty_string: count = 0
198 area_allocated: capacity >= n
199 end
200
201 feature -- Access
202
203 item, infix "@" (i: INTEGER): CHARACTER is
204 -- Character at position `i'
205 do
206 Result := area.item (i - 1)
207 end
208
209 item_code (i: INTEGER): INTEGER is
210 -- Numeric code of character at position `i'
211 require
212 index_small_enough: i <= count
213 index_large_enough: i > 0
214 do
215 Result := area.item (i - 1).code
216 end
217
218 hash_code: INTEGER is
219 -- Hash code value
220 do
221 Result := internal_hash_code
222 if Result = 0 then
223 Result := hashcode ($area, count)
224 internal_hash_code := Result
225 end
226 end
227
228 false_constant: STRING is "false"
229 -- Constant string "false"
230
231 true_constant: STRING is "true"
232 -- Constant string "true"
233
234 shared_with (other: STRING): BOOLEAN is
235 -- Does string share the text of `other'?
236 do
237 Result := (other /= Void) and then (area = other.area)
238 end
239
240 index_of (c: CHARACTER; start_index: INTEGER): INTEGER is
241 -- Position of first occurrence of `c' at or after `start_index';
242 -- 0 if none.
243 require
244 start_large_enough: start_index >= 1
245 start_small_enough: start_index <= count + 1
246 local
247 a: like area
248 i, nb: INTEGER
249 do
250 nb := count
251 if start_index <= nb then
252 from
253 i := start_index - 1
254 nb := nb - 1
255 a := area
256 until
257 i > nb or else a.item (i) = c
258 loop
259 i := i + 1
260 end
261 if i <= nb then
262 -- We add +1 due to the area starting at 0 and not at 1.
263 Result := i + 1
264 end
265 end
266 ensure
267 valid_result: Result = 0 or (start_index <= Result and Result <= count)
268 zero_if_absent: (Result = 0) = not substring (start_index, count).has (c)
269 found_if_present: substring (start_index, count).has (c) implies item (Result) = c
270 none_before: substring (start_index, count).has (c) implies
271 not substring (start_index, Result - 1).has (c)
272 end
273
274 last_index_of (c: CHARACTER; start_index_from_end: INTEGER): INTEGER is
275 -- Position of last occurrence of `c'.
276 -- 0 if none
277 require
278 start_index_small_enough: start_index_from_end <= count
279 start_index_large_enough: start_index_from_end >= 1
280 local
281 a: like area
282 i: INTEGER
283 do
284 from
285 i := start_index_from_end - 1
286 a := area
287 until
288 i < 0 or else a.item (i) = c
289 loop
290 i := i - 1
291 end
292 -- We add +1 due to the area starting at 0 and not at 1.
293 Result := i + 1
294 ensure
295 last_index_of_non_negative: Result >= 0
296 correct_place: Result > 0 implies item (Result) = c
297 -- forall x : Result..last, item (x) /= c
298 end
299
300 substring_index_in_bounds (other: STRING; start_pos, end_pos: INTEGER): INTEGER is
301 -- Position of first occurrence of `other' at or after `start_pos'
302 -- and to or before `end_pos';
303 -- 0 if none.
304 require
305 other_nonvoid: other /= Void
306 other_notempty: not other.is_empty
307 start_pos_large_enough: start_pos >= 1
308 start_pos_small_enough: start_pos <= count
309 end_pos_large_enough: end_pos >= start_pos
310 end_pos_small_enough: end_pos <= count
311 local
312 a: ANY
313 do
314 a := other.area
315 Result := str_str ($area, $a, end_pos, other.count, start_pos, 0)
316 ensure
317 correct_place: Result > 0 implies
318 other.is_equal (substring (Result, Result + other.count - 1))
319 -- forall x : start_pos..Result
320 -- not substring (x, x+other.count -1).is_equal (other)
321 end
322
323 string: STRING is
324 -- New STRING having same character sequence as `Current'.
325 do
326 create Result.make (count)
327 Result.append (Current)
328 ensure
329 string_not_void: Result /= Void
330 string_type: Result.same_type ("")
331 first_item: count > 0 implies Result.item (1) = item (1)
332 recurse: count > 1 implies Result.substring (2, count).is_equal (
333 substring (2, count).string)
334 end
335
336 substring_index (other: STRING; start_index: INTEGER): INTEGER is
337 -- Index of first occurrence of other at or after start_index;
338 -- 0 if none
339 require
340 other_not_void: other /= Void
341 valid_start_index: start_index >= 1 and start_index <= count + 1
342 local
343 a: ANY
344 l_other_count: INTEGER
345 do
346 if other = Current then
347 if start_index = 1 then
348 Result := 1
349 end
350 else
351 l_other_count := other.count
352 if l_other_count = 0 then
353 Result := start_index
354 elseif start_index <= (count - l_other_count + 1) then
355 a := other.area
356 Result := str_str ($area, $a, count, l_other_count, start_index, 0)
357 end
358 end
359 ensure
360 valid_result: Result = 0 or else
361 (start_index <= Result and Result <= count - other.count + 1)
362 zero_if_absent: (Result = 0) =
363 not substring (start_index, count).has_substring (other)
364 at_this_index: Result >= start_index implies
365 other.same_string (substring (Result, Result + other.count - 1))
366 none_before: Result > start_index implies
367 not substring (start_index, Result + other.count - 2).has_substring (other)
368 end
369
370 fuzzy_index (other: STRING; start: INTEGER; fuzz: INTEGER): INTEGER is
371 -- Position of first occurrence of `other' at or after `start'
372 -- with 0..`fuzz' mismatches between the string and `other'.
373 -- 0 if there are no fuzzy matches
374 require
375 other_exists: other /= Void
376 other_not_empty: not other.is_empty
377 start_large_enough: start >= 1
378 start_small_enough: start <= count
379 acceptable_fuzzy: fuzz <= other.count
380 local
381 a: ANY
382 do
383 a := other.area
384 Result := str_str ($area, $a, count, other.count, start, fuzz)
385 end
386
387 feature -- Measurement
388
389 capacity: INTEGER is
390 -- Allocated space
391 do
392 if area /= Void then
393 Result := safe_capacity
394 end
395 end
396
397 count: INTEGER
398 -- Actual number of characters making up the string
399
400 occurrences (c: CHARACTER): INTEGER is
401 -- Number of times `c' appears in the string
402 local
403 counter, nb: INTEGER
404 a: SPECIAL [CHARACTER]
405 do
406 from
407 counter := 0
408 nb := count - 1
409 a := area
410 until
411 counter > nb
412 loop
413 if a.item (counter) = c then
414 Result := Result + 1
415 end
416 counter := counter + 1
417 end
418 ensure then
419 zero_if_empty: count = 0 implies Result = 0
420 recurse_if_not_found_at_first_position:
421 (count > 0 and then item (1) /= c) implies
422 Result = substring (2, count).occurrences (c)
423 recurse_if_found_at_first_position:
424 (count > 0 and then item (1) = c) implies
425 Result = 1 + substring (2, count).occurrences (c)
426 end
427
428 index_set: INTEGER_INTERVAL is
429 -- Range of acceptable indexes
430 do
431 create Result.make (1, count)
432 ensure then
433 Result.count = count
434 end
435
436 feature -- Comparison
437
438 is_equal (other: like Current): BOOLEAN is
439 -- Is string made of same character sequence as `other'
440 -- (possibly with a different capacity)?
441 local
442 o_area: like area
443 do
444 if other = Current then
445 Result := True
446 elseif count = other.count then
447 o_area := other.area
448 Result := str_strict_cmp ($area, $o_area, count) = 0
449 end
450 end
451
452 same_string (other: STRING): BOOLEAN is
453 -- Do `Current' and `other' have same character sequence?
454 require
455 other_not_void: other /= Void
456 local
457 i, nb: INTEGER
458 l_area, l_other_area: like area
459 do
460 if other = Current then
461 Result := True
462 elseif other.count = count then
463 from
464 i := 0
465 nb := count - 1
466 l_area := area
467 l_other_area := other.area
468 Result := True
469 until
470 i > nb or not Result
471 loop
472 Result := l_area.item (i) = l_other_area.item (i)
473 i := i + 1
474 end
475 end
476 ensure
477 definition: Result = string.is_equal (other.string)
478 end
479
480 infix "<" (other: like Current): BOOLEAN is
481 -- Is string lexicographically lower than `other'?
482 local
483 other_area: like area
484 other_count: INTEGER
485 current_count: INTEGER
486 do
487 if other /= Current then
488 other_area := other.area
489 other_count := other.count
490 current_count := count
491 if other_count = current_count then
492 Result := str_strict_cmp ($other_area, $area, other_count) > 0
493 else
494 if current_count < other_count then
495 Result := str_strict_cmp ($other_area, $area, current_count) >= 0
496 else
497 Result := str_strict_cmp ($other_area, $area, other_count) > 0
498 end
499 end
500 end
501 end
502
503 feature -- Status report
504
505 has (c: CHARACTER): BOOLEAN is
506 -- Does string include `c'?
507 local
508 counter: INTEGER
509 do
510 if not is_empty then
511 from
512 counter := 1
513 until
514 counter > count or else (item (counter) = c)
515 loop
516 counter := counter + 1
517 end
518 Result := (counter <= count)
519 end
520 ensure then
521 false_if_empty: count = 0 implies not Result
522 true_if_first: count > 0 and then item (1) = c implies Result
523 recurse: (count > 0 and then item (1) /= c) implies
524 (Result = substring (2, count).has (c))
525 end
526
527 has_substring (other: STRING): BOOLEAN is
528 -- Does `Current' contain `other'?
529 require
530 other_not_void: other /= Void
531 do
532 if other = Current then
533 Result := True
534 elseif other.count <= count then
535 Result := substring_index (other, 1) > 0
536 end
537 ensure
538 false_if_too_small: count < other.count implies not Result
539 true_if_initial: (count >= other.count and then
540 other.same_string (substring (1, other.count))) implies Result
541 recurse: (count >= other.count and then
542 not other.same_string (substring (1, other.count))) implies
543 (Result = substring (2, count).has_substring (other))
544 end
545
546 extendible: BOOLEAN is True
547 -- May new items be added? (Answer: yes.)
548
549 prunable: BOOLEAN is
550 -- May items be removed? (Answer: yes.)
551 do
552 Result := True
553 end
554
555 valid_index (i: INTEGER): BOOLEAN is
556 -- Is `i' within the bounds of the string?
557 do
558 Result := (i > 0) and (i <= count)
559 end
560
561 changeable_comparison_criterion: BOOLEAN is False
562
563 is_integer: BOOLEAN is
564 -- Does `Current' represent an INTEGER?
565 local
566 l_c: CHARACTER
567 l_area: like area
568 i, nb, l_state: INTEGER
569 do
570 -- l_state = 0 : waiting sign or first digit.
571 -- l_state = 1 : sign read, waiting first digit.
572 -- l_state = 2 : in the number.
573 -- l_state = 3 : trailing white spaces
574 -- l_state = 4 : error state.
575 from
576 l_area := area
577 i := 0
578 nb := count - 1
579 until
580 i > nb or l_state > 3
581 loop
582 l_c := l_area.item (i)
583 i := i + 1
584 inspect l_state
585 when 0 then
586 -- Let's find beginning of an integer, if any.
587 if l_c.is_digit then
588 l_state := 2
589 elseif l_c = '-' or l_c = '+' then
590 l_state := 1
591 elseif l_c = ' ' then
592 else
593 l_state := 4
594 end
595 when 1 then
596 -- Let's find first digit after sign.
597 if l_c.is_digit then
598 l_state := 2
599 else
600 l_state := 4
601 end
602 when 2 then
603 -- Let's find another digit or end of integer.
604 if l_c.is_digit then
605 elseif l_c = ' ' then
606 l_state := 3
607 else
608 l_state := 4
609 end
610 when 3 then
611 -- Consume remaining white space.
612 if l_c /= ' ' then
613 l_state := 4
614 end
615 end
616 end
617 Result := l_state = 2 or l_state = 3
618 ensure
619 syntax_and_range:
620 -- Result is true if and only if the following two
621 -- conditions are satisfied:
622 --
623 -- 1. In the following BNF grammar, the value of
624 -- Current can be produced by "Integer_literal":
625 --
626 -- Integer_literal = [Space] [Sign] Integer [Space]
627 -- Space = " " | " " Space
628 -- Sign = "+" | "-"
629 -- Integer = Digit | Digit Integer
630 -- Digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
631 --
632 -- 2. The integer value represented by Current
633 -- is within the range that can be represented
634 -- by an instance of type INTEGER.
635 end
636
637 is_real: BOOLEAN is
638 -- Does `Current' represent a REAL?
639 do
640 Result := str_isr ($area, count)
641 ensure
642 syntax_and_range:
643 -- 'result' is True if and only if the following two
644 -- conditions are satisfied:
645 --
646 -- 1. In the following BNF grammar, the value of
647 -- 'Current' can be produced by "Real_literal":
648 --
649 -- Real_literal = Mantissa [Exponent_part]
650 -- Exponent_part = "E" Exponent
651 -- | "e" Exponent
652 -- Exponent = Integer_literal
653 -- Mantissa = Decimal_literal
654 -- Decimal_literal = Integer_literal ["." Integer]
655 -- Integer_literal = [Sign] Integer
656 -- Sign = "+" | "-"
657 -- Integer = Digit | Digit Integer
658 -- Digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
659 --
660 -- 2. The numerical value represented by 'Current'
661 -- is within the range that can be represented
662 -- by an instance of type REAL.
663 end
664
665 is_double: BOOLEAN is
666 -- Does `Current' represent a DOUBLE?
667 do
668 Result := str_isd ($area, count)
669 ensure
670 syntax_and_range:
671 -- 'result' is True if and only if the following two
672 -- conditions are satisfied:
673 --
674 -- 1. In the following BNF grammar, the value of
675 -- 'Current' can be produced by "Real_literal":
676 --
677 -- Real_literal = Mantissa [Exponent_part]
678 -- Exponent_part = "E" Exponent
679 -- | "e" Exponent
680 -- Exponent = Integer_literal
681 -- Mantissa = Decimal_literal
682 -- Decimal_literal = Integer_literal ["." Integer]
683 -- Integer_literal = [Sign] Integer
684 -- Sign = "+" | "-"
685 -- Integer = Digit | Digit Integer
686 -- Digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
687 --
688 -- 2. The numerical value represented by 'Current'
689 -- is within the range that can be represented
690 -- by an instance of type DOUBLE.
691 end
692
693 is_boolean: BOOLEAN is
694 -- Does `Current' represent a BOOLEAN?
695 local
696 s: STRING
697 do
698 s := twin
699 s.right_adjust
700 s.left_adjust
701 s.to_lower
702 Result := s.is_equal (true_constant) or else s.is_equal (false_constant)
703 ensure
704 is_boolean: Result = (as_lower.has_substring (true_constant) or as_lower.has_substring (false_constant))
705 end
706
707 feature -- Element change
708
709 set (t: like Current; n1, n2: INTEGER) is
710 -- Set current string to substring of `t' from indices `n1'
711 -- to `n2', or to empty string if no such substring.
712 require
713 argument_not_void: t /= Void
714 local
715 s: STRING
716 do
717 s := t.substring (n1, n2)
718 area := s.area
719 count := s.count
720 internal_hash_code := 0
721 ensure
722 is_substring: is_equal (t.substring (n1, n2))
723 end
724
725 copy (other: like Current) is
726 -- Reinitialize by copying the characters of `other'.
727 -- (This is also used by `twin'.)
728 local
729 old_area: like area
730 do
731 if other /= Current then
732 old_area := area
733 standard_copy (other)
734 -- Note: <= is needed as all Eiffel string should have an
735 -- extra character to insert null character at the end.
736 if old_area = Void or else old_area.count <= count then
737 area := area.standard_twin
738 else
739 old_area.base_address.memory_copy ($area, count)
740 area := old_area
741 end
742 internal_hash_code := 0
743 end
744 ensure then
745 new_result_count: count = other.count
746 -- same_characters: For every `i' in 1..`count', `item' (`i') = `other'.`item' (`i')
747 end
748
749 subcopy (other: like Current; start_pos, end_pos, index_pos: INTEGER) is
750 -- Copy characters of `other' within bounds `start_pos' and
751 -- `end_pos' to current string starting at index `index_pos'.
752 require
753 other_not_void: other /= Void
754 valid_start_pos: other.valid_index (start_pos)
755 valid_end_pos: other.valid_index (end_pos)
756 valid_bounds: (start_pos <= end_pos) or (start_pos = end_pos + 1)
757 valid_index_pos: valid_index (index_pos)
758 enough_space: (count - index_pos) >= (end_pos - start_pos)
759 local
760 other_area: like area
761 start0, end0, index0: INTEGER
762 do
763 other_area := other.area
764 start0 := start_pos - 1
765 end0 := end_pos - 1
766 index0 := index_pos - 1
767 spsubcopy ($other_area, $area, start0, end0, index0)
768 internal_hash_code := 0
769 ensure
770 same_count: count = old count
771 copied: elks_checking implies
772 (is_equal (old substring (1, index_pos - 1) +
773 old other.substring (start_pos, end_pos) +
774 old substring (index_pos + (end_pos - start_pos + 1), count)))
775 end
776
777 replace_substring (s: STRING; start_index, end_index: INTEGER) is
778 -- Replace characters from `start_index' to `end_index' with `s'.
779 require
780 string_not_void: s /= Void
781 valid_start_index: 1 <= start_index
782 valid_end_index: end_index <= count
783 meaningfull_interval: start_index <= end_index + 1
784 local
785 new_size, substring_size: INTEGER
786 s_area: like area
787 do
788 substring_size := end_index - start_index + 1
789 new_size := s.count + count - substring_size
790 if new_size > safe_capacity then
791 resize (new_size + additional_space)
792 end
793 s_area := s.area
794 str_replace ($area, $s_area, count, s.count, start_index, end_index)
795 count := new_size
796 internal_hash_code := 0
797 ensure
798 new_count: count = old count + old s.count - end_index + start_index - 1
799 replaced: elks_checking implies
800 (is_equal (old (substring (1, start_index - 1) +
801 s + substring (end_index + 1, count))))
802 end
803
804 replace_substring_all (original, new: like Current) is
805 -- Replace every occurrence of `original' with `new'.
806 require
807 original_exists: original /= Void
808 new_exists: new /= Void
809 original_not_empty: not original.is_empty
810 local
811 change_pos: INTEGER
812 do
813 if not is_empty then
814 from
815 change_pos := substring_index (original, 1)
816 until
817 change_pos = 0
818 loop
819 replace_substring (new, change_pos, change_pos + original.count - 1)
820 if change_pos + new.count <= count then
821 change_pos := substring_index (original, change_pos + new.count)
822 else
823 change_pos := 0
824 end
825 end
826 internal_hash_code := 0
827 end
828 end
829
830 replace_blank is
831 -- Replace all current characters with blanks.
832 do
833 fill_with (' ')
834 ensure
835 same_size: (count = old count) and (capacity >= old capacity)
836 all_blank: elks_checking implies occurrences (' ') = count
837 end
838
839 fill_blank is
840 -- Fill with `capacity' blank characters.
841 do
842 fill_character (' ')
843 ensure
844 filled: full
845 same_size: (count = capacity) and (capacity = old capacity)
846 -- all_blank: For every `i' in `count'..`capacity', `item' (`i') = `Blank'
847 end
848
849 fill_with (c: CHARACTER) is
850 -- Replace every character with `c'.
851 do
852 area.base_address.memory_set (c.code, count)
853 internal_hash_code := 0
854 ensure
855 same_count: (count = old count) and (capacity >= old capacity)
856 filled: elks_checking implies occurrences (c) = count
857 end
858
859 replace_character (c: CHARACTER) is
860 -- Replace every character with `c'.
861 obsolete
862 "ELKS 2001: use `fill_with' instead'"
863 do
864 fill_with (c)
865 ensure
866 same_count: (count = old count) and (capacity >= old capacity)
867 filled: elks_checking implies occurrences (c) = count
868 end
869
870 fill_character (c: CHARACTER) is
871 -- Fill with `capacity' characters all equal to `c'.
872 local
873 l_cap: like safe_capacity
874 do
875 l_cap := safe_capacity
876 area.base_address.memory_set (c.code, l_cap)
877 count := l_cap
878 internal_hash_code := 0
879 ensure
880 filled: full
881 same_size: (count = capacity) and (capacity = old capacity)
882 -- all_char: For every `i' in 1..`capacity', `item' (`i') = `c'
883 end
884
885 head (n: INTEGER) is
886 -- Remove all characters except for the first `n';
887 -- do nothing if `n' >= `count'.
888 obsolete
889 "ELKS 2001: use `keep_head' instead'"
890 require
891 non_negative_argument: n >= 0
892 do
893 keep_head (n)
894 ensure
895 new_count: count = n.min (old count)
896 kept: elks_checking implies is_equal (old substring (1, n.min (count)))
897 end
898
899 keep_head (n: INTEGER) is
900 -- Remove all characters except for the first `n';
901 -- do nothing if `n' >= `count'.
902 require
903 non_negative_argument: n >= 0
904 do
905 if n < count then
906 count := n
907 internal_hash_code := 0
908 end
909 ensure
910 new_count: count = n.min (old count)
911 kept: elks_checking implies is_equal (old substring (1, n.min (count)))
912 end
913
914 tail (n: INTEGER) is
915 -- Remove all characters except for the last `n';
916 -- do nothing if `n' >= `count'.
917 obsolete
918 "ELKS 2001: use `keep_tail' instead'"
919 require
920 non_negative_argument: n >= 0
921 do
922 keep_tail (n)
923 ensure
924 new_count: count = n.min (old count)
925 kept: elks_checking implies is_equal (old substring (count - n.min(count) + 1, count))
926 end
927
928 keep_tail (n: INTEGER) is
929 -- Remove all characters except for the last `n';
930 -- do nothing if `n' >= `count'.
931 require
932 non_negative_argument: n >= 0
933 local
934 i, j: INTEGER
935 do
936 if n < count then
937 from
938 j := (count - n)
939 i := 0
940 until
941 i = n
942 loop
943 area.put (area.item (j), i)
944 i := i + 1
945 j := j + 1
946 end
947 count := n
948 internal_hash_code := 0
949 end
950 ensure
951 new_count: count = n.min (old count)
952 kept: elks_checking implies is_equal (old substring (count - n.min(count) + 1, count))
953 end
954
955 left_adjust is
956 -- Remove leading whitespace.
957 do
958 count := str_left ($area, count)
959 internal_hash_code := 0
960 ensure
961 valid_count: count <= old count
962 new_count: (count /= 0) implies
963 ((item (1) /= ' ') and
964 (item (1) /= '%T') and
965 (item (1) /= '%R') and
966 (item (1) /= '%N'))
967 kept: elks_checking implies is_equal ((old twin).substring (old count - count + 1, old count))
968 end
969
970 right_adjust is
971 -- Remove trailing whitespace.
972 do
973 count := str_right ($area, count)
974 internal_hash_code := 0
975 ensure
976 valid_count: count <= old count
977 new_count: (count /= 0) implies
978 ((item (count) /= ' ') and
979 (item (count) /= '%T') and
980 (item (count) /= '%R') and
981 (item (count) /= '%N'))
982 kept: elks_checking implies is_equal ((old twin).substring (1, count))
983 end
984
985 share (other: STRING) is
986 -- Make current string share the text of `other'.
987 -- Subsequent changes to the characters of current string
988 -- will also affect `other', and conversely.
989 require
990 argument_not_void: other /= Void
991 do
992 area := other.area
993 count := other.count
994 internal_hash_code := 0
995 ensure
996 shared_count: other.count = count
997 shared_area: other.area = area
998 end
999
1000 put (c: CHARACTER; i: INTEGER) is
1001 -- Replace character at position `i' by `c'.
1002 do
1003 area.put (c, i - 1)
1004 internal_hash_code := 0
1005 ensure then
1006 stable_count: count = old count
1007 stable_before_i: elks_checking implies substring (1, i - 1).is_equal (old substring (1, i - 1))
1008 stable_after_i: elks_checking implies substring (i + 1, count).is_equal (old substring (i + 1, count))
1009 end
1010
1011 precede, prepend_character (c: CHARACTER) is
1012 -- Add `c' at front.
1013 do
1014 if count = safe_capacity then
1015 resize (count + additional_space)
1016 end
1017 str_cprepend ($area, c, count)
1018 count := count + 1
1019 internal_hash_code := 0
1020 ensure
1021 new_count: count = old count + 1
1022 end
1023
1024 prepend (s: STRING) is
1025 -- Prepend a copy of `s' at front.
1026 require
1027 argument_not_void: s /= Void
1028 do
1029 insert_string (s, 1)
1030 ensure
1031 inserted: elks_checking implies is_equal (old (s.twin) + old substring (1, count))
1032 end
1033
1034 prepend_boolean (b: BOOLEAN) is
1035 -- Prepend the string representation of `b' at front.
1036 do
1037 prepend (b.out)
1038 end
1039
1040 prepend_double (d: DOUBLE) is
1041 -- Prepend the string representation of `d' at front.
1042 do
1043 prepend (d.out)
1044 end
1045
1046 prepend_integer (i: INTEGER) is
1047 -- Prepend the string representation of `i' at front.
1048 do
1049 prepend (i.out)
1050 end
1051
1052 prepend_real (r: REAL) is
1053 -- Prepend the string representation of `r' at front.
1054 do
1055 prepend (r.out)
1056 end
1057
1058 prepend_string (s: STRING) is
1059 -- Prepend a copy of `s', if not void, at front.
1060 do
1061 if s /= Void then
1062 prepend (s)
1063 end
1064 end
1065
1066 append (s: STRING) is
1067 -- Append a copy of `s' at end.
1068 require
1069 argument_not_void: s /= Void
1070 local
1071 new_size: INTEGER
1072 s_area: like area
1073 do
1074 new_size := s.count + count
1075 if new_size > safe_capacity then
1076 resize (new_size + additional_space)
1077 end
1078 s_area := s.area;
1079 area.item_address (count).memory_copy ($s_area, s.count)
1080 count := new_size
1081 internal_hash_code := 0
1082 ensure
1083 new_count: count = old count + old s.count
1084 appended: elks_checking implies is_equal (old twin + old s.twin)
1085 end
1086
1087 infix "+" (s: STRING): like Current is
1088 -- Append a copy of 's' at the end of a copy of Current,
1089 -- Then return the Result.
1090 require
1091 argument_not_void: s /= Void
1092 do
1093 Result := new_string (count + s.count)
1094 Result.append_string (Current)
1095 Result.append_string (s)
1096 ensure
1097 Result_exists: Result /= Void
1098 new_count: Result.count = count + s.count
1099 initial: elks_checking implies Result.substring (1, count).is_equal (Current)
1100 final: elks_checking implies Result.substring (count + 1, count + s.count).same_string (s)
1101 end
1102
1103 append_string (s: STRING) is
1104 -- Append a copy of `s', if not void, at end.
1105 do
1106 if s /= Void then
1107 append (s)
1108 end
1109 ensure
1110 appended: s /= Void implies
1111 (elks_checking implies is_equal (old twin + old s.twin))
1112 end
1113
1114 append_integer (i: INTEGER) is
1115 -- Append the string representation of `i' at end.
1116 local
1117 l_value: INTEGER
1118 l_starting_index, l_ending_index: INTEGER
1119 l_temp: CHARACTER
1120 l_area: like area
1121 do
1122 if i = 0 then
1123 append_character ('0')
1124 else
1125 -- Extract integer value digit by digit from right to left.
1126 from
1127 l_starting_index := count
1128 if i < 0 then
1129 append_character ('-')
1130 l_starting_index := l_starting_index + 1
1131 l_value := -i
1132 -- Special case for minimum integer value as negating it
1133 -- as no effect.
1134 if l_value = feature {INTEGER_REF}.Min_value then
1135 append_character ((-(l_value \\ 10) + 48).to_character)
1136 l_value := -(l_value // 10)
1137 end
1138 else
1139 l_value := i
1140 end
1141 until
1142 l_value = 0
1143 loop
1144 append_character (((l_value \\ 10)+ 48).to_character)
1145 l_value := l_value // 10
1146 end
1147
1148 -- Now put digits in correct order from left to right.
1149 from
1150 l_ending_index := count - 1
1151 l_area := area
1152 until
1153 l_starting_index >= l_ending_index
1154 loop
1155 l_temp := l_area.item (l_starting_index)
1156 l_area.put (l_area.item (l_ending_index), l_starting_index)
1157 l_area.put (l_temp, l_ending_index)
1158 l_ending_index := l_ending_index - 1
1159 l_starting_index := l_starting_index + 1
1160 end
1161 end
1162 end
1163
1164 append_real (r: REAL) is
1165 -- Append the string representation of `r' at end.
1166 do
1167 append (r.out)
1168 end
1169
1170 append_double (d: DOUBLE) is
1171 -- Append the string representation of `d' at end.
1172 do
1173 append (d.out)
1174 end
1175
1176 append_character, extend (c: CHARACTER) is
1177 -- Append `c' at end.
1178 local
1179 current_count: INTEGER
1180 do
1181 current_count := count
1182 if current_count = safe_capacity then
1183 resize (current_count + additional_space)
1184 end
1185 area.put (c, current_count)
1186 count := current_count + 1
1187 internal_hash_code := 0
1188 ensure then
1189 item_inserted: item (count) = c
1190 new_count: count = old count + 1
1191 stable_before: elks_checking implies substring (1, count - 1).is_equal (old twin)
1192 end
1193
1194 append_boolean (b: BOOLEAN) is
1195 -- Append the string representation of `b' at end.
1196 do
1197 append (b.out)
1198 end
1199
1200 insert (s: STRING; i: INTEGER) is
1201 -- Add `s' to left of position `i' in current string.
1202 obsolete
1203 "ELKS 2001: use `insert_string' instead"
1204 require
1205 string_exists: s /= Void
1206 index_small_enough: i <= count + 1
1207 index_large_enough: i > 0
1208 do
1209 insert_string (s, i)
1210 ensure
1211 inserted: elks_checking implies
1212 (is_equal (old substring (1, i - 1) + old (s.twin) + old substring (i, count)))
1213 end
1214
1215 insert_string (s: STRING; i: INTEGER) is
1216 -- Insert `s' at index `i', shifting characters between ranks
1217 -- `i' and `count' rightwards.
1218 require
1219 string_exists: s /= Void
1220 valid_insertion_index: 1 <= i and i <= count + 1
1221 local
1222 j, nb, pos, new_size: INTEGER
1223 l_s_count: INTEGER
1224 l_area, s_area: like area
1225 do
1226 -- Resize Current if necessary.
1227 l_s_count := s.count
1228 new_size := l_s_count + count
1229 if new_size > safe_capacity then
1230 resize (new_size + additional_space)
1231 end
1232
1233 -- Perform all operations using a zero based arrays.
1234 l_area := area
1235 s_area := s.area
1236 pos := i - 1
1237
1238 -- First shift from `s.count' position all characters starting at index `pos'.
1239 from
1240 j := count - 1
1241 until
1242 j < pos
1243 loop
1244 l_area.put (l_area.item (j), j + l_s_count)
1245 j := j - 1
1246 end
1247
1248 -- Copy string `s' at index `pos'.
1249 if l_area /= s_area then
1250 -- Normal copy as there is no overlap between `other' and `Current'.
1251 from
1252 j := 0
1253 nb := l_s_count - 1
1254 until
1255 j > nb
1256 loop
1257 l_area.put (s_area.item (j), j + pos)
1258 j := j + 1
1259 end
1260 else
1261 -- We have an overlap between `s' and `Current'. Since now Current
1262 -- is made of `low' + `empty' + `upper' part, we need to copy
1263 -- the `low' part at the beginning of `empty' and the `upper' part
1264 -- at the end of `empty'.
1265
1266 -- First copy characters of Current from low part `0..pos - 1' to
1267 -- `pos .. pos + pos - 1'.
1268 from
1269 j := 0
1270 nb := pos - 1
1271 until
1272 j > nb
1273 loop
1274 l_area.put (l_area.item (j), j + pos)
1275 j := j + 1
1276 end
1277
1278 -- Then copy characters of Current from upper part
1279 -- `pos + l_s_count .. new_size - 1' to `pos + pos .. pos + l_s_count - 1'.
1280 from
1281 j := pos + pos
1282 nb := pos + l_s_count - 1
1283 until
1284 j > nb
1285 loop
1286 l_area.put (l_area.item (j + l_s_count - pos), j)
1287 j := j + 1
1288 end
1289 end
1290 count := new_size
1291 internal_hash_code := 0
1292 ensure
1293 inserted: elks_checking implies
1294 (is_equal (old substring (1, i - 1) + old (s.twin) + old substring (i, count)))
1295 end
1296
1297 insert_character (c: CHARACTER; i: INTEGER) is
1298 -- Insert `c' at index `i', shifting characters between ranks
1299 -- `i' and `count' rightwards.
1300 require
1301 valid_insertion_index: 1 <= i and i <= count + 1
1302 local
1303 j, pos, new_size: INTEGER
1304 l_area: like area
1305 do
1306 -- Resize Current if necessary.
1307 new_size := 1 + count
1308 if new_size > safe_capacity then
1309 resize (new_size + additional_space)
1310 end
1311
1312 -- Perform all operations using a zero based arrays.
1313 l_area := area
1314 pos := i - 1
1315
1316 -- First shift from `s.count' position all characters starting at index `pos'.
1317 from
1318 j := count - 1
1319 until
1320 j < pos
1321 loop
1322 l_area.put (l_area.item (j), j + 1)
1323 j := j - 1
1324 end
1325
1326 -- Insert new character
1327 l_area.put (c, pos)
1328
1329 count := new_size
1330 internal_hash_code := 0
1331 ensure
1332 one_more_character: count = old count + 1
1333 inserted: item (i) = c
1334 stable_before_i: elks_checking implies substring (1, i - 1).is_equal (old substring (1, i - 1))
1335 stable_after_i: elks_checking implies substring (i + 1, count).is_equal (old substring (i, count))
1336 end
1337
1338 feature -- Removal
1339
1340 remove (i: INTEGER) is
1341 -- Remove `i'-th character.
1342 require
1343 index_small_enough: i <= count
1344 index_large_enough: i > 0
1345 do
1346 str_rmchar ($area, count, i)
1347 count := count - 1
1348 internal_hash_code := 0
1349 ensure
1350 new_count: count = old count - 1
1351 removed: elks_checking implies is_equal (old substring (1, i - 1) + old substring (i + 1, count))
1352 end
1353
1354 remove_head (n: INTEGER) is
1355 -- Remove first `n' characters;
1356 -- if `n' > `count', remove all.
1357 require
1358 n_non_negative: n >= 0
1359 do
1360 if n > count then
1361 count := 0
1362 internal_hash_code := 0
1363 else
1364 keep_tail (count - n)
1365 end
1366 ensure
1367 removed: elks_checking implies is_equal (old substring (n.min (count) + 1, count))
1368 end
1369
1370 remove_substring (start_index, end_index: INTEGER) is
1371 -- Remove all characters from `start_index'
1372 -- to `end_index' inclusive.
1373 require
1374 valid_start_index: 1 <= start_index
1375 valid_end_index: end_index <= count
1376 meaningful_interval: start_index <= end_index + 1
1377 local
1378 i: INTEGER
1379 do
1380 from
1381 i := 0
1382 until
1383 i > end_index - start_index
1384 loop
1385 remove (start_index)
1386 i := i + 1
1387 end
1388 ensure
1389 removed: elks_checking implies
1390 is_equal (old substring (1, start_index - 1) + old substring (end_index + 1, count))
1391 end
1392
1393 remove_tail (n: INTEGER) is
1394 -- Remove last `n' characters;
1395 -- if `n' > `count', remove all.
1396 require
1397 n_non_negative: n >= 0
1398 local
1399 l_count: INTEGER
1400 do
1401 l_count := count
1402 if n > l_count then
1403 count := 0
1404 internal_hash_code := 0
1405 else
1406 keep_head (l_count - n)
1407 end
1408 ensure
1409 removed: elks_checking implies is_equal (old substring (1, count - n.min (count)))
1410 end
1411
1412 prune (c: CHARACTER) is
1413 -- Remove first occurrence of `c', if any.
1414 require else
1415 True
1416 local
1417 counter: INTEGER
1418 do
1419 from
1420 counter := 1
1421 until
1422 counter > count or else (item (counter) = c)
1423 loop
1424 counter := counter + 1
1425 end
1426 if counter <= count then
1427 remove (counter)
1428 end
1429 end
1430
1431 prune_all (c: CHARACTER) is
1432 -- Remove all occurrences of `c'.
1433 require else
1434 True
1435 do
1436 count := str_rmall ($area, c, count)
1437 internal_hash_code := 0
1438 ensure then
1439 changed_count: count = (old count) - (old occurrences (c))
1440 -- removed: For every `i' in 1..`count', `item' (`i') /= `c'
1441 end
1442
1443 prune_all_leading (c: CHARACTER) is
1444 -- Remove all leading occurrences of `c'.
1445 do
1446 from
1447 until
1448 is_empty or else item (1) /= c
1449 loop
1450 remove (1)
1451 end
1452 end
1453
1454 prune_all_trailing (c: CHARACTER) is
1455 -- Remove all trailing occurrences of `c'.
1456 do
1457 from
1458 until
1459 is_empty or else item (count) /= c
1460 loop
1461 remove (count)
1462 end
1463 end
1464
1465 wipe_out is
1466 -- Remove all characters.
1467 do
1468 area := empty_area
1469 count := 0
1470 internal_hash_code := 0
1471 ensure then
1472 is_empty: count = 0
1473 empty_capacity: capacity = 0
1474 end
1475
1476 clear_all is
1477 -- Reset all characters.
1478 do
1479 count := 0
1480 internal_hash_code := 0
1481 ensure
1482 is_empty: count = 0
1483 same_capacity: capacity = old capacity
1484 end
1485
1486 feature -- Resizing
1487
1488 adapt_size is
1489 -- Adapt the size to accommodate `count' characters.
1490 do
1491 resize (count)
1492 end
1493
1494 resize (newsize: INTEGER) is
1495 -- Rearrange string so that it can accommodate
1496 -- at least `newsize' characters.
1497 -- Do not lose any previously entered character.
1498 require
1499 new_size_non_negative: newsize >= 0
1500 local
1501 area_count: INTEGER
1502 do
1503 area_count := area.count
1504 if newsize >= area_count then
1505 if area_count = 1 then
1506 make_area (newsize + 1)
1507 else
1508 area := str_resize ($area, newsize + 1)
1509 end
1510 end
1511 end
1512
1513 grow (newsize: INTEGER) is
1514 -- Ensure that the capacity is at least `newsize'.
1515 require else
1516 new_size_non_negative: newsize >= 0
1517 do
1518 if newsize > safe_capacity then
1519 resize (newsize)
1520 end
1521 end
1522
1523 feature -- Conversion
1524
1525 as_lower: like Current is
1526 -- New object with all letters in lower case.
1527 do
1528 Result := twin
1529 Result.to_lower
1530 ensure
1531 length: Result.count = count
1532 anchor: count > 0 implies Result.item (1) = item (1).as_lower
1533 recurse: count > 1 implies Result.substring (2, count).
1534 is_equal (substring (2, count).as_lower)
1535 end
1536
1537 as_upper: like Current is
1538 -- New object with all letters in upper case
1539 do
1540 Result := twin
1541 Result.to_upper
1542 ensure
1543 length: Result.count = count
1544 anchor: count > 0 implies Result.item (1) = item (1).as_upper
1545 recurse: count > 1 implies Result.substring (2, count).
1546 is_equal (substring (2, count).as_upper)
1547 end
1548
1549 left_justify is
1550 -- Left justify the string using
1551 -- the capacity as the width
1552 do
1553 str_ljustify ($area, count, safe_capacity)
1554 internal_hash_code := 0
1555 end
1556
1557 center_justify is
1558 -- Center justify the string using
1559 -- the capacity as the width
1560 do
1561 str_cjustify ($area, count, safe_capacity)
1562 internal_hash_code := 0
1563 end
1564
1565 right_justify is
1566 -- Right justify the string using
1567 -- the capacity as the width
1568 do
1569 str_rjustify ($area, count, safe_capacity)
1570 internal_hash_code := 0
1571 end
1572
1573 character_justify (pivot: CHARACTER; position: INTEGER) is
1574 -- Justify a string based on a `pivot'
1575 -- and the `position' it needs to be in
1576 -- the final string.
1577 -- This will grow the string if necessary
1578 -- to get the pivot in the correct place.
1579 require
1580 valid_position: position <= capacity
1581 positive_position: position >= 1
1582 pivot_not_space: pivot /= ' '
1583 not_empty: not is_empty
1584 local
1585 l_index_of_pivot: INTEGER
1586 do
1587 l_index_of_pivot := index_of (pivot, 1)
1588 if l_index_of_pivot /= 0 then
1589 if l_index_of_pivot < position then
1590 from
1591 precede (' ')
1592 until
1593 index_of (pivot, 1) = position
1594 loop
1595 precede (' ')
1596 end
1597 elseif l_index_of_pivot > position then
1598 from
1599 remove (1)
1600 until
1601 index_of (pivot, 1) = position
1602 loop
1603 remove (1)
1604 end
1605 end
1606 end
1607 from
1608 until
1609 count = safe_capacity
1610 loop
1611 extend (' ')
1612 end
1613 internal_hash_code := 0
1614 end
1615
1616 to_lower is
1617 -- Convert to lower case.
1618 local
1619 i: INTEGER
1620 a: like area
1621 do
1622 from
1623 i := count - 1
1624 a := area
1625 until
1626 i < 0
1627 loop
1628 a.put (a.item (i).lower, i)
1629 i := i - 1
1630 end
1631 internal_hash_code := 0
1632 ensure
1633 length_end_content: elks_checking implies is_equal (old as_lower)
1634 end
1635
1636 to_upper is
1637 -- Convert to upper case.
1638 local
1639 i: INTEGER
1640 a: like area
1641 do
1642 from
1643 i := count - 1
1644 a := area
1645 until
1646 i < 0
1647 loop
1648 a.put (a.item (i).upper, i)
1649 i := i - 1
1650 end
1651 internal_hash_code := 0
1652 ensure
1653 length_end_content: elks_checking implies is_equal (old as_upper)
1654 end
1655
1656 to_integer: INTEGER is
1657 -- Integer value;
1658 -- for example, when applied to "123", will yield 123
1659 require
1660 is_integer: is_integer
1661 do
1662 Result := str_atoi ($area, count)
1663 ensure
1664 single_digit: count = 1 implies Result = ("0123456789").index_of (item (1), 1) - 1
1665 minus_sign_followed_by_single_digit:
1666 count = 2 and item (1) = '-' implies Result = -substring (2, 2).to_integer
1667 plus_sign_followed_by_single_digit:
1668 count = 2 and item (1) = '+' implies Result = substring (2, 2).to_integer
1669 recurse_to_reduce_length:
1670 count > 2 or count = 2 and not(("+-").has (item (1))) implies
1671 Result // 10 = substring (1, count - 1).to_integer and
1672 (Result \\ 10).abs = substring (count, count).to_integer
1673 end
1674
1675 to_integer_64: INTEGER_64 is
1676 -- Integer value of type INTEGER_64;
1677 -- for example, when applied to "123", will yield 123
1678 require
1679 is_integer: is_integer
1680 local
1681 l_area: like area
1682 l_character: CHARACTER
1683 i, nb: INTEGER
1684 l_is_negative: BOOLEAN
1685 do
1686 from
1687 l_area := area
1688 nb := count - 1
1689 until
1690 i > nb
1691 loop
1692 l_character := l_area.item (i)
1693 if l_character.is_digit then
1694 Result := (Result * 10) + l_character.code - 48
1695 elseif l_character = '-' then
1696 l_is_negative := True
1697 end
1698 i := i + 1
1699 end
1700 if l_is_negative then
1701 Result := - Result
1702 end
1703 end
1704
1705 to_real: REAL is
1706 -- Real value;
1707 -- for example, when applied to "123.0", will yield 123.0
1708 require
1709 represents_a_real: is_real
1710 do
1711 Result := str_ator ($area, count)
1712 end
1713
1714 to_double: DOUBLE is
1715 -- "Double" value;
1716 -- for example, when applied to "123.0", will yield 123.0 (double)
1717 require
1718 represents_a_double: is_double
1719 do
1720 Result := str_atod ($area, count)
1721 end
1722
1723 to_boolean: BOOLEAN is
1724 -- Boolean value;
1725 -- "True" yields `True', "False" yields `False'
1726 -- (case-insensitive)
1727 require
1728 is_boolean: is_boolean
1729 local
1730 s: STRING
1731 do
1732 s := twin
1733 s.right_adjust
1734 s.left_adjust
1735 s.to_lower
1736 Result := s.is_equal (true_constant)
1737 ensure
1738 to_boolean: (Result = same_string (true_constant)) or
1739 (not Result = same_string (false_constant))
1740 end
1741
1742 linear_representation: LINEAR [CHARACTER] is
1743 -- Representation as a linear structure
1744 local
1745 temp: ARRAYED_LIST [CHARACTER]
1746 i: INTEGER
1747 do
1748 create temp.make (safe_capacity)
1749 from
1750 i := 1
1751 until
1752 i > count
1753 loop
1754 temp.extend (item (i))
1755 i := i + 1
1756 end
1757 Result := temp
1758 end
1759
1760 split (a_separator: CHARACTER): LIST [STRING] is
1761 -- Split on `a_separator'.
1762 local
1763 l_list: ARRAYED_LIST [STRING]
1764 part: STRING
1765 i, j, c: INTEGER
1766 do
1767 c := count
1768 -- Worse case allocation: every character is a separator
1769 create l_list.make (c + 1)
1770 if c > 0 then
1771 from
1772 i := 1
1773 until
1774 i > c
1775 loop
1776 j := index_of (a_separator, i)
1777 if j = 0 then
1778 -- No separator was found, we will
1779 -- simply create a list with a copy of
1780 -- Current in it.
1781 j := c + 1
1782 end
1783 part := substring (i, j - 1)
1784 l_list.extend (part)
1785 i := j + 1
1786 end
1787 if j = c then
1788 check
1789 last_character_is_a_separator: item (j) = a_separator
1790 end
1791 -- A separator was found at the end of the string
1792 l_list.extend ("")
1793 end
1794 else
1795 -- Extend empty string, since Current is empty.
1796 l_list.extend ("")
1797 end
1798 Result := l_list
1799 check
1800 l_list.count = occurrences (a_separator) + 1
1801 end
1802 ensure
1803 Result /= Void
1804 end
1805
1806 frozen to_c: ANY is
1807 -- A reference to a C form of current string.
1808 -- Useful only for interfacing with C software.
1809 local
1810 l_area: like area
1811 do
1812 --| `area' can be Void in some cases (e.g. during
1813 --| partial retrieval of objects).
1814 l_area := area
1815 if l_area /= Void then
1816 l_area.put ('%U', count)
1817 Result := l_area
1818 else
1819 Result := empty_area
1820 end
1821 end
1822
1823 mirrored: like Current is
1824 -- Mirror image of string;
1825 -- result for "Hello world" is "dlrow olleH".
1826 do
1827 Result := twin
1828 if count > 0 then
1829 Result.mirror
1830 end
1831 ensure
1832 same_count: Result.count = count
1833 -- reversed: For every `i' in 1..`count', `Result'.`item' (`i') = `item' (`count'+1-`i')
1834 end
1835
1836 mirror is
1837 -- Reverse the order of characters.
1838 -- "Hello world" -> "dlrow olleH".
1839 local
1840 a: like area
1841 c: CHARACTER
1842 i, j: INTEGER
1843 do
1844 if count > 0 then
1845 from
1846 i := count - 1
1847 a := area
1848 until
1849 i <= j
1850 loop
1851 c := a.item (i)
1852 a.put (a.item (j), i)
1853 a.put (c, j)
1854 i := i - 1
1855 j := j + 1
1856 end
1857 internal_hash_code := 0
1858 end
1859 ensure
1860 same_count: count = old count
1861 -- reversed: For every `i' in 1..`count', `item' (`i') = old `item' (`count'+1-`i')
1862 end
1863
1864 feature -- Duplication
1865
1866 substring (start_index, end_index: INTEGER): like Current is
1867 -- Copy of substring containing all characters at indices
1868 -- between `start_index' and `end_index'
1869 local
1870 other_area: like area
1871 do
1872 if (1 <= start_index) and (start_index <= end_index) and (end_index <= count) then
1873 Result := new_string (end_index - start_index + 1)
1874 other_area := Result.area;
1875 other_area.base_address.memory_copy (
1876 area.item_address (start_index - 1), end_index - start_index + 1)
1877 Result.set_count (end_index - start_index + 1)
1878 else
1879 Result := new_string (0)
1880 end
1881 ensure
1882 substring_not_void: Result /= Void
1883 substring_count: Result.count = end_index - start_index + 1 or Result.count = 0
1884 first_item: Result.count > 0 implies Result.item (1) = item (start_index)
1885 recurse: Result.count > 0 implies
1886 Result.substring (2, Result.count).is_equal (substring (start_index + 1, end_index))
1887 end
1888
1889 multiply (n: INTEGER) is
1890 -- Duplicate a string within itself
1891 -- ("hello").multiply(3) => "hellohellohello"
1892 require
1893 meaningful_multiplier: n >= 1
1894 local
1895 s: STRING
1896 i: INTEGER
1897 do
1898 s := twin
1899 grow (n * count)
1900 from
1901 i := n
1902 until
1903 i = 1
1904 loop
1905 append (s)
1906 i := i - 1
1907 end
1908 end
1909
1910 feature -- Output
1911
1912 out: STRING is
1913 -- Printable representation
1914 do
1915 create Result.make (count)
1916 Result.append (Current)
1917 ensure then
1918 out_not_void: Result /= Void
1919 same_items: same_type ("") implies Result.same_string (Current)
1920 end
1921
1922 feature {STRING_HANDLER} -- Implementation
1923
1924 frozen set_count (number: INTEGER) is
1925 -- Set `count' to `number' of characters.
1926 require
1927 valid_count: 0 <= number and number <= capacity
1928 do
1929 count := number
1930 internal_hash_code := 0
1931 ensure
1932 new_count: count = number
1933 end
1934
1935 feature {NONE} -- Empty string implementation
1936
1937 elks_checking: BOOLEAN is False
1938 -- Are ELKS expensive checkings verified?
1939
1940 empty_area: SPECIAL [CHARACTER] is
1941 -- Empty `area' used when calling `make (0)'.
1942 local
1943 old_area: like area
1944 once
1945 old_area := area
1946 make_area (1)
1947 Result := area
1948 area := old_area
1949 end
1950
1951 safe_capacity: INTEGER is
1952 -- Allocated space
1953 require
1954 area_not_void: area /= Void
1955 do
1956 Result := area.count - 1
1957 end
1958
1959 internal_hash_code: INTEGER
1960 -- Computed hash-code.
1961
1962 frozen set_internal_hash_code (v: like internal_hash_code) is
1963 -- Set `internal_hash_code' with `v'.
1964 require
1965 v_nonnegative: v >= 0
1966 do
1967 internal_hash_code := v
1968 ensure
1969 internal_hash_code_set: internal_hash_code = v
1970 end
1971
1972 feature {NONE} -- Implementation
1973
1974 new_string (n: INTEGER): like Current is
1975 -- New instance of current with space for at least `n' characters.
1976 require
1977 n_non_negative: n >= 0
1978 do
1979 create Result.make (n)
1980 ensure
1981 new_string_not_void: Result /= Void
1982 new_string_empty: Result.is_empty
1983 new_string_area_big_enough: Result.capacity >= n
1984 end
1985
1986 feature {NONE} -- Transformation
1987
1988 correct_mismatch is
1989 -- Attempt to correct object mismatch during retrieve using `mismatch_information'.
1990 do
1991 -- Nothing to be done because we only added `internal_hash_code' that will
1992 -- be recomputed next time we query `hash_code'.
1993 end
1994
1995 feature {STRING} -- Implementation
1996
1997 hashcode (c_string: POINTER; len: INTEGER): INTEGER is
1998 -- Hash code value of `c_string'
1999 external
2000 "C signature (char *, EIF_INTEGER): EIF_INTEGER use %"eif_tools.h%""
2001 end
2002
2003 str_str (c_str, o_str: POINTER; clen, olen, i, fuzzy: INTEGER): INTEGER is
2004 -- Forward search of `o_str' within `c_str' starting at `i'.
2005 -- Return the index within `c_str' where the pattern was
2006 -- located, 0 if not found.
2007 -- The 'fuzzy' parameter is the maximum allowed number of
2008 -- mismatches within the pattern. A 0 means an exact match.
2009 external
2010 "C signature (char *, char *, int, int, int, int): int use %"eif_eiffel.h%""
2011 end
2012
2013 str_len (c_string: POINTER): INTEGER is
2014 -- Length of the C string: `c_string'
2015 external
2016 "C signature (char *): EIF_INTEGER use %"eif_str.h%""
2017 alias
2018 "strlen"
2019 end
2020
2021 c_p_i: INTEGER is
2022 -- Number of characters per INTEGER
2023 obsolete
2024 "You now have to implement it yourself by inheriting from PLATFORM."
2025 do
2026 -- Example of implementation using features from PLATFORM
2027 -- Result := Integer_bits // Character_bits;
2028 end
2029
2030 str_ljustify (c_string: POINTER; length, cap: INTEGER) is
2031 -- Left justify in a field of `capacity'
2032 -- the `c_string' of length `length'
2033 external
2034 "C signature (EIF_CHARACTER *, EIF_INTEGER, EIF_INTEGER) use %"eif_str.h%""
2035 end
2036
2037 str_cjustify (c_string: POINTER; length, cap: INTEGER) is
2038 -- Center justify in a field of `capacity'
2039 -- the `c_string' of length `length'
2040 external
2041 "C signature (EIF_CHARACTER *, EIF_INTEGER, EIF_INTEGER) use %"eif_str.h%""
2042 end
2043
2044 str_rjustify (c_string: POINTER; length, cap: INTEGER) is
2045 -- Right justify in a field of `capacity'
2046 -- the `c_string' of length `length'
2047 external
2048 "C signature (EIF_CHARACTER *, EIF_INTEGER, EIF_INTEGER) use %"eif_str.h%""
2049 end
2050
2051 str_strict_cmp (this, other: POINTER; len: INTEGER): INTEGER is
2052 -- Compare `this' and `other' C strings
2053 -- for the first `len' characters.
2054 -- 0 if equal, < 0 if `this' < `other',
2055 -- > 0 if `this' > `other'
2056 external
2057 "C signature (char *, char *, size_t): EIF_INTEGER use <string.h>"
2058 alias
2059 "strncmp"
2060 end
2061
2062 str_atoi (c_string: POINTER; length: INTEGER): INTEGER is
2063 -- Value of integer in `c_string'
2064 external
2065 "C signature (EIF_CHARACTER *, EIF_INTEGER): EIF_INTEGER use %"eif_str.h%""
2066 end
2067
2068 str_ator (c_string: POINTER; length: INTEGER): REAL is
2069 -- Value of real in `c_string'
2070 external
2071 "C signature (EIF_CHARACTER *, EIF_INTEGER): EIF_REAL use %"eif_str.h%""
2072 end
2073
2074 str_atod (c_string: POINTER; length: INTEGER): DOUBLE is
2075 -- Value of double in `c_string'
2076 external
2077 "C signature (EIF_CHARACTER *, EIF_INTEGER): EIF_DOUBLE use %"eif_str.h%""
2078 end
2079
2080 str_isr (c_string: POINTER; length: INTEGER): BOOLEAN is
2081 -- Is is a real?
2082 external
2083 "C signature (EIF_CHARACTER *, EIF_INTEGER): EIF_BOOLEAN use %"eif_str.h%""
2084 end
2085
2086 str_isd (c_string: POINTER; length: INTEGER): BOOLEAN is
2087 -- Is is a double?
2088 external
2089 "C signature (EIF_CHARACTER *, EIF_INTEGER): EIF_BOOLEAN use %"eif_str.h%""
2090 end
2091
2092 str_cprepend (c_string: POINTER; c: CHARACTER; length: INTEGER) is
2093 -- Prepend `c' to `c_string'.
2094 external
2095 "C signature (EIF_CHARACTER *, EIF_CHARACTER, EIF_INTEGER) use %"eif_str.h%""
2096 end
2097
2098 str_rmchar (c_string: POINTER; length, i: INTEGER) is
2099 -- Remove `i'-th character from `c_string'.
2100 external
2101 "C signature (EIF_CHARACTER *, EIF_INTEGER, EIF_INTEGER) use %"eif_str.h%""
2102 end
2103
2104 str_replace (c_string, other_string: POINTER; c_length, other_length,
2105 star_post, end_pos: INTEGER) is
2106 -- Replace substring (`start_pos', `end_pos') from `c_string'
2107 -- by `other_string'.
2108 external
2109 "C signature (EIF_CHARACTER *, EIF_CHARACTER *, EIF_INTEGER, EIF_INTEGER, EIF_INTEGER, EIF_INTEGER) use %"eif_str.h%""
2110 end
2111
2112 str_rmall (c_string: POINTER; c: CHARACTER; length: INTEGER): INTEGER is
2113 -- Remove all occurrences of `c' in `c_string'.
2114 -- Return new number of character making up `c_string'
2115 external
2116 "C signature (EIF_CHARACTER *, EIF_CHARACTER, EIF_INTEGER): EIF_INTEGER use %"eif_str.h%""
2117 end
2118
2119 str_left (c_string: POINTER; length: INTEGER): INTEGER is
2120 -- Remove all leading whitespace from `c_string'.
2121 -- Return the new number of characters making `c_string'
2122 external
2123 "C signature (EIF_CHARACTER *, EIF_INTEGER): EIF_INTEGER use %"eif_str.h%""
2124 end
2125
2126 str_right (c_string: POINTER; length: INTEGER): INTEGER is
2127 -- Remove all trailing whitespace from `c_string'.
2128 -- Return the new number of characters making `c_string'
2129 external
2130 "C signature (EIF_CHARACTER *, EIF_INTEGER): EIF_INTEGER use %"eif_str.h%""
2131 end
2132
2133 str_resize (a: POINTER; newsize: INTEGER): like area is
2134 -- Area which can accomodate
2135 -- at least `newsize' characters
2136 external
2137 "C signature (EIF_REFERENCE, unsigned int): EIF_REFERENCE use %"eif_malloc.h%""
2138 alias
2139 "sprealloc"
2140 end
2141
2142 spsubcopy (source, target: POINTER; s, e, i: INTEGER) is
2143 -- Copy characters of `source' within bounds `s'
2144 -- and `e' to `target' starting at index `i'.
2145 external
2146 "C signature (EIF_REFERENCE, EIF_REFERENCE, EIF_INTEGER, EIF_INTEGER, EIF_INTEGER) use %"eif_copy.h%""
2147 end
2148
2149 invariant
2150 extendible: extendible
2151 compare_character: not object_comparison
2152 index_set_has_same_count: index_set.count = count
2153
2154 indexing
2155
2156 library: "[
2157 EiffelBase: Library of reusable components for Eiffel.
2158 ]"
2159
2160 status: "[
2161 Copyright 1986-2001 Interactive Software Engineering (ISE).
2162 For ISE customers the original versions are an ISE product
2163 covered by the ISE Eiffel license and support agreements.
2164 ]"
2165
2166 license: "[
2167 EiffelBase may now be used by anyone as FREE SOFTWARE to
2168 develop any product, public-domain or commercial, without
2169 payment to ISE, under the terms of the ISE Free Eiffel Library
2170 License (IFELL) at http://eiffel.com/products/base/license.html.
2171 ]"
2172
2173 source: "[
2174 Interactive Software Engineering Inc.
2175 ISE Building
2176 360 Storke Road, Goleta, CA 93117 USA
2177 Telephone 805-685-1006, Fax 805-685-6869
2178 Electronic mail <info@eiffel.com>
2179 Customer support http://support.eiffel.com
2180 ]"
2181
2182 info: "[
2183 For latest info see award-winning pages: http://eiffel.com
2184 ]"
2185
2186 end -- class STRING
2187
2188
2189

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.23