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

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

  ViewVC Help
Powered by ViewVC 1.1.23