diff --git a/include/vectorwrapper/vectorwrapper.hpp b/include/vectorwrapper/vectorwrapper.hpp index 5b0b854..6e1d0f9 100644 --- a/include/vectorwrapper/vectorwrapper.hpp +++ b/include/vectorwrapper/vectorwrapper.hpp @@ -37,12 +37,40 @@ namespace vwr { define_has_typedef(higher_vector_type, HigherVec); define_has_enum(offset_x, OffsetX); define_has_method(get_at, GetAt); + define_has_enum(cast_ignore_trailing_properties, CastIgnoreTrailingProperties); template Vec& assign ( Vec& parLeft, const Vec& parRight ); template Vec& assign_same_type ( Vec& parLeft, const Vec& parRight ); + template struct get_offset_enum_from_index; + template struct get_offset_enum_from_index { + enum { value = VectorWrapperInfo::offset_x }; + }; + template struct get_offset_enum_from_index { + enum { value = VectorWrapperInfo::offset_y }; + }; + template struct get_offset_enum_from_index { + enum { value = VectorWrapperInfo::offset_z }; + }; + template struct get_offset_enum_from_index { + enum { value = VectorWrapperInfo::offset_w }; + }; + + template ::dimensions> struct min_offset { + enum { + value = ( + static_cast(get_offset_enum_from_index::value) < static_cast(min_offset::value) ? + static_cast(get_offset_enum_from_index::value) : + static_cast(min_offset::value) + ) + }; + }; + template struct min_offset { + enum { value = get_offset_enum_from_index::value }; + }; + template ::dimensions, std::size_t US=VectorWrapperInfo::dimensions> struct have_compat_offsets { enum { value = false }; }; @@ -54,28 +82,25 @@ namespace vwr { template struct have_compat_offsets { enum { value = - VectorWrapperInfo::offset_y - VectorWrapperInfo::offset_x == - VectorWrapperInfo::offset_y - VectorWrapperInfo::offset_x + VectorWrapperInfo::offset_x - min_offset::value == VectorWrapperInfo::offset_x - min_offset::value and + VectorWrapperInfo::offset_y - min_offset::value == VectorWrapperInfo::offset_y - min_offset::value }; }; template struct have_compat_offsets { enum { value = - VectorWrapperInfo::offset_y - VectorWrapperInfo::offset_x == - VectorWrapperInfo::offset_y - VectorWrapperInfo::offset_x and - VectorWrapperInfo::offset_z - VectorWrapperInfo::offset_x == - VectorWrapperInfo::offset_z - VectorWrapperInfo::offset_x + VectorWrapperInfo::offset_x - min_offset::value == VectorWrapperInfo::offset_x - min_offset::value and + VectorWrapperInfo::offset_y - min_offset::value == VectorWrapperInfo::offset_y - min_offset::value and + VectorWrapperInfo::offset_z - min_offset::value == VectorWrapperInfo::offset_z - min_offset::value }; }; template struct have_compat_offsets { enum { value = - VectorWrapperInfo::offset_y - VectorWrapperInfo::offset_x == - VectorWrapperInfo::offset_y - VectorWrapperInfo::offset_x and - VectorWrapperInfo::offset_z - VectorWrapperInfo::offset_x == - VectorWrapperInfo::offset_z - VectorWrapperInfo::offset_x and - VectorWrapperInfo::offset_w - VectorWrapperInfo::offset_x == - VectorWrapperInfo::offset_w - VectorWrapperInfo::offset_x + VectorWrapperInfo::offset_x - min_offset::value == VectorWrapperInfo::offset_x - min_offset::value and + VectorWrapperInfo::offset_y - min_offset::value == VectorWrapperInfo::offset_y - min_offset::value and + VectorWrapperInfo::offset_z - min_offset::value == VectorWrapperInfo::offset_z - min_offset::value and + VectorWrapperInfo::offset_w - min_offset::value == VectorWrapperInfo::offset_w - min_offset::value }; }; @@ -91,7 +116,6 @@ namespace vwr { }; template struct is_vec { - typedef void vector_type; enum { value = false }; }; template struct is_vec> { @@ -127,9 +151,9 @@ namespace vwr { const vector_type& data ( void ) const { return m_wrapped; } template - const typename std::enable_if::value and have_compat_layout::value, typename is_vec::vector_type, V>::type>::value and sizeof(V2) <= sizeof(V), V2>::type& cast ( void ) const; + const typename std::enable_if::value, V2>::type& cast ( void ) const; template - typename std::enable_if::value and have_compat_layout::value, typename is_vec::vector_type, V>::type>::value and sizeof(V2) <= sizeof(V), V2>::type& cast ( void ); + typename std::enable_if::value, V2>::type& cast ( void ); template VecBase& operator+= ( const VecBase& parOther ); template VecBase& operator-= ( const VecBase& parOther ); @@ -140,20 +164,6 @@ namespace vwr { vector_type m_wrapped; }; - template struct get_offset_enum_from_index; - template struct get_offset_enum_from_index { - enum { value = VectorWrapperInfo::offset_x }; - }; - template struct get_offset_enum_from_index { - enum { value = VectorWrapperInfo::offset_y }; - }; - template struct get_offset_enum_from_index { - enum { value = VectorWrapperInfo::offset_z }; - }; - template struct get_offset_enum_from_index { - enum { value = VectorWrapperInfo::offset_w }; - }; - template ::dimensions> struct offsets_array_wrapper { template diff --git a/include/vectorwrapper/vectorwrapper.inl b/include/vectorwrapper/vectorwrapper.inl index f96b216..861a92e 100644 --- a/include/vectorwrapper/vectorwrapper.inl +++ b/include/vectorwrapper/vectorwrapper.inl @@ -16,6 +16,10 @@ namespace vwr { namespace implem { + template >::value> struct IsCastIgnoreTrailingPropertiesSet; + template struct IsCastIgnoreTrailingPropertiesSet { static const bool value = static_cast(VectorWrapperInfo::cast_ignore_trailing_properties); }; + template struct IsCastIgnoreTrailingPropertiesSet { static const bool value = false; }; + template template VecBase::VecBase (const T& parInit, typename std::enable_if::value and not std::is_same::value, bool>::type) { @@ -67,7 +71,19 @@ namespace vwr { template template - const typename std::enable_if::value and have_compat_layout::value, typename is_vec::vector_type, V>::type>::value and sizeof(V2) <= sizeof(V), V2>::type& VecBase::cast() const { + const typename std::enable_if::value, V2>::type& VecBase::cast() const { + static_assert(sizeof(V2) <= sizeof(VecBase) - min_offset::value, "V2 must fit in V starting from the first coordinate"); + static_assert(std::is_standard_layout::value, "V2 must be a standard layout type"); + static_assert(min_offset::vector_type>::value == 0, "V2 must not have any properties before the first coordinate"); + static_assert(have_compat_layout::vector_type>::value, "V is not suitable for casting to V2"); + + //Assert that V2 won't stomp on part of V's data, unless the user + //has explicitly said he doesn't care. + static_assert((sizeof(typename VectorWrapperInfo::vector_type>::scalar_type) * dimensions == sizeof(V2)) or + IsCastIgnoreTrailingPropertiesSet::vector_type>::value, + "V2 must not have any properties past the last coordinate"); + static_assert(alignof(typename VectorWrapperInfo::scalar_type) == alignof(V2), "Casting to V2 would give you a misaligned variable"); + return *reinterpret_cast( reinterpret_cast(this) + VectorWrapperInfo::offset_x ); @@ -75,10 +91,8 @@ namespace vwr { template template - typename std::enable_if::value and have_compat_layout::value, typename is_vec::vector_type, V>::type>::value and sizeof(V2) <= sizeof(V), V2>::type& VecBase::cast() { - return *reinterpret_cast( - reinterpret_cast(this) + VectorWrapperInfo::offset_x - ); + typename std::enable_if::value, V2>::type& VecBase::cast() { + return const_cast(const_cast*>(this)->cast()); } template diff --git a/test/unit/sample_vectors.hpp b/test/unit/sample_vectors.hpp index 0c31040..defc683 100644 --- a/test/unit/sample_vectors.hpp +++ b/test/unit/sample_vectors.hpp @@ -45,7 +45,14 @@ namespace vwr { float x; float y; float z; - float c; + int c, d; + }; + + struct TrailingDataVector3 { + float X; + float Y; + float Z; + int a, b; }; template <> @@ -145,6 +152,21 @@ namespace vwr { }; }; + template <> + struct VectorWrapperInfo { + enum { + dimensions = 3, + cast_ignore_trailing_properties = 1 + }; + typedef float scalar_type; + + enum { + offset_x = offsetof(TrailingDataVector3, X), + offset_y = offsetof(TrailingDataVector3, Y), + offset_z = offsetof(TrailingDataVector3, Z) + }; + }; + typedef Vec svec1; typedef Vec svec2; typedef Vec svec3; @@ -153,6 +175,7 @@ namespace vwr { typedef Vec ivec3; typedef Vec mvec3; typedef Vec pvec3; + typedef Vec tvec3; static_assert(sizeof(svec1) == sizeof(float), "Wrong size"); static_assert(sizeof(svec2) == sizeof(SimpleVector2), "Wrong size"); diff --git a/test/unit/test_conversions.cpp b/test/unit/test_conversions.cpp index 5de8086..374bbe0 100644 --- a/test/unit/test_conversions.cpp +++ b/test/unit/test_conversions.cpp @@ -7,6 +7,12 @@ void test_svec3 (const vwr::svec3& parVec, float parX, float parY, float parZ) { EXPECT_EQ(parVec.z(), parZ); } +void test_tvec3 (const vwr::tvec3& parVec, float parX, float parY, float parZ) { + EXPECT_EQ(parVec.x(), parX); + EXPECT_EQ(parVec.y(), parY); + EXPECT_EQ(parVec.z(), parZ); +} + TEST(vwr, conversion) { using namespace vwr; @@ -42,5 +48,6 @@ TEST(vwr, conversion) { { pvec3 p3(1.0f, 2.0f, 3.0f); test_svec3(p3.cast(), p3.x(), p3.y(), p3.z()); + test_tvec3(p3.cast(), p3.x(), p3.y(), p3.z()); } }