moab
|
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