[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