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
28 namespace detail {
29
30 // Get the value from a std::reference_wrapper or simply forward the argument of any other type.
31 template <typename U>
32 FORCEINLINE U &&fget(U &&x) {
33 return std::forward<U>(x);
34 }
35
36 // Specialization of fget for std::reference_wrapper.
37 template <typename U>
38 FORCEINLINE decltype(auto) fget(std::reference_wrapper<U> x) {
39 return x.get();
40 }
41
42 } // namespace detail
43
52 template <typename Tag>
53 struct operation;
54
56 template <>
57 struct operation<tags::terminal> {
65 template <typename L>
66 FORCEINLINE L operator()(L &&l) const {
67 return std::forward<L>(l);
68 }
69 };
70
72 template <>
73 struct operation<tags::function> {
83 template <typename F, typename... Args>
84 FORCEINLINE decltype(auto) operator()(F &&f, Args &&...args) const {
85 return detail::fget(std::forward<F>(f))(detail::fget(std::forward<Args>(args))...);
86 }
87 };
88
90 template <>
91 struct operation<tags::subscript> {
101 template <typename F, typename... Args>
102 FORCEINLINE decltype(auto) operator()(F &&f, Args &&...args) const {
103 // directly calling [args...] breaks clang
104 return detail::fget(std::forward<F>(f)).operator[](detail::fget(std::forward<Args>(args))...);
105 }
106 };
107
108 // Define and implement all lazy binary operations.
109#define CLEF_OPERATION(TAG, OP) \
110 namespace tags { \
111 \
112 struct TAG : binary_op { \
113 \
114 static const char *name() { return AS_STRING(OP); } \
115 }; \
116 } \
117 \
118 template <typename L, typename R> \
119 FORCEINLINE auto operator OP(L &&l, R &&r) \
120 requires(is_any_lazy<L, R>) \
121 { \
122 return expr<tags::TAG, expr_storage_t<L>, expr_storage_t<R>>{tags::TAG(), std::forward<L>(l), std::forward<R>(r)}; \
123 } \
124 \
125 template <> \
126 struct operation<tags::TAG> { \
127 \
128 template <typename L, typename R> \
129 FORCEINLINE decltype(auto) operator()(L &&l, R &&r) const { \
130 return detail::fget(std::forward<L>(l)) OP detail::fget(std::forward<R>(r)); \
131 } \
132 }
133
134 // clang-format off
135 CLEF_OPERATION(plus, +);
136 CLEF_OPERATION(minus, -);
137 CLEF_OPERATION(multiplies, *);
138 CLEF_OPERATION(divides, /);
139 CLEF_OPERATION(greater, >);
140 CLEF_OPERATION(less, <);
141 CLEF_OPERATION(leq, <=);
142 CLEF_OPERATION(geq, >=);
143 CLEF_OPERATION(eq, ==);
144 // clang-format on
145#undef CLEF_OPERATION
146
147 // Define and implement all lazy unary operations.
148#define CLEF_OPERATION(TAG, OP) \
149 namespace tags { \
150 \
151 struct TAG : unary_op { \
152 \
153 static const char *name() { return AS_STRING(OP); } \
154 }; \
155 } \
156 \
157 template <typename L> \
158 FORCEINLINE auto operator OP(L &&l) \
159 requires(is_any_lazy<L>) \
160 { \
161 return expr<tags::TAG, expr_storage_t<L>>{tags::TAG(), std::forward<L>(l)}; \
162 } \
163 \
164 template <> \
165 struct operation<tags::TAG> { \
166 \
167 template <typename L> \
168 FORCEINLINE decltype(auto) operator()(L &&l) const { \
169 return OP detail::fget(std::forward<L>(l)); \
170 } \
171 }
172
173 CLEF_OPERATION(unaryplus, +);
174 CLEF_OPERATION(negate, -);
175 CLEF_OPERATION(loginot, !);
176#undef CLEF_OPERATION
177
179 template <>
180 struct operation<tags::if_else> {
192 template <typename C, typename A, typename B>
193 FORCEINLINE A operator()(C const &c, A const &a, B const &b) const {
194 return detail::fget(c) ? detail::fget(a) : detail::fget(b);
195 }
196 };
197
210 template <typename C, typename A, typename B>
211 FORCEINLINE auto if_else(C &&c, A &&a, B &&b) {
212 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),
213 std::forward<B>(b)};
214 }
215
227 template <typename Tag, typename... Args>
228 FORCEINLINE auto op_dispatch(std::true_type, Args &&...args) {
229 return expr<Tag, expr_storage_t<Args>...>{Tag(), std::forward<Args>(args)...};
230 }
231
243 template <typename Tag, typename... Args>
244 FORCEINLINE decltype(auto) op_dispatch(std::false_type, Args &&...args) {
245 return operation<Tag>()(std::forward<Args>(args)...);
246 }
247
249
250} // 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: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:66
Generic operation performed on expression nodes.
Definition operation.hpp:53
Tag for conditional expressions.