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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 91477 - (show annotations)
Sun Jan 14 09:47:13 2007 UTC (13 years ago) by ericb
File size: 68276 byte(s)
Synchronized with ISE 6.0.65740
1 indexing
2 description: "[
3 Sequences of characters, accessible through integer indices
4 in a contiguous range.
5 ]"
6 library: "Free implementation of ELKS library"
7 copyright: "Copyright (c) 1986-2006, Eiffel Software and others"
8 license: "Eiffel Forum License v2 (see forum.txt)"
9 date: "$Date$"
10 revision: "$Revision$"
11
12 class
13 STRING_8
14
15 inherit
16 STRING_GENERAL
17 rename
18 append as append_string_general
19 redefine
20 copy, is_equal, out, append_string_general
21 end
22
23 INDEXABLE [CHARACTER, INTEGER]
24 rename
25 item as item
26 redefine
27 copy, is_equal, out, prune_all,
28 changeable_comparison_criterion
29 end
30
31 RESIZABLE [CHARACTER]
32 redefine
33 copy, is_equal, out,
34 changeable_comparison_criterion
35 end
36
37 TO_SPECIAL [CHARACTER]
38 rename
39 item as item
40 redefine
41 copy, is_equal, out,
42 item, infix "@", put, valid_index
43 end
44
45 MISMATCH_CORRECTOR
46 redefine
47 copy, is_equal, out, correct_mismatch
48 end
49
50 create
51 make,
52 make_empty,
53 make_filled,
54 make_from_string,
55 make_from_c,
56 make_from_cil
57
58 convert
59 to_cil: {SYSTEM_STRING},
60 as_string_32: {STRING_32},
61 make_from_cil ({SYSTEM_STRING})
62
63 feature -- Initialization
64
65 make (n: INTEGER) is
66 -- Allocate space for at least `n' characters.
67 require
68 non_negative_size: n >= 0
69 do
70 count := 0
71 internal_hash_code := 0
72 make_area (n + 1)
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 C function
120 require
121 c_string_exists: c_string /= default_pointer
122 local
123 l_count: INTEGER
124 do
125 if area = Void then
126 c_string_provider.share_from_pointer (c_string)
127 l_count := c_string_provider.count
128 make_area (l_count + 1)
129 count := l_count
130 internal_hash_code := 0
131 c_string_provider.read_string_into (Current)
132 else
133 from_c (c_string)
134 end
135 end
136
137 make_from_cil (a_system_string: SYSTEM_STRING) is
138 -- Initialize Current with `a_system_string'.
139 require
140 is_dotnet: {PLATFORM}.is_dotnet
141 local
142 l_count: INTEGER
143 do
144 if a_system_string /= Void then
145 l_count := a_system_string.length
146 make_area (l_count + 1)
147 count := l_count
148 internal_hash_code := 0
149 dotnet_convertor.read_system_string_into (a_system_string, Current)
150 else
151 make (0)
152 end
153 end
154
155 from_c (c_string: POINTER) is
156 -- Reset contents of string from contents of `c_string',
157 -- a string created by some C function.
158 require
159 c_string_exists: c_string /= default_pointer
160 local
161 l_count: INTEGER
162 do
163 c_string_provider.share_from_pointer (c_string)
164 -- Resize string in case it is not big enough
165 l_count := c_string_provider.count
166 resize (l_count + 1)
167 count := l_count
168 internal_hash_code := 0
169 c_string_provider.read_string_into (Current)
170 ensure
171 no_zero_byte: not has ('%/0/')
172 -- characters: for all i in 1..count, item (i) equals
173 -- ASCII character at address c_string + (i - 1)
174 -- correct_count: the ASCII character at address c_string + count
175 -- is NULL
176 end
177
178 from_c_substring (c_string: POINTER; start_pos, end_pos: INTEGER) is
179 -- Reset contents of string from substring of `c_string',
180 -- a string created by some C function.
181 require
182 c_string_exists: c_string /= default_pointer
183 start_position_big_enough: start_pos >= 1
184 end_position_big_enough: start_pos <= end_pos + 1
185 local
186 l_count: INTEGER
187 do
188 l_count := end_pos - start_pos + 1
189 c_string_provider.share_from_pointer_and_count (c_string + (start_pos - 1), l_count)
190 -- Resize string in case it is not big enough
191 resize (l_count + 1)
192 count := l_count
193 internal_hash_code := 0
194 c_string_provider.read_substring_into (Current, 1, l_count)
195 ensure
196 valid_count: count = end_pos - start_pos + 1
197 -- characters: for all i in 1..count, item (i) equals
198 -- ASCII character at address c_string + (i - 1)
199 end
200
201 adapt (s: STRING): like Current is
202 -- Object of a type conforming to the type of `s',
203 -- initialized with attributes from `s'
204 do
205 Result := new_string (0)
206 Result.share (s)
207 ensure
208 adapt_not_void: Result /= Void
209 shared_implementation: Result.shared_with (s)
210 end
211
212 remake (n: INTEGER) is
213 -- Allocate space for at least `n' characters.
214 obsolete
215 "Use `make' instead"
216 require
217 non_negative_size: n >= 0
218 do
219 make (n)
220 ensure
221 empty_string: count = 0
222 area_allocated: capacity >= n
223 end
224
225 feature -- Access
226
227 item, infix "@" (i: INTEGER): CHARACTER assign put is
228 -- Character at position `i'
229 do
230 Result := area.item (i - 1)
231 end
232
233
234 code (i: INTEGER): NATURAL_32 is
235 -- Numeric code of character at position `i'
236 do
237 Result := area.item (i - 1).code.to_natural_32
238 end
239
240 item_code (i: INTEGER): INTEGER is
241 -- Numeric code of character at position `i'
242 require
243 index_small_enough: i <= count
244 index_large_enough: i > 0
245 do
246 Result := area.item (i - 1).code
247 end
248
249 hash_code: INTEGER is
250 -- Hash code value
251 local
252 i, nb: INTEGER
253 l_area: like area
254 do
255 Result := internal_hash_code
256 if Result = 0 then
257 -- The magic number `8388593' below is the greatest prime lower than
258 -- 2^23 so that this magic number shifted to the left does not exceed 2^31.
259 from
260 i := 0
261 nb := count
262 l_area := area
263 until
264 i = nb
265 loop
266 Result := ((Result \\ 8388593) |<< 8) + l_area.item (i).code
267 i := i + 1
268 end
269 internal_hash_code := Result
270 end
271 end
272
273 false_constant: STRING is "false"
274 -- Constant string "false"
275
276 true_constant: STRING is "true"
277 -- Constant string "true"
278
279 shared_with (other: STRING): BOOLEAN is
280 -- Does string share the text of `other'?
281 do
282 Result := (other /= Void) and then (area = other.area)
283 end
284
285 index_of (c: CHARACTER; start_index: INTEGER): INTEGER is
286 -- Position of first occurrence of `c' at or after `start_index';
287 -- 0 if none.
288 require
289 start_large_enough: start_index >= 1
290 start_small_enough: start_index <= count + 1
291 local
292 a: like area
293 i, nb: INTEGER
294 do
295 nb := count
296 if start_index <= nb then
297 from
298 i := start_index - 1
299 a := area
300 until
301 i = nb or else a.item (i) = c
302 loop
303 i := i + 1
304 end
305 if i < nb then
306 -- We add +1 due to the area starting at 0 and not at 1.
307 Result := i + 1
308 end
309 end
310 ensure
311 valid_result: Result = 0 or (start_index <= Result and Result <= count)
312 zero_if_absent: (Result = 0) = not substring (start_index, count).has (c)
313 found_if_present: substring (start_index, count).has (c) implies item (Result) = c
314 none_before: substring (start_index, count).has (c) implies
315 not substring (start_index, Result - 1).has (c)
316 end
317
318 last_index_of (c: CHARACTER; start_index_from_end: INTEGER): INTEGER is
319 -- Position of last occurrence of `c'.
320 -- 0 if none
321 require
322 start_index_small_enough: start_index_from_end <= count
323 start_index_large_enough: start_index_from_end >= 1
324 local
325 a: like area
326 i: INTEGER
327 do
328 from
329 i := start_index_from_end - 1
330 a := area
331 until
332 i < 0 or else a.item (i) = c
333 loop
334 i := i - 1
335 end
336 -- We add +1 due to the area starting at 0 and not at 1.
337 Result := i + 1
338 ensure
339 last_index_of_non_negative: Result >= 0
340 correct_place: Result > 0 implies item (Result) = c
341 -- forall x : Result..last, item (x) /= c
342 end
343
344 substring_index_in_bounds (other: STRING; start_pos, end_pos: INTEGER): INTEGER is
345 -- Position of first occurrence of `other' at or after `start_pos'
346 -- and to or before `end_pos';
347 -- 0 if none.
348 require
349 other_nonvoid: other /= Void
350 other_notempty: not other.is_empty
351 start_pos_large_enough: start_pos >= 1
352 start_pos_small_enough: start_pos <= count
353 end_pos_large_enough: end_pos >= start_pos
354 end_pos_small_enough: end_pos <= count
355 do
356 Result := string_searcher.substring_index (Current, other, start_pos, end_pos)
357 ensure
358 correct_place: Result > 0 implies
359 other.is_equal (substring (Result, Result + other.count - 1))
360 -- forall x : start_pos..Result
361 -- not substring (x, x+other.count -1).is_equal (other)
362 end
363
364 string: STRING_8 is
365 -- New STRING having same character sequence as `Current'.
366 do
367 create Result.make (count)
368 Result.append (Current)
369 ensure
370 string_not_void: Result /= Void
371 string_type: Result.same_type (create {STRING_8}.make_empty)
372 first_item: count > 0 implies Result.item (1) = item (1)
373 recurse: count > 1 implies Result.substring (2, count).is_equal (
374 substring (2, count).string)
375 end
376
377 string_representation: STRING_8 is
378 -- Similar to `string' but only create a new object if `Current' is not of dynamic type {STRING_8}
379 do
380 if same_type (create {STRING_8}.make_empty) then
381 Result := Current
382 else
383 Result := string
384 end
385 ensure
386 Result_not_void: Result /= Void
387 correct_type: Result.same_type (create {STRING_8}.make_empty)
388 first_item: count > 0 implies Result.item (1) = item (1)
389 recurse: count > 1 implies Result.substring (2, count).is_equal (
390 substring (2, count).string)
391 end
392
393 substring_index (other: STRING; start_index: INTEGER): INTEGER is
394 -- Index of first occurrence of other at or after start_index;
395 -- 0 if none
396 require
397 other_not_void: other /= Void
398 valid_start_index: start_index >= 1 and start_index <= count + 1
399 do
400 Result := string_searcher.substring_index (Current, other, start_index, count)
401 ensure
402 valid_result: Result = 0 or else
403 (start_index <= Result and Result <= count - other.count + 1)
404 zero_if_absent: (Result = 0) =
405 not substring (start_index, count).has_substring (other)
406 at_this_index: Result >= start_index implies
407 other.same_string (substring (Result, Result + other.count - 1))
408 none_before: Result > start_index implies
409 not substring (start_index, Result + other.count - 2).has_substring (other)
410 end
411
412 fuzzy_index (other: STRING; start: INTEGER; fuzz: INTEGER): INTEGER is
413 -- Position of first occurrence of `other' at or after `start'
414 -- with 0..`fuzz' mismatches between the string and `other'.
415 -- 0 if there are no fuzzy matches
416 require
417 other_exists: other /= Void
418 other_not_empty: not other.is_empty
419 start_large_enough: start >= 1
420 start_small_enough: start <= count
421 acceptable_fuzzy: fuzz <= other.count
422 do
423 Result := string_searcher.fuzzy_index (Current, other, start, count, fuzz)
424 end
425
426 feature -- Measurement
427
428 capacity: INTEGER is
429 -- Allocated space
430 do
431 Result := area.count - 1
432 end
433
434 count: INTEGER
435 -- Actual number of characters making up the string
436
437 occurrences (c: CHARACTER): INTEGER is
438 -- Number of times `c' appears in the string
439 local
440 i, nb: INTEGER
441 a: SPECIAL [CHARACTER]
442 do
443 from
444 nb := count
445 a := area
446 until
447 i = nb
448 loop
449 if a.item (i) = c then
450 Result := Result + 1
451 end
452 i := i + 1
453 end
454 ensure then
455 zero_if_empty: count = 0 implies Result = 0
456 recurse_if_not_found_at_first_position:
457 (count > 0 and then item (1) /= c) implies
458 Result = substring (2, count).occurrences (c)
459 recurse_if_found_at_first_position:
460 (count > 0 and then item (1) = c) implies
461 Result = 1 + substring (2, count).occurrences (c)
462 end
463
464 index_set: INTEGER_INTERVAL is
465 -- Range of acceptable indexes
466 do
467 create Result.make (1, count)
468 ensure then
469 Result.count = count
470 end
471
472 feature -- Comparison
473
474 is_equal (other: like Current): BOOLEAN is
475 -- Is string made of same character sequence as `other'
476 -- (possibly with a different capacity)?
477 local
478 l_count: INTEGER
479 do
480 if other = Current then
481 Result := True
482 else
483 l_count := count
484 if l_count = other.count then
485 Result := str_strict_cmp (area, other.area, l_count) = 0
486 end
487 end
488 end
489
490 is_case_insensitive_equal (other: like Current): BOOLEAN is
491 -- Is string made of same character sequence as `other' regardless of casing
492 -- (possibly with a different capacity)?
493 require
494 other_not_void: other /= Void
495 local
496 l_area, l_other_area: like area
497 i, nb: INTEGER
498 do
499 if other = Current then
500 Result := True
501 else
502 nb := count
503 if nb = other.count then
504 from
505 l_area := area
506 l_other_area := other.area
507 Result := True
508 until
509 i = nb
510 loop
511 if l_area.item (i).as_lower /= l_other_area.item (i).as_lower then
512 Result := False
513 i := nb - 1 -- Jump out of loop
514 end
515 i := i + 1
516 end
517 end
518 end
519 ensure
520 symmetric: Result implies other.is_case_insensitive_equal (Current)
521 consistent: standard_is_equal (other) implies Result
522 valid_result: as_lower.is_equal (other.as_lower) implies Result
523 end
524
525 same_string (other: STRING): BOOLEAN is
526 -- Do `Current' and `other' have same character sequence?
527 require
528 other_not_void: other /= Void
529 local
530 i, nb: INTEGER
531 l_area, l_other_area: like area
532 do
533 if other = Current then
534 Result := True
535 elseif other.count = count then
536 Result := True
537 nb := count
538 if same_type (other) then
539 from
540 l_area := area
541 l_other_area := other.area
542 until
543 i = nb
544 loop
545 if l_area.item (i) /= l_other_area.item (i) then
546 Result := False
547 i := nb -- Jump out of the loop.
548 else
549 i := i + 1
550 end
551 end
552 else
553 from
554 i := 1
555 nb := nb + 1
556 until
557 i = nb
558 loop
559 if item (i) /= other.item (i) then
560 Result := False
561 i := nb -- Jump out of the loop.
562 else
563 i := i + 1
564 end
565 end
566 end
567 end
568 ensure
569 definition: Result = string.is_equal (other.string)
570 end
571
572 infix "<" (other: like Current): BOOLEAN is
573 -- Is string lexicographically lower than `other'?
574 local
575 other_count: INTEGER
576 current_count: INTEGER
577 do
578 if other /= Current then
579 other_count := other.count
580 current_count := count
581 if other_count = current_count then
582 Result := str_strict_cmp (other.area, area, other_count) > 0
583 else
584 if current_count < other_count then
585 Result := str_strict_cmp (other.area, area, current_count) >= 0
586 else
587 Result := str_strict_cmp (other.area, area, other_count) > 0
588 end
589 end
590 end
591 end
592
593 feature -- Status report
594
595 is_string_8: BOOLEAN is True
596 -- Current is not a STRING_8 instance
597
598 is_string_32: BOOLEAN is False
599 -- Current is a STRING_32 instance
600
601 is_valid_as_string_8: BOOLEAN is True
602 -- Is `Current' convertible to STRING_8 without information loss?
603
604 has (c: CHARACTER): BOOLEAN is
605 -- Does string include `c'?
606 local
607 i, nb: INTEGER
608 l_area: like area
609 do
610 nb := count
611 if nb > 0 then
612 from
613 l_area := area
614 until
615 i = nb or else (l_area.item (i) = c)
616 loop
617 i := i + 1
618 end
619 Result := (i < nb)
620 end
621 ensure then
622 false_if_empty: count = 0 implies not Result
623 true_if_first: count > 0 and then item (1) = c implies Result
624 recurse: (count > 0 and then item (1) /= c) implies
625 (Result = substring (2, count).has (c))
626 end
627
628 has_substring (other: STRING): BOOLEAN is
629 -- Does `Current' contain `other'?
630 require
631 other_not_void: other /= Void
632 do
633 if other = Current then
634 Result := True
635 elseif other.count <= count then
636 Result := substring_index (other, 1) > 0
637 end
638 ensure
639 false_if_too_small: count < other.count implies not Result
640 true_if_initial: (count >= other.count and then
641 other.same_string (substring (1, other.count))) implies Result
642 recurse: (count >= other.count and then
643 not other.same_string (substring (1, other.count))) implies
644 (Result = substring (2, count).has_substring (other))
645 end
646
647 extendible: BOOLEAN is True
648 -- May new items be added? (Answer: yes.)
649
650 prunable: BOOLEAN is
651 -- May items be removed? (Answer: yes.)
652 do
653 Result := True
654 end
655
656 valid_index (i: INTEGER): BOOLEAN is
657 -- Is `i' within the bounds of the string?
658 do
659 Result := (i > 0) and (i <= count)
660 end
661
662 valid_code (v: NATURAL_32): BOOLEAN is
663 -- Is `v' a valid code for a CHARACTER_32?
664 do
665 Result := v <= {CHARACTER}.max_value.to_natural_32
666 end
667
668 changeable_comparison_criterion: BOOLEAN is False
669
670 is_number_sequence: BOOLEAN is
671 -- Does `Current' represent a number sequence?
672 do
673 Result := is_valid_integer_or_natural ({NUMERIC_INFORMATION}.type_no_limitation)
674 ensure
675 syntax_and_range:
676 -- Result is true if and only if the following two
677 -- conditions are satisfied:
678 --
679 -- In the following BNF grammar, the value of
680 -- Current can be produced by "Integer_literal":
681 --
682 -- Integer_literal = [Space] [Sign] Integer [Space]
683 -- Space = " " | " " Space
684 -- Sign = "+" | "-"
685 -- Integer = Digit | Digit Integer
686 -- Digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
687 end
688
689 is_real: BOOLEAN is
690 -- Does `Current' represent a REAL?
691 do
692 Result := is_double
693 ensure
694 syntax_and_range:
695 -- 'Result' is True if and only if the following two
696 -- conditions are satisfied:
697 --
698 -- 1. In the following BNF grammar, the value of
699 -- 'Current' can be produced by "Real_literal":
700 --
701 -- Real_literal = Mantissa [Exponent_part]
702 -- Exponent_part = "E" Exponent
703 -- | "e" Exponent
704 -- Exponent = Integer_literal
705 -- Mantissa = Decimal_literal
706 -- Decimal_literal = Integer_literal ["." [Integer]] | "." Integer
707 -- Integer_literal = [Sign] Integer
708 -- Sign = "+" | "-"
709 -- Integer = Digit | Digit Integer
710 -- Digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
711 --
712 -- 2. The numerical value represented by 'Current'
713 -- is within the range that can be represented
714 -- by an instance of type REAL.
715 end
716
717 is_double: BOOLEAN is
718 -- Does `Current' represent a DOUBLE?
719 do
720 ctor_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_double)
721 Result := ctor_convertor.is_integral_double
722 ensure
723 syntax_and_range:
724 -- 'Result' is True if and only if the following two
725 -- conditions are satisfied:
726 --
727 -- 1. In the following BNF grammar, the value of
728 -- 'Current' can be produced by "Real_literal":
729 --
730 -- Real_literal = Mantissa [Exponent_part]
731 -- Exponent_part = "E" Exponent
732 -- | "e" Exponent
733 -- Exponent = Integer_literal
734 -- Mantissa = Decimal_literal
735 -- Decimal_literal = Integer_literal ["." [Integer]] | "." Integer
736 -- Integer_literal = [Sign] Integer
737 -- Sign = "+" | "-"
738 -- Integer = Digit | Digit Integer
739 -- Digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
740 --
741 -- 2. The numerical value represented by 'Current'
742 -- is within the range that can be represented
743 -- by an instance of type DOUBLE.
744 end
745
746 is_boolean: BOOLEAN is
747 -- Does `Current' represent a BOOLEAN?
748 local
749 nb: INTEGER
750 l_area: like area
751 do
752 nb := count
753 if nb = 4 then
754 -- Check if this is `true_constant'
755 l_area := area
756 Result := l_area.item (0).lower = 't' and then
757 l_area.item (1).lower = 'r' and then
758 l_area.item (2).lower = 'u' and then
759 l_area.item (3).lower = 'e'
760 elseif nb = 5 then
761 -- Check if this is `false_constant'
762 l_area := area
763 Result := l_area.item (0).lower = 'f' and then
764 l_area.item (1).lower = 'a' and then
765 l_area.item (2).lower = 'l' and then
766 l_area.item (3).lower = 's' and then
767 l_area.item (4).lower = 'e'
768 end
769 ensure
770 is_boolean: Result = (true_constant.same_string (as_lower) or false_constant.same_string (as_lower))
771 end
772
773 is_integer_8: BOOLEAN is
774 -- Does `Current' represent an INTEGER_8?
775 do
776 Result := is_valid_integer_or_natural ({NUMERIC_INFORMATION}.type_integer_8)
777 end
778
779 is_integer_16: BOOLEAN is
780 -- Does `Current' represent an INTEGER_16?
781 do
782 Result := is_valid_integer_or_natural ({NUMERIC_INFORMATION}.type_integer_16)
783 end
784
785 is_integer, is_integer_32: BOOLEAN is
786 -- Does `Current' represent an INTEGER?
787 do
788 Result := is_valid_integer_or_natural ({NUMERIC_INFORMATION}.type_integer_32)
789 end
790
791 is_integer_64: BOOLEAN is
792 -- Does `Current' represent an INTEGER_64?
793 do
794 Result := is_valid_integer_or_natural ({NUMERIC_INFORMATION}.type_integer_64)
795 end
796
797 is_natural_8: BOOLEAN is
798 -- Does `Current' represent a NATURAL_8?
799 do
800 Result := is_valid_integer_or_natural ({NUMERIC_INFORMATION}.type_natural_8)
801 end
802
803 is_natural_16: BOOLEAN is
804 -- Does `Current' represent a NATURAL_16?
805
806 do
807 Result := is_valid_integer_or_natural ({NUMERIC_INFORMATION}.type_natural_16)
808 end
809
810 is_natural, is_natural_32: BOOLEAN is
811 -- Does `Current' represent a NATURAL_32?
812 do
813 Result := is_valid_integer_or_natural ({NUMERIC_INFORMATION}.type_natural_32)
814 end
815
816 is_natural_64: BOOLEAN is
817 -- Does `Current' represent a NATURAL_64?
818 do
819 Result := is_valid_integer_or_natural ({NUMERIC_INFORMATION}.type_natural_64)
820 end
821
822 feature -- Element change
823
824 set (t: like Current; n1, n2: INTEGER) is
825 -- Set current string to substring of `t' from indices `n1'
826 -- to `n2', or to empty string if no such substring.
827 require
828 argument_not_void: t /= Void
829 local
830 s: STRING
831 do
832 s := t.substring (n1, n2)
833 area := s.area
834 count := s.count
835 internal_hash_code := 0
836 ensure
837 is_substring: is_equal (t.substring (n1, n2))
838 end
839
840 copy (other: like Current) is
841 -- Reinitialize by copying the characters of `other'.
842 -- (This is also used by `twin'.)
843 local
844 old_area: like area
845 do
846 if other /= Current then
847 old_area := area
848 standard_copy (other)
849 -- Note: <= is needed as all Eiffel string should have an
850 -- extra character to insert null character at the end.
851 if old_area = Void or else old_area.count <= count then
852 area := area.twin
853 else
854 old_area.copy_data (area, 0, 0, count)
855 area := old_area
856 end
857 internal_hash_code := 0
858 end
859 ensure then
860 new_result_count: count = other.count
861 -- same_characters: For every `i' in 1..`count', `item' (`i') = `other'.`item' (`i')
862 end
863
864 subcopy (other: like Current; start_pos, end_pos, index_pos: INTEGER) is
865 -- Copy characters of `other' within bounds `start_pos' and
866 -- `end_pos' to current string starting at index `index_pos'.
867 require
868 other_not_void: other /= Void
869 valid_start_pos: other.valid_index (start_pos)
870 valid_end_pos: other.valid_index (end_pos)
871 valid_bounds: (start_pos <= end_pos) or (start_pos = end_pos + 1)
872 valid_index_pos: valid_index (index_pos)
873 enough_space: (count - index_pos) >= (end_pos - start_pos)
874 local
875 l_other_area, l_area: like area
876 do
877 l_other_area := other.area
878 l_area := area
879 if end_pos >= start_pos then
880 if l_area /= l_other_area then
881 l_area.copy_data (l_other_area, start_pos - 1, index_pos - 1,
882 end_pos - start_pos + 1)
883 else
884 l_area.overlapping_move (start_pos - 1, index_pos - 1,
885 end_pos - start_pos + 1)
886 end
887 internal_hash_code := 0
888 end
889 ensure
890 same_count: count = old count
891 copied: elks_checking implies
892 (is_equal (old substring (1, index_pos - 1) +
893 old other.substring (start_pos, end_pos) +
894 old substring (index_pos + (end_pos - start_pos + 1), count)))
895 end
896
897 replace_substring (s: STRING; start_index, end_index: INTEGER) is
898 -- Replace characters from `start_index' to `end_index' with `s'.
899 require
900 string_not_void: s /= Void
901 valid_start_index: 1 <= start_index
902 valid_end_index: end_index <= count
903 meaningfull_interval: start_index <= end_index + 1
904 local
905 new_size: INTEGER
906 diff: INTEGER
907 l_area: like area
908 s_count: INTEGER
909 old_count: INTEGER
910 do
911 s_count := s.count
912 old_count := count
913 diff := s_count - (end_index - start_index + 1)
914 new_size := diff + old_count
915 if diff > 0 then
916 -- We need to resize the string.
917 grow (new_size)
918 end
919
920 l_area := area
921 --| We move the end of the string forward (if diff is > 0), backward (if diff < 0),
922 --| and nothing otherwise.
923 if diff /= 0 then
924 l_area.overlapping_move (end_index, end_index + diff, old_count - end_index)
925 end
926 --| Set new count
927 set_count (new_size)
928 --| We copy the substring.
929 l_area.copy_data (s.area, 0, start_index - 1, s_count)
930 ensure
931 new_count: count = old count + old s.count - end_index + start_index - 1
932 replaced: elks_checking implies
933 (is_equal (old (substring (1, start_index - 1) +
934 s + substring (end_index + 1, count))))
935 end
936
937 replace_substring_all (original, new: like Current) is
938 -- Replace every occurrence of `original' with `new'.
939 require
940 original_exists: original /= Void
941 new_exists: new /= Void
942 original_not_empty: not original.is_empty
943 local
944 l_first_pos, l_next_pos: INTEGER
945 l_orig_count, l_new_count, l_count: INTEGER
946 l_area, l_new_area: like area
947 l_offset: INTEGER
948 l_string_searcher: like string_searcher
949 do
950 if not is_empty then
951 l_count := count
952 l_string_searcher := string_searcher
953 l_string_searcher.initialize_deltas (original)
954 l_first_pos := l_string_searcher.substring_index_with_deltas (Current, original, 1, l_count)
955 if l_first_pos > 0 then
956 l_orig_count := original.count
957 l_new_count := new.count
958 if l_orig_count = l_new_count then
959 -- String will not be resized, simply perform character substitution
960 from
961 l_area := area
962 l_new_area := new.area
963 until
964 l_first_pos = 0
965 loop
966 l_area.copy_data (l_new_area, 0, l_first_pos - 1, l_new_count)
967 if l_first_pos + l_new_count <= l_count then
968 l_first_pos := l_string_searcher.substring_index_with_deltas (Current, original, l_first_pos + l_new_count, l_count)
969 else
970 l_first_pos := 0
971 end
972 end
973 elseif l_orig_count > l_new_count then
974 -- New string is smaller than previous string, we can optimize
975 -- substitution by only moving block between two occurrences of `orginal'.
976 from
977 l_next_pos := l_string_searcher.substring_index_with_deltas (Current, original, l_first_pos + l_orig_count, l_count)
978 l_area := area
979 l_new_area := new.area
980 until
981 l_next_pos = 0
982 loop
983 -- Copy new string into Current
984 l_area.copy_data (l_new_area, 0, l_first_pos - 1 - l_offset, l_new_count)
985 -- Shift characters between `l_first_pos' and `l_next_pos'
986 l_area.overlapping_move (l_first_pos + l_orig_count - 1,
987 l_first_pos + l_new_count - 1 - l_offset, l_next_pos - l_first_pos - l_orig_count)
988 l_first_pos := l_next_pos
989 l_offset := l_offset + (l_orig_count - l_new_count)
990 if l_first_pos + l_new_count <= l_count then
991 l_next_pos := l_string_searcher.substring_index_with_deltas (Current, original, l_first_pos + l_orig_count, l_count)
992 else
993 l_next_pos := 0
994 end
995 end
996 -- Perform final substitution:
997 -- Copy new string into Current
998 l_area.copy_data (l_new_area, 0, l_first_pos - 1 - l_offset, l_new_count)
999 -- Shift characters between `l_first_pos' and the end of the string
1000 l_area.overlapping_move (l_first_pos + l_orig_count - 1,
1001 l_first_pos + l_new_count - 1 - l_offset, l_count + 1 - l_first_pos - l_orig_count)
1002 -- Perform last substitution
1003 l_offset := l_offset + (l_orig_count - l_new_count)
1004
1005 -- Update `count'
1006 set_count (l_count - l_offset)
1007 else
1008 -- Optimization is harder as we don't know how many times we need to resize
1009 -- the string. For now, we do like we did in our previous implementation
1010 from
1011 until
1012 l_first_pos = 0
1013 loop
1014 replace_substring (new, l_first_pos, l_first_pos + l_orig_count - 1)
1015 l_count := count
1016 if l_first_pos + l_new_count <= l_count then
1017 l_first_pos := l_string_searcher.substring_index_with_deltas (Current, original, l_first_pos + l_new_count, l_count)
1018 else
1019 l_first_pos := 0
1020 end
1021 end
1022 end
1023 internal_hash_code := 0
1024 end
1025 end
1026 end
1027
1028 replace_blank is
1029 -- Replace all current characters with blanks.
1030 do
1031 fill_with (' ')
1032 ensure
1033 same_size: (count = old count) and (capacity >= old capacity)
1034 all_blank: elks_checking implies occurrences (' ') = count
1035 end
1036
1037 fill_blank is
1038 -- Fill with `capacity' blank characters.
1039 do
1040 fill_character (' ')
1041 ensure
1042 filled: full
1043 same_size: (count = capacity) and (capacity = old capacity)
1044 -- all_blank: For every `i' in `count'..`capacity', `item' (`i') = `Blank'
1045 end
1046
1047 fill_with (c: CHARACTER) is
1048 -- Replace every character with `c'.
1049 local
1050 l_count: INTEGER
1051 do
1052 l_count := count
1053 if l_count /= 0 then
1054 area.fill_with (c, 0, count - 1)
1055 internal_hash_code := 0
1056 end
1057 ensure
1058 same_count: (count = old count) and (capacity >= old capacity)
1059 filled: elks_checking implies occurrences (c) = count
1060 end
1061
1062 replace_character (c: CHARACTER) is
1063 -- Replace every character with `c'.
1064 obsolete
1065 "ELKS 2001: use `fill_with' instead'"
1066 do
1067 fill_with (c)
1068 ensure
1069 same_count: (count = old count) and (capacity >= old capacity)
1070 filled: elks_checking implies occurrences (c) = count
1071 end
1072
1073 fill_character (c: CHARACTER) is
1074 -- Fill with `capacity' characters all equal to `c'.
1075 local
1076 l_cap: like capacity
1077 do
1078 l_cap := capacity
1079 if l_cap /= 0 then
1080 area.fill_with (c, 0, l_cap - 1)
1081 count := l_cap
1082 internal_hash_code := 0
1083 end
1084 ensure
1085 filled: full
1086 same_size: (count = capacity) and (capacity = old capacity)
1087 -- all_char: For every `i' in 1..`capacity', `item' (`i') = `c'
1088 end
1089
1090 head (n: INTEGER) is
1091 -- Remove all characters except for the first `n';
1092 -- do nothing if `n' >= `count'.
1093 obsolete
1094 "ELKS 2001: use `keep_head' instead'"
1095 require
1096 non_negative_argument: n >= 0
1097 do
1098 keep_head (n)
1099 ensure
1100 new_count: count = n.min (old count)
1101 kept: elks_checking implies is_equal (old substring (1, n.min (count)))
1102 end
1103
1104 keep_head (n: INTEGER) is
1105 -- Remove all characters except for the first `n';
1106 -- do nothing if `n' >= `count'.
1107 require
1108 non_negative_argument: n >= 0
1109 do
1110 if n < count then
1111 count := n
1112 internal_hash_code := 0
1113 end
1114 ensure
1115 new_count: count = n.min (old count)
1116 kept: elks_checking implies is_equal (old substring (1, n.min (count)))
1117 end
1118
1119 tail (n: INTEGER) is
1120 -- Remove all characters except for the last `n';
1121 -- do nothing if `n' >= `count'.
1122 obsolete
1123 "ELKS 2001: use `keep_tail' instead'"
1124 require
1125 non_negative_argument: n >= 0
1126 do
1127 keep_tail (n)
1128 ensure
1129 new_count: count = n.min (old count)
1130 kept: elks_checking implies is_equal (old substring (count - n.min(count) + 1, count))
1131 end
1132
1133 keep_tail (n: INTEGER) is
1134 -- Remove all characters except for the last `n';
1135 -- do nothing if `n' >= `count'.
1136 require
1137 non_negative_argument: n >= 0
1138 local
1139 nb: like count
1140 do
1141 nb := count
1142 if n < nb then
1143 area.overlapping_move (nb - n, 0, n)
1144 count := n
1145 internal_hash_code := 0
1146 end
1147 ensure
1148 new_count: count = n.min (old count)
1149 kept: elks_checking implies is_equal (old substring (count - n.min(count) + 1, count))
1150 end
1151
1152 left_adjust is
1153 -- Remove leading whitespace.
1154 local
1155 nb, nb_space: INTEGER
1156 l_area: like area
1157 do
1158 -- Compute number of spaces at the left of current string.
1159 from
1160 nb := count - 1
1161 l_area := area
1162 until
1163 nb_space > nb or else not l_area.item (nb_space).is_space
1164 loop
1165 nb_space := nb_space + 1
1166 end
1167
1168 if nb_space > 0 then
1169 -- Set new count value.
1170 nb := nb + 1 - nb_space
1171 -- Shift characters to the left.
1172 l_area.overlapping_move (nb_space, 0, nb)
1173 -- Set new count.
1174 count := nb
1175 internal_hash_code := 0
1176 end
1177 ensure
1178 valid_count: count <= old count
1179 new_count: not is_empty implies not item (1).is_space
1180 kept: elks_checking implies is_equal ((old twin).substring (old count - count + 1, old count))
1181 end
1182
1183 right_adjust is
1184 -- Remove trailing whitespace.
1185 local
1186 i, nb: INTEGER
1187 nb_space: INTEGER
1188 l_area: like area
1189 do
1190 -- Compute number of spaces at the right of current string.
1191 from
1192 nb := count - 1
1193 i := nb
1194 l_area := area
1195 until
1196 i < 0 or else not l_area.item (i).is_space
1197 loop
1198 nb_space := nb_space + 1
1199 i := i - 1
1200 end
1201
1202 if nb_space > 0 then
1203 -- Set new count.
1204 count := nb + 1 - nb_space
1205 internal_hash_code := 0
1206 end
1207 ensure
1208 valid_count: count <= old count
1209 new_count: (count /= 0) implies
1210 ((item (count) /= ' ') and
1211 (item (count) /= '%T') and
1212 (item (count) /= '%R') and
1213 (item (count) /= '%N'))
1214 kept: elks_checking implies is_equal ((old twin).substring (1, count))
1215 end
1216
1217 share (other: STRING) is
1218 -- Make current string share the text of `other'.
1219 -- Subsequent changes to the characters of current string
1220 -- will also affect `other', and conversely.
1221 require
1222 argument_not_void: other /= Void
1223 do
1224 area := other.area
1225 count := other.count
1226 internal_hash_code := 0
1227 ensure
1228 shared_count: other.count = count
1229 shared_area: other.area = area
1230 end
1231
1232 put (c: CHARACTER; i: INTEGER) is
1233 -- Replace character at position `i' by `c'.
1234 do
1235 area.put (c, i - 1)
1236 internal_hash_code := 0
1237 ensure then
1238 stable_count: count = old count
1239 stable_before_i: elks_checking implies substring (1, i - 1).is_equal (old substring (1, i - 1))
1240 stable_after_i: elks_checking implies substring (i + 1, count).is_equal (old substring (i + 1, count))
1241 end
1242
1243 put_code (v: NATURAL_32; i: INTEGER) is
1244 -- Replace character at position `i' by character of code `v'.
1245 do
1246 area.put (v.to_character_8, i - 1)
1247 internal_hash_code := 0
1248 end
1249
1250 precede, prepend_character (c: CHARACTER) is
1251 -- Add `c' at front.
1252 local
1253 l_area: like area
1254 do
1255 if count = capacity then
1256 resize (count + additional_space)
1257 end
1258 l_area := area
1259 l_area.overlapping_move (0, 1, count)
1260 l_area.put (c, 0)
1261 count := count + 1
1262 internal_hash_code := 0
1263 ensure
1264 new_count: count = old count + 1
1265 end
1266
1267 prepend (s: STRING) is
1268 -- Prepend a copy of `s' at front.
1269 require
1270 argument_not_void: s /= Void
1271 do
1272 insert_string (s, 1)
1273 ensure
1274 new_count: count = old (count + s.count)
1275 inserted: elks_checking implies string.is_equal (old (s.twin) + old substring (1, count))
1276 end
1277
1278 prepend_boolean (b: BOOLEAN) is
1279 -- Prepend the string representation of `b' at front.
1280 do
1281 prepend (b.out)
1282 end
1283
1284 prepend_double (d: DOUBLE) is
1285 -- Prepend the string representation of `d' at front.
1286 do
1287 prepend (d.out)
1288 end
1289
1290 prepend_integer (i: INTEGER) is
1291 -- Prepend the string representation of `i' at front.
1292 do
1293 prepend (i.out)
1294 end
1295
1296 prepend_real (r: REAL) is
1297 -- Prepend the string representation of `r' at front.
1298 do
1299 prepend (r.out)
1300 end
1301
1302 prepend_string (s: STRING) is
1303 -- Prepend a copy of `s', if not void, at front.
1304 do
1305 if s /= Void then
1306 prepend (s)
1307 end
1308 end
1309
1310 append_string_general (s: STRING_GENERAL) is
1311 -- Append a copy of `s' at end.
1312 local
1313 l_s8: STRING
1314 do
1315 if same_type (s) then
1316 l_s8 ?= s
1317 append (l_s8)
1318 else
1319 Precursor {STRING_GENERAL} (s)
1320 end
1321 end
1322
1323 append (s: STRING) is
1324 -- Append a copy of `s' at end.
1325 require
1326 argument_not_void: s /= Void
1327 local
1328 l_count, l_s_count, l_new_size: INTEGER
1329 do
1330 l_s_count := s.count
1331 if l_s_count > 0 then
1332 l_count := count
1333 l_new_size := l_s_count + l_count
1334 if l_new_size > capacity then
1335 resize (l_new_size + additional_space)
1336 end
1337 area.copy_data (s.area, 0, l_count, l_s_count)
1338 count := l_new_size
1339 internal_hash_code := 0
1340 end
1341 ensure
1342 new_count: count = old count + old s.count
1343 appended: elks_checking implies is_equal (old twin + old s.twin)
1344 end
1345
1346 infix "+" (s: STRING): like Current is
1347 -- Append a copy of 's' at the end of a copy of Current,
1348 -- Then return the Result.
1349 require
1350 argument_not_void: s /= Void
1351 do
1352 Result := new_string (count + s.count)
1353 Result.append (Current)
1354 Result.append (s)
1355 ensure
1356 Result_exists: Result /= Void
1357 new_count: Result.count = count + s.count
1358 initial: elks_checking implies Result.substring (1, count).is_equal (Current)
1359 final: elks_checking implies Result.substring (count + 1, count + s.count).same_string (s)
1360 end
1361
1362 append_string (s: STRING) is
1363 -- Append a copy of `s', if not void, at end.
1364 do
1365 if s /= Void then
1366 append (s)
1367 end
1368 ensure
1369 appended: s /= Void implies
1370 (elks_checking implies is_equal (old twin + old s.twin))
1371 end
1372
1373 append_integer (i: INTEGER) is
1374 -- Append the string representation of `i' at end.
1375 local
1376 l_value: INTEGER
1377 l_starting_index, l_ending_index: INTEGER
1378 l_temp: CHARACTER
1379 l_area: like area
1380 do
1381 if i = 0 then
1382 append_character ('0')
1383 else
1384 -- Extract integer value digit by digit from right to left.
1385 from
1386 l_starting_index := count
1387 if i < 0 then
1388 append_character ('-')
1389 l_starting_index := l_starting_index + 1
1390 -- Special case for minimum integer value as negating it
1391 -- as no effect.
1392 if i = {INTEGER}.Min_value then
1393 append_character ('8')
1394 l_value := -(i // 10)
1395 else
1396 l_value := -i
1397 end
1398 else
1399 l_value := i
1400 end
1401 until
1402 l_value = 0
1403 loop
1404 append_character (((l_value \\ 10)+ 48).to_character_8)
1405 l_value := l_value // 10
1406 end
1407
1408 -- Now put digits in correct order from left to right.
1409 from
1410 l_ending_index := count - 1
1411 l_area := area
1412 until
1413 l_starting_index >= l_ending_index
1414 loop
1415 l_temp := l_area.item (l_starting_index)
1416 l_area.put (l_area.item (l_ending_index), l_starting_index)
1417 l_area.put (l_temp, l_ending_index)
1418 l_ending_index := l_ending_index - 1
1419 l_starting_index := l_starting_index + 1
1420 end
1421 end
1422 end
1423
1424 append_integer_8 (i: INTEGER_8) is
1425 -- Append the string representation of `i' at end.
1426 local
1427 l_value: INTEGER_8
1428 l_starting_index, l_ending_index: INTEGER
1429 l_temp: CHARACTER
1430 l_area: like area
1431 do
1432 if i = 0 then
1433 append_character ('0')
1434 else
1435 -- Extract integer value digit by digit from right to left.
1436 from
1437 l_starting_index := count
1438 if i < 0 then
1439 append_character ('-')
1440 l_starting_index := l_starting_index + 1
1441 -- Special case for minimum integer value as negating it
1442 -- as no effect.
1443 if i = {INTEGER_8}.Min_value then
1444 append_character ('8')
1445 l_value := -(i // 10)
1446 else
1447 l_value := -i
1448 end
1449 else
1450 l_value := i
1451 end
1452 until
1453 l_value = 0
1454 loop
1455 append_character (((l_value \\ 10)+ 48).to_character_8)
1456 l_value := l_value // 10
1457 end
1458
1459 -- Now put digits in correct order from left to right.
1460 from
1461 l_ending_index := count - 1
1462 l_area := area
1463 until
1464 l_starting_index >= l_ending_index
1465 loop
1466 l_temp := l_area.item (l_starting_index)
1467 l_area.put (l_area.item (l_ending_index), l_starting_index)
1468 l_area.put (l_temp, l_ending_index)
1469 l_ending_index := l_ending_index - 1
1470 l_starting_index := l_starting_index + 1
1471 end
1472 end
1473 end
1474
1475 append_integer_16 (i: INTEGER_16) is
1476 -- Append the string representation of `i' at end.
1477 local
1478 l_value: INTEGER_16
1479 l_starting_index, l_ending_index: INTEGER
1480 l_temp: CHARACTER
1481 l_area: like area
1482 do
1483 if i = 0 then
1484 append_character ('0')
1485 else
1486 -- Extract integer value digit by digit from right to left.
1487 from
1488 l_starting_index := count
1489 if i < 0 then
1490 append_character ('-')
1491 l_starting_index := l_starting_index + 1
1492 -- Special case for minimum integer value as negating it
1493 -- as no effect.
1494 if i = {INTEGER_16}.Min_value then
1495 append_character ('8')
1496 l_value := -(i // 10)
1497 else
1498 l_value := -i
1499 end
1500 else
1501 l_value := i
1502 end
1503 until
1504 l_value = 0
1505 loop
1506 append_character (((l_value \\ 10)+ 48).to_character_8)
1507 l_value := l_value // 10
1508 end
1509
1510 -- Now put digits in correct order from left to right.
1511 from
1512 l_ending_index := count - 1
1513 l_area := area
1514 until
1515 l_starting_index >= l_ending_index
1516 loop
1517 l_temp := l_area.item (l_starting_index)
1518 l_area.put (l_area.item (l_ending_index), l_starting_index)
1519 l_area.put (l_temp, l_ending_index)
1520 l_ending_index := l_ending_index - 1
1521 l_starting_index := l_starting_index + 1
1522 end
1523 end
1524 end
1525
1526 append_integer_64 (i: INTEGER_64) is
1527 -- Append the string representation of `i' at end.
1528 local
1529 l_value: INTEGER_64
1530 l_starting_index, l_ending_index: INTEGER
1531 l_temp: CHARACTER
1532 l_area: like area
1533 do
1534 if i = 0 then
1535 append_character ('0')
1536 else
1537 -- Extract integer value digit by digit from right to left.
1538 from
1539 l_starting_index := count
1540 if i < 0 then
1541 append_character ('-')
1542 l_starting_index := l_starting_index + 1
1543 -- Special case for minimum integer value as negating it
1544 -- as no effect.
1545 if i = {INTEGER_64}.Min_value then
1546 append_character ('8')
1547 l_value := -(i // 10)
1548 else
1549 l_value := -i
1550 end
1551 else
1552 l_value := i
1553 end
1554 until
1555 l_value = 0
1556 loop
1557 append_character (((l_value \\ 10)+ 48).to_character_8)
1558 l_value := l_value // 10
1559 end
1560
1561 -- Now put digits in correct order from left to right.
1562 from
1563 l_ending_index := count - 1
1564 l_area := area
1565 until
1566 l_starting_index >= l_ending_index
1567 loop
1568 l_temp := l_area.item (l_starting_index)
1569 l_area.put (l_area.item (l_ending_index), l_starting_index)
1570 l_area.put (l_temp, l_ending_index)
1571 l_ending_index := l_ending_index - 1
1572 l_starting_index := l_starting_index + 1
1573 end
1574 end
1575 end
1576
1577 append_natural_8 (i: NATURAL_8) is
1578 -- Append the string representation of `i' at end.
1579 local
1580 l_value: NATURAL_8
1581 l_starting_index, l_ending_index: INTEGER
1582 l_temp: CHARACTER
1583 l_area: like area
1584 do
1585 if i = 0 then
1586 append_character ('0')
1587 else
1588 -- Extract integer value digit by digit from right to left.
1589 from
1590 l_starting_index := count
1591 l_value := i
1592 until
1593 l_value = 0
1594 loop
1595 append_character (((l_value \\ 10)+ 48).to_character_8)
1596 l_value := l_value // 10
1597 end
1598
1599 -- Now put digits in correct order from left to right.
1600 from
1601 l_ending_index := count - 1
1602 l_area := area
1603 until
1604 l_starting_index >= l_ending_index
1605 loop
1606 l_temp := l_area.item (l_starting_index)
1607 l_area.put (l_area.item (l_ending_index), l_starting_index)
1608 l_area.put (l_temp, l_ending_index)
1609 l_ending_index := l_ending_index - 1
1610 l_starting_index := l_starting_index + 1
1611 end
1612 end
1613 end
1614
1615 append_natural_16 (i: NATURAL_16) is
1616 -- Append the string representation of `i' at end.
1617 local
1618 l_value: NATURAL_16
1619 l_starting_index, l_ending_index: INTEGER
1620 l_temp: CHARACTER
1621 l_area: like area
1622 do
1623 if i = 0 then
1624 append_character ('0')
1625 else
1626 -- Extract integer value digit by digit from right to left.
1627 from
1628 l_starting_index := count
1629 l_value := i
1630 until
1631 l_value = 0
1632 loop
1633 append_character (((l_value \\ 10)+ 48).to_character_8)
1634 l_value := l_value // 10
1635 end
1636
1637 -- Now put digits in correct order from left to right.
1638 from
1639 l_ending_index := count - 1
1640 l_area := area
1641 until
1642 l_starting_index >= l_ending_index
1643 loop
1644 l_temp := l_area.item (l_starting_index)
1645 l_area.put (l_area.item (l_ending_index), l_starting_index)
1646 l_area.put (l_temp, l_ending_index)
1647 l_ending_index := l_ending_index - 1
1648 l_starting_index := l_starting_index + 1
1649 end
1650 end
1651 end
1652
1653 append_natural_32 (i: NATURAL_32) is
1654 -- Append the string representation of `i' at end.
1655 local
1656 l_value: NATURAL_32
1657 l_starting_index, l_ending_index: INTEGER
1658 l_temp: CHARACTER
1659 l_area: like area
1660 do
1661 if i = 0 then
1662 append_character ('0')
1663 else
1664 -- Extract integer value digit by digit from right to left.
1665 from
1666 l_starting_index := count
1667 l_value := i
1668 until
1669 l_value = 0
1670 loop
1671 append_character (((l_value \\ 10)+ 48).to_character_8)
1672 l_value := l_value // 10
1673 end
1674
1675 -- Now put digits in correct order from left to right.
1676 from
1677 l_ending_index := count - 1
1678 l_area := area
1679 until
1680 l_starting_index >= l_ending_index
1681 loop
1682 l_temp := l_area.item (l_starting_index)
1683 l_area.put (l_area.item (l_ending_index), l_starting_index)
1684 l_area.put (l_temp, l_ending_index)
1685 l_ending_index := l_ending_index - 1
1686 l_starting_index := l_starting_index + 1
1687 end
1688 end
1689 end
1690
1691 append_natural_64 (i: NATURAL_64) is
1692 -- Append the string representation of `i' at end.
1693 local
1694 l_value: NATURAL_64
1695 l_starting_index, l_ending_index: INTEGER
1696 l_temp: CHARACTER
1697 l_area: like area
1698 do
1699 if i = 0 then
1700 append_character ('0')
1701 else
1702 -- Extract integer value digit by digit from right to left.
1703 from
1704 l_starting_index := count
1705 l_value := i
1706 until
1707 l_value = 0
1708 loop
1709 append_character (((l_value \\ 10)+ 48).to_character_8)
1710 l_value := l_value // 10
1711 end
1712
1713 -- Now put digits in correct order from left to right.
1714 from
1715 l_ending_index := count - 1
1716 l_area := area
1717 until
1718 l_starting_index >= l_ending_index
1719 loop
1720 l_temp := l_area.item (l_starting_index)
1721 l_area.put (l_area.item (l_ending_index), l_starting_index)
1722 l_area.put (l_temp, l_ending_index)
1723 l_ending_index := l_ending_index - 1
1724 l_starting_index := l_starting_index + 1
1725 end
1726 end
1727 end
1728
1729 append_real (r: REAL) is
1730 -- Append the string representation of `r' at end.
1731 do
1732 append (r.out)
1733 end
1734
1735 append_double (d: DOUBLE) is
1736 -- Append the string representation of `d' at end.
1737 do
1738 append (d.out)
1739 end
1740
1741 append_character, extend (c: CHARACTER) is
1742 -- Append `c' at end.
1743 local
1744 current_count: INTEGER
1745 do
1746 current_count := count
1747 if current_count = capacity then
1748 resize (current_count + additional_space)
1749 end
1750 area.put (c, current_count)
1751 count := current_count + 1
1752 internal_hash_code := 0
1753 ensure then
1754 item_inserted: item (count) = c
1755 new_count: count = old count + 1
1756 stable_before: elks_checking implies substring (1, count - 1).is_equal (old twin)
1757 end
1758
1759 append_boolean (b: BOOLEAN) is
1760 -- Append the string representation of `b' at end.
1761 do
1762 append (b.out)
1763 end
1764
1765 insert (s: STRING; i: INTEGER) is
1766 -- Add `s' to left of position `i' in current string.
1767 obsolete
1768 "ELKS 2001: use `insert_string' instead"
1769 require
1770 string_exists: s /= Void
1771 index_small_enough: i <= count + 1
1772 index_large_enough: i > 0
1773 do
1774 insert_string (s, i)
1775 ensure
1776 inserted: elks_checking implies
1777 (is_equal (old substring (1, i - 1) + old (s.twin) + old substring (i, count)))
1778 end
1779
1780 insert_string (s: STRING; i: INTEGER) is
1781 -- Insert `s' at index `i', shifting characters between ranks
1782 -- `i' and `count' rightwards.
1783 require
1784 string_exists: s /= Void
1785 valid_insertion_index: 1 <= i and i <= count + 1
1786 local
1787 pos, new_size: INTEGER
1788 l_s_count: INTEGER
1789 l_area: like area
1790 do
1791 -- Insert `s' if `s' is not empty, otherwise is useless.
1792 l_s_count := s.count
1793 if l_s_count /= 0 then
1794 -- Resize Current if necessary.
1795 new_size := l_s_count + count
1796 if new_size > capacity then
1797 resize (new_size + additional_space)
1798 end
1799
1800 -- Perform all operations using a zero based arrays.
1801 l_area := area
1802 pos := i - 1
1803
1804 -- First shift from `s.count' position all characters starting at index `pos'.
1805 l_area.overlapping_move (pos, pos + l_s_count, count - pos)
1806
1807 -- Copy string `s' at index `pos'.
1808 l_area.copy_data (s.area, 0, pos, l_s_count)
1809
1810 count := new_size
1811 internal_hash_code := 0
1812 end
1813 ensure
1814 inserted: elks_checking implies
1815 (is_equal (old substring (1, i - 1) + old (s.twin) + old substring (i, count)))
1816 end
1817
1818 insert_character (c: CHARACTER; i: INTEGER) is
1819 -- Insert `c' at index `i', shifting characters between ranks
1820 -- `i' and `count' rightwards.
1821 require
1822 valid_insertion_index: 1 <= i and i <= count + 1
1823 local
1824 pos, new_size: INTEGER
1825 l_area: like area
1826 do
1827 -- Resize Current if necessary.
1828 new_size := 1 + count
1829 if new_size > capacity then
1830 resize (new_size + additional_space)
1831 end
1832
1833 -- Perform all operations using a zero based arrays.
1834 pos := i - 1
1835 l_area := area
1836
1837 -- First shift from `s.count' position all characters starting at index `pos'.
1838 l_area.overlapping_move (pos, pos + 1, count - pos)
1839
1840 -- Insert new character
1841 l_area.put (c, pos)
1842
1843 count := new_size
1844 internal_hash_code := 0
1845 ensure
1846 one_more_character: count = old count + 1
1847 inserted: item (i) = c
1848 stable_before_i: elks_checking implies substring (1, i - 1).is_equal (old substring (1, i - 1))
1849 stable_after_i: elks_checking implies substring (i + 1, count).is_equal (old substring (i, count))
1850 end
1851
1852 feature -- Removal
1853
1854 remove (i: INTEGER) is
1855 -- Remove `i'-th character.
1856 local
1857 l_count: INTEGER
1858 do
1859 l_count := count
1860 -- Shift characters to the left.
1861 area.overlapping_move (i, i - 1, l_count - i)
1862 -- Update content.
1863 count := l_count - 1
1864 internal_hash_code := 0
1865 end
1866
1867 remove_head (n: INTEGER) is
1868 -- Remove first `n' characters;
1869 -- if `n' > `count', remove all.
1870 require
1871 n_non_negative: n >= 0
1872 do
1873 if n > count then
1874 count := 0
1875 internal_hash_code := 0
1876 else
1877 keep_tail (count - n)
1878 end
1879 ensure
1880 removed: elks_checking implies is_equal (old substring (n.min (count) + 1, count))
1881 end
1882
1883 remove_substring (start_index, end_index: INTEGER) is
1884 -- Remove all characters from `start_index'
1885 -- to `end_index' inclusive.
1886 require
1887 valid_start_index: 1 <= start_index
1888 valid_end_index: end_index <= count
1889 meaningful_interval: start_index <= end_index + 1
1890 local
1891 l_count, nb_removed: INTEGER
1892 do
1893 nb_removed := end_index - start_index + 1
1894 if nb_removed > 0 then
1895 l_count := count
1896 area.overlapping_move (start_index + nb_removed - 1, start_index - 1, l_count - end_index)
1897 count := l_count - nb_removed
1898 end
1899 ensure
1900 removed: elks_checking implies
1901 is_equal (old substring (1, start_index - 1) + old substring (end_index + 1, count))
1902 end
1903
1904 remove_tail (n: INTEGER) is
1905 -- Remove last `n' characters;
1906 -- if `n' > `count', remove all.
1907 require
1908 n_non_negative: n >= 0
1909 local
1910 l_count: INTEGER
1911 do
1912 l_count := count
1913 if n > l_count then
1914 count := 0
1915 internal_hash_code := 0
1916 else
1917 keep_head (l_count - n)
1918 end
1919 ensure
1920 removed: elks_checking implies is_equal (old substring (1, count - n.min (count)))
1921 end
1922
1923 prune (c: CHARACTER) is
1924 -- Remove first occurrence of `c', if any.
1925 require else
1926 True
1927 local
1928 counter: INTEGER
1929 do
1930 from
1931 counter := 1
1932 until
1933 counter > count or else (item (counter) = c)
1934 loop
1935 counter := counter + 1
1936 end
1937 if counter <= count then
1938 remove (counter)
1939 end
1940 end
1941
1942 prune_all (c: CHARACTER) is
1943 -- Remove all occurrences of `c'.
1944 require else
1945 True
1946 local
1947 i, j, nb: INTEGER
1948 l_area: like area
1949 l_char: CHARACTER
1950 do
1951 -- Traverse string and shift characters to the left
1952 -- each time we find an occurrence of `c'.
1953 from
1954 l_area := area
1955 nb := count
1956 until
1957 i = nb
1958 loop
1959 l_char := l_area.item (i)
1960 if l_char /= c then
1961 l_area.put (l_char, j)
1962 j := j + 1
1963 end
1964 i := i + 1
1965 end
1966 count := j
1967 internal_hash_code := 0
1968 ensure then
1969 changed_count: count = (old count) - (old occurrences (c))
1970 -- removed: For every `i' in 1..`count', `item' (`i') /= `c'
1971 end
1972
1973 prune_all_leading (c: CHARACTER) is
1974 -- Remove all leading occurrences of `c'.
1975 do
1976 from
1977 until
1978 is_empty or else item (1) /= c
1979 loop
1980 remove (1)
1981 end
1982 end
1983
1984 prune_all_trailing (c: CHARACTER) is
1985 -- Remove all trailing occurrences of `c'.
1986 do
1987 from
1988 until
1989 is_empty or else item (count) /= c
1990 loop
1991 remove (count)
1992 end
1993 end
1994
1995 wipe_out is
1996 -- Remove all characters.
1997 do
1998 create area.make (1)
1999 count := 0
2000 internal_hash_code := 0
2001 ensure then
2002 is_empty: count = 0
2003 empty_capacity: capacity = 0
2004 end
2005
2006 clear_all is
2007 -- Reset all characters.
2008 do
2009 count := 0
2010 internal_hash_code := 0
2011 ensure
2012 is_empty: count = 0
2013 same_capacity: capacity = old capacity
2014 end
2015
2016 feature -- Resizing
2017
2018 adapt_size is
2019 -- Adapt the size to accommodate `count' characters.
2020 do
2021 resize (count)
2022 end
2023
2024 resize (newsize: INTEGER) is
2025 -- Rearrange string so that it can accommodate
2026 -- at least `newsize' characters.
2027 -- Do not lose any previously entered character.
2028 local
2029 area_count: INTEGER
2030 do
2031 area_count := area.count
2032 if newsize >= area_count then
2033 area := area.aliased_resized_area (newsize + 1)
2034 end
2035 end
2036
2037 grow (newsize: INTEGER) is
2038 -- Ensure that the capacity is at least `newsize'.
2039 do
2040 if newsize > capacity then
2041 resize (newsize)
2042 end
2043 end
2044
2045 feature -- Conversion
2046
2047 as_lower: like Current is
2048 -- New object with all letters in lower case.
2049 do
2050 Result := twin
2051 Result.to_lower
2052 ensure
2053 length: Result.count = count
2054 anchor: count > 0 implies Result.item (1) = item (1).as_lower
2055 recurse: count > 1 implies Result.substring (2, count).
2056 is_equal (substring (2, count).as_lower)
2057 end
2058
2059 as_upper: like Current is
2060 -- New object with all letters in upper case
2061 do
2062 Result := twin
2063 Result.to_upper
2064 ensure
2065 length: Result.count = count
2066 anchor: count > 0 implies Result.item (1) = item (1).as_upper
2067 recurse: count > 1 implies Result.substring (2, count).
2068 is_equal (substring (2, count).as_upper)
2069 end
2070
2071 left_justify is
2072 -- Left justify Current using `count' as witdth.
2073 local
2074 i, nb: INTEGER
2075 l_area: like area
2076 do
2077 -- Remove leading white spaces.
2078 nb := count
2079 left_adjust
2080
2081 -- Get new count
2082 i := count
2083 if i < nb then
2084 -- `left_adjust' did remove some characters, so we need to add
2085 -- some white spaces at the end of the string.
2086 from
2087 l_area := area
2088 until
2089 i = nb
2090 loop
2091 l_area.put (' ', i)
2092 i := i + 1
2093 end
2094 -- Restore `count'
2095 count := nb
2096 internal_hash_code := 0
2097 end
2098 end
2099
2100 center_justify is
2101 -- Center justify Current using `count' as width.
2102 local
2103 i, nb, l_offset: INTEGER
2104 left_nb_space, right_nb_space: INTEGER
2105 l_area: like area
2106 do
2107 -- Compute number of spaces at the left of current string.
2108 from
2109 nb := count
2110 l_area := area
2111 until
2112 left_nb_space = nb or else not l_area.item (left_nb_space).is_space
2113 loop
2114 left_nb_space := left_nb_space + 1
2115 end
2116
2117 -- Compute number of spaces at the right of current string.
2118 from
2119 i := nb - 1
2120 l_area := area
2121 until
2122 i = -1 or else not l_area.item (i).is_space
2123 loop
2124 right_nb_space := right_nb_space + 1
2125 i := i - 1
2126 end
2127
2128 -- We encourage that more spaces will be put to the left, when
2129 -- number of spaces is not even.
2130 l_offset := left_nb_space + right_nb_space
2131 if l_offset \\ 2 = 0 then
2132 l_offset := left_nb_space - l_offset // 2
2133 else
2134 l_offset := left_nb_space - l_offset // 2 - 1
2135 end
2136 if l_offset = 0 then
2137 -- Nothing to be done.
2138 else
2139 -- Shift characters to the right or left (depending on sign of
2140 -- `l_offset' by `l_offset' position.
2141 l_area.move_data (left_nb_space, left_nb_space - l_offset,
2142 nb - left_nb_space - right_nb_space)
2143
2144 if l_offset < 0 then
2145 -- Fill left part with spaces.
2146 l_area.fill_with (' ', left_nb_space, left_nb_space - l_offset - 1)
2147 else
2148 -- Fill right part with spaces.
2149 l_area.fill_with (' ', nb - right_nb_space - l_offset, nb - 1)
2150 end
2151 internal_hash_code := 0
2152 end
2153 end
2154
2155 right_justify is
2156 -- Right justify Current using `count' as width.
2157 local
2158 i, nb: INTEGER
2159 nb_space: INTEGER
2160 l_area: like area
2161 do
2162 nb := count
2163 right_adjust
2164 i := count
2165 nb_space := nb - i
2166 if nb_space > 0 then
2167 -- Shift characters to the right.
2168 from
2169 l_area := area
2170 variant
2171 i + 1
2172 until
2173 i = 0
2174 loop
2175 i := i - 1
2176 l_area.put (l_area.item (i), i + nb_space)
2177 end
2178
2179 -- Fill left part with spaces.
2180 from
2181 variant
2182 nb_space + 1
2183 until
2184 nb_space = 0
2185 loop
2186 nb_space := nb_space - 1
2187 l_area.put (' ', nb_space)
2188 end
2189 -- Restore `count'
2190 count := nb
2191 internal_hash_code := 0
2192 end
2193 ensure
2194 same_count: count = old count
2195 end
2196
2197 character_justify (pivot: CHARACTER; position: INTEGER) is
2198 -- Justify a string based on a `pivot'
2199 -- and the `position' it needs to be in
2200 -- the final string.
2201 -- This will grow the string if necessary
2202 -- to get the pivot in the correct place.
2203 require
2204 valid_position: position <= capacity
2205 positive_position: position >= 1
2206 pivot_not_space: pivot /= ' '
2207 not_empty: not is_empty
2208 local
2209 l_index_of_pivot, l_new_size: INTEGER
2210 l_area: like area
2211 do
2212 l_index_of_pivot := index_of (pivot, 1)
2213 if l_index_of_pivot /= 0 then
2214 if l_index_of_pivot < position then
2215 -- We need to resize Current so that we can shift Current by
2216 -- `l_index_of_pivot - position'.
2217 l_new_size := count + position - l_index_of_pivot
2218 grow (l_new_size)
2219 l_area := area
2220 l_area.move_data (0, position - l_index_of_pivot, count)
2221 l_area.fill_with (' ', 0, position - l_index_of_pivot - 1)
2222 count := l_new_size
2223 else
2224 -- Simply shift content to the left and reset trailing with spaces.
2225 l_area := area
2226 l_area.move_data (l_index_of_pivot - position, 0, count - l_index_of_pivot + position)
2227 l_area.fill_with (' ', count - l_index_of_pivot + position, count - 1)
2228 end
2229 internal_hash_code := 0
2230 end
2231 end
2232
2233 to_lower is
2234 -- Convert to lower case.
2235 local
2236 i: INTEGER
2237 a: like area
2238 do
2239 from
2240 i := count - 1
2241 a := area
2242 until
2243 i < 0
2244 loop
2245 a.put (a.item (i).lower, i)
2246 i := i - 1
2247 end
2248 internal_hash_code := 0
2249 ensure
2250 length_end_content: elks_checking implies is_equal (old as_lower)
2251 end
2252
2253 to_upper is
2254 -- Convert to upper case.
2255 local
2256 i: INTEGER
2257 a: like area
2258 do
2259 from
2260 i := count - 1
2261 a := area
2262 until
2263 i < 0
2264 loop
2265 a.put (a.item (i).upper, i)
2266 i := i - 1
2267 end
2268 internal_hash_code := 0
2269 ensure
2270 length_end_content: elks_checking implies is_equal (old as_upper)
2271 end
2272
2273 to_integer_8: INTEGER_8 is
2274 -- 8-bit integer value
2275 require
2276 is_integer_8: is_integer_8
2277 do
2278 ctoi_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_integer_8)
2279 Result := ctoi_convertor.parsed_integer_8
2280 end
2281
2282 to_integer_16: INTEGER_16 is
2283 -- 16-bit integer value
2284 require
2285 is_integer_16: is_integer_16
2286 do
2287 ctoi_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_integer_16)
2288 Result := ctoi_convertor.parsed_integer_16
2289 end
2290
2291 to_integer, to_integer_32: INTEGER is
2292 -- 32-bit integer value
2293 require
2294 is_integer: is_integer_32
2295 do
2296 ctoi_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_integer_32)
2297 Result := ctoi_convertor.parsed_integer
2298 end
2299
2300 to_integer_64: INTEGER_64 is
2301 -- 64-bit integer value
2302 require
2303 is_integer_64: is_integer_64
2304 do
2305 ctoi_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_integer_64)
2306 Result := ctoi_convertor.parsed_integer_64
2307 end
2308
2309 to_natural_8: NATURAL_8 is
2310 -- 8-bit natural value
2311 require
2312 is_natural_8: is_natural_8
2313 do
2314 ctoi_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_natural_8)
2315 Result := ctoi_convertor.parsed_natural_8
2316 end
2317
2318 to_natural_16: NATURAL_16 is
2319 -- 16-bit natural value
2320 require
2321 is_natural_16: is_natural_16
2322 do
2323 ctoi_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_natural_16)
2324 Result := ctoi_convertor.parsed_natural_16
2325 end
2326
2327 to_natural, to_natural_32: NATURAL_32 is
2328 -- 32-bit natural value
2329 require
2330 is_natural: is_natural
2331 do
2332 ctoi_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_natural_32)
2333 Result := ctoi_convertor.parsed_natural_32
2334 end
2335
2336 to_natural_64: NATURAL_64 is
2337 -- 64-bit natural value
2338 require
2339 is_natural_64: is_natural_64
2340 do
2341 ctoi_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_natural_64)
2342 Result := ctoi_convertor.parsed_natural_64
2343 end
2344
2345 to_real: REAL is
2346 -- Real value;
2347 -- for example, when applied to "123.0", will yield 123.0
2348 require
2349 represents_a_real: is_real
2350 do
2351 Result := to_double
2352 end
2353
2354 to_double: DOUBLE is
2355 -- "Double" value;
2356 -- for example, when applied to "123.0", will yield 123.0 (double)
2357 require
2358 represents_a_double: is_double
2359 do
2360 ctor_convertor.parse_string_with_type (Current, {NUMERIC_INFORMATION}.type_double)
2361 Result := ctor_convertor.parsed_double
2362 end
2363
2364 to_boolean: BOOLEAN is
2365 -- Boolean value;
2366 -- "True" yields `True', "False" yields `False'
2367 -- (case-insensitive)
2368 require
2369 is_boolean: is_boolean
2370 do
2371 check true_constant.count = 4 end
2372 if count = 4 then
2373 Result := True
2374 end
2375 ensure
2376 to_boolean: (Result = true_constant.same_string (as_lower)) or
2377 (not Result = false_constant.same_string (as_lower))
2378 end
2379
2380 linear_representation: LINEAR [CHARACTER] is
2381 -- Representation as a linear structure
2382 local
2383 temp: ARRAYED_LIST [CHARACTER]
2384 i: INTEGER
2385 do
2386 create temp.make (capacity)
2387 from
2388 i := 1
2389 until
2390 i > count
2391 loop
2392 temp.extend (item (i))
2393 i := i + 1
2394 end
2395 Result := temp
2396 end
2397
2398 split (a_separator: CHARACTER): LIST [STRING] is
2399 -- Split on `a_separator'.
2400 local
2401 l_list: ARRAYED_LIST [STRING]
2402 part: STRING
2403 i, j, c: INTEGER
2404 do
2405 c := count
2406 -- Worse case allocation: every character is a separator
2407 create l_list.make (c + 1)
2408 if c > 0 then
2409 from
2410 i := 1
2411 until
2412 i > c
2413 loop
2414 j := index_of (a_separator, i)
2415 if j = 0 then
2416 -- No separator was found, we will
2417 -- simply create a list with a copy of
2418 -- Current in it.
2419 j := c + 1
2420 end
2421 part := substring (i, j - 1)
2422 l_list.extend (part)
2423 i := j + 1
2424 end
2425 if j = c then
2426 check
2427 last_character_is_a_separator: item (j) = a_separator
2428 end
2429 -- A separator was found at the end of the string
2430 l_list.extend ("")
2431 end
2432 else
2433 -- Extend empty string, since Current is empty.
2434 l_list.extend ("")
2435 end
2436 Result := l_list
2437 check
2438 l_list.count = occurrences (a_separator) + 1
2439 end
2440 ensure
2441 Result /= Void
2442 end
2443
2444 frozen to_c: ANY is
2445 -- A reference to a C form of current string.
2446 -- Useful only for interfacing with C software.
2447 require
2448 not_is_dotnet: not {PLATFORM}.is_dotnet
2449 local
2450 l_area: like area
2451 do
2452 l_area := area
2453 l_area.put ('%U', count)
2454 Result := l_area
2455 end
2456
2457 mirrored: like Current is
2458 -- Mirror image of string;
2459 -- Result for "Hello world" is "dlrow olleH".
2460 do
2461 Result := twin
2462 if count > 0 then
2463 Result.mirror
2464 end
2465 ensure
2466 same_count: Result.count = count
2467 -- reversed: For every `i' in 1..`count', `Result'.`item' (`i') = `item' (`count'+1-`i')
2468 end
2469
2470 mirror is
2471 -- Reverse the order of characters.
2472 -- "Hello world" -> "dlrow olleH".
2473 local
2474 a: like area
2475 c: CHARACTER
2476 i, j: INTEGER
2477 do
2478 if count > 0 then
2479 from
2480 i := count - 1
2481 a := area
2482 until
2483 i <= j
2484 loop
2485 c := a.item (i)
2486 a.put (a.item (j), i)
2487 a.put (c, j)
2488 i := i - 1
2489 j := j + 1
2490 end
2491 internal_hash_code := 0
2492 end
2493 ensure
2494 same_count: count = old count
2495 -- reversed: For every `i' in 1..`count', `item' (`i') = old `item' (`count'+1-`i')
2496 end
2497
2498 feature -- Duplication
2499
2500 substring (start_index, end_index: INTEGER): like Current is
2501 -- Copy of substring containing all characters at indices
2502 -- between `start_index' and `end_index'
2503 do
2504 if (1 <= start_index) and (start_index <= end_index) and (end_index <= count) then
2505 Result := new_string (end_index - start_index + 1)
2506 Result.area.copy_data (area, start_index - 1, 0, end_index - start_index + 1)
2507 Result.set_count (end_index - start_index + 1)
2508 else
2509 Result := new_string (0)
2510 end
2511 ensure then
2512 first_item: Result.count > 0 implies Result.item (1) = item (start_index)
2513 recurse: Result.count > 0 implies
2514 Result.substring (2, Result.count).is_equal (substring (start_index + 1, end_index))
2515 end
2516
2517 multiply (n: INTEGER) is
2518 -- Duplicate a string within itself
2519 -- ("hello").multiply(3) => "hellohellohello"
2520 require
2521 meaningful_multiplier: n >= 1
2522 local
2523 s: like Current
2524 i: INTEGER
2525 do
2526 s := twin
2527 grow (n * count)
2528 from
2529 i := n
2530 until
2531 i = 1
2532 loop
2533 append (s)
2534 i := i - 1
2535 end
2536 end
2537
2538 feature -- Output
2539
2540 out: STRING is
2541 -- Printable representation
2542 do
2543 create Result.make (count)
2544 Result.append (Current)
2545 ensure then
2546 out_not_void: Result /= Void
2547 same_items: same_type ("") implies Result.same_string (Current)
2548 end
2549
2550 feature {STRING_HANDLER} -- Implementation
2551
2552 frozen set_count (number: INTEGER) is
2553 -- Set `count' to `number' of characters.
2554 do
2555 count := number
2556 internal_hash_code := 0
2557 end
2558
2559 feature {NONE} -- Empty string implementation
2560
2561 internal_hash_code: INTEGER
2562 -- Computed hash-code.
2563
2564 frozen set_internal_hash_code (v: like internal_hash_code) is
2565 -- Set `internal_hash_code' with `v'.
2566 do
2567 internal_hash_code := v
2568 end
2569
2570 feature {NONE} -- Implementation
2571
2572 new_string (n: INTEGER): like Current is
2573 -- New instance of current with space for at least `n' characters.
2574 require
2575 n_non_negative: n >= 0
2576 do
2577 create Result.make (n)
2578 ensure
2579 new_string_not_void: Result /= Void
2580 new_string_empty: Result.is_empty
2581 new_string_area_big_enough: Result.capacity >= n
2582 end
2583
2584 feature {NONE} -- Transformation
2585
2586 correct_mismatch is
2587 -- Attempt to correct object mismatch during retrieve using `mismatch_information'.
2588 do
2589 -- Nothing to be done because we only added `internal_hash_code' that will
2590 -- be recomputed next time we query `hash_code'.
2591 end
2592
2593 feature {NONE} -- Implementation
2594
2595 is_valid_integer_or_natural (type: INTEGER) : BOOLEAN is
2596 -- Is `Current' a valid number according to given `type'?
2597 do
2598 ctoi_convertor.reset (type)
2599 ctoi_convertor.parse_string_with_type (Current, type)
2600 Result := ctoi_convertor.is_integral_integer
2601 end
2602
2603 str_strict_cmp (this, other: like area; nb: INTEGER): INTEGER is
2604 -- Compare `this' and `other' strings
2605 -- for the first `nb' characters.
2606 -- 0 if equal, < 0 if `this' < `other',
2607 -- > 0 if `this' > `other'
2608 require
2609 this_not_void: this /= Void or else nb = 0
2610 other_not_void: other /= Void
2611 nb_non_negative: nb >= 0
2612 nb_valid: (this /= Void implies nb <= this.count) and nb <= other.count
2613 local
2614 i, l_current_code, l_other_code: INTEGER
2615 do
2616 from
2617 until
2618 i = nb
2619 loop
2620 l_current_code := this.item (i).code
2621 l_other_code := other.item (i).code
2622 if l_current_code /= l_other_code then
2623 Result := l_current_code - l_other_code
2624 i := nb - 1 -- Jump out of loop
2625 end
2626 i := i + 1
2627 end
2628 end
2629
2630 empty_area: SPECIAL [CHARACTER] is
2631 -- Empty `area' to avoid useless creation of empty areas when wiping out a STRING.
2632 obsolete
2633 "Simply create `area' directly."
2634 do
2635 create Result.make (1)
2636 ensure
2637 empty_area_not_void: Result /= Void
2638 end
2639
2640 invariant
2641 extendible: extendible
2642 compare_character: not object_comparison
2643 index_set_has_same_count: index_set.count = count
2644 area_not_void: area /= Void
2645
2646 end

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.23