Fix casting.
Casting conditions got clarified. User is now able to say he doesn't care if casting a wrapper on a type larger than just the coordinates will stomp on extra data from the casted type.
This commit is contained in:
parent
e64db02ac3
commit
1567feaa81
4 changed files with 89 additions and 35 deletions
|
@ -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 <typename V1, typename V2, std::size_t D>
|
||||
Vec<V1>& assign ( Vec<V1, D>& parLeft, const Vec<V2, D>& parRight );
|
||||
template <typename V>
|
||||
Vec<V>& assign_same_type ( Vec<V>& parLeft, const Vec<V>& parRight );
|
||||
|
||||
template <typename T, std::size_t I> struct get_offset_enum_from_index;
|
||||
template <typename T> struct get_offset_enum_from_index<T, 0> {
|
||||
enum { value = VectorWrapperInfo<T>::offset_x };
|
||||
};
|
||||
template <typename T> struct get_offset_enum_from_index<T, 1> {
|
||||
enum { value = VectorWrapperInfo<T>::offset_y };
|
||||
};
|
||||
template <typename T> struct get_offset_enum_from_index<T, 2> {
|
||||
enum { value = VectorWrapperInfo<T>::offset_z };
|
||||
};
|
||||
template <typename T> struct get_offset_enum_from_index<T, 3> {
|
||||
enum { value = VectorWrapperInfo<T>::offset_w };
|
||||
};
|
||||
|
||||
template <typename T, std::size_t S=VectorWrapperInfo<T>::dimensions> struct min_offset {
|
||||
enum {
|
||||
value = (
|
||||
static_cast<int>(get_offset_enum_from_index<T, S-1>::value) < static_cast<int>(min_offset<T, S-1>::value) ?
|
||||
static_cast<int>(get_offset_enum_from_index<T, S-1>::value) :
|
||||
static_cast<int>(min_offset<T, S-1>::value)
|
||||
)
|
||||
};
|
||||
};
|
||||
template <typename T> struct min_offset<T, 1> {
|
||||
enum { value = get_offset_enum_from_index<T, 0>::value };
|
||||
};
|
||||
|
||||
template <typename T, typename U, std::size_t TS=VectorWrapperInfo<T>::dimensions, std::size_t US=VectorWrapperInfo<U>::dimensions> struct have_compat_offsets {
|
||||
enum { value = false };
|
||||
};
|
||||
|
@ -54,28 +82,25 @@ namespace vwr {
|
|||
template <typename T, typename U> struct have_compat_offsets<T, U, 2, 2> {
|
||||
enum {
|
||||
value =
|
||||
VectorWrapperInfo<T>::offset_y - VectorWrapperInfo<T>::offset_x ==
|
||||
VectorWrapperInfo<U>::offset_y - VectorWrapperInfo<U>::offset_x
|
||||
VectorWrapperInfo<T>::offset_x - min_offset<T>::value == VectorWrapperInfo<U>::offset_x - min_offset<U>::value and
|
||||
VectorWrapperInfo<T>::offset_y - min_offset<T>::value == VectorWrapperInfo<U>::offset_y - min_offset<U>::value
|
||||
};
|
||||
};
|
||||
template <typename T, typename U> struct have_compat_offsets<T, U, 3, 3> {
|
||||
enum {
|
||||
value =
|
||||
VectorWrapperInfo<T>::offset_y - VectorWrapperInfo<T>::offset_x ==
|
||||
VectorWrapperInfo<U>::offset_y - VectorWrapperInfo<U>::offset_x and
|
||||
VectorWrapperInfo<T>::offset_z - VectorWrapperInfo<T>::offset_x ==
|
||||
VectorWrapperInfo<U>::offset_z - VectorWrapperInfo<U>::offset_x
|
||||
VectorWrapperInfo<T>::offset_x - min_offset<T>::value == VectorWrapperInfo<U>::offset_x - min_offset<U>::value and
|
||||
VectorWrapperInfo<T>::offset_y - min_offset<T>::value == VectorWrapperInfo<U>::offset_y - min_offset<U>::value and
|
||||
VectorWrapperInfo<T>::offset_z - min_offset<T>::value == VectorWrapperInfo<U>::offset_z - min_offset<U>::value
|
||||
};
|
||||
};
|
||||
template <typename T, typename U> struct have_compat_offsets<T, U, 4, 4> {
|
||||
enum {
|
||||
value =
|
||||
VectorWrapperInfo<T>::offset_y - VectorWrapperInfo<T>::offset_x ==
|
||||
VectorWrapperInfo<U>::offset_y - VectorWrapperInfo<U>::offset_x and
|
||||
VectorWrapperInfo<T>::offset_z - VectorWrapperInfo<T>::offset_x ==
|
||||
VectorWrapperInfo<U>::offset_z - VectorWrapperInfo<U>::offset_x and
|
||||
VectorWrapperInfo<T>::offset_w - VectorWrapperInfo<T>::offset_x ==
|
||||
VectorWrapperInfo<U>::offset_w - VectorWrapperInfo<U>::offset_x
|
||||
VectorWrapperInfo<T>::offset_x - min_offset<T>::value == VectorWrapperInfo<U>::offset_x - min_offset<U>::value and
|
||||
VectorWrapperInfo<T>::offset_y - min_offset<T>::value == VectorWrapperInfo<U>::offset_y - min_offset<U>::value and
|
||||
VectorWrapperInfo<T>::offset_z - min_offset<T>::value == VectorWrapperInfo<U>::offset_z - min_offset<U>::value and
|
||||
VectorWrapperInfo<T>::offset_w - min_offset<T>::value == VectorWrapperInfo<U>::offset_w - min_offset<U>::value
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -91,7 +116,6 @@ namespace vwr {
|
|||
};
|
||||
|
||||
template <typename V> struct is_vec {
|
||||
typedef void vector_type;
|
||||
enum { value = false };
|
||||
};
|
||||
template <typename V> struct is_vec<Vec<V>> {
|
||||
|
@ -127,9 +151,9 @@ namespace vwr {
|
|||
const vector_type& data ( void ) const { return m_wrapped; }
|
||||
|
||||
template <typename V2>
|
||||
const typename std::enable_if<is_vec<V2>::value and have_compat_layout<V, typename std::conditional<is_vec<V2>::value, typename is_vec<V2>::vector_type, V>::type>::value and sizeof(V2) <= sizeof(V), V2>::type& cast ( void ) const;
|
||||
const typename std::enable_if<is_vec<V2>::value, V2>::type& cast ( void ) const;
|
||||
template <typename V2>
|
||||
typename std::enable_if<is_vec<V2>::value and have_compat_layout<V, typename std::conditional<is_vec<V2>::value, typename is_vec<V2>::vector_type, V>::type>::value and sizeof(V2) <= sizeof(V), V2>::type& cast ( void );
|
||||
typename std::enable_if<is_vec<V2>::value, V2>::type& cast ( void );
|
||||
|
||||
template <typename V2> VecBase& operator+= ( const VecBase<V2>& parOther );
|
||||
template <typename V2> VecBase& operator-= ( const VecBase<V2>& parOther );
|
||||
|
@ -140,20 +164,6 @@ namespace vwr {
|
|||
vector_type m_wrapped;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t I> struct get_offset_enum_from_index;
|
||||
template <typename T> struct get_offset_enum_from_index<T, 0> {
|
||||
enum { value = VectorWrapperInfo<T>::offset_x };
|
||||
};
|
||||
template <typename T> struct get_offset_enum_from_index<T, 1> {
|
||||
enum { value = VectorWrapperInfo<T>::offset_y };
|
||||
};
|
||||
template <typename T> struct get_offset_enum_from_index<T, 2> {
|
||||
enum { value = VectorWrapperInfo<T>::offset_z };
|
||||
};
|
||||
template <typename T> struct get_offset_enum_from_index<T, 3> {
|
||||
enum { value = VectorWrapperInfo<T>::offset_w };
|
||||
};
|
||||
|
||||
template <typename T, std::size_t S=VectorWrapperInfo<T>::dimensions>
|
||||
struct offsets_array_wrapper {
|
||||
template <std::size_t... I>
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
namespace vwr {
|
||||
namespace implem {
|
||||
template <typename T, bool=HasCastIgnoreTrailingPropertiesEnum<VectorWrapperInfo<T>>::value> struct IsCastIgnoreTrailingPropertiesSet;
|
||||
template <typename T> struct IsCastIgnoreTrailingPropertiesSet<T, true> { static const bool value = static_cast<bool>(VectorWrapperInfo<T>::cast_ignore_trailing_properties); };
|
||||
template <typename T> struct IsCastIgnoreTrailingPropertiesSet<T, false> { static const bool value = false; };
|
||||
|
||||
template <typename V>
|
||||
template <typename T>
|
||||
VecBase<V>::VecBase (const T& parInit, typename std::enable_if<std::is_same<T, scalar_type>::value and not std::is_same<scalar_type, vector_type>::value, bool>::type) {
|
||||
|
@ -67,7 +71,19 @@ namespace vwr {
|
|||
|
||||
template <typename V>
|
||||
template <typename V2>
|
||||
const typename std::enable_if<is_vec<V2>::value and have_compat_layout<V, typename std::conditional<is_vec<V2>::value, typename is_vec<V2>::vector_type, V>::type>::value and sizeof(V2) <= sizeof(V), V2>::type& VecBase<V>::cast() const {
|
||||
const typename std::enable_if<is_vec<V2>::value, V2>::type& VecBase<V>::cast() const {
|
||||
static_assert(sizeof(V2) <= sizeof(VecBase<V>) - min_offset<V>::value, "V2 must fit in V starting from the first coordinate");
|
||||
static_assert(std::is_standard_layout<V2>::value, "V2 must be a standard layout type");
|
||||
static_assert(min_offset<typename is_vec<V2>::vector_type>::value == 0, "V2 must not have any properties before the first coordinate");
|
||||
static_assert(have_compat_layout<V, typename is_vec<V2>::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<typename is_vec<V2>::vector_type>::scalar_type) * dimensions == sizeof(V2)) or
|
||||
IsCastIgnoreTrailingPropertiesSet<typename is_vec<V2>::vector_type>::value,
|
||||
"V2 must not have any properties past the last coordinate");
|
||||
static_assert(alignof(typename VectorWrapperInfo<V>::scalar_type) == alignof(V2), "Casting to V2 would give you a misaligned variable");
|
||||
|
||||
return *reinterpret_cast<const V2*>(
|
||||
reinterpret_cast<const char*>(this) + VectorWrapperInfo<V>::offset_x
|
||||
);
|
||||
|
@ -75,10 +91,8 @@ namespace vwr {
|
|||
|
||||
template <typename V>
|
||||
template <typename V2>
|
||||
typename std::enable_if<is_vec<V2>::value and have_compat_layout<V, typename std::conditional<is_vec<V2>::value, typename is_vec<V2>::vector_type, V>::type>::value and sizeof(V2) <= sizeof(V), V2>::type& VecBase<V>::cast() {
|
||||
return *reinterpret_cast<V2*>(
|
||||
reinterpret_cast<char*>(this) + VectorWrapperInfo<V>::offset_x
|
||||
);
|
||||
typename std::enable_if<is_vec<V2>::value, V2>::type& VecBase<V>::cast() {
|
||||
return const_cast<V2&>(const_cast<const VecBase<V>*>(this)->cast<V2>());
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
|
|
|
@ -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<TrailingDataVector3> {
|
||||
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<float> svec1;
|
||||
typedef Vec<SimpleVector2> svec2;
|
||||
typedef Vec<SimpleVector3> svec3;
|
||||
|
@ -153,6 +175,7 @@ namespace vwr {
|
|||
typedef Vec<IntVector3> ivec3;
|
||||
typedef Vec<MixedDataVector3> mvec3;
|
||||
typedef Vec<PaddedVector3> pvec3;
|
||||
typedef Vec<TrailingDataVector3> tvec3;
|
||||
|
||||
static_assert(sizeof(svec1) == sizeof(float), "Wrong size");
|
||||
static_assert(sizeof(svec2) == sizeof(SimpleVector2), "Wrong size");
|
||||
|
|
|
@ -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<svec3>(), p3.x(), p3.y(), p3.z());
|
||||
test_tvec3(p3.cast<tvec3>(), p3.x(), p3.y(), p3.z());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue