class EL_ZSTRING_CHARACTER_8_IMPLEMENTATION
Aspect of ZSTRING as an array of 8-bit characters
note
description: "Aspect of ${ZSTRING} as an array of 8-bit characters"
author: "Finnian Reilly"
copyright: "Copyright (c) 2001-2022 Finnian Reilly"
contact: "finnian at eiffel hyphen loop dot com"
license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
date: "2024-08-25 7:21:00 GMT (Sunday 25th August 2024)"
revision: "33"
deferred class
EL_ZSTRING_CHARACTER_8_IMPLEMENTATION
inherit
EL_SHARED_STRING_8_CURSOR
feature {NONE} -- Initialization
make (n: INTEGER)
-- Allocate space for at least `n' characters.
do
set_count (0)
create area.make_filled ('%/000/', n + 1)
end
feature -- Access
area: SPECIAL [CHARACTER_8]
-- Storage for characters.
hash_code: INTEGER
-- Hash code value
local
i, i_upper: INTEGER; b: EL_BIT_ROUTINES
do
if attached area as l_area then
i_upper := count - 1
from i := 0 until i > i_upper loop
Result := b.extended_hash (Result, l_area [i].code)
i := i + 1
end
end
end
index_of (c: CHARACTER_8; start_index: INTEGER): INTEGER
-- Position of first occurrence of `c' at or after `start_index';
-- 0 if none.
require
start_large_enough: start_index >= 1
start_small_enough: start_index <= count + 1
local
a: like area
i, nb, l_lower_area: INTEGER
do
nb := count
if start_index <= nb then
from
l_lower_area := area_lower
i := start_index - 1 + l_lower_area
nb := nb + l_lower_area
a := area
until
i = nb or else a.item (i) = c
loop
i := i + 1
end
if i < nb then
-- We add +1 due to the area starting at 0 and not at 1
-- and substract `area_lower'
Result := i + 1 - l_lower_area
end
end
ensure
valid_result: Result = 0 or (start_index <= Result and Result <= count)
end
item (i: INTEGER): CHARACTER_8
-- Character at position `i'.
do
Result := area.item (i - 1)
end
last_index_of (c: CHARACTER_8; start_index_from_end: INTEGER): INTEGER
-- Position of last occurrence of `c',
-- 0 if none.
require
start_index_small_enough: start_index_from_end <= count
start_index_large_enough: start_index_from_end >= 1
local
a: like area
i, l_lower_area: INTEGER
do
from
l_lower_area := area_lower
i := start_index_from_end - 1 + l_lower_area
a := area
until
i < l_lower_area or else a.item (i) = c
loop
i := i - 1
end
-- We add +1 due to the area starting at 0 and not at 1.
Result := i + 1 - l_lower_area
ensure
valid_result: 0 <= Result and Result <= start_index_from_end
zero_if_absent: (Result = 0) = not substring (1, start_index_from_end).has (c)
found_if_present: substring (1, start_index_from_end).has (c) implies item (Result) = c
none_after: substring (1, start_index_from_end).has (c) implies
not substring (Result + 1, start_index_from_end).has (c)
end
feature -- Measurement
capacity: INTEGER
-- Allocated space
do
Result := area.count - 1
end
count: INTEGER
-- Actual number of characters making up the string
deferred
end
feature -- Status query
valid_index (i: INTEGER): BOOLEAN
deferred
end
feature -- Resizing
adapt_size
-- Adapt the size to accommodate `count' characters.
do
resize (count)
end
grow (newsize: INTEGER)
-- Ensure that the capacity is at least `newsize'.
do
if newsize > capacity then
resize (newsize)
end
end
resize (newsize: INTEGER)
-- Rearrange string so that it can accommodate
-- at least `newsize' characters.
do
area := area.aliased_resized_area_with_default ('%U', newsize + 1)
end
trim
-- <Precursor>
local
n: like count
do
n := count
if n < capacity then
area := area.aliased_resized_area (n + 1)
end
ensure then
same_string: same_string (old twin)
end
feature -- Contract support
is_ascii_string_8 (str: READABLE_STRING_8): BOOLEAN
do
Result := cursor_8 (str).all_ascii
end
feature -- Conversion
string: EL_STRING_8
do
create Result.make_from_zstring (Current)
end
substring (start_index, end_index: INTEGER): like string
do
Result := string.substring (start_index, end_index)
end
feature -- Comparison
same_characters (other: EL_ZSTRING_CHARACTER_8_IMPLEMENTATION; start_pos, end_pos, index_pos: INTEGER): BOOLEAN
-- Are characters of `other' within bounds `start_pos' and `end_pos'
-- identical to characters of current string starting at index `index_pos'.
require
valid_start_pos: other.valid_index (start_pos)
valid_end_pos: other.valid_index (end_pos)
valid_bounds: (start_pos <= end_pos) or (start_pos = end_pos + 1)
valid_index_pos: valid_index (index_pos)
local
nb: INTEGER
do
nb := end_pos - start_pos + 1
if nb <= count - index_pos + 1 then
Result := area.same_items (other.area, other.area_lower + start_pos - 1, area_lower + index_pos - 1, nb)
end
ensure
same_characters:
attached substring (index_pos, index_pos + end_pos - start_pos) as current_substring
and then Result = current_substring.same_string (other.substring (start_pos, end_pos))
end
same_string (other: EL_ZSTRING_CHARACTER_8_IMPLEMENTATION): BOOLEAN
-- Do `Current' and `other' have same character sequence?
require
other_not_void: other /= Void
local
nb: INTEGER
do
if other = Current then
Result := True
else
nb := count
if nb = other.count then
Result := nb = 0 or else same_characters (other, 1, nb, 1)
end
end
ensure
definition: Result = (string ~ other.string)
end
feature {NONE} -- Element change
fill_character (c: CHARACTER_8)
-- Fill with `capacity' characters all equal to `c'.
local
l_cap: like capacity
do
l_cap := capacity
if l_cap /= 0 then
area.fill_with (c, 0, l_cap - 1)
set_count (l_cap)
end
ensure
filled: count = capacity
same_size: capacity = old capacity
-- all_char: For every `i' in 1..`capacity', `item' (`i') = `c'
end
insert_string (s: EL_ZSTRING_CHARACTER_8_IMPLEMENTATION; i: INTEGER)
-- Insert `s' at index `i', shifting characters between ranks
-- `i' and `count' rightwards.
require
valid_insertion_index: 1 <= i and i <= count + 1
local
pos, new_size, s_count: INTEGER; l_area: like area
do
-- Insert `s' if `s' is not empty, otherwise is useless.
s_count := s.count
if s_count /= 0 then
-- Resize Current if necessary.
new_size := s_count + count
if new_size > capacity then
resize (new_size + additional_space)
end
-- Perform all operations using a zero based arrays.
l_area := area; pos := i - 1
-- First shift from `s.count' position all characters starting at index `pos'.
l_area.overlapping_move (pos, pos + s_count, count - pos)
-- Copy string `s' at index `pos'.
l_area.copy_data (s.area, s.area_lower, pos, s_count)
set_count (new_size)
end
ensure
inserted: elks_checking implies (string ~ (old substring (1, i - 1) + old (s.string) + old substring (i, count)))
end
keep_head (n: INTEGER)
-- Remove all characters except for the first `n';
-- do nothing if `n' >= `count'.
do
if n < count then
set_count (n)
end
end
keep_tail (n: INTEGER)
-- Remove all characters except for the last `n';
-- do nothing if `n' >= `count'.
local
nb: like count
do
nb := count
if n < nb then
area.overlapping_move (nb - n, 0, n)
set_count (n)
end
end
feature {NONE} -- Implementation
share (other: EL_ZSTRING_CHARACTER_8_IMPLEMENTATION)
-- Make current string share the text of `other'.
-- Subsequent changes to the characters of current string
-- will also affect `other', and conversely.
do
area := other.area
set_count (other.count)
ensure
shared_count: other.count = count
shared_area: other.area = area
end
feature -- Removal
remove (i: INTEGER)
-- Remove `i'-th character.
local
l_count: INTEGER
do
l_count := count
-- Shift characters to the left.
area.overlapping_move (i, i - 1, l_count - i)
-- Update content.
set_count (l_count - 1)
end
wipe_out
-- Remove all characters.
do
set_count (0)
ensure then
is_empty: count = 0
same_capacity: capacity = old capacity
end
feature {EL_ZSTRING_CHARACTER_8_IMPLEMENTATION, EL_STRING_8_IMPLEMENTATION} -- Implementation
area_lower: INTEGER
-- Minimum index
do
ensure
area_lower_non_negative: Result >= 0
area_lower_valid: Result <= area.upper
end
area_upper: INTEGER
-- Maximum index
do
Result := area_lower + count - 1
ensure
area_upper_valid: Result <= area.upper
area_upper_in_bound: area_lower <= Result + 1
end
copy_area (a_old_area: detachable like area; other: like Current)
do
if attached a_old_area as old_area then
if old_area = other.area or else old_area.count <= count then
-- Prevent copying of large `area' if only a few characters are actually used.
area := area.resized_area (count + 1)
else
old_area.copy_data (area, 0, 0, count)
area := old_area
end
else
area := area.resized_area (count + 1)
end
end
current_string_8: EL_STRING_8
do
Result := String_8.injected (Current, 0)
end
order_comparison (this, other: like area; this_index, other_index, n: INTEGER): INTEGER
-- Compare `n' characters from `this' starting at `this_index' with
-- `n' characters from and `other' starting at `other_index'.
-- 0 if equal, < 0 if `this' < `other',
-- > 0 if `this' > `other'
require
this_not_void: this /= Void
other_not_void: other /= Void
n_non_negative: n >= 0
n_valid: n <= (this.upper - this_index + 1) and n <= (other.upper - other_index + 1)
local
i, j, nb: INTEGER; c, c_other: CHARACTER
do
from
i := this_index
nb := i + n
j := other_index
until
i = nb
loop
c := this [i]; c_other := other [j]
if c /= c_other then
Result := c |-| c_other
i := nb - 1 -- Jump out of loop
end
i := i + 1
j := j + 1
end
end
set_from_ascii (str: READABLE_STRING_8)
require
is_7_bit: is_ascii_string_8 (str)
local
s: STRING_8
do
create s.make_from_string (str)
area := s.area
set_count (str.count)
end
set_from_string_8 (str: EL_STRING_8)
do
area := str.area; set_count (str.count)
end
feature {NONE} -- Deferred
additional_space: INTEGER
deferred
end
elks_checking: BOOLEAN
deferred
end
reset_hash
deferred
end
set_count (number: INTEGER)
deferred
end
feature -- Constants
String_8: EL_STRING_8_IMPLEMENTATION
once
create Result.make
end
end