vectorwrapper/include/vectorwrapper/implem_vec_base.inl

201 lines
9.3 KiB
C++

/*
* Copyright 2015-2020 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 <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 (size_type z = 0; z < VectorWrapperInfo<V>::dimensions; ++z) {
VecGetter<V>::get_at(data(), z) = parInit;
}
}
template <typename V>
VecBase<V>::VecBase (const vector_type& parInit) :
VecBaseStorage<V>(parInit)
{
if constexpr (not VecBaseStorage<V>::IsWrappedCopyConstructible) {
for (size_type z = 0; z < dimensions; ++z) {
(*this)[z] = parInit[z];
}
}
}
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(data(), 0) = parX;
VecGetter<V>::get_at(data(), 1) = parY;
assign_values(bt::number_range<size_type, 2, dimensions>(), std::forward<Args>(parArgs)...);
}
template <typename V>
template <size_type... I, typename... Args>
void VecBase<V>::assign_values (const bt::number_seq<size_type, I...>&, Args... parArgs) {
static_assert(sizeof...(I) == sizeof...(Args), "Argument count and indices count mismatch");
std::initializer_list<scalar_type> t {
(VecGetter<V>::get_at(data(), I) = parArgs)...
};
static_cast<void>(t);
}
template <typename V>
template <typename Op, typename V2, size_type... I>
void VecBase<V>::assign_values_op (Op parOp, const bt::number_seq<size_type, I...>& parSeq, const VecBase<V2>& parOther) {
this->assign_values(parSeq, parOp((*this)[I], parOther[I])...);
}
template <typename V>
template <typename Op, size_type... I>
void VecBase<V>::assign_values_op_scalar (Op parOp, const bt::number_seq<size_type, I...>& parSeq, const scalar_type& parOther) {
this->assign_values(parSeq, parOp((*this)[I], parOther)...);
}
template <typename V>
auto VecBase<V>::operator[] (size_type parIndex) -> scalar_type& {
return VecGetter<V>::get_at(data(), parIndex);
}
template <typename V>
auto VecBase<V>::operator[] (size_type parIndex) const -> const scalar_type& {
return VecGetter<V>::get_at(const_cast<vector_type&>(data()), parIndex);
}
template <typename V>
template <typename V2>
auto VecBase<V>::cast() const -> const typename std::enable_if<is_vec<V2>::value and directly_convertible<V, V2>::value, V2>::type& {
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>
auto VecBase<V>::cast() -> typename std::enable_if<is_vec<V2>::value and directly_convertible<V, V2>::value, V2>::type& {
return const_cast<V2&>(const_cast<const VecBase<V>*>(this)->cast<V2>());
}
template <typename V>
template <typename V2>
auto VecBase<V>::cast() const -> const typename std::enable_if<is_vec<V2>::value and not directly_convertible<V, V2>::value, V2>::type& {
static_assert(std::is_standard_layout<V2>::value, "V2 must be a standard layout type");
typedef typename is_vec<V2>::vector_type v2_type;
static_assert(std::is_base_of<is_castable_to<typename VectorWrapperInfo<v2_type>::vector_type>, VectorWrapperInfo<V>>::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<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)[0])
);
}
template <typename V>
template <typename V2>
auto VecBase<V>::cast() -> typename std::enable_if<is_vec<V2>::value and not directly_convertible<V, V2>::value, V2>::type& {
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");
this->assign_values_op(std::plus<scalar_type>(), bt::number_range<size_type, 0, VectorWrapperInfo<V>::dimensions>(), parOther);
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");
this->assign_values_op(std::minus<scalar_type>(), bt::number_range<size_type, 0, VectorWrapperInfo<V>::dimensions>(), parOther);
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");
this->assign_values_op(std::multiplies<scalar_type>(), bt::number_range<size_type, 0, VectorWrapperInfo<V>::dimensions>(), parOther);
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");
this->assign_values_op(std::divides<scalar_type>(), bt::number_range<size_type, 0, VectorWrapperInfo<V>::dimensions>(), parOther);
return *this;
}
template <typename V>
VecBase<V>& VecBase<V>::operator+= (const scalar_type& parOther) {
this->assign_values_op_scalar(std::plus<scalar_type>(), bt::number_range<size_type, 0, VectorWrapperInfo<V>::dimensions>(), parOther);
return *this;
}
template <typename V>
VecBase<V>& VecBase<V>::operator-= (const scalar_type& parOther) {
this->assign_values_op_scalar(std::minus<scalar_type>(), bt::number_range<size_type, 0, VectorWrapperInfo<V>::dimensions>(), parOther);
return *this;
}
template <typename V>
VecBase<V>& VecBase<V>::operator*= (const scalar_type& parOther) {
this->assign_values_op_scalar(std::multiplies<scalar_type>(), bt::number_range<size_type, 0, VectorWrapperInfo<V>::dimensions>(), parOther);
return *this;
}
template <typename V>
VecBase<V>& VecBase<V>::operator/= (const scalar_type& parOther) {
this->assign_values_op_scalar(std::divides<scalar_type>(), bt::number_range<size_type, 0, VectorWrapperInfo<V>::dimensions>(), parOther);
return *this;
}
template <typename V>
inline VecBase<V>::VecBase (const VecBase& parOther) :
VecBase<V>(parOther.data())
{
}
} //namespace implem
} //namespace vwr
#if defined VWR_OUTER_NAMESPACE
} //namespace VWR_OUTER_NAMESPACE
#endif