#ifndef PFOR_PFOR_EXPRESSION_EXPRESSION_H #define PFOR_PFOR_EXPRESSION_EXPRESSION_H #include #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 struct Expression; template struct Constant; template struct Constant { using IsExpression = tag::Expression; using DataType = T; using Id = IgnoredId; using ThisType = Constant; 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>* = nullptr> inline ThisType& operator[](Index const&) { return *this; } }; template struct Constant { using IsExpression = tag::Expression; using DataType = T const*; using Id = IgnoredId; using ThisType = Constant; 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>* = nullptr> inline ThisType& operator[](Index const&) { return *this; } }; template struct Constant> { using IsExpression = tag::Expression; using DataType = index::Value; using Id = IgnoredId; using ThisType = Constant; using Index = index::IndexImpl; Constant() = delete; Constant(Index) {} Constant(ThisType const&) {} inline DataType operator[](index::Value i) const { return Index::eval(i); } }; template struct Expression { using IsExpression = tag::Expression; using DataType = T*; using Index = Index_; using ThisType = Expression; DataType data; Expression() = delete; Expression(DataType data): data{data} {} inline auto& operator[](index::Value i) { return data[Index::eval(i)]; } template>* = nullptr> inline auto operator[](NIndex const&) { return Expression{data}; } inline auto begin() { return std::begin(data); } inline auto end() { return std::end(data); } // inline auto operator=(ThisType const& rhs) { // return Expression{{}, *this, rhs}; // } template>* = nullptr> inline auto operator=(Rhs rhs) { return Expression{{}, *this, rhs}; } template>* = nullptr> inline auto operator=(Rhs rhs) { return Expression>{{}, *this, rhs}; } inline auto operator++(int) { return Expression{{}, *this}; } inline auto operator--(int) { return Expression{{}, *this}; } inline auto operator++() { return Expression{{}, *this}; } inline auto operator--() { return Expression{{}, *this}; } }; template struct Expression, Id, Index_> { using IsExpression = tag::Expression; using DataTypeRaw = std::array; using DataType = DataTypeRaw&; using Index = Index_; using ThisType = Expression; DataType data; Expression() = delete; Expression(DataType data): data{data} {} inline auto& operator[](index::Value i) { return data[Index::eval(i)]; } template>* = nullptr> inline auto operator[](NIndex const&) { return Expression{data}; } inline auto begin() { return std::begin(data); } inline auto end() { return std::end(data); } // inline auto operator=(ThisType const& rhs) { // return Expression{{}, *this, rhs}; // } template>* = nullptr> inline auto operator=(Rhs rhs) { return Expression{{}, *this, rhs}; } template>* = nullptr> inline auto operator=(Rhs rhs) { return Expression>{{}, *this, rhs}; } inline auto operator++(int) { return Expression{{}, *this}; } inline auto operator--(int) { return Expression{{}, *this}; } inline auto operator++() { return Expression{{}, *this}; } inline auto operator--() { return Expression{{}, *this}; } }; template struct Expression { using IsExpression = tag::Expression; using ThisType = Expression; static constexpr std::size_t arity = sizeof...(ETs); using AritySequence = decltype(std::make_index_sequence()); Op op; std::tuple 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{{}, *this, rhs}; // } template>* = nullptr> inline auto operator=(Rhs rhs) { return Expression{{}, *this, rhs}; } template>* = nullptr> inline auto operator=(Rhs rhs) { return Expression>{{}, *this, rhs}; } template inline decltype(auto) eval(std::index_sequence) { return op.eval(std::get(operands)...); } template inline decltype(auto) eval(index::Value i, std::index_sequence) { return op.eval(i, std::get(operands)...); } inline auto operator++(int) { return Expression{{}, *this}; } inline auto operator--(int) { return Expression{{}, *this}; } inline auto operator++() { return Expression{{}, *this}; } inline auto operator--() { return Expression{{}, *this}; } }; template struct Expression, View, ETs...> { using IsExpression = tag::Expression; using ThisType = Expression; using Tuple = std::tuple; using RefExpression = Expression; static constexpr std::size_t arity = packSize; using AritySequence = decltype(std::make_index_sequence()); Op op; TupleView 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 inline decltype(auto) eval(std::index_sequence) { return op.eval(std::get(operands)...); } template inline decltype(auto) eval(index::Value i, std::index_sequence) { return op.eval(i, std::get(operands)...); } }; } } #endif