mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Allow symbols to be used in compile-time expressions.
This commit is contained in:
@@ -29,9 +29,9 @@ const int Dynamic = -1;
|
||||
*/
|
||||
const int DynamicIndex = 0xffffff;
|
||||
|
||||
/** This value means that the increment to go from one value to another in a sequence is not constant for each step.
|
||||
/** This value means that the requested value is not defined.
|
||||
*/
|
||||
const int UndefinedIncr = 0xfffffe;
|
||||
const int Undefined = 0xfffffe;
|
||||
|
||||
/** This value means +Infinity; it is currently used only as the p parameter to MatrixBase::lpNorm<int>().
|
||||
* The value Infinity there means the L-infinity norm.
|
||||
|
||||
@@ -91,6 +91,8 @@ template <typename XprType, typename RowIndices, typename ColIndices>
|
||||
class IndexedView;
|
||||
template <typename XprType, int Rows = Dynamic, int Cols = Dynamic, int Order = 0>
|
||||
class Reshaped;
|
||||
template <typename FirstType, typename SizeType, typename IncrType>
|
||||
class ArithmeticSequence;
|
||||
|
||||
template <typename MatrixType, int Size = Dynamic>
|
||||
class VectorBlock;
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
struct symbolic_last_tag {};
|
||||
|
||||
struct all_t {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
namespace placeholders {
|
||||
@@ -42,131 +45,7 @@ typedef symbolic::SymbolExpr<internal::symbolic_last_tag> last_t;
|
||||
*
|
||||
* \sa end
|
||||
*/
|
||||
static const last_t last;
|
||||
|
||||
} // namespace placeholders
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Replace symbolic last/end "keywords" by their true runtime value
|
||||
inline Index eval_expr_given_size(Index x, Index /* size */) { return x; }
|
||||
|
||||
template <int N>
|
||||
FixedInt<N> eval_expr_given_size(FixedInt<N> x, Index /*size*/) {
|
||||
return x;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
Index eval_expr_given_size(const symbolic::BaseExpr<Derived>& x, Index size) {
|
||||
return x.derived().eval(Eigen::placeholders::last = size - 1);
|
||||
}
|
||||
|
||||
// Extract increment/step at compile time
|
||||
template <typename T, typename EnableIf = void>
|
||||
struct get_compile_time_incr {
|
||||
enum { value = UndefinedIncr };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr Index get_runtime_incr(const T&) EIGEN_NOEXCEPT {
|
||||
return Index(1);
|
||||
}
|
||||
|
||||
// Analogue of std::get<0>(x), but tailored for our needs.
|
||||
template <typename T>
|
||||
EIGEN_CONSTEXPR Index first(const T& x) EIGEN_NOEXCEPT {
|
||||
return x.first();
|
||||
}
|
||||
|
||||
// IndexedViewCompatibleType/makeIndexedViewCompatible turn an arbitrary object of type T into something usable by
|
||||
// MatrixSlice The generic implementation is a no-op
|
||||
template <typename T, int XprSize, typename EnableIf = void>
|
||||
struct IndexedViewCompatibleType {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T, typename Q>
|
||||
const T& makeIndexedViewCompatible(const T& x, Index /*size*/, Q) {
|
||||
return x;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Handling of a single Index
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
struct SingleRange {
|
||||
enum { SizeAtCompileTime = 1 };
|
||||
SingleRange(Index val) : m_value(val) {}
|
||||
Index operator[](Index) const { return m_value; }
|
||||
static EIGEN_CONSTEXPR Index size() EIGEN_NOEXCEPT { return 1; }
|
||||
Index first() const EIGEN_NOEXCEPT { return m_value; }
|
||||
Index m_value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_compile_time_incr<SingleRange> {
|
||||
enum { value = 1 }; // 1 or 0 ??
|
||||
};
|
||||
|
||||
// Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operator[](int)
|
||||
// methods)
|
||||
template <typename T, int XprSize>
|
||||
struct IndexedViewCompatibleType<T, XprSize, std::enable_if_t<internal::is_integral<T>::value>> {
|
||||
// Here we could simply use Array, but maybe it's less work for the compiler to use
|
||||
// a simpler wrapper as SingleRange
|
||||
// typedef Eigen::Array<Index,1,1> type;
|
||||
typedef SingleRange type;
|
||||
};
|
||||
|
||||
template <typename T, int XprSize>
|
||||
struct IndexedViewCompatibleType<T, XprSize, std::enable_if_t<symbolic::is_symbolic<T>::value>> {
|
||||
typedef SingleRange type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<symbolic::is_symbolic<T>::value, SingleRange> makeIndexedViewCompatible(const T& id, Index size,
|
||||
SpecializedType) {
|
||||
return eval_expr_given_size(id, size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Handling of all
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
struct all_t {
|
||||
all_t() {}
|
||||
};
|
||||
|
||||
// Convert a symbolic 'all' into a usable range type
|
||||
template <int XprSize>
|
||||
struct AllRange {
|
||||
enum { SizeAtCompileTime = XprSize };
|
||||
AllRange(Index size = XprSize) : m_size(size) {}
|
||||
EIGEN_CONSTEXPR Index operator[](Index i) const EIGEN_NOEXCEPT { return i; }
|
||||
EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT { return m_size.value(); }
|
||||
EIGEN_CONSTEXPR Index first() const EIGEN_NOEXCEPT { return 0; }
|
||||
variable_if_dynamic<Index, XprSize> m_size;
|
||||
};
|
||||
|
||||
template <int XprSize>
|
||||
struct IndexedViewCompatibleType<all_t, XprSize> {
|
||||
typedef AllRange<XprSize> type;
|
||||
};
|
||||
|
||||
template <typename XprSizeType>
|
||||
inline AllRange<get_fixed_value<XprSizeType>::value> makeIndexedViewCompatible(all_t, XprSizeType size,
|
||||
SpecializedType) {
|
||||
return AllRange<get_fixed_value<XprSizeType>::value>(size);
|
||||
}
|
||||
|
||||
template <int Size>
|
||||
struct get_compile_time_incr<AllRange<Size>> {
|
||||
enum { value = 1 };
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
namespace placeholders {
|
||||
static constexpr const last_t last;
|
||||
|
||||
typedef symbolic::AddExpr<symbolic::SymbolExpr<internal::symbolic_last_tag>,
|
||||
symbolic::ValueExpr<Eigen::internal::FixedInt<1>>>
|
||||
@@ -186,28 +65,251 @@ typedef Eigen::internal::all_t all_t;
|
||||
* \sa last
|
||||
*/
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
static const auto lastp1 = last + fix<1>;
|
||||
static constexpr auto lastp1 = last + fix<1>;
|
||||
#else
|
||||
// Using a FixedExpr<1> expression is important here to make sure the compiler
|
||||
// can fully optimize the computation starting indices with zero overhead.
|
||||
static const lastp1_t lastp1(last + fix<1>());
|
||||
static constexpr lastp1_t lastp1(last + fix<1>());
|
||||
#endif
|
||||
|
||||
/** \var end
|
||||
* \ingroup Core_Module
|
||||
* \sa lastp1
|
||||
*/
|
||||
static const lastp1_t end = lastp1;
|
||||
static constexpr lastp1_t end = lastp1;
|
||||
|
||||
/** \var all
|
||||
* \ingroup Core_Module
|
||||
* Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or
|
||||
* columns
|
||||
*/
|
||||
static const Eigen::internal::all_t all;
|
||||
static constexpr Eigen::internal::all_t all;
|
||||
|
||||
} // namespace placeholders
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Evaluate a symbolic expression or constant given the "size" of an object, allowing
|
||||
// any symbols like `last` to be evaluated. The default here assumes a dynamic constant.
|
||||
template <typename Expr, int SizeAtCompileTime, typename EnableIf = void>
|
||||
struct SymbolicExpressionEvaluator {
|
||||
static constexpr Index ValueAtCompileTime = Undefined;
|
||||
static Index eval(const Expr& expr, Index /*size*/) { return static_cast<Index>(expr); }
|
||||
};
|
||||
|
||||
// Symbolic expression with size known at compile-time.
|
||||
template <typename Expr, int SizeAtCompileTime>
|
||||
struct SymbolicExpressionEvaluator<Expr, SizeAtCompileTime, std::enable_if_t<symbolic::is_symbolic<Expr>::value>> {
|
||||
static constexpr Index ValueAtCompileTime =
|
||||
Expr::Derived::eval_at_compile_time(Eigen::placeholders::last = fix<SizeAtCompileTime - 1>);
|
||||
static Index eval(const Expr& expr, Index /*size*/) {
|
||||
return expr.eval(Eigen::placeholders::last = fix<SizeAtCompileTime - 1>);
|
||||
}
|
||||
};
|
||||
|
||||
// Symbolic expression with dynamic size.
|
||||
template <typename Expr>
|
||||
struct SymbolicExpressionEvaluator<Expr, Dynamic, std::enable_if_t<symbolic::is_symbolic<Expr>::value>> {
|
||||
static constexpr Index ValueAtCompileTime = Undefined;
|
||||
static Index eval(const Expr& expr, Index size) { return expr.eval(Eigen::placeholders::last = size - 1); }
|
||||
};
|
||||
|
||||
// Fixed int.
|
||||
template <int N, int SizeAtCompileTime>
|
||||
struct SymbolicExpressionEvaluator<FixedInt<N>, SizeAtCompileTime, void> {
|
||||
static constexpr Index ValueAtCompileTime = static_cast<Index>(N);
|
||||
static Index eval(const FixedInt<N>& /*expr*/, Index /*size*/) { return ValueAtCompileTime; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Handling of generic indices (e.g. array)
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
// Potentially wrap indices in a type that is better-suited for IndexedView evaluation.
|
||||
template <typename Indices, int NestedSizeAtCompileTime, typename EnableIf = void>
|
||||
struct IndexedViewHelperIndicesWrapper {
|
||||
using type = Indices;
|
||||
static const type& CreateIndexSequence(const Indices& indices, Index /*nested_size*/) { return indices; }
|
||||
};
|
||||
|
||||
// Extract compile-time and runtime first, size, increments.
|
||||
template <typename Indices, typename EnableIf = void>
|
||||
struct IndexedViewHelper {
|
||||
static constexpr Index FirstAtCompileTime = Undefined;
|
||||
static constexpr Index SizeAtCompileTime = array_size<Indices>::value;
|
||||
static constexpr Index IncrAtCompileTime = Undefined;
|
||||
|
||||
static constexpr Index first(const Indices& indices) { return static_cast<Index>(indices[0]); }
|
||||
static constexpr Index size(const Indices& indices) { return index_list_size(indices); }
|
||||
static constexpr Index incr(const Indices& /*indices*/) { return Undefined; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Handling of ArithmeticSequence
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
template <Index FirstAtCompileTime_, Index SizeAtCompileTime_, Index IncrAtCompileTime_>
|
||||
class ArithmeticSequenceRange {
|
||||
public:
|
||||
static constexpr Index FirstAtCompileTime = FirstAtCompileTime_;
|
||||
static constexpr Index SizeAtCompileTime = SizeAtCompileTime_;
|
||||
static constexpr Index IncrAtCompileTime = IncrAtCompileTime_;
|
||||
|
||||
constexpr ArithmeticSequenceRange(Index first, Index size, Index incr) : first_{first}, size_{size}, incr_{incr} {}
|
||||
constexpr Index operator[](Index i) const { return first() + i * incr(); }
|
||||
constexpr Index first() const noexcept { return first_.value(); }
|
||||
constexpr Index size() const noexcept { return size_.value(); }
|
||||
constexpr Index incr() const noexcept { return incr_.value(); }
|
||||
|
||||
private:
|
||||
variable_if_dynamicindex<Index, int(FirstAtCompileTime)> first_;
|
||||
variable_if_dynamic<Index, int(SizeAtCompileTime)> size_;
|
||||
variable_if_dynamicindex<Index, int(IncrAtCompileTime)> incr_;
|
||||
};
|
||||
|
||||
template <typename FirstType, typename SizeType, typename IncrType, int NestedSizeAtCompileTime>
|
||||
struct IndexedViewHelperIndicesWrapper<ArithmeticSequence<FirstType, SizeType, IncrType>, NestedSizeAtCompileTime,
|
||||
void> {
|
||||
static constexpr Index EvalFirstAtCompileTime =
|
||||
SymbolicExpressionEvaluator<FirstType, NestedSizeAtCompileTime>::ValueAtCompileTime;
|
||||
static constexpr Index EvalSizeAtCompileTime =
|
||||
SymbolicExpressionEvaluator<SizeType, NestedSizeAtCompileTime>::ValueAtCompileTime;
|
||||
static constexpr Index EvalIncrAtCompileTime =
|
||||
SymbolicExpressionEvaluator<IncrType, NestedSizeAtCompileTime>::ValueAtCompileTime;
|
||||
|
||||
static constexpr Index FirstAtCompileTime =
|
||||
(int(EvalFirstAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalFirstAtCompileTime;
|
||||
static constexpr Index SizeAtCompileTime =
|
||||
(int(EvalSizeAtCompileTime) == Undefined) ? Index(Dynamic) : EvalSizeAtCompileTime;
|
||||
static constexpr Index IncrAtCompileTime =
|
||||
(int(EvalIncrAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalIncrAtCompileTime;
|
||||
|
||||
using Indices = ArithmeticSequence<FirstType, SizeType, IncrType>;
|
||||
using type = ArithmeticSequenceRange<FirstAtCompileTime, SizeAtCompileTime, IncrAtCompileTime>;
|
||||
|
||||
static type CreateIndexSequence(const Indices& indices, Index nested_size) {
|
||||
Index first =
|
||||
SymbolicExpressionEvaluator<FirstType, NestedSizeAtCompileTime>::eval(indices.firstObject(), nested_size);
|
||||
Index size =
|
||||
SymbolicExpressionEvaluator<SizeType, NestedSizeAtCompileTime>::eval(indices.sizeObject(), nested_size);
|
||||
Index incr =
|
||||
SymbolicExpressionEvaluator<IncrType, NestedSizeAtCompileTime>::eval(indices.incrObject(), nested_size);
|
||||
return type(first, size, incr);
|
||||
}
|
||||
};
|
||||
|
||||
template <Index FirstAtCompileTime_, Index SizeAtCompileTime_, Index IncrAtCompileTime_>
|
||||
struct IndexedViewHelper<ArithmeticSequenceRange<FirstAtCompileTime_, SizeAtCompileTime_, IncrAtCompileTime_>, void> {
|
||||
public:
|
||||
using Indices = ArithmeticSequenceRange<FirstAtCompileTime_, SizeAtCompileTime_, IncrAtCompileTime_>;
|
||||
static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime;
|
||||
static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime;
|
||||
static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime;
|
||||
static Index first(const Indices& indices) { return indices.first(); }
|
||||
static Index size(const Indices& indices) { return indices.size(); }
|
||||
static Index incr(const Indices& indices) { return indices.incr(); }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Handling of a single index.
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
template <Index ValueAtCompileTime>
|
||||
class SingleRange {
|
||||
public:
|
||||
static constexpr Index FirstAtCompileTime = ValueAtCompileTime;
|
||||
static constexpr Index SizeAtCompileTime = Index(1);
|
||||
static constexpr Index IncrAtCompileTime = Index(1); // Needs to be 1 to be treated as block-like.
|
||||
|
||||
constexpr SingleRange(Index v) noexcept : value_(v) {}
|
||||
constexpr Index operator[](Index) const noexcept { return first(); }
|
||||
constexpr Index first() const noexcept { return value_.value(); }
|
||||
constexpr Index size() const noexcept { return SizeAtCompileTime; }
|
||||
constexpr Index incr() const noexcept { return IncrAtCompileTime; }
|
||||
|
||||
private:
|
||||
variable_if_dynamicindex<Index, int(ValueAtCompileTime)> value_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_single_range : public std::false_type {};
|
||||
|
||||
template <Index ValueAtCompileTime>
|
||||
struct is_single_range<SingleRange<ValueAtCompileTime>> : public std::true_type {};
|
||||
|
||||
template <typename SingleIndex, int NestedSizeAtCompileTime>
|
||||
struct IndexedViewHelperIndicesWrapper<
|
||||
SingleIndex, NestedSizeAtCompileTime,
|
||||
std::enable_if_t<std::is_integral<SingleIndex>::value || symbolic::is_symbolic<SingleIndex>::value>> {
|
||||
static constexpr Index EvalValueAtCompileTime =
|
||||
SymbolicExpressionEvaluator<SingleIndex, NestedSizeAtCompileTime>::ValueAtCompileTime;
|
||||
static constexpr Index ValueAtCompileTime =
|
||||
(int(EvalValueAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalValueAtCompileTime;
|
||||
using type = SingleRange<ValueAtCompileTime>;
|
||||
static type CreateIndexSequence(const SingleIndex& index, Index nested_size) {
|
||||
return type(SymbolicExpressionEvaluator<SingleIndex, NestedSizeAtCompileTime>::eval(index, nested_size));
|
||||
}
|
||||
};
|
||||
|
||||
template <int N, int NestedSizeAtCompileTime>
|
||||
struct IndexedViewHelperIndicesWrapper<FixedInt<N>, NestedSizeAtCompileTime, void> {
|
||||
using type = SingleRange<Index(N)>;
|
||||
static type CreateIndexSequence(const FixedInt<N>& /*index*/) { return type(Index(N)); }
|
||||
};
|
||||
|
||||
template <Index ValueAtCompileTime>
|
||||
struct IndexedViewHelper<SingleRange<ValueAtCompileTime>, void> {
|
||||
using Indices = SingleRange<ValueAtCompileTime>;
|
||||
static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime;
|
||||
static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime;
|
||||
static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime;
|
||||
|
||||
static constexpr Index first(const Indices& indices) { return indices.first(); }
|
||||
static constexpr Index size(const Indices& /*indices*/) { return SizeAtCompileTime; }
|
||||
static constexpr Index incr(const Indices& /*indices*/) { return IncrAtCompileTime; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Handling of all
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
// Convert a symbolic 'all' into a usable range type
|
||||
template <Index SizeAtCompileTime_>
|
||||
class AllRange {
|
||||
public:
|
||||
static constexpr Index FirstAtCompileTime = Index(0);
|
||||
static constexpr Index SizeAtCompileTime = SizeAtCompileTime_;
|
||||
static constexpr Index IncrAtCompileTime = Index(1);
|
||||
constexpr AllRange(Index size) : size_(size) {}
|
||||
constexpr Index operator[](Index i) const noexcept { return i; }
|
||||
constexpr Index first() const noexcept { return FirstAtCompileTime; }
|
||||
constexpr Index size() const noexcept { return size_.value(); }
|
||||
constexpr Index incr() const noexcept { return IncrAtCompileTime; }
|
||||
|
||||
private:
|
||||
variable_if_dynamic<Index, int(SizeAtCompileTime)> size_;
|
||||
};
|
||||
|
||||
template <int NestedSizeAtCompileTime>
|
||||
struct IndexedViewHelperIndicesWrapper<all_t, NestedSizeAtCompileTime, void> {
|
||||
using type = AllRange<Index(NestedSizeAtCompileTime)>;
|
||||
static type CreateIndexSequence(const all_t& /*indices*/, Index nested_size) { return type(nested_size); }
|
||||
};
|
||||
|
||||
template <Index SizeAtCompileTime_>
|
||||
struct IndexedViewHelper<AllRange<SizeAtCompileTime_>, void> {
|
||||
using Indices = AllRange<SizeAtCompileTime_>;
|
||||
static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime;
|
||||
static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime;
|
||||
static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime;
|
||||
|
||||
static Index first(const Indices& indices) { return indices.first(); }
|
||||
static Index size(const Indices& indices) { return indices.size(); }
|
||||
static Index incr(const Indices& indices) { return indices.incr(); }
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_INDEXED_VIEW_HELPER_H
|
||||
|
||||
@@ -54,65 +54,60 @@ class VariableAndFixedInt;
|
||||
template <int N>
|
||||
class FixedInt {
|
||||
public:
|
||||
static const int value = N;
|
||||
EIGEN_CONSTEXPR operator int() const { return value; }
|
||||
static constexpr int value = N;
|
||||
constexpr operator int() const { return N; }
|
||||
|
||||
EIGEN_CONSTEXPR
|
||||
FixedInt() = default;
|
||||
constexpr FixedInt() = default;
|
||||
constexpr FixedInt(std::integral_constant<int, N>) {}
|
||||
|
||||
EIGEN_CONSTEXPR
|
||||
FixedInt(std::integral_constant<int, N>) {}
|
||||
|
||||
EIGEN_CONSTEXPR
|
||||
FixedInt(VariableAndFixedInt<N> other) {
|
||||
constexpr FixedInt(VariableAndFixedInt<N> other) {
|
||||
#ifndef EIGEN_INTERNAL_DEBUGGING
|
||||
EIGEN_UNUSED_VARIABLE(other);
|
||||
#endif
|
||||
eigen_internal_assert(int(other) == N);
|
||||
}
|
||||
|
||||
EIGEN_CONSTEXPR
|
||||
FixedInt<-N> operator-() const { return FixedInt<-N>(); }
|
||||
constexpr FixedInt<-N> operator-() const { return FixedInt<-N>(); }
|
||||
|
||||
template <int M>
|
||||
EIGEN_CONSTEXPR FixedInt<N + M> operator+(FixedInt<M>) const {
|
||||
constexpr FixedInt<N + M> operator+(FixedInt<M>) const {
|
||||
return FixedInt<N + M>();
|
||||
}
|
||||
|
||||
template <int M>
|
||||
EIGEN_CONSTEXPR FixedInt<N - M> operator-(FixedInt<M>) const {
|
||||
constexpr FixedInt<N - M> operator-(FixedInt<M>) const {
|
||||
return FixedInt<N - M>();
|
||||
}
|
||||
|
||||
template <int M>
|
||||
EIGEN_CONSTEXPR FixedInt<N * M> operator*(FixedInt<M>) const {
|
||||
constexpr FixedInt<N * M> operator*(FixedInt<M>) const {
|
||||
return FixedInt<N * M>();
|
||||
}
|
||||
|
||||
template <int M>
|
||||
EIGEN_CONSTEXPR FixedInt<N / M> operator/(FixedInt<M>) const {
|
||||
constexpr FixedInt<N / M> operator/(FixedInt<M>) const {
|
||||
return FixedInt<N / M>();
|
||||
}
|
||||
|
||||
template <int M>
|
||||
EIGEN_CONSTEXPR FixedInt<N % M> operator%(FixedInt<M>) const {
|
||||
constexpr FixedInt<N % M> operator%(FixedInt<M>) const {
|
||||
return FixedInt<N % M>();
|
||||
}
|
||||
|
||||
template <int M>
|
||||
EIGEN_CONSTEXPR FixedInt<N | M> operator|(FixedInt<M>) const {
|
||||
constexpr FixedInt<N | M> operator|(FixedInt<M>) const {
|
||||
return FixedInt<N | M>();
|
||||
}
|
||||
|
||||
template <int M>
|
||||
EIGEN_CONSTEXPR FixedInt<N & M> operator&(FixedInt<M>) const {
|
||||
constexpr FixedInt<N & M> operator&(FixedInt<M>) const {
|
||||
return FixedInt<N & M>();
|
||||
}
|
||||
|
||||
// Needed in C++14 to allow fix<N>():
|
||||
EIGEN_CONSTEXPR FixedInt operator()() const { return *this; }
|
||||
constexpr FixedInt operator()() const { return *this; }
|
||||
|
||||
VariableAndFixedInt<N> operator()(int val) const { return VariableAndFixedInt<N>(val); }
|
||||
constexpr VariableAndFixedInt<N> operator()(int val) const { return VariableAndFixedInt<N>(val); }
|
||||
};
|
||||
|
||||
/** \internal
|
||||
|
||||
@@ -44,6 +44,8 @@ namespace symbolic {
|
||||
|
||||
template <typename Tag>
|
||||
class Symbol;
|
||||
template <typename Tag, typename Type>
|
||||
class SymbolValue;
|
||||
template <typename Arg0>
|
||||
class NegateExpr;
|
||||
template <typename Arg1, typename Arg2>
|
||||
@@ -52,136 +54,123 @@ template <typename Arg1, typename Arg2>
|
||||
class ProductExpr;
|
||||
template <typename Arg1, typename Arg2>
|
||||
class QuotientExpr;
|
||||
|
||||
// A simple wrapper around an integral value to provide the eval method.
|
||||
// We could also use a free-function symbolic_eval...
|
||||
template <typename IndexType = Index>
|
||||
class ValueExpr {
|
||||
public:
|
||||
ValueExpr(IndexType val) : m_value(val) {}
|
||||
template <typename T>
|
||||
IndexType eval_impl(const T&) const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
protected:
|
||||
IndexType m_value;
|
||||
};
|
||||
|
||||
// Specialization for compile-time value,
|
||||
// It is similar to ValueExpr(N) but this version helps the compiler to generate better code.
|
||||
template <int N>
|
||||
class ValueExpr<internal::FixedInt<N> > {
|
||||
public:
|
||||
ValueExpr() {}
|
||||
template <typename T>
|
||||
EIGEN_CONSTEXPR Index eval_impl(const T&) const {
|
||||
return N;
|
||||
}
|
||||
};
|
||||
class ValueExpr;
|
||||
|
||||
/** \class BaseExpr
|
||||
* \ingroup Core_Module
|
||||
* Common base class of any symbolic expressions
|
||||
*/
|
||||
template <typename Derived>
|
||||
template <typename Derived_>
|
||||
class BaseExpr {
|
||||
public:
|
||||
const Derived& derived() const { return *static_cast<const Derived*>(this); }
|
||||
using Derived = Derived_;
|
||||
constexpr const Derived& derived() const { return *static_cast<const Derived*>(this); }
|
||||
|
||||
/** Evaluate the expression given the \a values of the symbols.
|
||||
*
|
||||
* \param values defines the values of the symbols, it can either be a SymbolValue or a std::tuple of SymbolValue
|
||||
* as constructed by SymbolExpr::operator= operator.
|
||||
* \param values defines the values of the symbols, as constructed by SymbolExpr::operator= operator.
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
Index eval(const T& values) const {
|
||||
return derived().eval_impl(values);
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr Index eval(const SymbolValue<Tags, Types>&... values) const {
|
||||
return derived().eval_impl(values...);
|
||||
}
|
||||
|
||||
template <typename... Types>
|
||||
Index eval(Types&&... values) const {
|
||||
return derived().eval_impl(std::make_tuple(values...));
|
||||
/** Evaluate the expression at compile time given the \a values of the symbols.
|
||||
*
|
||||
* If a value is not known at compile-time, returns Eigen::Undefined.
|
||||
*
|
||||
*/
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr Index eval_at_compile_time(const SymbolValue<Tags, Types>&...) {
|
||||
return Derived::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
|
||||
}
|
||||
|
||||
NegateExpr<Derived> operator-() const { return NegateExpr<Derived>(derived()); }
|
||||
constexpr NegateExpr<Derived> operator-() const { return NegateExpr<Derived>(derived()); }
|
||||
|
||||
AddExpr<Derived, ValueExpr<> > operator+(Index b) const { return AddExpr<Derived, ValueExpr<> >(derived(), b); }
|
||||
AddExpr<Derived, ValueExpr<> > operator-(Index a) const { return AddExpr<Derived, ValueExpr<> >(derived(), -a); }
|
||||
ProductExpr<Derived, ValueExpr<> > operator*(Index a) const {
|
||||
constexpr AddExpr<Derived, ValueExpr<>> operator+(Index b) const {
|
||||
return AddExpr<Derived, ValueExpr<>>(derived(), b);
|
||||
}
|
||||
constexpr AddExpr<Derived, ValueExpr<>> operator-(Index a) const {
|
||||
return AddExpr<Derived, ValueExpr<>>(derived(), -a);
|
||||
}
|
||||
constexpr ProductExpr<Derived, ValueExpr<>> operator*(Index a) const {
|
||||
return ProductExpr<Derived, ValueExpr<> >(derived(), a);
|
||||
}
|
||||
QuotientExpr<Derived, ValueExpr<> > operator/(Index a) const {
|
||||
constexpr QuotientExpr<Derived, ValueExpr<>> operator/(Index a) const {
|
||||
return QuotientExpr<Derived, ValueExpr<> >(derived(), a);
|
||||
}
|
||||
|
||||
friend AddExpr<Derived, ValueExpr<> > operator+(Index a, const BaseExpr& b) {
|
||||
friend constexpr AddExpr<Derived, ValueExpr<>> operator+(Index a, const BaseExpr& b) {
|
||||
return AddExpr<Derived, ValueExpr<> >(b.derived(), a);
|
||||
}
|
||||
friend AddExpr<NegateExpr<Derived>, ValueExpr<> > operator-(Index a, const BaseExpr& b) {
|
||||
friend constexpr AddExpr<NegateExpr<Derived>, ValueExpr<>> operator-(Index a, const BaseExpr& b) {
|
||||
return AddExpr<NegateExpr<Derived>, ValueExpr<> >(-b.derived(), a);
|
||||
}
|
||||
friend ProductExpr<ValueExpr<>, Derived> operator*(Index a, const BaseExpr& b) {
|
||||
friend constexpr ProductExpr<ValueExpr<>, Derived> operator*(Index a, const BaseExpr& b) {
|
||||
return ProductExpr<ValueExpr<>, Derived>(a, b.derived());
|
||||
}
|
||||
friend QuotientExpr<ValueExpr<>, Derived> operator/(Index a, const BaseExpr& b) {
|
||||
friend constexpr QuotientExpr<ValueExpr<>, Derived> operator/(Index a, const BaseExpr& b) {
|
||||
return QuotientExpr<ValueExpr<>, Derived>(a, b.derived());
|
||||
}
|
||||
|
||||
template <int N>
|
||||
AddExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>) const {
|
||||
constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator+(internal::FixedInt<N>) const {
|
||||
return AddExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >());
|
||||
}
|
||||
template <int N>
|
||||
AddExpr<Derived, ValueExpr<internal::FixedInt<-N> > > operator-(internal::FixedInt<N>) const {
|
||||
constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<-N>>> operator-(internal::FixedInt<N>) const {
|
||||
return AddExpr<Derived, ValueExpr<internal::FixedInt<-N> > >(derived(), ValueExpr<internal::FixedInt<-N> >());
|
||||
}
|
||||
template <int N>
|
||||
ProductExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator*(internal::FixedInt<N>) const {
|
||||
constexpr ProductExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator*(internal::FixedInt<N>) const {
|
||||
return ProductExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >());
|
||||
}
|
||||
template <int N>
|
||||
QuotientExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator/(internal::FixedInt<N>) const {
|
||||
constexpr QuotientExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator/(internal::FixedInt<N>) const {
|
||||
return QuotientExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >());
|
||||
}
|
||||
|
||||
template <int N>
|
||||
friend AddExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>, const BaseExpr& b) {
|
||||
friend constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator+(internal::FixedInt<N>,
|
||||
const BaseExpr& b) {
|
||||
return AddExpr<Derived, ValueExpr<internal::FixedInt<N> > >(b.derived(), ValueExpr<internal::FixedInt<N> >());
|
||||
}
|
||||
template <int N>
|
||||
friend AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N> > > operator-(internal::FixedInt<N>,
|
||||
const BaseExpr& b) {
|
||||
friend constexpr AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N>>> operator-(internal::FixedInt<N>,
|
||||
const BaseExpr& b) {
|
||||
return AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N> > >(-b.derived(),
|
||||
ValueExpr<internal::FixedInt<N> >());
|
||||
}
|
||||
template <int N>
|
||||
friend ProductExpr<ValueExpr<internal::FixedInt<N> >, Derived> operator*(internal::FixedInt<N>, const BaseExpr& b) {
|
||||
friend constexpr ProductExpr<ValueExpr<internal::FixedInt<N>>, Derived> operator*(internal::FixedInt<N>,
|
||||
const BaseExpr& b) {
|
||||
return ProductExpr<ValueExpr<internal::FixedInt<N> >, Derived>(ValueExpr<internal::FixedInt<N> >(), b.derived());
|
||||
}
|
||||
template <int N>
|
||||
friend QuotientExpr<ValueExpr<internal::FixedInt<N> >, Derived> operator/(internal::FixedInt<N>, const BaseExpr& b) {
|
||||
friend constexpr QuotientExpr<ValueExpr<internal::FixedInt<N>>, Derived> operator/(internal::FixedInt<N>,
|
||||
const BaseExpr& b) {
|
||||
return QuotientExpr<ValueExpr<internal::FixedInt<N> >, Derived>(ValueExpr<internal::FixedInt<N> >(), b.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
AddExpr<Derived, OtherDerived> operator+(const BaseExpr<OtherDerived>& b) const {
|
||||
constexpr AddExpr<Derived, OtherDerived> operator+(const BaseExpr<OtherDerived>& b) const {
|
||||
return AddExpr<Derived, OtherDerived>(derived(), b.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
AddExpr<Derived, NegateExpr<OtherDerived> > operator-(const BaseExpr<OtherDerived>& b) const {
|
||||
constexpr AddExpr<Derived, NegateExpr<OtherDerived>> operator-(const BaseExpr<OtherDerived>& b) const {
|
||||
return AddExpr<Derived, NegateExpr<OtherDerived> >(derived(), -b.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
ProductExpr<Derived, OtherDerived> operator*(const BaseExpr<OtherDerived>& b) const {
|
||||
constexpr ProductExpr<Derived, OtherDerived> operator*(const BaseExpr<OtherDerived>& b) const {
|
||||
return ProductExpr<Derived, OtherDerived>(derived(), b.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
QuotientExpr<Derived, OtherDerived> operator/(const BaseExpr<OtherDerived>& b) const {
|
||||
constexpr QuotientExpr<Derived, OtherDerived> operator/(const BaseExpr<OtherDerived>& b) const {
|
||||
return QuotientExpr<Derived, OtherDerived>(derived(), b.derived());
|
||||
}
|
||||
};
|
||||
@@ -193,21 +182,137 @@ struct is_symbolic {
|
||||
enum { value = internal::is_convertible<T, BaseExpr<T> >::value };
|
||||
};
|
||||
|
||||
// A simple wrapper around an integral value to provide the eval method.
|
||||
// We could also use a free-function symbolic_eval...
|
||||
template <typename IndexType>
|
||||
class ValueExpr : BaseExpr<ValueExpr<IndexType>> {
|
||||
public:
|
||||
constexpr ValueExpr() = default;
|
||||
constexpr ValueExpr(IndexType val) : value_(val) {}
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr IndexType eval_impl(const SymbolValue<Tags, Types>&...) const {
|
||||
return value_;
|
||||
}
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr IndexType eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
|
||||
return IndexType(Undefined);
|
||||
}
|
||||
|
||||
protected:
|
||||
IndexType value_;
|
||||
};
|
||||
|
||||
// Specialization for compile-time value,
|
||||
// It is similar to ValueExpr(N) but this version helps the compiler to generate better code.
|
||||
template <int N>
|
||||
class ValueExpr<internal::FixedInt<N>> : public BaseExpr<ValueExpr<internal::FixedInt<N>>> {
|
||||
public:
|
||||
constexpr ValueExpr() = default;
|
||||
constexpr ValueExpr(internal::FixedInt<N>) {}
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const {
|
||||
return Index(N);
|
||||
}
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
|
||||
return Index(N);
|
||||
}
|
||||
};
|
||||
|
||||
/** Represents the actual value of a symbol identified by its tag
|
||||
*
|
||||
* It is the return type of SymbolValue::operator=, and most of the time this is only way it is used.
|
||||
*/
|
||||
template <typename Tag, typename Type>
|
||||
class SymbolValue : public BaseExpr<SymbolValue<Tag, Type>> {};
|
||||
|
||||
template <typename Tag>
|
||||
class SymbolValue {
|
||||
class SymbolValue<Tag, Index> : public BaseExpr<SymbolValue<Tag, Index>> {
|
||||
public:
|
||||
constexpr SymbolValue() = default;
|
||||
|
||||
/** Default constructor from the value \a val */
|
||||
SymbolValue(Index val) : m_value(val) {}
|
||||
constexpr SymbolValue(Index val) : value_(val) {}
|
||||
|
||||
/** \returns the stored value of the symbol */
|
||||
Index value() const { return m_value; }
|
||||
constexpr Index value() const { return value_; }
|
||||
|
||||
/** \returns the stored value of the symbol at compile time, or Undefined if not known. */
|
||||
static constexpr Index value_at_compile_time() { return Index(Undefined); }
|
||||
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const {
|
||||
return value();
|
||||
}
|
||||
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
|
||||
return value_at_compile_time();
|
||||
}
|
||||
|
||||
protected:
|
||||
Index m_value;
|
||||
Index value_;
|
||||
};
|
||||
|
||||
template <typename Tag, int N>
|
||||
class SymbolValue<Tag, internal::FixedInt<N>> : public BaseExpr<SymbolValue<Tag, internal::FixedInt<N>>> {
|
||||
public:
|
||||
constexpr SymbolValue() = default;
|
||||
|
||||
/** Default constructor from the value \a val */
|
||||
constexpr SymbolValue(internal::FixedInt<N>){};
|
||||
|
||||
/** \returns the stored value of the symbol */
|
||||
constexpr Index value() const { return static_cast<Index>(N); }
|
||||
|
||||
/** \returns the stored value of the symbol at compile time, or Undefined if not known. */
|
||||
static constexpr Index value_at_compile_time() { return static_cast<Index>(N); }
|
||||
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const {
|
||||
return value();
|
||||
}
|
||||
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
|
||||
return value_at_compile_time();
|
||||
}
|
||||
};
|
||||
|
||||
// Find and return a symbol value based on the tag.
|
||||
template <typename Tag, typename... Types>
|
||||
struct EvalSymbolValueHelper;
|
||||
|
||||
// Empty base case, symbol not found.
|
||||
template <typename Tag>
|
||||
struct EvalSymbolValueHelper<Tag> {
|
||||
static constexpr Index eval_impl() {
|
||||
eigen_assert(false && "Symbol not found.");
|
||||
return Index(Undefined);
|
||||
}
|
||||
static constexpr Index eval_at_compile_time_impl() { return Index(Undefined); }
|
||||
};
|
||||
|
||||
// We found a symbol value matching the provided Tag!
|
||||
template <typename Tag, typename Type, typename... OtherTypes>
|
||||
struct EvalSymbolValueHelper<Tag, SymbolValue<Tag, Type>, OtherTypes...> {
|
||||
static constexpr Index eval_impl(const SymbolValue<Tag, Type>& symbol, const OtherTypes&...) {
|
||||
return symbol.value();
|
||||
}
|
||||
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tag, Type>& symbol, const OtherTypes&...) {
|
||||
return symbol.value_at_compile_time();
|
||||
}
|
||||
};
|
||||
|
||||
// No symbol value in first value, recursive search starting with next.
|
||||
template <typename Tag, typename T1, typename... OtherTypes>
|
||||
struct EvalSymbolValueHelper<Tag, T1, OtherTypes...> {
|
||||
static constexpr Index eval_impl(const T1&, const OtherTypes&... values) {
|
||||
return EvalSymbolValueHelper<Tag, OtherTypes...>::eval_impl(values...);
|
||||
}
|
||||
static constexpr Index eval_at_compile_time_impl(const T1&, const OtherTypes&...) {
|
||||
return EvalSymbolValueHelper<Tag, OtherTypes...>::eval_at_compile_time_impl(OtherTypes{}...);
|
||||
}
|
||||
};
|
||||
|
||||
/** Expression of a symbol uniquely identified by the template parameter type \c tag */
|
||||
@@ -217,32 +322,47 @@ class SymbolExpr : public BaseExpr<SymbolExpr<tag> > {
|
||||
/** Alias to the template parameter \c tag */
|
||||
typedef tag Tag;
|
||||
|
||||
SymbolExpr() {}
|
||||
constexpr SymbolExpr() = default;
|
||||
|
||||
/** Associate the value \a val to the given symbol \c *this, uniquely identified by its \c Tag.
|
||||
*
|
||||
* The returned object should be passed to ExprBase::eval() to evaluate a given expression with this specified
|
||||
* runtime-time value.
|
||||
*/
|
||||
SymbolValue<Tag> operator=(Index val) const { return SymbolValue<Tag>(val); }
|
||||
constexpr SymbolValue<Tag, Index> operator=(Index val) const { return SymbolValue<Tag, Index>(val); }
|
||||
|
||||
Index eval_impl(const SymbolValue<Tag>& values) const { return values.value(); }
|
||||
template <int N>
|
||||
constexpr SymbolValue<Tag, internal::FixedInt<N>> operator=(internal::FixedInt<N>) const {
|
||||
return SymbolValue<Tag, internal::FixedInt<N>>{internal::FixedInt<N>{}};
|
||||
}
|
||||
|
||||
// C++14 versions suitable for multiple symbols
|
||||
template <typename... Types>
|
||||
Index eval_impl(const std::tuple<Types...>& values) const {
|
||||
return std::get<SymbolValue<Tag> >(values).value();
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
|
||||
return EvalSymbolValueHelper<Tag, SymbolValue<Tags, Types>...>::eval_impl(values...);
|
||||
}
|
||||
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
|
||||
return EvalSymbolValueHelper<Tag, SymbolValue<Tags, Types>...>::eval_at_compile_time_impl(
|
||||
SymbolValue<Tags, Types>{}...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Arg0>
|
||||
class NegateExpr : public BaseExpr<NegateExpr<Arg0> > {
|
||||
public:
|
||||
NegateExpr(const Arg0& arg0) : m_arg0(arg0) {}
|
||||
constexpr NegateExpr() = default;
|
||||
constexpr NegateExpr(const Arg0& arg0) : m_arg0(arg0) {}
|
||||
|
||||
template <typename T>
|
||||
Index eval_impl(const T& values) const {
|
||||
return -m_arg0.eval_impl(values);
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
|
||||
return -m_arg0.eval_impl(values...);
|
||||
}
|
||||
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
|
||||
constexpr Index v = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
|
||||
return (v == Undefined) ? Undefined : -v;
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -252,11 +372,19 @@ class NegateExpr : public BaseExpr<NegateExpr<Arg0> > {
|
||||
template <typename Arg0, typename Arg1>
|
||||
class AddExpr : public BaseExpr<AddExpr<Arg0, Arg1> > {
|
||||
public:
|
||||
AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
|
||||
constexpr AddExpr() = default;
|
||||
constexpr AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
|
||||
|
||||
template <typename T>
|
||||
Index eval_impl(const T& values) const {
|
||||
return m_arg0.eval_impl(values) + m_arg1.eval_impl(values);
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
|
||||
return m_arg0.eval_impl(values...) + m_arg1.eval_impl(values...);
|
||||
}
|
||||
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
|
||||
constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
|
||||
constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
|
||||
return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 + v1;
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -267,11 +395,19 @@ class AddExpr : public BaseExpr<AddExpr<Arg0, Arg1> > {
|
||||
template <typename Arg0, typename Arg1>
|
||||
class ProductExpr : public BaseExpr<ProductExpr<Arg0, Arg1> > {
|
||||
public:
|
||||
ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
|
||||
constexpr ProductExpr() = default;
|
||||
constexpr ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
|
||||
|
||||
template <typename T>
|
||||
Index eval_impl(const T& values) const {
|
||||
return m_arg0.eval_impl(values) * m_arg1.eval_impl(values);
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
|
||||
return m_arg0.eval_impl(values...) * m_arg1.eval_impl(values...);
|
||||
}
|
||||
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
|
||||
constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
|
||||
constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
|
||||
return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 * v1;
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -282,11 +418,19 @@ class ProductExpr : public BaseExpr<ProductExpr<Arg0, Arg1> > {
|
||||
template <typename Arg0, typename Arg1>
|
||||
class QuotientExpr : public BaseExpr<QuotientExpr<Arg0, Arg1> > {
|
||||
public:
|
||||
QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
|
||||
constexpr QuotientExpr() = default;
|
||||
constexpr QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
|
||||
|
||||
template <typename T>
|
||||
Index eval_impl(const T& values) const {
|
||||
return m_arg0.eval_impl(values) / m_arg1.eval_impl(values);
|
||||
template <typename... Tags, typename... Types>
|
||||
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
|
||||
return m_arg0.eval_impl(values...) / m_arg1.eval_impl(values...);
|
||||
}
|
||||
|
||||
template <typename... Tags, typename... Types>
|
||||
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
|
||||
constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
|
||||
constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
|
||||
return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 / v1;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user