Skip to content

Commit 26fbcc0

Browse files
committed
Refactor container concepts checks
1 parent 579264a commit 26fbcc0

File tree

1 file changed

+62
-62
lines changed

1 file changed

+62
-62
lines changed

offload/include/PerThreadTable.h

Lines changed: 62 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -73,37 +73,62 @@ template <typename ObjectType> class PerThread {
7373
}
7474
};
7575

76+
template <typename ContainerTy> struct ContainerConcepts {
77+
template <typename, template <typename> class, typename = std::void_t<>>
78+
struct has : std::false_type {};
79+
template <typename Ty, template <typename> class Op>
80+
struct has<Ty, Op, std::void_t<Op<Ty>>> : std::true_type {};
81+
82+
template <typename Ty> using IteratorTypeCheck = typename Ty::iterator;
83+
template <typename Ty> using MappedTypeCheck = typename Ty::mapped_type;
84+
template <typename Ty> using ValueTypeCheck = typename Ty::value_type;
85+
template <typename Ty> using KeyTypeCheck = typename Ty::key_type;
86+
template <typename Ty> using SizeTyCheck = typename Ty::size_type;
87+
88+
template <typename Ty>
89+
using ClearCheck = decltype(std::declval<Ty>().clear());
90+
template <typename Ty>
91+
using ClearAllCheck = decltype(std::declval<Ty>().clearAll(1));
92+
template <typename Ty>
93+
using ReserveCheck = decltype(std::declval<Ty>().reserve(1));
94+
template <typename Ty>
95+
using ResizeCheck = decltype(std::declval<Ty>().resize(1));
96+
97+
static constexpr bool hasIterator =
98+
has<ContainerTy, IteratorTypeCheck>::value;
99+
static constexpr bool hasClear = has<ContainerTy, ClearCheck>::value;
100+
static constexpr bool hasClearAll = has<ContainerTy, ClearAllCheck>::value;
101+
static constexpr bool isAssociative =
102+
has<ContainerTy, MappedTypeCheck>::value;
103+
static constexpr bool hasReserve = has<ContainerTy, ReserveCheck>::value;
104+
static constexpr bool hasResize = has<ContainerTy, ResizeCheck>::value;
105+
106+
template <typename, template <typename> class, typename = std::void_t<>>
107+
struct has_type {
108+
using type = void;
109+
};
110+
template <typename Ty, template <typename> class Op>
111+
struct has_type<Ty, Op, std::void_t<Op<Ty>>> {
112+
using type = Op<Ty>;
113+
};
114+
115+
using iterator = typename has_type<ContainerTy, IteratorTypeCheck>::type;
116+
using value_type = typename std::conditional_t<
117+
isAssociative, typename has_type<ContainerTy, MappedTypeCheck>::type,
118+
typename has_type<ContainerTy, ValueTypeCheck>::type>;
119+
using key_type = typename std::conditional_t<
120+
isAssociative, typename has_type<ContainerTy, KeyTypeCheck>::type,
121+
typename has_type<ContainerTy, SizeTyCheck>::type>;
122+
};
123+
76124
// Using an STL container (such as std::vector) indexed by thread ID has
77125
// too many race conditions issues so we store each thread entry into a
78126
// thread_local variable.
79127
// ContainerType is the container type used to store the objects, e.g.,
80128
// std::vector, std::set, etc. by each thread. ObjectType is the type of the
81129
// stored objects e.g., omp_interop_val_t *, ...
82130
template <typename ContainerType, typename ObjectType> class PerThreadTable {
83-
using iterator = typename ContainerType::iterator;
84-
85-
template <typename, typename = std::void_t<>>
86-
struct has_iterator : std::false_type {};
87-
template <typename T>
88-
struct has_iterator<T, std::void_t<typename T::iterator>> : std::true_type {};
89-
90-
template <typename T, typename = std::void_t<>>
91-
struct has_clear : std::false_type {};
92-
template <typename T>
93-
struct has_clear<T, std::void_t<decltype(std::declval<T>().clear())>>
94-
: std::true_type {};
95-
96-
template <typename T, typename = std::void_t<>>
97-
struct has_clearAll : std::false_type {};
98-
template <typename T>
99-
struct has_clearAll<T, std::void_t<decltype(std::declval<T>().clearAll(1))>>
100-
: std::true_type {};
101-
102-
template <typename, typename = std::void_t<>>
103-
struct is_associative : std::false_type {};
104-
template <typename T>
105-
struct is_associative<T, std::void_t<typename T::mapped_type>>
106-
: std::true_type {};
131+
using iterator = typename ContainerConcepts<ContainerType>::iterator;
107132

108133
struct PerThreadData {
109134
size_t NElements = 0;
@@ -188,12 +213,12 @@ template <typename ContainerType, typename ObjectType> class PerThreadTable {
188213
for (std::shared_ptr<PerThreadData> ThreadData : ThreadDataList) {
189214
if (!ThreadData->ThreadEntry || ThreadData->NElements == 0)
190215
continue;
191-
if constexpr (has_clearAll<ContainerType>::value) {
216+
if constexpr (ContainerConcepts<ContainerType>::hasClearAll) {
192217
ThreadData->ThreadEntry->clearAll(ClearFunc);
193-
} else if constexpr (has_iterator<ContainerType>::value &&
194-
has_clear<ContainerType>::value) {
218+
} else if constexpr (ContainerConcepts<ContainerType>::hasIterator &&
219+
ContainerConcepts<ContainerType>::hasClear) {
195220
for (auto &Obj : *ThreadData->ThreadEntry) {
196-
if constexpr (is_associative<ContainerType>::value) {
221+
if constexpr (ContainerConcepts<ContainerType>::isAssociative) {
197222
ClearFunc(Obj.second);
198223
} else {
199224
ClearFunc(Obj);
@@ -215,7 +240,7 @@ template <typename ContainerType, typename ObjectType> class PerThreadTable {
215240
if (!ThreadData->ThreadEntry || ThreadData->NElements == 0)
216241
continue;
217242
for (auto &Obj : *ThreadData->ThreadEntry) {
218-
if constexpr (is_associative<ContainerType>::value) {
243+
if constexpr (ContainerConcepts<ContainerType>::isAssociative) {
219244
if (auto Err = DeinitFunc(Obj.second))
220245
return Err;
221246
} else {
@@ -228,49 +253,24 @@ template <typename ContainerType, typename ObjectType> class PerThreadTable {
228253
}
229254
};
230255

231-
template <typename T, typename = std::void_t<>> struct ContainerValueType {
232-
using type = typename T::value_type;
233-
};
234-
template <typename T>
235-
struct ContainerValueType<T, std::void_t<typename T::mapped_type>> {
236-
using type = typename T::mapped_type;
237-
};
238-
239256
template <typename ContainerType, size_t ReserveSize = 0>
240257
class PerThreadContainer
241-
: public PerThreadTable<ContainerType,
242-
typename ContainerValueType<ContainerType>::type> {
258+
: public PerThreadTable<ContainerType, typename ContainerConcepts<
259+
ContainerType>::value_type> {
260+
261+
using IndexType = typename ContainerConcepts<ContainerType>::key_type;
262+
using ObjectType = typename ContainerConcepts<ContainerType>::value_type;
243263

244-
// helpers
245-
template <typename T, typename = std::void_t<>> struct indexType {
246-
using type = typename T::size_type;
247-
};
248-
template <typename T> struct indexType<T, std::void_t<typename T::key_type>> {
249-
using type = typename T::key_type;
250-
};
251-
template <typename T, typename = std::void_t<>>
252-
struct has_resize : std::false_type {};
253-
template <typename T>
254-
struct has_resize<T, std::void_t<decltype(std::declval<T>().resize(1))>>
255-
: std::true_type {};
256-
257-
template <typename T, typename = std::void_t<>>
258-
struct has_reserve : std::false_type {};
259-
template <typename T>
260-
struct has_reserve<T, std::void_t<decltype(std::declval<T>().reserve(1))>>
261-
: std::true_type {};
262-
263-
using IndexType = typename indexType<ContainerType>::type;
264-
using ObjectType = typename ContainerValueType<ContainerType>::type;
265264
public:
266265
// Get the object for the given index in the current thread
267266
ObjectType &get(IndexType Index) {
268267
ContainerType &Entry = this->getThreadEntry();
269268

270269
// specialized code for vector-like containers
271-
if constexpr (has_resize<ContainerType>::value) {
270+
if constexpr (ContainerConcepts<ContainerType>::hasResize) {
272271
if (Index >= Entry.size()) {
273-
if constexpr (has_reserve<ContainerType>::value && ReserveSize > 0)
272+
if constexpr (ContainerConcepts<ContainerType>::hasReserve &&
273+
ReserveSize > 0)
274274
Entry.reserve(ReserveSize);
275275

276276
// If the index is out of bounds, try resize the container

0 commit comments

Comments
 (0)