class EL_TYPE_UTILITIES
SED_UTILITIES with optimized abstract_type and various type property queries
note
description: "[
${SED_UTILITIES} with optimized `abstract_type' and various type property queries
]"
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: "2025-04-23 15:30:28 GMT (Wednesday 23rd April 2025)"
revision: "11"
class
EL_TYPE_UTILITIES
inherit
SED_UTILITIES
rename
abstract_type as abstract_type_of_type
redefine
abstract_type_of_type
end
EL_EIFFEL_C_API
rename
eif_type_flags as type_flags
export
{NONE} all
end
EL_CONTAINER_CONVERSION [ANY]
feature -- Access
abstract_type (object: ANY): INTEGER
do
Result := abstract_type_of_type (dynamic_type (object))
end
abstract_type_of_type (a_type_id: INTEGER): INTEGER
-- Abstract type of `a_type_id'.
do
Result := abstract_type_item (Abstract_type_array, a_type_id)
end
abstract_type_of_type_plus (a_type_id: INTEGER): INTEGER
-- The same as `abstract_type_of_type' except `a_type_id' might also be
-- the reference version of an expanded type, `({NATURAL_8_REF}).type_id' for example.
do
Result := abstract_type_item (Abstract_type_array_plus, a_type_id)
end
dynamic_type (object: separate ANY): INTEGER
do
Result := {ISE_RUNTIME}.dynamic_type (object)
end
type_parameters (type: TYPE [ANY]): IMMUTABLE_STRING_8
-- type parameter list as a shared sub-string from `type.name'
local
left_index, right_index: INTEGER
do
if attached type.name as name then
left_index := name.index_of ('[', 1)
if left_index > 0 then
right_index := name.last_index_of (']', name.count)
if right_index > 0 then
Result := name.shared_substring (left_index + 1, right_index - 1)
else
Result := name.shared_substring (1, 0)
end
else
Result := name.shared_substring (1, 0)
end
end
end
type_flag_names (flags: NATURAL_16): EL_STRING_8_LIST
local
i: INTEGER
do
create Result.make (7)
from i := 1 until i > Type_status_array.count loop
if flags & (1 |<< (i + 5)).to_natural_16 > 0 then
Result.extend (Type_status_array [i])
end
i := i + 1
end
end
feature -- Status query
is_reference_type (type_id: INTEGER): BOOLEAN
do
Result := not is_type_expanded (type_flags (type_id))
end
is_type_in_set (type_id: INTEGER; set: SPECIAL [INTEGER]): BOOLEAN
local
i: INTEGER
do
from until i = set.count or Result loop
Result := type_id = set [i]
i := i + 1
end
end
is_uniform_type (container: CONTAINER [ANY]): BOOLEAN
-- `True' if items in `container' are all the same type
local
i, type_first: INTEGER
do
Result := True
if attached as_structure (container) as structure
and then attached structure.to_special_shared as area and then area.count > 0
then
type_first := dynamic_type (area [0])
from i := 1 until i = area.count or not Result loop
Result := dynamic_type (area [i]) = type_first
i := i + 1
end
end
end
same_type_as (item: ANY; type_id: INTEGER): BOOLEAN
do
Result := dynamic_type (item) = type_id
end
same_abstract_types (type_id_1, type_id_2: INTEGER): BOOLEAN
-- `True' if abstract type of both `type_id_1' and `type_id_2' are the same
-- even if one is the reference type ancestor of an expanded type.
-- For example: {BOOLEAN_REF}.type_id and {BOOLEAN}.type_id will be the same.
do
Result := abstract_type_of_type_plus (type_id_1) = abstract_type_of_type_plus (type_id_2)
end
feature -- Status type flag
is_type_composite (flags: NATURAL_16): BOOLEAN
do
Result := (flags & {EL_TYPE_FLAG}.Is_composite) > 0
end
is_type_dead (flags: NATURAL_16): BOOLEAN
do
Result := (flags & {EL_TYPE_FLAG}.Is_dead) > 0
end
is_type_declared_expanded (flags: NATURAL_16): BOOLEAN
do
Result := (flags & {EL_TYPE_FLAG}.Is_declared_expanded) > 0
end
is_type_deferred (flags: NATURAL_16): BOOLEAN
do
Result := (flags & {EL_TYPE_FLAG}.Is_deferred) > 0
end
is_type_expanded (flags: NATURAL_16): BOOLEAN
do
Result := (flags & {EL_TYPE_FLAG}.Is_expanded) > 0
end
is_type_frozen (flags: NATURAL_16): BOOLEAN
do
Result := (flags & {EL_TYPE_FLAG}.Is_frozen) > 0
end
is_type_special (flags: NATURAL_16): BOOLEAN
do
Result := (flags & {EL_TYPE_FLAG}.Is_special) > 0
end
is_type_tuple (flags: NATURAL_16): BOOLEAN
do
Result := (flags & {EL_TYPE_FLAG}.Is_tuple) > 0
end
type_has_dispose (flags: NATURAL_16): BOOLEAN
do
Result := (flags & {EL_TYPE_FLAG}.Has_dispose) > 0
end
feature {NONE} -- Implementation
abstract_type_item (array: ARRAY [INTEGER]; i: INTEGER): INTEGER
do
if array.valid_index (i) then
Result := array [i]
else
Result := {REFLECTOR_CONSTANTS}.Reference_type
end
inspect Result
when {REFLECTOR_CONSTANTS}.None_type then
Result := {REFLECTOR_CONSTANTS}.reference_type
else
end
end
is_reference_name_of (type_id: INTEGER; expanded_type: STRING_8): BOOLEAN
-- `True' if `type_id' is reference version of `expanded_type'
do
if attached {ISE_RUNTIME}.generating_type_of_type (type_id) as ref_name
and then ref_name.count = expanded_type.count + 4 and then ref_name.starts_with (expanded_type)
then
Result := ref_name.same_characters ("_REF", 1, 4, expanded_type.count + 1)
end
end
reference_type_of (abstract_type_id: INTEGER): INTEGER
-- Eg. if `abstract_type_id' is `({BOOLEAN}).type_id' then the result
-- is ({BOOLEAN_REF}).type_id
local
break: BOOLEAN; type_name: STRING_8
do
type_name := {ISE_RUNTIME}.generating_type_of_type (abstract_type_id)
from Result := abstract_type_id - 1 until Result < 0 or break loop
if {ISE_RUNTIME}.type_conforms_to (abstract_type_id, Result)
and then is_reference_name_of (Result, type_name)
then
break := True
else
Result := Result - 1
end
end
end
feature {NONE} -- Constants
Abstract_type_array: ARRAY [INTEGER]
-- `Special_type_mapping' as sparse array for faster lookup
local
map_list: EL_ARRAYED_MAP_LIST [INTEGER, INTEGER]
once
create map_list.make_from_table (Special_type_mapping)
map_list.sort_by_key (True)
create Result.make_filled ({REFLECTOR_CONSTANTS}.None_type, map_list.first_key, map_list.last_key)
across map_list as map loop
Result [map.key] := map.value
end
end
Abstract_type_array_plus: ARRAY [INTEGER]
-- `Abstract_type_array' with the addition of reference versions of basic expanded types
-- Eg. << ({BOOLEAN_REF}).type_id, ({NATURAL_8_REF}).type_id, .. >>
local
type_id, lower, upper, l_type: INTEGER
once
lower := Abstract_type_array.lower; upper := Abstract_type_array.upper
create Result.make_filled ({REFLECTOR_CONSTANTS}.None_type, reference_type_of (lower), upper)
if attached Abstract_type_array as array then
from type_id := lower until type_id > upper loop
l_type := array [type_id]
inspect l_type
when {REFLECTOR_CONSTANTS}.None_type then
do_Nothing
else
Result [type_id] := l_type; Result [reference_type_of (type_id)] := l_type
end
type_id := type_id + 1
end
end
end
Type_status_array: EL_STRING_8_LIST
once
Result := "tuple, special, declared-expanded, expanded, has-dispose, composite, deferred, frozen, dead"
end
end