First import

This commit is contained in:
King_DuckZ 2015-07-23 01:37:35 +02:00
parent 4c15aadf4e
commit 08050e42da
5 changed files with 970 additions and 0 deletions

164
README.md Normal file
View file

@ -0,0 +1,164 @@
# Vector Wrapper #
## Motivation ##
We all need vectors in our code, and there are quite a few implementations out there. They all do their job, and in terms of interface they are pretty similar to each other, but not *exactly* the same thing.
While this is not an issue in its own, it can become a problem when your code depends on external libraries that will provide their own vector implementation. So you might have your own implementation, MyVector, and the library will give you Ogre::Vector3, which is what you must use when you invoke Ogre's functions. If you also depend on openCV you will have yet another vector around. Microsoft Kinect SDK also imposes you its own, barebone vector implementation.
While through discipline you can manage such cases more or less well, there is one major issue that I couldn't work around: your own library code. I like to write code I think I will re-use at some point in the future in libraries separate from the main program. Odds are at some point you will need some maths that are not covered by the library vector you are using. Unless it's something really particular, I will probably try to write it in some library so that other projects can benefit from my new formula. The good thing about low level libraries is that they have very few dependencies, or none at all, and can thus be carried around and adapted to a variety of projects. It's all nice and good, but how would you add your new function taking a Ogre::Vector3 into a library that depends on nothing without bringing in the whole Ogre3D library?
This is where my class comes into play.
## Implementation ##
The basic idea is that all vectors will somehow give you access to some x, y, z coordinates. You will do that very frequently in your code, maybe on different platforms and in time critical parts of your code, so virtual calls (or equivalent) are not an option. This library is entirely templated, and will let you wrap any type inside a Vec. In fact, you could even just use this wrapper as your vector of choice, using an `std::array<float, 3>` as the wrapped type and forget how it's working under the hood.
Unfortunately the fact that you use `Vec<std::array<float, 3>>` and `Vec<Ogre::Vector3>` also means that you still have several types of vectors in your program. The good news is that conversion is automated (no more `Ogre::Vector3(other_vec.X, other_vec.Y, other_vec.Z)` in your code) and often it will not even be necessary, as casting will suffice.
You still need to type some code in order to get started using the vector wrapper class, which is basically your custom implementation of a struct listing informations about the wrapped type. That's not a lot of code.
## Features ##
### Automated conversion ###
You can assign or construct a `Vec<A>` from a `Vec<B>`, provided they have the same dimensions and the assignemnt operator is able to convert B's scalar type to that of A.
### Access the wrapped type ###
Through the `data()` method you can always obtain a ref to the wrapped type.
### Dimension change ###
Depending on the wrapped type, Vec can provide methods to get a Vec of lower or higher dimensions. For example, `Vec<Ogre::Vector3>` can optionally expose a `xy()` method that is equivalent to `Vec<Ogre::Vector2>(vec3.x(), vec3.y())`.
### Casting ###
You can cast `Vec<A>` to `Vec<B>` if they have the same layout and if `B` is only as big as the coordinates part in `A`.
For example you could conceptually wrap a type A:
struct A {
int something;
float x, y, z;
std::string something_else;
};
and still have it castable to type B:
struct B {
float x, y, z;
};
Vectors must still have the same dimensions. `cast<type>()` is only available when you define `offset_x` (see <u>Usage</u>). Either way, to cast (reinterpret_cast actually, be careful about the strict aliasing rule) you can just do the following:
typedef Vec<A> avec;
typedef Vec<B> bvec;
avec a(0);
some_function(bvec(a)); //creates a temporary
some_function(a.cast<bvec>()); //reinterpret_cast
## Usage ##
In this example we will adapt `std::array<float, N>` and `Ogre::VectorN`. In your real code, write the VectorWrapperInfo specializations for your own wrapped types in some header file, and just include it in your code to use Vec with those types.
//Include Vec's header
#include "vectorwrapper.hpp"
#include <array>
#include <stddef.h>
template <>
struct VectorWrapperInfo<std::array<float, 3>> {
enum {
//Tell Vec this is a 3D vector
dimensions = 3
};
//The inner type is a float
typedef float scalar_type;
//Not required by Vec but useful for us
typedef std::array<float, 3> vector_type;
//This will make the xy(), xz() and yz() methods available
typedef std::array<float, 2> lower_vector_type;
scalar_type& get_at (size_t parIndex, vector_type& parVector) {
//parIndex is already asserted to be < dimensions
//so you can always assume it's valid.
return parVector[parIndex];
}
};
template <>
struct VectorWrapperInfo<std::array<float, 2>> {
enum {
dimensions = 2
};
typedef float scalar_type;
typedef std::array<float, 2> vector_type;
typedef std::array<float, 3> higher_vector_type;
typedef std::array<float, 1> lower_vector_type;
scalar_type& get_at (size_t parIndex, vector_type& parVector) {
return parVector[parIndex];
}
};
//Not really useful I suppose, but this is just an example
template <>
struct VectorWrapperInfo<float> {
enum {
dimensions = 1
};
typedef float scalar_type;
typedef float vector_type;
typedef std::array<float, 2> higher_vector_type;
scalar_type& get_at (size_t, vector_type& parVector) {
return parVector;
}
};
template <>
struct VectorWrapperInfo<Ogre::Vector3> {
enum {
dimensions = 3
};
typedef Ogre::Real scalar_type;
typedef Ogre::Vector3 vector_type;
typedef Ogre::Vector2 lower_vector_type;
//If you want, you can implement the get_at() method as we did
//for std::array, returning *(&parVector.x + parIndex)
//but you can let Vec do that for you and just provide some
//offsets. By doing this, you also give a hint to Vec about
//what the wrapped type's layout is, so it will enable
//certain casts that would be disabled if you provided
//the get_at() method instead.
enum {
offset_x = offestof(Ogre::Vector3, x),
offset_y = offsetof(Ogre::Vector3, y),
offset_z = offsetof(Ogre::Vector3, z)
};
};
template <>
struct VectorWrapperInfo<Ogre::Vector2> {
enum {
dimensions = 2
};
typedef Ogre::Real scalar_type;
typedef Ogre::Vector2 vector_type;
typedef Ogre::Vector3 higher_vector_type;
enum {
offset_x = offestof(Ogre::Vector3, x),
offset_y = offsetof(Ogre::Vector3, y)
};
};
typedef Vec<std::array<float, 3>> avec3;
typedef Vec<std::array<float, 2>> avec2;
typedef Vec<float> avec1;
typedef Vec<Ogre::Vector3> ovec3;
typedef Vec<Ogre::Vector2> ovec2;
## Limitations ##
* 4D vectors are not currently supported
* Read-only vectors are not supported (not sure if such a thing is really needed)

View file

@ -0,0 +1,54 @@
/*
* Copyright 2015 Michele "King_DuckZ" Santullo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef idFBC29C5127784D35BE62F7BAC16E3687
#define idFBC29C5127784D35BE62F7BAC16E3687
#define define_has_method(method_name,pretty_name) \
template <typename T> \
struct Has ## pretty_name ## Method { \
private: \
struct TrueType { int a[2]; }; \
typedef int FalseType; \
template <typename C> static TrueType has_method ( decltype(&C::method_name) ); \
template <typename C> static FalseType has_method ( ... ); \
public: \
enum { value = sizeof(has_method<T>(0)) == sizeof(TrueType) }; \
}
#define define_has_typedef(typedef_name,pretty_name) \
template <typename T> \
struct Has ## pretty_name ## Typedef { \
private: \
struct TrueType { int a[2]; }; \
typedef int FalseType; \
template <typename C> static decltype(C::typedef_name(), TrueType()) has_typedef ( int ); \
template <typename C> static FalseType has_typedef ( ... ); \
public: \
enum { value = sizeof(has_typedef<T>(0)) == sizeof(TrueType) }; \
}
#define define_has_enum(enum_name,pretty_name) \
template <typename T> \
struct Has ## pretty_name ## Enum { \
private: \
struct TrueType { int a[2]; }; \
typedef int FalseType; \
template <typename C> static TrueType has_enum ( int = C::enum_name ); \
template <typename C> static FalseType has_enum ( ... ); \
public:\
enum { value = sizeof(has_enum<T>(0)) == sizeof(TrueType) }; \
}
#endif

View file

@ -0,0 +1,47 @@
/*
* Copyright 2015 Michele "King_DuckZ" Santullo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef id4FAEF395B9ED47CB9D6B50B54C9A289A
#define id4FAEF395B9ED47CB9D6B50B54C9A289A
#include <cstddef>
namespace vwr {
namespace bt {
template <std::size_t... I>
struct index_seq {
};
namespace implem {
template <std::size_t MIN, std::size_t MAX, std::size_t... I>
struct range_builder;
template <std::size_t MIN, std::size_t... I>
struct range_builder<MIN, MIN, I...> {
typedef index_seq<I...> type;
};
template <std::size_t MIN, std::size_t N, std::size_t... I>
struct range_builder : public range_builder<MIN, N - 1, N - 1, I...> {
};
} //namespace implem
template <std::size_t MIN, std::size_t MAX>
using index_range = typename implem::range_builder<MIN, MAX>::type;
} //namespace bt
} //namespace vwr
#endif

View file

@ -0,0 +1,364 @@
/*
* Copyright 2015 Michele "King_DuckZ" Santullo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef id1F562E68E5184552A7E8C9270B016692
#define id1F562E68E5184552A7E8C9270B016692
#include "vectorwrapper/has_method.hpp"
#include "vectorwrapper/sequence_bt.hpp"
#include <cstddef>
#include <ciso646>
#include <type_traits>
#include <array>
#include <cassert>
namespace vwr {
template <typename V>
struct VectorWrapperInfo;
template <typename V, std::size_t S=VectorWrapperInfo<V>::dimensions>
class Vec;
namespace implem {
define_has_typedef(lower_vector_type, LowerVec);
define_has_typedef(higher_vector_type, HigherVec);
define_has_enum(vector_x, VectorX);
define_has_method(get_at, GetAt);
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, typename U, std::size_t TS=VectorWrapperInfo<T>::dimensions, std::size_t US=VectorWrapperInfo<T>::dimensions> struct have_same_offsets {
enum { value = false };
};
template <typename T, typename U> struct have_same_offsets<T, U, 1, 1> {
enum {
value = (VectorWrapperInfo<T>::offset_x == VectorWrapperInfo<U>::offset_x)
};
};
template <typename T, typename U> struct have_same_offsets<T, U, 2, 2> {
enum {
value = (VectorWrapperInfo<T>::offset_x == VectorWrapperInfo<U>::offset_x) and
(VectorWrapperInfo<T>::offset_y == VectorWrapperInfo<U>::offset_y)
};
};
template <typename T, typename U> struct have_same_offsets<T, U, 3, 3> {
enum {
value = (VectorWrapperInfo<T>::offset_x == VectorWrapperInfo<U>::offset_x) and
(VectorWrapperInfo<T>::offset_y == VectorWrapperInfo<U>::offset_y) and
(VectorWrapperInfo<T>::offset_z == VectorWrapperInfo<U>::offset_z)
};
};
template <typename T, typename U> struct have_same_offsets<T, U, 4, 4> {
enum {
value = (VectorWrapperInfo<T>::offset_x == VectorWrapperInfo<U>::offset_x) and
(VectorWrapperInfo<T>::offset_y == VectorWrapperInfo<U>::offset_y) and
(VectorWrapperInfo<T>::offset_z == VectorWrapperInfo<U>::offset_z) and
(VectorWrapperInfo<T>::offset_w == VectorWrapperInfo<U>::offset_w)
};
};
template <typename T, typename U>
struct have_same_layout {
enum {
value =
HasVectorXEnum<T>::value and HasVectorXEnum<U>::value and
VectorWrapperInfo<T>::dimensions == VectorWrapperInfo<U>::dimensions and
have_same_offsets<T, U>::value;
};
};
template <typename V> struct is_vec {
enum { value = false };
};
template <typename V> struct is_vec<Vec<V>> {
enum { value = true };
};
template <typename V>
class VecBase {
friend Vec<V>& assign_same_type<V> ( Vec<V>& parLeft, const Vec<V>& parRight );
public:
typedef V vector_type;
typedef typename VectorWrapperInfo<V>::scalar_type scalar_type;
enum {
dimensions = VectorWrapperInfo<V>::dimensions
};
VecBase ( void ) = default;
explicit VecBase ( scalar_type parInit );
explicit VecBase ( const vector_type& parInit );
template <typename... Args>
VecBase ( scalar_type parX, scalar_type parY, Args... parArgs );
~VecBase ( void ) = default;
scalar_type& operator[] ( std::size_t parIndex );
scalar_type& operator[] ( int parIndex );
const scalar_type& operator[] ( std::size_t parIndex ) const;
const scalar_type& operator[] ( int parIndex ) const;
vector_type& data ( void ) { return m_wrapped; }
const vector_type& data ( void ) const { return m_wrapped; }
template <typename V2>
const typename std::enable_if<is_vec<V2>::value and have_same_layout<V, typename V2::vector_type>::value, V2>::type& cast ( void ) const;
template <typename V2>
typename std::enable_if<is_vec<V2>::value and have_same_layout<V, typename V2::vector_type>::value, V2>::type& cast ( void );
template <typename V2> VecBase& operator+= ( const VecBase<V2>& parOther );
template <typename V2> VecBase& operator-= ( const VecBase<V2>& parOther );
template <typename V2> VecBase& operator*= ( const VecBase<V2>& parOther );
template <typename V2> VecBase& operator/= ( const VecBase<V2>& parOther );
private:
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>
offsets_array_wrapper ( const bt::index_seq<I...>& );
const std::array<unsigned int, S> offsets;
};
template <typename T, bool=HasVectorXEnum<VectorWrapperInfo<T>>::value and std::is_standard_layout<typename VectorWrapperInfo<T>::vector_type>::value>
class VecGetter;
template <typename T>
struct VecGetter<T, true> {
static typename VectorWrapperInfo<T>::scalar_type& get_at ( typename VectorWrapperInfo<T>::vector_type& parVec, std::size_t parIndex );
};
template <typename T>
struct VecGetter<T, false> {
private:
static_assert(HasGetAtMethod<VectorWrapperInfo<T>>::value, "You must provide a get_at() static method for this vector_type");
typedef decltype(&VectorWrapperInfo<T>::get_at) get_at_func;
static_assert(not std::is_rvalue_reference<typename std::result_of<get_at_func>::type>::value, "rvalue ref return types not implemented");
static_assert(std::is_lvalue_reference<typename std::result_of<get_at_func>::type>::value, "Read-only vectors not implemented");
public:
static typename VectorWrapperInfo<T>::scalar_type& get_at ( typename VectorWrapperInfo<T>::vector_type& parVec, std::size_t parIndex );
};
template <typename V, bool Enabled> struct Vec2Promotion;
template <typename V> struct Vec2Promotion<V, false> {};
template <typename V> struct Vec2Promotion<V, true> {
typedef Vec<typename VectorWrapperInfo<V>::higher_vector_type> higher_vector_type;
typedef typename VectorWrapperInfo<V>::scalar_type scalar_type;
static_assert(VectorWrapperInfo<typename VectorWrapperInfo<V>::higher_vector_type>::dimensions == 3, "Wrong promoted vector type");
higher_vector_type xy1 ( void ) const { return xyz(scalar_type(1)); }
higher_vector_type xy0 ( void ) const { return xyz(scalar_type(0)); }
higher_vector_type xyz ( const scalar_type& parZ ) const;
};
template <typename V, bool Enabled> struct Vec3Promotion;
template <typename V> struct Vec3Promotion<V, false> {};
template <typename V> struct Vec3Promotion<V, true> {
typedef Vec<typename VectorWrapperInfo<V>::higher_vector_type> higher_vector_type;
typedef typename VectorWrapperInfo<V>::scalar_type scalar_type;
static_assert(VectorWrapperInfo<typename VectorWrapperInfo<V>::higher_vector_type>::dimensions == 4, "Wrong promoted vector type");
higher_vector_type xyz1 ( void ) const { return xyzw(scalar_type(1)); }
higher_vector_type xyz0 ( void ) const { return xyzw(scalar_type(0)); }
higher_vector_type xyzw ( const scalar_type& parW ) const;
};
template <typename V, bool Enabled> struct Vec3Demotion;
template <typename V> struct Vec3Demotion<V, false> : Vec3Promotion<V, HasHigherVecTypedef<V>::value> {};
template <typename V> struct Vec3Demotion<V, true> : Vec3Promotion<V, HasHigherVecTypedef<V>::value> {
typedef Vec<typename VectorWrapperInfo<V>::lower_vector_type> lower_vector_type;
typedef typename VectorWrapperInfo<V>::scalar_type scalar_type;
static_assert(VectorWrapperInfo<typename VectorWrapperInfo<V>::lower_vector_type>::dimensions == 2, "Wrong demoted vector type");
lower_vector_type xy ( void ) const;
lower_vector_type xz ( void ) const;
lower_vector_type yz ( void ) const;
};
template <typename V, std::size_t D>
struct VecAccessors;
//Workaround for visual studio - VecAccessors<V, 3> should inherit from
//both Vec3Promotion and Vec3Demotion, but when I do that, sizeof(Vec)
//is wrong. I had to linearize the inheritance hierarchy so that the
//sizeof(Vec<V>) == sizeof(V) condition is verified.
template <typename V>
struct VecAccessors<V, 3> : Vec3Demotion<V, HasLowerVecTypedef<VectorWrapperInfo<V>>::value> {
typedef typename VectorWrapperInfo<V>::scalar_type scalar_type;
const Vec<V>& xyz ( void ) const { return *static_cast<const Vec<V>*>(this); }
const scalar_type& x ( void ) const;
const scalar_type& y ( void ) const;
const scalar_type& z ( void ) const;
scalar_type& x ( void );
scalar_type& y ( void );
scalar_type& z ( void );
};
template <typename V>
struct VecAccessors<V, 2> : Vec2Promotion<V, HasHigherVecTypedef<VectorWrapperInfo<V>>::value> {
typedef typename VectorWrapperInfo<V>::scalar_type scalar_type;
const Vec<V>& xy ( void ) const { return *static_cast<const Vec<V>*>(this); }
const scalar_type& x ( void ) const;
const scalar_type& y ( void ) const;
scalar_type& x ( void );
scalar_type& y ( void );
};
} //namespace implem
template <typename V, std::size_t S>
class Vec : public implem::VecBase<V> {
public:
enum {
dimensions = S
};
};
template <typename V>
class Vec<V, 1> : public implem::VecBase<V> {
typedef typename implem::VecBase<V>::vector_type vector_type;
typedef typename implem::VecBase<V>::scalar_type scalar_type;
public:
enum {
dimensions = 1
};
static const Vec<V, 1> unit_x;
Vec ( void ) = default;
Vec ( const Vec& ) = default;
explicit Vec ( const vector_type& parIn ) : implem::VecBase<V>(parIn) { }
explicit Vec ( const scalar_type parX ) : implem::VecBase<V>(parX) { }
template <typename V2> Vec ( const Vec<V2, dimensions>& parOther ) { implem::assign(*this, parOther); }
scalar_type& x ( void ) { return (*this)[0]; }
const scalar_type& x ( void ) const { return (*this)[0]; }
Vec& operator= ( const Vec& parOther ) { return implem::assign_same_type(*this, parOther); }
template <typename V2>
Vec& operator= ( const Vec<V2, dimensions>& parOther ) { return implem::assign(*this, parOther); }
};
template <typename V>
class Vec<V, 2> : public implem::VecBase<V>, public implem::VecAccessors<V, 2> {
static_assert(std::is_standard_layout<implem::VecBase<V>>::value, "Base class must be a standard layout type");
static_assert(std::is_standard_layout<implem::VecAccessors<V, 2>>::value, "Base class must be a standard layout type");
typedef typename implem::VecBase<V>::scalar_type scalar_type;
typedef typename implem::VecBase<V>::vector_type vector_type;
public:
enum {
dimensions = 2
};
static const Vec<V, 2> unit_x;
static const Vec<V, 2> unit_y;
Vec ( void ) = default;
Vec ( const Vec& ) = default;
explicit Vec ( const vector_type& parIn ) : implem::VecBase<V>(parIn) { }
explicit Vec ( const scalar_type parX ) : implem::VecBase<V>(parX) { }
Vec ( scalar_type parX, scalar_type parY ) : implem::VecBase<V>(parX, parY) { }
template <typename V2> Vec ( const Vec<V2, dimensions>& parOther ) { implem::assign(*this, parOther); }
Vec& operator= ( const Vec& parOther ) { return implem::assign_same_type(*this, parOther); }
template <typename V2>
Vec& operator= ( const Vec<V2, dimensions>& parOther ) { return implem::assign(*this, parOther); }
Vec& operator= ( const vector_type& parOther ) { this->data() = parOther; return *this; }
};
template <typename V>
class Vec<V, 3> : public implem::VecBase<V>, public implem::VecAccessors<V, 3> {
static_assert(std::is_standard_layout<implem::VecBase<V>>::value, "Base class must be a standard layout type");
static_assert(std::is_standard_layout<implem::VecAccessors<V, 3>>::value, "Base class must be a standard layout type");
typedef typename implem::VecBase<V>::scalar_type scalar_type;
typedef typename implem::VecBase<V>::vector_type vector_type;
public:
enum {
dimensions = 3
};
static const Vec<V, 3> unit_x;
static const Vec<V, 3> unit_y;
static const Vec<V, 3> unit_z;
Vec ( void ) = default;
Vec ( const Vec& ) = default;
explicit Vec ( const vector_type& parIn ) : implem::VecBase<V>(parIn) { }
explicit Vec ( const scalar_type parX ) : implem::VecBase<V>(parX) { }
Vec ( scalar_type parX, scalar_type parY, scalar_type parZ ) : implem::VecBase<V>(parX, parY, parZ) { }
template <typename V2> Vec ( const Vec<V2, dimensions>& parOther ) { implem::assign(*this, parOther); }
Vec& operator= ( const Vec& parOther ) { return implem::assign_same_type(*this, parOther); }
template <typename V2>
Vec& operator= ( const Vec<V2, dimensions>& parOther ) { return implem::assign(*this, parOther); }
Vec& operator= ( const vector_type& parOther ) { this->data() = parOther; return *this; }
};
template <typename V>
Vec<V> mk_vec ( const V& parVec );
template <typename V1, typename V2>
bool operator== ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
template <typename V1, typename V2>
bool operator< ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
template <typename V>
bool operator== ( const Vec<V>& parLeft, const typename VectorWrapperInfo<V>::scalar_type& parRight );
template <typename V>
bool operator< ( const Vec<V>& parLeft, const typename VectorWrapperInfo<V>::scalar_type& parRight );
template <typename V1, typename T>
bool operator> ( const Vec<V1>& parLeft, const T& parRight );
template <typename V1, typename T>
bool operator<= ( const Vec<V1>& parLeft, const T& parRight );
template <typename V1, typename T>
bool operator>= ( const Vec<V1>& parLeft, const T& parRight );
template <typename V1, typename T>
bool operator!= ( const Vec<V1>& parLeft, const T& parRight );
template <typename V1, typename V2>
Vec<typename std::common_type<V1, V2>::type> operator+ ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
template <typename V1, typename V2>
Vec<typename std::common_type<V1, V2>::type> operator- ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
template <typename V1, typename V2>
Vec<typename std::common_type<V1, V2>::type> operator* ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
template <typename V1, typename V2>
Vec<typename std::common_type<V1, V2>::type> operator/ ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
} //namespace vwr
#include "vectorwrapper/vectorwrapper.inl"
#endif

View file

@ -0,0 +1,341 @@
/*
* Copyright 2015 Michele "King_DuckZ" Santullo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace vwr {
namespace implem {
template <typename V>
VecBase<V>::VecBase (scalar_type parInit) :
m_wrapped(parInit)
{
}
template <typename V>
VecBase<V>::VecBase (const vector_type& parInit) :
m_wrapped(parInit)
{
}
template <typename V>
template <typename... Args>
VecBase<V>::VecBase (scalar_type parX, scalar_type parY, Args... parArgs) :
m_wrapped(parX, parY, parArgs...)
{
static_assert(2 + sizeof...(Args) == dimensions, "Wrong number of parameters received");
}
template <typename V>
auto VecBase<V>::operator[] (std::size_t parIndex) -> scalar_type& {
return VecGetter<V>::get_at(m_wrapped, parIndex);
}
template <typename V>
auto VecBase<V>::operator[] (int parIndex) -> scalar_type& {
assert(parIndex >= 0);
return VecGetter<V>::get_at(m_wrapped, static_cast<std::size_t>(parIndex));
}
template <typename V>
auto VecBase<V>::operator[] (std::size_t parIndex) const -> const scalar_type& {
return VecGetter<V>::get_at(const_cast<vector_type&>(m_wrapped), parIndex);
}
template <typename V>
auto VecBase<V>::operator[] (int parIndex) const -> const scalar_type& {
assert(parIndex >= 0);
return VecGetter<V>::get_at(const_cast<vector_type&>(m_wrapped), static_cast<std::size_t>(parIndex));
}
template <typename V>
template <typename V2>
const typename std::enable_if<is_vec<V2>::value and have_same_layout<V, typename V2::vector_type>::value, V2>::type& VecBase<V>::cast() const {
return *reinterpret_cast<const V2*>(this);
}
template <typename V>
template <typename V2>
typename std::enable_if<is_vec<V2>::value and have_same_layout<V, typename V2::vector_type>::value, V2>::type& VecBase<V>::cast() {
return *reinterpret_cast<V2*>(this);
}
template <typename V>
template <typename V2>
VecBase<V>& VecBase<V>::operator+= (const VecBase<V2>& parOther) {
static_assert(VectorWrapperInfo<V>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
for (int z = 0; z < VectorWrapperInfo<V>::dimensions; ++z) {
(*this)[z] += parOther[z];
}
return *this;
}
template <typename V>
template <typename V2>
VecBase<V>& VecBase<V>::operator-= (const VecBase<V2>& parOther) {
static_assert(VectorWrapperInfo<V>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
for (int z = 0; z < VectorWrapperInfo<V>::dimensions; ++z) {
(*this)[z] -= parOther[z];
}
return *this;
}
template <typename V>
template <typename V2>
VecBase<V>& VecBase<V>::operator*= (const VecBase<V2>& parOther) {
static_assert(VectorWrapperInfo<V>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
for (int z = 0; z < VectorWrapperInfo<V>::dimensions; ++z) {
(*this)[z] *= parOther[z];
}
return *this;
}
template <typename V>
template <typename V2>
VecBase<V>& VecBase<V>::operator/= (const VecBase<V2>& parOther) {
static_assert(VectorWrapperInfo<V>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
for (int z = 0; z < VectorWrapperInfo<V>::dimensions; ++z) {
(*this)[z] /= parOther[z];
}
return *this;
}
template <typename T>
typename VectorWrapperInfo<T>::scalar_type& VecGetter<T, true>::get_at (typename VectorWrapperInfo<T>::vector_type& parVec, std::size_t parIndex) {
assert(parIndex < VectorWrapperInfo<T>::dimensions);
typedef typename VectorWrapperInfo<T>::vector_type vector_type;
typedef typename VectorWrapperInfo<T>::scalar_type scalar_type;
typedef scalar_type (vector_type::*coordinate_property);
static_assert(std::is_standard_layout<vector_type>::value, "Can't use this function with this vector_type");
const offsets_array_wrapper<T> oaw((bt::index_range<0, VectorWrapperInfo<T>::dimensions>()));
return *reinterpret_cast<scalar_type*>(reinterpret_cast<char*>(&parVec) + oaw.offsets[parIndex]);
}
template <typename T>
typename VectorWrapperInfo<T>::scalar_type& VecGetter<T, false>::get_at (typename VectorWrapperInfo<T>::vector_type& parVec, std::size_t parIndex) {
assert(parIndex < VectorWrapperInfo<T>::dimensions);
return VectorWrapperInfo<T>::get_at(parVec, parIndex);
}
template <typename V1, typename V2, std::size_t D>
inline Vec<V1>& assign (Vec<V1, D>& parLeft, const Vec<V2, D>& parRight) {
for (std::size_t z = 0; z < D; ++z) {
parLeft[z] = parRight[z];
}
return parLeft;
}
template <typename V>
Vec<V>& assign_same_type (Vec<V>& parLeft, const Vec<V>& parRight) {
parLeft.m_wrapped = parRight.m_wrapped;
return parLeft;
}
template <typename V>
auto Vec3Demotion<V, true>::xy() const -> lower_vector_type {
auto& this_vec = *static_cast<const Vec<V>*>(this);
return lower_vector_type(this_vec[0], this_vec[1]);
}
template <typename V>
auto Vec3Demotion<V, true>::xz() const -> lower_vector_type {
auto& this_vec = *static_cast<const Vec<V>*>(this);
return lower_vector_type(this_vec[0], this_vec[2]);
}
template <typename V>
auto Vec3Demotion<V, true>::yz() const -> lower_vector_type {
auto& this_vec = *static_cast<const Vec<V>*>(this);
return lower_vector_type(this_vec[1], this_vec[2]);
}
template <typename V>
auto Vec2Promotion<V, true>::xyz (const scalar_type& parZ) const -> higher_vector_type {
auto& this_vec = *static_cast<const Vec<V>*>(this);
return higher_vector_type(this_vec[0], this_vec[1], parZ);
}
template <typename V>
auto Vec3Promotion<V, true>::xyzw (const scalar_type& parW) const -> higher_vector_type {
auto& this_vec = *static_cast<const Vec<V>*>(this);
return higher_vector_type(this_vec[0], this_vec[1], this_vec[2], parW);
}
template <typename V>
auto VecAccessors<V, 2>::x() -> scalar_type& {
auto& this_vec = *static_cast<Vec<V>*>(this);
return this_vec[0];
}
template <typename V>
auto VecAccessors<V, 2>::x() const -> const scalar_type& {
const auto& this_vec = *static_cast<const Vec<V>*>(this);
return this_vec[0];
}
template <typename V>
auto VecAccessors<V, 2>::y() -> scalar_type& {
auto& this_vec = *static_cast<Vec<V>*>(this);
return this_vec[1];
}
template <typename V>
auto VecAccessors<V, 2>::y() const -> const scalar_type& {
const auto& this_vec = *static_cast<const Vec<V>*>(this);
return this_vec[1];
}
template <typename V>
auto VecAccessors<V, 3>::x() -> scalar_type& {
auto& this_vec = *static_cast<Vec<V>*>(this);
return this_vec[0];
}
template <typename V>
auto VecAccessors<V, 3>::x() const -> const scalar_type& {
const auto& this_vec = *static_cast<const Vec<V>*>(this);
return this_vec[0];
}
template <typename V>
auto VecAccessors<V, 3>::y() -> scalar_type& {
auto& this_vec = *static_cast<Vec<V>*>(this);
return this_vec[1];
}
template <typename V>
auto VecAccessors<V, 3>::y() const -> const scalar_type& {
const auto& this_vec = *static_cast<const Vec<V>*>(this);
return this_vec[1];
}
template <typename V>
auto VecAccessors<V, 3>::z() -> scalar_type& {
auto& this_vec = *static_cast<Vec<V>*>(this);
return this_vec[2];
}
template <typename V>
auto VecAccessors<V, 3>::z() const -> const scalar_type& {
const auto& this_vec = *static_cast<const Vec<V>*>(this);
return this_vec[2];
}
template <typename T, std::size_t S>
template <std::size_t... I>
offsets_array_wrapper<T, S>::offsets_array_wrapper (const bt::index_seq<I...>&) :
offsets({get_offset_enum_from_index<T, I>::value...})
{
static_assert(sizeof...(I) == S, "Bug?");
}
} //namespace implem
template <typename V> const Vec<V, 1> Vec<V, 1>::unit_x(scalar_type(1));
template <typename V> const Vec<V, 2> Vec<V, 2>::unit_x(scalar_type(1), scalar_type(0));
template <typename V> const Vec<V, 2> Vec<V, 2>::unit_y(scalar_type(0), scalar_type(1));
template <typename V> const Vec<V, 3> Vec<V, 3>::unit_x(scalar_type(1), scalar_type(0), scalar_type(0));
template <typename V> const Vec<V, 3> Vec<V, 3>::unit_y(scalar_type(0), scalar_type(1), scalar_type(0));
template <typename V> const Vec<V, 3> Vec<V, 3>::unit_z(scalar_type(0), scalar_type(0), scalar_type(1));
template <typename V>
Vec<V> mk_vec (const V& parVec) {
return Vec<V>(parVec);
}
template <typename V1, typename V2>
inline bool operator== (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
static_assert(VectorWrapperInfo<V1>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
bool retval = true;
for (int z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
retval &= (parLeft[z] == parRight[z]);
}
return retval;
}
template <typename V1, typename V2>
inline bool operator< (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
static_assert(VectorWrapperInfo<V1>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
bool retval = true;
for (int z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
retval &= (parLeft[z] < parRight[z]);
}
return retval;
}
template <typename V>
inline bool operator== (const Vec<V>& parLeft, const typename VectorWrapperInfo<V>::scalar_type& parRight) {
bool retval = true;
for (int z = 0; z < VectorWrapperInfo<V>::dimensions; ++z) {
retval &= (parLeft[z] == parRight);
}
return retval;
}
template <typename V>
inline bool operator< ( const Vec<V>& parLeft, const typename VectorWrapperInfo<V>::scalar_type& parRight) {
bool retval = true;
for (int z = 0; z < VectorWrapperInfo<V>::dimensions; ++z) {
retval &= (parLeft[z] < parRight);
}
return retval;
}
template <typename V1, typename T>
inline bool operator> (const Vec<V1>& parLeft, const T& parRight) {
return not (parLeft < parRight) and not (parLeft == parRight);
}
template <typename V1, typename T>
inline bool operator<= (const Vec<V1>& parLeft, const T& parRight) {
return (parLeft < parRight) or (parLeft == parRight);
}
template <typename V1, typename T>
inline bool operator>= (const Vec<V1>& parLeft, const T& parRight) {
return not (parLeft < parRight);
}
template <typename V1, typename T>
inline bool operator!= (const Vec<V1>& parLeft, const T& parRight) {
return not (parLeft == parRight);
}
template <typename V1, typename V2>
inline Vec<typename std::common_type<V1, V2>::type> operator+ (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
static_assert(VectorWrapperInfo<V1>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
Vec<typename std::common_type<V1, V2>::type> retval;
for (int z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
retval[z] = parLeft[z] + parRight[z];
}
return retval;
}
template <typename V1, typename V2>
inline Vec<typename std::common_type<V1, V2>::type> operator- (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
static_assert(VectorWrapperInfo<V1>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
Vec<typename std::common_type<V1, V2>::type> retval;
for (int z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
retval[z] = parLeft[z] - parRight[z];
}
return retval;
}
template <typename V1, typename V2>
inline Vec<typename std::common_type<V1, V2>::type> operator* (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
static_assert(VectorWrapperInfo<V1>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
Vec<typename std::common_type<V1, V2>::type> retval;
for (int z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
retval[z] = parLeft[z] * parRight[z];
}
return retval;
}
template <typename V1, typename V2>
inline Vec<typename std::common_type<V1, V2>::type> operator/ (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
static_assert(VectorWrapperInfo<V1>::dimensions == VectorWrapperInfo<V2>::dimensions, "Dimensions mismatch");
Vec<typename std::common_type<V1, V2>::type> retval;
for (int z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
retval[z] = parLeft[z] / parRight[z];
}
return retval;
}
} //namespace vwr