/* indexing description: "Set of features needed by the Eiffel compiler and Eiffel libraries to work properly" date: "$Date$" revision: "$Revision$" copyright: "Copyright (c) 1984-2006, Eiffel Software" license: "GPL version 2 see http://www.eiffel.com/licensing/gpl.txt" licensing_options: "http://www.eiffel.com/licensing" copying: "[ This file is part of Eiffel Software's Eiffel Development Environment. Eiffel Software's Eiffel Development Environment is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2 of the License (available at the URL listed under "license" above). Eiffel Software's Eiffel Development Environment is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Eiffel Software's Eiffel Development Environment; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ]" source: "[ Eiffel Software 356 Storke Road, Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" */ using System; using System.Collections; using System.Text; using System.Reflection; using EiffelSoftware.Runtime.CA; using EiffelSoftware.Runtime.Enums; using EiffelSoftware.Runtime.Types; using System.Runtime.InteropServices; namespace EiffelSoftware.Runtime { public delegate int WEL_DISPATCHER_DELEGATE (IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam); public delegate void WEL_ENUM_FONT_DELEGATE (IntPtr lpelf, IntPtr lpntm, int font_type, IntPtr lparam); public delegate void WEL_ENUM_WINDOW_DELEGATE (IntPtr hwnd); public delegate void EV_PIXMAP_IMP_DELEGATE (int error_code, int data_type, int pixmap_width, int pixmap_height, IntPtr rgb_data, IntPtr alpha_data); public delegate int WEL_RICH_EDIT_STREAM_IN_DELEGATE (IntPtr a_buffer, int a_buffer_length, IntPtr a_data_length); public delegate int WEL_RICH_EDIT_STREAM_OUT_DELEGATE (IntPtr a_buffer, int length); public delegate void WEL_DISK_SPACE_DELEGATE (int free_space, int total_space, int free_space_in_bytes, int total_space_in_bytes); public delegate void EIFFEL_PROCEDURE_DELEGATE (object args); public delegate object EIFFEL_FUNCTION_DELEGATE (object args); public delegate void EIFFEL_EVENT_HANDLER (object sender, EIFFEL_EVENT_ARGS a); public delegate int GTK_MARSHAL_DISPATCHER_DELEGATE (IntPtr action, int n_args, IntPtr args, IntPtr return_value); // Generic event arguments public class EIFFEL_EVENT_ARGS : EventArgs { public EIFFEL_EVENT_ARGS(string s) { msg = s; } private string msg; public string Message { get { return msg; } } } [Serializable] public sealed class ISE_RUNTIME { /* feature {NONE} -- Initialization */ static ISE_RUNTIME() // Type initializer { marked_objects = new Hashtable (500, new RT_REFERENCE_COMPARER()); marking_mutex = new System.Threading.Mutex(); } /* feature -- Assertions */ public static bool in_assertion () // Is checking of assertions needed? { return (internal_is_assertion_skipped || internal_in_assertion); } public static void set_in_assertion (bool val) // Set `internal_in_assertion' with `val'. { internal_in_assertion = val; } public static bool in_precondition() // Is checking precondition? { return internal_in_precondition; } public static void set_in_precondition(bool val) // set `in_precondition' with `val' { internal_in_precondition = val; } public static bool invariant_entry () // Is entry invariant checking? { return internal_invariant_entry; } public static bool check_assert (bool val) // Enable or disable checking of assertions? { bool tmp = !internal_is_assertion_skipped; internal_is_assertion_skipped = !val; return tmp; } [System.Diagnostics.DebuggerHiddenAttribute] [System.Diagnostics.DebuggerStepThroughAttribute] public static void check_invariant (object o, bool entry) // Given object `o' if it has some invariant to be checked, make // sure that they are checked and recursively goes to inherited // invariants and check them too. { EIFFEL_TYPE_INFO target; bool o_entry; o_entry = internal_invariant_entry; internal_invariant_entry = entry; if ( (!in_assertion()) && (o != null && is_assertion_checked(o.GetType(), ASSERTION_LEVEL_ENUM.invariant, false)) ) { target = o as EIFFEL_TYPE_INFO; if (target != null) { set_in_assertion(true); invariant_checked_table = new Hashtable(10); // Check current invariant defined in `target'. target._invariant(); set_in_assertion(false); } } internal_invariant_entry = o_entry; } public static bool is_invariant_checked_for (RuntimeTypeHandle type_handle) // Is `invariant' for type `type_handle' already processed? { bool Result = invariant_checked_table.ContainsKey (type_handle); if (!Result) { invariant_checked_table.Add (type_handle, true); } return Result; } [ThreadStatic] public static string assertion_tag; // Tag of last checked assertion public static void assertion_initialize (RuntimeTypeHandle type_handle) // Initializes runtime datastructure for assembly associated with // `type_handle'. { assertion_levels = new Hashtable (100); Assembly a = Type.GetTypeFromHandle (type_handle).Assembly; ASSERTION_LEVEL_ATTRIBUTE level_attribute; ASSERTION_LEVEL_ENUM l_common_level, l_current_level; bool l_computed, l_same_level; #if ASSERTIONS ASSERTIONS.CHECK ("There should be an assembly", a != null); #endif try { object [] cas = a.GetCustomAttributes (typeof (ASSERTION_LEVEL_ATTRIBUTE), false); if ((cas != null) && (cas.Length > 0)) { l_same_level = true; l_computed = false; l_common_level = ASSERTION_LEVEL_ENUM.no; foreach (object ca in cas) { level_attribute = (ASSERTION_LEVEL_ATTRIBUTE) ca; l_current_level = level_attribute.assertion_level; assertion_levels.Add ( level_attribute.class_type, // key l_current_level); // value if (!l_computed) { l_common_level = l_current_level; l_computed = true; } else { if (l_same_level) { l_same_level = (l_common_level == l_current_level); } } } if (l_same_level) { global_assertion_level = l_common_level; is_global_assertion_level_set = true; } else { is_global_assertion_level_set = false; } } else { global_assertion_level = ASSERTION_LEVEL_ENUM.no; is_global_assertion_level_set = true; } } catch { global_assertion_level = ASSERTION_LEVEL_ENUM.no; is_global_assertion_level_set = true; } } public static bool is_assertion_checked (Type t, ASSERTION_LEVEL_ENUM val, bool saved_caller_supplier_precondition) // Are assertions checked for type `t' for assertion type `val'. // Note that `val' is not a combination. { ASSERTION_LEVEL_ENUM type_assertion_level; object obj; bool Result; #if ASSERTIONS ASSERTIONS.CHECK ("Valid val", (val == ASSERTION_LEVEL_ENUM.no) || (val == ASSERTION_LEVEL_ENUM.check) || (val == ASSERTION_LEVEL_ENUM.require) || (val == ASSERTION_LEVEL_ENUM.ensure) || (val == ASSERTION_LEVEL_ENUM.loop) || (val == ASSERTION_LEVEL_ENUM.invariant)); #endif Result = !in_assertion(); if (Result) { if (val == ASSERTION_LEVEL_ENUM.require && saved_caller_supplier_precondition) { Result = true; } else { // Let's extract the specified assertion level for type `t'. // If `is_global_assertion_level_set' is set, then we can return // the global one. if (is_global_assertion_level_set) { return (global_assertion_level & val) == val; } else if ((assertion_levels != null)) { obj = assertion_levels [t]; if (obj != null) { type_assertion_level = (ASSERTION_LEVEL_ENUM) obj; } else { type_assertion_level = ASSERTION_LEVEL_ENUM.no; } } else { type_assertion_level = ASSERTION_LEVEL_ENUM.no; } Result = ((type_assertion_level & val) == val); } } return Result; } public static bool save_supplier_precondition (Type t) // Are supplier preconditions checked for type `t'. { ASSERTION_LEVEL_ENUM type_assertion_level; object obj; bool Result = caller_supplier_precondition; // Let's extract the specified assertion level for type `t'. // If `is_global_assertion_level_set' is set, then we can return // the global one. if (is_global_assertion_level_set) { caller_supplier_precondition = (global_assertion_level & ASSERTION_LEVEL_ENUM.supplier_precond ) == ASSERTION_LEVEL_ENUM.supplier_precond; return Result; } else if ((assertion_levels != null)) { obj = assertion_levels [t]; if (obj != null) { type_assertion_level = (ASSERTION_LEVEL_ENUM) obj; } else { type_assertion_level = ASSERTION_LEVEL_ENUM.no; } } else { type_assertion_level = ASSERTION_LEVEL_ENUM.no; } caller_supplier_precondition = ((type_assertion_level & ASSERTION_LEVEL_ENUM.supplier_precond ) == ASSERTION_LEVEL_ENUM.supplier_precond); return Result; } public static void restore_supplier_precondition (bool val) { caller_supplier_precondition = val; } /* feature -- Exceptions */ public static Exception last_exception // Last raised exception in `rescue' clause. { get { return _last_exception; } set { _last_exception = exception_manager.compute_last_exception(value); } } public static void restore_last_exception(Exception ex) // Restore value of `last_exception'. { _last_exception = ex; } [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] public static void enter_rescue() // Enter a rescue clause, we increase the rescue level { _rescue_level++; } public static bool exception_from_rescue () // Exception was raised in rescue clause? { return (rescue_level > 1); } [ThreadStatic] private static Exception _last_exception; // Store exception object per thread. [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] public static RT_EXCEPTION_MANAGER exception_manager // Exception manager // The exception manager instance might not exist, when the entry point is not executed. // The normal situation is assemblies generated by ISE compiler are used by other systems. // In this case, we try to locate the associated type among all loaded assemblies and initialize such. { get { if (_exception_manager != null) { return _exception_manager; } else { _exception_manager = create_exception_manager(); return _exception_manager; } } set { _exception_manager = value; } } private static RT_EXCEPTION_MANAGER _exception_manager; // Hold the object for `exception_manager' attribute. private static RT_EXCEPTION_MANAGER create_exception_manager() // Looks for type ISE_EXCEPTION_MANAGER in all loaded assemblies, // and create the instance of it. { Assembly [] l_assemblies = AppDomain.CurrentDomain.GetAssemblies(); Type l_t = null; foreach (Assembly l_ass in l_assemblies) { l_t = l_ass.GetType("EiffelSoftware.Library.Base.Kernel.Dotnet.Impl.IseExceptionManager"); if (l_t == null) { l_t = l_ass.GetType("EiffelSoftware.Library.Base.kernel.dotnet.Impl.ISE_EXCEPTION_MANAGER"); } if (l_t != null) { break; } } object l_o = Activator.CreateInstance(l_t); return l_o as RT_EXCEPTION_MANAGER; } [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] private static Type getTypeOfAssertionViolation () { Assembly [] l_assemblies = AppDomain.CurrentDomain.GetAssemblies(); Type l_t = null; foreach (Assembly l_ass in l_assemblies) { l_t = l_ass.GetType("EiffelSoftware.Library.Base.kernel.exceptions.AssertionViolation"); if (l_t == null) { l_t = l_ass.GetType("EiffelSoftware.Library.Base.kernel.exceptions.ASSERTION_VIOLATION"); } if (l_t != null) { break; } } return l_t; } [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] public static bool is_ignore_contract_violation_once; //Should next/current contract violation be ignored? [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] public static void set_ignore_contract_violation_once (bool a_bool) //Set `is_ignore_contract_violation_once' with `a_bool' { is_ignore_contract_violation_once = a_bool; } public static void raise (Exception e) // Throw an exception `e'. { try{ throw e; }catch (Exception a_e) { if (!is_ignore_contract_violation_once) { throw; }else { //reset flag first is_ignore_contract_violation_once = false; Type l_t = getTypeOfAssertionViolation(); if (a_e.GetType().IsSubclassOf(l_t)) { // Do nothing, just ignore it } else { throw; } } } } public static void generate_call_on_void_target_exception () // Throw VOID_TARGET // when first argument of static routine of ANY is Void. { raise_code(exception_manager.Void_call_target(), ""); } [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] internal static void raise_precondition(string msg) // Throw PRECONDITION_VIOLATION // when first argument of static routine of ANY is Void. { raise_code(exception_manager.Precondition(), msg); } [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] internal static void raise_postcondition(string msg) // Throw POSTCONDITION_VIOLATION // when first argument of static routine of ANY is Void. { raise_code(exception_manager.Postcondition(), msg); } [EIFFEL_CONSUMABLE_ATTRIBUTE (false)] internal static void raise_check(string msg) // Throw CHECK_VIOLATION // when first argument of static routine of ANY is Void. { raise_code(exception_manager.Check_instruction(), msg); } [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] public static void raise_code(int e_code, string msg) // Raise Eiffel code exception of code `e_code'. { exception_manager.internal_raise(e_code, msg); } public static void raise_old(Exception ex) // Raise Eiffel code exception of code `e_code'. { exception_manager.internal_raise_old(ex); } [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] public static void rethrow (bool for_once) //Throw unhandled exception at the end of rescue clause. { exception_manager.throw_last_exception(_last_exception, for_once); } [EIFFEL_CONSUMABLE_ATTRIBUTE(false)] public static int rescue_level // Record number of levels in rescue clause. { get { return _rescue_level; } set { _rescue_level = value; } } [ThreadStatic] private static int _rescue_level; // Record number of levels in rescue clause. /* feature {NONE} -- RT Extension */ [ThreadStatic] public static RT_EXTENSION_I rt_extension_object; // RT_EXTENSION object /* feature {NONE} -- Implementation */ private static Hashtable assertion_levels; // HASH_TABLE [ASSERTION_LEVEL_ENUM, Type] to store for each Eiffe type // its associated assertion level. /* feature {NONE} -- Implementations: Assertions */ [ThreadStatic] private static Hashtable invariant_checked_table; // Equivalent of an HASH_TABLE [Boolean, RuntimeTypeHandle] // For each type we have processed, key is True. [ThreadStatic] private static bool internal_is_assertion_skipped = false; // Are assertions skipped? [ThreadStatic] private static bool internal_in_assertion = false; // Flag used during assertion checking to make sure // that assertions are not checked within an assertion // checking. [ThreadStatic] private static bool internal_invariant_entry = false; // Flag if invariant checking is the entry of a routine. [ThreadStatic] private static bool internal_in_precondition = false; // Flag if in precondition checking. [ThreadStatic] private static bool caller_supplier_precondition = false; // Flag used to detect whether the caller has supplier // preconditions enabled. private static ASSERTION_LEVEL_ENUM global_assertion_level = ASSERTION_LEVEL_ENUM.no; // Default global level of assertion checking. If `is_global_assertion_level_set' // then all types have the same level of assertions, therefore no need to look // into the `assertion_levels' table to find out if we should check the assertion // for a given type. private static bool is_global_assertion_level_set = false; // Is `global_assertion_level' set? /* feature -- Builtin implementations for Eiffel classes, see Eiffel classes for comments */ private static System.Threading.Mutex identified_mutex = new System.Threading.Mutex(); // Synchronization object for all IDENTIFIED_ROUTINES operations. private static System.Collections.Generic.List<WeakReference> identified_list = new System.Collections.Generic.List<WeakReference>(50); // List holding the IDENTIFIED objects. Synchronized access using `identified_mutex'. public static int builtin_IDENTIFIED_CONTROLLER_object_id_stack_size (object Current) { int Result; identified_mutex.WaitOne(); Result = identified_list.Capacity / 1000 + 1; identified_mutex.ReleaseMutex(); return Result; } public static void builtin_IDENTIFIED_CONTROLLER_extend_object_id_stack (object Current, int nb_chunks) { identified_mutex.WaitOne(); identified_list.Capacity = identified_list.Capacity + nb_chunks * 1000; identified_mutex.ReleaseMutex(); } public static object builtin_IDENTIFIED_ROUTINES_eif_id_object (int an_id) // Return object associated with `an_id' if ANY, Void otherwise. { object Result = null; identified_mutex.WaitOne(); if (an_id > 0 && an_id <= identified_list.Count) { WeakReference wr = identified_list [an_id - 1]; if (wr != null) { Result = wr.Target; if (Result == null) { // Object has been collected, let's get rid of the associated weak reference identified_list [an_id - 1] = null; } } } identified_mutex.ReleaseMutex(); return Result; } public static int builtin_IDENTIFIED_ROUTINES_eif_object_id (object an_object) // Compute new ID for object `an_object'. { int Result; identified_mutex.WaitOne(); identified_list.Add(new WeakReference(an_object)); Result = identified_list.Count; identified_mutex.ReleaseMutex(); return Result; } public static void builtin_IDENTIFIED_ROUTINES_eif_object_id_free (int an_id) // Free the entry `an_id'. { identified_mutex.WaitOne(); if (an_id <= identified_list.Count) { identified_list [an_id - 1] = null; } identified_mutex.ReleaseMutex(); } public static bool builtin_PLATFORM_is_thread_capable () { return true; } public static bool builtin_PLATFORM_is_scoop_capable () { return false; } public static bool builtin_PLATFORM_is_dotnet () { return true; } public static bool builtin_PLATFORM_is_windows () { #if NET5_0_OR_GREATER return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); #else return true; #endif } public static bool builtin_PLATFORM_is_unix () { #if NET5_0_OR_GREATER return (! RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); #else return false; #endif } public static bool builtin_PLATFORM_is_vms () { return false; } public static bool builtin_PLATFORM_is_mac () { #if NET5_0_OR_GREATER return RuntimeInformation.IsOSPlatform(OSPlatform.OSX); #else return false; #endif } public static bool builtin_PLATFORM_is_vxworks () { return false; } public static bool builtin_PLATFORM_is_64_bits () { return IntPtr.Size == 8; } public static int builtin_PLATFORM_boolean_bytes () { return 1; } public static int builtin_PLATFORM_character_bytes () { return 1; } public static int builtin_PLATFORM_wide_character_bytes () { return 4; } public static int builtin_PLATFORM_integer_bytes () { return 4; } public static int builtin_PLATFORM_real_bytes () { return 4; } public static int builtin_PLATFORM_double_bytes () { return 8; } public static int builtin_PLATFORM_pointer_bytes () { return System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)); } public static float builtin_REAL_32_REF_nan () { return System.Single.NaN; } public static float builtin_REAL_32_REF_negative_infinity () { return System.Single.NegativeInfinity; } public static float builtin_REAL_32_REF_positive_infinity () { return System.Single.PositiveInfinity; } public static double builtin_REAL_64_REF_nan () { return System.Double.NaN; } public static double builtin_REAL_64_REF_negative_infinity () { return System.Double.NegativeInfinity; } public static double builtin_REAL_64_REF_positive_infinity () { return System.Double.PositiveInfinity; } public static int builtin_IDENTIFIED_ROUTINES_eif_current_object_id(object Current){ return builtin_IDENTIFIED_ROUTINES_eif_object_id (Current); } public static bool builtin_IDENTIFIED_ROUTINES_eif_is_object_id_of_current(object Current, int an_id) { return builtin_IDENTIFIED_ROUTINES_eif_id_object(an_id) == Current; } /* feature -- IEEE comparisons of REAL_32 and REAL_64 */ // Disabling warning is necessary #pragma warning disable 1718 public static bool is_equal_real_32 (float d1, float d2) { return (d1 == d1 ? d1 == d2 : d2 != d2); } public static bool is_less_real_32 (float d1, float d2) { return (d1 == d1 ? d1 < d2 : d2 == d2); } public static bool is_less_equal_real_32 (float d1, float d2) { return (d1 == d1 ? d1 <= d2 : true); } public static bool is_greater_real_32 (float d1, float d2) { return (d2 == d2 ? d1 > d2 : d1 == d1); } public static bool is_greater_equal_real_32 (float d1, float d2) { return (d2 == d2 ? d1 >= d2 : true); } public static bool is_equal_real_64 (double d1, double d2) { return (d1 == d1 ? d1 == d2 : d2 != d2); } public static bool is_less_real_64 (double d1, double d2) { return (d1 == d1 ? d1 < d2 : d2 == d2); } public static bool is_less_equal_real_64 (double d1, double d2) { return (d1 == d1 ? d1 <= d2 : true); } public static bool is_greater_real_64 (double d1, double d2) { return (d2 == d2 ? d1 > d2 : d1 == d1); } public static bool is_greater_equal_real_64 (double d1, double d2) { return (d2 == d2 ? d1 >= d2 : true); } public static float min_real_32 (float i, float j) { return (is_less_equal_real_32(i, j) ? i : j); } public static double min_real_64 (double i, double j) { return (is_less_equal_real_64(i, j) ? i : j); } public static float max_real_32 (float i, float j) { return (is_greater_equal_real_32(i, j) ? i : j); } public static double max_real_64 (double i, double j) { return (is_greater_equal_real_64(i, j) ? i : j); } public static int three_way_comparison_real_32 (float i, float j) { return (is_less_real_32(i, j) ? -1 : is_less_real_32(j, i) ? 1 : 0); } public static int three_way_comparison_real_64 (double i, double j) { return (is_less_real_64(i, j) ? -1 : is_less_real_64(j, i) ? 1 : 0); } #pragma warning restore 1718 /* feature -- Redirection to feature of ANY class */ public static bool conforms_to (Object obj1, Object obj2) // Does dynamic type of object attached to `obj1' conform to // dynamic type of object attached to `obj2'? { return ANY.conforms_to (obj1, obj2); } public static object clone (object Current, object other) // 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'. { return ANY.clone (Current, other); } public static void copy (object Current, object other) // Update current object using fields of object attached // to `other', so as to yield equal objects. { ANY.copy (Current, other); } public static object deep_clone (object Current, object other) // Obsolete use `deep_twin' instead. { return ANY.deep_clone (Current, other); } public static void deep_copy (object Current, object other) // Effect equivalent to that of: // `copy' (`other' . `deep_twin') { ANY.deep_copy (Current, other); } public static bool deep_equal (object Current, object some, object other) // Are `some' and `other' either both void // or attached to isomorphic object structures? { return ANY.deep_equal (Current, some, other); } public static bool is_deep_equal (object Current, object other) // Are `Current' and `other' attached to isomorphic object structures? { return ANY.deep_equal (Current, Current, other); } public static object deep_twin (object Current) // New object structure recursively duplicated from Current. { return ANY.deep_twin (Current); } public static bool equal (object Current, object some, object other) // Are `some' and `other' either both void or attached // to objects considered equal? { return ANY.equal (Current, some, other); } public static String generator (object o) // Generator class name of `o'. { return ANY.generator (o); } public static String generating_type (object o) // Generating type name of `o'. { return ANY.generating_type (o); } public static bool is_equal (object Current, object other) // Is `other' attached to an object considered // equal to current object? { return ANY.is_equal (Current, other); } public static String @out (object o) // `out' of `o' { return ANY.@out (o); } public static bool same_type (object Current, object other) // Is type of current object identical to type of `other'? { return ANY.same_type (Current, other); } public static object standard_clone (object Current, object other) // Void if `other' is void; otherwise new object // field-by-field identical to `other'. // Always uses default copying semantics. { return ANY.standard_clone (Current, other); } public static void standard_copy (object Current, object other) // Update current object using fields of object attached // to `other', so as to yield equal objects. { ANY.standard_copy (Current, other); } public static bool standard_equal (object Current, object some, object other) // Are `some' and `other' either both void or attached to // field-by-field identical objects of the same type? // Always uses default object comparison criterion. { return ANY.standard_equal (Current, some, other); } public static bool standard_is_equal (object Current, object other) // Is `other' attached to an object of the same type // as current object, and field-by-field identical to it? { return ANY.standard_is_equal (Current, other); } public static object standard_twin (object Current) // New object field-by-field identical to `other'. // Always uses default copying semantics. { return ANY.standard_twin (Current); } public static String tagged_out (object o) // `out' of `o' { return ANY.tagged_out (o); } public static object twin (object Current) // New object equal to `Current' // `twin' calls `copy'; to change copying/twining semantics, redefine `copy'. { return ANY.twin (Current); } /* feature -- Object creation */ public static object create_type (RT_CLASS_TYPE a_type) // Create new instance of `a_type'. { // Create new object of type `a_type'. // Properly initializes `Result'. return GENERIC_CONFORMANCE.create_instance (Type.GetTypeFromHandle (a_type.type), a_type as RT_GENERIC_TYPE); } /* feature -- Status report */ public static int generic_parameter_count (object o) // Number of generic Parameter if any. { int Result = 0; EIFFEL_TYPE_INFO l_object = o as EIFFEL_TYPE_INFO; if (l_object != null) { Result = l_object.____type ().count; } return Result; } public static Type interface_type (Type a_type) // Given a type `a_type' retrieves its associated interface type if any (i.e. only // it is an Eiffel type). // Used for conformance because the .NET routine `GetType()' will always return // the implementation type and it cannot be used for conformance because two implementation // classes do not conform even if their interfaces do. { object [] l_attributes; Type result; #if ASSERTIONS ASSERTIONS.REQUIRE ("a_type not null", a_type != null); #endif result = interface_type_mapping [a_type] as Type; if (result == null) { l_attributes = a_type.GetCustomAttributes (typeof (RT_INTERFACE_TYPE_ATTRIBUTE), false); if (l_attributes != null && l_attributes.Length > 0) { result = ((RT_INTERFACE_TYPE_ATTRIBUTE) l_attributes [0]).class_type; } else { l_attributes = a_type.GetCustomAttributes (typeof (INTERFACE_TYPE_ATTRIBUTE), false); if (l_attributes != null && l_attributes.Length > 0) { result = ((INTERFACE_TYPE_ATTRIBUTE) l_attributes [0]).class_type; } else { result = a_type; } } interface_type_mapping [a_type] = result; } return result; } private static Hashtable interface_type_mapping = new Hashtable (100); // Mapping between implementation types and interface types. public static RT_GENERIC_TYPE generic_type (object an_obj) // Given an Eiffel object `an_obj' retrieves its associated type if any. { EIFFEL_TYPE_INFO l_object = an_obj as EIFFEL_TYPE_INFO; if (l_object != null) { return l_object.____type (); } else { return null; } } public static RT_CLASS_TYPE type_of_generic (object an_obj, int pos) // Given an Eiffel object `an_obj', find the associated type of generic parameter // at position `pos'. { EIFFEL_TYPE_INFO l_object = an_obj as EIFFEL_TYPE_INFO; if (l_object != null) { #if ASSERTIONS ASSERTIONS.REQUIRE ("Has generic info", l_object.____type() != null); ASSERTIONS.REQUIRE ("Valid position `pos'", (pos > 0) && (pos <= l_object.____type().count)); ASSERTIONS.REQUIRE ("valid element type", l_object.____type().generics [pos - 1] is RT_CLASS_TYPE); #endif return (RT_CLASS_TYPE) (l_object.____type ().generics [pos - 1]); } else { return null; } } public static object attempted_on_type (Type a_type, object obj) // Given an dotnet type `a_type` , return `obj` if it is an instance of that type. { if (a_type != null && a_type.IsInstanceOfType (obj)) { return obj; } return null; } public static object attempted_on_rt_type (object current, RT_TYPE a_rt_type, object obj) // return `obj` if it is an instance of `a_rt_type`, or // of type associated with position of formal type for `current` object. { Type t = null; if (a_rt_type is RT_CLASS_TYPE) { RT_CLASS_TYPE cl_t = a_rt_type as RT_CLASS_TYPE; t = cl_t.dotnet_type(); } else if (a_rt_type is RT_FORMAL_TYPE) { RT_FORMAL_TYPE f_t = a_rt_type as RT_FORMAL_TYPE; t = type_of_generic_parameter (current, f_t.position); } return attempted_on_type (t,obj); } //FIXME: to remove when TUPLE is updated not to use this routine anymore. public static Type type_of_generic_parameter (object an_obj, int pos) // Given an Eiffel object `an_obj', find the associated type of generic parameter // at position `pos'. { EIFFEL_TYPE_INFO l_object = an_obj as EIFFEL_TYPE_INFO; RT_GENERIC_TYPE l_gen_type; RT_CLASS_TYPE cl_type; Type Result = null; if (l_object != null) { #if ASSERTIONS ASSERTIONS.REQUIRE ("Has generic info", l_object.____type() != null); ASSERTIONS.REQUIRE ("Valid position `pos'", (pos > 0) && (pos <= l_object.____type().count)); #endif l_gen_type = l_object.____type (); cl_type = (RT_CLASS_TYPE) l_gen_type.generics [pos - 1]; if (!cl_type.is_basic ()) { if (cl_type.type.Value != (System.IntPtr) 0) { Result = interface_type (Type.GetTypeFromHandle (cl_type.type)); } else { /* Generic parameter is of type NONE, so we return an instance * of RT_NONE_TYPE as associated type. It is mostly there to fix * assertions violations in TUPLE when one of the elements of * a manifest tuple is `Void'. */ #if ASSERTIONS ASSERTIONS.CHECK ("Is NONE type.", cl_type is RT_NONE_TYPE); #endif Result = typeof(RT_NONE_TYPE); } } else { Result = Type.GetTypeFromHandle (cl_type.type); } } return Result; } public static Boolean is_eiffel_string (object o) // Is `o' an instance of an Eiffel STRING. { RT_GENERIC_TYPE l_gen_type; EIFFEL_TYPE_INFO info = o as EIFFEL_TYPE_INFO; Boolean Result = false; if (info != null) { l_gen_type = info.____type (); if (l_gen_type == null) { // Not a generic class, possibly a good candidate for STRING. Result = info.____class_name ().Equals ("STRING"); } } return Result; } public static Boolean is_eiffel_array (object o) // Is `o' an instance of an Eiffel ARRAY. { RT_GENERIC_TYPE l_gen_type; EIFFEL_TYPE_INFO info = o as EIFFEL_TYPE_INFO; Boolean Result = false; if (info != null) { l_gen_type = info.____type (); if (l_gen_type != null) { // A generic class, possibly a good candidate for ARRAY. Result = l_gen_type.class_name ().Equals ("ARRAY"); } } return Result; } public static String eiffel_string (object o) // System.String representation of `o' if it is an Eiffel STRING instance. { String Result = null; if (is_eiffel_string (o)) { Result = "\"" + o.ToString () + "\""; } return Result; } public static Array eiffel_array (object o) // System.Array representation of `o' if it is an Eiffel ARRAY instance. { Array Result = null; Type eiffel_array_type, eiffel_special_type; FieldInfo area_info, native_info; Object special; if (is_eiffel_array (o)) { // Get SPECIAL object eiffel_array_type = o.GetType(); area_info = eiffel_array_type.GetField ("$$area"); if (area_info == null) { area_info = eiffel_array_type.GetField ("$$Area"); } special = area_info.GetValue (o); // Get System.Array eiffel_special_type = special.GetType(); native_info = eiffel_special_type.GetField ("$$internal_native_array"); if (native_info == null) { native_info = eiffel_special_type.GetField ("internal_native_array"); if (native_info == null) { native_info = eiffel_special_type.GetField ("$$internalNativeArray"); if (native_info == null) { native_info = eiffel_special_type.GetField ("internalNativeArray"); } } } Result = (Array) native_info.GetValue (special); } return Result; } /* feature -- Hash code */ public static Int32 hash_code (Object o) // Result of call of `o.GetHashCode()'. { return o.GetHashCode(); } /* feature -- Duplication */ public static object standard_clone (object obj) // { #if ASSERTIONS ASSERTIONS.REQUIRE ("Valid type", obj is EIFFEL_TYPE_INFO); #endif return GENERIC_CONFORMANCE.create_like_object ((EIFFEL_TYPE_INFO) obj); } /* feature -- Marking */ public static bool is_object_marked (object obj) // Is `obj' marked? // Note that `marking_mutex' should be owned to safely call this routine. { return marked_objects.Contains(obj); } public static void mark_object (object obj) // Mark object `obj'. // Note that `marking_mutex' should be owned to safely call this routine. { marked_objects.Add(obj, obj); } public static void unmark_object(object obj) // Mark object `obj'. // Note that `marking_mutex' should be owned to safely call this routine. { marked_objects.Remove(obj); } public static void lock_marking () // Get a lock for `mark_object', `unmark_object' and `is_object_marked' so that they can // be safely executed. { marking_mutex.WaitOne(); } public static void unlock_marking () // Release a lock for `mark_object', `unmark_object' and `is_object_marked' so that marking // routines can be executed from another thread. { marking_mutex.ReleaseMutex(); } private static Hashtable marked_objects; // Store all marked objects. private static System.Threading.Mutex marking_mutex; // Mutex used to mark objects in `marked_objects'. /* feature -- Introspection */ public static int field_bit_size (int i, object obj) // BIT size of the `i'-th field of `obj' assuming it is a BIT instance. { // BIT types are not implemented on .NET return 0; } [CLSCompliant(false)] public static ulong object_size (object obj) // Physical size of an object. { #if ASSERTIONS ASSERTIONS.REQUIRE("obj not void", obj != null); #endif return (ulong) System.Runtime.InteropServices.Marshal.SizeOf(obj.GetType()); } public static void set_field_of_expanded (object root_object, FieldInfo [] a_fields, FieldInfo a_field, object val) // Set `a_field' with `val', an attribute reachable from `root_object' using `a_fields' as a path to // reach it. { TypedReference t = TypedReference.MakeTypedReference(root_object, a_fields); a_field.SetValueDirect(t, val); } public static object field_of_expanded (object root_object, FieldInfo [] a_fields, FieldInfo a_field) // Get value of `a_field', an attribute reachable from `root_object' using `a_fields' as a path to // reach it. { TypedReference t = TypedReference.MakeTypedReference(root_object, a_fields); return a_field.GetValueDirect(t); } } }