From cab7c296f155ae31eec36d2c6fd3bdf8ffb369e5 Mon Sep 17 00:00:00 2001 From: Michele Santullo Date: Thu, 30 Jul 2015 16:12:12 +0200 Subject: [PATCH] Replace cloonel jump vector with vectorwrapper. It's missing operators, so the build is broken. --- CMakeLists.txt | 1 + include/doorkeeper/implem/vector.hpp | 58 +++ include/doorkeeper/primitivetypes.hpp | 2 +- lib/vectorwrapper/LICENSE | 202 +++++++++ lib/vectorwrapper/README.md | 184 ++++++++ .../include/vectorwrapper/has_method.hpp | 54 +++ .../include/vectorwrapper/sequence_bt.hpp | 47 ++ .../include/vectorwrapper/vectorfuncs.hpp | 38 ++ .../include/vectorwrapper/vectorwrapper.hpp | 416 ++++++++++++++++++ .../include/vectorwrapper/vectorwrapper.inl | 389 ++++++++++++++++ test/unit/vector.cpp | 15 +- 11 files changed, 1403 insertions(+), 3 deletions(-) create mode 100644 include/doorkeeper/implem/vector.hpp create mode 100644 lib/vectorwrapper/LICENSE create mode 100644 lib/vectorwrapper/README.md create mode 100644 lib/vectorwrapper/include/vectorwrapper/has_method.hpp create mode 100644 lib/vectorwrapper/include/vectorwrapper/sequence_bt.hpp create mode 100644 lib/vectorwrapper/include/vectorwrapper/vectorfuncs.hpp create mode 100644 lib/vectorwrapper/include/vectorwrapper/vectorwrapper.hpp create mode 100644 lib/vectorwrapper/include/vectorwrapper/vectorwrapper.inl diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d7db21..1f6a2da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/include/doorkeeper/implem/vector.hpp b/include/doorkeeper/implem/vector.hpp new file mode 100644 index 0000000..d5cd5fe --- /dev/null +++ b/include/doorkeeper/implem/vector.hpp @@ -0,0 +1,58 @@ +#ifndef id134A9223C9F7403B9BC600DCAC4875BC +#define id134A9223C9F7403B9BC600DCAC4875BC + +#include "doorkeeper/implem/configuration.h" +#include "vectorwrapper/vectorwrapper.hpp" +#include +#include +#include +#if defined(WITH_VECTOR_IOSTREAM) +# include +#endif + +namespace vwr { + template + struct VectorWrapperInfo> { + enum { + dimensions = D + }; + + typedef dk::CoordinateScalarType scalar_type; + typedef std::array vector_type; + typedef std::array higher_vector_type; + typedef std::array lower_vector_type; + + static scalar_type& get_at (std::size_t parIndex, vector_type& parVector) { + return parVector[parIndex]; + } + }; + template <> + struct VectorWrapperInfo> { + enum { + dimensions = 1 + }; + + typedef dk::CoordinateScalarType scalar_type; + typedef std::array vector_type; + typedef std::array higher_vector_type; + + static scalar_type& get_at (std::size_t, vector_type& parVector) { + return parVector[0]; + } + }; + +#if defined(WITH_VECTOR_IOSTREAM) + template + std::ostream& operator<< (std::ostream& parStream, const vwr::Vec& parVec) { + const int dim = vwr::Vec::dimensions; + parStream << '<'; + for (int z = 0; z < dim - 1; ++z) { + parStream << parVec[z] << ", "; + } + parStream << parVec[dim - 1] << '>'; + return parStream; + } +#endif +} //namespace vwr + +#endif diff --git a/include/doorkeeper/primitivetypes.hpp b/include/doorkeeper/primitivetypes.hpp index a053342..cc26481 100644 --- a/include/doorkeeper/primitivetypes.hpp +++ b/include/doorkeeper/primitivetypes.hpp @@ -9,7 +9,7 @@ namespace dk { template - using Vector = cloonel::Vector; + using Vector = vwr::Vec>; } //namespace dk #endif diff --git a/lib/vectorwrapper/LICENSE b/lib/vectorwrapper/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/lib/vectorwrapper/LICENSE @@ -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. + diff --git a/lib/vectorwrapper/README.md b/lib/vectorwrapper/README.md new file mode 100644 index 0000000..9863866 --- /dev/null +++ b/lib/vectorwrapper/README.md @@ -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` 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` as the wrapped type and forget how it's working under the hood. + +Unfortunately the fact that you use `Vec>` and `Vec` 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` from a `Vec`, 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` can optionally expose a `xy()` method that is equivalent to `Vec(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()` is only available when you define `offset_x` (see Usage). Either way, to cast (reinterpret_cast actually, be careful about the strict aliasing rule) you can just do the following: + + typedef Vec avec; + typedef Vec bvec; + + avec a(0); + + some_function(bvec(a)); //creates a temporary + some_function(a.cast()); //reinterpret_cast + +## Usage ## +In this example we will adapt `std::array` 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 + #include + + template <> + struct VectorWrapperInfo> { + 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 vector_type; + + //This will make the xy(), xz() and yz() methods available + typedef std::array 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> { + enum { + dimensions = 2 + }; + + typedef float scalar_type; + typedef std::array vector_type; + typedef std::array higher_vector_type; + typedef std::array 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 { + enum { + dimensions = 1 + }; + + typedef float scalar_type; + typedef float vector_type; + typedef std::array higher_vector_type; + + static scalar_type& get_at (size_t, vector_type& parVector) { + return parVector; + } + }; + + template <> + struct VectorWrapperInfo { + 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 { + 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> avec3; + typedef Vec> avec2; + typedef Vec avec1; + typedef Vec ovec3; + typedef Vec 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. diff --git a/lib/vectorwrapper/include/vectorwrapper/has_method.hpp b/lib/vectorwrapper/include/vectorwrapper/has_method.hpp new file mode 100644 index 0000000..d641771 --- /dev/null +++ b/lib/vectorwrapper/include/vectorwrapper/has_method.hpp @@ -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 \ + struct Has ## pretty_name ## Method { \ + private: \ + struct TrueType { int a[2]; }; \ + typedef int FalseType; \ + template static TrueType has_method ( decltype(&C::method_name) ); \ + template static FalseType has_method ( ... ); \ + public: \ + enum { value = sizeof(has_method(0)) == sizeof(TrueType) }; \ + } +#define define_has_typedef(typedef_name,pretty_name) \ + template \ + struct Has ## pretty_name ## Typedef { \ + private: \ + struct TrueType { int a[2]; }; \ + typedef int FalseType; \ + template static TrueType has_typedef ( const typename C::typedef_name* ); \ + template static FalseType has_typedef ( ... ); \ + public: \ + enum { value = sizeof(has_typedef(nullptr)) == sizeof(TrueType) }; \ + } +#define define_has_enum(enum_name,pretty_name) \ + template \ + struct Has ## pretty_name ## Enum { \ + private: \ + struct TrueType { int a[2]; }; \ + typedef int FalseType; \ + template static TrueType has_enum ( decltype(C::enum_name)* ); \ + template static FalseType has_enum ( ... ); \ + public:\ + enum { value = sizeof(has_enum(nullptr)) == sizeof(TrueType) }; \ + } + +#endif diff --git a/lib/vectorwrapper/include/vectorwrapper/sequence_bt.hpp b/lib/vectorwrapper/include/vectorwrapper/sequence_bt.hpp new file mode 100644 index 0000000..a887401 --- /dev/null +++ b/lib/vectorwrapper/include/vectorwrapper/sequence_bt.hpp @@ -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 + +namespace vwr { + namespace bt { + template + struct index_seq { + }; + + namespace implem { + template + struct range_builder; + + template + struct range_builder { + typedef index_seq type; + }; + + template + struct range_builder : public range_builder { + }; + } //namespace implem + + template + using index_range = typename implem::range_builder::type; + } //namespace bt +} //namespace vwr + +#endif diff --git a/lib/vectorwrapper/include/vectorwrapper/vectorfuncs.hpp b/lib/vectorwrapper/include/vectorwrapper/vectorfuncs.hpp new file mode 100644 index 0000000..04178ee --- /dev/null +++ b/lib/vectorwrapper/include/vectorwrapper/vectorfuncs.hpp @@ -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 +#include + +namespace vwr { + template + typename std::common_type::scalar_type, typename Vec::scalar_type>::type dot ( const Vec& parLeft, const Vec& parRight ); + + template + inline typename std::common_type::scalar_type, typename Vec::scalar_type>::type dot (const Vec& parLeft, const Vec& parRight) { + auto retval = parLeft.x() * parRight.x(); + for (int z = 1; z < S; ++z) { + retval += parLeft[z] * parRight[z]; + } + return retval; + } +} //namespace vwr + +#endif diff --git a/lib/vectorwrapper/include/vectorwrapper/vectorwrapper.hpp b/lib/vectorwrapper/include/vectorwrapper/vectorwrapper.hpp new file mode 100644 index 0000000..3bfc092 --- /dev/null +++ b/lib/vectorwrapper/include/vectorwrapper/vectorwrapper.hpp @@ -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 +#include +#include +#include +#include + +namespace vwr { + template + struct VectorWrapperInfo; + + template ::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 + Vec& assign ( Vec& parLeft, const Vec& parRight ); + template + Vec& assign_same_type ( Vec& parLeft, const Vec& parRight ); + + template struct get_offset_enum_from_index; + template struct get_offset_enum_from_index { + enum { value = VectorWrapperInfo::offset_x }; + }; + template struct get_offset_enum_from_index { + enum { value = VectorWrapperInfo::offset_y }; + }; + template struct get_offset_enum_from_index { + enum { value = VectorWrapperInfo::offset_z }; + }; + template struct get_offset_enum_from_index { + enum { value = VectorWrapperInfo::offset_w }; + }; + + template ::dimensions> struct min_offset { + enum { + value = ( + static_cast(get_offset_enum_from_index::value) < static_cast(min_offset::value) ? + static_cast(get_offset_enum_from_index::value) : + static_cast(min_offset::value) + ) + }; + }; + template struct min_offset { + enum { value = get_offset_enum_from_index::value }; + }; + + template < + typename T, + typename U, + std::size_t S=( + static_cast(VectorWrapperInfo::dimensions) < static_cast(VectorWrapperInfo::dimensions) ? + static_cast(VectorWrapperInfo::dimensions) + : + static_cast(VectorWrapperInfo::dimensions) + ) + > struct have_compat_offsets; + template struct have_compat_offsets { + enum { + value = true + }; + }; + template struct have_compat_offsets { + enum { + value = + VectorWrapperInfo::offset_x - min_offset::value == VectorWrapperInfo::offset_x - min_offset::value and + VectorWrapperInfo::offset_y - min_offset::value == VectorWrapperInfo::offset_y - min_offset::value + }; + }; + template struct have_compat_offsets { + enum { + value = + VectorWrapperInfo::offset_x - min_offset::value == VectorWrapperInfo::offset_x - min_offset::value and + VectorWrapperInfo::offset_y - min_offset::value == VectorWrapperInfo::offset_y - min_offset::value and + VectorWrapperInfo::offset_z - min_offset::value == VectorWrapperInfo::offset_z - min_offset::value + }; + }; + template struct have_compat_offsets { + enum { + value = + VectorWrapperInfo::offset_x - min_offset::value == VectorWrapperInfo::offset_x - min_offset::value and + VectorWrapperInfo::offset_y - min_offset::value == VectorWrapperInfo::offset_y - min_offset::value and + VectorWrapperInfo::offset_z - min_offset::value == VectorWrapperInfo::offset_z - min_offset::value and + VectorWrapperInfo::offset_w - min_offset::value == VectorWrapperInfo::offset_w - min_offset::value + }; + }; + + template + struct have_compat_layout { + enum { + value = + HasOffsetXEnum>::value and + HasOffsetXEnum>::value and + have_compat_offsets::value + }; + }; + + template struct is_vec { + enum { value = false }; + }; + template struct is_vec> { + typedef V vector_type; + enum { value = true }; + }; + + template + class VecBase { + friend Vec& assign_same_type ( Vec& parLeft, const Vec& parRight ); + public: + typedef V vector_type; + typedef typename VectorWrapperInfo::scalar_type scalar_type; + + enum { + dimensions = VectorWrapperInfo::dimensions + }; + + VecBase ( void ) = default; + template + explicit VecBase ( const T& parInit, typename std::enable_if::value and not std::is_same::value, bool>::type=false ); + explicit VecBase ( const vector_type& parInit ); + template + 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 + const typename std::enable_if::value, V2>::type& cast ( void ) const; + template + typename std::enable_if::value, V2>::type& cast ( void ); + + template VecBase& operator+= ( const VecBase& parOther ); + template VecBase& operator-= ( const VecBase& parOther ); + template VecBase& operator*= ( const VecBase& parOther ); + template VecBase& operator/= ( const VecBase& parOther ); + + private: + vector_type m_wrapped; + }; + + template ::dimensions> + struct offsets_array_wrapper { + template + offsets_array_wrapper ( const bt::index_seq& ); + + const std::array offsets; + }; + + template >::value and std::is_standard_layout::value> + class VecGetter; + template + struct VecGetter { + static typename VectorWrapperInfo::scalar_type& get_at ( T& parVec, std::size_t parIndex ); + }; + template + struct VecGetter { + private: + static_assert(HasGetAtMethod>::value, "You must provide a get_at() static method for this vector_type"); + typedef typename VectorWrapperInfo::scalar_type scalar_type; + using return_type = decltype(std::declval>().get_at(std::declval(), std::declval())); + static_assert(not std::is_rvalue_reference::value, "rvalue ref return types not implemented"); + static_assert(std::is_lvalue_reference::value, "Read-only vectors not implemented"); + + public: + static typename VectorWrapperInfo::scalar_type& get_at ( T& parVec, std::size_t parIndex ); + }; + + template struct Vec1Promotion; + template struct Vec1Promotion { }; + template struct Vec1Promotion { + typedef Vec::higher_vector_type> higher_vector_type; + typedef typename VectorWrapperInfo::scalar_type scalar_type; + + static_assert(VectorWrapperInfo::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 struct Vec2Promotion; + template struct Vec2Promotion {}; + template struct Vec2Promotion { + typedef Vec::higher_vector_type> higher_vector_type; + typedef typename VectorWrapperInfo::scalar_type scalar_type; + + static_assert(VectorWrapperInfo::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 struct Vec3Promotion; + template struct Vec3Promotion {}; + template struct Vec3Promotion { + typedef Vec::higher_vector_type> higher_vector_type; + typedef typename VectorWrapperInfo::scalar_type scalar_type; + + static_assert(VectorWrapperInfo::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 struct Vec3Demotion; + template struct Vec3Demotion : Vec3Promotion::value> {}; + template struct Vec3Demotion : Vec3Promotion::value> { + typedef Vec::lower_vector_type> lower_vector_type; + typedef typename VectorWrapperInfo::scalar_type scalar_type; + + static_assert(VectorWrapperInfo::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 + struct VecAccessors; + + //Workaround for visual studio - VecAccessors 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) == sizeof(V) condition is verified. + template + struct VecAccessors : Vec3Demotion>::value> { + typedef typename VectorWrapperInfo::scalar_type scalar_type; + const Vec& xyz ( void ) const { return *static_cast*>(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 + struct VecAccessors : Vec2Promotion>::value> { + typedef typename VectorWrapperInfo::scalar_type scalar_type; + const Vec& xy ( void ) const { return *static_cast*>(this); } + const scalar_type& x ( void ) const; + const scalar_type& y ( void ) const; + scalar_type& x ( void ); + scalar_type& y ( void ); + }; + + template + struct VecAccessors : Vec1Promotion>::value> { + typedef typename VectorWrapperInfo::scalar_type scalar_type; + scalar_type& x ( void ); + const scalar_type& x ( void ) const; + }; + } //namespace implem + + template + class Vec : public implem::VecBase { + public: + enum { + dimensions = S + }; + + template + Vec ( Args... parArgs ) : implem::VecBase(std::forward(parArgs)...) + { + } + }; + + template + class Vec : public implem::VecBase, public implem::VecAccessors { + static_assert(std::is_standard_layout>::value, "Base class must be a standard layout type"); + public: + typedef typename implem::VecBase::vector_type vector_type; + typedef typename implem::VecBase::scalar_type scalar_type; + enum { + dimensions = 1 + }; + + static const Vec unit_x; + + Vec ( void ) = default; + Vec ( const Vec& ) = default; + explicit Vec ( const vector_type& parIn ) : implem::VecBase(parIn) { } + template + explicit Vec ( const typename std::enable_if::value and not std::is_same::value, T>::type& parX ) : implem::VecBase(parX) { } + template Vec ( const Vec& parOther ) { implem::assign(*this, parOther); } + + Vec& operator= ( const Vec& parOther ) { return implem::assign_same_type(*this, parOther); } + template + Vec& operator= ( const Vec& parOther ) { return implem::assign(*this, parOther); } + }; + + template + class Vec : public implem::VecBase, public implem::VecAccessors { + static_assert(std::is_standard_layout>::value, "Base class must be a standard layout type"); + static_assert(std::is_standard_layout>::value, "Base class must be a standard layout type"); + public: + typedef typename implem::VecBase::scalar_type scalar_type; + typedef typename implem::VecBase::vector_type vector_type; + enum { + dimensions = 2 + }; + + static const Vec unit_x; + static const Vec unit_y; + + Vec ( void ) = default; + Vec ( const Vec& ) = default; + explicit Vec ( const vector_type& parIn ) : implem::VecBase(parIn) { } + explicit Vec ( const scalar_type parX ) : implem::VecBase(parX) { } + Vec ( scalar_type parX, scalar_type parY ) : implem::VecBase(parX, parY) { } + template Vec ( const Vec& parOther ) { implem::assign(*this, parOther); } + + Vec& operator= ( const Vec& parOther ) { return implem::assign_same_type(*this, parOther); } + template + Vec& operator= ( const Vec& parOther ) { return implem::assign(*this, parOther); } + Vec& operator= ( const vector_type& parOther ) { this->data() = parOther; return *this; } + }; + + template + class Vec : public implem::VecBase, public implem::VecAccessors { + static_assert(std::is_standard_layout>::value, "Base class must be a standard layout type"); + static_assert(std::is_standard_layout>::value, "Base class must be a standard layout type"); + public: + typedef typename implem::VecBase::scalar_type scalar_type; + typedef typename implem::VecBase::vector_type vector_type; + enum { + dimensions = 3 + }; + + static const Vec unit_x; + static const Vec unit_y; + static const Vec unit_z; + + Vec ( void ) = default; + Vec ( const Vec& ) = default; + explicit Vec ( const vector_type& parIn ) : implem::VecBase(parIn) { } + explicit Vec ( const scalar_type parX ) : implem::VecBase(parX) { } + Vec ( scalar_type parX, scalar_type parY, scalar_type parZ ) : implem::VecBase(parX, parY, parZ) { } + template Vec ( const Vec& parOther ) { implem::assign(*this, parOther); } + + Vec& operator= ( const Vec& parOther ) { return implem::assign_same_type(*this, parOther); } + template + Vec& operator= ( const Vec& parOther ) { return implem::assign(*this, parOther); } + Vec& operator= ( const vector_type& parOther ) { this->data() = parOther; return *this; } + }; + + template + Vec mk_vec ( const V& parVec ); + + template + bool operator== ( const Vec& parLeft, const Vec& parRight ); + template + bool operator< ( const Vec& parLeft, const Vec& parRight ); + + template + bool operator== ( const Vec& parLeft, const typename VectorWrapperInfo::scalar_type& parRight ); + template + bool operator< ( const Vec& parLeft, const typename VectorWrapperInfo::scalar_type& parRight ); + + template + bool operator> ( const Vec& parLeft, const T& parRight ); + template + bool operator<= ( const Vec& parLeft, const T& parRight ); + template + bool operator>= ( const Vec& parLeft, const T& parRight ); + template + bool operator!= ( const Vec& parLeft, const T& parRight ); + + template + Vec::type> operator+ ( const Vec& parLeft, const Vec& parRight ); + template + Vec::type> operator- ( const Vec& parLeft, const Vec& parRight ); + template + Vec::type> operator* ( const Vec& parLeft, const Vec& parRight ); + template + Vec::type> operator/ ( const Vec& parLeft, const Vec& parRight ); +} //namespace vwr + +#include "vectorwrapper/vectorwrapper.inl" + +#endif diff --git a/lib/vectorwrapper/include/vectorwrapper/vectorwrapper.inl b/lib/vectorwrapper/include/vectorwrapper/vectorwrapper.inl new file mode 100644 index 0000000..a2ca96d --- /dev/null +++ b/lib/vectorwrapper/include/vectorwrapper/vectorwrapper.inl @@ -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 >::value> struct IsCastIgnoreTrailingPropertiesSet; + template struct IsCastIgnoreTrailingPropertiesSet { static const bool value = static_cast(VectorWrapperInfo::cast_ignore_trailing_properties); }; + template struct IsCastIgnoreTrailingPropertiesSet { static const bool value = false; }; + + template + template + VecBase::VecBase (const T& parInit, typename std::enable_if::value and not std::is_same::value, bool>::type) { + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + VecGetter::get_at(m_wrapped, z) = parInit; + } + } + + template + VecBase::VecBase (const vector_type& parInit) : + m_wrapped(parInit) + { + } + + template + template + VecBase::VecBase (scalar_type parX, scalar_type parY, Args... parArgs) { + static_assert(2 + sizeof...(Args) == dimensions, "Wrong number of parameters received"); + VecGetter::get_at(m_wrapped, 0) = parX; + VecGetter::get_at(m_wrapped, 1) = parY; + + const scalar_type args[sizeof...(Args)] = {parArgs...}; + for (int z = 0; z < sizeof...(Args); ++z) { + VecGetter::get_at(m_wrapped, z + 2) = args[z]; + } + } + + template + auto VecBase::operator[] (std::size_t parIndex) -> scalar_type& { + return VecGetter::get_at(m_wrapped, parIndex); + } + + template + auto VecBase::operator[] (int parIndex) -> scalar_type& { + assert(parIndex >= 0); + return VecGetter::get_at(m_wrapped, static_cast(parIndex)); + } + + template + auto VecBase::operator[] (std::size_t parIndex) const -> const scalar_type& { + return VecGetter::get_at(const_cast(m_wrapped), parIndex); + } + + template + auto VecBase::operator[] (int parIndex) const -> const scalar_type& { + assert(parIndex >= 0); + return VecGetter::get_at(const_cast(m_wrapped), static_cast(parIndex)); + } + + template + template + const typename std::enable_if::value, V2>::type& VecBase::cast() const { + static_assert(sizeof(V2) <= sizeof(VecBase) - min_offset::value, "V2 must fit in V starting from the first coordinate"); + static_assert(std::is_standard_layout::value, "V2 must be a standard layout type"); + static_assert(min_offset::vector_type>::value == 0, "V2 must not have any properties before the first coordinate"); + static_assert(have_compat_layout::vector_type>::value, "V is not suitable for casting to V2"); + + //Assert that V2 won't stomp on part of V's data, unless the user + //has explicitly said he doesn't care. + static_assert((sizeof(typename VectorWrapperInfo::vector_type>::scalar_type) * VectorWrapperInfo::vector_type>::dimensions == sizeof(V2)) or + IsCastIgnoreTrailingPropertiesSet::vector_type>::value, + "V2 must not have any properties past the last coordinate"); + static_assert(alignof(typename VectorWrapperInfo::scalar_type) == alignof(V2), "Casting to V2 would give you a misaligned variable"); + + return *reinterpret_cast( + reinterpret_cast(this) + VectorWrapperInfo::offset_x + ); + } + + template + template + typename std::enable_if::value, V2>::type& VecBase::cast() { + return const_cast(const_cast*>(this)->cast()); + } + + template + template + VecBase& VecBase::operator+= (const VecBase& parOther) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + (*this)[z] += parOther[z]; + } + return *this; + } + template + template + VecBase& VecBase::operator-= (const VecBase& parOther) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + (*this)[z] -= parOther[z]; + } + return *this; + } + template + template + VecBase& VecBase::operator*= (const VecBase& parOther) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + (*this)[z] *= parOther[z]; + } + return *this; + } + template + template + VecBase& VecBase::operator/= (const VecBase& parOther) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + (*this)[z] /= parOther[z]; + } + return *this; + } + + template + typename VectorWrapperInfo::scalar_type& VecGetter::get_at (T& parVec, std::size_t parIndex) { + assert(parIndex < VectorWrapperInfo::dimensions); + typedef T vector_type; + typedef typename VectorWrapperInfo::scalar_type scalar_type; + static_assert(std::is_standard_layout::value, "Can't use this function with this vector_type"); + const offsets_array_wrapper oaw((bt::index_range<0, VectorWrapperInfo::dimensions>())); + return *reinterpret_cast(reinterpret_cast(&parVec) + oaw.offsets[parIndex]); + } + + template + typename VectorWrapperInfo::scalar_type& VecGetter::get_at (T& parVec, std::size_t parIndex) { + assert(parIndex < VectorWrapperInfo::dimensions); + return VectorWrapperInfo::get_at(parIndex, parVec); + } + + template + inline Vec& assign (Vec& parLeft, const Vec& parRight) { + for (std::size_t z = 0; z < D; ++z) { + parLeft[z] = parRight[z]; + } + return parLeft; + } + + template + Vec& assign_same_type (Vec& parLeft, const Vec& parRight) { + parLeft.m_wrapped = parRight.m_wrapped; + return parLeft; + } + + template + auto Vec3Demotion::xy() const -> lower_vector_type { + auto& this_vec = *static_cast*>(this); + return lower_vector_type(this_vec[0], this_vec[1]); + } + + template + auto Vec3Demotion::xz() const -> lower_vector_type { + auto& this_vec = *static_cast*>(this); + return lower_vector_type(this_vec[0], this_vec[2]); + } + + template + auto Vec3Demotion::yz() const -> lower_vector_type { + auto& this_vec = *static_cast*>(this); + return lower_vector_type(this_vec[1], this_vec[2]); + } + + template + auto Vec1Promotion::xn (const scalar_type& parN) const -> higher_vector_type { + auto& this_vec = *static_cast*>(this); + return higher_vector_type(this_vec[0], parN); + } + + template + auto Vec1Promotion::nx (const scalar_type& parN) const -> higher_vector_type { + auto& this_vec = *static_cast*>(this); + return higher_vector_type(parN, this_vec[0]); + } + + template + auto Vec2Promotion::xyn (const scalar_type& parN) const -> higher_vector_type { + auto& this_vec = *static_cast*>(this); + return higher_vector_type(this_vec[0], this_vec[1], parN); + } + + template + auto Vec3Promotion::xyzw (const scalar_type& parW) const -> higher_vector_type { + auto& this_vec = *static_cast*>(this); + return higher_vector_type(this_vec[0], this_vec[1], this_vec[2], parW); + } + + template + auto VecAccessors::x() -> scalar_type& { + auto& this_vec = *static_cast*>(this); + return this_vec[0]; + } + + template + auto VecAccessors::x() const -> const scalar_type& { + const auto& this_vec = *static_cast*>(this); + return this_vec[0]; + } + + template + auto VecAccessors::x() -> scalar_type& { + auto& this_vec = *static_cast*>(this); + return this_vec[0]; + } + + template + auto VecAccessors::x() const -> const scalar_type& { + const auto& this_vec = *static_cast*>(this); + return this_vec[0]; + } + + template + auto VecAccessors::y() -> scalar_type& { + auto& this_vec = *static_cast*>(this); + return this_vec[1]; + } + + template + auto VecAccessors::y() const -> const scalar_type& { + const auto& this_vec = *static_cast*>(this); + return this_vec[1]; + } + + template + auto VecAccessors::x() -> scalar_type& { + auto& this_vec = *static_cast*>(this); + return this_vec[0]; + } + + template + auto VecAccessors::x() const -> const scalar_type& { + const auto& this_vec = *static_cast*>(this); + return this_vec[0]; + } + + template + auto VecAccessors::y() -> scalar_type& { + auto& this_vec = *static_cast*>(this); + return this_vec[1]; + } + + template + auto VecAccessors::y() const -> const scalar_type& { + const auto& this_vec = *static_cast*>(this); + return this_vec[1]; + } + + template + auto VecAccessors::z() -> scalar_type& { + auto& this_vec = *static_cast*>(this); + return this_vec[2]; + } + + template + auto VecAccessors::z() const -> const scalar_type& { + const auto& this_vec = *static_cast*>(this); + return this_vec[2]; + } + + template + template + offsets_array_wrapper::offsets_array_wrapper (const bt::index_seq&) : + offsets({get_offset_enum_from_index::value...}) + { + static_assert(sizeof...(I) == S, "Bug?"); + } + } //namespace implem + + template const Vec Vec::unit_x(scalar_type(1)); + template const Vec Vec::unit_x(scalar_type(1), scalar_type(0)); + template const Vec Vec::unit_y(scalar_type(0), scalar_type(1)); + template const Vec Vec::unit_x(scalar_type(1), scalar_type(0), scalar_type(0)); + template const Vec Vec::unit_y(scalar_type(0), scalar_type(1), scalar_type(0)); + template const Vec Vec::unit_z(scalar_type(0), scalar_type(0), scalar_type(1)); + + template + Vec mk_vec (const V& parVec) { + return Vec(parVec); + } + + template + inline bool operator== (const Vec& parLeft, const Vec& parRight) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + bool retval = true; + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + retval &= (parLeft[z] == parRight[z]); + } + return retval; + } + template + inline bool operator< (const Vec& parLeft, const Vec& parRight) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + bool retval = true; + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + retval &= (parLeft[z] < parRight[z]); + } + return retval; + } + + template + inline bool operator== (const Vec& parLeft, const typename VectorWrapperInfo::scalar_type& parRight) { + bool retval = true; + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + retval &= (parLeft[z] == parRight); + } + return retval; + } + template + inline bool operator< ( const Vec& parLeft, const typename VectorWrapperInfo::scalar_type& parRight) { + bool retval = true; + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + retval &= (parLeft[z] < parRight); + } + return retval; + } + + template + inline bool operator> (const Vec& parLeft, const T& parRight) { + return not (parLeft < parRight) and not (parLeft == parRight); + } + template + inline bool operator<= (const Vec& parLeft, const T& parRight) { + return (parLeft < parRight) or (parLeft == parRight); + } + template + inline bool operator>= (const Vec& parLeft, const T& parRight) { + return not (parLeft < parRight); + } + template + inline bool operator!= (const Vec& parLeft, const T& parRight) { + return not (parLeft == parRight); + } + + template + inline Vec::type> operator+ (const Vec& parLeft, const Vec& parRight) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + Vec::type> retval; + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + retval[z] = parLeft[z] + parRight[z]; + } + return retval; + } + template + inline Vec::type> operator- (const Vec& parLeft, const Vec& parRight) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + Vec::type> retval; + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + retval[z] = parLeft[z] - parRight[z]; + } + return retval; + } + template + inline Vec::type> operator* (const Vec& parLeft, const Vec& parRight) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + Vec::type> retval; + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + retval[z] = parLeft[z] * parRight[z]; + } + return retval; + } + template + inline Vec::type> operator/ (const Vec& parLeft, const Vec& parRight) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + Vec::type> retval; + for (int z = 0; z < VectorWrapperInfo::dimensions; ++z) { + retval[z] = parLeft[z] / parRight[z]; + } + return retval; + } +} //namespace vwr diff --git a/test/unit/vector.cpp b/test/unit/vector.cpp index 5afe2ff..4287754 100644 --- a/test/unit/vector.cpp +++ b/test/unit/vector.cpp @@ -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); + } }