TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
concepts.hpp
Go to the documentation of this file.
1// Copyright (c) 2020-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, Olivier Parcollet, Nils Wentzell
16
22#pragma once
23
25#include "./traits.hpp"
26
27#include <array>
28#include <concepts>
29#include <type_traits>
30#include <utility>
31
32namespace nda {
33
39 // clang has full support for "lambdas in unevaluated context" only for versions >= 17.
40#ifndef __clang__
41
42 // clang-format off
52 template <typename A, int R>
53 concept CallableWithLongs = requires(A const &a) {
54 // if decltype is not present, the concept will fail to compile for an A for which the a(Is...) is not well formed
55 []<auto... Is>(std::index_sequence<Is...>, auto const &aa) -> decltype(aa(long(Is)...)) {return aa(long(Is)...);}
56 (std::make_index_sequence<R>{}, a);
57 };
58 // clang-format on
59
60#else
61
62 namespace detail {
63
64 // Helper function declaration to check if A can be called with R long arguments.
65 template <auto... Is, typename A>
66 auto call_on_R_longs(std::index_sequence<Is...>, A const &a) -> decltype(a((long{Is})...)); // no impl needed
67
68 } // namespace detail
69
79 template <typename A, int R>
80 concept CallableWithLongs = requires(A const &a) {
81 { detail::call_on_R_longs(std::make_index_sequence<R>{}, a) };
82 };
83
84#endif // __clang__
85
86 namespace detail {
87
88 // Check if T is of type std::array<long, R> for arbitrary array sizes R.
89 template <typename T>
90 constexpr bool is_std_array_of_long_v = false;
91
92 // Specialization of nda::detail::is_std_array_of_long_v for cvref types.
93 template <typename T>
94 requires(!std::is_same_v<T, std::remove_cvref_t<T>>)
95 constexpr bool is_std_array_of_long_v<T> = is_std_array_of_long_v<std::remove_cvref_t<T>>;
96
97 // Specialization of nda::detail::is_std_array_of_long_v for std::array<long, R>.
98 template <auto R>
99 constexpr bool is_std_array_of_long_v<std::array<long, R>> = true;
100
101 } // namespace detail
102
111 template <class T>
112 concept StdArrayOfLong = detail::is_std_array_of_long_v<T>;
113
118 template <typename S>
120
125 template <typename S>
127
136 template <typename T, template <typename...> class TMPLT>
138
141 namespace mem {
142
149 // Forward declarations.
150 struct blk_t;
151 enum class AddressSpace;
153
165 template <typename A>
166 concept Allocator = requires(A &a) {
167 { a.allocate(size_t{}) } noexcept -> std::same_as<blk_t>;
168 { a.allocate_zero(size_t{}) } noexcept -> std::same_as<blk_t>;
169 { a.deallocate(std::declval<blk_t>()) } noexcept;
170 { A::address_space } -> std::same_as<AddressSpace const &>;
171 };
172
183 template <typename H, typename T = typename std::remove_cvref_t<H>::value_type>
184 concept Handle = requires(H const &h) {
185 requires std::is_same_v<typename std::remove_cvref_t<H>::value_type, T>;
186 { h.is_null() } noexcept -> std::same_as<bool>;
187 { h.data() } noexcept -> std::same_as<T *>;
188 { H::address_space } -> std::same_as<AddressSpace const &>;
189 };
190
200 template <typename H, typename T = typename std::remove_cvref_t<H>::value_type>
201 concept OwningHandle = Handle<H, T> and requires(H const &h) {
202 requires not std::is_const_v<typename std::remove_cvref_t<H>::value_type>;
203 { h.size() } noexcept -> std::same_as<long>;
204 };
205
208 } // namespace mem
209
229 template <typename A>
230 concept Array = requires(A const &a) {
231 { a.shape() } -> StdArrayOfLong;
232 { a.size() } -> std::same_as<long>;
234 };
235
247 template <typename A, typename A_t = std::remove_cvref_t<A>>
248 concept MemoryArray = Array<A> && requires(A &a) {
249 typename A_t::storage_t;
251 typename A_t::value_type;
252 {
253 a.data()
254 } -> std::same_as<std::conditional_t<std::is_const_v<std::remove_reference_t<A>> || std::is_const_v<typename A_t::value_type>,
256 { a.indexmap().strides() } -> StdArrayOfLong;
257 };
258
265 template <typename A, int R>
266 concept ArrayOfRank = Array<A> and (get_rank<A> == R);
267
274 template <typename A, int R>
276
281 template <typename AS>
283
289 template <typename M>
291
297 template <typename V>
299
305 template <typename M>
307
313 template <typename V>
315
324 template <typename A, typename B>
325 concept ArrayInitializer = requires(A const &a) {
326 { a.shape() } -> StdArrayOfLong;
327 typename std::remove_cvref_t<A>::value_type;
328 requires MemoryArray<B> && requires(B &b) { a.invoke(b); }; // FIXME not perfect: it should accept any layout ??
329 };
330
331 // FIXME : We should not need this ... Only used once...
338 template <typename A, typename U>
339 concept HasValueTypeConstructibleFrom = Array<A> and (std::is_constructible_v<U, get_value_t<A>>);
340
343} // namespace nda
Check if a given type satisfies the array concept.
Definition concepts.hpp:230
Check if a given type satisfies the array initializer concept for a given nda::MemoryArray type.
Definition concepts.hpp:325
Check if a given type is an nda::Array of a certain rank.
Definition concepts.hpp:266
Check if if a given type is either an nda::Array or an nda::Scalar.
Definition concepts.hpp:282
Check if a given type can be called with a certain number of long arguments.
Definition concepts.hpp:53
Check if a given type is either a double or complex type.
Definition concepts.hpp:126
Check if a given type is constructible from the value type of a given nda::Array type.
Definition concepts.hpp:339
Check if a given type is an instantiation of some other template type.
Definition concepts.hpp:137
Check if a given type is a matrix, i.e. an nda::ArrayOfRank<2>.
Definition concepts.hpp:290
Check if a given type satisfies the memory array concept.
Definition concepts.hpp:248
Check if a given type is an nda::MemoryArray of a certain rank.
Definition concepts.hpp:275
Check if a given type is a memory matrix, i.e. an nda::MemoryArrayOfRank<2>.
Definition concepts.hpp:306
Check if a given type is a memory vector, i.e. an nda::MemoryArrayOfRank<1>.
Definition concepts.hpp:314
Check if a given type is either an arithmetic or complex type.
Definition concepts.hpp:119
Check if a given type is of type std::array<long, R> for some arbitrary R.
Definition concepts.hpp:112
Check if a given type is a vector, i.e. an nda::ArrayOfRank<1>.
Definition concepts.hpp:298
Check if a given type satisfies the allocator concept.
Definition concepts.hpp:166
Check if a given type satisfies the memory handle concept.
Definition concepts.hpp:184
Check if a given type satisfies the owning memory handle concept.
Definition concepts.hpp:201
constexpr int get_rank
Constexpr variable that specifies the rank of an nda::Array or of a contiguous 1-dimensional range.
Definition traits.hpp:136
std::decay_t< decltype(get_first_element(std::declval< A const >()))> get_value_t
Get the value type of an array/view or a scalar type.
Definition traits.hpp:192
AddressSpace
Enum providing identifiers for the different memory address spaces.
constexpr bool is_instantiation_of_v
Constexpr variable that is true if type T is an instantiation of TMPLT (see nda::is_instantiation_of)...
Definition traits.hpp:59
constexpr bool is_double_or_complex_v
Constexpr variable that is true if type T is a std::complex type or a double type.
Definition traits.hpp:98
constexpr bool is_scalar_v
Constexpr variable that is true if type S is a scalar type, i.e. arithmetic or complex.
Definition traits.hpp:79
Provides missing concepts for older compiler versions.
Provides type traits for the nda library.