-
Notifications
You must be signed in to change notification settings - Fork 113
Expand file tree
/
Copy pathfield_cache.h
More file actions
176 lines (153 loc) · 5.97 KB
/
field_cache.h
File metadata and controls
176 lines (153 loc) · 5.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#pragma once
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <reference_wrapper_helper.h>
namespace quda {
/**
FieldKey is a container for a key for a std::map to cache
allocated field instances.
@tparam T The field type
*/
template <typename T>
struct FieldKey {
std::string volume; /** volume string */
std::string aux; /** auxiliary string */
FieldKey() = default;
/**
@brief Constructor for FieldKey
@param[in] a Field whose key we wish to generate
*/
FieldKey(const T &a) : volume(a.VolString()), aux(a.AuxString()) { }
/**
@brief Less than operator used for ordering in the container
*/
bool operator<(const FieldKey<T> &other) const
{
if (volume < other.volume) {
return true;
} else if (volume == other.volume) {
return aux < other.aux ? true : false;
}
return false;
}
};
/**
FieldTmp is a wrapper for a cached field.
@tparam T The field type
*/
template <typename T>
class FieldTmp {
static std::map<FieldKey<T>, std::stack<T>> cache; /** Field Cache */
T tmp; /** The temporary field instance */
FieldKey<T> key; /** Key associated with this instance */
public:
/**
@brief Allow FieldTmp<T> to be used in lieu of T
*/
operator T&() { return tmp; }
/**
@brief Create a field temporary that is identical to the field
instance argument. If a matching field is present in the cache,
it will be popped from the cache. If no such temporary exists, a
temporary will be allocated.
@param[in] a Field we wish to create a matching temporary for
*/
FieldTmp(const T &a);
/**
@brief Create a field temporary that corresponds to the key
parameter. If a matching field is present in the cache, it
will be popped from the cache. If no such temporary exists an
error will be thrown. Note that this constructor allows for a
custom key that doesn't necessarily correspond to the key
return by FieldKey<T>(const T&).
@param[in] key Key corresponding to the field instance we
require
@param[in] param Parameter structure used to allocated the temporary
*/
FieldTmp(const FieldKey<T> &key, const typename T::param_type ¶m);
/**
@brief Create a field temporary that corresponds to the field
constructed from the param struct. If a matching field is
present in the cache, it will be popped from the cache. If no
such temporary exists a temporary will be allocated.
@param[in] key Key corresponding to the field instance we
require
@param[in] param Parameter structure used to allocated
the temporary
*/
FieldTmp(typename T::param_type param);
/**
@brief Copy constructor is deleted to prevent accidental cache
bloat
*/
FieldTmp(const FieldTmp<T> &a) = delete;
/**
@brief Move constructor is noexcept to ensure it is used by STL
*/
FieldTmp(FieldTmp<T> &&a) noexcept = default;
/**
@brief Push the temporary onto the cache, where it will be
available for subsequent reuse.
*/
~FieldTmp();
/** @brief Flush the cache and frees all temporary allocations */
static void destroy();
};
/**
@brief Get a field temporary that is identical to the field
instance argument. If a matching field is present in the cache,
it will be popped from the cache. If no such temporary exists, a
temporary will be allocated. When the destructor for the
FieldTmp is called, e.g., the returned object goes out of scope,
the temporary will be pushed onto the cache.
@param[in] a Field we wish to create a matching temporary for
*/
template <typename T> auto getFieldTmp(const T &a) { return FieldTmp<T>(a); }
/**
@brief Get a field temporary that correspond to the field
parameter argument. If a matching field is present in the cache,
it will be popped from the cache. If no such temporary exists, a
temporary will be allocated. When the destructor for the
FieldTmp is called, e.g., the returned object goes out of scope,
the temporary will be pushed onto the cache.
@param[in] a Field paramer we wish to create a matching temporary for
*/
template <typename T> auto getFieldTmp(const typename T::param_type ¶m) { return FieldTmp<T>(param); }
/**
@brief Get a vector of field temporaries that are identical to
the vector instance argument. If enough matching fields are
present in the cache, they will be popped from the cache. If an
insufficient number of temporaries exist, enough will be
allocated. When the destructor is called, e.g.,
the returned object goes out of scope, the temporaries will be
pushed onto the cache.
@param[in] a Vector of fields we wish to create a matching
temporary for
*/
template <typename T> auto getFieldTmp(cvector_ref<T> &a)
{
std::vector<FieldTmp<T>> tmp;
tmp.reserve(a.size());
for (auto i = 0u; i < a.size(); i++) tmp.push_back(std::move(getFieldTmp(a[i])));
return tmp;
}
/**
@brief Get a vector of field temporaries that correspond to the field
parameter argument. If enough matching fields are present in the cache,
they will be popped from the cache. If an
insufficient number of temporaries exist, enough will be
allocated. When the destructor is called, e.g.,
the returned object goes out of scope, the temporaries will be
pushed onto the cache.
@param[in] a Field param we wish to create a matching vector of temporaries for
*/
template <typename T> auto getFieldTmp(size_t size, const typename T::param_type ¶m)
{
std::vector<FieldTmp<T>> tmp;
tmp.reserve(size);
for (auto i = 0u; i < size; i++) tmp.push_back(std::move(getFieldTmp<T>(param)));
return tmp;
}
}