[MOAB-dev] r1519 - MOAB/trunk

kraftche at mcs.anl.gov kraftche at mcs.anl.gov
Mon Jan 14 13:13:42 CST 2008


Author: kraftche
Date: 2008-01-14 13:13:42 -0600 (Mon, 14 Jan 2008)
New Revision: 1519

Added:
   MOAB/trunk/VarLenTag.hpp
   MOAB/trunk/VarLenTagTest.cpp
Modified:
   MOAB/trunk/Makefile.am
Log:
Add class for storing variable-length tag data

Modified: MOAB/trunk/Makefile.am
===================================================================
--- MOAB/trunk/Makefile.am	2008-01-14 19:09:31 UTC (rev 1518)
+++ MOAB/trunk/Makefile.am	2008-01-14 19:13:42 UTC (rev 1519)
@@ -27,7 +27,8 @@
 	vtk_test \
 	adaptive_kd_tree_tests \
 	file_options_test \
-        kd_tree_test
+        kd_tree_test \
+        var_len_test var_len_test_no_template
 #                 merge_test \         # input files no longer exist?
 #                 test_tag_server \    # fails
 
@@ -322,6 +323,11 @@
 file_options_test_SOURCES = FileOptions.cpp 
 file_options_test_CPPFLAGS = -DTEST
 
+var_len_test_SOURCES = VarLenTagTest.cpp
+var_len_test_no_template_SOURCES = $(var_len_test_SOURCES)
+var_len_test_no_template_CPPFLAGS = -UTEMPLATE_SPECIALIZATION
+
+
 # Other files to clean up (e.g. output from tests)
 MOSTLYCLEANFILES = dumped_acis.sat
 

Added: MOAB/trunk/VarLenTag.hpp
===================================================================
--- MOAB/trunk/VarLenTag.hpp	                        (rev 0)
+++ MOAB/trunk/VarLenTag.hpp	2008-01-14 19:13:42 UTC (rev 1519)
@@ -0,0 +1,221 @@
+#ifndef VAR_LEN_TAG_HPP
+#define VAR_LEN_TAG_HPP
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Remove this preprocessor macro to compile 
+ * simple implementation w/ no inlined storage
+ */
+#define VAR_LEN_TAG_ELIDE_DATA
+
+
+/* Define class data layout depenkding on macros:
+ * VAR_LEN_TAG_ELIDE_DATA and TEMPLATE_SPECIALIZATION
+ */
+#ifndef VAR_LEN_TAG_ELIDE_DATA
+
+/* The trivial implementation */
+public VarLenTagData {
+protected:
+
+  struct { struct { unsigned size; unsigned char* array; } mPointer; } mData;
+};
+
+#elif !defined(TEMPLATE_SPECIALIZATION)
+
+/* A little more advanced data structure for VarLenTag.
+ * If the amount of tag data is less than or equal to the
+ * size of the array pointer, store it inline in the pointer
+ * value field so no memory needs to be allocated.
+ */
+class VarLenTagData {
+protected:
+
+  enum {
+    INLINE_COUNT = sizeof(unsigned char*)
+  };
+
+  union {
+    struct { 
+      unsigned char* array;
+      unsigned size;
+    } mPointer;
+    struct {
+      unsigned char array[INLINE_COUNT];
+      unsigned size;
+    } mInline;
+  } mData;
+};
+
+#else
+
+/* Most complex implementation.  Same as the previous one, except
+ * when storing data inline, also utilize any padding in the struct.
+ * This implementation requires support for template specialization.
+ * 
+ * - The data must be first in the struct to avoid alignment issues
+ *   for double and 64-bit handle values on some platforms.
+ * - The size must therefore be at the end of the struct (including
+ *   after any padding) becase a) it cannot be at the beginning and
+ *   b) it must be at the same location in both structs in the union.
+ * - For the mPointer variation, the padding must be declared
+ *   explicitly in order for the size to be forced to the end.
+ * - Template specialiation is used to avoid declaring a
+ *   zero-length array for pad on 32-bit platforms.  
+ *   NOTE: GCC allows zero-length arrays, but Sun's compiler 
+ *   (and most others) do not.
+ */
+template <unsigned>
+class VarLenTagDataTemplate {
+protected:
+
+  struct MallocData {
+    unsigned char* array;
+    unsigned size;
+  };
+
+  enum {
+    INLINE_COUNT = sizeof(MallocData) - sizeof(unsigned)
+  };
+  
+  union {
+    struct {
+      unsigned char* array;
+      unsigned char pad[INLINE_COUNT - sizeof(unsigned char*)];
+      unsigned size;
+    } mPointer;
+    struct {
+      unsigned char array[INLINE_COUNT];
+      unsigned size;
+    } mInline;
+  } mData;
+};
+
+template <> class VarLenTagDataTemplate<0u>
+{
+protected:
+
+  enum {
+    INLINE_COUNT = sizeof(unsigned char*)
+  };
+  
+  union {
+    struct {
+      unsigned char* array;
+      unsigned size;
+    } mPointer;
+    struct {
+      unsigned char array[INLINE_COUNT];
+      unsigned size;
+    } mInline;
+  } mData;
+};
+
+typedef VarLenTagDataTemplate<sizeof(unsigned char*) - sizeof(unsigned)> VarLenTagData;
+
+#endif
+
+/**\brief Class for storing variable-length tag data
+ *
+ * Class for managing variable-length tag data.  
+ *\NOTE This class must behave as if it were initialized to
+ *      if it is memset to zero w/out invoking any constructor.
+ */ 
+class VarLenTag : public VarLenTagData {
+public:
+
+  inline VarLenTag() { mData.mPointer.size = 0; }
+  inline VarLenTag( unsigned size );
+  inline ~VarLenTag() { clear(); }
+  inline VarLenTag( const VarLenTag& copy );
+  inline VarLenTag( unsigned size, void* data );
+  
+  inline unsigned size() const { return mData.mPointer.size; }
+
+  inline unsigned char* data() 
+#ifdef VAR_LEN_TAG_ELIDE_DATA    
+    { return size() <= INLINE_COUNT ? mData.mInline.array : mData.mPointer.array; }
+#else
+    { return mData.mPointer.array; }
+#endif
+
+  inline const unsigned char* data() const 
+    { return const_cast<VarLenTag*>(this)->data(); }
+  
+  inline unsigned char* resize( unsigned size );
+  
+  inline void clear();
+  
+};
+  
+inline unsigned char* VarLenTag::resize( unsigned s ) 
+{
+#ifdef VAR_LEN_TAG_ELIDE_DATA
+  if (s <= INLINE_COUNT) {
+    if (size() > INLINE_COUNT) {
+      unsigned char* tmp_ptr = mData.mPointer.array;
+      memcpy( mData.mInline.array, tmp_ptr, s );
+      free( tmp_ptr );
+    }
+    mData.mInline.size = s;
+    return mData.mInline.array;
+  }
+  else if (size() <= INLINE_COUNT) {
+    void* tmp_ptr = malloc(s);
+    memcpy( tmp_ptr, mData.mInline.array, size() );
+    mData.mPointer.array = reinterpret_cast<unsigned char*>(tmp_ptr);
+  }
+  else 
+#endif
+  if (size() < s) {
+    void* tmp_ptr = size() ? realloc( mData.mPointer.array, s ) : malloc( s );
+    mData.mPointer.array = reinterpret_cast<unsigned char*>(tmp_ptr);
+  }
+  mData.mPointer.size = s;
+  return mData.mPointer.array;
+}
+
+inline VarLenTag::VarLenTag( unsigned size )
+{
+#ifdef VAR_LEN_TAG_ELIDE_DATA
+  if (size > INLINE_COUNT) 
+#endif
+    mData.mPointer.array = reinterpret_cast<unsigned char*>(malloc(size));
+  mData.mPointer.size = size;
+}
+
+inline void VarLenTag::clear()
+{
+#ifdef VAR_LEN_TAG_ELIDE_DATA
+  if (size() > INLINE_COUNT)
+#else
+  if (size())
+#endif
+    free( mData.mPointer.array );
+  mData.mPointer.size = 0;
+}
+
+inline VarLenTag( const VarLenTag& copy )
+  : VarLenTagData( copy )
+{
+#ifdef 
+  if (size() > INLINE_COUNT)
+#endif
+  {
+    copy.mData.mPointer.array = reinterpret_cast<unsigned char*>(malloc(size()));
+    memcpy( copy.mData.mPointer.array, mData.mPointer.array, size() );
+  }
+}
+
+inline VarLenTag( unsigned size, void* data )
+{
+  mData.mPointer.size = 0;
+  if (size) 
+    memcpy( resize(size), data, size );
+}
+
+#endif
+
+
+    

Added: MOAB/trunk/VarLenTagTest.cpp
===================================================================
--- MOAB/trunk/VarLenTagTest.cpp	                        (rev 0)
+++ MOAB/trunk/VarLenTagTest.cpp	2008-01-14 19:13:42 UTC (rev 1519)
@@ -0,0 +1,116 @@
+#include "TestUtil.hpp"
+#include "VarLenTag.hpp"
+
+#include <iostream>
+
+void test_valid_struct();
+void test_inline();
+void test_non_inline();
+void test_resize_ii();
+void test_resize_in();
+void test_resize_ni();
+void test_resize_nn();
+
+int main()
+{
+  int count = 0;
+  count += RUN_TEST( test_valid_struct );
+  if (count) {
+    std::cerr << "ABORTING VarLenTag TEST" << std::endl
+              << "Structure is not valid" << std::endl;
+    return count;
+  }
+  
+  count += RUN_TEST( test_inline );
+  count += RUN_TEST( test_non_inline );
+  count += RUN_TEST( test_resize_ii );
+  count += RUN_TEST( test_resize_in );
+  count += RUN_TEST( test_resize_ni );
+  count += RUN_TEST( test_resize_nn );
+  
+  return count;
+}
+  
+
+#define OFFSET( A ) ((char*)(&(A)) - (char*)this)
+class GetOffsets : public VarLenTag
+{
+public:
+  unsigned pointer_array_offset() { return OFFSET(mData.mPointer.array); }
+  unsigned pointer_size_offset() { return OFFSET(mData.mPointer.size); }
+#ifdef VAR_LEN_TAG_ELIDE_DATA
+  unsigned inline_array_offset() { return OFFSET(mData.mInline.array); }
+  unsigned inline_size_offset() { return OFFSET(mData.mInline.size); }
+#endif
+};
+struct ExpectedSize
+{
+  unsigned char* pointer;
+  unsigned size;
+};
+
+
+void test_valid_struct()
+{
+  GetOffsets off;
+  CHECK_EQUAL( 0u, off.pointer_array_offset() );
+#ifdef VAR_LEN_TAG_ELIDE_DATA
+  CHECK_EQUAL( 0u, off.inline_array_offset() );
+  CHECK_EQUAL( off.pointer_size_offset(), off.inline_size_offset() );
+#endif
+  CHECK_EQUAL( sizeof(ExpectedSize), sizeof(VarLenTag) );
+}
+
+void test_inline()
+{
+  VarLenTag tag( sizeof(void*) );
+  CHECK_EQUAL( (unsigned char*)&tag, tag.data() );
+}
+
+void test_non_inline()
+{
+  VarLenTag tag( 2*sizeof(void*) );
+  CHECK( (unsigned char*)&tag != tag.data() );
+}
+
+void test_resize_ii()
+{
+  VarLenTag tag( 1 );
+  tag.data()[0] = 'X';
+  unsigned char* ptr = tag.resize( 3 );
+  CHECK_EQUAL( tag.data(), ptr );
+  CHECK_EQUAL( (unsigned char*)&tag, tag.data() );
+  CHECK_EQUAL( tag.data()[0], 'X' );
+}
+
+void test_resize_in()
+{
+  VarLenTag tag( sizeof(void*) );
+  memcpy( tag.data(), "ABCDEFGHIJKLMNOPQRST", sizeof(void*) );
+  unsigned char* ptr = tag.resize( 2*sizeof(void*) );
+  CHECK_EQUAL( tag.data(), ptr );
+  CHECK( (unsigned char*)&tag != tag.data() );
+  CHECK( !memcmp( tag.data(), "ABCDEFGHIJKLMNOPQRST", sizeof(void*) ) );
+}
+
+void test_resize_ni()
+{
+  VarLenTag tag( 2*sizeof(void*) );
+  memcpy( tag.data(), "12345678901234567890", sizeof(void*) );
+  unsigned char* ptr = tag.resize( sizeof(void*) );
+  CHECK_EQUAL( tag.data(), ptr );
+  CHECK_EQUAL( (unsigned char*)&tag, tag.data() );
+  CHECK( !memcmp( tag.data(), "12345678901234567890", sizeof(void*) ) );
+}
+  
+void test_resize_nn()
+{
+  VarLenTag tag( 2*sizeof(void*) );
+  memcpy( tag.data(), "TSRQPONMLKJIHGFEDCBA", 2*sizeof(void*) );
+  unsigned char* ptr = tag.resize( 4*sizeof(void*) );
+  CHECK_EQUAL( tag.data(), ptr );
+  CHECK( (unsigned char*)&tag != tag.data() );
+  CHECK( !memcmp( tag.data(), "TSRQPONMLKJIHGFEDCBA", sizeof(void*) ) );
+}
+ 
+




More information about the moab-dev mailing list