Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
VarLenTag.hpp
Go to the documentation of this file.
1 #ifndef VAR_LEN_TAG_HPP
2 #define VAR_LEN_TAG_HPP
3 
4 #include <cstdlib>
5 #include <cstring>
6 
7 namespace moab
8 {
9 
10 /* Remove this preprocessor macro to compile
11  * simple implementation w/ no inlined storage
12  */
13 #define VAR_LEN_TAG_ELIDE_DATA
14 
15 /* Define class data layout depending on macros:
16  * VAR_LEN_TAG_ELIDE_DATA and TEMPLATE_SPECIALIZATION
17  */
18 #ifndef VAR_LEN_TAG_ELIDE_DATA
19 
20 /* The trivial implementation */
21 public
22 VarLenTagData
23 {
24  public:
25  struct
26  {
27  struct
28  {
29  unsigned size;
30  unsigned char* array;
31  } mPointer;
32  } mData;
33 };
34 
35 #elif !defined( MOAB_TEMPLATE_SPECIALIZATION )
36 
37 /* A little more advanced data structure for VarLenTag.
38  * If the amount of tag data is less than or equal to the
39  * size of the array pointer, store it inline in the pointer
40  * value field so no memory needs to be allocated.
41  */
43 {
44  public:
45  enum
46  {
47  INLINE_COUNT = sizeof( unsigned char* )
48  };
49 
50  union
51  {
52  struct
53  {
54  unsigned char* array;
55  unsigned size;
57  struct
58  {
59  unsigned char array[INLINE_COUNT];
60  unsigned size;
62  } mData;
63 };
64 
65 #else
66 
67 /* Most complex implementation. Same as the previous one, except
68  * when storing data inline, also utilize any padding in the struct.
69  * This implementation requires support for template specialization.
70  *
71  * - The data must be first in the struct to avoid alignment issues
72  * for double and 64-bit handle values on some platforms.
73  * - The size must therefore be at the end of the struct (including
74  * after any padding) because a) it cannot be at the beginning and
75  * b) it must be at the same location in both structs in the union.
76  * - For the mPointer variation, the padding must be declared
77  * explicitly in order for the size to be forced to the end.
78  * - Template specialization is used to avoid declaring a
79  * zero-length array for pad on 32-bit platforms.
80  * NOTE: GCC allows zero-length arrays, but Sun's compiler
81  * (and most others) do not.
82  */
83 template < unsigned >
84 class VarLenTagDataTemplate
85 {
86  public:
87  inline VarLenTagDataTemplate() {}
88 
89  struct MallocData
90  {
91  unsigned char* array;
92  unsigned size;
93  };
94 
95  enum
96  {
97  INLINE_COUNT = sizeof( MallocData ) - sizeof( unsigned )
98  };
99 
100  union
101  {
102  struct
103  {
104  unsigned char* array;
105  unsigned char pad[INLINE_COUNT - sizeof( unsigned char* )];
106  unsigned size;
107  } mPointer;
108  struct
109  {
110  unsigned char array[INLINE_COUNT];
111  unsigned size;
112  } mInline;
113  } mData;
114 };
115 
116 template <>
117 class VarLenTagDataTemplate< 0u >
118 {
119  public:
120  inline VarLenTagDataTemplate< 0u >() {}
121 
122  enum
123  {
124  INLINE_COUNT = sizeof( unsigned char* )
125  };
126 
127  union
128  {
129  struct
130  {
131  unsigned char* array;
132  unsigned size;
133  } mPointer;
134  struct
135  {
136  unsigned char array[INLINE_COUNT];
137  unsigned size;
138  } mInline;
139  } mData;
140 };
141 
142 typedef VarLenTagDataTemplate< sizeof( unsigned char* ) - sizeof( unsigned ) > VarLenTagData;
143 
144 #endif
145 
146 /**\brief Class for storing variable-length tag data
147  *
148  * Class for managing variable-length tag data.
149  *\NOTE This class must behave as if it were initialized to empty
150  * if it is memset to zero w/out invoking any constructor.
151  */
153 {
154  protected:
156 
157  public:
158  inline VarLenTag()
159  {
160  mData.mData.mPointer.size = 0;
161  }
162  inline VarLenTag( unsigned size );
163  inline ~VarLenTag()
164  {
165  clear();
166  }
167  inline VarLenTag( const VarLenTag& copy );
168  inline VarLenTag( unsigned size, const void* data );
169 
170  inline unsigned size() const
171  {
172  return mData.mData.mPointer.size;
173  }
174 
175  inline unsigned char* data()
176 #ifdef VAR_LEN_TAG_ELIDE_DATA
177  {
179  }
180 #else
181  {
182  return mData.mData.mPointer.array;
183  }
184 #endif
185 
186  inline unsigned long mem() const
187 #ifdef VAR_LEN_TAG_ELIDE_DATA
188  {
189  return size() <= VarLenTagData::INLINE_COUNT ? 0 : size();
190  }
191 #else
192  {
193  return size();
194  }
195 #endif
196 
197  inline const unsigned char* data() const
198  {
199  return const_cast< VarLenTag* >( this )->data();
200  }
201 
202  inline unsigned char* resize( unsigned size );
203 
204  inline void clear();
205 
206  inline void set( const void* dat, unsigned sz )
207  {
208  memcpy( resize( sz ), dat, sz );
209  }
210 
211  inline VarLenTag& operator=( const VarLenTag& other )
212  {
213  set( other.data(), other.size() );
214  return *this;
215  }
216 };
217 
218 inline unsigned char* VarLenTag::resize( unsigned s )
219 {
220 #ifdef VAR_LEN_TAG_ELIDE_DATA
221  if( s <= VarLenTagData::INLINE_COUNT )
222  {
224  {
225  unsigned char* tmp_ptr = mData.mData.mPointer.array;
226  memcpy( mData.mData.mInline.array, tmp_ptr, s );
227  free( tmp_ptr );
228  }
229  mData.mData.mInline.size = s;
230  return mData.mData.mInline.array;
231  }
232  else if( size() <= VarLenTagData::INLINE_COUNT )
233  {
234  void* tmp_ptr = malloc( s );
235  memcpy( tmp_ptr, mData.mData.mInline.array, size() );
236  mData.mData.mPointer.array = reinterpret_cast< unsigned char* >( tmp_ptr );
237  }
238  else
239 #endif
240  if( size() < s )
241  {
242  void* tmp_ptr = size() ? realloc( mData.mData.mPointer.array, s ) : malloc( s );
243  mData.mData.mPointer.array = reinterpret_cast< unsigned char* >( tmp_ptr );
244  }
245  mData.mData.mPointer.size = s;
246  return mData.mData.mPointer.array;
247 }
248 
249 inline VarLenTag::VarLenTag( unsigned sz )
250 {
251 #ifdef VAR_LEN_TAG_ELIDE_DATA
252  if( sz > VarLenTagData::INLINE_COUNT )
253 #endif
254  mData.mData.mPointer.array = reinterpret_cast< unsigned char* >( malloc( sz ) );
255  mData.mData.mPointer.size = sz;
256 }
257 
258 inline void VarLenTag::clear()
259 {
260 #ifdef VAR_LEN_TAG_ELIDE_DATA
262 #else
263  if( size() )
264 #endif
265  free( mData.mData.mPointer.array );
266  mData.mData.mPointer.size = 0;
267 }
268 
269 inline VarLenTag::VarLenTag( const VarLenTag& copy ) : mData( copy.mData )
270 {
271 #ifdef VAR_LEN_TAG_ELIDE_DATA
273 #endif
274  {
275  mData.mData.mPointer.array = reinterpret_cast< unsigned char* >( malloc( size() ) );
276  memcpy( mData.mData.mPointer.array, copy.mData.mData.mPointer.array, size() );
277  }
278 }
279 
280 inline VarLenTag::VarLenTag( unsigned sz, const void* dat )
281 {
282  mData.mData.mPointer.size = 0;
283  if( sz ) memcpy( resize( sz ), dat, sz );
284 }
285 
286 } // namespace moab
287 
288 #endif