Home | History | Annotate | Download | only in include
      1 /* Dynamic testing for abstract is-a relationships.
      2    Copyright (C) 2012-2013 Free Software Foundation, Inc.
      3    Contributed by Lawrence Crowl.
      4 
      5 This file is part of GCC.
      6 
      7 GCC is free software; you can redistribute it and/or modify it under
      8 the terms of the GNU General Public License as published by the Free
      9 Software Foundation; either version 3, or (at your option) any later
     10 version.
     11 
     12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15 for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with GCC; see the file COPYING3.  If not see
     19 <http://www.gnu.org/licenses/>.  */
     20 
     21 
     22 /* This header generic type query and conversion functions.
     23 
     24 
     25 USING THE GENERIC TYPE FACILITY
     26 
     27 
     28 The user functions are:
     29 
     30 bool is_a <TYPE> (pointer)
     31 
     32     Tests whether the pointer actually points to a more derived TYPE.
     33 
     34     Suppose you have a symtab_node_def *ptr, AKA symtab_node ptr.  You can test
     35     whether it points to a 'derived' cgraph_node as follows.
     36 
     37       if (is_a <cgraph_node> (ptr))
     38         ....
     39 
     40 
     41 TYPE *as_a <TYPE> (pointer)
     42 
     43     Converts pointer to a TYPE*.
     44 
     45     You can just assume that it is such a node.
     46 
     47       do_something_with (as_a <cgraph_node> *ptr);
     48 
     49 TYPE *dyn_cast <TYPE> (pointer)
     50 
     51     Converts pointer to TYPE* if and only if "is_a <TYPE> pointer".  Otherwise,
     52     returns NULL.  This function is essentially a checked down cast.
     53 
     54     This functions reduce compile time and increase type safety when treating a
     55     generic item as a more specific item.
     56 
     57     You can test and obtain a pointer to the 'derived' type in one indivisible
     58     operation.
     59 
     60       if (cgraph_node *cptr = dyn_cast <cgraph_node> (ptr))
     61         ....
     62 
     63     As an example, the code change is from
     64 
     65       if (symtab_function_p (node))
     66         {
     67           struct cgraph_node *cnode = cgraph (node);
     68           ....
     69         }
     70 
     71     to
     72 
     73       if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
     74         {
     75           ....
     76         }
     77 
     78     The necessary conditional test defines a variable that holds a known good
     79     pointer to the specific item and avoids subsequent conversion calls and
     80     the assertion checks that may come with them.
     81 
     82     When, the property test is embedded within a larger condition, the
     83     variable declaration gets pulled out of the condition.  (This approach
     84     leaves some room for using the variable inappropriately.)
     85 
     86       if (symtab_variable_p (node) && varpool (node)->finalized)
     87         varpool_analyze_node (varpool (node));
     88 
     89     becomes
     90 
     91       varpool_node *vnode = dyn_cast <varpool_node> (node);
     92       if (vnode && vnode->finalized)
     93         varpool_analyze_node (vnode);
     94 
     95     Note that we have converted two sets of assertions in the calls to varpool
     96     into safe and efficient use of a variable.
     97 
     98 
     99 If you use these functions and get a 'inline function not defined' or a
    100 'missing symbol' error message for 'is_a_helper<....>::test', it means that
    101 the connection between the types has not been made.  See below.
    102 
    103 
    104 EXTENDING THE GENERIC TYPE FACILITY
    105 
    106 Each connection between types must be made by defining a specialization of the
    107 template member function 'test' of the template class 'is_a_helper'.  For
    108 example,
    109 
    110   template <>
    111   template <>
    112   inline bool
    113   is_a_helper <cgraph_node>::test (symtab_node_def *p)
    114   {
    115     return p->symbol.type == SYMTAB_FUNCTION;
    116   }
    117 
    118 If a simple reinterpret_cast between the pointer types is incorrect, then you
    119 must also specialize the template member function 'cast'.  Failure to do so
    120 when needed may result in a crash.  For example,
    121 
    122   template <>
    123   template <>
    124   inline bool
    125   is_a_helper <cgraph_node>::cast (symtab_node_def *p)
    126   {
    127     return &p->x_function;
    128   }
    129 
    130 */
    131 
    132 #ifndef GCC_IS_A_H
    133 #define GCC_IS_A_H
    134 
    135 /* A generic type conversion internal helper class.  */
    136 
    137 template <typename T>
    138 struct is_a_helper
    139 {
    140   template <typename U>
    141   static inline bool test (U *p);
    142   template <typename U>
    143   static inline T *cast (U *p);
    144 };
    145 
    146 /* Note that we deliberately do not define the 'test' member template.  Not
    147    doing so will result in a build-time error for type relationships that have
    148    not been defined, rather than a run-time error.  See the discussion above
    149    for when to define this member.  */
    150 
    151 /* This is the generic implementation for casting from one type to another.
    152    Do not use this routine directly; it is an internal function.  See the
    153    discussion above for when to define this member.  */
    154 
    155 template <typename T>
    156 template <typename U>
    157 inline T *
    158 is_a_helper <T>::cast (U *p)
    159 {
    160   return reinterpret_cast <T *> (p);
    161 }
    162 
    163 
    164 /* The public interface.  */
    165 
    166 /* A generic test for a type relationship.  See the discussion above for when
    167    to use this function.  The question answered is "Is type T a derived type of
    168    type U?".  */
    169 
    170 template <typename T, typename U>
    171 inline bool
    172 is_a (U *p)
    173 {
    174   return is_a_helper<T>::test (p);
    175 }
    176 
    177 /* A generic conversion from a base type U to a derived type T.  See the
    178    discussion above for when to use this function.  */
    179 
    180 template <typename T, typename U>
    181 inline T *
    182 as_a (U *p)
    183 {
    184   gcc_assert (is_a <T> (p));
    185   return is_a_helper <T>::cast (p);
    186 }
    187 
    188 /* A generic checked conversion from a base type U to a derived type T.  See
    189    the discussion above for when to use this function.  */
    190 
    191 template <typename T, typename U>
    192 inline T *
    193 dyn_cast (U *p)
    194 {
    195   if (is_a <T> (p))
    196     return is_a_helper <T>::cast (p);
    197   else
    198     return static_cast <T *> (0);
    199 }
    200 
    201 #endif  /* GCC_IS_A_H  */
    202