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:
King_DuckZ 2015-07-25 19:12:21 +02:00
parent e64db02ac3
commit 1567feaa81
4 changed files with 89 additions and 35 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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");

View File

@ -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());
}
}