iterative-solver 0.0
 
Loading...
Searching...
No Matches
util.h
1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ARRAY_UTIL_H
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ARRAY_UTIL_H
3#include <array>
4#include <atomic>
5#include <cstddef>
6#include <future>
7#include <iterator>
8#include <memory>
9#include <stdexcept>
10#include <string>
11#include <type_traits>
12#include <typeinfo>
13#include <vector>
14
15#include <molpro/linalg/array/Span.h>
16#include <molpro/mpi.h>
17
18namespace molpro::linalg::array {
19
20namespace util {
21
22template <typename T>
23struct is_std_array : std::false_type {};
24
25template <typename T, std::size_t N>
26struct is_std_array<std::array<T, N>> : std::true_type {};
27
28template <typename T>
30
31template <typename T>
32constexpr bool is_array_v = std::is_array<T>::value || is_std_array_v<T>;
33
34template <typename T, typename = void>
35struct is_allocatable : std::false_type {};
36
37// We use the existence of a constructor taking a size-type as a proxy
38// for whether the given type is "allocatable", that is it can be newly
39// constructed by simply telling it how many elements it shall contain.
40template <typename T>
41struct is_allocatable<T, std::enable_if_t<std::is_constructible_v<T, std::size_t>>> : std::true_type {};
42
43template <typename T>
45
46} // namespace util
47
63template<typename T>
64T allocate_array(std::size_t size) {
65 if constexpr (util::is_allocatable_v<T>) {
66 return T(size);
67 }
68
69 throw std::runtime_error("Required molpro::linalg::array::allocate_array for type '"
70 + std::string(typeid(T).name())
71 + "' - you have to provide an explicit template specialization for this function & type");
72}
73
74namespace util {
81template <typename T>
82T allocate_like(std::size_t size) {
83 if constexpr (is_array_v<T>)
84 return T();
85 else if constexpr (is_allocatable_v<T>)
86 return T(size);
87 else
88 return allocate_array<T>(size);
89}
90
92template <class R>
93auto contiguous_span(R &r) {
94 return Span<std::remove_pointer_t<decltype(std::data(r))>>(std::data(r), std::size(r));
95}
96} // namespace util
97
98} // namespace molpro::linalg::array
99
101
103class LockMPI3 {
104protected:
105 MPI_Comm m_comm = MPI_COMM_NULL;
106 MPI_Win m_win = MPI_WIN_NULL;
107 bool m_locked = false;
108
109public:
111 LockMPI3(MPI_Comm comm);
113 ~LockMPI3();
114
115 LockMPI3() = delete;
116 LockMPI3(const LockMPI3 &) = delete;
117 LockMPI3 &operator=(const LockMPI3 &) = delete;
118
120 void lock();
121
123 void unlock();
124
125protected:
127 struct Proxy {
129 explicit Proxy(LockMPI3 &);
130 Proxy() = delete;
131 ~Proxy();
132
133 bool m_deleted = false;
134 };
135
137 std::weak_ptr<Proxy> m_proxy;
138
139public:
142 std::shared_ptr<Proxy> scope();
143};
144
147public:
148 explicit ScopeLock(MPI_Comm comm) : lock{comm}, l{lock.scope()} {}
149
150protected:
152 decltype(std::declval<LockMPI3>().scope()) l;
153};
154
155template <typename Result = void>
156class Task {
157public:
158 Task(std::future<Result> &&task) : m_task{std::move(task)} {};
159 Task(Task &&other) = default;
160
161 template <class Func, typename... Args>
162 static Task create(Func &&f, Args &&...args) {
163 return {std::async(std::launch::async, std::forward<Func>(f), std::forward<Args>(args)...)};
164 }
165
167 // Don't call wait() here: a moved-from Task has an invalid future, and
168 // wait() throws future_error in that case. A throwing destructor in a
169 // non-noexcept context would terminate the program.
170 if (m_task.valid())
171 m_task.wait();
172 }
173
175 bool test() { return m_task.wait_for(std::chrono::microseconds{1}) == std::future_status::ready; }
177 Result wait() {
178 if (!m_task.valid())
179 throw std::future_error(std::future_errc::no_state);
180 return m_task.get();
181 }
182
183protected:
184 std::future<Result> m_task;
185};
186
187} // namespace molpro::linalg::array::util
188
189#endif // LINEARALGEBRA_SRC_MOLPRO_LINALG_ARRAY_UTIL_H
Non-owning container taking a pointer to the data buffer and its size and exposing routines for itera...
Definition Span.h:31
Atomic lock allowing only one process to acquire it. Implemented using MPI3 RMA.
Definition util.h:103
void unlock()
Release the lock.
Definition util.cpp:24
MPI_Comm m_comm
MPI communicator.
Definition util.h:105
~LockMPI3()
Release the lock and destroy it. This is collective and must be called by all processes in the commun...
Definition util.cpp:10
void lock()
Acquire exclusive lock.
Definition util.cpp:17
std::shared_ptr< Proxy > scope()
Definition util.cpp:31
bool m_locked
whether lock is active
Definition util.h:107
std::weak_ptr< Proxy > m_proxy
Keep track of proxy object so that if lock is deleted, the proxy does not try to unlock.
Definition util.h:137
LockMPI3(const LockMPI3 &)=delete
LockMPI3 & operator=(const LockMPI3 &)=delete
MPI_Win m_win
empty window handle
Definition util.h:106
Utility object that locks on creation and unlocks on destruction.
Definition util.h:146
LockMPI3 lock
Definition util.h:151
ScopeLock(MPI_Comm comm)
Definition util.h:148
decltype(std::declval< LockMPI3 >().scope()) l
Definition util.h:152
Task(Task &&other)=default
static Task create(Func &&f, Args &&...args)
Definition util.h:162
Task(std::future< Result > &&task)
Definition util.h:158
Result wait()
wait for the task to complete and return its result
Definition util.h:177
std::future< Result > m_task
Definition util.h:184
~Task()
Definition util.h:166
bool test()
Returns true if the task has completed.
Definition util.h:175
Definition ArrayHandler.h:24
T allocate_like(std::size_t size)
Creates an array of type T able to hold size elements.
Definition util.h:82
auto contiguous_span(R &r)
A view of all the elements of a contiguous array.
Definition util.h:93
constexpr bool is_array_v
Definition util.h:32
constexpr bool is_std_array_v
Definition util.h:29
constexpr bool is_allocatable_v
Definition util.h:44
Definition ArrayHandler.h:19
T allocate_array(std::size_t size)
Allocates an array of type T to hold the specified amount of items.
Definition util.h:64
Proxy that locks on creation and unlocks on destruction. Useful for locking a scope.
Definition util.h:127
LockMPI3 & m_lock
Definition util.h:128
bool m_deleted
whether the lock was already deleted
Definition util.h:133