moab
VarLenTag.hpp
Go to the documentation of this file.
00001 #ifndef VAR_LEN_TAG_HPP
00002 #define VAR_LEN_TAG_HPP
00003 
00004 #include <stdlib.h>
00005 #include <string.h>
00006 
00007 namespace moab {
00008 
00009 /* Remove this preprocessor macro to compile 
00010  * simple implementation w/ no inlined storage
00011  */
00012 #define VAR_LEN_TAG_ELIDE_DATA
00013 
00014 
00015 /* Define class data layout depenkding on macros:
00016  * VAR_LEN_TAG_ELIDE_DATA and TEMPLATE_SPECIALIZATION
00017  */
00018 #ifndef VAR_LEN_TAG_ELIDE_DATA
00019 
00020 /* The trivial implementation */
00021 public VarLenTagData {
00022 public:
00023 
00024   struct { struct { unsigned size; unsigned char* array; } mPointer; } mData;
00025 };
00026 
00027 #elif !defined(TEMPLATE_SPECIALIZATION)
00028 
00029 /* A little more advanced data structure for VarLenTag.
00030  * If the amount of tag data is less than or equal to the
00031  * size of the array pointer, store it inline in the pointer
00032  * value field so no memory needs to be allocated.
00033  */
00034 class VarLenTagData {
00035 public:
00036 
00037   enum {
00038     INLINE_COUNT = sizeof(unsigned char*)
00039   };
00040 
00041   union {
00042     struct { 
00043       unsigned char* array;
00044       unsigned size;
00045     } mPointer;
00046     struct {
00047       unsigned char array[INLINE_COUNT];
00048       unsigned size;
00049     } mInline;
00050   } mData;
00051 };
00052 
00053 #else
00054 
00055 /* Most complex implementation.  Same as the previous one, except
00056  * when storing data inline, also utilize any padding in the struct.
00057  * This implementation requires support for template specialization.
00058  * 
00059  * - The data must be first in the struct to avoid alignment issues
00060  *   for double and 64-bit handle values on some platforms.
00061  * - The size must therefore be at the end of the struct (including
00062  *   after any padding) becase a) it cannot be at the beginning and
00063  *   b) it must be at the same location in both structs in the union.
00064  * - For the mPointer variation, the padding must be declared
00065  *   explicitly in order for the size to be forced to the end.
00066  * - Template specialiation is used to avoid declaring a
00067  *   zero-length array for pad on 32-bit platforms.  
00068  *   NOTE: GCC allows zero-length arrays, but Sun's compiler 
00069  *   (and most others) do not.
00070  */
00071 template <unsigned>
00072 class VarLenTagDataTemplate {
00073 public:
00074   inline VarLenTagDataTemplate() {}
00075 
00076   struct MallocData {
00077     unsigned char* array;
00078     unsigned size;
00079   };
00080 
00081   enum {
00082     INLINE_COUNT = sizeof(MallocData) - sizeof(unsigned)
00083   };
00084   
00085   union {
00086     struct {
00087       unsigned char* array;
00088       unsigned char pad[INLINE_COUNT - sizeof(unsigned char*)];
00089       unsigned size;
00090     } mPointer;
00091     struct {
00092       unsigned char array[INLINE_COUNT];
00093       unsigned size;
00094     } mInline;
00095   } mData;
00096 };
00097 
00098 template <> class VarLenTagDataTemplate<0u>
00099 {
00100 public:
00101   inline VarLenTagDataTemplate<0u>() {}
00102 
00103   enum {
00104     INLINE_COUNT = sizeof(unsigned char*)
00105   };
00106   
00107   union {
00108     struct {
00109       unsigned char* array;
00110       unsigned size;
00111     } mPointer;
00112     struct {
00113       unsigned char array[INLINE_COUNT];
00114       unsigned size;
00115     } mInline;
00116   } mData;
00117 };
00118 
00119 typedef VarLenTagDataTemplate<sizeof(unsigned char*) - sizeof(unsigned)> VarLenTagData;
00120 
00121 #endif
00122 
00129 class VarLenTag {
00130 protected:
00131   VarLenTagData mData;
00132 public:
00133   inline VarLenTag() { mData.mData.mPointer.size = 0; }
00134   inline VarLenTag( unsigned size );
00135   inline ~VarLenTag() { clear(); }
00136   inline VarLenTag( const VarLenTag& copy );
00137   inline VarLenTag( unsigned size, const void* data );
00138   
00139   inline unsigned size() const { return mData.mData.mPointer.size; }
00140 
00141   inline unsigned char* data() 
00142 #ifdef VAR_LEN_TAG_ELIDE_DATA    
00143     { return size() <= VarLenTagData::INLINE_COUNT ? 
00144                         mData.mData.mInline.array : 
00145                         mData.mData.mPointer.array; }
00146 #else
00147     { return mData.mData.mPointer.array; }
00148 #endif
00149 
00150   inline unsigned long mem() const
00151 #ifdef VAR_LEN_TAG_ELIDE_DATA    
00152     { return size() <= VarLenTagData::INLINE_COUNT ? 0 : size(); }
00153 #else
00154     { return size(); }
00155 #endif
00156 
00157   inline const unsigned char* data() const 
00158     { return const_cast<VarLenTag*>(this)->data(); }
00159   
00160   inline unsigned char* resize( unsigned size );
00161   
00162   inline void clear();
00163   
00164   inline void set( const void* dat, unsigned sz )
00165     { memcpy( resize(sz), dat, sz ); }
00166     
00167   inline VarLenTag& operator=( const VarLenTag& other )
00168     { set( other.data(), other.size() ); return *this; }
00169   
00170 };
00171   
00172 inline unsigned char* VarLenTag::resize( unsigned s ) 
00173 {
00174 #ifdef VAR_LEN_TAG_ELIDE_DATA
00175   if (s <= VarLenTagData::INLINE_COUNT) {
00176     if (size() > VarLenTagData::INLINE_COUNT) {
00177       unsigned char* tmp_ptr = mData.mData.mPointer.array;
00178       memcpy( mData.mData.mInline.array, tmp_ptr, s );
00179       free( tmp_ptr );
00180     }
00181     mData.mData.mInline.size = s;
00182     return mData.mData.mInline.array;
00183   }
00184   else if (size() <= VarLenTagData::INLINE_COUNT) {
00185     void* tmp_ptr = malloc(s);
00186     memcpy( tmp_ptr, mData.mData.mInline.array, size() );
00187     mData.mData.mPointer.array = reinterpret_cast<unsigned char*>(tmp_ptr);
00188   }
00189   else 
00190 #endif
00191   if (size() < s) {
00192     void* tmp_ptr = size() ? realloc( mData.mData.mPointer.array, s ) : malloc( s );
00193     mData.mData.mPointer.array = reinterpret_cast<unsigned char*>(tmp_ptr);
00194   }
00195   mData.mData.mPointer.size = s;
00196   return mData.mData.mPointer.array;
00197 }
00198 
00199 inline VarLenTag::VarLenTag( unsigned sz )
00200 {
00201 #ifdef VAR_LEN_TAG_ELIDE_DATA
00202   if (sz > VarLenTagData::INLINE_COUNT) 
00203 #endif
00204     mData.mData.mPointer.array = reinterpret_cast<unsigned char*>(malloc(sz));
00205   mData.mData.mPointer.size = sz;
00206 }
00207 
00208 inline void VarLenTag::clear()
00209 {
00210 #ifdef VAR_LEN_TAG_ELIDE_DATA
00211   if (size() > VarLenTagData::INLINE_COUNT)
00212 #else
00213   if (size())
00214 #endif
00215     free( mData.mData.mPointer.array );
00216   mData.mData.mPointer.size = 0;
00217 }
00218 
00219 inline VarLenTag::VarLenTag( const VarLenTag& copy )
00220   : mData( copy.mData )
00221 {
00222 #ifdef VAR_LEN_TAG_ELIDE_DATA
00223   if (size() > VarLenTagData::INLINE_COUNT)
00224 #endif
00225   {
00226     mData.mData.mPointer.array = reinterpret_cast<unsigned char*>(malloc(size()));
00227     memcpy( mData.mData.mPointer.array, copy.mData.mData.mPointer.array, size() );
00228   }
00229 }
00230 
00231 inline VarLenTag::VarLenTag( unsigned sz, const void* dat )
00232 {
00233   mData.mData.mPointer.size = 0;
00234   if (sz) 
00235     memcpy( resize(sz), dat, sz );
00236 }
00237 
00238 } // namespace moab
00239 
00240 #endif
00241 
00242 
00243     
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines