note
	description: "Routines that ought to be in class STRING"
	remark: "[
		Unless otherwise specified in their preconditions,
		the features of this class can deal with UC_STRING
		whenever a STRING is expected.
	]"
	library: "Gobo Eiffel Kernel Library"
	copyright: "Copyright (c) 1999-2018, Eric Bezault and others"
	license: "MIT License"
	date: "$Date: 2019-02-07 22:54:15 +0000 (Thu, 07 Feb 2019) $"
	revision: "$Revision: 102807 $"

class 
	KL_STRING_ROUTINES

create 
	default_create

feature -- Initialization

	make_buffer (n: INTEGER_32): STRING_8
			-- Create a new string containing n characters.
			-- (Not in ELKS 2001 STRING)
		require
			non_negative_n: n >= 0
		do
			create Result.make_filled ('%U', n)
		ensure
			instance_free: class
			string_not_void: Result /= Void
			string_type: Any_.same_types (Result, "")
			count_set: Result.count = n
		end

	make_from_string (s: STRING_8): STRING_8
			-- Initialize from the character sequence of s.
			-- s is considered with its characters which do not fit
			-- in a CHARACTER replaced by a '%U'.
			-- (ELKS 2001 STRING)
			-- Note: Use this routine instead of 'STRING.make_from_string (s)'
			-- when s is of dynamic type other than STRING (e.g. UC_STRING)
			-- because the class STRING provided with the Eiffel compilers
			-- is not necessarily aware of the implementation of UC_STRING
			-- and this may lead to run-time errors or crashes.
		require
			s_not_void: s /= Void
		local
			i, j, nb: INTEGER_32
		do
			if Any_.same_types (s, Dummy_string) then
				create Result.make_from_string (s)
			else
				nb := s.count
				create Result.make (nb)
				if attached {UC_STRING} s as uc_string then
					nb := uc_string.byte_count
					from
						j := 1
					until
						j > nb
					loop
						Result.append_character (uc_string.character_item_at_byte_index (j))
						j := uc_string.next_byte_index (j)
					end
				else
					from
						i := 1
					until
						i > nb
					loop
						Result.append_character (s.item (i))
						i := i + 1
					end
				end
			end
		ensure
			instance_free: class
			string_not_void: Result /= Void
			new_string: Result /= s
			string_type: Any_.same_types (Result, "")
			initialized: elks_same_string (Result, s)
		end
	
feature {NONE} -- Initialization

	default_create
			-- Process instances of classes with no creation clause.
			-- (Default: do nothing.)
			-- (from ANY)
		do
		end
	
feature -- Access

	Any_: KL_ANY_ROUTINES
			-- Routines that ought to be in class ANY
			-- (from KL_IMPORTED_ANY_ROUTINES)
		once
			create Result
		ensure -- from KL_IMPORTED_ANY_ROUTINES
			instance_free: class
			any_routines_not_void: Result /= Void
		end

	case_insensitive_hash_code (a_string: STRING_8): INTEGER_32
			-- Hash code value of a_string which doesn't
			-- take case sensitivity into account
			-- (Not in ELKS 2001 STRING)
		require
			a_string_not_void: a_string /= Void
		local
			i, nb: INTEGER_32
		do
			nb := a_string.count
			from
				i := 1
			until
				i > nb
			loop
				Result := ((Result \\ 8388593) |<< 8) + a_string.item (i).upper.code
				i := i + 1
			end
			if Result < 0 then
				Result := - (Result + 1)
			end
		ensure
			instance_free: class
			hash_code_not_negative: Result >= 0
		end

	Character_: KL_CHARACTER_ROUTINES
			-- Routines that ought to be in class CHARACTER
			-- (from KL_IMPORTED_CHARACTER_ROUTINES)
		once
			create Result
		ensure -- from KL_IMPORTED_CHARACTER_ROUTINES
			instance_free: class
			character_routines_not_void: Result /= Void
		end

	concat (a_string, other: STRING_8): STRING_8
			-- New object which contains the characters of a_string
			-- followed by the characters of other; If other is
			-- of dynamic type UC_STRING or one of its descendants and
			-- a_string is not, then the dynamic type of the result
			-- is the same as the dynamic type of other. Otherwise
			-- the result is similar to 'a_string + other';
			-- Note: Use this routine instead of 'a_string + other' or
			-- 'a_string.append_string (other)' when a_string
			-- can be of dynamic type STRING and other of dynamic
			-- type other than STRING such as UC_STRING, because class
			-- STRING provided by the Eiffel compilers is not necessarily
			-- aware of the implementation of UC_STRING and this may
			-- lead to run-time errors or crashes.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		do
			if attached {UC_STRING} a_string as uc_string then
				Result := uc_string + other
			elseif attached {UC_STRING} other as uc_string then
				Result := uc_string.prefixed_string (a_string)
			else
				Result := a_string + other
			end
		ensure
			instance_free: class
			concat_not_void: Result /= Void
			concat_count: Result.count = a_string.count + other.count
			initial: same_string (Result.substring (1, a_string.count), a_string)
			final: same_string (Result.substring (a_string.count + 1, Result.count), other)
		end

	generating_type: TYPE [detachable KL_STRING_ROUTINES]
			-- Type of current object
			-- (type of which it is a direct instance)
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			generating_type_not_void: Result /= Void
		end

	generator: STRING_8
			-- Name of current object's generating class
			-- (base class of the type of which it is a direct instance)
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			generator_not_void: Result /= Void
			generator_not_empty: not Result.is_empty
		end

	Integer_: KL_INTEGER_ROUTINES
			-- Routines that ought to be in class INTEGER
			-- (from KL_IMPORTED_INTEGER_ROUTINES)
		once
			create Result
		ensure -- from KL_IMPORTED_INTEGER_ROUTINES
			instance_free: class
			integer_routines_not_void: Result /= Void
		end

	new_empty_string (a_string: STRING_8; n: INTEGER_32): STRING_8
			-- New empty string with same dynamic type as a_string;
			-- Try to allocate space for at least n characters.
			-- (Not in ELKS 2001 STRING)
		require
			a_string_not_void: a_string /= Void
			non_negative_n: n >= 0
		do
			if Any_.same_types (a_string, Dummy_string) then
				create Result.make (n)
			else
				if attached {UC_STRING} a_string as uc_string then
					Result := uc_string.new_empty_string (n)
				else
					Result := cloned_string (a_string)
					Result.wipe_out
				end
			end
		ensure
			instance_free: class
			new_string_not_void: Result /= Void
			same_type: Any_.same_types (Result, a_string)
			new_string_empty: Result.count = 0
		end

	Platform: KL_PLATFORM
			-- Platform-dependent properties
			-- (from KL_SHARED_PLATFORM)
		once
			create Result
		ensure -- from KL_SHARED_PLATFORM
			instance_free: class
			platform_not_void: Result /= Void
		end

	substring_index (a_string, other: STRING_8; start_index: INTEGER_32): INTEGER_32
			-- Index of first occurrence of other at or after start_index in
			-- a_string; 0 if none. a_string and other are considered with
			-- their characters which do not fit in a CHARACTER replaced by a '%U'.
			-- (ELKS 2001 STRING)
			-- Note: Use this feature instead of 'a_string.substring_index (other,
			-- start_index)' when a_string can be of dynamic type STRING and
			-- other of dynamic type other than STRING such as UC_STRING, because
			-- class STRING provided by the Eiffel compilers is not necessarily
			-- aware of the implementation of UC_STRING and this may lead to
			-- run-time errors or crashes.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
			valid_start_index: start_index >= 1 and start_index <= a_string.count + 1
		local
			i, j, nb: INTEGER_32
			a_code: INTEGER_32
			k, end_index: INTEGER_32
			found: BOOLEAN
			max_code: INTEGER_32
			other_count: INTEGER_32
		do
			if other = a_string then
				if start_index = 1 then
					Result := 1
				end
			else
				other_count := other.count
				if other_count = 0 then
					Result := start_index
				else
					end_index := a_string.count - other_count + 1
					if start_index <= end_index then
						if Any_.same_types (a_string, Dummy_string) then
							if Any_.same_types (other, Dummy_string) then
								Result := a_string.substring_index (other, start_index)
							elseif attached {UC_STRING} other as other_unicode then
								nb := other_unicode.byte_count
								max_code := Platform.Maximum_character_code
								from
									k := start_index
								until
									k > end_index
								loop
									j := k
									found := True
									from
										i := 1
									until
										i > nb
									loop
										a_code := other_unicode.item_code_at_byte_index (i)
										if a_code > max_code then
											a_code := 0
										end
										if a_string.item_code (j) /= a_code then
											found := False
											i := nb + 1
										else
											j := j + 1
											i := other_unicode.next_byte_index (i)
										end
									end
									if found then
										Result := k
										k := end_index + 1
									else
										k := k + 1
									end
								end
							else
								nb := other_count
								from
									k := start_index
								until
									k > end_index
								loop
									j := k
									found := True
									from
										i := 1
									until
										i > nb
									loop
										if a_string.item (j) /= other.item (i) then
											found := False
											i := nb + 1
										else
											j := j + 1
											i := i + 1
										end
									end
									if found then
										Result := k
										k := end_index + 1
									else
										k := k + 1
									end
								end
							end
						else
							Result := a_string.substring_index (other, start_index)
						end
					end
				end
			end
		ensure
			instance_free: class
			valid_result: Result = 0 or else (start_index <= Result and Result <= a_string.count - other.count + 1)
			zero_if_absent: (Result = 0) = not has_substring (a_string.substring (start_index, a_string.count), other)
			at_this_index: Result >= start_index implies elks_same_string (other, a_string.substring (Result, Result + other.count - 1))
			none_before: Result > start_index implies not has_substring (a_string.substring (start_index, Result + other.count - 2), other)
		end

	to_utf16_be (a_string: STRING_8): STRING_8
			-- New STRING made up of bytes corresponding to
			-- the UTF-16BE representation of a_string
		require
			a_string_not_void: a_string /= Void
		local
			i, nb, a_code, a_high, a_low, a_surrogate: INTEGER_32
		do
			if attached {UC_STRING} a_string as uc_string then
				Result := uc_string.to_utf16_be
			else
				nb := a_string.count
				create Result.make (nb)
				from
					i := 1
				until
					i > nb
				loop
					a_code := a_string.item_code (i)
					if Unicode.is_bmp_code (a_code) then
						a_high := a_code // 256
						a_low := a_code \\ 256
						Result.append_character (Integer_.to_character (a_high))
						Result.append_character (Integer_.to_character (a_low))
					else
						a_surrogate := Utf16.supplementary_to_high_surrogate (a_code)
						a_high := a_surrogate // 256
						a_low := a_surrogate \\ 256
						Result.append_character (Integer_.to_character (a_high))
						Result.append_character (Integer_.to_character (a_low))
						a_surrogate := Utf16.supplementary_to_low_surrogate (a_code)
						a_high := a_surrogate // 256
						a_low := a_surrogate \\ 256
						Result.append_character (Integer_.to_character (a_high))
						Result.append_character (Integer_.to_character (a_low))
					end
					i := i + 1
				end
			end
		ensure
			instance_free: class
			to_utf16_be_not_void: Result /= Void
			string_type: Any_.same_types (Result, "")
			valid_utf16: Utf16.valid_utf16 (Result)
		end

	to_utf16_le (a_string: STRING_8): STRING_8
			-- New STRING made up of bytes corresponding to
			-- the UTF-16LE representation of a_string
		require
			a_string_not_void: a_string /= Void
		local
			i, nb, a_code, a_high, a_low, a_surrogate: INTEGER_32
		do
			if attached {UC_STRING} a_string as uc_string then
				Result := uc_string.to_utf16_le
			else
				nb := a_string.count
				create Result.make (nb)
				from
					i := 1
				until
					i > nb
				loop
					a_code := a_string.item_code (i)
					if Unicode.is_bmp_code (a_code) then
						a_high := a_code // 256
						a_low := a_code \\ 256
						Result.append_character (Integer_.to_character (a_low))
						Result.append_character (Integer_.to_character (a_high))
					else
						a_surrogate := Utf16.supplementary_to_high_surrogate (a_code)
						a_high := a_surrogate // 256
						a_low := a_surrogate \\ 256
						Result.append_character (Integer_.to_character (a_low))
						Result.append_character (Integer_.to_character (a_high))
						a_surrogate := Utf16.supplementary_to_low_surrogate (a_code)
						a_high := a_surrogate // 256
						a_low := a_surrogate \\ 256
						Result.append_character (Integer_.to_character (a_low))
						Result.append_character (Integer_.to_character (a_high))
					end
					i := i + 1
				end
			end
		ensure
			instance_free: class
			to_utf16_le_not_void: Result /= Void
			string_type: Any_.same_types (Result, "")
			valid_utf16: Utf16.valid_utf16 (Utf16.Bom_le + Result)
		end

	to_utf32_be (a_string: STRING_8): STRING_8
			-- New STRING made up of bytes corresponding to
			-- the UTF-32BE representation of a_string
		require
			a_string_not_void: a_string /= Void
		local
			i, j, k, l, m, nb, a_code: INTEGER_32
		do
			if attached {UC_STRING} a_string as uc_string then
				Result := uc_string.to_utf32_be
			else
				nb := a_string.count
				create Result.make (4 * nb)
				from
					i := 1
				until
					i > nb
				loop
					a_code := a_string.item_code (i)
					m := a_code \\ 256
					a_code := a_code // 256
					l := a_code \\ 256
					a_code := a_code // 256
					j := a_code // 256
					k := a_code \\ 256
					Result.append_character (Integer_.to_character (j))
					Result.append_character (Integer_.to_character (k))
					Result.append_character (Integer_.to_character (l))
					Result.append_character (Integer_.to_character (m))
					i := i + 1
				end
			end
		ensure
			instance_free: class
			to_utf32_be_not_void: Result /= Void
			string_type: Any_.same_types (Result, "")
			valid_utf32: Utf32.valid_utf32 (Result)
		end

	to_utf32_le (a_string: STRING_8): STRING_8
			-- New STRING made up of bytes corresponding to
			-- the UTF-32LE representation of a_string
		require
			a_string_not_void: a_string /= Void
		local
			i, j, k, l, m, nb, a_code: INTEGER_32
		do
			if attached {UC_STRING} a_string as uc_string then
				Result := uc_string.to_utf32_le
			else
				nb := a_string.count
				create Result.make (4 * nb)
				from
					i := 1
				until
					i > nb
				loop
					a_code := a_string.item_code (i)
					m := a_code \\ 256
					a_code := a_code // 256
					l := a_code \\ 256
					a_code := a_code // 256
					j := a_code // 256
					k := a_code \\ 256
					Result.append_character (Integer_.to_character (m))
					Result.append_character (Integer_.to_character (l))
					Result.append_character (Integer_.to_character (k))
					Result.append_character (Integer_.to_character (j))
					i := i + 1
				end
			end
		ensure
			instance_free: class
			to_utf32_le_not_void: Result /= Void
			string_type: Any_.same_types (Result, "")
			valid_utf32: Utf32.valid_utf32 (Utf32.Bom_le + Result)
		end

	Unicode: UC_UNICODE_ROUTINES
			-- Unicode routines
			-- (from UC_IMPORTED_UNICODE_ROUTINES)
		once
			create Result
		ensure -- from UC_IMPORTED_UNICODE_ROUTINES
			instance_free: class
			unicode_not_void: Result /= Void
		end

	Utf16: UC_UTF16_ROUTINES
			-- UTF-16 encoding routines
			-- (from UC_IMPORTED_UTF16_ROUTINES)
		once
			create Result
		ensure -- from UC_IMPORTED_UTF16_ROUTINES
			instance_free: class
			utf16_not_void: Result /= Void
		end

	Utf32: UC_UTF32_ROUTINES
			-- UTF-32 encoding routines
			-- (from UC_IMPORTED_UTF32_ROUTINES)
		once
			create Result
		ensure -- from UC_IMPORTED_UTF32_ROUTINES
			instance_free: class
			utf32_not_void: Result /= Void
		end
	
feature -- Comparison

	frozen deep_equal (a: detachable ANY; b: like arg #1): BOOLEAN
			-- Are a and b either both void
			-- or attached to isomorphic object structures?
			-- (from ANY)
		do
			if a = Void then
				Result := b = Void
			else
				Result := b /= Void and then a.is_deep_equal (b)
			end
		ensure -- from ANY
			instance_free: class
			shallow_implies_deep: standard_equal (a, b) implies Result
			both_or_none_void: (a = Void) implies (Result = (b = Void))
			same_type: (Result and (a /= Void)) implies (b /= Void and then a.same_type (b))
			symmetric: Result implies deep_equal (b, a)
		end

	elks_same_string (a_string, other: STRING_8): BOOLEAN
			-- Do a_string and other have the same character sequence?
			-- a_string and other are considered with their characters
			-- which do not fit in a CHARACTER replaced by a '%U'.
			-- (Extended from ELKS 2001 STRING)
			-- Note: Use this feature instead of 'a_string.same_string
			-- (other)' when a_string can be of dynamic type STRING and
			-- other of dynamic type other than STRING such as UC_STRING,
			-- because class STRING provided by the Eiffel compilers is
			-- not necessarily aware of the implementation of UC_STRING
			-- and this may lead to run-time errors or crashes.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		do
			if other = a_string then
				Result := True
			elseif other.count = a_string.count then
				if Any_.same_types (other, Dummy_string) then
					Result := a_string.same_string (other)
				else
					Result := other.same_string (a_string)
				end
			end
		ensure
			instance_free: class
			definition: Result = a_string.string.is_equal (other.string)
		end

	frozen equal (a: detachable ANY; b: like arg #1): BOOLEAN
			-- Are a and b either both void or attached
			-- to objects considered equal?
			-- (from ANY)
		do
			if a = Void then
				Result := b = Void
			else
				Result := b /= Void and then a.is_equal (b)
			end
		ensure -- from ANY
			instance_free: class
			definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.is_equal (b))
		end

	frozen is_deep_equal (other: KL_STRING_ROUTINES): BOOLEAN
			-- Are Current and other attached to isomorphic object structures?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			shallow_implies_deep: standard_is_equal (other) implies Result
			same_type: Result implies same_type (other)
			symmetric: Result implies other.is_deep_equal (Current)
		end

	is_equal (other: KL_STRING_ROUTINES): BOOLEAN
			-- Is other attached to an object considered
			-- equal to current object?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			symmetric: Result implies other ~ Current
			consistent: standard_is_equal (other) implies Result
		end

	is_less (a_string, other: STRING_8): BOOLEAN
			-- Is a_string considered less than other?
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		do
			Result := three_way_comparison (a_string, other) = -1
		ensure
			instance_free: class
		end

	same_case_insensitive (s1, s2: STRING_8): BOOLEAN
			-- Are s1 and s2 made up of the same
			-- characters (case insensitive)?
			-- (Not in ELKS 2001 STRING)
		require
			s1_not_void: s1 /= Void
			s2_not_void: s2 /= Void
		local
			c1, c2: CHARACTER_8
			a_code1, a_code2: INTEGER_32
			i, nb: INTEGER_32
		do
			if s1 = s2 then
				Result := True
			elseif s1.count = s2.count then
				nb := s1.count
				Result := True
				if not (Any_.same_types (s1, Dummy_string) and Any_.same_types (s2, Dummy_string)) then
					from
						i := 1
					until
						i > nb
					loop
						a_code1 := s1.item_code (i)
						a_code2 := s2.item_code (i)
						if a_code1 = a_code2 then
							i := i + 1
						elseif Unicode.lower_code (a_code1) = Unicode.lower_code (a_code2) then
							i := i + 1
						else
							Result := False
							i := nb + 1
						end
					end
				else
					from
						i := 1
					until
						i > nb
					loop
						c1 := s1.item (i)
						c2 := s2.item (i)
						if c1 = c2 then
							i := i + 1
						elseif c1.lower = c2.lower then
							i := i + 1
						else
							Result := False
							i := nb + 1
						end
					end
				end
			end
		ensure
			instance_free: class
		end

	same_string (a_string, other: STRING_8): BOOLEAN
			-- Do a_string and other have the same unicode character sequence?
			-- (Not in ELKS 2001 STRING)
			-- Note: the difference with elks_same_string is that here the
			-- implementation uses STRING.item_code instead of STRING.item
			-- and hence characters which have different codes are not
			-- considered equal even if they do not fit into a CHARACTER.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		local
			i, nb: INTEGER_32
		do
			if other = a_string then
				Result := True
			elseif other.count = a_string.count then
				if attached {UC_STRING} a_string as uc_string then
					Result := uc_string.same_unicode_string (other)
				elseif attached {UC_STRING} other as uc_string then
					Result := uc_string.same_unicode_string (a_string)
				elseif Any_.same_types (a_string, Dummy_string) and Any_.same_types (other, Dummy_string) then
					Result := elks_same_string (a_string, other)
				else
					Result := True
					nb := a_string.count
					from
						i := 1
					until
						i > nb
					loop
						if a_string.item_code (i) /= other.item_code (i) then
							Result := False
							i := nb + 1
						else
							i := i + 1
						end
					end
				end
			end
		ensure
			instance_free: class
			definition: Result = (a_string.count = other.count and then (a_string.count > 0 implies (a_string.item_code (1) = other.item_code (1) and (a_string.count >= 2 implies same_string (a_string.substring (2, a_string.count), other.substring (2, a_string.count))))))
			elks_same_string: Result implies elks_same_string (a_string, other)
		end

	frozen standard_equal (a: detachable ANY; b: like arg #1): BOOLEAN
			-- Are a and b either both void or attached to
			-- field-by-field identical objects of the same type?
			-- Always uses default object comparison criterion.
			-- (from ANY)
		do
			if a = Void then
				Result := b = Void
			else
				Result := b /= Void and then a.standard_is_equal (b)
			end
		ensure -- from ANY
			instance_free: class
			definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.standard_is_equal (b))
		end

	frozen standard_is_equal (other: KL_STRING_ROUTINES): BOOLEAN
			-- Is other attached to an object of the same type
			-- as current object, and field-by-field identical to it?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			same_type: Result implies same_type (other)
			symmetric: Result implies other.standard_is_equal (Current)
		end

	three_way_case_insensitive_comparison (a_string, other: STRING_8): INTEGER_32
			-- If a_string equal to other, 0; if smaller, -1; if greater, 1
			-- (case insensitive comparison)
			-- (Not in ELKS 2001 STRING)
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		do
			Result := three_way_lower_case_comparison (a_string, other)
		ensure
			instance_free: class
		end

	three_way_comparison (a_string, other: STRING_8): INTEGER_32
			-- If a_string equal to other, 0;
			-- if smaller, -1; if greater, 1
			-- (ELKS 2001 STRING)
			-- Note: there is a bug in the specification of the
			-- contracts of three_way_comparison from class
			-- COMPARABLE. This routine cannot satisfy its
			-- postconditions if other is not of the same type
			-- as Current because the postcondition uses is_equal
			-- and is_equal has a postcondition inherited from
			-- ANY which says if it returns true then other has
			-- the same type as Current. The current feature
			-- three_way_comparison in class KL_STRING_ROTUINES
			-- solves this problem and make the comparison
			-- polymorphically safe by changing the signature
			-- from 'like Current' to 'STRING' and by using
			-- STRING_.same_string instead of is_equal in
			-- its postcondition.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		local
			i, nb, nb1, nb2: INTEGER_32
			a1, a2: CHARACTER_8
			c1, c2: INTEGER_32
			found: BOOLEAN
		do
			if other = a_string then
				Result := 0
			elseif Any_.same_types (a_string, Dummy_string) and Any_.same_types (other, Dummy_string) then
				nb1 := a_string.count
				nb2 := other.count
				if nb1 < nb2 then
					nb := nb1
				else
					nb := nb2
				end
				from
					i := 1
				until
					i > nb
				loop
					a1 := a_string.item (i)
					a2 := other.item (i)
					if a1 = a2 then
						i := i + 1
					elseif a1 < a2 then
						found := True
						Result := -1
						i := nb + 1
					else
						found := True
						Result := 1
						i := nb + 1
					end
				end
				if not found then
					if nb1 < nb2 then
						Result := -1
					elseif nb1 /= nb2 then
						Result := 1
					end
				end
			elseif attached {UC_STRING} a_string as uc_string then
				Result := uc_string.three_way_unicode_comparison (other)
			elseif attached {UC_STRING} other as uc_string then
				Result := - uc_string.three_way_unicode_comparison (a_string)
			else
				nb1 := a_string.count
				nb2 := other.count
				if nb1 < nb2 then
					nb := nb1
				else
					nb := nb2
				end
				from
					i := 1
				until
					i > nb
				loop
					c1 := a_string.item_code (i)
					c2 := other.item_code (i)
					if c1 = c2 then
						i := i + 1
					elseif c1 < c2 then
						found := True
						Result := -1
						i := nb + 1
					else
						found := True
						Result := 1
						i := nb + 1
					end
				end
				if not found then
					if nb1 < nb2 then
						Result := -1
					elseif nb1 /= nb2 then
						Result := 1
					end
				end
			end
		ensure
			instance_free: class
			equal_zero: (Result = 0) = same_string (a_string, other)
		end

	three_way_lower_case_comparison (a_string, other: STRING_8): INTEGER_32
			-- If a_string equal to other, 0; if smaller, -1; if greater, 1
			-- (case insensitive comparison, consider letters as lower-case)
			-- (Not in ELKS 2001 STRING)
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		local
			i, nb, nb1, nb2: INTEGER_32
			c1, c2: CHARACTER_8
			d1, d2: INTEGER_32
			found: BOOLEAN
		do
			if other = a_string then
				Result := 0
			elseif Any_.same_types (a_string, Dummy_string) and Any_.same_types (other, Dummy_string) then
				nb1 := a_string.count
				nb2 := other.count
				if nb1 < nb2 then
					nb := nb1
				else
					nb := nb2
				end
				from
					i := 1
				until
					i > nb
				loop
					c1 := a_string.item (i)
					c2 := other.item (i)
					if c1 = c2 then
						i := i + 1
					else
						c1 := c1.lower
						c2 := c2.lower
						if c1 = c2 then
							i := i + 1
						elseif c1 < c2 then
							found := True
							Result := -1
							i := nb + 1
						else
							found := True
							Result := 1
							i := nb + 1
						end
					end
				end
				if not found then
					if nb1 < nb2 then
						Result := -1
					elseif nb1 /= nb2 then
						Result := 1
					end
				end
			else
				nb1 := a_string.count
				nb2 := other.count
				if nb1 < nb2 then
					nb := nb1
				else
					nb := nb2
				end
				from
					i := 1
				until
					i > nb
				loop
					d1 := a_string.item_code (i)
					d2 := other.item_code (i)
					if d1 = d2 then
						i := i + 1
					else
						d1 := Unicode.lower_code (d1)
						d2 := Unicode.lower_code (d2)
						if d1 = d2 then
							i := i + 1
						elseif d1 < d2 then
							found := True
							Result := -1
							i := nb + 1
						else
							found := True
							Result := 1
							i := nb + 1
						end
					end
				end
				if not found then
					if nb1 < nb2 then
						Result := -1
					elseif nb1 /= nb2 then
						Result := 1
					end
				end
			end
		ensure
			instance_free: class
		end

	three_way_upper_case_comparison (a_string, other: STRING_8): INTEGER_32
			-- If a_string equal to other, 0; if smaller, -1; if greater, 1
			-- (case insensitive comparison, consider letters as upper-case)
			-- (Not in ELKS 2001 STRING)
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		local
			i, nb, nb1, nb2: INTEGER_32
			c1, c2: CHARACTER_8
			d1, d2: INTEGER_32
			found: BOOLEAN
		do
			if other = a_string then
				Result := 0
			elseif Any_.same_types (a_string, Dummy_string) and Any_.same_types (other, Dummy_string) then
				nb1 := a_string.count
				nb2 := other.count
				if nb1 < nb2 then
					nb := nb1
				else
					nb := nb2
				end
				from
					i := 1
				until
					i > nb
				loop
					c1 := a_string.item (i)
					c2 := other.item (i)
					if c1 = c2 then
						i := i + 1
					else
						c1 := c1.upper
						c2 := c2.upper
						if c1 = c2 then
							i := i + 1
						elseif c1 < c2 then
							found := True
							Result := -1
							i := nb + 1
						else
							found := True
							Result := 1
							i := nb + 1
						end
					end
				end
				if not found then
					if nb1 < nb2 then
						Result := -1
					elseif nb1 /= nb2 then
						Result := 1
					end
				end
			else
				nb1 := a_string.count
				nb2 := other.count
				if nb1 < nb2 then
					nb := nb1
				else
					nb := nb2
				end
				from
					i := 1
				until
					i > nb
				loop
					d1 := a_string.item_code (i)
					d2 := other.item_code (i)
					if d1 = d2 then
						i := i + 1
					else
						d1 := Unicode.upper_code (d1)
						d2 := Unicode.upper_code (d2)
						if d1 = d2 then
							i := i + 1
						elseif d1 < d2 then
							found := True
							Result := -1
							i := nb + 1
						else
							found := True
							Result := 1
							i := nb + 1
						end
					end
				end
				if not found then
					if nb1 < nb2 then
						Result := -1
					elseif nb1 /= nb2 then
						Result := 1
					end
				end
			end
		ensure
			instance_free: class
		end
	
feature -- Status report

	conforms_to (other: ANY): BOOLEAN
			-- Does type of current object conform to type
			-- of other (as per Eiffel: The Language, chapter 13)?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		end

	has_substring (a_string, other: STRING_8): BOOLEAN
			-- Does a_string contain other? a_string and other
			-- are considered with their characters which do not fit
			-- in a CHARACTER replaced by a '%U'.
			-- (Extended from ELKS 2001 STRING)
			-- Note: Use this feature instead of 'a_string.has_substring
			-- (other)' when a_string can be of dynamic type STRING and
			-- other of dynamic type other than STRING such as UC_STRING,
			-- because class STRING provided by the Eiffel compilers is
			-- not necessarily aware of the implementation of UC_STRING
			-- and this may lead to run-time errors or crashes.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		do
			if other = a_string then
				Result := True
			elseif other.count <= a_string.count then
				Result := substring_index (a_string, other, 1) /= 0
			end
		ensure
			instance_free: class
			false_if_too_small: a_string.count < other.count implies not Result
			true_if_initial: (a_string.count >= other.count and then elks_same_string (other, a_string.substring (1, other.count))) implies Result
			recurse: (a_string.count >= other.count and then not elks_same_string (other, a_string.substring (1, other.count))) implies (Result = has_substring (a_string.substring (2, a_string.count), other))
		end

	is_base64 (a_string: STRING_8): BOOLEAN
			-- Is a string made up of characters +, /, =, XML whitespace, 0-9 or A-Z or a-z?
			-- (Not in ELKS 2001 STRING)
		require
			a_string_not_void: a_string /= Void
		local
			i, nb: INTEGER_32
			c: CHARACTER_8
		do
			nb := a_string.count
			if nb = 0 then
				Result := False
			else
				Result := True
				from
					i := 1
				until
					i > nb
				loop
					c := a_string.item (i)
					if (c < '0' or c > '9') and (c < 'a' or c > 'z') and (c < 'A' or c > 'Z') and c /= '+' and c /= '/' and c /= '=' and c /= ' ' and c /= '%T' and c /= '%R' and c /= '%N' then
						Result := False
						i := nb + 1
					else
						i := i + 1
					end
				end
			end
		ensure
			instance_free: class
		end

	is_decimal (a_string: STRING_8): BOOLEAN
			-- Is a_string only made up of characters 0-9?
			-- (Not in ELKS 2001 STRING)
		require
			a_string_not_void: a_string /= Void
		local
			i, nb: INTEGER_32
			c: CHARACTER_8
		do
			nb := a_string.count
			if nb = 0 then
				Result := False
			else
				Result := True
				from
					i := 1
				until
					i > nb
				loop
					c := a_string.item (i)
					if c < '0' or c > '9' then
						Result := False
						i := nb + 1
					else
						i := i + 1
					end
				end
			end
		ensure
			instance_free: class
		end

	is_hexadecimal (a_string: STRING_8): BOOLEAN
			-- Is a string made up of characters 0-9 or A-F or a-f?
			-- (Not in ELKS 2001 STRING)
		require
			a_string_not_void: a_string /= Void
		local
			i, nb: INTEGER_32
			c: CHARACTER_8
		do
			nb := a_string.count
			if nb = 0 then
				Result := False
			else
				Result := True
				from
					i := 1
				until
					i > nb
				loop
					c := a_string.item (i)
					if (c < '0' or c > '9') and (c < 'a' or c > 'f') and (c < 'A' or c > 'F') then
						Result := False
						i := nb + 1
					else
						i := i + 1
					end
				end
			end
		ensure
			instance_free: class
		end

	is_integer_64 (a_string: STRING_8): BOOLEAN
			-- Does a_string represent a positive INTEGER_64?
		require
			a_string_not_void: a_string /= Void
		local
			i, j, k, l, m: INTEGER_32
			l_is_negative: BOOLEAN
			c: CHARACTER_8
		do
			i := a_string.count
			if i > 0 then
				k := 1
				c := a_string.item (1)
				if c = '+' then
					k := k + 1
				elseif c = '-' then
					k := k + 1
					l_is_negative := True
				end
				from
					j := k
				until
					k /= j or j > i
				loop
					if a_string.item (j) = '0' then
						k := k + 1
					end
					j := j + 1
				end
				i := i - k + 1
				if i < 20 then
					Result := True
					from
						l := k
					until
						l > i + k - 1
					loop
						c := a_string.item (l)
						if c < '0' or c > '9' then
							Result := False
							l := i + k + 1
						else
							l := l + 1
						end
					end
					if Result and i = 19 then
						from
							l := a_string.count
							m := l - i
						until
							not Result or k > l
						loop
							j := a_string.item_code (k) - Code_zero
							if l_is_negative then
								i := Min_negative_integer_64_digits.item (k - m)
							else
								i := Max_integer_64_digits.item (k - m)
							end
							if j < i then
								Result := True
								k := l + 1
							else
								Result := j = i
								k := k + 1
							end
						end
					end
				end
			end
		ensure
			instance_free: class
		end

	same_type (other: ANY): BOOLEAN
			-- Is type of current object identical to type of other?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			definition: Result = (conforms_to (other) and other.conforms_to (Current))
		end
	
feature -- Element change

	append_substring_to_string (a_string: STRING_8; other: STRING_8; s, e: INTEGER_32)
			-- Append substring of other between indexes
			-- s and e at end of a_string.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
			same_type: Any_.same_types (other, a_string)
			s_large_enough: s >= 1
			e_small_enough: e <= other.count
			valid_interval: s <= e + 1
		local
			i: INTEGER_32
		do
			if attached {UC_STRING} a_string as uc_string then
				uc_string.gobo_append_substring (other, s, e)
			else
				from
					i := s
				until
					i > e
				loop
					a_string.append_character (other.item (i))
					i := i + 1
				end
			end
		ensure
			instance_free: class
			appended: a_string.is_equal (old cloned_string (a_string) + old other.substring (s, e))
		end

	appended_string (a_string, other: STRING_8): STRING_8
			-- If the dynamic type of other is UC_STRING or one of
			-- its descendants and a_string is not, then return a
			-- new object with the same dynamic type as other and
			-- which contains the characters of a_string followed
			-- by the characters of other. Otherwise append the
			-- characters of other to a_string and return a_string.
			-- Note: Use this routine instead of 'a_string.append_string (other)'
			-- when a_string can be of dynamic type STRING and other
			-- of dynamic type other than STRING such as UC_STRING, because
			-- class STRING provided by the Eiffel compilers is not necessarily
			-- aware of the implementation of UC_STRING and this may
			-- lead to run-time errors or crashes.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
		do
			if attached {UC_STRING} a_string as uc_string then
				uc_string.append_string (other)
				Result := uc_string
			elseif attached {UC_STRING} other as uc_string then
				Result := concat (a_string, other)
			else
				a_string.append_string (other)
				Result := a_string
			end
		ensure
			instance_free: class
			append_not_void: Result /= Void
			type_if_not_aliased: Result /= a_string implies Any_.same_types (Result, other)
			new_count: Result.count = old a_string.count + old other.count
			initial: same_string (Result.substring (1, old a_string.count), old cloned_string (a_string))
			final: same_string (Result.substring (old a_string.count + 1, Result.count), old cloned_string (other))
		end

	appended_substring (a_string, other: STRING_8; s, e: INTEGER_32): STRING_8
			-- If the dynamic type of other is UC_STRING or one of
			-- its descendants and a_string is not, then return a
			-- new object with the same dynamic type as other and
			-- which contains the characters of a_string followed by
			-- the characters of other between indexes s and e.
			-- Otherwise append the characters of other between s
			-- and e to a_string and return a_string.
			-- Note: Use this routine instead of 'a_string.append_string
			-- (other.substring (s, e)' when a_string can be of dynamic
			-- type STRING and other of dynamic type other than STRING
			-- such as UC_STRING, because class STRING provided by the
			-- Eiffel compilers is not necessarily aware of the
			-- implementation of UC_STRING and this may lead to run-time
			-- errors or crashes.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
			s_large_enough: s >= 1
			e_small_enough: e <= other.count
			valid_interval: s <= e + 1
		local
			l_uc_string: UC_STRING
			i: INTEGER_32
		do
			if attached {UC_STRING} a_string as uc_string then
				uc_string.gobo_append_substring (other, s, e)
				Result := uc_string
			elseif attached {UC_STRING} other as l_other_uc_string then
				l_uc_string := l_other_uc_string.new_empty_string (a_string.count + e - s + 1)
				l_uc_string.append_string (a_string)
				l_uc_string.gobo_append_substring (other, s, e)
				Result := l_uc_string
			else
				from
					i := s
				until
					i > e
				loop
					a_string.append_character (other.item (i))
					i := i + 1
				end
				Result := a_string
			end
		ensure
			instance_free: class
			append_not_void: Result /= Void
			type_if_not_aliased: Result /= a_string implies Any_.same_types (Result, other)
			new_count: Result.count = old a_string.count + e - s + 1
			initial: same_string (Result.substring (1, old a_string.count), old cloned_string (a_string))
			final: same_string (Result.substring (old a_string.count + 1, Result.count), old other.substring (s, e))
		end

	replaced_all_substrings (a_text, a_old, a_new: STRING_8): STRING_8
			-- Copy of a_text for which each occurrence of a_old has been replaced
			-- by a_new; a_text if no occurrence could be found
		require
			a_text_not_void: a_text /= Void
			a_old_not_void: a_old /= Void
			a_new_not_void: a_new /= Void
		local
			a_text_count: INTEGER_32
			a_old_count: INTEGER_32
			a_start: INTEGER_32
			a_end: INTEGER_32
		do
			a_start := 1
			a_end := substring_index (a_text, a_old, a_start)
			if a_end > 0 then
				a_text_count := a_text.count
				a_old_count := a_old.count
				Result := new_empty_string (a_text, a_text_count)
				from
				until
					a_end = 0
				loop
					Result := appended_substring (Result, a_text, a_start, a_end - 1)
					Result := appended_string (Result, a_new)
					a_start := a_end + a_old_count
					if a_start > a_text_count then
						a_end := 0
					else
						a_end := substring_index (a_text, a_old, a_start)
					end
				end
				Result := appended_substring (Result, a_text, a_start, a_text_count)
			else
				check
					not_found: a_end = 0
				end
				Result := a_text
			end
		ensure
			instance_free: class
			replaced_all_substrings_not_void: Result /= Void
		end

	replaced_first_substring (a_text: STRING_8; a_old, a_new: STRING_8): STRING_8
			-- Copy of a_text for which first occurrence of a_old has been replaced
			-- by a_new; a_text if no occurrence could be found
		require
			a_text_not_void: a_text /= Void
			a_old_not_void: a_old /= Void
			a_new_not_void: a_new /= Void
		local
			a_text_count: INTEGER_32
			a_old_count: INTEGER_32
			a_end: INTEGER_32
		do
			a_end := substring_index (a_text, a_old, 1)
			if a_end > 0 then
				a_text_count := a_text.count
				a_old_count := a_old.count
				Result := new_empty_string (a_text, a_text_count - a_old_count + a_new.count)
				Result := appended_substring (Result, a_text, 1, a_end - 1)
				Result := appended_string (Result, a_new)
				Result := appended_substring (Result, a_text, a_end + a_old_count, a_text_count)
			else
				check
					not_found: a_end = 0
				end
				Result := a_text
			end
		ensure
			instance_free: class
			replaced_first_substring_not_void: Result /= Void
		end

	replaced_substring (a_string, other: STRING_8; start_index, end_index: INTEGER_32): STRING_8
			-- If the dynamic type of other is UC_STRING or one of
			-- its descendants and a_string is not, then return a
			-- new object with the same dynamic type as other and
			-- which contains the characters of a_string from which
			-- the substring from start_index to end_index, inclusive,
			-- has been replaced with other. Otherwise replace the
			-- substring from start_index to end_index, inclusive,
			-- in a_string with other and return a_string.
			-- Note: Use this routine instead of 'a_string.replace_substring (other)'
			-- when a_string can be of dynamic type STRING and other
			-- of dynamic type other than STRING such as UC_STRING, because
			-- class STRING provided by the Eiffel compilers is not necessarily
			-- aware of the implementation of UC_STRING and this may
			-- lead to run-time errors or crashes.
		require
			a_string_not_void: a_string /= Void
			other_not_void: other /= Void
			valid_start_index: 1 <= start_index
			valid_end_index: end_index <= a_string.count
			meaningful_interval: start_index <= end_index + 1
		do
			if Any_.same_types (a_string, other) then
				a_string.replace_substring (other, start_index, end_index)
				Result := a_string
			else
				if attached {UC_STRING} a_string as uc_string then
					uc_string.replace_substring_by_string (other, start_index, end_index)
					Result := uc_string
				else
					Result := appended_string (appended_string (a_string.substring (1, start_index - 1), other), a_string.substring (end_index + 1, a_string.count))
				end
			end
		ensure
			instance_free: class
			replaced_substring_not_void: Result /= Void
			replaced: same_string (Result, old (appended_string (appended_string (a_string.substring (1, start_index - 1), other), a_string.substring (end_index + 1, a_string.count))))
		end
	
feature -- Removal

	left_adjust (a_string: STRING_8)
			-- Remove leading whitespace from a_string.
			-- (Not in ELKS 2001 STRING)
			-- Note: SE 1.1 removes the following characters: ' ';
			-- ISE 5.4 removes the following characters: ' ', '%T', '%R', '%N';
		require
			a_string_not_void: a_string /= Void
		local
			i, nb: INTEGER_32
		do
			nb := a_string.count
			from
				i := 1
			until
				i > nb
			loop
				inspect a_string.item (i)
				when ' ', '%T', '%R', '%N' then
					i := i + 1
				else
					nb := 0
				end
			end
			a_string.remove_head (i - 1)
		ensure
			instance_free: class
			left_adjusted: (a_string.count /= 0) implies ((a_string.item_code (1) /= (' ').code) and (a_string.item_code (1) /= ('%T').code) and (a_string.item_code (1) /= ('%R').code) and (a_string.item_code (1) /= ('%N').code))
		end

	prune_all_trailing (a_string: STRING_8; c: CHARACTER_8)
			-- Remove all trailing occurrences of c in a_string.
		require
			a_string_not_void: a_string /= Void
		do
			a_string.prune_all_trailing (c)
		ensure
			instance_free: class
			no_more_trailing: a_string.is_empty or else a_string.item (a_string.count) /= c
		end

	right_adjust (a_string: STRING_8)
			-- Remove trailing whitespace from a_string.
			-- (Not in ELKS 2001 STRING)
			-- Note: SE 1.1 removes the following characters: ' ';
			-- ISE 5.4 removes the following characters: ' ', '%T', '%R', '%N';
		require
			a_string_not_void: a_string /= Void
		local
			i, nb: INTEGER_32
		do
			nb := a_string.count
			from
				i := 1
			until
				i > nb
			loop
				inspect a_string.item (nb)
				when ' ', '%T', '%R', '%N' then
					nb := nb - 1
				else
					i := nb + 1
				end
			end
			a_string.keep_head (nb)
		ensure
			instance_free: class
			right_adjusted: (a_string.count /= 0) implies ((a_string.item_code (a_string.count) /= (' ').code) and (a_string.item_code (a_string.count) /= ('%T').code) and (a_string.item_code (a_string.count) /= ('%R').code) and (a_string.item_code (a_string.count) /= ('%N').code))
		end

	wipe_out (a_string: STRING_8)
			-- Remove all characters in a_string.
			-- Do not discard allocated memory (i.e. do not
			-- change capacity) when allowed by the underlying
			-- Eiffel compiler.
			-- Note: currently ISE and SE will not change capacity.
		require
			a_string_not_void: a_string /= Void
		do
			a_string.keep_head (0)
		ensure
			instance_free: class
			wiped_out: a_string.count = 0
		end
	
feature -- Resizing

	resize_buffer (a_string: STRING_8; n: INTEGER_32)
			-- Resize a_string so that it contains n characters.
			-- Do not lose any previously entered characters.
		require
			a_string_not_void: a_string /= Void
			a_string_is_string: Any_.same_types (a_string, "")
			n_large_enough: n >= a_string.count
		local
			i: INTEGER_32
		do
			from
				i := n - a_string.count
				a_string.resize (n)
			until
				i = 0
			loop
				a_string.append_character ('#')
				i := i - 1
			end
		ensure
			instance_free: class
			count_set: a_string.count = n
		end
	
feature -- Conversion

	as_string (a_string: STRING_8): STRING_8
			-- String version of a_string;
			-- Return a_string if it is of dynamic type STRING,
			-- return the UTF encoding version if it is a descendant
			-- of UC_STRING, return 'string (a_string)' otherwise.
		require
			a_string_not_void: a_string /= Void
		do
			if Any_.same_types (a_string, Dummy_string) then
				Result := a_string
			else
				if attached {UC_STRING} a_string as uc_string then
					Result := uc_string.as_string
				else
					Result := a_string.string
				end
			end
		ensure
			instance_free: class
			as_string_not_void: Result /= Void
			string_type: Any_.same_types (Result, "")
			aliasing: Any_.same_types (a_string, "") implies Result = a_string
		end

	hexadecimal_to_integer (a_string: STRING_8): INTEGER_32
			-- Convert hexadecimal number string to integer;
			-- (Not in ELKS 2001 STRING)
			-- Note: Do not take overflow into account.
		require
			not_void: a_string /= Void
			hexadecimal: is_hexadecimal (a_string)
		local
			i, nb: INTEGER_32
		do
			nb := a_string.count
			from
				i := 1
			until
				i > nb
			loop
				Result := Result * 16
				inspect a_string.item (i)
				when '0' then
				when '1' then
					Result := Result + 1
				when '2' then
					Result := Result + 2
				when '3' then
					Result := Result + 3
				when '4' then
					Result := Result + 4
				when '5' then
					Result := Result + 5
				when '6' then
					Result := Result + 6
				when '7' then
					Result := Result + 7
				when '8' then
					Result := Result + 8
				when '9' then
					Result := Result + 9
				when 'a', 'A' then
					Result := Result + 10
				when 'b', 'B' then
					Result := Result + 11
				when 'c', 'C' then
					Result := Result + 12
				when 'd', 'D' then
					Result := Result + 13
				when 'e', 'E' then
					Result := Result + 14
				when 'f', 'F' then
					Result := Result + 15
				end
				i := i + 1
			end
		ensure
			instance_free: class
		end

	to_integer_64 (a_string: STRING_8): INTEGER_64
			-- a_string as INTEGER_64
		require
			a_string_not_void: a_string /= Void
			integer_64_string: is_integer_64 (a_string)
		do
			Result := a_string.to_integer_64
		ensure
			instance_free: class
		end
	
feature -- Duplication

	frozen clone (other: detachable ANY): like other
		obsolete "Use `twin' instead. [2017-05-31]"
			-- Void if other is void; otherwise new object
			-- equal to other
			--
			-- For non-void other, clone calls copy;
			-- to change copying/cloning semantics, redefine copy.
			-- (from ANY)
		do
			if other /= Void then
				Result := other.twin
			end
		ensure -- from ANY
			instance_free: class
			equal: Result ~ other
		end

	cloned_string (a_string: STRING_8): STRING_8
			-- Clone of a_string
		require
			a_string_not_void: a_string /= Void
		do
			Result := a_string.twin
		ensure
			instance_free: class
			cloned_not_void: Result /= Void
			same_type: Any_.same_types (Result, a_string)
			is_equal: Result.is_equal (a_string)
		end

	copy (other: KL_STRING_ROUTINES)
			-- Update current object using fields of object attached
			-- to other, so as to yield equal objects.
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
			type_identity: same_type (other)
		external
			"built_in"
		ensure -- from ANY
			is_equal: Current ~ other
		end

	frozen deep_clone (other: detachable ANY): like other
		obsolete "Use `deep_twin' instead. [2017-05-31]"
			-- Void if other is void: otherwise, new object structure
			-- recursively duplicated from the one attached to other
			-- (from ANY)
		do
			if other /= Void then
				Result := other.deep_twin
			end
		ensure -- from ANY
			instance_free: class
			deep_equal: deep_equal (other, Result)
		end

	frozen deep_copy (other: KL_STRING_ROUTINES)
			-- Effect equivalent to that of:
			--		copy (other . deep_twin)
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		do
			copy (other.deep_twin)
		ensure -- from ANY
			deep_equal: deep_equal (Current, other)
		end

	frozen deep_twin: KL_STRING_ROUTINES
			-- New object structure recursively duplicated from Current.
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			deep_twin_not_void: Result /= Void
			deep_equal: deep_equal (Current, Result)
		end

	frozen standard_clone (other: detachable ANY): like other
		obsolete "Use `standard_twin' instead. [2017-05-31]"
			-- Void if other is void; otherwise new object
			-- field-by-field identical to other.
			-- Always uses default copying semantics.
			-- (from ANY)
		do
			if other /= Void then
				Result := other.standard_twin
			end
		ensure -- from ANY
			instance_free: class
			equal: standard_equal (Result, other)
		end

	frozen standard_copy (other: KL_STRING_ROUTINES)
			-- Copy every field of other onto corresponding field
			-- of current object.
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
			type_identity: same_type (other)
		external
			"built_in"
		ensure -- from ANY
			is_standard_equal: standard_is_equal (other)
		end

	frozen standard_twin: KL_STRING_ROUTINES
			-- New object field-by-field identical to other.
			-- Always uses default copying semantics.
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			standard_twin_not_void: Result /= Void
			equal: standard_equal (Result, Current)
		end

	frozen twin: KL_STRING_ROUTINES
			-- New object equal to Current
			-- twin calls copy; to change copying/twinning semantics, redefine copy.
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			twin_not_void: Result /= Void
			is_equal: Result ~ Current
		end
	
feature -- Basic operations

	frozen as_attached: attached KL_STRING_ROUTINES
		obsolete "Remove calls to this feature. [2017-05-31]"
			-- Attached version of Current.
			-- (Can be used during transitional period to convert
			-- non-void-safe classes to void-safe ones.)
			-- (from ANY)
		do
			Result := Current
		end

	frozen default: detachable KL_STRING_ROUTINES
			-- Default value of object's type
			-- (from ANY)
		do
		end

	frozen default_pointer: POINTER
			-- Default value of type POINTER
			-- (Avoid the need to write p.default for
			-- some p of type POINTER.)
			-- (from ANY)
		do
		ensure -- from ANY
			instance_free: class
		end

	default_rescue
			-- Process exception for routines with no Rescue clause.
			-- (Default: do nothing.)
			-- (from ANY)
		do
		end

	frozen do_nothing
			-- Execute a null action.
			-- (from ANY)
		do
		ensure -- from ANY
			instance_free: class
		end
	
feature {NONE} -- Implementation

	Code_zero: INTEGER_32
			-- code for '0'
		once
			Result := ('0').code
		ensure
			instance_free: class
		end

	Dummy_string: STRING_8 = ""
			-- Dummy string

	Max_integer_64_digits: ARRAY [INTEGER_32]
			-- Digits of maximum INTEGER_64 value
		once
			Result := <<9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 7>>
		ensure
			instance_free: class
			result_not_void: Result /= Void
			ninteen_digits: Result.count = 19
		end

	Min_negative_integer_64_digits: ARRAY [INTEGER_32]
			-- Digits of minimum INTEGER_64 value
		once
			Result := <<9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8>>
		ensure
			instance_free: class
			result_not_void: Result /= Void
			ninteen_digits: Result.count = 19
		end
	
feature -- Output

	Io: STD_FILES
			-- Handle to standard file setup
			-- (from ANY)
		once
			create Result
			Result.set_output_default
		ensure -- from ANY
			instance_free: class
			io_not_void: Result /= Void
		end

	out: STRING_8
			-- New string containing terse printable representation
			-- of current object
			-- (from ANY)
		do
			Result := tagged_out
		ensure -- from ANY
			out_not_void: Result /= Void
		end

	print (o: detachable ANY)
			-- Write terse external representation of o
			-- on standard output.
			-- (from ANY)
		do
			if o /= Void then
				Io.put_string (o.out)
			end
		ensure -- from ANY
			instance_free: class
		end

	frozen tagged_out: STRING_8
			-- New string containing terse printable representation
			-- of current object
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			tagged_out_not_void: Result /= Void
		end
	
feature -- Platform

	Operating_environment: OPERATING_ENVIRONMENT
			-- Objects available from the operating system
			-- (from ANY)
		once
			create Result
		ensure -- from ANY
			instance_free: class
			operating_environment_not_void: Result /= Void
		end
	
feature {NONE} -- Retrieval

	frozen internal_correct_mismatch
			-- Called from runtime to perform a proper dynamic dispatch on correct_mismatch
			-- from MISMATCH_CORRECTOR.
			-- (from ANY)
		local
			l_msg: STRING_8
			l_exc: EXCEPTIONS
		do
			if attached {MISMATCH_CORRECTOR} Current as l_corrector then
				l_corrector.correct_mismatch
			else
				create l_msg.make_from_string ("Mismatch: ")
				create l_exc
				l_msg.append (generating_type.name)
				l_exc.raise_retrieval_exception (l_msg)
			end
		end
	
invariant
		-- from ANY
	reflexive_equality: standard_is_equal (Current)
	reflexive_conformance: conforms_to (Current)

end -- class KL_STRING_ROUTINES

Generated by ISE EiffelStudio