class EL_TUPLE_ROUTINES
Routines for populating tuple fields and converting to and from string types. Accessible via shared instance EL_MODULE_TUPLE
note
description: "[
Routines for populating tuple fields and converting to and from string types.
Accessible via shared instance ${EL_MODULE_TUPLE}
]"
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-10-06 12:21:28 GMT (Sunday 6th October 2024)"
revision: "54"
class
EL_TUPLE_ROUTINES
inherit
EL_INTEGER_MATH
export
{NONE} all
end
EL_MODULE_CONVERT_STRING; EL_MODULE_EIFFEL
EL_STRING_8_CONSTANTS; EL_CHARACTER_8_CONSTANTS; EL_TYPE_CATEGORY_CONSTANTS
EL_SHARED_CLASS_ID
create
make
feature {NONE} -- Initialization
make
do
create types_table.make (17, agent new_type_array)
create procedure
create empty
create counter
readable_string_8_types := Class_id.readable_string_8_types
readable_string_32_types := Class_id.readable_string_32_types
el_path_types := Class_id.el_path_types
end
feature -- Access
all_readable_strings (tuple: TUPLE): BOOLEAN
-- True if all `tuple' items conform to `READABLE_STRING_GENERAL'
do
Result := type_array (tuple).all_conform_to ({READABLE_STRING_GENERAL})
end
closed_operands (a_procedure: PROCEDURE): TUPLE
do
procedure.set_from_other (a_procedure)
Result := procedure.closed_operands
end
empty: TUPLE
last_reset_count: INTEGER
do
Result := counter.item.to_integer_32
end
type_array (tuple: TUPLE): EL_TUPLE_TYPE_ARRAY
-- Caches results in `types_table'
do
Result := types_table.item ({ISE_RUNTIME}.dynamic_type (tuple))
end
feature -- Measurement
i_th_string_width (tuple: TUPLE; i: INTEGER): INTEGER
require
valid_index: tuple.valid_index (i)
do
inspect tuple.item_code (i)
when {TUPLE}.Boolean_code then
if tuple.boolean_item (i) then
Result := 4
else
Result := 5
end
when {TUPLE}.Character_8_code, {TUPLE}.Character_32_code then
Result := 1
when {TUPLE}.Pointer_code then
-- Hexadecimal number
Result := {PLATFORM}.pointer_bytes * 2 + 2
-- Integers
when {TUPLE}.Integer_8_code then
Result := string_size (tuple.integer_8_item (i))
when {TUPLE}.Integer_16_code then
Result := string_size (tuple.integer_16_item (i))
when {TUPLE}.Integer_32_code then
Result := string_size (tuple.integer_32_item (i))
when {TUPLE}.Integer_64_code then
Result := string_size (tuple.integer_64_item (i))
-- Naturals
when {TUPLE}.Natural_8_code then
Result := natural_digit_count (tuple.natural_8_item (i))
when {TUPLE}.Natural_16_code then
Result := natural_digit_count (tuple.natural_16_item (i))
when {TUPLE}.Natural_32_code then
Result := natural_digit_count (tuple.natural_32_item (i))
when {TUPLE}.Natural_64_code then
Result := natural_digit_count (tuple.natural_64_item (i))
-- Reals
when {TUPLE}.Real_32_code then
Result := tuple.real_32_item (i).out.count
when {TUPLE}.Real_64_code then
Result := tuple.real_64_item (i).out.count
-- Reference
when {TUPLE}.Reference_code then
if attached tuple.reference_item (i) as ref_item then
Result := string_width_any (ref_item)
end
else
end
end
string_width (tuple: TUPLE): INTEGER
local
i: INTEGER
do
from i := 1 until i > tuple.count loop
Result := Result + i_th_string_width (tuple, i)
i := i + 1
end
end
feature -- Conversion
to_string_32_list (tuple: TUPLE): EL_STRING_32_LIST
do
Result := tuple
end
to_string_8_list (tuple: TUPLE): EL_STRING_8_LIST
do
Result := tuple
end
to_zstring_list (tuple: TUPLE): EL_ZSTRING_LIST
do
Result := tuple
end
feature -- Basic operations
append_i_th (tuple: TUPLE; i: INTEGER; string: STRING_32)
-- append i'th item of `tuple' to `string'
require
valid_index: tuple.valid_index (i)
do
inspect tuple.item_code (i)
when {TUPLE}.Integer_8_code then
string.append_integer_8 (tuple.integer_8_item (i))
when {TUPLE}.Integer_16_code then
string.append_integer_16 (tuple.integer_16_item (i))
when {TUPLE}.Integer_32_code then
string.append_integer (tuple.integer_32_item (i))
when {TUPLE}.Integer_64_code then
string.append_integer_64 (tuple.integer_64_item (i))
when {TUPLE}.Natural_8_code then
string.append_natural_8 (tuple.natural_8_item (i))
when {TUPLE}.Natural_16_code then
string.append_natural_16 (tuple.natural_16_item (i))
when {TUPLE}.Natural_32_code then
string.append_natural_32 (tuple.natural_32_item (i))
when {TUPLE}.Natural_64_code then
string.append_natural_64 (tuple.natural_64_item (i))
when {TUPLE}.Real_32_code then
string.append_real (tuple.real_32_item (i))
when {TUPLE}.Real_64_code then
string.append_double (tuple.real_64_item (i))
when {TUPLE}.Reference_code then
if attached tuple.reference_item (i) as ref_item then
if attached {READABLE_STRING_GENERAL} ref_item as general then
if attached {ZSTRING} general as zstr then
zstr.append_to_string_32 (string)
else
string.append_string_general (general)
end
elseif attached {EL_PATH} ref_item as path then
path.append_to_32 (string)
end
end
end
end
fill (tuple: TUPLE; csv_list: READABLE_STRING_GENERAL)
do
fill_adjusted (tuple, csv_list, True)
end
fill_adjusted (tuple: TUPLE; csv_list: READABLE_STRING_GENERAL; left_adjusted: BOOLEAN)
-- fill tuple with STRING items from comma-separated list `csv_list' of strings
-- TUPLE may contain any of types STRING_8, STRING_32, ZSTRING
-- items are left adjusted if `left_adjusted' is True
do
Convert_string.fill_tuple (tuple, csv_list, ',', left_adjusted)
end
fill_default (tuple: TUPLE; default_value: ANY)
local
i: INTEGER; type_id: INTEGER
tuple_types: EL_TUPLE_TYPE_ARRAY
do
type_id := {ISE_RUNTIME}.dynamic_type (default_value)
tuple_types := type_array (tuple)
from i := 1 until i > tuple.count loop
if tuple.item_code (i) = {TUPLE}.Reference_code and then
Eiffel.field_conforms_to (type_id, tuple_types [i].type_id)
then
tuple.put_reference (default_value, i)
end
i := i + 1
end
ensure
filled: is_filled (tuple, 1, tuple.count)
end
fill_immutable (tuple: TUPLE; csv_list: STRING)
-- fill tuple with `IMMUTABLE_STRING_8' items from comma-separated list `csv_list' of strings
-- created items are left adjusted and share the same `SPECIAL [CHARACTER]' area
require
all_immutable_string_8: type_array (tuple).is_uniformly ({IMMUTABLE_STRING_8})
local
comma_splitter: EL_SPLIT_IMMUTABLE_STRING_8_LIST; tuple_types: EL_TUPLE_TYPE_ARRAY
do
tuple_types := type_array (tuple)
create comma_splitter.make_shared_adjusted (csv_list, ',', {EL_SIDE}.Left)
across comma_splitter as list until list.cursor_index > tuple.count loop
if tuple_types [list.cursor_index].type_id = Class_id.IMMUTABLE_STRING_8 then
tuple.put_reference (list.item, list.cursor_index)
end
end
ensure
filled: is_filled (tuple, 1, tuple.count)
end
fill_with_new (tuple: TUPLE; csv_field_list: STRING; a_new_item: FUNCTION [STRING, ANY]; start_index: INTEGER)
-- fill tuple from `start_index' with factory function call `a_new_item (x)' where `x' is a field name
-- in the comma separated field list `csv_field_list'
require
valid_start_index: start_index >= 1
valid_list: csv_field_list.count > 0 and then start_index + csv_field_list.occurrences (',') <= tuple.count
not_filled: not is_filled (tuple, start_index, start_index + csv_field_list.occurrences (','))
local
result_type_id: INTEGER; comma_splitter: EL_SPLIT_ON_CHARACTER_8 [STRING_8]
tuple_types: EL_TUPLE_TYPE_ARRAY; index: INTEGER
do
result_type_id := a_new_item.generating_type.generic_parameter_type (2).type_id
tuple_types := type_array (tuple)
create comma_splitter.make_adjusted (csv_field_list, ',', {EL_SIDE}.Left)
across comma_splitter as list until (start_index + list.cursor_index - 1) > tuple.count loop
index := start_index + list.cursor_index - 1
if tuple.item_code (index) = {TUPLE}.Reference_code and then
Eiffel.field_conforms_to (result_type_id, tuple_types [index].type_id)
and then attached a_new_item (list.item_copy) as new
then
tuple.put_reference (new, index)
end
end
ensure
filled: is_filled (tuple, start_index, start_index + csv_field_list.occurrences (','))
end
line_fill (tuple: TUPLE; line_list: READABLE_STRING_GENERAL)
do
Convert_string.fill_tuple (tuple, line_list, '%N', False)
end
read (tuple: TUPLE; readable: EL_READABLE)
local
i: INTEGER
do
from i := 1 until i > tuple.count loop
set_i_th (tuple, i, readable, 0)
i := i + 1
end
end
reset (tuple: TUPLE)
-- reset all tuple items to default values, wiping out any strings
-- `last_reset_count' returns the number of items reset
local
i: INTEGER
do
from i := 1 until i > tuple.count loop
reset_i_th (tuple, i, tuple.item_code (i))
i := i + 1
end
end
reset_i_th (tuple: TUPLE; i, type_id: INTEGER)
require
valid_index: tuple.valid_index (i)
do
inspect tuple.item_code (i)
when {TUPLE}.Character_8_code then
tuple.put_character ('%U', i); counter.bump
when {TUPLE}.Character_32_code then
tuple.put_character_32 ('%U', i); counter.bump
when {TUPLE}.Boolean_code then
tuple.put_boolean (False, i); counter.bump
when {TUPLE}.Pointer_code then
tuple.put_pointer (default_pointer, i)
when {TUPLE}.Integer_8_code then
tuple.put_integer_8 (0, i); counter.bump
when {TUPLE}.Integer_16_code then
tuple.put_integer_16 (0, i); counter.bump
when {TUPLE}.Integer_32_code then
tuple.put_integer (0, i); counter.bump
when {TUPLE}.Integer_64_code then
tuple.put_integer_64 (0, i); counter.bump
when {TUPLE}.Natural_8_code then
tuple.put_natural_8 (0, i); counter.bump
when {TUPLE}.Natural_16_code then
tuple.put_natural_16 (0, i); counter.bump
when {TUPLE}.Natural_32_code then
tuple.put_natural_32 (0, i); counter.bump
when {TUPLE}.Natural_64_code then
tuple.put_natural_64 (0, i); counter.bump
when {TUPLE}.Real_32_code then
tuple.put_real_32 (0, i); counter.bump
when {TUPLE}.Real_64_code then
tuple.put_real_64 (0, i); counter.bump
when {TUPLE}.Reference_code then
reset_i_th_reference (
tuple, tuple.reference_item (i), i, Eiffel.generic_dynamic_type (tuple, i)
)
else
end
end
set_i_th (tuple: TUPLE; i: INTEGER; readable: EL_READABLE; type_id: INTEGER)
require
valid_index: tuple.valid_index (i)
do
inspect tuple.item_code (i)
when {TUPLE}.Character_8_code then
tuple.put_character (readable.read_character_8, i)
when {TUPLE}.Character_32_code then
tuple.put_character_32 (readable.read_character_32, i)
when {TUPLE}.Boolean_code then
tuple.put_boolean (readable.read_boolean, i)
when {TUPLE}.Pointer_code then
tuple.put_pointer (readable.read_pointer, i)
when {TUPLE}.Integer_8_code then
tuple.put_integer_8 (readable.read_integer_8, i)
when {TUPLE}.Integer_16_code then
tuple.put_integer_16 (readable.read_integer_16, i)
when {TUPLE}.Integer_32_code then
tuple.put_integer (readable.read_integer_32, i)
when {TUPLE}.Integer_64_code then
tuple.put_integer_64 (readable.read_integer_64, i)
when {TUPLE}.Natural_8_code then
tuple.put_natural_8 (readable.read_natural_8, i)
when {TUPLE}.Natural_16_code then
tuple.put_natural_16 (readable.read_natural_16, i)
when {TUPLE}.Natural_32_code then
tuple.put_natural_32 (readable.read_natural_32, i)
when {TUPLE}.Natural_64_code then
tuple.put_natural_64 (readable.read_natural_64, i)
when {TUPLE}.Real_32_code then
tuple.put_real_32 (readable.read_real_32, i)
when {TUPLE}.Real_64_code then
tuple.put_real_64 (readable.read_real_64, i)
when {TUPLE}.Reference_code then
set_i_th_reference (tuple, i, readable, Eiffel.generic_dynamic_type (tuple, i))
else
end
end
write (tuple: TUPLE; writable: EL_WRITABLE; a_delimiter: detachable READABLE_STRING_8)
local
i: INTEGER; separator: CHARACTER; delimiter: READABLE_STRING_8
has_delimiter: BOOLEAN
do
if attached a_delimiter as str then
if str.count = 1 then
separator := str [1]
else
delimiter := str
end
has_delimiter := True
else
delimiter := Empty_string_8
end
from i := 1 until i > tuple.count loop
if i > 1 and has_delimiter then
if separator = '%U' then
writable.write_string_8 (delimiter)
else
writable.write_character_8 (separator)
end
end
write_i_th (tuple, i, writable)
i := i + 1
end
end
write_i_th (tuple: TUPLE; i: INTEGER; writable: EL_WRITABLE)
do
inspect tuple.item_code (i)
when {TUPLE}.Character_8_code then
writable.write_character_8 (tuple.character_8_item (i))
when {TUPLE}.Character_32_code then
writable.write_character_32 (tuple.character_32_item (i))
when {TUPLE}.Boolean_code then
writable.write_boolean (tuple.boolean_item (i))
when {TUPLE}.Integer_8_code then
writable.write_integer_8 (tuple.integer_8_item (i))
when {TUPLE}.Integer_16_code then
writable.write_integer_16 (tuple.integer_16_item (i))
when {TUPLE}.Integer_32_code then
writable.write_integer_32 (tuple.integer_32_item (i))
when {TUPLE}.Integer_64_code then
writable.write_integer_64 (tuple.integer_64_item (i))
when {TUPLE}.Natural_8_code then
writable.write_natural_8 (tuple.natural_8_item (i))
when {TUPLE}.Natural_16_code then
writable.write_natural_16 (tuple.natural_16_item (i))
when {TUPLE}.Natural_32_code then
writable.write_natural_32 (tuple.natural_32_item (i))
when {TUPLE}.Natural_64_code then
writable.write_natural_64 (tuple.natural_64_item (i))
when {TUPLE}.Pointer_code then
writable.write_pointer (tuple.pointer_item (i))
when {TUPLE}.Real_32_code then
writable.write_real_32 (tuple.real_32_item (i))
when {TUPLE}.Real_64_code then
writable.write_real_64 (tuple.real_64_item (i))
when {TUPLE}.Reference_code then
if attached tuple.reference_item (i) as object then
writable.write_any (object)
end
else
end
end
write_with_comma (tuple: TUPLE; writable: EL_WRITABLE; extra_space: BOOLEAN)
do
if extra_space then
write (tuple, writable, Comma_space)
else
write (tuple, writable, comma)
end
end
feature {NONE} -- Factory
new_read_path (readable: EL_READABLE; type_id: INTEGER): EL_PATH
do
if type_id = Class_id.DIR_PATH then
create {DIR_PATH} Result.make (readable.read_string)
elseif type_id = Class_id.FILE_PATH then
create {FILE_PATH} Result.make (readable.read_string)
elseif type_id = Class_id.EL_DIR_URI_PATH then
create {EL_DIR_URI_PATH} Result.make (readable.read_string)
elseif type_id = Class_id.EL_FILE_URI_PATH then
create {EL_FILE_URI_PATH} Result.make (readable.read_string)
end
end
new_read_string_32 (readable: EL_READABLE; type_id: INTEGER): READABLE_STRING_32
do
if type_id = Class_id.ZSTRING then
Result := readable.read_string
elseif type_id = Class_id.STRING_32 then
Result := readable.read_string_32
elseif type_id = Class_id.IMMUTABLE_STRING_32 then
create {IMMUTABLE_STRING_32} Result.make_from_string_32 (readable.read_string_32)
end
end
new_read_string_8 (readable: EL_READABLE; type_id: INTEGER): READABLE_STRING_8
do
if type_id = Class_id.STRING_8 then
Result := readable.read_string_8
elseif type_id = Class_id.IMMUTABLE_STRING_8 then
create {IMMUTABLE_STRING_8} Result.make_from_string (readable.read_string_8)
end
end
new_type_array (static_type: INTEGER): EL_TUPLE_TYPE_ARRAY
do
create Result.make_from_static (static_type)
end
feature {NONE} -- Implementation
reset_i_th_reference (tuple: TUPLE; ref_item: ANY; i, type_id: INTEGER)
do
if Eiffel.is_bag_type (type_id) and then attached {BAG [ANY]} ref_item as bag then
-- includes `STRING_GENERAL'
bag.wipe_out; counter.bump
elseif Eiffel.is_type_in_set (type_id, el_path_types)
and then attached {EL_PATH} ref_item as path
then
path.wipe_out; counter.bump
elseif type_id = Class_id.PATH and then attached {PATH} ref_item as path then
tuple.put_reference (create {PATH}.make_empty, i); counter.bump
elseif Eiffel.is_type_in_set (type_id, Class_id.immutable_string_types) and then
attached {IMMUTABLE_STRING_GENERAL} ref_item as immutable
then
if immutable.is_string_8 then
tuple.put_reference (create {IMMUTABLE_STRING_8}.make_empty, i)
counter.bump
else
tuple.put_reference (create {IMMUTABLE_STRING_32}.make_empty, i)
counter.bump
end
end
end
set_i_th_reference (tuple: TUPLE; i: INTEGER; readable: EL_READABLE; type_id: INTEGER)
do
inspect Class_id.type_category (type_id)
when C_readable_string_8 then
tuple.put_reference (new_read_string_8 (readable, type_id), i)
when C_readable_string_32 then
tuple.put_reference (new_read_string_32 (readable, type_id), i)
when C_el_path then
tuple.put_reference (new_read_path (readable, type_id), i)
else
end
end
string_width_any (object: ANY): INTEGER
do
inspect Class_id.object_type_category (object)
when C_readable_string_8 then
if attached {READABLE_STRING_8} object as str_8 then
Result := str_8.count
end
when C_readable_string_32 then
if attached {READABLE_STRING_32} object as str_32 then
Result := str_32.count
end
when C_el_path then
if attached {EL_PATH} object as path then
Result := path.count
end
when C_el_path_steps then
if attached {EL_PATH_STEPS} object as steps then
Result := steps.count
end
when C_path then
if attached {PATH} object as path then
Result := path.name.count
end
when C_type_any then
if attached {TYPE [ANY]} object as type then
Result := type.name.count
end
else
Result := object.out.count
end
end
feature {NONE} -- Internal attributes
counter: EL_NATURAL_32_COUNTER
el_path_types: SPECIAL [INTEGER]
procedure: EL_PROCEDURE
readable_string_32_types: SPECIAL [INTEGER]
readable_string_8_types: SPECIAL [INTEGER]
types_table: EL_AGENT_CACHE_TABLE [EL_TUPLE_TYPE_ARRAY, INTEGER]
feature -- Contract Support
is_filled (tuple: TUPLE; start_index, end_index: INTEGER): BOOLEAN
do
Result := across start_index |..| end_index as i_th all
tuple.is_reference_item (i_th.item) implies attached tuple.reference_item (i_th.item)
end
end
end