diff --git a/include/vectorwrapper/implem_vec_base.hpp b/include/vectorwrapper/implem_vec_base.hpp index b0c25a6..803c295 100644 --- a/include/vectorwrapper/implem_vec_base.hpp +++ b/include/vectorwrapper/implem_vec_base.hpp @@ -19,6 +19,8 @@ #include "implem_vec_common.hpp" #include "sequence_bt.hpp" #include +#include +#include #if defined VWR_OUTER_NAMESPACE namespace VWR_OUTER_NAMESPACE { @@ -107,9 +109,63 @@ namespace vwr { vector_type m_wrapped; }; + + template < + typename T, + typename U, + size_type 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 + }; + }; } //namespace implem + + template struct is_castable_to { }; } //namespace vwr #if defined VWR_OUTER_NAMESPACE } //namespace VWR_OUTER_NAMESPACE #endif + +#include "implem_vec_base.inl" diff --git a/include/vectorwrapper/implem_vec_base.inl b/include/vectorwrapper/implem_vec_base.inl new file mode 100644 index 0000000..8711405 --- /dev/null +++ b/include/vectorwrapper/implem_vec_base.inl @@ -0,0 +1,189 @@ +/* + * Copyright 2015-2017 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. + */ + +#if defined VWR_OUTER_NAMESPACE +namespace VWR_OUTER_NAMESPACE { +#endif + +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 (size_type 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; + + assign_values(bt::number_range(), std::forward(parArgs)...); + } + + template + template + void VecBase::assign_values (const bt::number_seq&, Args... parArgs) { + static_assert(sizeof...(I) == sizeof...(Args), "Argument count and indices count mismatch"); + + std::initializer_list t { + (VecGetter::get_at(m_wrapped, I) = parArgs)... + }; + static_cast(t); + } + + template + template + void VecBase::assign_values_op (Op parOp, const bt::number_seq& parSeq, const VecBase& parOther) { + this->assign_values(parSeq, parOp((*this)[I], parOther[I])...); + } + + template + template + void VecBase::assign_values_op_scalar (Op parOp, const bt::number_seq& parSeq, const scalar_type& parOther) { + this->assign_values(parSeq, parOp((*this)[I], parOther)...); + } + + template + auto VecBase::operator[] (size_type parIndex) -> scalar_type& { + return VecGetter::get_at(m_wrapped, parIndex); + } + + template + auto VecBase::operator[] (size_type parIndex) const -> const scalar_type& { + return VecGetter::get_at(const_cast(m_wrapped), parIndex); + } + + template + template + auto VecBase::cast() const -> const typename std::enable_if::value and directly_convertible::value, V2>::type& { + 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 + auto VecBase::cast() -> typename std::enable_if::value and directly_convertible::value, V2>::type& { + return const_cast(const_cast*>(this)->cast()); + } + + template + template + auto VecBase::cast() const -> const typename std::enable_if::value and not directly_convertible::value, V2>::type& { + static_assert(std::is_standard_layout::value, "V2 must be a standard layout type"); + typedef typename is_vec::vector_type v2_type; + static_assert(std::is_base_of::vector_type>, VectorWrapperInfo>::value, "Casting for this type has to be explicitly enabled"); + + //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)[0]) + ); + } + + template + template + auto VecBase::cast() -> typename std::enable_if::value and not directly_convertible::value, V2>::type& { + 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"); + this->assign_values_op(std::plus(), bt::number_range::dimensions>(), parOther); + return *this; + } + template + template + VecBase& VecBase::operator-= (const VecBase& parOther) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + this->assign_values_op(std::minus(), bt::number_range::dimensions>(), parOther); + return *this; + } + template + template + VecBase& VecBase::operator*= (const VecBase& parOther) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + this->assign_values_op(std::multiplies(), bt::number_range::dimensions>(), parOther); + return *this; + } + template + template + VecBase& VecBase::operator/= (const VecBase& parOther) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + this->assign_values_op(std::divides(), bt::number_range::dimensions>(), parOther); + return *this; + } + + template + VecBase& VecBase::operator+= (const scalar_type& parOther) { + this->assign_values_op_scalar(std::plus(), bt::number_range::dimensions>(), parOther); + return *this; + } + template + VecBase& VecBase::operator-= (const scalar_type& parOther) { + this->assign_values_op_scalar(std::minus(), bt::number_range::dimensions>(), parOther); + return *this; + } + template + VecBase& VecBase::operator*= (const scalar_type& parOther) { + this->assign_values_op_scalar(std::multiplies(), bt::number_range::dimensions>(), parOther); + return *this; + } + template + VecBase& VecBase::operator/= (const scalar_type& parOther) { + this->assign_values_op_scalar(std::divides(), bt::number_range::dimensions>(), parOther); + return *this; + } + } //namespace implem +} //namespace vwr + +#if defined VWR_OUTER_NAMESPACE +} //namespace VWR_OUTER_NAMESPACE +#endif diff --git a/include/vectorwrapper/implem_vec_common.hpp b/include/vectorwrapper/implem_vec_common.hpp index 1a9b038..6b8452f 100644 --- a/include/vectorwrapper/implem_vec_common.hpp +++ b/include/vectorwrapper/implem_vec_common.hpp @@ -18,25 +18,75 @@ #include "size_type.hpp" #include "has_method.hpp" +#include #if defined VWR_OUTER_NAMESPACE namespace VWR_OUTER_NAMESPACE { #endif 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 >::value and std::is_standard_layout::value> + struct VecGetter; + template + struct VecGetter { + static typename VectorWrapperInfo::scalar_type& get_at ( T& parVec, size_type 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; + typedef T vector_type; + using get_at_func = decltype(&VectorWrapperInfo::get_at)(size_type, vector_type&); + using get_at_rettype = typename std::result_of::type; + + 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 get_at_rettype get_at ( T& parVec, size_type parIndex ); + }; + + 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 }; + }; } //namespace implem - - template - struct VectorWrapperInfo; - - template ::dimensions> - class Vec; } //namespace vwr #if defined VWR_OUTER_NAMESPACE diff --git a/include/vectorwrapper/vectorwrapper.hpp b/include/vectorwrapper/vectorwrapper.hpp index 66efe28..8fc8482 100644 --- a/include/vectorwrapper/vectorwrapper.hpp +++ b/include/vectorwrapper/vectorwrapper.hpp @@ -16,14 +16,15 @@ #pragma once -#include "implem_vec_base.hpp" -#include "implem_vec_common.hpp" #include "sequence_bt.hpp" #include "size_type.hpp" +#include "implem_vec_base.hpp" +#include "implem_vec_common.hpp" #include #include #include #include +#include #if defined VWR_OUTER_NAMESPACE namespace VWR_OUTER_NAMESPACE { @@ -42,83 +43,6 @@ namespace vwr { Vec& assign ( Vec& parLeft, const Vec& parRight ); #endif - 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, - size_type 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 ::dimensions> struct offsets_array_wrapper { template @@ -127,28 +51,6 @@ namespace vwr { const std::array offsets; }; - template >::value and std::is_standard_layout::value> - struct VecGetter; - template - struct VecGetter { - static typename VectorWrapperInfo::scalar_type& get_at ( T& parVec, size_type 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; - typedef T vector_type; - using get_at_func = decltype(&VectorWrapperInfo::get_at)(size_type, vector_type&); - using get_at_rettype = typename std::result_of::type; - - 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 get_at_rettype get_at ( T& parVec, size_type parIndex ); - }; - template struct Vec1Promotion; template struct Vec1Promotion { }; template struct Vec1Promotion { @@ -265,8 +167,6 @@ namespace vwr { Vec::type> binary_op ( const Vec& parLeft, const Vec& parRight, Op parOp, const Vec::type>& parLastVal, bt::number_seq ); } //namespace implem - template struct is_castable_to { }; - template class Vec : public implem::VecBase { public: diff --git a/include/vectorwrapper/vectorwrapper.inl b/include/vectorwrapper/vectorwrapper.inl index 88e7dfe..be97a86 100644 --- a/include/vectorwrapper/vectorwrapper.inl +++ b/include/vectorwrapper/vectorwrapper.inl @@ -20,168 +20,6 @@ namespace VWR_OUTER_NAMESPACE { 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 (size_type 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; - - assign_values(bt::number_range(), std::forward(parArgs)...); - } - - template - template - void VecBase::assign_values (const bt::number_seq&, Args... parArgs) { - static_assert(sizeof...(I) == sizeof...(Args), "Argument count and indices count mismatch"); - - std::initializer_list t { - (VecGetter::get_at(m_wrapped, I) = parArgs)... - }; - static_cast(t); - } - - template - template - void VecBase::assign_values_op (Op parOp, const bt::number_seq& parSeq, const VecBase& parOther) { - this->assign_values(parSeq, parOp((*this)[I], parOther[I])...); - } - - template - template - void VecBase::assign_values_op_scalar (Op parOp, const bt::number_seq& parSeq, const scalar_type& parOther) { - this->assign_values(parSeq, parOp((*this)[I], parOther)...); - } - - template - auto VecBase::operator[] (size_type parIndex) -> scalar_type& { - return VecGetter::get_at(m_wrapped, parIndex); - } - - template - auto VecBase::operator[] (size_type parIndex) const -> const scalar_type& { - return VecGetter::get_at(const_cast(m_wrapped), parIndex); - } - - template - template - auto VecBase::cast() const -> const typename std::enable_if::value and directly_convertible::value, V2>::type& { - 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 - auto VecBase::cast() -> typename std::enable_if::value and directly_convertible::value, V2>::type& { - return const_cast(const_cast*>(this)->cast()); - } - - template - template - auto VecBase::cast() const -> const typename std::enable_if::value and not directly_convertible::value, V2>::type& { - static_assert(std::is_standard_layout::value, "V2 must be a standard layout type"); - typedef typename is_vec::vector_type v2_type; - static_assert(std::is_base_of::vector_type>, VectorWrapperInfo>::value, "Casting for this type has to be explicitly enabled"); - - //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)[0]) - ); - } - - template - template - auto VecBase::cast() -> typename std::enable_if::value and not directly_convertible::value, V2>::type& { - 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"); - this->assign_values_op(std::plus(), bt::number_range::dimensions>(), parOther); - return *this; - } - template - template - VecBase& VecBase::operator-= (const VecBase& parOther) { - static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); - this->assign_values_op(std::minus(), bt::number_range::dimensions>(), parOther); - return *this; - } - template - template - VecBase& VecBase::operator*= (const VecBase& parOther) { - static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); - this->assign_values_op(std::multiplies(), bt::number_range::dimensions>(), parOther); - return *this; - } - template - template - VecBase& VecBase::operator/= (const VecBase& parOther) { - static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); - this->assign_values_op(std::divides(), bt::number_range::dimensions>(), parOther); - return *this; - } - - template - VecBase& VecBase::operator+= (const scalar_type& parOther) { - this->assign_values_op_scalar(std::plus(), bt::number_range::dimensions>(), parOther); - return *this; - } - template - VecBase& VecBase::operator-= (const scalar_type& parOther) { - this->assign_values_op_scalar(std::minus(), bt::number_range::dimensions>(), parOther); - return *this; - } - template - VecBase& VecBase::operator*= (const scalar_type& parOther) { - this->assign_values_op_scalar(std::multiplies(), bt::number_range::dimensions>(), parOther); - return *this; - } - template - VecBase& VecBase::operator/= (const scalar_type& parOther) { - this->assign_values_op_scalar(std::divides(), bt::number_range::dimensions>(), parOther); - return *this; - } - template typename VectorWrapperInfo::scalar_type& VecGetter::get_at (T& parVec, size_type parIndex) { assert(parIndex < VectorWrapperInfo::dimensions);