VTK  9.7.20261101
vtkKeysTraits.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2// SPDX-License-Identifier: BSD-3-Clause
11
12#ifndef vtkKeysTraits_h
13#define vtkKeysTraits_h
14
15#include "vtkABINamespace.h"
16
17#include <cstdint>
18#include <type_traits>
19#include <utility>
20
21namespace vtk
22{
23namespace keys
24{
25VTK_ABI_NAMESPACE_BEGIN
26template <typename TKey, typename TElementId, typename TKeyId>
27class KeysBase;
28VTK_ABI_NAMESPACE_END
29
30namespace detail
31{
32VTK_ABI_NAMESPACE_BEGIN
33
34// The type traits of the declarations of vtkKeys.h.
35
36// Input and InputMapper: their number of records.
37template <typename In, typename = void>
38struct HasGetNumberOfRecords : std::false_type
39{
40};
41template <typename In>
43 std::enable_if_t<
44 std::is_integral_v<std::decay_t<decltype(std::declval<const In&>().GetNumberOfRecords())>>>>
45 : std::true_type
46{
47};
48
49// The type of the records of an input, as it gives their number.
50template <typename In>
51using RecordIdOf = std::decay_t<decltype(std::declval<const In&>().GetNumberOfRecords())>;
52
53// The key and element id types of an input: its KeyType and ElementIdType, if declared,
54// otherwise the type of GetKey() and RecordIdType, or void.
55template <typename In, typename = void>
57{
58 using type = void;
59};
60template <typename In>
61struct GetKeyTypeOf<In,
62 std::void_t<decltype(std::declval<const In&>().GetKey(std::declval<RecordIdOf<In>>()))>>
63{
64 using type =
65 std::decay_t<decltype(std::declval<const In&>().GetKey(std::declval<RecordIdOf<In>>()))>;
66};
67template <typename In, typename = void>
69{
70};
71template <typename In>
72struct KeyTypeOf<In, std::void_t<typename In::KeyType>>
73{
74 using type = typename In::KeyType;
75};
76template <typename In>
78
79template <typename In, typename = void>
81{
82 using type = void;
83};
84template <typename In>
85struct RecordIdTypeOf<In, std::enable_if_t<HasGetNumberOfRecords<In>::value>>
86{
88};
89template <typename In, typename = void>
91{
92};
93template <typename In>
94struct ElementIdTypeOf<In, std::void_t<typename In::ElementIdType>>
95{
96 using type = typename In::ElementIdType;
97};
98template <typename In>
100
101// The key type of an element of an array.
102template <typename T>
103using ElementKeyOf = std::decay_t<decltype(std::declval<const T&>().GetKey())>;
104
105//------------------------------------------------------------------------------
106// The checks of the concepts, in the order of their first use by vtkKeys.txx, each detection trait
107// right before its first check. Each check reports what to implement, and returns whether it
108// passed, so that a caller can skip, with `if constexpr`, the code that would only add errors to
109// the reported one.
110
111// InputMapper: CountElements(), by which it is recognized.
112template <typename In, typename ElementId, typename = void>
113struct HasCountElements : std::false_type
114{
115};
116template <typename In, typename ElementId>
117struct HasCountElements<In, ElementId,
118 std::void_t<decltype(std::declval<const In&>().CountElements(std::declval<RecordIdOf<In>>(),
119 std::declval<RecordIdOf<In>>(), std::declval<ElementId*>()))>> : std::true_type
120{
121};
122
123// The InputMapper of CountElements().
124template <typename InputMapper>
125constexpr bool ValidateCountElements()
126{
127 constexpr bool isMapper = HasGetNumberOfRecords<InputMapper>::value &&
129 static_assert(isMapper,
130 "CountElements() requires an InputMapper: using ElementIdType, RecordIdType "
131 "GetNumberOfRecords() const, void CountElements(RecordIdType beginRecord, RecordIdType "
132 "endRecord, ElementIdType* counts) const");
133 return isMapper;
134}
135
136// Output: SetElement() with the values of an element.
137template <typename Out, typename ElementId, typename Void, typename... Values>
138struct HasSetElementImpl : std::false_type
139{
140};
141template <typename Out, typename ElementId, typename... Values>
142struct HasSetElementImpl<Out, ElementId,
143 std::void_t<decltype(std::declval<Out&>().SetElement(
144 std::declval<ElementId>(), std::declval<Values>()...))>,
145 Values...> : std::true_type
146{
147};
148template <typename Out, typename ElementId, typename... Values>
149using HasSetElement = HasSetElementImpl<Out, ElementId, void, Values...>;
150
151// SetElement() of the Output, with the values of an element.
152template <typename Output, typename ElementIdType, typename... Values>
153constexpr bool ValidateSetElement()
154{
155 constexpr bool hasSetElement = HasSetElement<Output, ElementIdType, Values...>::value;
156 static_assert(hasSetElement,
157 "Output must implement: SetElement(ElementIdType position, RecordIdType record) for an "
158 "Input, or SetElement(ElementIdType position, RecordIdType record, ElementIdType index) for "
159 "an InputMapper");
160 return hasSetElement;
161}
162
163// Input: GetKey().
164template <typename In, typename Key, typename = void>
165struct HasGetKey : std::false_type
166{
167};
168template <typename In, typename Key>
169struct HasGetKey<In, Key,
170 std::enable_if_t<std::is_convertible_v<
171 decltype(std::declval<const In&>().GetKey(std::declval<RecordIdOf<In>>())), Key>>>
172 : std::true_type
173{
174};
175
176// InputMapper: WriteKeys().
177template <typename In, typename ElementId, typename Key, typename = void>
178struct HasWriteKeys : std::false_type
179{
180};
181template <typename In, typename ElementId, typename Key>
182struct HasWriteKeys<In, ElementId, Key,
183 std::void_t<decltype(std::declval<const In&>().WriteKeys(std::declval<RecordIdOf<In>>(),
184 std::declval<RecordIdOf<In>>(), std::declval<const ElementId*>(), std::declval<Key*>()))>>
185 : std::true_type
186{
187};
188
189// Output: SetNumberOfElements().
190template <typename Out, typename ElementId, typename = void>
191struct HasSetNumberOfElements : std::false_type
192{
193};
194template <typename Out, typename ElementId>
195struct HasSetNumberOfElements<Out, ElementId,
196 std::void_t<decltype(std::declval<Out&>().SetNumberOfElements(std::declval<ElementId>()))>>
197 : std::true_type
198{
199};
200
201// The Input or InputMapper, and the Output, of a scatter. Every check needs the previous ones.
202template <typename Input, typename Output>
203constexpr bool ValidateScatter()
204{
205 using KeyType = KeyTypeOfT<Input>;
206 using ElementIdType = ElementIdTypeOfT<Input>;
207 constexpr bool hasRecords = HasGetNumberOfRecords<Input>::value;
208 static_assert(hasRecords, "Input must implement: RecordIdType GetNumberOfRecords() const");
209 if constexpr (hasRecords)
210 {
211 constexpr bool hasTypes = !std::is_void_v<KeyType> && std::is_integral_v<ElementIdType>;
212 static_assert(hasTypes,
213 "Input must implement KeyType GetKey(RecordIdType record) const (Input), or declare a "
214 "KeyType and an integer ElementIdType (InputMapper)");
215 if constexpr (hasTypes)
216 {
217 constexpr bool isInput = HasGetKey<Input, KeyType>::value;
218 constexpr bool isMapper = HasCountElements<Input, ElementIdType>::value;
219 static_assert(isInput || isMapper,
220 "Input must implement KeyType GetKey(RecordIdType record) const (Input), or void "
221 "CountElements(RecordIdType beginRecord, RecordIdType endRecord, ElementIdType* counts) "
222 "const (InputMapper)");
223 static_assert(!(isInput && isMapper), "Input is both an Input and an InputMapper");
224 constexpr bool hasWriteKeys = !isMapper || HasWriteKeys<Input, ElementIdType, KeyType>::value;
225 static_assert(hasWriteKeys,
226 "InputMapper must implement: void WriteKeys(RecordIdType beginRecord, RecordIdType "
227 "endRecord, const ElementIdType* offsets, KeyType* keys) const");
229 static_assert(
230 hasSize, "Output must implement: void SetNumberOfElements(ElementIdType numberOfElements)");
231 return isInput != isMapper && hasWriteKeys && hasSize;
232 }
233 }
234 return false;
235}
236
237// The keys of ScatterDense(): integers, indexed by their difference with the minimum key.
238template <typename KeyType>
239constexpr bool ValidateDenseKey()
240{
241 constexpr bool isKey = std::is_integral_v<KeyType> && !std::is_same_v<KeyType, bool>;
242 static_assert(
243 isKey, "The keys of ScatterDense() must be integers: use ScatterSparse() otherwise");
244 return isKey;
245}
246
247// An array of elements to scatter.
248template <typename Element, typename ElementIdType>
249constexpr bool ValidateArray()
250{
251 static_assert(
252 std::is_integral_v<ElementIdType>, "The number of elements must be of an integer type");
253 static_assert(std::is_copy_assignable_v<Element>, "The elements must be copy assignable");
254 return std::is_integral_v<ElementIdType> && std::is_copy_assignable_v<Element>;
255}
256
257// Element and sparse KeyType: operator<.
258template <typename T, typename = void>
259struct HasLess : std::false_type
260{
261};
262template <typename T>
263struct HasLess<T,
264 std::enable_if_t<
265 std::is_convertible_v<decltype(std::declval<const T&>() < std::declval<const T&>()), bool>>>
266 : std::true_type
267{
268};
269
270// The keys of ScatterSparse(): sorted, and stored, by value.
271template <typename KeyType>
272constexpr bool ValidateSparseKey()
273{
274 constexpr bool isKey = HasLess<KeyType>::value && std::is_default_constructible_v<KeyType> &&
275 std::is_copy_assignable_v<KeyType>;
276 static_assert(isKey,
277 "The keys of ScatterSparse() must be default constructible, copy assignable, and implement "
278 "operator<");
279 return isKey;
280}
281
282// Functors: the optional Initialize() and Reduce() of a vtkSMPTools functor.
283template <typename P, typename = void>
284struct HasInitialize : std::false_type
285{
286};
287template <typename P>
288struct HasInitialize<P, std::void_t<decltype(std::declval<P&>().Initialize())>> : std::true_type
289{
290};
291
292template <typename P, typename = void>
293struct HasReduce : std::false_type
294{
295};
296template <typename P>
297struct HasReduce<P, std::void_t<decltype(std::declval<P&>().Reduce())>> : std::true_type
298{
299};
300
301// Keys: whether a type derives from KeysBase, e.g., DenseKeys, SparseKeys and their reductions.
302template <typename TKey, typename TElementId, typename TKeyId>
304std::false_type IsKeysImpl(...);
305template <typename T>
306using IsKeys = decltype(IsKeysImpl(std::declval<const T*>()));
307
308// Keys: DenseKeys, SparseKeys or their reductions.
309template <typename Keys>
310constexpr bool ValidateKeys()
311{
312 static_assert(IsKeys<Keys>::value,
313 "The keys must be DenseKeys or SparseKeys, as returned by ScatterDense() or ScatterSparse()");
314 return IsKeys<Keys>::value;
315}
316
317// The functor of ForEachKeyRange().
318template <typename Functor, typename Output, typename Keys, typename... Args>
320{
321 constexpr bool isFunctor = std::is_invocable_v<Functor&, Output&, typename Keys::KeyIdType,
322 typename Keys::KeyIdType, const typename Keys::ElementIdType*, Args...>;
323 static_assert(isFunctor,
324 "The functor of ForEachKeyRange() must implement: operator()(Output& output, KeyIdType "
325 "beginKeyId, KeyIdType "
326 "endKeyId, const ElementIdType* offsets, args...)");
327 return isFunctor;
328}
329
330// The reduce functor of Reduce().
331template <typename Functor, typename Output, typename Keys>
332constexpr bool ValidateReduceFunctor()
333{
334 constexpr bool isFunctor = std::is_invocable_v<Functor&, Output&, typename Keys::KeyIdType,
335 typename Keys::KeyIdType, const typename Keys::ElementIdType*, typename Keys::ElementIdType*>;
336 static_assert(isFunctor,
337 "The reduce functor of Reduce() must implement: void operator()(Output& output, KeyIdType "
338 "beginKeyId, KeyIdType endKeyId, const ElementIdType* offsets, ElementIdType* counts)");
339 return isFunctor;
340}
341
342// Output: CopyData(), for Compact().
343template <typename Out, typename ElementId, typename = void>
344struct HasCopyData : std::false_type
345{
346};
347template <typename Out, typename ElementId>
348struct HasCopyData<Out, ElementId,
349 std::void_t<decltype(std::declval<Out&>().CopyData(std::declval<const Out&>(),
350 std::declval<ElementId>(), std::declval<ElementId>(), std::declval<ElementId>()))>>
351 : std::true_type
352{
353};
354
355// The Output of Compact().
356template <typename Output, typename ElementIdType>
357constexpr bool ValidateCompactOutput()
358{
361 static_assert(isOutput,
362 "The Output of Compact() must implement: void SetNumberOfElements(ElementIdType), and void "
363 "CopyData(const Output& source, ElementIdType destinationStart, ElementIdType count, "
364 "ElementIdType sourceStart)");
365 return isOutput;
366}
367
368// Element: operator==.
369template <typename T, typename = void>
370struct HasEqual : std::false_type
371{
372};
373template <typename T>
374struct HasEqual<T,
375 std::enable_if_t<
376 std::is_convertible_v<decltype(std::declval<const T&>() == std::declval<const T&>()), bool>>>
377 : std::true_type
378{
379};
380
381// The elements of SortUnique.
382template <typename Element>
383constexpr bool ValidateSortUnique()
384{
385 constexpr bool isElement = HasLess<Element>::value && HasEqual<Element>::value;
386 static_assert(isElement, "The elements of SortUnique must implement: operator< and operator==");
387 return isElement;
388}
389
390// The group functor of Group().
391template <typename Functor, typename Output, typename Keys>
392constexpr bool ValidateGroupFunctor()
393{
394 constexpr bool isFunctor = std::is_invocable_v<Functor&, Output&, typename Keys::KeyIdType,
395 typename Keys::KeyIdType, const typename Keys::ElementIdType*, uint8_t*>;
396 static_assert(isFunctor,
397 "The group functor of Group() must implement: void operator()(Output& output, KeyIdType "
398 "beginKeyId, KeyIdType endKeyId, const ElementIdType* offsets, uint8_t* groupStarts)");
399 return isFunctor;
400}
401
402// Element: operator!=.
403template <typename T, typename = void>
404struct HasNotEqual : std::false_type
405{
406};
407template <typename T>
408struct HasNotEqual<T,
409 std::enable_if_t<
410 std::is_convertible_v<decltype(std::declval<const T&>() != std::declval<const T&>()), bool>>>
411 : std::true_type
412{
413};
414
415// The elements of SortGroup.
416template <typename Element>
417constexpr bool ValidateSortGroup()
418{
419 constexpr bool isElement = HasLess<Element>::value && HasNotEqual<Element>::value;
420 static_assert(isElement, "The elements of SortGroup must implement: operator< and operator!=");
421 return isElement;
422}
423
424VTK_ABI_NAMESPACE_END
425} // namespace detail
426} // namespace keys
427} // namespace vtk
428
429#endif
430// VTK-HeaderTest-Exclude: vtkKeysTraits.h
What DenseKeys and SparseKeys share, and all that Reduce(), Group(), Compact() and ForEachKeyRange() ...
Definition vtkKeys.h:150
decltype(IsKeysImpl(std::declval< const T * >())) IsKeys
constexpr bool ValidateKeyRangeFunctor()
std::true_type IsKeysImpl(const KeysBase< TKey, TElementId, TKeyId > *)
constexpr bool ValidateCompactOutput()
constexpr bool ValidateReduceFunctor()
constexpr bool ValidateScatter()
typename ElementIdTypeOf< In >::type ElementIdTypeOfT
HasSetElementImpl< Out, ElementId, void, Values... > HasSetElement
constexpr bool ValidateSparseKey()
std::decay_t< decltype(std::declval< const T & >().GetKey())> ElementKeyOf
constexpr bool ValidateCountElements()
constexpr bool ValidateSortGroup()
std::decay_t< decltype(std::declval< const In & >().GetNumberOfRecords())> RecordIdOf
constexpr bool ValidateSetElement()
constexpr bool ValidateArray()
constexpr bool ValidateDenseKey()
typename KeyTypeOf< In >::type KeyTypeOfT
constexpr bool ValidateKeys()
constexpr bool ValidateGroupFunctor()
constexpr bool ValidateSortUnique()
Specialization of tuple ranges and iterators for vtkAOSDataArrayTemplate.
std::decay_t< decltype(std::declval< const In & >().GetKey(std::declval< RecordIdOf< In > >()))> type