Inferno
0.2
|
00001 #ifndef ITEMISE_HPP 00002 #define ITEMISE_HPP 00003 00004 #include <stdio.h> 00005 #include <vector> 00006 #include "common/common.hpp" 00007 #include <inttypes.h> 00008 00009 using namespace std; 00010 00011 // Note about multiple inheritance: 00012 // If Itemiser::Element is at the base of a diamond, itemiser will see it twice, 00013 // *even if* virtual inheritance is used. This may be a compiler bug in which case the above 00014 // is true only for GCC4.3. Anyway, if we see it twice it will have the same address, 00015 // so we de-duplicate during itemise algorithm. 00016 00017 class Itemiser : public virtual Traceable 00018 { 00019 public: 00020 class Element 00021 { 00022 public: 00023 virtual ~Element() {} 00024 Element &operator=( const Element &other ) 00025 { 00026 if( (uintptr_t)this >= (uintptr_t)dstart && 00027 (uintptr_t)this < (uintptr_t)dend ) 00028 { 00029 uintptr_t ofs = (uintptr_t)this - (uintptr_t)dstart; 00030 FOREACH( uintptr_t x, v ) 00031 if( x==ofs ) 00032 return *this; // don't insert if in there already, see above 00033 v.push_back( ofs ); 00034 //TRACE("%d ", ofs ); 00035 } 00036 return *this; 00037 } 00038 }; 00039 00040 template< class ITEMISE_TYPE > 00041 inline static vector< uintptr_t > ItemiseImpl( const ITEMISE_TYPE *itemise_architype ) 00042 { 00043 //TRACE("Static itemise %s ", typeid(*itemise_architype).name() ); 00044 (void)itemise_architype; 00045 ITEMISE_TYPE d( *itemise_architype ); 00046 ITEMISE_TYPE s( *itemise_architype ); 00047 dstart = (char *)&d; 00048 dend = dstart + sizeof(d); 00049 v.clear(); 00050 00051 // This is the assignment that will be detected 00052 //TRACE("Assigning "); 00053 d = s; 00054 //TRACE(" done\n"); 00055 00056 return v; 00057 } 00058 00059 template< class ITEMISE_TYPE > 00060 inline static const vector< uintptr_t > &BasicItemiseStatic( const ITEMISE_TYPE *itemise_architype ) 00061 { 00062 // Just a cache on ItemiseImpl() 00063 static vector< uintptr_t > v; 00064 static bool done=false; 00065 if(!done) 00066 { 00067 v = ItemiseImpl( itemise_architype ); 00068 done = true; 00069 } 00070 return v; 00071 } 00072 00073 template< class ITEMISE_TYPE > 00074 inline static const vector< Itemiser::Element * > ItemiseStatic( const ITEMISE_TYPE *itemise_architype, 00075 const Itemiser *itemise_object ) 00076 { 00077 ASSERT( itemise_architype )("Itemiser got itemise_architype=NULL\n"); 00078 ASSERT( itemise_object )("Itemiser got itemise_object=NULL\n"); 00079 00080 // Do a safety check: itemise_object we're itemising must be same as or derived 00081 // from the architype, so that all the architype's members are also in itemise_object. 00082 ASSERT( dynamic_cast<const ITEMISE_TYPE *>(itemise_object) ) 00083 ( "Cannot itemise because itemise_object=")(*itemise_object) 00084 ( " is not a nonstrict subclass of itemise_architype=")(*itemise_architype); 00085 00086 // Do the pointer math to get "elements of A in B" type behaviour 00087 // This must be done in bounce because we need the architype's type for the dynamic_cast 00088 const vector< uintptr_t > &vofs = BasicItemiseStatic( itemise_architype ); 00089 00090 const ITEMISE_TYPE *target_object = dynamic_cast<const ITEMISE_TYPE *>(itemise_object); 00091 vector< Itemiser::Element * > vout; 00092 FOREACH( uintptr_t ofs, vofs ) 00093 vout.push_back( (Element *)((const char *)target_object + ofs) ); 00094 00095 return vout; 00096 } 00097 00098 template< class ITEMISE_TYPE > 00099 inline static Itemiser::Element *ItemiseIndexStatic( const ITEMISE_TYPE *itemise_object, 00100 int i ) 00101 { 00102 const vector< uintptr_t > &v = BasicItemiseStatic( itemise_object ); 00103 ASSERT( i>=0 ); 00104 ASSERT( i<v.size() ); 00105 uintptr_t ofs = v[i]; 00106 return (Element *)((const char *)itemise_object + ofs); 00107 } 00108 00109 template< class ITEMISE_TYPE > 00110 inline static int ItemiseSizeStatic( const ITEMISE_TYPE *itemise_object ) 00111 { 00112 const vector< uintptr_t > &v = BasicItemiseStatic( itemise_object ); 00113 return v.size(); 00114 } 00115 00116 static const char *dstart; 00117 static const char *dend; 00118 static vector<uintptr_t> v; 00119 00120 virtual vector< Itemiser::Element * > Itemise(const Itemiser *itemise_object) const = 0; 00121 }; 00122 00123 #define ITEMISE_FUNCTION \ 00124 virtual vector< Itemiser::Element * > Itemise( const Itemiser *itemise_object = 0 ) const \ 00125 { \ 00126 return Itemiser::ItemiseStatic( this, itemise_object ? itemise_object : this ); \ 00127 } \ 00128 virtual Itemiser::Element *ItemiseIndex( int i ) const \ 00129 { \ 00130 return Itemiser::ItemiseIndexStatic( this, i ); \ 00131 } \ 00132 virtual int ItemiseSize() const \ 00133 { \ 00134 return Itemiser::ItemiseSizeStatic( this ); \ 00135 } 00136 #endif