diff --git a/CMakeLists.txt b/CMakeLists.txt index 20085212..88d77454 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,6 +435,9 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/librapid/vendor/xsimd") target_compile_definitions(fmt PUBLIC FMT_HEADER_ONLY) target_link_libraries(${module_name} PUBLIC fmt xsimd) +# Disable "parameter passing for argument of type ... changed to match ..." for xsimd +target_compile_options(xsimd INTERFACE $<$,$>:-Wno-psabi>) + if (${LIBRAPID_USE_MULTIPREC}) # Load MPIR find_package(MPIR QUIET) diff --git a/librapid/include/librapid/array/arrayContainer.hpp b/librapid/include/librapid/array/arrayContainer.hpp index 4768ce6f..5ee80f21 100644 --- a/librapid/include/librapid/array/arrayContainer.hpp +++ b/librapid/include/librapid/array/arrayContainer.hpp @@ -56,7 +56,13 @@ namespace librapid { static constexpr bool supportsArithmetic = TypeInfo::supportsArithmetic; static constexpr bool supportsLogical = TypeInfo::supportsLogical; static constexpr bool supportsBinary = TypeInfo::supportsBinary; - static constexpr bool allowVectorisation = TypeInfo::packetWidth > 1; + static constexpr bool allowVectorisation = []() { + if constexpr (typetraits::HasAllowVectorisation>::value) { + return TypeInfo::allowVectorisation; + } else { + return TypeInfo::packetWidth > 1; + } + }(); #if defined(LIBRAPID_HAS_CUDA) static constexpr cudaDataType_t CudaType = TypeInfo::CudaType; @@ -67,15 +73,6 @@ namespace librapid { static constexpr int64_t canMemcpy = false; }; - /// Evaluates as true if the input type is an ArrayContainer instance - /// \tparam T Input type - template - struct IsArrayContainer : std::false_type {}; - - template - struct IsArrayContainer> : std::true_type { - }; - LIBRAPID_DEFINE_AS_TYPE(typename StorageScalar, array::ArrayContainer); @@ -686,7 +683,7 @@ namespace librapid { sizeof...(Indices), m_shape.ndim()); - int dim = 0; + int dim = 0; int64_t index = 0; for (int64_t i : {indices...}) { LIBRAPID_ASSERT( diff --git a/librapid/include/librapid/array/assignOps.hpp b/librapid/include/librapid/array/assignOps.hpp index 3ba5d15b..ba95ae6c 100644 --- a/librapid/include/librapid/array/assignOps.hpp +++ b/librapid/include/librapid/array/assignOps.hpp @@ -24,11 +24,17 @@ namespace librapid { using Function = detail::Function; using Scalar = typename array::ArrayContainer>::Scalar; - constexpr int64_t packetWidth = typetraits::TypeInfo::packetWidth; constexpr bool allowVectorisation = typetraits::TypeInfo< detail::Function>::allowVectorisation && Function::argsAreSameType; + constexpr int64_t packetWidth = []() { + if constexpr (allowVectorisation) { + return typetraits::TypeInfo::packetWidth; + } else { + return 1; + } + }(); const int64_t size = function.shape().size(); const int64_t vectorSize = size - (size % packetWidth); @@ -74,13 +80,21 @@ namespace librapid { using Scalar = typename array::ArrayContainer>::Scalar; - constexpr int64_t packetWidth = typetraits::TypeInfo::packetWidth; - constexpr int64_t elements = ::librapid::product(); - constexpr int64_t vectorSize = elements - (elements % packetWidth); + constexpr bool allowVectorisation = typetraits::TypeInfo< detail::Function>::allowVectorisation && Function::argsAreSameType; + constexpr int64_t packetWidth = []() { + if constexpr (allowVectorisation) { + return typetraits::TypeInfo::packetWidth; + } else { + return 1; + } + }(); + + constexpr int64_t elements = ::librapid::product(); + constexpr int64_t vectorSize = elements - (elements % packetWidth); // Ensure the function can actually be assigned to the array container static_assert( @@ -124,12 +138,18 @@ namespace librapid { using Function = detail::Function; using Scalar = typename array::ArrayContainer>::Scalar; - constexpr size_t packetWidth = typetraits::TypeInfo::packetWidth; constexpr bool allowVectorisation = typetraits::TypeInfo< detail::Function>::allowVectorisation && Function::argsAreSameType; + constexpr int64_t packetWidth = []() { + if constexpr (allowVectorisation) { + return typetraits::TypeInfo::packetWidth; + } else { + return 1; + } + }(); const size_t size = function.size(); const size_t vectorSize = size - (size % packetWidth); @@ -180,12 +200,18 @@ namespace librapid { using Scalar = typename array::ArrayContainer>::Scalar; - constexpr int64_t packetWidth = typetraits::TypeInfo::packetWidth; constexpr bool allowVectorisation = typetraits::TypeInfo< detail::Function>::allowVectorisation && Function::argsAreSameType; + constexpr int64_t packetWidth = []() { + if constexpr (allowVectorisation) { + return typetraits::TypeInfo::packetWidth; + } else { + return 1; + } + }(); constexpr int64_t size = ::librapid::product(); constexpr int64_t vectorSize = size - (size % packetWidth); diff --git a/librapid/include/librapid/array/function.hpp b/librapid/include/librapid/array/function.hpp index dc2c61c1..8d92ab87 100644 --- a/librapid/include/librapid/array/function.hpp +++ b/librapid/include/librapid/array/function.hpp @@ -35,13 +35,60 @@ namespace librapid { } } + // Normally, we want to use the scalar type of the input. This said, there are a few edge + // cases where it is necessary to use the type itself. + + // Default + template + struct ScalarTypeHelper { + using Type = typename TypeInfo>::Scalar; + }; + + // Vectors + template + struct ScalarTypeHelper> { + using Type = Vector; + }; + + // Once we have the correct scalar types, we need to check if the result is a lazy-evaluated + // function. If so, we need to extract the actual return type from the function. + + // Default + template + struct ReturnTypeHelper { + using Type = T; + }; + + // Binary vector operation + template + struct ReturnTypeHelper> { + using IntermediateType = vectorDetail::BinaryVecOp; + using Type = decltype(std::declval().eval()); + }; + + // Unary vector operation + template + struct ReturnTypeHelper> { + using IntermediateType = vectorDetail::UnaryVecOp; + using Type = decltype(std::declval().eval()); + }; + template struct TypeInfo<::librapid::detail::Function> { static constexpr detail::LibRapidType type = detail::LibRapidType::ArrayFunction; - using Scalar = decltype(std::declval()( - std::declval>::Scalar>()...)); - using Packet = typename TypeInfo::Packet; - using Backend = decltype(commonBackend()); + // using Scalar = decltype(std::declval()( + // std::declval>::Scalar>()...)); + + // using Scalar = decltype(std::declval()( + // std::declval::Type>()...)); + + using TempScalar = decltype(std::declval()( + std::declval::Type>()...)); + + using Scalar = typename ReturnTypeHelper::Type; + + using Packet = typename TypeInfo::Packet; + using Backend = decltype(commonBackend()); using ShapeType = typename detail::ShapeTypeHelper::ShapeType...>::Type; @@ -81,16 +128,12 @@ namespace librapid { return Packet(obj); } - template::type != - ::librapid::detail::LibRapidType::Scalar, - int> = 0> + template::val, int> = 0> LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto scalarExtractor(const T &obj, size_t index) { return obj.scalar(index); } - template::type == - ::librapid::detail::LibRapidType::Scalar, - int> = 0> + template::val, int> = 0> LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto scalarExtractor(const T &obj, size_t) { return obj; } diff --git a/librapid/include/librapid/array/operations.hpp b/librapid/include/librapid/array/operations.hpp index b15d67be..d17c2fc9 100644 --- a/librapid/include/librapid/array/operations.hpp +++ b/librapid/include/librapid/array/operations.hpp @@ -67,20 +67,37 @@ return std::get<0>(args).shape(); \ } +//#define LIBRAPID_BINARY_SHAPE_EXTRACTOR \ +// template \ +// LIBRAPID_NODISCARD static LIBRAPID_ALWAYS_INLINE auto getShapeImpl( \ +// const std::tuple &tup) { \ +// if constexpr (TypeInfo>::type != detail::LibRapidType::Scalar && \ +// TypeInfo>::type != detail::LibRapidType::Scalar) { \ +// LIBRAPID_ASSERT(std::get<0>(tup).shape() == std::get<1>(tup).shape(), \ +// "Shapes must match for binary operations"); \ +// return std::get<0>(tup).shape(); \ +// } else if constexpr (TypeInfo>::type == \ +// detail::LibRapidType::Scalar) { \ +// return std::get<1>(tup).shape(); \ +// } else { \ +// return std::get<0>(tup).shape(); \ +// } \ +// } \ + + #define LIBRAPID_BINARY_SHAPE_EXTRACTOR \ template \ LIBRAPID_NODISCARD static LIBRAPID_ALWAYS_INLINE auto getShapeImpl( \ const std::tuple &tup) { \ - if constexpr (TypeInfo>::type != detail::LibRapidType::Scalar && \ - TypeInfo>::type != detail::LibRapidType::Scalar) { \ - LIBRAPID_ASSERT(std::get<0>(tup).shape() == std::get<1>(tup).shape(), \ - "Shapes must match for binary operations"); \ + if constexpr (IsArrayType>::value) { \ + if constexpr (IsArrayType>::value) { \ + LIBRAPID_ASSERT(std::get<0>(tup).shape() == std::get<1>(tup).shape(), \ + "Shapes must match for binary operations"); \ + return std::get<0>(tup).shape(); \ + } \ return std::get<0>(tup).shape(); \ - } else if constexpr (TypeInfo>::type == \ - detail::LibRapidType::Scalar) { \ + } else if constexpr (IsArrayType>::value) { \ return std::get<1>(tup).shape(); \ - } else { \ - return std::get<0>(tup).shape(); \ } \ } \ \ @@ -523,6 +540,12 @@ namespace librapid { } // namespace typetraits namespace detail { + template + constexpr bool isType() { + constexpr LibRapidType t = typetraits::TypeInfo>::type; + return ((t == ValidTypes) || ...); + } + template constexpr bool isArrayOp() { return (typetraits::IsArrayContainer>::value || @@ -531,18 +554,59 @@ namespace librapid { template constexpr bool isArrayOpArray() { - return (typetraits::TypeInfo>::type != LibRapidType::Scalar) && - (typetraits::TypeInfo>::type != LibRapidType::Scalar) && - typetraits::IsLibRapidType>::value && - typetraits::IsLibRapidType>::value; + // return (typetraits::TypeInfo>::type != LibRapidType::Scalar) && + // (typetraits::TypeInfo>::type != LibRapidType::Scalar) && + // typetraits::IsLibRapidType>::value && + // typetraits::IsLibRapidType>::value; + + // ArrayContainer, + // ArrayFunction, + // GeneralArrayView + + constexpr bool lhsIsValid = isType(); + + constexpr bool rhsIsValid = isType(); + + return lhsIsValid && rhsIsValid; } template constexpr bool isArrayOpWithScalar() { - return (typetraits::IsLibRapidType>::value && - typetraits::TypeInfo>::type == LibRapidType::Scalar) || - (typetraits::TypeInfo>::type == LibRapidType::Scalar && - typetraits::IsLibRapidType>::value); + // // We allow operations with vectors here + // return (typetraits::IsLibRapidType>::value && + // ( + // (typetraits::TypeInfo>::type == LibRapidType::Scalar) || + // (typetraits::TypeInfo>::type == LibRapidType::Vector) + // ) + // ) || + // ( + // ( + // (typetraits::TypeInfo>::type == LibRapidType::Scalar) || + // (typetraits::TypeInfo>::type == LibRapidType::Vector) + // ) && + // typetraits::IsLibRapidType>::value); + + constexpr bool lhsIsArray = isType(); + + constexpr bool rhsIsArray = isType(); + + constexpr bool lhsIsScalar = isType(); + + constexpr bool rhsIsScalar = isType(); + + return (lhsIsArray ^ rhsIsArray) && (lhsIsScalar ^ rhsIsScalar); } } // namespace detail diff --git a/librapid/include/librapid/array/shape.hpp b/librapid/include/librapid/array/shape.hpp index 6e7c5903..061e296b 100644 --- a/librapid/include/librapid/array/shape.hpp +++ b/librapid/include/librapid/array/shape.hpp @@ -776,34 +776,19 @@ namespace librapid { using Type = VectorShape; }; - template<> - struct ShapeTypeHelperImpl { - using Type = Shape; + template + struct ShapeTypeHelperImpl { + using Type = NonFalseType; }; - template<> - struct ShapeTypeHelperImpl { + template + struct ShapeTypeHelperImpl { using Type = Shape; }; template<> - struct ShapeTypeHelperImpl { - using Type = MatrixShape; - }; - - template<> - struct ShapeTypeHelperImpl { - using Type = MatrixShape; - }; - - template<> - struct ShapeTypeHelperImpl { - using Type = VectorShape; - }; - - template<> - struct ShapeTypeHelperImpl { - using Type = VectorShape; + struct ShapeTypeHelperImpl { + using Type = VectorShape; // Fastest }; template diff --git a/librapid/include/librapid/core/forward.hpp b/librapid/include/librapid/core/forward.hpp index f7594eb6..1ea1b423 100644 --- a/librapid/include/librapid/core/forward.hpp +++ b/librapid/include/librapid/core/forward.hpp @@ -28,6 +28,17 @@ namespace librapid { class ArrayContainer; } + namespace typetraits { + /// Evaluates as true if the input type is an ArrayContainer instance + /// \tparam T Input type + template + struct IsArrayContainer : std::false_type {}; + + template + struct IsArrayContainer> : std::true_type { + }; + } + namespace detail { /// \brief Identifies which type of function is being used namespace descriptor { diff --git a/librapid/include/librapid/core/typetraits.hpp b/librapid/include/librapid/core/typetraits.hpp index c4cd8962..28964131 100644 --- a/librapid/include/librapid/core/typetraits.hpp +++ b/librapid/include/librapid/core/typetraits.hpp @@ -46,6 +46,12 @@ namespace librapid::typetraits { std::true_type testCast(int); template std::false_type testCast(float); + + // Test for T::allowVectorisation (static constexpr bool) + template + std::true_type testAllowVectorisation(int); + template + std::false_type testAllowVectorisation(float); } // namespace impl template @@ -63,6 +69,10 @@ namespace librapid::typetraits { // Detect whether a class can be default constructed template using TriviallyDefaultConstructible = std::is_trivially_default_constructible; + + // Detect whether a class has a static constexpr bool member called allowVectorization + template + struct HasAllowVectorisation : public decltype(impl::testAllowVectorisation(1)) {}; } // namespace librapid::typetraits #endif // LIBRAPID_CORE_TYPETRAITS_HPP \ No newline at end of file diff --git a/librapid/include/librapid/datastructures/bitset.hpp b/librapid/include/librapid/datastructures/bitset.hpp index 1dcab841..2991eda5 100644 --- a/librapid/include/librapid/datastructures/bitset.hpp +++ b/librapid/include/librapid/datastructures/bitset.hpp @@ -394,10 +394,10 @@ namespace librapid { } } // namespace librapid -template -struct fmt::formatter, Char> { +template +struct fmt::formatter, Char> { private: - using Type = librapid::BitSet; + using Type = librapid::BitSet; using Base = fmt::formatter; Base m_base; @@ -414,11 +414,11 @@ struct fmt::formatter, Char> { } }; -LIBRAPID_SIMPLE_IO_NORANGE(uint64_t numBits, librapid::BitSet) +LIBRAPID_SIMPLE_IO_NORANGE(uint64_t numBits COMMA bool stackAlloc, librapid::BitSet) // std ostream support -template -std::ostream &operator<<(std::ostream &os, const librapid::BitSet &bitset) { +template +std::ostream &operator<<(std::ostream &os, const librapid::BitSet &bitset) { return os << fmt::format("{}", bitset); } diff --git a/librapid/include/librapid/math/vector.hpp b/librapid/include/librapid/math/vector.hpp index 8dc25aac..d578470a 100644 --- a/librapid/include/librapid/math/vector.hpp +++ b/librapid/include/librapid/math/vector.hpp @@ -18,6 +18,41 @@ namespace librapid { using Vec2 = Vector; using Vec3 = Vector; using Vec4 = Vector; + + template + Vector randomPointOnSphere() { + // Given X = [x_1, x_2, ..., x_n], where x_n ~ N(1, 0), + // X / |X| will be uniformly distributed on the unit sphere + + Vector result; + for (uint64_t i = 0; i < numDims; ++i) { + result[i] = ::librapid::randomGaussian(); + } + + return norm(result); + } + + /// \brief Generate a random point within the unit sphere + /// \tparam T Scalar type of the vector, defaulting to ``float`` + /// \return 3D vector, \f$\vec{v}\f$, with \f$0 \leq |\vec{v}| \leq 1\f$ + template + Vector randomPointInSphere() { + // Adapted from https://karthikkaranth.me/blog/generating-random-points-in-a-sphere/ + + auto u = ::librapid::random(); // [0, 1) + auto v = ::librapid::random(); // [0, 1) + auto theta = u * 2 * PI; + auto phi = ::librapid::acos(2 * v - 1); + auto r = ::librapid::cbrt(random()); + auto sinTheta = ::librapid::sin(theta); + auto cosTheta = ::librapid::cos(theta); + auto sinPhi = ::librapid::sin(phi); + auto cosPhi = ::librapid::cos(phi); + auto x = r * sinPhi * cosTheta; + auto y = r * sinPhi * sinTheta; + auto z = r * cosPhi; + return {x, y, z}; + } } // namespace librapid #endif // LIBRAPID_MATH_VECTOR_OLD_HPP \ No newline at end of file diff --git a/librapid/include/librapid/math/vectorForward.hpp b/librapid/include/librapid/math/vectorForward.hpp index a825195f..0d53203f 100644 --- a/librapid/include/librapid/math/vectorForward.hpp +++ b/librapid/include/librapid/math/vectorForward.hpp @@ -3,13 +3,13 @@ namespace librapid { namespace vectorDetail { - template + template struct GenericVectorStorage; - template + template struct SimdVectorStorage; - template + template struct VectorStorageType { using type = std::conditional_t<(typetraits::TypeInfo::packetWidth > 1), SimdVectorStorage, GenericVectorStorage>; @@ -17,18 +17,23 @@ namespace librapid { template auto vectorStorageTypeMerger() { - using Scalar0 = typename typetraits::TypeInfo::Scalar; - using Scalar1 = typename typetraits::TypeInfo::Scalar; - static constexpr size_t packetWidth0 = typetraits::TypeInfo::packetWidth; - static constexpr size_t packetWidth1 = typetraits::TypeInfo::packetWidth; - if constexpr (packetWidth0 > 1 && packetWidth1 > 1) { + using Scalar0 = typename typetraits::TypeInfo::Scalar; + using Scalar1 = typename typetraits::TypeInfo::Scalar; + static constexpr uint64_t packetWidth0 = typetraits::TypeInfo::packetWidth; + static constexpr uint64_t packetWidth1 = typetraits::TypeInfo::packetWidth; + if constexpr (typetraits::TypeInfo::type == detail::LibRapidType::Scalar) { + return Storage1 {}; + } else if constexpr (typetraits::TypeInfo::type == + detail::LibRapidType::Scalar) { + return Storage0 {}; + } else if constexpr (packetWidth0 > 1 && packetWidth1 > 1) { return SimdVectorStorage {}; } else { return GenericVectorStorage {}; } } - template + template using VectorStorage = typename VectorStorageType::type; template @@ -50,7 +55,9 @@ namespace librapid { return static_cast(*this); } - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto eval() const { return derived(); } +// LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE virtual Derived eval() const { +// return derived(); +// } LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE virtual IndexTypeConst operator[](int64_t index) const { @@ -84,13 +91,13 @@ namespace librapid { derived().str(formatter, ctx); } - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE virtual GetType _get(size_t index) const { + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE virtual GetType _get(uint64_t index) const { return derived()._get(index); } }; } // namespace vectorDetail - template + template class Vector; namespace vectorDetail { @@ -100,27 +107,35 @@ namespace librapid { template struct UnaryVecOp; - template LIBRAPID_ALWAYS_INLINE void assignImpl(Vector &dst, const BinaryVecOp &src, std::index_sequence); - template + template LIBRAPID_ALWAYS_INLINE void assignImpl(Vector &dst, const UnaryVecOp &src, std::index_sequence); - template + template LIBRAPID_ALWAYS_INLINE void assign(Vector &dst, const BinaryVecOp &src); - template + template LIBRAPID_ALWAYS_INLINE void assign(Vector &dst, const UnaryVecOp &src); } // namespace vectorDetail - template - class Vector; + namespace typetraits { + LIBRAPID_DEFINE_AS_TYPE(typename ScalarType COMMA uint64_t NumDims, + Vector); + + LIBRAPID_DEFINE_AS_TYPE(typename LHS COMMA typename RHS COMMA typename Op, + vectorDetail::BinaryVecOp); + + LIBRAPID_DEFINE_AS_TYPE(typename Val COMMA typename Op, + vectorDetail::UnaryVecOp); + } // namespace typetraits } // namespace librapid #endif // LIBRAPID_MATH_VECTOR_FORWARD_HPP \ No newline at end of file diff --git a/librapid/include/librapid/math/vectorImpl.hpp b/librapid/include/librapid/math/vectorImpl.hpp index c805c3f4..bc8ff529 100644 --- a/librapid/include/librapid/math/vectorImpl.hpp +++ b/librapid/include/librapid/math/vectorImpl.hpp @@ -8,13 +8,13 @@ namespace librapid { template struct IsVector : std::false_type {}; - template + template struct IsVector> : std::true_type {}; - template + template struct IsVector> : std::true_type {}; - template + template struct IsVector> : std::true_type {}; template @@ -23,20 +23,20 @@ namespace librapid { template struct IsVector> : std::true_type {}; - template + template struct TypeInfo> { static constexpr detail::LibRapidType type = detail::LibRapidType::Vector; using Scalar = T; using IndexType = T &; using IndexTypeConst = const T &; using GetType = const T &; + using StorageType = vectorDetail::GenericVectorStorage; + using ShapeType = std::false_type; - using StorageType = vectorDetail::GenericVectorStorage; - - static constexpr size_t length = N; + static constexpr uint64_t length = N; }; - template + template struct TypeInfo> { static constexpr detail::LibRapidType type = detail::LibRapidType::Vector; using Scalar = T; @@ -44,24 +44,30 @@ namespace librapid { using IndexType = T &; using IndexTypeConst = const T &; using GetType = Packet; + using Backend = backend::CPU; + using StorageType = vectorDetail::SimdVectorStorage; + using ShapeType = std::false_type; - using StorageType = vectorDetail::SimdVectorStorage; - - static constexpr size_t packetWidth = TypeInfo::packetWidth; - static constexpr size_t length = + static constexpr uint64_t packetWidth = TypeInfo::packetWidth; + static constexpr uint64_t length = (N + TypeInfo::packetWidth - 1) / TypeInfo::packetWidth; }; - template + template struct TypeInfo> { static constexpr detail::LibRapidType type = detail::LibRapidType::Vector; using Scalar = ScalarType; - static constexpr size_t dims = NumDims; - using StorageType = vectorDetail::VectorStorage; - static constexpr size_t length = StorageType::length; - using IndexTypeConst = typename StorageType::IndexTypeConst; - using IndexType = typename StorageType::IndexType; - using GetType = typename StorageType::GetType; + using Packet = std::false_type; + static constexpr uint64_t dims = NumDims; + using StorageType = vectorDetail::VectorStorage; + static constexpr uint64_t length = StorageType::length; + using IndexTypeConst = typename StorageType::IndexTypeConst; + using IndexType = typename StorageType::IndexType; + using GetType = typename StorageType::GetType; + using Backend = backend::CPU; + using ShapeType = std::false_type; + + static constexpr bool allowVectorisation = false; }; template @@ -70,71 +76,81 @@ namespace librapid { using ScalarLHS = typename typetraits::TypeInfo::Scalar; using ScalarRHS = typename typetraits::TypeInfo::Scalar; using Scalar = decltype(Op()(std::declval(), std::declval())); - using IndexTypeConst = Scalar; - using IndexType = Scalar; - using StorageType = typename vectorDetail::VectorStorageMerger; - static constexpr size_t dims = StorageType::dims; - static constexpr size_t length = StorageType::length; - using GetType = typename std::decay_t; + using Packet = std::false_type; + using IndexTypeConst = Scalar; + using IndexType = Scalar; + using StorageType = typename vectorDetail::VectorStorageMerger; + static constexpr uint64_t dims = StorageType::dims; + static constexpr uint64_t length = StorageType::length; + using GetType = typename std::decay_t; + using Backend = backend::CPU; + using ShapeType = std::false_type; + + static constexpr bool allowVectorisation = false; }; template struct TypeInfo> { static constexpr detail::LibRapidType type = detail::LibRapidType::Vector; using Scalar = typename typetraits::TypeInfo::Scalar; + using Packet = std::false_type; using IndexTypeConst = Scalar; using IndexType = Scalar; - using StorageType = typename vectorDetail::VectorStorage; - static constexpr size_t dims = StorageType::dims; - static constexpr size_t length = StorageType::length; - using GetType = typename std::decay_t; + using StorageType = typename vectorDetail::VectorStorage; + static constexpr uint64_t dims = StorageType::dims; + static constexpr uint64_t length = StorageType::length; + using GetType = typename std::decay_t; + using Backend = backend::CPU; + + static constexpr bool allowVectorisation = false; }; } // namespace typetraits namespace vectorDetail { - template + template LIBRAPID_ALWAYS_INLINE void vectorStorageAssigner(std::index_sequence, GenericVectorStorage &dst, const Args &...args) { ((dst[Indices] = args), ...); } - template + template LIBRAPID_ALWAYS_INLINE void vectorStorageAssigner(std::index_sequence, SimdVectorStorage &dst, const Args &...args) { ((dst.data.scalar[Indices] = args), ...); } - template + template LIBRAPID_ALWAYS_INLINE void vectorStorageAssigner(std::index_sequence, GenericVectorStorage &dst, const GenericVectorStorage &src) { ((dst[Indices] = src[Indices]), ...); } - template + template LIBRAPID_ALWAYS_INLINE void vectorStorageAssigner(std::index_sequence, GenericVectorStorage &dst, const SimdVectorStorage &src) { ((dst[Indices] = src.data.scalar[Indices]), ...); } - template + template LIBRAPID_ALWAYS_INLINE void vectorStorageAssigner(std::index_sequence, SimdVectorStorage &dst, const GenericVectorStorage &src) { ((dst.data.scalar[Indices] = src[Indices]), ...); } - template + template LIBRAPID_ALWAYS_INLINE void - vectorStorageAssigner_simdHelper(std::index_sequence, SimdVectorStorage &dst, - const SimdVectorStorage &src) { + vectorStorageAssigner_simdHelper(std::index_sequence, + SimdVectorStorage &dst, + const SimdVectorStorage &src) { ((dst.data.simd[Indices] = src.data.simd[Indices]), ...); } - template + template LIBRAPID_ALWAYS_INLINE void vectorStorageAssigner(std::index_sequence, SimdVectorStorage &dst, const SimdVectorStorage &src) { @@ -144,19 +160,20 @@ namespace librapid { // packets. if constexpr (std::is_same_v) { - constexpr size_t packetWidth = typetraits::TypeInfo::packetWidth; - constexpr size_t length = (N + packetWidth - 1) / packetWidth; - vectorStorageAssigner_simdHelper(std::make_index_sequence(), dst, src); + constexpr uint64_t packetWidth = typetraits::TypeInfo::packetWidth; + constexpr uint64_t length = (N + packetWidth - 1) / packetWidth; + vectorStorageAssigner_simdHelper( + std::make_index_sequence(length)>(), dst, src); } else { ((dst.data.scalar[Indices] = src.data.scalar[Indices]), ...); } } - template + template struct GenericVectorStorage { - using Scalar = ScalarType; - static constexpr size_t dims = NumDims; - static constexpr size_t length = typetraits::TypeInfo::length; + using Scalar = ScalarType; + static constexpr uint64_t dims = NumDims; + static constexpr uint64_t length = typetraits::TypeInfo::length; using IndexType = typename typetraits::TypeInfo::IndexType; using IndexTypeConst = typename typetraits::TypeInfo::IndexTypeConst; @@ -177,7 +194,7 @@ namespace librapid { template GenericVectorStorage(const T &other) { - for (size_t i = 0; i < length; ++i) { data[i] = other[i]; } + for (uint64_t i = 0; i < length; ++i) { data[i] = other[i]; } } template @@ -186,8 +203,10 @@ namespace librapid { "Initializer list for Vector is too long ({} > {})", other.size(), dims); - const size_t minDims = (other.size() < dims) ? other.size() : dims; - for (size_t i = 0; i < minDims; ++i) { this->operator[](i) = *(other.begin() + i); } + const uint64_t minDims = (other.size() < dims) ? other.size() : dims; + for (uint64_t i = 0; i < minDims; ++i) { + this->operator[](i) = *(other.begin() + i); + } } template @@ -196,8 +215,8 @@ namespace librapid { "Initializer list for Vector is too long ({} > {})", other.size(), dims); - const size_t minDims = (other.size() < dims) ? other.size() : dims; - for (size_t i = 0; i < minDims; ++i) { this->operator[](i) = other[i]; } + const uint64_t minDims = (other.size() < dims) ? other.size() : dims; + for (uint64_t i = 0; i < minDims; ++i) { this->operator[](i) = other[i]; } } LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE IndexTypeConst @@ -219,17 +238,17 @@ namespace librapid { LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Scalar sum() const { Scalar sum = Scalar(0); - for (size_t i = 0; i < dims; ++i) { sum += data[i]; } + for (uint64_t i = 0; i < dims; ++i) { sum += data[i]; } return sum; } LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Scalar sum2() const { Scalar sum = Scalar(0); - for (size_t i = 0; i < dims; ++i) { sum += data[i] * data[i]; } + for (uint64_t i = 0; i < dims; ++i) { sum += data[i] * data[i]; } return sum; } - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE const Scalar &_get(size_t index) const { + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE const Scalar &_get(uint64_t index) const { LIBRAPID_ASSERT(index >= 0 && index < dims, "Index {} out of bounds for Vector of length {}", index, @@ -237,7 +256,7 @@ namespace librapid { return data[index]; } - LIBRAPID_ALWAYS_INLINE void _set(size_t index, const Scalar &value) { + LIBRAPID_ALWAYS_INLINE void _set(uint64_t index, const Scalar &value) { LIBRAPID_ASSERT(index >= 0 && index < dims, "Index {} out of bounds for Vector of length {}", index, @@ -250,12 +269,12 @@ namespace librapid { /// equal to \f$(N + L - 1) / L\f$, where \f$L\f$ is the packet width of the scalar type. /// \tparam Scalar_ The scalar type to store /// \tparam N The number of scalars to store - template + template union ScalarToSimd { - using Scalar = Scalar_; - using Packet = typename typetraits::TypeInfo::Packet; - static constexpr size_t packetWidth = typetraits::TypeInfo::packetWidth; - static constexpr size_t length = (N + packetWidth - 1) / packetWidth; + using Scalar = Scalar_; + using Packet = typename typetraits::TypeInfo::Packet; + static constexpr uint64_t packetWidth = typetraits::TypeInfo::packetWidth; + static constexpr uint64_t length = (N + packetWidth - 1) / packetWidth; #if defined(LIBRAPID_NATIVE_ARCH) alignas(LIBRAPID_MEM_ALIGN) std::array scalar; @@ -266,13 +285,13 @@ namespace librapid { #endif }; - template + template struct SimdVectorStorage { - using Scalar = ScalarType; - static constexpr size_t dims = NumDims; - using Packet = typename typetraits::TypeInfo::Packet; - static constexpr size_t packetWidth = typetraits::TypeInfo::packetWidth; - static constexpr size_t length = (dims + packetWidth - 1) / packetWidth; + using Scalar = ScalarType; + static constexpr uint64_t dims = NumDims; + using Packet = typename typetraits::TypeInfo::Packet; + static constexpr uint64_t packetWidth = typetraits::TypeInfo::packetWidth; + static constexpr uint64_t length = (dims + packetWidth - 1) / packetWidth; using IndexType = typename typetraits::TypeInfo::IndexType; using IndexTypeConst = typename typetraits::TypeInfo::IndexTypeConst; @@ -285,9 +304,9 @@ namespace librapid { template explicit SimdVectorStorage(Args... args) { - constexpr size_t minLength = (sizeof...(Args) < dims) ? sizeof...(Args) : dims; + constexpr uint64_t minLength = (sizeof...(Args) < dims) ? sizeof...(Args) : dims; vectorDetail::vectorStorageAssigner( - std::make_index_sequence(), *this, args...); + std::make_index_sequence(minLength)>(), *this, args...); } template @@ -296,8 +315,8 @@ namespace librapid { "Initializer list for Vector is too long ({} > {})", other.size(), dims); - const size_t minDims = (other.size() < dims) ? other.size() : dims; - for (size_t i = 0; i < minDims; ++i) { data.scalar[i] = *(other.begin() + i); } + const uint64_t minDims = (other.size() < dims) ? other.size() : dims; + for (uint64_t i = 0; i < minDims; ++i) { data.scalar[i] = *(other.begin() + i); } } template @@ -306,8 +325,8 @@ namespace librapid { "Initializer list for Vector is too long ({} > {})", other.size(), dims); - const size_t minDims = (other.size() < dims) ? other.size() : dims; - for (size_t i = 0; i < minDims; ++i) { data.scalar[i] = other[i]; } + const uint64_t minDims = (other.size() < dims) ? other.size() : dims; + for (uint64_t i = 0; i < minDims; ++i) { data.scalar[i] = other[i]; } } LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE IndexTypeConst @@ -329,19 +348,19 @@ namespace librapid { LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto sum() const -> Scalar { Packet sum = Packet(0); - for (size_t i = 0; i < length; ++i) { sum += data.simd[i]; } + for (uint64_t i = 0; i < length; ++i) { sum += data.simd[i]; } // return sum.sum(); return xsimd::reduce_add(sum); } LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto sum2() const -> Scalar { Packet sum = Packet(0); - for (size_t i = 0; i < length; ++i) { sum += data.simd[i] * data.simd[i]; } + for (uint64_t i = 0; i < length; ++i) { sum += data.simd[i] * data.simd[i]; } // return sum.sum(); return xsimd::reduce_add(sum); } - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE const Packet &_get(size_t index) const { + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE const Packet &_get(uint64_t index) const { LIBRAPID_ASSERT(index >= 0 && index < dims, "Index {} out of bounds for Vector of length {}", index, @@ -349,7 +368,7 @@ namespace librapid { return data.simd[index]; } - LIBRAPID_ALWAYS_INLINE void _set(size_t index, const Packet &value) { + LIBRAPID_ALWAYS_INLINE void _set(uint64_t index, const Packet &value) { LIBRAPID_ASSERT(index >= 0 && index < dims, "Index {} out of bounds for Vector of length {}", index, @@ -360,25 +379,25 @@ namespace librapid { template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE constexpr auto - scalarSubscriptHelper(const T &val, size_t index) { + scalarSubscriptHelper(const T &val, uint64_t index) { return val; } - template + template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE constexpr auto - scalarSubscriptHelper(const Vector &val, size_t index) { + scalarSubscriptHelper(const Vector &val, uint64_t index) { return val[index]; } template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE constexpr auto - scalarSubscriptHelper(const BinaryVecOp &val, size_t index) { + scalarSubscriptHelper(const BinaryVecOp &val, uint64_t index) { return val[index]; } template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE constexpr auto - scalarSubscriptHelper(const UnaryVecOp &val, size_t index) { + scalarSubscriptHelper(const UnaryVecOp &val, uint64_t index) { return val[index]; } @@ -388,13 +407,13 @@ namespace librapid { return val; } - template + template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto constexpr scalarGetHelper( const Vector &val, size_t index) { return val._get(index); } - template + template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto constexpr scalarGetHelper(Vector &val, size_t index) { @@ -419,7 +438,7 @@ namespace librapid { using type = std::false_type; }; - template + template struct VectorScalarStorageExtractor> { using type = typename typetraits::TypeInfo>::StorageType; }; @@ -436,35 +455,35 @@ namespace librapid { template struct VectorScalarDimensionExtractor { - static constexpr size_t value = 0; + static constexpr uint64_t value = 0; }; - template + template struct VectorScalarDimensionExtractor> { - static constexpr size_t value = NumDims; + static constexpr uint64_t value = NumDims; }; template struct VectorScalarDimensionExtractor> { - static constexpr size_t value = BinaryVecOp::dims; + static constexpr uint64_t value = BinaryVecOp::dims; }; template struct VectorScalarDimensionExtractor> { - static constexpr size_t value = UnaryVecOp::dims; + static constexpr uint64_t value = UnaryVecOp::dims; }; } // namespace vectorDetail - template + template class Vector : public vectorDetail::VectorBase> { public: - using Scalar = ScalarType; - static constexpr size_t dims = NumDims; - using StorageType = vectorDetail::VectorStorage; - static constexpr size_t length = StorageType::length; - using IndexTypeConst = typename StorageType::IndexTypeConst; - using IndexType = typename StorageType::IndexType; - using GetType = typename StorageType::GetType; + using Scalar = ScalarType; + static constexpr uint64_t dims = NumDims; + using StorageType = vectorDetail::VectorStorage; + static constexpr uint64_t length = StorageType::length; + using IndexTypeConst = typename StorageType::IndexTypeConst; + using IndexType = typename StorageType::IndexType; + using GetType = typename StorageType::GetType; Vector() = default; Vector(const Vector &other) = default; @@ -479,7 +498,7 @@ namespace librapid { template explicit Vector(const std::vector &args) : m_data(args) {} - template + template explicit Vector(const Vector &other) { *this = other.template cast(); } @@ -498,27 +517,29 @@ namespace librapid { LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE static auto one() -> Vector { Vector ret; - for (size_t i = 0; i < dims; ++i) { ret[i] = Scalar(1); } + for (uint64_t i = 0; i < dims; ++i) { ret[i] = Scalar(1); } return ret; } LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE static auto full(Scalar val) -> Vector { Vector ret; - for (size_t i = 0; i < dims; ++i) { ret[i] = val; } + for (uint64_t i = 0; i < dims; ++i) { ret[i] = val; } return ret; } LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE static auto random(Scalar lower = 0, Scalar upper = 1) { Vector ret; - for (size_t i = 0; i < dims; ++i) { ret[i] = ::librapid::random(lower, upper); } + for (uint64_t i = 0; i < dims; ++i) { + ret[i] = ::librapid::random(lower, upper); + } return ret; } LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE static auto random(const Vector &lower = Vector::zero(), const Vector &upper = Vector::one()) { Vector ret; - for (size_t i = 0; i < dims; ++i) { + for (uint64_t i = 0; i < dims; ++i) { ret[i] = ::librapid::random(lower[i], upper[i]); } return ret; @@ -538,7 +559,7 @@ namespace librapid { auto operator=(const Vector &other) -> Vector & = default; auto operator=(Vector &&other) noexcept -> Vector & = default; - template + template auto operator=(const Vector &other) -> Vector & { *this = other.template cast(); return *this; @@ -567,17 +588,17 @@ namespace librapid { LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Vector eval() const { return *this; } - template + template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto cast() const { - using NewVectorType = Vector; - constexpr size_t minDims = (NewVectorType::dims < dims) ? NewVectorType::dims : dims; + using NewVectorType = Vector; + constexpr uint64_t minDims = (NewVectorType::dims < dims) ? NewVectorType::dims : dims; NewVectorType ret; vectorDetail::vectorStorageAssigner( - std::make_index_sequence(), ret.storage(), m_data); + std::make_index_sequence(minDims)>(), ret.storage(), m_data); return ret; } - template + template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE operator Vector() const { return cast(); } @@ -601,7 +622,7 @@ namespace librapid { // LIBRAPID_NODISCARD std::string str(const std::string &format) const override { // std::string ret = "("; - // for (size_t i = 0; i < dims; ++i) { + // for (uint64_t i = 0; i < dims; ++i) { // ret += fmt::format(format, m_data[i]); // if (i != dims - 1) { ret += ", "; } // } @@ -612,7 +633,7 @@ namespace librapid { template void str(const fmt::formatter &formatter, Ctx &ctx) const { fmt::format_to(ctx.out(), "("); - for (size_t i = 0; i < dims; ++i) { + for (uint64_t i = 0; i < dims; ++i) { formatter.format(m_data[i], ctx); if (i != dims - 1) { fmt::format_to(ctx.out(), ", "); } } @@ -624,11 +645,11 @@ namespace librapid { } LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE StorageType &storage() { return m_data; } - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE GetType _get(size_t index) const override { + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE GetType _get(uint64_t index) const override { return m_data._get(index); } - LIBRAPID_ALWAYS_INLINE void _set(size_t index, const GetType &value) { + LIBRAPID_ALWAYS_INLINE void _set(uint64_t index, const GetType &value) { m_data._set(index, value); } @@ -639,12 +660,12 @@ namespace librapid { namespace vectorDetail { template struct BinaryVecOp : public VectorBase> { - using Scalar = typename typetraits::TypeInfo::Scalar; - using StorageLHS = typename VectorScalarStorageExtractor::type; - using StorageRHS = typename VectorScalarStorageExtractor::type; - using StorageType = VectorStorageMerger; - static constexpr size_t dims = StorageType::dims; - static constexpr size_t length = StorageType::length; + using Scalar = typename typetraits::TypeInfo::Scalar; + using StorageLHS = typename VectorScalarStorageExtractor::type; + using StorageRHS = typename VectorScalarStorageExtractor::type; + using StorageType = VectorStorageMerger; + static constexpr uint64_t dims = StorageType::dims; + static constexpr uint64_t length = StorageType::length; using IndexTypeConst = typename typetraits::TypeInfo::IndexTypeConst; using IndexType = typename typetraits::TypeInfo::IndexType; using GetType = typename typetraits::TypeInfo::GetType; @@ -668,45 +689,40 @@ namespace librapid { return result; } - template + template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto cast() const { return eval().template cast(); } - template + template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE operator Vector() const { return cast(); } - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE IndexType - operator[](int64_t index) const override { + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE IndexType operator[](int64_t index) const { return op(scalarSubscriptHelper(left, index), scalarSubscriptHelper(right, index)); } - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE IndexType operator[](int64_t index) override { + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE IndexType operator[](int64_t index) { return op(scalarSubscriptHelper(left, index), scalarSubscriptHelper(right, index)); } - // LIBRAPID_NODISCARD std::string str(const std::string &format) const override - //{ return eval().str(format); - // } - template void str(const fmt::formatter &formatter, Ctx &ctx) const { eval().str(formatter, ctx); } - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE GetType _get(size_t index) const override { + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE GetType _get(uint64_t index) const { return op(scalarGetHelper(left, index), scalarGetHelper(right, index)); } }; template struct UnaryVecOp : public VectorBase> { - using Scalar = typename typetraits::TypeInfo::Scalar; - using StorageType = typename VectorScalarStorageExtractor::type; - static constexpr size_t dims = StorageType::dims; - static constexpr size_t length = StorageType::length; + using Scalar = typename typetraits::TypeInfo::Scalar; + using StorageType = typename VectorScalarStorageExtractor::type; + static constexpr uint64_t dims = StorageType::dims; + static constexpr uint64_t length = StorageType::length; using IndexTypeConst = typename typetraits::TypeInfo::IndexTypeConst; using IndexType = typename typetraits::TypeInfo::IndexType; using GetType = typename typetraits::TypeInfo::GetType; @@ -728,12 +744,12 @@ namespace librapid { return result; } - template + template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto cast() const { return eval().template cast(); } - template + template LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE operator Vector() const { return cast(); } @@ -756,12 +772,12 @@ namespace librapid { eval().str(formatter, ctx); } - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE GetType _get(size_t index) const override { + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE GetType _get(uint64_t index) const override { return op(scalarGetHelper(val, index)); } }; - template LIBRAPID_ALWAYS_INLINE void assignImpl(Vector &dst, const BinaryVecOp &src, @@ -772,37 +788,37 @@ namespace librapid { ...); } - template + template LIBRAPID_ALWAYS_INLINE void assignImpl(Vector &dst, const UnaryVecOp &src, std::index_sequence) { ((dst._set(Indices, src.op(scalarGetHelper(src.val, Indices)))), ...); } - template + template LIBRAPID_ALWAYS_INLINE void assign(Vector &dst, const BinaryVecOp &src) { using ScalarDst = typename typetraits::TypeInfo>::Scalar; using ScalarSrc = typename typetraits::TypeInfo>::Scalar; if constexpr (std::is_same_v) { - constexpr size_t lengthDst = Vector::length; - constexpr size_t lengthSrc = BinaryVecOp::length; - constexpr size_t minLength = (lengthDst < lengthSrc) ? lengthDst : lengthSrc; - assignImpl(dst, src, std::make_index_sequence()); + constexpr uint64_t lengthDst = Vector::length; + constexpr uint64_t lengthSrc = BinaryVecOp::length; + constexpr uint64_t minLength = (lengthDst < lengthSrc) ? lengthDst : lengthSrc; + assignImpl(dst, src, std::make_index_sequence(minLength)>()); } else { dst = src.template cast(); } } - template + template LIBRAPID_ALWAYS_INLINE void assign(Vector &dst, const UnaryVecOp &src) { using ScalarDst = typename typetraits::TypeInfo>::Scalar; using ScalarSrc = typename typetraits::TypeInfo>::Scalar; if constexpr (std::is_same_v) { - constexpr size_t lengthDst = Vector::length; - constexpr size_t lengthSrc = UnaryVecOp::length; - constexpr size_t minLength = (lengthDst < lengthSrc) ? lengthDst : lengthSrc; - assignImpl(dst, src, std::make_index_sequence()); + constexpr uint64_t lengthDst = Vector::length; + constexpr uint64_t lengthSrc = UnaryVecOp::length; + constexpr uint64_t minLength = (lengthDst < lengthSrc) ? lengthDst : lengthSrc; + assignImpl(dst, src, std::make_index_sequence(minLength)>()); } else { dst = src.template cast(); } @@ -819,22 +835,22 @@ namespace librapid { // return static_cast(val); // } - template + template constexpr auto scalarVectorCaster(const T &val) { return static_cast(val); } - template + template constexpr auto scalarVectorCaster(const Vector &val) { return val.template cast(); } - template + template constexpr auto scalarVectorCaster(const BinaryVecOp &val) { return val.template cast(); } - template + template constexpr auto scalarVectorCaster(const UnaryVecOp &val) { return val.template cast(); } @@ -850,8 +866,10 @@ namespace librapid { \ template::value || \ - typetraits::IsVector::value, \ + typename std::enable_if_t<(typetraits::IsVector::value || \ + typetraits::IsVector::value) && \ + (!typetraits::IsArrayContainer::value && \ + !typetraits::IsArrayContainer::value), \ int> = 0> \ LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator OP_(const LHS &lhs, const RHS &rhs) { \ using namespace ::librapid::vectorDetail; \ @@ -863,9 +881,9 @@ namespace librapid { return BinaryVecOp {lhs, rhs, Op {}}; \ } else { \ using Scalar = decltype(std::declval() + std::declval()); \ - constexpr size_t dimsLhs = VectorScalarDimensionExtractor::value; \ - constexpr size_t dimsRhs = VectorScalarDimensionExtractor::value; \ - constexpr size_t maxDims = (dimsLhs > dimsRhs) ? dimsLhs : dimsRhs; \ + constexpr uint64_t dimsLhs = VectorScalarDimensionExtractor::value; \ + constexpr uint64_t dimsRhs = VectorScalarDimensionExtractor::value; \ + constexpr uint64_t maxDims = (dimsLhs > dimsRhs) ? dimsLhs : dimsRhs; \ return BinaryVecOp {scalarVectorCaster(lhs), \ scalarVectorCaster(rhs), \ Op {}}; \ @@ -884,7 +902,6 @@ namespace librapid { \ template::value, int> = 0> \ LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto OP_NAME_(const Val &val) { \ - using namespace ::librapid::vectorDetail; \ using Op = NAME_; \ return ::librapid::vectorDetail::UnaryVecOp {val, Op {}}; \ } @@ -944,7 +961,7 @@ namespace librapid { } // namespace vectorDetail #define VECTOR_FUNC_IMPL_DEF(NAME_) \ - template \ + template \ auto NAME_(const Vector &vec) { \ return vectorDetail::UnaryVecOp {vec, vectorDetail::Vector_##NAME_ {}}; \ } \ @@ -1047,7 +1064,7 @@ struct fmt::formatter, Char> { } }; -template +template struct fmt::formatter, Char> { using Base = fmt::formatter; Base m_base; @@ -1058,7 +1075,7 @@ struct fmt::formatter, Char> { } template - auto format(const librapid::Vector &vec, FormatContext &ctx) { + auto format(const librapid::Vector &vec, FormatContext &ctx) const { vec.str(m_base, ctx); return ctx.out(); } diff --git a/librapid/vendor/fmt b/librapid/vendor/fmt index 130cf54c..d9063baf 160000 --- a/librapid/vendor/fmt +++ b/librapid/vendor/fmt @@ -1 +1 @@ -Subproject commit 130cf54cbc77abf0c8200a1206638cb70c9e26f1 +Subproject commit d9063baf227882da0f48c761abcbb08247eb1296