GLSL Struct 1.4.0
glslstruct
Loading...
Searching...
No Matches
layout_traits_concept.hpp
1/*
2 * glslstruct - a C++ library designed to easily represent GLSL's Uniform Buffer Objects (UBOs) and Shader Storage Buffer Objects (SSBOs) in C++.
3 *
4 * Licensed under the BSD 3-Clause License with Attribution Requirement.
5 * See the LICENSE file for details: https://github.com/MAIPA01/glslstruct/blob/main/LICENSE
6 *
7 * Copyright (c) 2025, Patryk Antosik (MAIPA01)
8 */
9
10#pragma once
11#ifndef _GLSL_STRUCT_LAYOUT_TRAITS_CONCEPT_HPP_
12 #define _GLSL_STRUCT_LAYOUT_TRAITS_CONCEPT_HPP_
13
14 #include <glslstruct/config.hpp>
15
17_GLSL_STRUCT_ERROR("This is only available for c++17 and greater!");
18 #else
19
20 #include <glslstruct/utils/ValueType.hpp>
21
22/**
23 * @defgroup layout_traits Layout Traits
24 * @brief Traits for different layouts
25 * @ingroup glslstruct
26 * @details Layout Trait needs to have defined static functions:
27 * @code{.cpp}
28 * size_t get_scalar_alignment(const ValueType type, [[optional(define only if you have using context_type)]] context_type& ctx); // returns base alignment of scalar with given scalar type
29 * size_t get_vec_alignment(const ValueType type, const size_t length, [[optional(define only if you have using context_type)]] context_type& ctx); // returns base alignment of vec with given scalar type and length
30 * size_t get_array_alignment(const size_t elemBaseAlignment, [[optional(define only if you have using context_type)]] context_type& ctx); // returns base alignment of array with given array elem base alignment
31 * size_t get_struct_alignment([[optional(define only if you have using context_type)]] context_type& ctx); // returns base alignment of struct
32 * @endcode
33 *
34 * There are also optional functions:
35 * - To make action before variable is added:
36 * @code{.cpp}
37 * // Default for all types
38 * void before_add(size_t& currentOffset, [[optional(define only if you have using context_type)]] context_type& ctx);
39 *
40 * // Specialized for given type (if defined they are invoked instead of before_add)
41 * void before_add_scalar(size_t& currentOffset, [[optional(define only if you have using context_type)]] context_type& ctx);
42 * void before_add_vec(size_t& currentOffset, [[optional(define only if you have using context_type)]] context_type& ctx);
43 * void before_add_mat(size_t& currentOffset, [[optional(define only if you have using context_type)]] context_type& ctx);
44 * void before_add_array(size_t& currentOffset, [[optional(define only if you have using context_type)]] context_type& ctx);
45 * void before_add_struct(size_t& currentOffset, [[optional(define only if you have using context_type)]] context_type& ctx);
46 * @endcode
47 *
48 * - To make some action after variable was added:
49 * @code{.cpp}
50 * // Default for all types
51 * void after_add(size_t& currentOffset, const size_t size, const size_t alignment, [[optional(define only if you have using context_type)]] context_type& ctx);
52 *
53 * // Specialized for given type (if defined they are invoked instead of after_add)
54 * void after_add_scalar(size_t& currentOffset, const size_t size, const size_t alignment, [[optional(define only if you have using context_type)]] context_type& ctx);
55 * void after_add_vec(size_t& currentOffset, const size_t size, const size_t alignment, [[optional(define only if you have using context_type)]] context_type& ctx);
56 * void after_add_mat(size_t& currentOffset, const size_t size, const size_t alignment, [[optional(define only if you have using context_type)]] context_type& ctx);
57 * void after_add_array(size_t& currentOffset, const size_t size, const size_t alignment, [[optional(define only if you have using context_type)]] context_type& ctx);
58 * void after_add_struct(size_t& currentOffset, const size_t size, const size_t alignment, [[optional(define only if you have using context_type)]] context_type& ctx);
59 * @endcode
60 */
61
62namespace glslstruct {
64 #pragma region CXX20_CONCEPTS
65
66 namespace utils {
67 #pragma region HAS_CONTEXT
68 /**
69 * @ingroup utils
70 * @brief Checks if a type T provides a nested 'context_type'.
71 *
72 * Layout traits can optionally depend on a context object (e.g., to track
73 * state across multiple member additions).
74 */
75 template<class T> concept has_layout_traits_context = requires { typename T::context_type; };
76 #pragma endregion
77
78 #pragma region GET_ALIGNMENT
79 /**
80 * @ingroup utils
81 * @brief Validates that T provides mandatory alignment calculation methods.
82 *
83 * A valid layout trait must implement static methods for calculating
84 * scalar, vector, array, and struct alignments.
85 *
86 * @tparam T The layout trait class.
87 * @tparam Args Optional context arguments.
88 */
89 template<class T, class... Args>
98 #pragma endregion
99
100 #pragma region BEFORE_ADD
101 #pragma region OPTIONAL
103
104 template<class T, class... Args>
108
110
111 template<class T, class... Args>
115
117
118 template<class T, class... Args>
122
124
125 template<class T, class... Args>
129
131
132 template<class T, class... Args>
136
138
139 template<class T, class... Args>
143 #pragma endregion
144
145 /**
146 * @ingroup utils
147 * @brief Validates optional "before_add" hooks.
148 *
149 * These hooks allow a layout trait to modify the current offset before a
150 * member is added to the structure.
151 */
152 template<class T, class... Args>
157 #pragma endregion
158
159 #pragma region AFTER_ADD
160 #pragma region OPTIONAL
162
163 template<class T, class... Args>
165 {
166 T::after_add(std::declval<size_t&>(), std::declval<const size_t>(), std::declval<const size_t>(),
167 std::declval<Args&>()...)
168 } -> std::same_as<void>;
169 };
170
172
173 template<class T, class... Args>
180
182
183 template<class T, class... Args>
190
192
193 template<class T, class... Args>
200
202
203 template<class T, class... Args>
210
212
213 template<class T, class... Args>
220 #pragma endregion
221
222 /**
223 * @ingroup utils
224 * @brief Validates optional "after_add" hooks.
225 *
226 * These hooks allow a layout trait to update the current offset or context
227 * after a member has been placed, often used to handle padding.
228 */
229 template<class T, class... Args>
234 #pragma endregion
235
236 template<class T>
240
241 template<class T>
244 } // namespace utils
245
246 /**
247 * @ingroup layout_traits
248 * @brief The primary concept for GLSL layout trait definitions.
249 *
250 * A type satisfies `layout_traits` if it provides the necessary alignment
251 * logic and follows the optional hook patterns, either with or without
252 * a nested context_type.
253 */
255
256 /**
257 * @ingroup layout_traits
258 * @brief Compile-time constant to check if T is a valid layout trait.
259 */
260 template<class T>
262
263 /**
264 * @ingroup layout_traits
265 * @brief Type trait to check if T is a valid layout trait.
266 */
267 template<class T>
269
270 namespace utils {
271 /**
272 * @ingroup layout_traits
273 * @name Feature Detection Constants
274 * @brief Boolean constants to detect specific optional methods within a layout trait.
275 * @{
276 */
277 template<class T>
279
280 #pragma region HAS_BEFORE_ADD
281 template<class T>
284
285 template<class T>
288
289 template<class T>
292
293 template<class T>
296
297 template<class T>
300
301 template<class T>
304 #pragma endregion
305
306 #pragma region HAS_AFTER_ADD
307 template<class T>
310
311 template<class T>
314
315 template<class T>
318
319 template<class T>
322
323 template<class T>
326
327 template<class T>
330 #pragma endregion
331 /** @} */
332 } // namespace utils
333
334 #pragma endregion
335 #else
336 #pragma region CXX17_CONCEPTS
337
338 namespace utils {
339 #pragma region HAS_CONTEXT
340
341 /**
342 * @ingroup layout_traits
343 * @brief Checks if a type T provides a nested 'context_type'.
344 *
345 * Layout traits can optionally depend on a context object (e.g., to track
346 * state across multiple member additions).
347 */
348 template<class T, class = void>
349 struct has_layout_traits_context : std::false_type {};
350
351 template<class T>
352 struct has_layout_traits_context<T, std::void_t<typename T::context_type> > : std::true_type {};
353
354 #pragma endregion
355
356 #pragma region GET_ALIGNMENT
357
358 /**
359 * @ingroup layout_traits
360 * @brief Validates that T provides mandatory alignment calculation methods.
361 *
362 * A valid layout trait must implement static methods for calculating
363 * scalar, vector, array, and struct alignments.
364 *
365 * @tparam T The layout trait class.
366 * @tparam Args Optional context arguments.
367 */
368 template<class T, class Enable, class... Args>
369 struct layout_traits_get_alignment : std::false_type {};
370
371 template<class T, class... Args>
374 decltype(T::get_scalar_alignment(std::declval<const ValueType>(), std::declval<Args&>()...))> >,
376 std::declval<const size_t>(), std::declval<Args&>()...))> >,
378 decltype(T::get_array_alignment(std::declval<const size_t>(), std::declval<Args&>()...))> >,
380 Args...> : std::true_type {};
381
382 #pragma endregion
383
384 #pragma region BEFORE_ADD
385 #pragma region OPTIONAL
386
387 template<class T, class = void>
388 struct has_layout_traits_opt_before_add : std::false_type {};
389
390 template<class T>
392
393 template<class T, class Enable, class... Args>
394 struct is_layout_traits_opt_before_add_valid : std::false_type {};
395
396 template<class T, class... Args>
399 decltype(T::before_add(std::declval<size_t&>(), std::declval<Args&>()...))> > >,
400 Args...> : std::true_type {};
401
402 template<class T, class... Args>
403 struct layout_traits_opt_before_add : std::bool_constant<!has_layout_traits_opt_before_add<T>::value ||
404 is_layout_traits_opt_before_add_valid<T, void, Args...>::value> {
405 };
406
407 template<class T, class = void>
408 struct has_layout_traits_opt_before_add_scalar : std::false_type {};
409
410 template<class T>
412
413 template<class T, class Enable, class... Args>
414 struct is_layout_traits_opt_before_add_scalar_valid : std::false_type {};
415
416 template<class T, class... Args>
419 decltype(T::before_add_scalar(std::declval<size_t&>(), std::declval<Args&>()...))> > >,
420 Args...> : std::true_type {};
421
422 template<class T, class... Args>
423 struct layout_traits_opt_before_add_scalar
424 : std::bool_constant<!has_layout_traits_opt_before_add_scalar<T>::value ||
425 is_layout_traits_opt_before_add_scalar_valid<T, void, Args...>::value> {};
426
427 template<class T, class = void>
428 struct has_layout_traits_opt_before_add_vec : std::false_type {};
429
430 template<class T>
432
433 template<class T, class Enable, class... Args>
434 struct is_layout_traits_opt_before_add_vec_valid : std::false_type {};
435
436 template<class T, class... Args>
439 decltype(T::before_add_vec(std::declval<size_t&>(), std::declval<Args&>()...))> > >,
440 Args...> : std::true_type {};
441
442 template<class T, class... Args>
443 struct layout_traits_opt_before_add_vec
444 : std::bool_constant<!has_layout_traits_opt_before_add_vec<T>::value ||
445 is_layout_traits_opt_before_add_vec_valid<T, void, Args...>::value> {};
446
447 template<class T, class = void>
448 struct has_layout_traits_opt_before_add_mat : std::false_type {};
449
450 template<class T>
452
453 template<class T, class Enable, class... Args>
454 struct is_layout_traits_opt_before_add_mat_valid : std::false_type {};
455
456 template<class T, class... Args>
459 decltype(T::before_add_mat(std::declval<size_t&>(), std::declval<Args&>()...))> > >,
460 Args...> : std::true_type {};
461
462 template<class T, class... Args>
463 struct layout_traits_opt_before_add_mat
464 : std::bool_constant<!has_layout_traits_opt_before_add_mat<T>::value ||
465 is_layout_traits_opt_before_add_mat_valid<T, void, Args...>::value> {};
466
467 template<class T, class = void>
468 struct has_layout_traits_opt_before_add_array : std::false_type {};
469
470 template<class T>
472
473 template<class T, class Enable, class... Args>
474 struct is_layout_traits_opt_before_add_array_valid : std::false_type {};
475
476 template<class T, class... Args>
479 decltype(T::before_add_array(std::declval<size_t&>(), std::declval<Args&>()...))> > >,
480 Args...> : std::true_type {};
481
482 template<class T, class... Args>
483 struct layout_traits_opt_before_add_array
484 : std::bool_constant<!has_layout_traits_opt_before_add_array<T>::value ||
485 is_layout_traits_opt_before_add_array_valid<T, void, Args...>::value> {};
486
487 template<class T, class = void>
488 struct has_layout_traits_opt_before_add_struct : std::false_type {};
489
490 template<class T>
492
493 template<class T, class Enable, class... Args>
494 struct is_layout_traits_opt_before_add_struct_valid : std::false_type {};
495
496 template<class T, class... Args>
499 decltype(T::before_add_struct(std::declval<size_t&>(), std::declval<Args&>()...))> > >,
500 Args...> : std::true_type {};
501
502 template<class T, class... Args>
503 struct layout_traits_opt_before_add_struct
504 : std::bool_constant<!has_layout_traits_opt_before_add_struct<T>::value ||
505 is_layout_traits_opt_before_add_struct_valid<T, void, Args...>::value> {};
506
507 #pragma endregion
508
509 /**
510 * @ingroup layout_traits
511 * @brief Validates optional "before_add" hooks.
512 *
513 * These hooks allow a layout trait to modify the current offset before a
514 * member is added to the structure.
515 */
516 template<class T, class... Args>
517 struct layout_traits_before_add
518 : std::bool_constant<
519 layout_traits_opt_before_add<T, Args...>::value && layout_traits_opt_before_add_scalar<T, Args...>::value &&
520 layout_traits_opt_before_add_vec<T, Args...>::value && layout_traits_opt_before_add_mat<T, Args...>::value &&
521 layout_traits_opt_before_add_array<T, Args...>::value && layout_traits_opt_before_add_struct<T, Args...>::value
522 > {};
523
524 #pragma endregion
525
526 #pragma region AFTER_ADD
527 #pragma region OPTIONAL
528
529 template<class T, class = void>
530 struct has_layout_traits_opt_after_add : std::false_type {};
531
532 template<class T>
533 struct has_layout_traits_opt_after_add<T, std::void_t<decltype(T::after_add)> > : std::true_type {};
534
535 template<class T, class Enable, class... Args>
536 struct is_layout_traits_opt_after_add_valid : std::false_type {};
537
538 template<class T, class... Args>
541 decltype(T::after_add(std::declval<size_t&>(), std::declval<const size_t>(), std::declval<const size_t>(),
542 std::declval<Args&>()...))> > >,
543 Args...> : std::true_type {};
544
545 template<class T, class... Args>
546 struct layout_traits_opt_after_add : std::bool_constant<!has_layout_traits_opt_after_add<T>::value ||
547 is_layout_traits_opt_after_add_valid<T, void, Args...>::value> {};
548
549 template<class T, class = void>
550 struct has_layout_traits_opt_after_add_scalar : std::false_type {};
551
552 template<class T>
554
555 template<class T, class Enable, class... Args>
556 struct is_layout_traits_opt_after_add_scalar_valid : std::false_type {};
557
558 template<class T, class... Args>
561 decltype(T::after_add_scalar(std::declval<size_t&>(), std::declval<const size_t>(), std::declval<const size_t>(),
562 std::declval<Args&>()...))> > >,
563 Args...> : std::true_type {};
564
565 template<class T, class... Args>
566 struct layout_traits_opt_after_add_scalar
567 : std::bool_constant<!has_layout_traits_opt_after_add_scalar<T>::value ||
568 is_layout_traits_opt_after_add_scalar_valid<T, void, Args...>::value> {};
569
570 template<class T, class = void>
571 struct has_layout_traits_opt_after_add_vec : std::false_type {};
572
573 template<class T>
575
576 template<class T, class Enable, class... Args>
577 struct is_layout_traits_opt_after_add_vec_valid : std::false_type {};
578
579 template<class T, class... Args>
582 decltype(T::after_add_vec(std::declval<size_t&>(), std::declval<const size_t>(), std::declval<const size_t>(),
583 std::declval<Args&>()...))> > >,
584 Args...> : std::true_type {};
585
586 template<class T, class... Args>
587 struct layout_traits_opt_after_add_vec
588 : std::bool_constant<!has_layout_traits_opt_after_add_vec<T>::value ||
589 is_layout_traits_opt_after_add_vec_valid<T, void, Args...>::value> {};
590
591 template<class T, class = void>
592 struct has_layout_traits_opt_after_add_mat : std::false_type {};
593
594 template<class T>
596
597 template<class T, class Enable, class... Args>
598 struct is_layout_traits_opt_after_add_mat_valid : std::false_type {};
599
600 template<class T, class... Args>
603 decltype(T::after_add_mat(std::declval<size_t&>(), std::declval<const size_t>(), std::declval<const size_t>(),
604 std::declval<Args&>()...))> > >,
605 Args...> : std::true_type {};
606
607 template<class T, class... Args>
608 struct layout_traits_opt_after_add_mat
609 : std::bool_constant<!has_layout_traits_opt_after_add_mat<T>::value ||
610 is_layout_traits_opt_after_add_mat_valid<T, void, Args...>::value> {};
611
612 template<class T, class = void>
613 struct has_layout_traits_opt_after_add_array : std::false_type {};
614
615 template<class T>
617
618 template<class T, class Enable, class... Args>
619 struct is_layout_traits_opt_after_add_array_valid : std::false_type {};
620
621 template<class T, class... Args>
624 decltype(T::after_add_array(std::declval<size_t&>(), std::declval<const size_t>(), std::declval<const size_t>(),
625 std::declval<Args&>()...))> > >,
626 Args...> : std::true_type {};
627
628 template<class T, class... Args>
629 struct layout_traits_opt_after_add_array
630 : std::bool_constant<!has_layout_traits_opt_after_add_array<T>::value ||
631 is_layout_traits_opt_after_add_array_valid<T, void, Args...>::value> {};
632
633 template<class T, class = void>
634 struct has_layout_traits_opt_after_add_struct : std::false_type {};
635
636 template<class T>
638
639 template<class T, class Enable, class... Args>
640 struct is_layout_traits_opt_after_add_struct_valid : std::false_type {};
641
642 template<class T, class... Args>
645 decltype(T::after_add_struct(std::declval<size_t&>(), std::declval<const size_t>(), std::declval<const size_t>(),
646 std::declval<Args&>()...))> > >,
647 Args...> : std::true_type {};
648
649 template<class T, class... Args>
650 struct layout_traits_opt_after_add_struct
651 : std::bool_constant<!has_layout_traits_opt_after_add_struct<T>::value ||
652 is_layout_traits_opt_after_add_struct_valid<T, void, Args...>::value> {};
653
654 #pragma endregion
655
656 /**
657 * @ingroup layout_traits
658 * @brief Validates optional "after_add" hooks.
659 *
660 * These hooks allow a layout trait to update the current offset or context
661 * after a member has been placed, often used to handle padding.
662 */
663 template<class T, class... Args>
664 struct layout_traits_after_add
665 : std::bool_constant<
666 layout_traits_opt_after_add<T, Args...>::value && layout_traits_opt_after_add_scalar<T, Args...>::value &&
667 layout_traits_opt_after_add_vec<T, Args...>::value && layout_traits_opt_after_add_mat<T, Args...>::value &&
668 layout_traits_opt_after_add_array<T, Args...>::value && layout_traits_opt_after_add_struct<T, Args...>::value
669 > {};
670
671 #pragma endregion
672
673 template<class T>
674 struct layout_traits_with_context
675 : std::bool_constant<has_layout_traits_context<T>::value &&
676 layout_traits_get_alignment<T, void, typename T::context_type>::value &&
677 layout_traits_before_add<T, typename T::context_type>::value &&
678 layout_traits_after_add<T, typename T::context_type>::value> {};
679
680 template<class T>
681 struct layout_traits_without_context
682 : std::bool_constant<!has_layout_traits_context<T>::value && layout_traits_get_alignment<T, void>::value &&
683 layout_traits_before_add<T>::value && layout_traits_after_add<T>::value> {};
684 } // namespace utils
685
686 /**
687 * @ingroup layout_traits
688 * @brief The primary concept for GLSL layout trait definitions.
689 *
690 * A type satisfies `layout_traits` if it provides the necessary alignment
691 * logic and follows the optional hook patterns, either with or without
692 * a nested context_type.
693 */
694 template<class T>
695 struct is_layout_traits
696 : std::bool_constant<utils::layout_traits_with_context<T>::value || utils::layout_traits_without_context<T>::value> {};
697
698 /**
699 * @ingroup layout_traits
700 * @brief Compile-time constant to check if T is a valid layout trait.
701 */
702 template<class T>
703 static _GLSL_STRUCT_CONSTEXPR17 const bool is_layout_traits_v = is_layout_traits<T>::value;
704
705 namespace utils {
706 /**
707 * @ingroup layout_traits
708 * @name Feature Detection Constants
709 * @brief Boolean constants to detect specific optional methods within a layout trait.
710 * @{
711 */
712 template<class T>
713 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_context_v =
715
716 #pragma region HAS_BEFORE_ADD
717 template<class T>
718 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_before_add_v =
720
721 template<class T>
722 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_before_add_scalar_v =
724
725 template<class T>
726 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_before_add_vec_v =
728
729 template<class T>
730 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_before_add_mat_v =
732
733 template<class T>
734 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_before_add_array_v =
736
737 template<class T>
738 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_before_add_struct_v =
740 #pragma endregion
741
742 #pragma region HAS_AFTER_ADD
743 template<class T>
744 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_after_add_v =
746
747 template<class T>
748 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_after_add_scalar_v =
750
751 template<class T>
752 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_after_add_vec_v =
754
755 template<class T>
756 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_after_add_mat_v =
758
759 template<class T>
760 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_after_add_array_v =
762
763 template<class T>
764 static _GLSL_STRUCT_CONSTEXPR17 bool has_layout_traits_after_add_struct_v =
766 #pragma endregion
767 /** @} */
768 } // namespace utils
769
770 #pragma endregion
771 #endif
772} // namespace glslstruct
773
774 #endif
775#endif
#define _GLSL_STRUCT_HAS_CXX20
check if compiler has c++ version greater or equal to c++20 and if user enabled c++20 features using ...
Definition config.hpp:142
#define _GLSL_STRUCT_HAS_CXX17
check if compiler has c++ version greater or equal to c++17
Definition config.hpp:130
#define _GLSL_STRUCT_CONSTEXPR17
constexpr for c++17 and higher
Definition config.hpp:196
Definition writer.hpp:25
Main namespace of glslstruct library.
Definition scalar_layout_traits.hpp:23