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 Simons Foundation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0.txt
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Authors: Thomas Hahn
16
22#pragma once
23
24#include "./expression.hpp"
25#include "./utils.hpp"
26#include "../macros.hpp"
27
28#include <functional>
29#include <type_traits>
30#include <utility>
31
32namespace nda::clef {
33
39 namespace detail {
40
41 // Get the value from a std::reference_wrapper or simply forward the argument of any other type.
42 template <typename U>
43 FORCEINLINE U &&fget(U &&x) {
44 return std::forward<U>(x);
45 }
46
47 // Specialization of fget for std::reference_wrapper.
48 template <typename U>
49 FORCEINLINE decltype(auto) fget(std::reference_wrapper<U> x) {
50 return x.get();
51 }
52
53 } // namespace detail
54
63 template <typename Tag>
64 struct operation;
65
67 template <>
68 struct operation<tags::terminal> {
76 template <typename L>
77 FORCEINLINE L operator()(L &&l) const {
78 return std::forward<L>(l);
79 }
80 };
81
83 template <>
84 struct operation<tags::function> {
94 template <typename F, typename... Args>
95 FORCEINLINE decltype(auto) operator()(F &&f, Args &&...args) const {
96 return detail::fget(std::forward<F>(f))(detail::fget(std::forward<Args>(args))...);
97 }
98 };
99
101 template <>
102 struct operation<tags::subscript> {
112 template <typename F, typename... Args>
113 FORCEINLINE decltype(auto) operator()(F &&f, Args &&...args) const {
114 // directly calling [args...] breaks clang
115 return detail::fget(std::forward<F>(f)).operator[](detail::fget(std::forward<Args>(args))...);
116 }
117 };
118
119 // Define and implement all lazy binary operations.
120#define CLEF_OPERATION(TAG, OP) \
121 namespace tags { \
122 \
123 struct TAG : binary_op { \
124 \
125 static const char *name() { return AS_STRING(OP); } \
126 }; \
127 } \
128 \
129 template <typename L, typename R> \
130 FORCEINLINE auto operator OP(L &&l, R &&r) \
131 requires(is_any_lazy<L, R>) \
132 { \
133 return expr<tags::TAG, expr_storage_t<L>, expr_storage_t<R>>{tags::TAG(), std::forward<L>(l), std::forward<R>(r)}; \
134 } \
135 \
136 template <> \
137 struct operation<tags::TAG> { \
138 \
139 template <typename L, typename R> \
140 FORCEINLINE decltype(auto) operator()(L &&l, R &&r) const { \
141 return detail::fget(std::forward<L>(l)) OP detail::fget(std::forward<R>(r)); \
142 } \
143 }
144
145 // clang-format off
146 CLEF_OPERATION(plus, +);
147 CLEF_OPERATION(minus, -);
148 CLEF_OPERATION(multiplies, *);
149 CLEF_OPERATION(divides, /);
150 CLEF_OPERATION(greater, >);
151 CLEF_OPERATION(less, <);
152 CLEF_OPERATION(leq, <=);
153 CLEF_OPERATION(geq, >=);
154 CLEF_OPERATION(eq, ==);
155 // clang-format on
156#undef CLEF_OPERATION
157
158 // Define and implement all lazy unary operations.
159#define CLEF_OPERATION(TAG, OP) \
160 namespace tags { \
161 \
162 struct TAG : unary_op { \
163 \
164 static const char *name() { return AS_STRING(OP); } \
165 }; \
166 } \
167 \
168 template <typename L> \
169 FORCEINLINE auto operator OP(L &&l) \
170 requires(is_any_lazy<L>) \
171 { \
172 return expr<tags::TAG, expr_storage_t<L>>{tags::TAG(), std::forward<L>(l)}; \
173 } \
174 \
175 template <> \
176 struct operation<tags::TAG> { \
177 \
178 template <typename L> \
179 FORCEINLINE decltype(auto) operator()(L &&l) const { \
180 return OP detail::fget(std::forward<L>(l)); \
181 } \
182 }
183
184 CLEF_OPERATION(unaryplus, +);
185 CLEF_OPERATION(negate, -);
186 CLEF_OPERATION(loginot, !);
187#undef CLEF_OPERATION
188
190 template <>
191 struct operation<tags::if_else> {
203 template <typename C, typename A, typename B>
204 FORCEINLINE A operator()(C const &c, A const &a, B const &b) const {
205 return detail::fget(c) ? detail::fget(a) : detail::fget(b);
206 }
207 };
208
221 template <typename C, typename A, typename B>
222 FORCEINLINE auto if_else(C &&c, A &&a, B &&b) {
223 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),
224 std::forward<B>(b)};
225 }
226
238 template <typename Tag, typename... Args>
239 FORCEINLINE auto op_dispatch(std::true_type, Args &&...args) {
240 return expr<Tag, expr_storage_t<Args>...>{Tag(), std::forward<Args>(args)...};
241 }
242
254 template <typename Tag, typename... Args>
255 FORCEINLINE decltype(auto) op_dispatch(std::false_type, Args &&...args) {
256 return operation<Tag>()(std::forward<Args>(args)...);
257 }
258
261} // 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.
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:148
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:77
Generic operation performed on expression nodes.
Definition operation.hpp:64
Tag for conditional expressions.