/*********************************************************************
(C) Copyright 1994;       MetaWare Incorporated;  Santa Cruz, CA 95060
This program is the unpublished property and trade secret of MetaWare.
It is to be  utilized  solely  under  license  from  MetaWare  and  it
is to be maintained on a confidential basis for internal  company  use
only.  The  security  and  protection  of  the program is paramount to
maintenance of the trade secret status.  It is to  be  protected  from
disclosure  to	unauthorized parties, both within the Licensee company
and outside, in a manner not less stringent than that utilized for Li-
censee's own proprietary  internal  information.   No  copies  of  the
source or Object Code are to leave the premises of Licensee's business
except	in  strict accordance with the license agreement signed by Li-
censee with MetaWare.
*********************************************************************/

#ifndef _TYPEINFO_H
#define _TYPEINFO_H

#if __TYPEINFO_IMPLEMENTATION
#if __SOM_ENABLED__
#include "som.ch"
// IBM's somcorba.h defines true and false!
#undef TRUE
#undef FALSE
#else
class SOMClass{}; class SOMObject{}; typedef char boolean;
#endif
#define SOMClass SOMClass
#endif

#if !defined(_CRTIMPCC)
    #if _MSNT && _DLL && !_DLLBUILD
	#define _CRTIMPCC __declspec(dllimport)
    #else
	#define _CRTIMPCC
    #endif
#endif

#pragma off(macro_substitution)

namespace typeinfo {

pragma on(run_time_type_info);

struct Force_vtab_at_0 {
    virtual ~Force_vtab_at_0();// = 0;
    };

// We used to figure out which kind a type was by doing address comparisons
// but this failed across DLLs, because each DLL had a separate copy of
// the fundamental types below.  So, we had to resort to storing the
// kind in the type.
short enum type_kind { 	// short: MAKE SURE this is one byte always.
    t_null,             // Not a type.
    t_basic,            // basic type: integer or pointer.
    t_pointer,          // pointer type
    t_array,            // an array
    t_class,            // a class/struct type
    t_member_pointer,   // a pointer-to-member
    t_func,             // a function type
    t_modified,         // a const/volatile-modified type
    t_SOM_class         // a SOM class/struct type
    };

class Type_info : Force_vtab_at_0 {
  private:
    Type_info& operator= (const Type_info&);	// Permit no assignment.
    char version;		// Version of the typeid structure.
    unsigned char _fnhash;      // Hash of full name.  Check hash before doing strcmp.
    type_kind tk;       	// Which kind of type is this?
    char pad1;			// Padding.
    const char *_name;		// Likeable type name, such as int *.
    const char *_full_name;	// Mangling, including full nesting.
    long _size;			// Type size.  (For SOM, this is dynamic.)
  protected:
    Type_info(const Type_info&);
    Type_info();
  public:
    virtual ~Type_info();
    virtual int operator ==(const Type_info&) const;
    virtual int operator !=(const Type_info&) const;
    virtual int before(const Type_info&) const;
    virtual const char* name() const;   // Simple name.
    virtual const char* full_name() const;	// Full name: w/mangling.
    virtual long size() const;	// Size of an object of this type.
    };

// Modified types:
class Modified_type_info: public Type_info {
  private:
    // Type flags from the compiler.  tf_CONST and tf_VOLATILE bits go here.
    long _type_flags;	// Compiler type flags.
    const Type_info *_modified_type;
  public:
    enum {tf_CONST = 1, tf_VOLATILE = 2};
    ~Modified_type_info();
    virtual long type_flags() const;
    virtual const Type_info *modified_type() const;
    };	

// Pointer types:
class Pointer_type_info: public Type_info {
  private:
    const Type_info *_base_type; // Pointer to base type's type info.
    char _pointer_is_ref;	// Whether this pointer is a reference type.
  public:
    ~Pointer_type_info();
    virtual const Type_info *base_type() const;
    virtual char pointer_is_ref() const;
    };

// Pointer-to-member types:
class Member_pointer_type_info: public Type_info {
  private:
    const Type_info *_base_type; // Pointer to base type's type info.
    const Type_info *_of_class;	// Class members to which we may point.
  public:
    ~Member_pointer_type_info();
    virtual const Type_info *base_type() const;
    virtual const Type_info *of_class() const;
    };

// Array types:
class Array_type_info: public Type_info {
  private:
    const Type_info *_element_type;    // Element type.
    unsigned long _element_count;      // # of elements.
  public:
    ~Array_type_info();
    virtual const Type_info *element_type() const;
    virtual unsigned long element_count() const;
    };

// Function types:
class Func_type_info: public Type_info {
  private:
    const Type_info *_return_type;
    const char *_signature;	// Contains everything you wanted to know about
				// the type, except return type
				// (with cfront-based mangling schemes).
  public:				
    ~Func_type_info();
    virtual const Type_info *return_type() const;
    virtual const char *signature() const;
    };

typedef short enum {		// short: MAKE SURE this is one byte always.
    A_NULL, A_PRIVATE, A_PROTECTED, A_PUBLIC, A_IDENTITY,
    } Access;

// Class types:
class Class_type_info;

// Abundant class information is given only for native C++ classes.
// SOM classes simply refer to the class object.

// pragma off(run_time_type_info);	// Don't want it for Base_info/Vbase_info/Member_info.
struct Base_info {
  private:
    const Class_type_info *_base;	// We know bases are of Class_type.
    Access _access;           	// Access of base.
    char _is_virtual;		// Is this base virtual?
    char pad1,pad2;
    long _offset;		// Offset to this base or to its virtual ptr.
  public:
    // These functions can't be virtual because it would change
    // the size of Base_info and break binary compatibility.
    // Same goes for Vbase_info and Member_info.
    const Class_type_info *base() const;
    Access access() const;
    char is_virtual() const;
    long offset() const;
    };

struct Vbase_info {
  private:
    const Class_type_info *_base;	// We know bases are of Class_type.
    char _has_ctd;		// Does this vbase have a ctor displacement?
    char pad1,pad2,pad3;
    long _offset;		// Offset to this base or to its virtual ptr.
  public:
    const Class_type_info *base() const;
    //!EH RT needs has_ctd; but do I want others to know?
    char has_ctd() const;
    long offset() const;
    };

// Members of class type; only these are relevant to exception handling.
struct Member_info {
  private:
    const Type_info *_member;	// Could be array or array of classes.
    long _offset;		// Offset of this member in the structure.
    char _is_som;		// This is currently unused.
    char pad1,pad2,pad3;	
  public:
    const Type_info *member() const;
    long offset() const;
    };

// pragma pop(run_time_type_info);	// Don't want it for Base_info/Vbase_info/Member_info.
class Class_type_info: public Type_info {
  public:
    typedef void (*dtor_type)(void *object,int,int);	// Third parm needed for SOM.
    typedef void (*ctor_type)(...);	// Constructor type.  Actual form private.
    // When we call operator delete we always pass the size, whether
    // or not it needs it.
    typedef void (*delete_type)(void *, unsigned size);
  private:
    unsigned short _nbases;	// Number of bases.
    unsigned short _nclass_members;	// Number of members that are classes.
    unsigned short _nvbases;	// Number of transitive virtual bases.
    enum { exception_aware = 1 };
    // Next three fields for exception handling only; not accessible by public.
    unsigned short _info;	// Bits from above enum.
    int _nobjects;		// Number of subobjects for this type: 1+embedded objects.
    int _total_subobjects;	// Number of total objects for the lattice rooted here.
    const Base_info *base_list;       // List of bases.
    const Vbase_info *vbase_list;	// List of virtual bases.
    const Member_info *member_list;	// List of members of a class type.
    // Used by some customers:  default constructor (ctor)
    // and default copy constructor (copy_ctor).  These members are 0 if
    // not provided.  To provide them, turn on toggle
    // rtti_includes_constructors.  If On, the compiler attempts to
    // generate the default constructor and copy constructor where it
    // lays down the RTTI for the class, and places the address in the
    // RTTI entry.  Such attempts at generation may produce compile-time
    // errors in some cases.  For example:
    //    - a base class has an inaccessible default ctor or copy ctor.
    //	  - a class has a copy constructor but no constructor; the
    //	    compiler is not permitted to synthesize a constructor.
    // NOTE that this is for native C++ classes only; SOM classes do not
    // use these RTTI structures.  The SOM object model does not allow
    // storing a pointer to the RTTI structure in an object's method
    // table, because SOM controls the object storage allocation and the
    // method table generation.
    //
    // You use methods constructor_address() to determine whether the
    // class has a constructor and/or copy constructor.  A non-zero
    // result from means you can call the method call_constructor() to
    // (default-) construct an object.  Similarly for
    // copy_constructor_address() and call_copy_constructor().
    ctor_type ctor, copy_ctor;
    // Needed by exception handling:  the destructor for a class:
    dtor_type dtor;
    delete_type opdel;	// Class's operator delete.
  public:
    ~Class_type_info();
    virtual int nbases() const;
    virtual int nclass_members() const;
    virtual int nvbases() const;
    virtual const Member_info *class_member(unsigned i) const;
    virtual const Base_info *base(unsigned i) const;
    virtual const Vbase_info *vbase(unsigned i) const;

    // Returns the address of the default constructor; 0 if none.
    virtual ctor_type constructor_address() const;
    virtual void call_constructor(void *object) const;

    // Returns the address of the default constructor; 0 if none.
    virtual ctor_type copy_constructor_address() const;
    virtual void call_copy_constructor(void *dest, void *src) const;

    // Returns the address of the destructor; 0 if none.
    virtual dtor_type destructor_address() const;
    virtual void call_destructor(void *object, char as_base) const;

    // Returns the address of a class-specific operator delete; 0 if none.
    virtual delete_type opdel_address() const;
    virtual void call_opdel(void *object) const;

    // These are for EH only and are not available to others, even though
    // stated public.  The implementation for them is within the EH RT only.
    int nobjects() const; 	  // Number of subobjects for this type: 1+embedded objects.
    int total_subobjects() const; // Number of total objects for the lattice rooted here.
    };

class SOM_class_type_info: public Type_info {
    // Because we can't declare SOMClass lest we traipse on ANSI name space,
    // we ask if it's been defined.
  public:
    #ifdef SOMClass
    typedef SOMClass** class_object_type;
    #else
    typedef void** class_object_type;
    #endif
  private:
    class_object_type _class_object;	// Points to a location containing the class object pointer.
  public:
    ~SOM_class_type_info();
    virtual class_object_type class_object() const;
    };

// In the Jan '94 draft Bad_cast was known both as Bad_cast and badcast.
// In the July 94 draft Bad_cast has become bad_cast.  Hmm.
struct Bad_cast {
    char *from;
    Class_type_info *actual_type, *from_type, *to_type;
    Bad_cast(char *from, Class_type_info *actual_type,
	Class_type_info *from_type, Class_type_info *to_type) {
	this->from = from;
	this->actual_type = actual_type;
	this->from_type = from_type;
	this->to_type = to_type;
	}
    virtual ~Bad_cast();	// Locate type
    };

pragma pop(run_time_type_info);

}
using typeinfo::Bad_cast;
using typeinfo::Type_info; // This what's it's supposed to be called?

/**************************************************************************
Type info structures.

The type of an object is represented by another object that is of type
Type_info or a type derived from Type_info.  For example, the type of a
struct/union/class is of type Class_type_info; the type of a pointer
type is of type Pointer_type_info.

For an object X of a polymorphic type, typeid(X) returns a reference to
the type object Tobj representing the type of X.  In the implementation,
location 0 of the virtual function table for X points to Tobj.

For a C++ type T, typeid(T) returns a reference to the type object
representing the type T.

For example:

	struct s { ... };
	s *p;
			  __vt_s         __rtti_1s
p -> 	+--------+      +--------+      +--------+
	|        |  ->  |        |  ->  |        |  -> __vt_Class_type_info
	+--------+      +--------+      +--------+
	|  ...   |      |  ...   |      | 1 | 0  |
	+--------+      +--------+      +--------+
					| info   |
					| about  |
					|   s    |
					+--------+

__vt_s is the virtual function table for type s.  It's 0th location
points to the object representing the type of s.  Typeid(s) has two
halfword 0s indicating no bases and no class members.

__rtti_1s is the type object for type s, obtained by writing Typeid(s)
in C++.  Typeid(s) is of type Class_type_info, because s is a class;
thus the virtual function table for Typeid(s) points to
__vt_Class_type_info.

The above picture is a general picture for all structure types.  In
general, for any structure type s, the compiler constructs an object
__rtti_1s, makes its vfunc table be __vt_Class_type_info, and makes
__vt_s[0] point to __rtti_1s.

This includes Class_type_info itself, which is a structure type.  If
we apply this algorithm to Class_type_info we get:

	struct Class_type_info { ... };
	Class_type_info *p;
		    __vt_Class_type_info  __rtti_15Class_type_info
p -> 	+--------+      +--------+      +--------+
	|        |  ->  |        |  ->  |        |  -> __vt_Class_type_info
	+--------+      +--------+      +--------+
	|  ...   |      |  ...   |      | 1 | 0  |
	+--------+      +--------+      +--------+     +--------+
					|  ...   |  -> | |      |
					+--------+     +-|------+
							 |
							 -> __rtti_16Type_info
							
Now you can see that Typeid(*p), which is Typeid(Class_type_info), has
type Class_type_info.  I.e.,

	Typeid(Class_type_info) = __rtti_15Class_type_info
	Typeid(__rtti_15Class_type_info) = __rtti_15Class_type_info

and thus you can conclude

	Typeid(Class_type_info) = Typeid(Typeid(Class_type_info))

In words, Typeid(Class_type_info) is an object that is its own type.

__rtti_15Class_type_info shows that there is exactly one base, and the
base is the __rtti_16Type_info object.  Examining Type_info we have the
following picture:

	struct Type_info { ... };
	Type_info *p;
		    __vt_Type_info  __rtti_16Type_info
p -> 	+--------+      +--------+      +--------+
	|        |  ->  |        |  ->  |        |  -> __vt_Class_type_info
	+--------+      +--------+      +--------+
	|  ...   |      |  ...   |      | 0 | 0  |
	+--------+      +--------+      +--------+
					|  ...   |
					+--------+
						
I.e., Typeid(Type_info) == __rtti_16Type_info, and
Typeid(__rtti_16Type_info) = __rtti_15Class_type_info.

Curiously, this means that __rtti_15Class_type_info is the type of the
type of Class_type_info's base.  Or, looking at the structures,
__rtti_15Class_type_info points to __rtti_16Type_info, and
Typeof(__rtti_16Type_info) = __rtti_15Class_type_info.

Summarizing the relationships between Type_info and Class_type_info:

       +-----------------------------------------------+
       V                                               |
__vt_Class_type_info  __rtti_15Class_type_info           |
    +--------+      +--------+                         |
    |        |  ->  |        |  -----------------------+
    +--------+      +--------+                         |
    |  ...   |      | 1 | 0  |                         |
    +--------+      +--------+     +--------+          |
		    |        |  -> | |      |          |
		    +--------+     +-|------+          |
				     |                 |
		       +-------------+                 |
		       V                               |
__vt_Type_info  __rtti_16Type_info                       |
    +--------+      +--------+                         |
->  |        |  ->  |        |  -----------------------+
    +--------+      +--------+
    |  ...   |      | 0 | 0  |
    +--------+      +--------+
		    |  ...   |
		    +--------+

// Example use:

#include "../tinfo.h"
pragma on(run_time_type_info);
struct base { int y; virtual goo() {} };
struct s:base { int x; virtual foo(){}} z;
main () {
    printf("%s\n",typeid(z).name());
    Class_type_info &cti = (Class_type_info&)typeid(z);
    for (int i = 0; i < cti.nbases; i++)
	printf("Base#%d is %s\n",i,cti.base_list[i].base->name());
    }

// prints:
s
Base#0 is base

**************************************************************************/

#if __TYPEINFO_IMPLEMENTATION
// Private to the implementation of typeinfo:
namespace typeinfo {

    enum {FALSE,TRUE};	
	
    struct conversion {
	void *object;	// Address of object, or pointer thereto.
	char backwards;	// Set TRUE for ptr-to-member contravariant conversion.
	conversion(void *O):object(O),backwards(FALSE) {}
	conversion(void *O, int b) :object(O),backwards(b) {}
	};

    int is_base_of_(
	const Type_info *this, const Type_info *of_that, conversion *C,
	char of_that_is_most_derived);

    int is_base_of(
	const Type_info *this, const Type_info *of_that, conversion *C);
	
    int same_type(const Type_info *T1, const Type_info *T2);

    void each_transitive_base(const Type_info *of_that, char DFO) ->
	(const Class_type_info*, char is_virtual);
	
    int modifier_superset(const Type_info *this, const Type_info *that);

    int is_modified_type(const Type_info *T);
    // Remove modifiers from a type.
    const Type_info *un_modify(const Type_info *tip);
    long modifiers(const Type_info *tip);
    type_kind tkind_mod(const Type_info *T);
    type_kind tkind(const Type_info *T);
    int is_reference_type(const Type_info *tip);
    // Remove a & from a reference type.
    const Type_info *un_ref(const Type_info *tip);
    pragma on(mangle_fname_only);
    void *dynamic_cast(char *ptr,
	Class_type_info *actual_type,
	Class_type_info *from, Class_type_info *to,
	char casting_to_reference);
    SOMObject *som_dynamic_cast(
	SOMObject *object, SOMClass *to_type, char casting_to_reference);
    Class_type_info *get_typeid(Class_type_info *type);
    pragma pop(mangle_fname_only);
    typedef int (SOMObject::*true_dtor)(char dealloc, void *control);
    extern struct SOM_info {
	// These pointers are brought in if you link with -Hsom;
	// otherwise they remain 0 (linker puts them in common).
	boolean (SOMClass::*somDescendedFrom)(SOMClass* aClassObj);
	// The default constructor:
	int (SOMObject::*ctor)(void);
	// The copy constructor:
	int (SOMObject::*copy_ctor)(const SOMObject&);
	// The destructor:
	int (SOMObject::*dtor)();
	// Make something an object:
	SOMObject* (SOMClass::*somRenewNoInit)(void* obj);
	// Destruct bases in a partially-constructed SOM object.
	void (*destruct_SOM_bases)(
		SOMObject *p, SOMClass *tor_type, int bases_constructed);
	// Find starting address of local data.
	void *(*local_data_start)(SOMObject *p);
	// Ask if an object responds to methods.
	boolean (SOMObject::*somIsA)(SOMClass* aClassObj);
	long (SOMClass::*somGetInstanceSize)();
	} SOM_ptrs;
    void checkSOM();
    }
#endif
namespace exceptions {
    _CRTIMPCC extern void *error_file;      // Where to write exception errors; default stdout.
    _CRTIMPCC extern int exception_tracing; // If you have tracing compiled in, turn
				  // this on to start tracing.
    _CRTIMPCC extern int abnormal_messages; // Default on; unexpected/terminate print
				  // a message before doing their job.
    typedef const typeinfo::Type_info TI;
    typedef void (*pfv)();
    struct exception_state;	// private.
    pragma on(mangle_fname_only);
    void enter(exception_state *p);
    void exit(exception_state *p);
    // Same as exit, but leave the current object count intact
    // (it has to be passed to the callee).
    void exit_ret(exception_state *p);
    void exit_cnt(exception_state *p, int set_count_to_this_value);
    int dyn_obj_count(TI *type);
    void rethrow();
    typedef void (*copy_ctor_ptr)(...);
    void throwe(void *op, TI *tip, copy_ctor_ptr copyp);
    void trace_throw(void *op, TI *tip, copy_ctor_ptr copyp,
	const char *file_name, const char *func_name, int line_number);
    void trace_rethrow(
	const char *file_name, const char *func_name, int line_number);
    void *array_type_and_inc(char *object_ptr, long offset_to_vp);
    void catch_finish();
    pragma pop(mangle_fname_only);
    }
// According to the ARM these have to be global; too bad they
// can't be in the exceptions namespace.
exceptions::pfv set_terminate(exceptions::pfv p);
exceptions::pfv set_unexpected(exceptions::pfv p);
void terminate();
void unexpected();

#pragma pop(macro_substitution)
;

#endif /* _TYPEINFO_H */
