Replace cloonel jump vector with vectorwrapper.

It's missing operators, so the build is broken.
This commit is contained in:
Michele Santullo 2015-07-30 16:12:12 +02:00
parent b3bf60fff2
commit cab7c296f1
11 changed files with 1403 additions and 3 deletions

View File

@ -22,6 +22,7 @@ target_include_directories(${PROJECT_NAME} SYSTEM
target_include_directories(${PROJECT_NAME}
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/lib/sprout
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/lib/vectorwrapper/include
)
#add_subdirectory(lib/sprout)

View File

@ -0,0 +1,58 @@
#ifndef id134A9223C9F7403B9BC600DCAC4875BC
#define id134A9223C9F7403B9BC600DCAC4875BC
#include "doorkeeper/implem/configuration.h"
#include "vectorwrapper/vectorwrapper.hpp"
#include <cstdint>
#include <cstddef>
#include <array>
#if defined(WITH_VECTOR_IOSTREAM)
# include <iostream>
#endif
namespace vwr {
template <std::size_t D>
struct VectorWrapperInfo<std::array<dk::CoordinateScalarType, D>> {
enum {
dimensions = D
};
typedef dk::CoordinateScalarType scalar_type;
typedef std::array<dk::CoordinateScalarType, D> vector_type;
typedef std::array<dk::CoordinateScalarType, D+1> higher_vector_type;
typedef std::array<dk::CoordinateScalarType, D-1> lower_vector_type;
static scalar_type& get_at (std::size_t parIndex, vector_type& parVector) {
return parVector[parIndex];
}
};
template <>
struct VectorWrapperInfo<std::array<dk::CoordinateScalarType, 1>> {
enum {
dimensions = 1
};
typedef dk::CoordinateScalarType scalar_type;
typedef std::array<dk::CoordinateScalarType, 1> vector_type;
typedef std::array<dk::CoordinateScalarType, 2> higher_vector_type;
static scalar_type& get_at (std::size_t, vector_type& parVector) {
return parVector[0];
}
};
#if defined(WITH_VECTOR_IOSTREAM)
template <typename V>
std::ostream& operator<< (std::ostream& parStream, const vwr::Vec<V>& parVec) {
const int dim = vwr::Vec<V>::dimensions;
parStream << '<';
for (int z = 0; z < dim - 1; ++z) {
parStream << parVec[z] << ", ";
}
parStream << parVec[dim - 1] << '>';
return parStream;
}
#endif
} //namespace vwr
#endif

View File

@ -9,7 +9,7 @@
namespace dk {
template <uint32_t D>
using Vector = cloonel::Vector<CoordinateScalarType, D>;
using Vector = vwr::Vec<std::array<CoordinateScalarType, D>>;
} //namespace dk
#endif

202
lib/vectorwrapper/LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

184
lib/vectorwrapper/README.md Normal file
View File

@ -0,0 +1,184 @@
# Vector Wrapper #
![Image Build status](https://travis-ci.org/KingDuckZ/vectorwrapper.svg?branch=master)
## Motivation ##
### Short version ###
A vector wrapper is mainly useful if used as an adapter between vectors from different libraries. It basically removes the need to explicitly construct a vector of type B when you have a vector of type A.
It's roughly equivalent to using a reinterpret_cast on your vectors, but the code tries really hard to make sure the cast is valid in all cases, wrapping it nicely behind a clean interface. Implicit constructors also allow to convert easily from one type to the other.
### Long version ###
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.
## Practical example ##
So what's the real benefit of using `Vec<Ogre::Vector3>` instead of just `Ogre::Vector3`, for example? Can't I just assign/cast manually?
Sure you can, but it's more verbose. And as your codebase grows, you will have more and more boundaries where you have to convert from one vector to the other just to call a function from this or that library. Check test/unit/example.cpp for a head-to-head comparison of the two methods.
## 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 ###
A must have some fundamental properties before it can be casted to B:
* casting won't result in a misaligned object
* the casted object won't go past the memory reserved to the original object (in other words sizeof(B) <= sizeof(A) - offset of the first coordinate in A)
* B must be a standard layout struct
* B has no data before the first coordinate
* Coordinates in B appear in the same order and at the same offsets as they appear in A
* B is exactly as large as dimensions * sizeof(scalar_type), but you can disable this constraint by setting cast_ignore_trailing_properties=1 in B's VectorWrapperInfo
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 <cstddef>
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;
static 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;
static 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;
static 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 = offsetof(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 = offsetof(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)
* I haven't profiled this code yet (please be patient), but while I don't want it to slow your program down, I know it won't be comparable to any super optimized vector library. This is not a vector library to begin with. Supporting SSE would be nice, but there is no guarantee the wrapped type has been created with SSE and optimizations in mind. Writing functions for both cases (SIMD-ready structures and scalar structures) would essentially require implementing every function twice. I think it's just a better idea to take an already made vector library and use vectorwrapper as it was intended - to wrap the vector classes that come from that library.

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 TrueType has_typedef ( const typename C::typedef_name* ); \
template <typename C> static FalseType has_typedef ( ... ); \
public: \
enum { value = sizeof(has_typedef<T>(nullptr)) == 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 ( decltype(C::enum_name)* ); \
template <typename C> static FalseType has_enum ( ... ); \
public:\
enum { value = sizeof(has_enum<T>(nullptr)) == 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,38 @@
/*
* 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 id8949C80C36BA42CABC49EA4C1DB54BC7
#define id8949C80C36BA42CABC49EA4C1DB54BC7
#include "vectorwrapper.hpp"
#include <type_traits>
#include <cstddef>
namespace vwr {
template <typename V1, typename V2, std::size_t S>
typename std::common_type<typename Vec<V1>::scalar_type, typename Vec<V2>::scalar_type>::type dot ( const Vec<V1, S>& parLeft, const Vec<V2, S>& parRight );
template <typename V1, typename V2, std::size_t S>
inline typename std::common_type<typename Vec<V1>::scalar_type, typename Vec<V2>::scalar_type>::type dot (const Vec<V1, S>& parLeft, const Vec<V2, S>& parRight) {
auto retval = parLeft.x() * parRight.x();
for (int z = 1; z < S; ++z) {
retval += parLeft[z] * parRight[z];
}
return retval;
}
} //namespace vwr
#endif

View File

@ -0,0 +1,416 @@
/*
* 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(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 S=(
static_cast<int>(VectorWrapperInfo<T>::dimensions) < static_cast<int>(VectorWrapperInfo<U>::dimensions) ?
static_cast<int>(VectorWrapperInfo<T>::dimensions)
:
static_cast<int>(VectorWrapperInfo<U>::dimensions)
)
> struct have_compat_offsets;
template <typename T, typename U> struct have_compat_offsets<T, U, 1> {
enum {
value = true
};
};
template <typename T, typename U> struct have_compat_offsets<T, U, 2> {
enum {
value =
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> {
enum {
value =
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> {
enum {
value =
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
};
};
template <typename T, typename U>
struct have_compat_layout {
enum {
value =
HasOffsetXEnum<VectorWrapperInfo<T>>::value and
HasOffsetXEnum<VectorWrapperInfo<U>>::value and
have_compat_offsets<T, U>::value
};
};
template <typename V> struct is_vec {
enum { value = false };
};
template <typename V> struct is_vec<Vec<V>> {
typedef V vector_type;
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;
template <typename T>
explicit 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=false );
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, V2>::type& cast ( void ) const;
template <typename V2>
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 );
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 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=HasOffsetXEnum<VectorWrapperInfo<T>>::value and std::is_standard_layout<T>::value>
class VecGetter;
template <typename T>
struct VecGetter<T, true> {
static typename VectorWrapperInfo<T>::scalar_type& get_at ( T& 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 typename VectorWrapperInfo<T>::scalar_type scalar_type;
using return_type = decltype(std::declval<VectorWrapperInfo<T>>().get_at(std::declval<std::size_t>(), std::declval<T&>()));
static_assert(not std::is_rvalue_reference<return_type>::value, "rvalue ref return types not implemented");
static_assert(std::is_lvalue_reference<return_type>::value, "Read-only vectors not implemented");
public:
static typename VectorWrapperInfo<T>::scalar_type& get_at ( T& parVec, std::size_t parIndex );
};
template <typename V, bool Enabled> struct Vec1Promotion;
template <typename V> struct Vec1Promotion<V, false> { };
template <typename V> struct Vec1Promotion<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 == 2, "Wrong promoted vector type");
higher_vector_type x1 ( void ) const { return xn(scalar_type(1)); }
higher_vector_type x0 ( void ) const { return xn(scalar_type(0)); }
higher_vector_type xn ( const scalar_type& parN ) const;
higher_vector_type nx ( const scalar_type& parN ) const;
};
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 xyn(scalar_type(1)); }
higher_vector_type xy0 ( void ) const { return xyn(scalar_type(0)); }
higher_vector_type xyn ( 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 );
};
template <typename V>
struct VecAccessors<V, 1> : Vec1Promotion<V, HasHigherVecTypedef<VectorWrapperInfo<V>>::value> {
typedef typename VectorWrapperInfo<V>::scalar_type scalar_type;
scalar_type& x ( void );
const scalar_type& x ( void ) const;
};
} //namespace implem
template <typename V, std::size_t S>
class Vec : public implem::VecBase<V> {
public:
enum {
dimensions = S
};
template <typename... Args>
Vec ( Args... parArgs ) : implem::VecBase<V>(std::forward<Args>(parArgs)...)
{
}
};
template <typename V>
class Vec<V, 1> : public implem::VecBase<V>, public implem::VecAccessors<V, 1> {
static_assert(std::is_standard_layout<implem::VecBase<V>>::value, "Base class must be a standard layout type");
public:
typedef typename implem::VecBase<V>::vector_type vector_type;
typedef typename implem::VecBase<V>::scalar_type scalar_type;
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) { }
template <typename T>
explicit Vec ( const typename std::enable_if<std::is_same<T, scalar_type>::value and not std::is_same<scalar_type, vector_type>::value, T>::type& parX ) : implem::VecBase<V>(parX) { }
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); }
};
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");
public:
typedef typename implem::VecBase<V>::scalar_type scalar_type;
typedef typename implem::VecBase<V>::vector_type vector_type;
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");
public:
typedef typename implem::VecBase<V>::scalar_type scalar_type;
typedef typename implem::VecBase<V>::vector_type vector_type;
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,389 @@
/*
* 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 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) {
for (int z = 0; z < VectorWrapperInfo<V>::dimensions; ++z) {
VecGetter<V>::get_at(m_wrapped, z) = 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) {
static_assert(2 + sizeof...(Args) == dimensions, "Wrong number of parameters received");
VecGetter<V>::get_at(m_wrapped, 0) = parX;
VecGetter<V>::get_at(m_wrapped, 1) = parY;
const scalar_type args[sizeof...(Args)] = {parArgs...};
for (int z = 0; z < sizeof...(Args); ++z) {
VecGetter<V>::get_at(m_wrapped, z + 2) = args[z];
}
}
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, 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) * VectorWrapperInfo<typename is_vec<V2>::vector_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
);
}
template <typename V>
template <typename V2>
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>
template <typename V2>
VecBase<V>& VecBase<V>::operator+= (const VecBase<V2>& parOther) {
static_assert(static_cast<int>(VectorWrapperInfo<V>::dimensions) == static_cast<int>(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(static_cast<int>(VectorWrapperInfo<V>::dimensions) == static_cast<int>(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(static_cast<int>(VectorWrapperInfo<V>::dimensions) == static_cast<int>(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(static_cast<int>(VectorWrapperInfo<V>::dimensions) == static_cast<int>(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 (T& parVec, std::size_t parIndex) {
assert(parIndex < VectorWrapperInfo<T>::dimensions);
typedef T vector_type;
typedef typename VectorWrapperInfo<T>::scalar_type scalar_type;
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 (T& parVec, std::size_t parIndex) {
assert(parIndex < VectorWrapperInfo<T>::dimensions);
return VectorWrapperInfo<T>::get_at(parIndex, parVec);
}
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 Vec1Promotion<V, true>::xn (const scalar_type& parN) const -> higher_vector_type {
auto& this_vec = *static_cast<const Vec<V>*>(this);
return higher_vector_type(this_vec[0], parN);
}
template <typename V>
auto Vec1Promotion<V, true>::nx (const scalar_type& parN) const -> higher_vector_type {
auto& this_vec = *static_cast<const Vec<V>*>(this);
return higher_vector_type(parN, this_vec[0]);
}
template <typename V>
auto Vec2Promotion<V, true>::xyn (const scalar_type& parN) const -> higher_vector_type {
auto& this_vec = *static_cast<const Vec<V>*>(this);
return higher_vector_type(this_vec[0], this_vec[1], parN);
}
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, 1>::x() -> scalar_type& {
auto& this_vec = *static_cast<Vec<V>*>(this);
return this_vec[0];
}
template <typename V>
auto VecAccessors<V, 1>::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>::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(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(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(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(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(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(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(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(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(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(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(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(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

View File

@ -3,9 +3,10 @@
TEST(misc, vector) {
{
typedef dk::Vector<2> coords2;
typedef dk::Vector<2> coords2;
typedef dk::Vector<8> coords8;
{
const coords2 small(5, 6);
EXPECT_EQ(small.x(), 5);
EXPECT_EQ(small.y(), 6);
@ -29,4 +30,14 @@ TEST(misc, vector) {
EXPECT_FALSE(med2_a == med);
EXPECT_FALSE(med > med2_a);
}
{
const coords8 small(1, 2, 3, 4, 5, 6, 7, 8);
const coords8 big(small * 100);
for (int z = 0; z < coords8::Dimension; ++z) {
EXPECT_EQ(big[z], (z + 1) * 100);
}
EXPECT_LT(small, big);
}
}