Line data Source code
1 : ///////////////////////////////////////////////////////////////////////////
2 : // Spetabaru - Berenger Bramas MPCDF - 2017
3 : // Under LGPL Licence, please you must read the LICENCE file.
4 : ///////////////////////////////////////////////////////////////////////////
5 : #ifndef SPDATAACCESSMODE_HPP
6 : #define SPDATAACCESSMODE_HPP
7 :
8 : #include <type_traits>
9 : #include <array>
10 :
11 : #include "Config/SpConfig.hpp"
12 : #include "Utils/SpArrayView.hpp"
13 : #include "Utils/SpDebug.hpp"
14 : #include "Data/SpDataDuplicator.hpp"
15 : #include "Utils/SpArrayAccessor.hpp"
16 : #include "Utils/small_vector.hpp"
17 :
18 : ////////////////////////////////////////////////////////
19 : /// All possible data access modes
20 : ////////////////////////////////////////////////////////
21 :
22 : enum class SpDataAccessMode{
23 : READ=0,
24 : WRITE,
25 : PARALLEL_WRITE,
26 : COMMUTATIVE_WRITE,
27 : POTENTIAL_WRITE
28 : };
29 :
30 : using SpDataAccessModeField = unsigned char;
31 :
32 : ////////////////////////////////////////////////////////
33 : /// Convert to string
34 : ////////////////////////////////////////////////////////
35 :
36 16403 : inline std::string SpModeToStr(const SpDataAccessMode inMode){
37 16403 : switch(inMode){
38 5606 : case SpDataAccessMode::READ: return "READ";
39 7868 : case SpDataAccessMode::WRITE: return "WRITE";
40 135 : case SpDataAccessMode::PARALLEL_WRITE: return "PARALLEL_WRITE";
41 133 : case SpDataAccessMode::COMMUTATIVE_WRITE: return "COMMUTATIVE_WRITE";
42 2673 : case SpDataAccessMode::POTENTIAL_WRITE: return "POTENTIAL_WRITE";
43 : }
44 0 : return "UNDEFINED";
45 : }
46 :
47 : ////////////////////////////////////////////////////////
48 : /// Data mode => a mode + a data
49 : ////////////////////////////////////////////////////////
50 :
51 : template <SpDataAccessMode AccessModeT, class HandleTypeT>
52 : struct SpScalarDataMode{
53 : static_assert(std::is_reference<HandleTypeT>::value,
54 : "The given type must be a reference");
55 : public:
56 : // To test at compile time if it is a scalar
57 : static const bool IsScalar = true;
58 : // The access mode of the data/access pair
59 : static const SpDataAccessMode AccessMode = AccessModeT;
60 : // The original data type (including reference)
61 : using HandleTypeRef = HandleTypeT;
62 : static_assert(std::is_reference<HandleTypeRef>::value, "The given type must be a reference");
63 : // The original data type (without reference)
64 : using HandleTypeNoRef = std::remove_reference_t<HandleTypeRef>;
65 : static_assert(!std::is_reference<HandleTypeNoRef>::value, "HandleTypeNoRef should be without reference");
66 : // The original data type (without reference with pointer)
67 : using HandleTypePtr = std::remove_reference_t<HandleTypeRef>*;
68 : static_assert(!std::is_reference<HandleTypePtr>::value && std::is_pointer<HandleTypePtr>::value, "HandleTypeNoRef should be without reference");
69 : // The raw data type (no const not ref)
70 : using RawHandleType = std::remove_const_t<std::remove_reference_t<HandleTypeRef>>;
71 : static_assert(!std::is_reference<RawHandleType>::value && !std::is_const<RawHandleType>::value, "HandleTypeNoRef should be without reference");
72 : private:
73 : // The reference on the data
74 : HandleTypePtr ptrToData;
75 :
76 : public:
77 : // Simple constructor (simply transfer the handle)
78 1566 : constexpr explicit SpScalarDataMode(HandleTypeT& inHandle)
79 1566 : : ptrToData(std::addressof(inHandle)){
80 1566 : }
81 :
82 : SpScalarDataMode(const SpScalarDataMode&) = default;
83 : SpScalarDataMode(SpScalarDataMode&&) = delete;
84 : SpScalarDataMode& operator=(const SpScalarDataMode&) = delete;
85 : SpScalarDataMode& operator=(SpScalarDataMode&&) = delete;
86 :
87 6772 : constexpr std::array<HandleTypePtr,1> getAllData(){
88 6772 : return std::array<HandleTypePtr,1>{ptrToData};
89 : }
90 :
91 1377 : constexpr HandleTypeRef getView(){
92 1377 : return *ptrToData;
93 : }
94 :
95 180 : constexpr void updatePtr([[maybe_unused]] const long int position, HandleTypePtr ptr){
96 180 : assert(position < 1);
97 180 : ptrToData = ptr;
98 180 : }
99 : };
100 :
101 : template <SpDataAccessMode AccessModeT, class HandleTypeT, class AccessorTypeT>
102 : struct SpContainerDataMode{
103 : static_assert(std::is_pointer<HandleTypeT>::value,
104 : "The given type must be a pointer");
105 : static_assert(!std::is_reference<HandleTypeT>::value,
106 : "The given type must be not a pointer");
107 : public:
108 : // To test at compile time if it is a scalar
109 : static const bool IsScalar = false;
110 : // The access mode of the data/access pair
111 : static const SpDataAccessMode AccessMode = AccessModeT;
112 : // The original data type (without reference with pointer)
113 : using HandleTypePtr = HandleTypeT;
114 : static_assert(!std::is_reference<HandleTypePtr>::value && std::is_pointer<HandleTypePtr>::value, "HandleTypeNoRef should be without reference");
115 : // The original data type (without reference)
116 : using HandleTypeNoRef = std::remove_pointer_t<HandleTypePtr>;
117 : static_assert(!std::is_reference<HandleTypeNoRef>::value, "HandleTypeNoRef should be without reference");
118 : // The original data type (including reference)
119 : using HandleTypeRef = HandleTypeNoRef&;
120 : static_assert(std::is_reference<HandleTypeRef>::value, "The given type must be a reference");
121 : // The raw data type (no const not ref)
122 : using RawHandleType = std::remove_const_t<std::remove_reference_t<HandleTypeRef>>;
123 : static_assert(!std::is_reference<RawHandleType>::value && !std::is_const<RawHandleType>::value, "HandleTypeNoRef should be without reference");
124 :
125 : using AccessorType = AccessorTypeT;
126 : private:
127 : AccessorTypeT accessor;
128 : small_vector<HandleTypePtr> ptrToData;
129 :
130 : public:
131 :
132 : template <class VHC>
133 66 : SpContainerDataMode(HandleTypePtr inHandle, VHC&& inView)
134 66 : : accessor(inHandle, std::forward<VHC>(inView)){
135 66 : ptrToData.reserve(accessor.getSize());
136 446 : for(HandleTypePtr ptr : accessor){
137 380 : ptrToData.push_back(ptr);
138 : }
139 66 : }
140 :
141 492 : small_vector_base<HandleTypePtr>& getAllData(){
142 492 : return ptrToData;
143 : }
144 :
145 74 : AccessorType& getView(){
146 74 : return accessor;
147 : }
148 :
149 110 : void updatePtr(const long int position, HandleTypePtr ptr){
150 110 : assert(position < static_cast<long int>(ptrToData.size()));
151 110 : ptrToData[position] = ptr;
152 110 : accessor.updatePtr(position, ptr);
153 110 : }
154 :
155 : SpContainerDataMode(SpContainerDataMode&&) = default;
156 232 : SpContainerDataMode(const SpContainerDataMode&) = default;
157 : SpContainerDataMode& operator=(const SpContainerDataMode&) = delete;
158 : SpContainerDataMode& operator=(SpContainerDataMode&&) = delete;
159 : };
160 :
161 : ////////////////////////////////////////////////////////
162 : /// Access mode functions
163 : ////////////////////////////////////////////////////////
164 :
165 : template <class DepType>
166 370 : constexpr SpScalarDataMode<SpDataAccessMode::READ, const DepType&> SpRead(const DepType& inDep){
167 370 : return SpScalarDataMode<SpDataAccessMode::READ, const DepType&>(inDep);
168 : }
169 :
170 : template <class DepType>
171 1041 : constexpr SpScalarDataMode<SpDataAccessMode::WRITE, DepType&> SpWrite(DepType& inDep){
172 : static_assert(std::is_const<DepType>::value == false, "Write cannot be done on const value");
173 1041 : return SpScalarDataMode<SpDataAccessMode::WRITE, DepType&>(inDep);
174 : }
175 :
176 : template <class DepType>
177 22 : constexpr SpScalarDataMode<SpDataAccessMode::PARALLEL_WRITE, DepType&> SpParallelWrite(DepType& inDep){
178 : static_assert(std::is_const<DepType>::value == false, "Atomic Write cannot be done on const value");
179 22 : return SpScalarDataMode<SpDataAccessMode::PARALLEL_WRITE, DepType&>(inDep);
180 : }
181 :
182 : template <class DepType>
183 14 : constexpr SpScalarDataMode<SpDataAccessMode::COMMUTATIVE_WRITE, DepType&> SpCommutativeWrite(DepType& inDep){
184 : static_assert(std::is_const<DepType>::value == false, "Commutative Write cannot be done on const value");
185 14 : return SpScalarDataMode<SpDataAccessMode::COMMUTATIVE_WRITE, DepType&>(inDep);
186 : }
187 :
188 : template <class DepType>
189 119 : constexpr SpScalarDataMode<SpDataAccessMode::POTENTIAL_WRITE, DepType&> SpPotentialWrite(DepType& inDep){
190 : static_assert(std::is_const<DepType>::value == false, "Potential write cannot be done on const value");
191 : static_assert(SpDataCanBeDuplicate<DepType>::value, "Potentially written to data must be duplicatable");
192 119 : return SpScalarDataMode<SpDataAccessMode::POTENTIAL_WRITE, DepType&>(inDep);
193 : }
194 :
195 : ////////////////////////////////////////////////////////
196 :
197 : template <class DepType, class ViewType>
198 66 : SpContainerDataMode<SpDataAccessMode::READ, const DepType*,SpArrayAccessor<const DepType>> SpReadArray(const DepType* inDep, ViewType&& inInterval){
199 66 : return SpContainerDataMode<SpDataAccessMode::READ, const DepType*,SpArrayAccessor<const DepType>>(inDep,std::forward<ViewType>(inInterval));
200 : }
201 :
202 : template <class DepType, class ViewType>
203 : SpContainerDataMode<SpDataAccessMode::WRITE, DepType*,SpArrayAccessor<DepType>> SpWriteArray(DepType* inDep, ViewType&& inInterval){
204 : static_assert(std::is_const<DepType>::value == false, "SpWriteArray cannot be done on const value");
205 : return SpContainerDataMode<SpDataAccessMode::WRITE, DepType*,SpArrayAccessor<DepType>>(inDep,std::forward<ViewType>(inInterval));
206 : }
207 :
208 : template <class DepType, class ViewType>
209 : SpContainerDataMode<SpDataAccessMode::COMMUTATIVE_WRITE, DepType*,SpArrayAccessor<DepType>> SpCommutativeWriteArray(DepType* inDep, ViewType&& inInterval){
210 : static_assert(std::is_const<DepType>::value == false, "SpCommutativeWriteArray cannot be done on const value");
211 : return SpContainerDataMode<SpDataAccessMode::COMMUTATIVE_WRITE, DepType*,SpArrayAccessor<DepType>>(inDep,std::forward<ViewType>(inInterval));
212 : }
213 :
214 : template <class DepType, class ViewType>
215 : SpContainerDataMode<SpDataAccessMode::PARALLEL_WRITE, DepType*,SpArrayAccessor<DepType>> SpParallelWriteArray(DepType* inDep, ViewType&& inInterval){
216 : static_assert(std::is_const<DepType>::value == false, "SpParallelWriteArray cannot be done on const value");
217 : return SpContainerDataMode<SpDataAccessMode::PARALLEL_WRITE, DepType*,SpArrayAccessor<DepType>>(inDep,std::forward<ViewType>(inInterval));
218 : }
219 :
220 : template <class DepType, class ViewType>
221 : SpContainerDataMode<SpDataAccessMode::POTENTIAL_WRITE, DepType*,SpArrayAccessor<DepType>> SpPotentialWriteArray(DepType* inDep, ViewType&& inInterval){
222 : static_assert(std::is_const<DepType>::value == false, "SpPotentialWriteArray cannot be done on const value");
223 : return SpContainerDataMode<SpDataAccessMode::POTENTIAL_WRITE, DepType*,SpArrayAccessor<DepType>>(inDep,std::forward<ViewType>(inInterval));
224 : }
225 :
226 : ////////////////////////////////////////////////////////
227 : /// Forbid on rvalue
228 : ////////////////////////////////////////////////////////
229 :
230 : template <class DepType>
231 : constexpr const DepType& SpRead(const DepType&& inDep) = delete;
232 :
233 : template <class DepType>
234 : constexpr std::remove_const_t<DepType>& SpWrite(DepType&& inDep) = delete;
235 :
236 : template <class DepType>
237 : constexpr std::remove_const_t<DepType>& SpParallelWrite(DepType&& inDep) = delete;
238 :
239 : template <class DepType>
240 : constexpr std::remove_const_t<DepType>& SpCommutativeWrite(DepType&& inDep) = delete;
241 :
242 : template <class DepType>
243 : constexpr std::remove_const_t<DepType>& SpPotentialWrite(DepType&& inDep) = delete;
244 :
245 : ////////////////////////////////////////////////////////
246 : /// Get data from data, or SpDataAccessMode or pair
247 : ////////////////////////////////////////////////////////
248 :
249 : template <SpDataAccessMode AccessMode, class ParamsType>
250 : ParamsType& GetRealData(SpScalarDataMode<AccessMode, ParamsType>& scalarData){
251 : return scalarData.data;
252 : }
253 :
254 : template <SpDataAccessMode AccessMode, class HandleTypeRef, class ViewType>
255 : ViewType& GetRealData(SpContainerDataMode<AccessMode, HandleTypeRef, ViewType>& containerData){
256 : return containerData.getView();
257 : }
258 :
259 : template<typename T, typename = void>
260 : struct is_plus_equal_compatible : std::false_type
261 : { };
262 :
263 : template<typename T>
264 : struct is_plus_equal_compatible<T,
265 : typename std::enable_if<
266 : true,
267 : decltype(std::declval<T&>() += std::declval<const T&>(), (void)0)
268 : >::type
269 : > : std::true_type
270 : {
271 : };
272 :
273 :
274 : ////////////////////////////////////////////////////////
275 : /// Test if a type has the getView method
276 : ////////////////////////////////////////////////////////
277 :
278 : template<class...> using void_t = void;
279 :
280 : template<class, class = void>
281 : struct has_getView : std::false_type {};
282 :
283 : template<class T>
284 : struct has_getView<T, void_t<decltype(std::declval<T>().getView())>> : std::true_type {};
285 :
286 : template<class, class = void>
287 : struct has_getAllData : std::false_type {};
288 :
289 : template<class T>
290 : struct has_getAllData<T, void_t<decltype(std::declval<T>().getAllData())>> : std::true_type {};
291 :
292 : template <SpDataAccessMode dam1, SpDataAccessMode dam2>
293 : struct access_modes_are_equal_internal : std::conditional_t<dam1==dam2, std::true_type, std::false_type> {};
294 :
295 : template<SpDataAccessMode dam1, typename T, typename = std::void_t<>>
296 : struct access_modes_are_equal : std::false_type {};
297 :
298 : template <SpDataAccessMode dam1, typename T>
299 : struct access_modes_are_equal<dam1, T, std::void_t<decltype(T::AccessMode)>> : access_modes_are_equal_internal<dam1, T::AccessMode> {};
300 :
301 : enum class SpCallableType {
302 : CPU=0,
303 : GPU
304 : };
305 :
306 : template <bool compileWithCuda, class T, SpCallableType ct>
307 : class SpCallableWrapper {
308 : private:
309 : using CallableTy = std::remove_reference_t<T>;
310 : CallableTy callable;
311 : public:
312 : static constexpr auto callable_type = ct;
313 :
314 : template <typename T2, typename=std::enable_if_t<std::is_same<std::remove_reference_t<T2>, CallableTy>::value>>
315 964 : SpCallableWrapper(T2&& inCallable) : callable(std::forward<T2>(inCallable)) {}
316 :
317 874 : CallableTy& getCallableRef() {
318 874 : return callable;
319 : }
320 : };
321 :
322 : template <class T, SpCallableType ct>
323 : class SpCallableWrapper<false, T, ct> {
324 : public:
325 : template<typename T2>
326 4 : SpCallableWrapper(T2&&) {}
327 : };
328 :
329 : template <class T>
330 964 : auto SpCpu(T &&callable) {
331 964 : return SpCallableWrapper<true, T, SpCallableType::CPU>(std::forward<T>(callable));
332 : }
333 :
334 : template <class T>
335 4 : auto SpGpu(T&& callable) {
336 4 : return SpCallableWrapper<SpConfig::CompileWithCuda, T, SpCallableType::GPU>(std::forward<T>(callable));
337 : }
338 :
339 : template <class T0>
340 : struct is_instantiation_of_callable_wrapper : std::false_type {};
341 :
342 : template <bool b, class T0, SpCallableType ct>
343 : struct is_instantiation_of_callable_wrapper<SpCallableWrapper<b, T0, ct>> : std::true_type {};
344 :
345 : template <class T0>
346 : inline constexpr bool is_instantiation_of_callable_wrapper_v = is_instantiation_of_callable_wrapper<T0>::value;
347 :
348 : template <class T0, SpCallableType callableType0>
349 : struct is_instantiation_of_callable_wrapper_with_type : std::false_type {};
350 :
351 : template <bool b, class T0, SpCallableType callableType0, SpCallableType callableType1>
352 : struct is_instantiation_of_callable_wrapper_with_type<SpCallableWrapper<b, T0, callableType1>, callableType0> :
353 : std::conditional_t<callableType0==callableType1, std::true_type, std::false_type> {};
354 :
355 : template <class T, SpCallableType callableType>
356 : inline constexpr bool is_instantiation_of_callable_wrapper_with_type_v = is_instantiation_of_callable_wrapper_with_type<T, callableType>::value;
357 :
358 : #endif
|