Inferno  0.2
rc_hold.hpp
Go to the documentation of this file.
00001 #ifndef RCHOLD_HPP
00002 #define RCHOLD_HPP
00003 
00004 #include "common/common.hpp"
00005 #include "node/node.hpp"
00006 #include <inttypes.h>
00007 
00008 template<typename NODE, typename RAW>
00009 class RCHold
00010 {
00011 //
00012 // This class converts between TreePtr and void * pointers and ensures that target
00013 // objects whoose TreePtr has been converted to void * remain in existance even if
00014 // the number of RCPtrs to it falls to zero.
00015 //
00016 // Target objects will be held in existance until the corresponding RCHold object
00017 // is destructed, after which only target objects with TreePtr refs will remain.
00018 //
00019 // For a set of raw pointers, create an RCHold object whose lifetime is a minimal
00020 // superset of the union of the raw pointers' lifetimes. Do all assignment to/from
00021 // those raw pointers using ToRaw() and FromRaw(). Note: always assign the return 
00022 // of new/malloc to an TreePtr and then convert to a raw ptr using ToRaw() if required,
00023 // otherwise the required extra ref will not be created.
00024 //
00025 // TODO: (done)
00026 // TODO: Consider supporting the new DeleteX() virtuals in the clang action interface,
00027 //       but most likely don't bother since we'll tear down anyway.
00028 
00029 public:
00030     RCHold() :
00031         id( ((uintptr_t)this % 255+1) << 24 ) // 8-bit hash of this pointer, never zero, placed in top 8 bits
00032     {
00033     }
00034     
00035 
00036     RAW ToRaw( TreePtr<NODE> p )
00037     {
00038         ASSERT( p )( "Cannot convert NULL pointer to raw" );
00039         uintptr_t i = (unsigned)hold_list.size(); // the index of the next push_back()
00040         ASSERT( (i & 0xFF000000) == 0 )( "gone over maximum number of elements, probably due to infinite loop, if not rejig id" );
00041         i |= id; // embed an id for the current hold object  
00042         //TRACE("ToRaw 0x%08x\n", i );
00043         void *vp = reinterpret_cast<void *>( i ); 
00044         hold_list.push_back( p );
00045         ASSERT(vp); // cannot return a NULL pointer, since clang inteprets that as an error
00046         return vp;
00047     }
00048     
00049     TreePtr<NODE> FromRaw( RAW p )
00050     {
00051         ASSERT( p != 0 )( "this raw value is uninitialised");
00052         uintptr_t i = reinterpret_cast<uintptr_t>(p);
00053         //TRACE("FromRaw 0x%08x (id=0x%08x)\n", i, id );
00054         ASSERT( (i & 0xFF000000) == id )( "this raw value was stored to a different holder or uninitialised");
00055         i &= 0x00FFFFFF; 
00056         return hold_list[i];
00057     }
00058     
00059 private:
00060     // When this object is destructed, all the members of the vector will be 
00061     // destructed and targets that then have no refs will be destructed.
00062     const unsigned id;
00063     vector< TreePtr< NODE > > hold_list;  // TODO does this need to be a vector?
00064 };
00065 
00066 
00067 #endif