// RTTI support internals for -*- C++ -*-
// Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000 Free Software Foundation

#include "typeinfo"
#include <cstddef>

// Class declarations shared between the typeinfo implementation files.

#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
// original (old) abi

// type_info for a class with no base classes (or an enum).

struct __user_type_info : public std::type_info {
  __user_type_info (const char *n) : type_info (n) {}

  // If our type can be upcast to a public and unambiguous base, then return
  // non-zero and set RES to point to the base object. OBJ points to the throw
  // object and can be NULL, if there is no object to adjust.
  int upcast (const type_info &target, void *obj, void **res) const;
  
  // If our type can be dynamicly cast to the target type, then return
  // pointer to the target object. OBJ is the pointer to the most derived
  // type and cannot be NULL. SUBTYPE and SUBOBJ indicate the static type
  // base object from whence we came, it cannot be NULL. SUBTYPE cannot be
  // the same as TARGET. TARGET cannot be a base of SUBTYPE.
  // BOFF indicates how SUBTYPE is related to TARGET.
  // BOFF >= 0, there is only one public non-virtual SUBTYPE base at offset
  //    BOFF, and there are no public virtual SUBTYPE bases.
  //    Therefore check if SUBOBJ is at offset BOFF when we find a target
  // BOFF == -1, SUBTYPE occurs as multiple public virtual or non-virtual bases.
  //    Lazily search all the bases of TARGET.
  // BOFF == -2, SUBTYPE is not a public base.
  // BOFF == -3, SUBTYPE occurs as multiple public non-virtual bases.
  //    Lazily search the non-virtual bases of TARGET.
  // For backwards compatibility set BOFF to -1, that is the safe "unknown"
  // value. We do not care about SUBTYPES as private bases of TARGET, as they
  // can never succeed as downcasts, only as crosscasts -- and then only if
  // they are virtual. This is more complicated that it might seem.
  void *dyncast (int boff,
                 const type_info &target, void *obj,
                 const type_info &subtype, void *subobj) const;
  
  // non_virtual_base_type is used to indicate that a base class is via a
  // non-virtual access path.
  static const type_info *const nonvirtual_base_type
      = static_cast <const type_info *> (0) + 1;
  
  // sub_kind tells us about how a base object is contained within a derived
  // object. We often do this lazily, hence the UNKNOWN value. At other times
  // we may use NOT_CONTAINED to mean not publicly contained.
  enum sub_kind
  {
    unknown = 0,              // we have no idea
    not_contained,            // not contained within us (in some
                              // circumstances this might mean not contained
                              // publicly)
    contained_ambig,          // contained ambiguously
    contained_mask = 4,       // contained within us
    contained_virtual_mask = 1, // via a virtual path
    contained_public_mask = 2,  // via a public path
    contained_private = contained_mask,
    contained_public = contained_mask | contained_public_mask
  };
  // some predicate functions for sub_kind
  static inline bool contained_p (sub_kind access_path)
  {
    return access_path >= contained_mask;
  }
  static inline bool contained_public_p (sub_kind access_path)
  {
    return access_path >= contained_public;
  }
  static inline bool contained_nonpublic_p (sub_kind access_path)
  {
    return (access_path & contained_public) == contained_mask;
  }
  static inline bool contained_nonvirtual_p (sub_kind access_path)
  {
    return (access_path & (contained_mask | contained_virtual_mask))
           == contained_mask;
  }
  static inline bool contained_virtual_p (sub_kind access_path)
  {
    return (access_path & (contained_mask | contained_virtual_mask))
           == (contained_mask | contained_virtual_mask);
  }
  
  struct upcast_result
  {
    void *target_obj;   // pointer to target object or NULL (init NULL)
    sub_kind whole2target;      // path from most derived object to target
    const type_info *base_type; // where we found the target, (init NULL)
                                // if in vbase the __user_type_info of vbase)
                                // if a non-virtual base then 1
                                // else NULL
    public:
    upcast_result ()
      :target_obj (NULL), whole2target (unknown), base_type (NULL)
      {}
  };
  struct dyncast_result
  {
    void *target_obj;   // pointer to target object or NULL (init NULL)
    sub_kind whole2target;      // path from most derived object to target
    sub_kind whole2sub;         // path from most derived object to sub object
    sub_kind target2sub;        // path from target to sub object
    
    public:
    dyncast_result ()
      :target_obj (NULL), whole2target (unknown),
       whole2sub (unknown), target2sub (unknown)
      {}
  };
  
  public:
  // Helper for upcast. See if TARGET is us, or one of our bases. ACCESS_PATH
  // gives the access from the start object. Return TRUE if we know the catch
  // fails.
  virtual bool do_upcast (sub_kind access_path,
                          const type_info &target, void *obj,
                          upcast_result &__restrict result) const;
  // Helper for dyncast. BOFF indicates how the SUBTYPE is related to TARGET.
  // ACCESS_PATH indicates the access from the most derived object.  It is
  // used to prune the DAG walk. All information about what we find is put
  // into RESULT. Return true, if the match we have found is ambiguous.
  virtual bool do_dyncast (int boff, sub_kind access_path,
                           const type_info &target, void *obj,
                           const type_info &subtype, void *subptr,
                           dyncast_result &__restrict result) const;
  public:
  // Indicate whether SUBPTR of type SUBTYPE is contained publicly within
  // OBJPTR. OBJPTR points to this base object. BOFF indicates how SUBTYPE
  // objects might be contained within this type.  If SUBPTR is one of our
  // SUBTYPE bases, indicate virtuality. Returns not_contained for non
  // containment or private containment.
  sub_kind find_public_subobj (int boff, const type_info &subtype,
                               void *objptr, void *subptr) const
  {
    if (boff >= 0)
      return ((char *)subptr - (char *)objptr) == boff
              ? contained_public : not_contained;
    if (boff == -2)
      return not_contained;
    return do_find_public_subobj (boff, subtype, objptr, subptr);
  }
  
  public:
  // Helper for find_subobj. BOFF indicates how SUBTYPE bases are inherited by
  // the type started from -- which is not necessarily the current type.
  // OBJPTR points to the current base.
  virtual sub_kind do_find_public_subobj (int boff, const type_info &subtype,
                                          void *objptr, void *subptr) const;
};

// type_info for a class with one public, nonvirtual base class.

class __si_type_info : public __user_type_info {
  const __user_type_info &base;

public:
  __si_type_info (const char *n, const __user_type_info &b)
    : __user_type_info (n), base (b) { }

  private:
  virtual bool do_upcast (sub_kind access_path,
                          const type_info &target, void *obj,
                          upcast_result &__restrict result) const;
  virtual bool do_dyncast (int boff, sub_kind access_path,
                           const type_info &target, void *obj,
                           const type_info &subtype, void *subptr,
                           dyncast_result &__restrict result) const;
  virtual sub_kind do_find_public_subobj (int boff, const type_info &subtype,
                                          void *objptr, void *subptr) const;
};

// type_info for a general class.

#include <climits>

#if INT_MAX == 2147483647
typedef int myint32;
#elif SHRT_MAX == 2147483647
typedef short myint32;
#elif SCHAR_MAX == 2147483647
typedef signed char myint32;
#elif LONG_MAX == 2147483647
typedef long myint32;
#else
# error "No 32-bit data type?"
#endif

struct __class_type_info : public __user_type_info {
  enum access { PUBLIC = 1, PROTECTED = 2, PRIVATE = 3 };

  struct base_info {
    const __user_type_info *base;
    myint32 offset: 29;
    bool is_virtual: 1;
    enum access access: 2;
  };

  const base_info *base_list;
  std::size_t n_bases;

  __class_type_info (const char *name, const base_info *bl, std::size_t bn)
    : __user_type_info (name), base_list (bl), n_bases (bn) {}

  public:
  virtual bool do_upcast (sub_kind access_path,
                          const type_info &target, void *obj,
                          upcast_result &__restrict result) const;
  virtual bool do_dyncast (int boff, sub_kind access_path,
                           const type_info &target, void *obj,
                           const type_info &subtype, void *subptr,
                           dyncast_result &__restrict result) const;
  virtual sub_kind do_find_public_subobj (int boff, const type_info &subtype,
                                          void *objptr, void *subptr) const;
};
#else
// new abi
#include <cxxabi.h>

#endif
