TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
operation.hpp
Go to the documentation of this file.
1// Copyright (c) 2024--present, The Simons Foundation
2// This file is part of TRIQS/nda and is licensed under the Apache License, Version 2.0.
3// SPDX-License-Identifier: Apache-2.0
4// See LICENSE in the root of this distribution for details.
5
10
11#pragma once
12
13#include "./expression.hpp"
14#include "./utils.hpp"
15#include "../macros.hpp"
16
17#include <functional>
18#include <type_traits>
19#include <utility>
20
21namespace nda::clef {
22
27
41 template <typename F>
42 constexpr bool supports_partial_eval_of_calls = false;
43
52 template <typename T>
53 constexpr bool supports_partial_eval_of_subscript = false;
54
55 namespace detail {
56
57 // Get the value from a std::reference_wrapper or simply forward the argument of any other type.
58 template <typename U>
59 FORCEINLINE U &&fget(U &&x) {
60 return std::forward<U>(x);
61 }
62
63 // Specialization of fget for std::reference_wrapper.
64 template <typename U>
65 FORCEINLINE decltype(auto) fget(std::reference_wrapper<U> x) {
66 return x.get();
67 }
68
69 } // namespace detail
70
79 template <typename Tag>
80 struct operation;
81
83 template <>
84 struct operation<tags::terminal> {
92 template <typename L>
93 FORCEINLINE L operator()(L &&l) const {
94 return std::forward<L>(l);
95 }
96 };
97
99 template <>
100 struct operation<tags::function> {
110 template <typename F, typename... Args>
111 FORCEINLINE decltype(auto) operator()(F &&f, Args &&...args) const {
112 return detail::fget(std::forward<F>(f))(detail::fget(std::forward<Args>(args))...);
113 }
114 };
115
117 template <>
118 struct operation<tags::subscript> {
128 template <typename F, typename... Args>
129 FORCEINLINE decltype(auto) operator()(F &&f, Args &&...args) const {
130 return detail::fget(std::forward<F>(f)).operator[](detail::fget(std::forward<Args>(args))...);
131 }
132 };
133
134 // Define and implement all lazy binary operations.
135#define CLEF_OPERATION(TAG, OP) \
136 namespace tags { \
137 \
138 struct TAG : binary_op { \
139 \
140 static const char *name() { return AS_STRING(OP); } \
141 }; \
142 } \
143 \
144 template <typename L, typename R> \
145 FORCEINLINE auto operator OP(L &&l, R &&r) \
146 requires(is_any_lazy<L, R>) \
147 { \
148 return expr<tags::TAG, expr_storage_t<L>, expr_storage_t<R>>{tags::TAG(), std::forward<L>(l), std::forward<R>(r)}; \
149 } \
150 \
151 template <> \
152 struct operation<tags::TAG> { \
153 \
154 template <typename L, typename R> \
155 FORCEINLINE decltype(auto) operator()(L &&l, R &&r) const { \
156 return detail::fget(std::forward<L>(l)) OP detail::fget(std::forward<R>(r)); \
157 } \
158 }
159
160 // clang-format off
161 CLEF_OPERATION(plus, +);
162 CLEF_OPERATION(minus, -);
163 CLEF_OPERATION(multiplies, *);
164 CLEF_OPERATION(divides, /);
165 CLEF_OPERATION(greater, >);
166 CLEF_OPERATION(less, <);
167 CLEF_OPERATION(leq, <=);
168 CLEF_OPERATION(geq, >=);
169 CLEF_OPERATION(eq, ==);
170 // clang-format on
171#undef CLEF_OPERATION
172
173 // Define and implement all lazy unary operations.
174#define CLEF_OPERATION(TAG, OP) \
175 namespace tags { \
176 \
177 struct TAG : unary_op { \
178 \
179 static const char *name() { return AS_STRING(OP); } \
180 }; \
181 } \
182 \
183 template <typename L> \
184 FORCEINLINE auto operator OP(L &&l) \
185 requires(is_any_lazy<L>) \
186 { \
187 return expr<tags::TAG, expr_storage_t<L>>{tags::TAG(), std::forward<L>(l)}; \
188 } \
189 \
190 template <> \
191 struct operation<tags::TAG> { \
192 \
193 template <typename L> \
194 FORCEINLINE decltype(auto) operator()(L &&l) const { \
195 return OP detail::fget(std::forward<L>(l)); \
196 } \
197 }
198
199 CLEF_OPERATION(unaryplus, +);
200 CLEF_OPERATION(negate, -);
201 CLEF_OPERATION(loginot, !);
202#undef CLEF_OPERATION
203
205 template <>
206 struct operation<tags::if_else> {
218 template <typename C, typename A, typename B>
219 FORCEINLINE A operator()(C const &c, A const &a, B const &b) const {
220 return detail::fget(c) ? detail::fget(a) : detail::fget(b);
221 }
222 };
223
236 template <typename C, typename A, typename B>
237 FORCEINLINE auto if_else(C &&c, A &&a, B &&b) {
238 return expr<tags::if_else, expr_storage_t<C>, expr_storage_t<A>, expr_storage_t<B>>{tags::if_else(), std::forward<C>(c), std::forward<A>(a),
239 std::forward<B>(b)};
240 }
241
253
254 template <typename Tag, typename... Args>
255 FORCEINLINE auto op_dispatch(std::true_type, Args &&...args) {
256 using Arg0 = std::decay_t<std::tuple_element_t<0, std::tuple<Args...>>>;
257 if constexpr ((std::is_same_v<Tag, tags::function> and not supports_partial_eval_of_calls<Arg0>) or //
258 (std::is_same_v<Tag, tags::subscript> and not supports_partial_eval_of_subscript<Arg0>) //
259 )
260 return expr<Tag, expr_storage_t<Args>...>{Tag(), std::forward<Args>(args)...};
261 else
262 return operation<Tag>()(std::forward<Args>(args)...);
263 }
264
276 template <typename Tag, typename... Args>
277 FORCEINLINE decltype(auto) op_dispatch(std::false_type, Args &&...args) {
278 return operation<Tag>()(std::forward<Args>(args)...);
279 }
280
282
283} // namespace nda::clef
Provides some utility functions and type traits for the CLEF library.
Provides a basic lazy expression type for the clef library.
__inline__ auto if_else(C &&c, A &&a, B &&b)
Create a lazy ternary (if-else) expression.
__inline__ auto op_dispatch(std::true_type, Args &&...args)
Dispatch operations containing at least one lazy operand.
constexpr bool supports_partial_eval_of_calls
Controls evaluation behavior of function nodes during partial expression evaluation.
Definition operation.hpp:42
constexpr bool supports_partial_eval_of_subscript
Controls evaluation behavior of subscript operations during partial expression evaluation.
Definition operation.hpp:53
typename detail::expr_storage_impl< T >::type expr_storage_t
Type trait to determine how a type should be stored in an expression tree, i.e. either by reference o...
Definition utils.hpp:137
Macros used in the nda library.
Single node of the expression tree.
__inline__ A operator()(C const &c, A const &a, B const &b) const
Perform a ternary (if-else) operation.
__inline__ L operator()(L &&l) const
Perform a terminal operation.
Definition operation.hpp:93
Generic operation performed on expression nodes.
Definition operation.hpp:80
Tag for conditional expressions.