Program Listing for File operations.hpp#
↰ Return to documentation for file (librapid/include/librapid/array/operations.hpp)
#ifndef LIBRAPID_ARRAY_OPERATIONS_HPP
#define LIBRAPID_ARRAY_OPERATIONS_HPP
#define LIBRAPID_BINARY_FUNCTOR(NAME_, OP_) \
struct NAME_ { \
template<typename T, typename V> \
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator()(const T &lhs, \
const V &rhs) const { \
return lhs OP_ rhs; \
} \
\
template<typename Packet> \
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto packet(const Packet &lhs, \
const Packet &rhs) const { \
return lhs OP_ rhs; \
} \
}
#define LIBRAPID_BINARY_COMPARISON_FUNCTOR(NAME_, OP_) \
struct NAME_ { \
template<typename T, typename V> \
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator()(const T &lhs, \
const V &rhs) const { \
return (typename std::common_type_t<T, V>)(lhs OP_ rhs); \
} \
\
template<typename Packet> \
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto packet(const Packet &lhs, \
const Packet &rhs) const { \
return Packet(lhs OP_ rhs); \
} \
}
#define LIBRAPID_UNARY_KERNEL_GETTER \
template<typename... Args> \
static constexpr const char *getKernelName(std::tuple<Args...> args) { \
static_assert(sizeof...(Args) == 1, "Invalid number of arguments for unary operation"); \
return kernelName; \
}
#define LIBRAPID_BINARY_KERNEL_GETTER \
template<typename T1, typename T2> \
static constexpr const char *getKernelNameImpl(std::tuple<T1, T2> args) { \
if constexpr (TypeInfo<std::decay_t<T1>>::type != detail::LibRapidType::Scalar && \
TypeInfo<std::decay_t<T2>>::type != detail::LibRapidType::Scalar) { \
return kernelName; \
} else if constexpr (TypeInfo<std::decay_t<T1>>::type == detail::LibRapidType::Scalar) { \
return kernelNameScalarLhs; \
} else if constexpr (TypeInfo<std::decay_t<T2>>::type == detail::LibRapidType::Scalar) { \
return kernelNameScalarRhs; \
} else { \
return kernelName; \
} \
} \
\
template<typename... Args> \
static constexpr const char *getKernelName(std::tuple<Args...> args) { \
static_assert(sizeof...(Args) == 2, "Invalid number of arguments for binary operation"); \
return getKernelNameImpl(args); \
}
#define LIBRAPID_UNARY_SHAPE_EXTRACTOR \
template<typename... Args> \
LIBRAPID_NODISCARD static LIBRAPID_ALWAYS_INLINE auto getShape( \
const std::tuple<Args...> &args) { \
static_assert(sizeof...(Args) == 1, "Invalid number of arguments for unary operation"); \
return std::get<0>(args).shape(); \
}
#define LIBRAPID_BINARY_SHAPE_EXTRACTOR \
template<typename First, typename Second> \
LIBRAPID_NODISCARD static LIBRAPID_ALWAYS_INLINE auto getShapeImpl( \
const std::tuple<First, Second> &tup) { \
if constexpr (TypeInfo<std::decay_t<First>>::type != detail::LibRapidType::Scalar && \
TypeInfo<std::decay_t<Second>>::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<std::decay_t<First>>::type == \
detail::LibRapidType::Scalar) { \
return std::get<1>(tup).shape(); \
} else { \
return std::get<0>(tup).shape(); \
} \
} \
\
template<typename... Args> \
LIBRAPID_NODISCARD static LIBRAPID_ALWAYS_INLINE auto getShape( \
const std::tuple<Args...> &args) { \
static_assert(sizeof...(Args) == 2, "Invalid number of arguments for binary operation"); \
return getShapeImpl(args); \
}
#define LIBRAPID_UNARY_FUNCTOR(NAME, OP) \
struct NAME { \
template<typename T> \
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator()(const T &arg) const { \
return (T)(OP(arg)); \
} \
\
template<typename Packet> \
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto packet(const Packet &arg) const { \
return OP(arg); \
} \
};
namespace librapid {
namespace detail {
template<typename desc, typename Functor, typename... Args>
auto makeFunction(Args &&...args) {
using OperationType = Function<desc, Functor, Args...>;
return OperationType(Functor(), std::forward<Args>(args)...);
}
LIBRAPID_BINARY_FUNCTOR(Plus, +); // a + b
LIBRAPID_BINARY_FUNCTOR(Minus, -); // a - b
LIBRAPID_BINARY_FUNCTOR(Multiply, *); // a * b
LIBRAPID_BINARY_FUNCTOR(Divide, /); // a / b
LIBRAPID_UNARY_FUNCTOR(Neg, -);
LIBRAPID_BINARY_COMPARISON_FUNCTOR(LessThan, <); // a < b
LIBRAPID_BINARY_COMPARISON_FUNCTOR(GreaterThan, >); // a > b
LIBRAPID_BINARY_COMPARISON_FUNCTOR(LessThanEqual, <=); // a <= b
LIBRAPID_BINARY_COMPARISON_FUNCTOR(GreaterThanEqual, >=); // a >= b
LIBRAPID_BINARY_COMPARISON_FUNCTOR(ElementWiseEqual, ==); // a == b
LIBRAPID_BINARY_COMPARISON_FUNCTOR(ElementWiseNotEqual, !=); // a != b
LIBRAPID_UNARY_FUNCTOR(Sin, ::librapid::sin); // sin(a)
LIBRAPID_UNARY_FUNCTOR(Cos, ::librapid::cos); // cos(a)
LIBRAPID_UNARY_FUNCTOR(Tan, ::librapid::tan); // tan(a)
LIBRAPID_UNARY_FUNCTOR(Asin, ::librapid::asin); // asin(a)
LIBRAPID_UNARY_FUNCTOR(Acos, ::librapid::acos); // acos(a)
LIBRAPID_UNARY_FUNCTOR(Atan, ::librapid::atan); // atan(a)
LIBRAPID_UNARY_FUNCTOR(Sinh, ::librapid::sinh); // sinh(a)
LIBRAPID_UNARY_FUNCTOR(Cosh, ::librapid::cosh); // cosh(a)
LIBRAPID_UNARY_FUNCTOR(Tanh, ::librapid::tanh); // tanh(a)
LIBRAPID_UNARY_FUNCTOR(Exp, ::librapid::exp); // exp(a)
LIBRAPID_UNARY_FUNCTOR(Log, ::librapid::log); // log(a)
LIBRAPID_UNARY_FUNCTOR(Log2, ::librapid::log2); // log2(a)
LIBRAPID_UNARY_FUNCTOR(Log10, ::librapid::log10); // log10(a)
LIBRAPID_UNARY_FUNCTOR(Sqrt, ::librapid::sqrt); // sqrt(a)
LIBRAPID_UNARY_FUNCTOR(Cbrt, ::librapid::cbrt); // cbrt(a)
LIBRAPID_UNARY_FUNCTOR(Abs, ::librapid::abs); // abs(a)
LIBRAPID_UNARY_FUNCTOR(Floor, ::librapid::floor); // floor(a)
LIBRAPID_UNARY_FUNCTOR(Ceil, ::librapid::ceil); // ceil(a)
} // namespace detail
namespace typetraits {
template<typename Descriptor1, typename Descriptor2>
struct DescriptorMerger {
using Type = ::librapid::detail::descriptor::Combined;
};
template<typename Descriptor1>
struct DescriptorMerger<Descriptor1, Descriptor1> {
using Type = Descriptor1;
};
template<typename T>
struct DescriptorExtractor {
using Type = ::librapid::detail::descriptor::Trivial;
};
template<typename ShapeType, typename StorageType>
struct DescriptorExtractor<array::ArrayContainer<ShapeType, StorageType>> {
using Type = ::librapid::detail::descriptor::Trivial;
};
template<typename T, typename S>
struct DescriptorExtractor<array::GeneralArrayView<T, S>> {
using Type = ::librapid::detail::descriptor::Trivial;
};
template<typename Descriptor, typename Functor, typename... Args>
struct DescriptorExtractor<::librapid::detail::Function<Descriptor, Functor, Args...>> {
using Type = Descriptor;
};
template<typename First, typename... Rest>
struct DescriptorType;
namespace impl {
template<typename... Rest>
constexpr auto descriptorExtractor() {
if constexpr (sizeof...(Rest) > 0) {
using ReturnType = typename DescriptorType<Rest...>::Type;
return ReturnType {};
} else {
using ReturnType = ::librapid::detail::descriptor::Trivial;
return ReturnType {};
}
}
} // namespace impl
template<typename First, typename... Rest>
struct DescriptorType {
using FirstType = std::decay_t<First>;
using FirstDescriptor = typename DescriptorExtractor<FirstType>::Type;
using RestDescriptor = decltype(impl::descriptorExtractor<Rest...>());
using Type = typename DescriptorMerger<FirstDescriptor, RestDescriptor>::Type;
};
template<typename... Args>
using DescriptorType_t = typename DescriptorType<Args...>::Type;
template<>
struct TypeInfo<::librapid::detail::Plus> {
static constexpr const char *name = "plus";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "addArrays";
static constexpr const char *kernelNameScalarRhs = "addArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "addArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Minus> {
static constexpr const char *name = "minus";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "subArrays";
static constexpr const char *kernelNameScalarRhs = "subArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "subArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Multiply> {
static constexpr const char *name = "multiply";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "mulArrays";
static constexpr const char *kernelNameScalarRhs = "mulArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "mulArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Divide> {
static constexpr const char *name = "divide";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "divArrays";
static constexpr const char *kernelNameScalarRhs = "divArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "divArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::LessThan> {
static constexpr const char *name = "less than";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "lessThanArrays";
static constexpr const char *kernelNameScalarRhs = "lessThanArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "lessThanArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::GreaterThan> {
static constexpr const char *name = "greater than";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "greaterThanArrays";
static constexpr const char *kernelNameScalarRhs = "greaterThanArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "greaterThanArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::LessThanEqual> {
static constexpr const char *name = "less than or equal";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "lessThanEqualArrays";
static constexpr const char *kernelNameScalarRhs = "lessThanEqualArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "lessThanEqualArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::GreaterThanEqual> {
static constexpr const char *name = "greater than or equal";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "greaterThanEqualArrays";
static constexpr const char *kernelNameScalarRhs = "greaterThanEqualArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "greaterThanEqualArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::ElementWiseEqual> {
static constexpr const char *name = "element wise equal";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "elementWiseEqualArrays";
static constexpr const char *kernelNameScalarRhs = "elementWiseEqualArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "elementWiseEqualArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::ElementWiseNotEqual> {
static constexpr const char *name = "element wise not equal";
static constexpr const char *filename = "arithmetic";
static constexpr const char *kernelName = "elementWiseNotEqualArrays";
static constexpr const char *kernelNameScalarRhs = "elementWiseNotEqualArraysScalarRhs";
static constexpr const char *kernelNameScalarLhs = "elementWiseNotEqualArraysScalarLhs";
LIBRAPID_BINARY_KERNEL_GETTER
LIBRAPID_BINARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Neg> {
static constexpr const char *name = "negate";
static constexpr const char *filename = "negate";
static constexpr const char *kernelName = "negateArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Sin> {
static constexpr const char *name = "sin";
static constexpr const char *filename = "trigonometry";
static constexpr const char *kernelName = "sinArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Cos> {
static constexpr const char *name = "cos";
static constexpr const char *filename = "trigonometry";
static constexpr const char *kernelName = "cosArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Tan> {
static constexpr const char *name = "tan";
static constexpr const char *filename = "trigonometry";
static constexpr const char *kernelName = "tanArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Asin> {
static constexpr const char *name = "arcsin";
static constexpr const char *filename = "trigonometry";
static constexpr const char *kernelName = "asinArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Acos> {
static constexpr const char *name = "arcos";
static constexpr const char *filename = "trigonometry";
static constexpr const char *kernelName = "acosArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Atan> {
static constexpr const char *name = "arctan";
static constexpr const char *filename = "trigonometry";
static constexpr const char *kernelName = "atanArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Sinh> {
static constexpr const char *name = "hyperbolic sine";
static constexpr const char *filename = "trigonometry";
static constexpr const char *kernelName = "sinhArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Cosh> {
static constexpr const char *name = "hyperbolic cosine";
static constexpr const char *filename = "trigonometry";
static constexpr const char *kernelName = "coshArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Tanh> {
static constexpr const char *name = "hyperbolic tangent";
static constexpr const char *filename = "trigonometry";
static constexpr const char *kernelName = "tanhArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Exp> {
static constexpr const char *name = "exponent";
static constexpr const char *filename = "expLogPow";
static constexpr const char *kernelName = "expArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Log> {
static constexpr const char *name = "logarithm";
static constexpr const char *filename = "expLogPow";
static constexpr const char *kernelName = "logArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Log2> {
static constexpr const char *name = "logarithm base 2";
static constexpr const char *filename = "expLogPow";
static constexpr const char *kernelName = "log2Arrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Log10> {
static constexpr const char *name = "logarithm base 10";
static constexpr const char *filename = "expLogPow";
static constexpr const char *kernelName = "log10Arrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Sqrt> {
static constexpr const char *name = "square root";
static constexpr const char *filename = "expLogPow";
static constexpr const char *kernelName = "sqrtArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Cbrt> {
static constexpr const char *name = "cube root";
static constexpr const char *filename = "expLogPow";
static constexpr const char *kernelName = "cbrtArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Abs> {
static constexpr const char *name = "absolute value";
static constexpr const char *filename = "abs";
static constexpr const char *kernelName = "absArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Floor> {
static constexpr const char *name = "floor";
static constexpr const char *filename = "floorCeilRound";
static constexpr const char *kernelName = "floorArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
template<>
struct TypeInfo<::librapid::detail::Ceil> {
static constexpr const char *name = "ceiling";
static constexpr const char *filename = "floorCeilRound";
static constexpr const char *kernelName = "ceilArrays";
LIBRAPID_UNARY_KERNEL_GETTER
LIBRAPID_UNARY_SHAPE_EXTRACTOR
};
} // namespace typetraits
namespace detail {
template<typename VAL>
constexpr bool isArrayOp() {
return (typetraits::IsArrayContainer<std::decay_t<VAL>>::value ||
typetraits::IsLibRapidType<std::decay_t<VAL>>::value);
}
template<typename LHS, typename RHS>
constexpr bool isArrayOpArray() {
return (typetraits::TypeInfo<std::decay_t<LHS>>::type != LibRapidType::Scalar) &&
(typetraits::TypeInfo<std::decay_t<RHS>>::type != LibRapidType::Scalar) &&
typetraits::IsLibRapidType<std::decay_t<LHS>>::value &&
typetraits::IsLibRapidType<std::decay_t<RHS>>::value;
}
template<typename LHS, typename RHS>
constexpr bool isArrayOpWithScalar() {
return (typetraits::IsLibRapidType<std::decay_t<LHS>>::value &&
typetraits::TypeInfo<std::decay_t<RHS>>::type == LibRapidType::Scalar) ||
(typetraits::TypeInfo<std::decay_t<LHS>>::type == LibRapidType::Scalar &&
typetraits::IsLibRapidType<std::decay_t<RHS>>::value);
}
} // namespace detail
namespace array {
#define IS_ARRAY_OP detail::isArrayOp<VAL>()
#define IS_ARRAY_OP_ARRAY detail::isArrayOpArray<LHS, RHS>()
#define IS_ARRAY_OP_WITH_SCALAR detail::isArrayOpWithScalar<LHS, RHS>()
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator+(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::Plus, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::Plus>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator+(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::Plus, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::Plus>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator-(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::Minus, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::Minus>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator-(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::Minus, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::Minus>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator*(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::Multiply, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::Multiply>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator*(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::Multiply, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::Multiply>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator/(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::Divide, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::Divide>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator/(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::Divide, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::Divide>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator<(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::LessThan, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::LessThan>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator<(LHS &&lhs, RHS &&rhs) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<LHS, RHS>, detail::LessThan, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>, detail::LessThan>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator>(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::GreaterThan, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::GreaterThan>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator>(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::GreaterThan, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::GreaterThan>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator<=(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::LessThanEqual, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::LessThanEqual>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator<=(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::LessThanEqual, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::LessThanEqual>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator>=(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::GreaterThanEqual, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::GreaterThanEqual>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator>=(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::GreaterThanEqual, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::GreaterThanEqual>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator==(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::ElementWiseEqual, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::ElementWiseEqual>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator==(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::ElementWiseEqual, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::ElementWiseEqual>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_ARRAY, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator!=(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::ElementWiseNotEqual, LHS, RHS> {
LIBRAPID_ASSERT(lhs.shape().operator==(rhs.shape()), "Shapes must be equal");
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::ElementWiseNotEqual>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class LHS, class RHS, typename std::enable_if_t<IS_ARRAY_OP_WITH_SCALAR, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator!=(LHS &&lhs, RHS &&rhs)
LIBRAPID_RELEASE_NOEXCEPT->detail::Function<typetraits::DescriptorType_t<LHS, RHS>,
detail::ElementWiseNotEqual, LHS, RHS> {
return detail::makeFunction<typetraits::DescriptorType_t<LHS, RHS>,
detail::ElementWiseNotEqual>(std::forward<LHS>(lhs),
std::forward<RHS>(rhs));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
operator-(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Neg, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Neg>(
std::forward<VAL>(val));
}
} // namespace array
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto sin(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Sin, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Sin>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto cos(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Cos, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Cos>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto tan(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Tan, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Tan>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto asin(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Asin, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Asin>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto acos(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Acos, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Acos>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto atan(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Atan, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Atan>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto sinh(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Sinh, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Sinh>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto cosh(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Cosh, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Cosh>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto tanh(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Tanh, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Tanh>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto exp(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Exp, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Exp>(
std::forward<VAL>(val));
}
// \brief Compute the natural logarithm of each element in the array
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto log(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Log, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Log>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto log10(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Log10, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Log10>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto log2(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Log2, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Log2>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto sqrt(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Sqrt, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Sqrt>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto cbrt(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Cbrt, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Cbrt>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto abs(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Abs, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Abs>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto floor(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Floor, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Floor>(
std::forward<VAL>(val));
}
template<class VAL, typename std::enable_if_t<IS_ARRAY_OP, int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto ceil(VAL &&val) LIBRAPID_RELEASE_NOEXCEPT
->detail::Function<typetraits::DescriptorType_t<VAL>, detail::Ceil, VAL> {
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Ceil>(
std::forward<VAL>(val));
}
} // namespace librapid
#endif // LIBRAPID_ARRAY_OPERATIONS_HPP