FastLED 3.9.15
Loading...
Searching...
No Matches
type_traits.h
Go to the documentation of this file.
1#pragma once
2
3/*
4Provides eanble_if and is_derived for compilers before C++14.
5*/
6
7#include <stddef.h>
8#include <stdint.h>
9
10#include "fl/namespace.h"
11
12namespace fl { // mandatory namespace to prevent name collision with
13 // std::enable_if.
14
15// Define enable_if for SFINAE
16template <bool Condition, typename T = void> struct enable_if {};
17
18// Specialization for true condition
19template <typename T> struct enable_if<true, T> {
20 using type = T;
21};
22
23// if enable_if<Condition, T> is true, then there will be a member type
24// called type. Otherwise it will not exist. This is (ab)used to enable
25// constructors and other functions based on template parameters. If there
26// is no member type, then the compiler will not fail to bind to the target
27// function or operation.
28template <bool Condition, typename T = void>
30
31// Define is_base_of to check inheritance relationship
32template <typename Base, typename Derived> struct is_base_of {
33 private:
34 typedef uint8_t yes;
35 typedef uint16_t no;
36 static yes test(Base *); // Matches if Derived is convertible to Base*
37 static no test(...); // Fallback if not convertible
38 enum {
39 kSizeDerived = sizeof(test(static_cast<Derived *>(nullptr))),
40 };
41
42 public:
43 static constexpr bool value = (kSizeDerived == sizeof(yes));
44};
45
46// Define is_base_of_v for compatibility with pre-C++14
47// Replaced variable template with a constant static member
48template <typename Base, typename Derived> struct is_base_of_v_helper {
49 static constexpr bool value = is_base_of<Base, Derived>::value;
50};
51
52// Define is_same trait
53template <typename T, typename U> struct is_same {
54 static constexpr bool value = false;
55};
56
57// Specialization for when T and U are the same type
58template <typename T> struct is_same<T, T> {
59 static constexpr bool value = true;
60};
61
62// Define is_same_v for compatibility with variable templates
63template <typename T, typename U> struct is_same_v_helper {
64 static constexpr bool value = is_same<T, U>::value;
65};
66
67// Define remove_reference trait
68template <typename T> struct remove_reference {
69 using type = T;
70};
71
72// Specialization for lvalue reference
73template <typename T> struct remove_reference<T &> {
74 using type = T;
75};
76
77// Specialization for rvalue reference
78template <typename T> struct remove_reference<T &&> {
79 using type = T;
80};
81
82// Helper alias template for remove_reference
83template <typename T>
85
86// Define conditional trait
87template <bool B, typename T, typename F> struct conditional {
88 using type = T;
89};
90
91template <typename T, typename F> struct conditional<false, T, F> {
92 using type = F;
93};
94
95template <bool B, typename T, typename F>
97
98// Define is_array trait
99template <typename T> struct is_array {
100 static constexpr bool value = false;
101};
102
103template <typename T> struct is_array<T[]> {
104 static constexpr bool value = true;
105};
106
107template <typename T, size_t N> struct is_array<T[N]> {
108 static constexpr bool value = true;
109};
110
111// Define remove_extent trait
112template <typename T> struct remove_extent {
113 using type = T;
114};
115
116template <typename T> struct remove_extent<T[]> {
117 using type = T;
118};
119
120template <typename T, size_t N> struct remove_extent<T[N]> {
121 using type = T;
122};
123
124// Define is_function trait
125template <typename T> struct is_function {
126 static constexpr bool value = false;
127};
128
129template <typename Ret, typename... Args> struct is_function<Ret(Args...)> {
130 static constexpr bool value = true;
131};
132
133template <typename Ret, typename... Args>
134struct is_function<Ret(Args...) const> {
135 static constexpr bool value = true;
136};
137
138template <typename Ret, typename... Args>
139struct is_function<Ret(Args...) volatile> {
140 static constexpr bool value = true;
141};
142
143template <typename Ret, typename... Args>
144struct is_function<Ret(Args...) const volatile> {
145 static constexpr bool value = true;
146};
147
148// Define add_pointer trait
149template <typename T> struct add_pointer {
150 using type = T *;
151};
152
153template <typename T> struct add_pointer<T &> {
154 using type = T *;
155};
156
157template <typename T> struct add_pointer<T &&> {
158 using type = T *;
159};
160
161template <typename T> using add_pointer_t = typename add_pointer<T>::type;
162
163// Define remove_const trait
164template <typename T> struct remove_const {
165 using type = T;
166};
167
168template <typename T> struct remove_const<const T> {
169 using type = T;
170};
171
172// Implementation of move
173template <typename T>
174constexpr typename remove_reference<T>::type &&move(T &&t) noexcept {
175 return static_cast<typename remove_reference<T>::type &&>(t);
176}
177
178// Define is_lvalue_reference trait
179template <typename T> struct is_lvalue_reference {
180 static constexpr bool value = false;
181};
182
183template <typename T> struct is_lvalue_reference<T &> {
184 static constexpr bool value = true;
185};
186
187// Implementation of forward
188template <typename T>
189constexpr T &&forward(typename remove_reference<T>::type &t) noexcept {
190 return static_cast<T &&>(t);
191}
192
193// Overload for rvalue references
194template <typename T>
195constexpr T &&forward(typename remove_reference<T>::type &&t) noexcept {
196 static_assert(!is_lvalue_reference<T>::value,
197 "Cannot forward an rvalue as an lvalue");
198 return static_cast<T &&>(t);
199}
200
201// Define remove_cv trait
202template <typename T> struct remove_cv {
203 using type = T;
204};
205
206template <typename T> struct remove_cv<const T> {
207 using type = T;
208};
209
210template <typename T> struct remove_cv<volatile T> {
211 using type = T;
212};
213
214template <typename T> struct remove_cv<const volatile T> {
215 using type = T;
216};
217
218template <typename T> using remove_cv_t = typename remove_cv<T>::type;
219
220// Define decay trait
221template <typename T> struct decay {
222 private:
223 using U = typename remove_reference<T>::type;
224
225 public:
226 using type = typename conditional<
229 typename add_pointer<U>::type,
231};
232
233template <typename T> using decay_t = typename decay<T>::type;
234
235// Define is_pod trait (basic implementation)
236template <typename T> struct is_pod {
237 static constexpr bool value = false; // Default to false for safety
238};
239
240// Specializations for fundamental types
241template <> struct is_pod<bool> {
242 static constexpr bool value = true;
243};
244template <> struct is_pod<char> {
245 static constexpr bool value = true;
246};
247template <> struct is_pod<signed char> {
248 static constexpr bool value = true;
249};
250template <> struct is_pod<unsigned char> {
251 static constexpr bool value = true;
252};
253template <> struct is_pod<short> {
254 static constexpr bool value = true;
255};
256template <> struct is_pod<unsigned short> {
257 static constexpr bool value = true;
258};
259template <> struct is_pod<int> {
260 static constexpr bool value = true;
261};
262template <> struct is_pod<unsigned int> {
263 static constexpr bool value = true;
264};
265template <> struct is_pod<long> {
266 static constexpr bool value = true;
267};
268template <> struct is_pod<unsigned long> {
269 static constexpr bool value = true;
270};
271template <> struct is_pod<long long> {
272 static constexpr bool value = true;
273};
274template <> struct is_pod<unsigned long long> {
275 static constexpr bool value = true;
276};
277template <> struct is_pod<float> {
278 static constexpr bool value = true;
279};
280template <> struct is_pod<double> {
281 static constexpr bool value = true;
282};
283template <> struct is_pod<long double> {
284 static constexpr bool value = true;
285};
286
287// Helper struct for is_pod_v (similar to other _v helpers)
288template <typename T> struct is_pod_v_helper {
289 static constexpr bool value = is_pod<T>::value;
290};
291
292//----------------------------------------------------------------------------
293// trait to detect pointer‑to‑member‑function
294// must come before Function so SFINAE sees it
295//----------------------------------------------------------------------------
296template <typename T> struct is_member_function_pointer;
297template <typename C, typename Ret, typename... A>
298struct is_member_function_pointer<Ret (C::*)(A...)>;
299template <typename C, typename Ret, typename... A>
300struct is_member_function_pointer<Ret (C::*)(A...) const>;
301
302template <typename T> struct is_member_function_pointer {
303 static constexpr bool value = false;
304};
305
306template <typename C, typename Ret, typename... A>
307struct is_member_function_pointer<Ret (C::*)(A...)> {
308 static constexpr bool value = true;
309};
310
311template <typename C, typename Ret, typename... A>
312struct is_member_function_pointer<Ret (C::*)(A...) const> {
313 static constexpr bool value = true;
314};
315
316//-------------------------------------------------------------------------------
317// is_integral trait (built-in integer types only)
318//-------------------------------------------------------------------------------
319template <typename T> struct is_integral {
320 static constexpr bool value = false;
321};
322template <> struct is_integral<bool> {
323 static constexpr bool value = true;
324};
325template <> struct is_integral<char> {
326 static constexpr bool value = true;
327};
328template <> struct is_integral<signed char> {
329 static constexpr bool value = true;
330};
331template <> struct is_integral<unsigned char> {
332 static constexpr bool value = true;
333};
334template <> struct is_integral<short> {
335 static constexpr bool value = true;
336};
337template <> struct is_integral<unsigned short> {
338 static constexpr bool value = true;
339};
340template <> struct is_integral<int> {
341 static constexpr bool value = true;
342};
343template <> struct is_integral<unsigned int> {
344 static constexpr bool value = true;
345};
346template <> struct is_integral<long> {
347 static constexpr bool value = true;
348};
349template <> struct is_integral<unsigned long> {
350 static constexpr bool value = true;
351};
352template <> struct is_integral<long long> {
353 static constexpr bool value = true;
354};
355template <> struct is_integral<unsigned long long> {
356 static constexpr bool value = true;
357};
358
359template <typename T> struct is_integral<const T> {
360 static constexpr bool value = is_integral<T>::value;
361};
362
363template <typename T> struct is_integral<volatile T> {
364 static constexpr bool value = is_integral<T>::value;
365};
366
367template <typename T> struct is_integral<T &> {
368 static constexpr bool value = is_integral<T>::value;
369};
370
371// This uses template magic to maybe generate a type for the given condition. If
372// that type doesn't exist then a type will fail to be generated, and the
373// compiler will skip the consideration of a target function. This is useful for
374// enabling template constructors that only become available if the class can be
375// upcasted to the desired type.
376//
377// Example:
378// This is an optional upcasting constructor for a Ref<T>. If the type U is not
379// derived from T then the constructor will not be generated, and the compiler
380// will skip it.
381//
382// template <typename U, typename = fl::is_derived<T, U>>
383// Ref(const Ref<U>& refptr) : referent_(refptr.get());
384template <typename Base, typename Derived>
386
387//-----------------------------------------------------------------------------
388// detect whether T has a member void swap(T&)
389//-----------------------------------------------------------------------------
390template <typename T> struct has_member_swap {
391 private:
392 // must be 1 byte vs. >1 byte for sizeof test
393 typedef uint8_t yes;
394 typedef uint16_t no;
395
396 // helper<U, &U::swap> is only well-formed if U::swap(T&) exists with that
397 // signature
398 template <typename U, void (U::*M)(U &)> struct helper {};
399
400 // picks this overload if helper<U, &U::swap> is valid
401 template <typename U> static yes test(helper<U, &U::swap> *);
402
403 // fallback otherwise
404 template <typename> static no test(...);
405
406 public:
407 static constexpr bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
408};
409
410// primary template: dispatch on has_member_swap<T>::value
411template <typename T, bool = has_member_swap<T>::value> struct swap_impl;
412
413// POD case
414template <typename T> struct swap_impl<T, false> {
415 static void apply(T &a, T &b) {
416 T tmp = a;
417 a = b;
418 b = tmp;
419 }
420};
421
422// non‑POD case (requires T implements swap)
423template <typename T> struct swap_impl<T, true> {
424 static void apply(T &a, T &b) { a.swap(b); }
425};
426
427// single entry‑point
428template <typename T> void swap(T &a, T &b) {
429 // if T is a POD, use use a simple data copy swap.
430 // if T is not a POD, use the T::Swap method.
432}
433
434template <typename T> void swap_by_copy(T &a, T &b) {
435 // if T is a POD, use use a simple data copy swap.
436 // if T is not a POD, use the T::Swap method.
437 T tmp = a;
438 a = b;
439 b = tmp;
440}
441
442// Container type checks.
443template <typename T, typename... Types> struct contains_type;
444
445template <typename T> struct contains_type<T> {
446 static constexpr bool value = false;
447};
448
449template <typename T, typename U, typename... Rest>
450struct contains_type<T, U, Rest...> {
451 static constexpr bool value =
453};
454
455// Helper to get maximum size of types
456template <typename... Types> struct max_size;
457
458template <> struct max_size<> {
459 static constexpr size_t value = 0;
460};
461
462template <typename T, typename... Rest> struct max_size<T, Rest...> {
463 static constexpr size_t value = (sizeof(T) > max_size<Rest...>::value)
464 ? sizeof(T)
465 : max_size<Rest...>::value;
466};
467
468// Helper to get maximum alignment of types
469template <typename... Types> struct max_align;
470
471template <> struct max_align<> {
472 static constexpr size_t value = 1;
473};
474
475template <typename T, typename... Rest> struct max_align<T, Rest...> {
476 static constexpr size_t value = (alignof(T) > max_align<Rest...>::value)
477 ? alignof(T)
478 : max_align<Rest...>::value;
479};
480
481} // namespace fl
482
483// For comparison operators that return bool against pod data. The class obj
484// will need to supply the comparison operator for the pod type. This example
485// will show how to define a comparison operator for a class that can be
486// compared against a pod type.
487// Example:
488// FASTLED_DEFINE_POD_COMPARISON_OPERATOR(Myclass, >=) will allow MyClass to
489// be compared MyClass obj; return obj >= 0;
490#define FASTLED_DEFINE_POD_COMPARISON_OPERATOR(CLASS, OP) \
491 template <typename T, typename U> \
492 typename fl::enable_if< \
493 fl::is_same<U, CLASS>::value && fl::is_pod<T>::value, bool>::type \
494 operator OP(const T &pod, const CLASS &obj) { \
495 return pod OP obj; \
496 } \
497 template <typename T> \
498 typename fl::enable_if<fl::is_pod<T>::value, bool>::type operator OP( \
499 const CLASS &obj, const T &pod) { \
500 return obj OP pod; \
501 }
Implements the FastLED namespace macros.
constexpr remove_reference< T >::type && move(T &&t) noexcept
typename conditional< B, T, F >::type conditional_t
Definition type_traits.h:96
void swap(array< T, N > &lhs, array< T, N > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Definition array.h:140
typename remove_cv< T >::type remove_cv_t
typename decay< T >::type decay_t
enable_if_t< is_base_of< Base, Derived >::value > is_derived
void swap_by_copy(T &a, T &b)
typename add_pointer< T >::type add_pointer_t
typename enable_if< Condition, T >::type enable_if_t
Definition type_traits.h:29
constexpr T && forward(typename remove_reference< T >::type &t) noexcept
typename remove_reference< T >::type remove_reference_t
Definition type_traits.h:84
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
static constexpr bool value
typename remove_reference< T >::type U
typename conditional< is_array< U >::value, typename remove_extent< U >::type *, typename conditional< is_function< U >::value, typename add_pointer< U >::type, typename remove_cv< U >::type >::type >::type type
static no test(...)
static yes test(helper< U, &U::swap > *)
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
Definition type_traits.h:49
static no test(...)
static constexpr bool value
Definition type_traits.h:43
static yes test(Base *)
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
Definition type_traits.h:59
static constexpr bool value
Definition type_traits.h:64
static constexpr bool value
Definition type_traits.h:54
static constexpr size_t value
static constexpr size_t value
static constexpr size_t value
static constexpr size_t value
static void apply(T &a, T &b)
static void apply(T &a, T &b)