class EL_MEMORY_STRING_READER_WRITER
Read/write strings from/to a memory buffer
note
description: "Read/write strings from/to a memory buffer"
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 8:02:07 GMT (Sunday 25th August 2024)"
revision: "17"
deferred class
EL_MEMORY_STRING_READER_WRITER
inherit
EL_MEMORY_READER_WRITER_IMPLEMENTATION
EL_ZCODE_CONVERSION
export
{NONE} all
end
EL_SHARED_STRING_8_CURSOR; EL_SHARED_STRING_32_CURSOR
feature -- Measurement
size_of_string (str: EL_READABLE_ZSTRING): INTEGER
do
Result := Integer_32_bytes + str.count + str.unencoded_count * Natural_32_bytes
end
size_of_string_32 (str: STRING_32): INTEGER
local
area: SPECIAL [CHARACTER_32]; i, i_final: INTEGER
do
Result := Integer_32_bytes
area := str.area; i_final := str.count
from i := 0 until i = i_final loop
Result := Result + size_of_compressed_natural_32 (area [i].natural_32_code)
i := i + 1
end
end
size_of_string_8 (str: STRING_8): INTEGER
do
Result := Integer_32_bytes + str.count
end
feature -- Read operations
read_into_string (str: ZSTRING)
require else
is_ready: is_ready_for_reading
local
char_count: INTEGER
do
char_count := read_integer_32
str.grow (char_count)
fill_string (str, char_count)
end
read_into_string_32 (str: STRING_32)
require else
is_ready: is_ready_for_reading
local
char_count: INTEGER
do
char_count := read_integer_32
str.grow (char_count)
fill_string_32 (str, char_count)
end
read_into_string_8 (str: STRING_8)
require else
is_ready: is_ready_for_reading
local
char_count, read_count, pos: INTEGER
do
if attached buffer as buf then
pos := count
char_count := compressed_natural_32 (buf, pos, $read_count).to_integer_32
if read_count.to_boolean then
pos := pos + read_count
if pos + char_count < buf.count then
str.grow (char_count)
buf.read_into_special_character_8 (str.area, pos, 0, char_count)
str.set_count (char_count)
pos := pos + char_count
end
end
count := pos
end
end
read_string: ZSTRING
require else
is_ready: is_ready_for_reading
local
char_count: INTEGER
do
char_count := read_integer_32
create Result.make (char_count)
fill_string (Result, char_count)
end
read_string_8: STRING
-- Read next 8-bits sequence of character
require else
is_ready: is_ready_for_reading
do
create Result.make (0)
read_into_string_8 (Result)
end
read_string_32: STRING_32
require else
is_ready: is_ready_for_reading
local
char_count: INTEGER
do
char_count := read_integer_32
create Result.make (char_count)
fill_string_32 (Result, char_count)
end
read_to_string_8 (str: STRING; n: INTEGER)
-- set the contents of `str' with `n' characters
require
is_ready: is_ready_for_reading
local
pos: INTEGER
do
str.grow (n); str.set_count (n)
pos := count
if attached buffer as buf and then pos + n < buf.count then
buffer.read_into_special_character_8 (str.area, pos, 0, n)
count := pos + n
end
end
feature {NONE} -- Implementation
fill_string (str: ZSTRING; char_count: INTEGER)
require
valid_string: str.is_empty and then char_count <= str.capacity
local
i, buffer_count, pos: INTEGER; done: BOOLEAN; code: NATURAL; l_last_upper: INTEGER
c: CHARACTER
do
if attached str.area as str_area and then attached buffer as l_buffer
and then attached str.empty_unencoded_buffer as unencoded_buffer
then
buffer_count := l_buffer.count; pos := count
l_last_upper := unencoded_buffer.last_upper
from i := 0 until done or else i = char_count loop
if pos + Character_8_bytes < buffer_count then
c := l_buffer.read_character (pos)
str_area [i] := c
pos := pos + Character_8_bytes
inspect c
when Substitute then
if pos + Natural_32_bytes < buffer_count then
code := l_buffer.read_natural_32 (pos)
pos := pos + Natural_32_bytes
l_last_upper := unencoded_buffer.extend (code.to_character_32, l_last_upper, i + 1)
else
done := True
end
else
end
i := i + 1
else
done := True
end
end
str_area [i] := '%U'
str.set_count (i)
unencoded_buffer.set_last_upper (l_last_upper)
str.set_unencoded_from_buffer (unencoded_buffer)
count := pos
end
ensure
valid_str: str.is_valid
end
fill_string_32 (str: STRING_32; a_count: INTEGER)
local
i, read_count, pos: INTEGER; code: NATURAL
done: BOOLEAN
do
if attached buffer as l_buffer and then attached str.area as str_area then
pos := count
from i := 0 until done or else i = a_count loop
code := compressed_natural_32 (l_buffer, pos, $read_count)
if read_count.to_boolean then
str_area [i] := code.to_character_32
pos := pos + read_count
i := i + 1
else
done := True
end
end
str_area [i] := '%U'
str.set_count (i)
count := pos
end
end
feature -- Write operations
write_string (a_string: EL_READABLE_ZSTRING)
require else
valid_string: a_string.is_valid
local
i, l_count, pos, block_index: INTEGER; iter: EL_COMPACT_SUBSTRINGS_32_ITERATION
c_i: CHARACTER
do
l_count := a_string.count
if attached a_string.area as area and then attached a_string.unencoded_area as area_32
and then attached big_enough_buffer (size_of_string (a_string)) as buf
then
pos := count
buf.put_natural_32 (l_count.to_natural_32, pos)
pos := pos + Natural_32_bytes
from i := 0 until i = l_count loop
c_i := area [i]
buf.put_character (c_i, pos)
pos := pos + Character_8_bytes
inspect c_i
when Substitute then
buf.put_natural_32 (iter.code ($block_index, area_32, i + 1), pos)
pos := pos + Natural_32_bytes
else
end
i := i + 1
end
count := pos
end
end
write_string_32 (str: READABLE_STRING_32)
local
i, pos, first_index, last_index: INTEGER; compressed_32: SPECIAL [NATURAL_8]
area: SPECIAL [CHARACTER_32]; is_native: BOOLEAN
do
if is_zstring (str) and then attached {ZSTRING} str as z_str then
write_string (z_str)
elseif attached big_enough_buffer (size_of_string_32 (str)) as buf then
pos := count; is_native := is_native_endian
buf.put_integer_32 (str.count, pos)
pos := pos + Integer_32_bytes
if attached cursor_32 (str) as c then
area := c.area; first_index := c.area_first_index
last_index := c.area_last_index
end
from i := first_index until i > last_index loop
compressed_32 := new_compressed_natural_32 (area [i].natural_32_code, is_native)
buf.put_special_natural_8 (compressed_32, 0, pos, compressed_32.count)
pos := pos + compressed_32.count
i := i + 1
end
count := pos
end
end
write_string_8 (str: READABLE_STRING_8)
-- Write `str'.
local
i, pos, first_index, last_index: INTEGER
area: SPECIAL [CHARACTER_8]
do
write_compressed_natural_32 (str.count.to_natural_32)
if attached cursor_8 (str) as cursor then
area := cursor.area
first_index := cursor.area_first_index
last_index := cursor.area_last_index
end
if attached big_enough_buffer (str.count) as buf then
pos := count
from i := first_index until i > last_index loop
buf.put_character (area [i], pos)
pos := pos + 1
i := i + 1
end
count := pos
end
end
end