242 lines
7.9 KiB
C++
242 lines
7.9 KiB
C++
#ifndef PFOR_PFOR_EXPRESSION_EXPRESSION_H
|
|
#define PFOR_PFOR_EXPRESSION_EXPRESSION_H
|
|
|
|
#include <tuple>
|
|
|
|
#include "op.h"
|
|
#include "tag.h"
|
|
#include "../index/index.h"
|
|
#include "../index/traits.h"
|
|
#include "../tuple_view.h"
|
|
|
|
namespace pfor {
|
|
namespace expr {
|
|
|
|
struct IgnoredId;
|
|
|
|
template<typename...> struct Expression;
|
|
template<typename...> struct Constant;
|
|
|
|
template<typename T>
|
|
struct Constant<T> {
|
|
using IsExpression = tag::Expression;
|
|
using DataType = T;
|
|
using Id = IgnoredId;
|
|
using ThisType = Constant<DataType, Id>;
|
|
|
|
DataType data;
|
|
|
|
Constant() = delete;
|
|
Constant(DataType const& data): data{data} {}
|
|
Constant(ThisType const& e): data{e.data} {}
|
|
|
|
inline DataType const& eval() { return data; }
|
|
inline DataType const& operator[](index::Value) const { return data; }
|
|
|
|
template<typename Index, std::enable_if_t<index::isIndex<Index>>* = nullptr>
|
|
inline ThisType& operator[](Index const&) { return *this; }
|
|
};
|
|
|
|
template<typename T>
|
|
struct Constant<T const*> {
|
|
using IsExpression = tag::Expression;
|
|
using DataType = T const*;
|
|
using Id = IgnoredId;
|
|
using ThisType = Constant<DataType, Id>;
|
|
|
|
DataType data;
|
|
|
|
Constant() = delete;
|
|
Constant(DataType const& data): data{data} {}
|
|
Constant(ThisType const& e): data{e.data} {}
|
|
|
|
inline T const& operator[](index::Value i) const { return data[i]; }
|
|
|
|
template<typename Index, std::enable_if_t<index::isIndex<Index>>* = nullptr>
|
|
inline ThisType& operator[](Index const&) { return *this; }
|
|
};
|
|
|
|
template<typename Expr, typename Prop>
|
|
struct Constant<index::IndexImpl<Expr, Prop>> {
|
|
using IsExpression = tag::Expression;
|
|
using DataType = index::Value;
|
|
using Id = IgnoredId;
|
|
using ThisType = Constant<DataType, Id>;
|
|
using Index = index::IndexImpl<Expr, Prop>;
|
|
|
|
Constant() = delete;
|
|
Constant(Index) {}
|
|
Constant(ThisType const&) {}
|
|
|
|
inline DataType operator[](index::Value i) const { return Index::eval(i); }
|
|
};
|
|
|
|
template<typename T, typename Id, typename Index_>
|
|
struct Expression<T*, Id, Index_> {
|
|
using IsExpression = tag::Expression;
|
|
using DataType = T*;
|
|
using Index = Index_;
|
|
using ThisType = Expression<DataType, Id, Index>;
|
|
|
|
DataType data;
|
|
|
|
Expression() = delete;
|
|
Expression(DataType data): data{data} {}
|
|
|
|
inline auto& operator[](index::Value i) { return data[Index::eval(i)]; }
|
|
|
|
template<typename NIndex, std::enable_if_t<index::isIndex<NIndex>>* = nullptr>
|
|
inline auto operator[](NIndex const&) { return Expression<DataType, Id, NIndex>{data}; }
|
|
|
|
inline auto begin() { return std::begin(data); }
|
|
inline auto end() { return std::end(data); }
|
|
|
|
// inline auto operator=(ThisType const& rhs) {
|
|
// return Expression<op::Assign, ThisType, ThisType>{{}, *this, rhs};
|
|
// }
|
|
|
|
template<typename Rhs, std::enable_if_t<isExpression<Rhs>>* = nullptr>
|
|
inline auto operator=(Rhs rhs) {
|
|
return Expression<op::Assign, ThisType, Rhs>{{}, *this, rhs};
|
|
}
|
|
|
|
template<typename Rhs, std::enable_if_t<not isExpression<Rhs>>* = nullptr>
|
|
inline auto operator=(Rhs rhs) {
|
|
return Expression<op::Assign, ThisType, Constant<Rhs>>{{}, *this, rhs};
|
|
}
|
|
|
|
inline auto operator++(int) { return Expression<op::PostIncr, ThisType>{{}, *this}; }
|
|
inline auto operator--(int) { return Expression<op::PostDecr, ThisType>{{}, *this}; }
|
|
inline auto operator++() { return Expression<op::PreIncr, ThisType>{{}, *this}; }
|
|
inline auto operator--() { return Expression<op::PreDecr, ThisType>{{}, *this}; }
|
|
};
|
|
|
|
template<typename T, std::size_t n, typename Id, typename Index_>
|
|
struct Expression<std::array<T, n>, Id, Index_> {
|
|
using IsExpression = tag::Expression;
|
|
using DataTypeRaw = std::array<T, n>;
|
|
using DataType = DataTypeRaw&;
|
|
using Index = Index_;
|
|
using ThisType = Expression<DataTypeRaw, Id, Index>;
|
|
|
|
DataType data;
|
|
|
|
Expression() = delete;
|
|
Expression(DataType data): data{data} {}
|
|
|
|
inline auto& operator[](index::Value i) { return data[Index::eval(i)]; }
|
|
|
|
template<typename NIndex, std::enable_if_t<index::isIndex<NIndex>>* = nullptr>
|
|
inline auto operator[](NIndex const&) { return Expression<DataTypeRaw, Id, NIndex>{data}; }
|
|
|
|
inline auto begin() { return std::begin(data); }
|
|
inline auto end() { return std::end(data); }
|
|
|
|
// inline auto operator=(ThisType const& rhs) {
|
|
// return Expression<op::Assign, ThisType, ThisType>{{}, *this, rhs};
|
|
// }
|
|
|
|
template<typename Rhs, std::enable_if_t<isExpression<Rhs>>* = nullptr>
|
|
inline auto operator=(Rhs rhs) {
|
|
return Expression<op::Assign, ThisType, Rhs>{{}, *this, rhs};
|
|
}
|
|
|
|
template<typename Rhs, std::enable_if_t<not isExpression<Rhs>>* = nullptr>
|
|
inline auto operator=(Rhs rhs) {
|
|
return Expression<op::Assign, ThisType, Constant<Rhs>>{{}, *this, rhs};
|
|
}
|
|
|
|
inline auto operator++(int) { return Expression<op::PostIncr, ThisType>{{}, *this}; }
|
|
inline auto operator--(int) { return Expression<op::PostDecr, ThisType>{{}, *this}; }
|
|
inline auto operator++() { return Expression<op::PreIncr, ThisType>{{}, *this}; }
|
|
inline auto operator--() { return Expression<op::PreDecr, ThisType>{{}, *this}; }
|
|
};
|
|
|
|
template<typename Op, typename... ETs>
|
|
struct Expression<Op, ETs...> {
|
|
using IsExpression = tag::Expression;
|
|
using ThisType = Expression<Op, ETs...>;
|
|
|
|
static constexpr std::size_t arity = sizeof...(ETs);
|
|
|
|
using AritySequence = decltype(std::make_index_sequence<arity>());
|
|
|
|
Op op;
|
|
std::tuple<ETs...> operands;
|
|
|
|
Expression() = delete;
|
|
Expression(Op const& op, ETs const&... e): op(op), operands{e...} {}
|
|
Expression(ThisType const& e): op(e.op), operands{e.operands} {}
|
|
Expression(ThisType&& e): op(std::move(e.op)), operands{std::move(e.operands)} {}
|
|
|
|
inline decltype(auto) eval() { return eval(AritySequence{}); }
|
|
inline decltype(auto) operator[](index::Value i) { return eval(i, AritySequence{}); }
|
|
|
|
// inline auto operator=(ThisType const& rhs) {
|
|
// return Expression<op::Assign, ThisType, ThisType>{{}, *this, rhs};
|
|
// }
|
|
|
|
template<typename Rhs, std::enable_if_t<isExpression<Rhs>>* = nullptr>
|
|
inline auto operator=(Rhs rhs) {
|
|
return Expression<op::Assign, ThisType, Rhs>{{}, *this, rhs};
|
|
}
|
|
|
|
template<typename Rhs, std::enable_if_t<not isExpression<Rhs>>* = nullptr>
|
|
inline auto operator=(Rhs rhs) {
|
|
return Expression<op::Assign, ThisType, Constant<Rhs>>{{}, *this, rhs};
|
|
}
|
|
|
|
template<std::size_t... indices>
|
|
inline decltype(auto) eval(std::index_sequence<indices...>) {
|
|
return op.eval(std::get<indices>(operands)...);
|
|
}
|
|
|
|
template<std::size_t... indices>
|
|
inline decltype(auto) eval(index::Value i, std::index_sequence<indices...>) {
|
|
return op.eval(i, std::get<indices>(operands)...);
|
|
}
|
|
|
|
inline auto operator++(int) { return Expression<op::PostIncr, ThisType>{{}, *this}; }
|
|
inline auto operator--(int) { return Expression<op::PostDecr, ThisType>{{}, *this}; }
|
|
inline auto operator++() { return Expression<op::PreIncr, ThisType>{{}, *this}; }
|
|
inline auto operator--() { return Expression<op::PreDecr, ThisType>{{}, *this}; }
|
|
};
|
|
|
|
template<typename Op, typename View, typename... ETs>
|
|
struct Expression<op::View<Op>, View, ETs...> {
|
|
using IsExpression = tag::Expression;
|
|
using ThisType = Expression<Op, View, ETs...>;
|
|
using Tuple = std::tuple<ETs...>;
|
|
using RefExpression = Expression<Op, ETs...>;
|
|
|
|
static constexpr std::size_t arity = packSize<View>;
|
|
|
|
using AritySequence = decltype(std::make_index_sequence<arity>());
|
|
|
|
Op op;
|
|
TupleView<Tuple, View> operands;
|
|
|
|
Expression() = delete;
|
|
Expression(RefExpression& e): op(e.op), operands{e.operands} {}
|
|
Expression(ThisType const& e): op(e.op), operands{e.operands} {}
|
|
Expression(ThisType&& e): op(std::move(e.op)), operands{std::move(e.operands)} {}
|
|
|
|
inline decltype(auto) eval() { return eval(AritySequence{}); }
|
|
inline decltype(auto) operator[](index::Value i) { return eval(i, AritySequence{}); }
|
|
|
|
template<std::size_t... indices>
|
|
inline decltype(auto) eval(std::index_sequence<indices...>) {
|
|
return op.eval(std::get<indices>(operands)...);
|
|
}
|
|
|
|
template<std::size_t... indices>
|
|
inline decltype(auto) eval(index::Value i, std::index_sequence<indices...>) {
|
|
return op.eval(i, std::get<indices>(operands)...);
|
|
}
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|