Browse code

Add offset to Members

Robert Cranston authored on 08/03/2023 23:08:40
Showing 4 changed files

... ...
@@ -399,8 +399,15 @@ either
399 399
 -   `T` itself, if `T` is a [scalar][]
400 400
 
401 401
 then `constexpr auto GLTraits::members<T>()` returns an instance of the
402
-[empty][] `struct GLTraits::Members<typename T, typename... Values>` where
403
-`Values...` are the ("member") types above, in the order they occur in `T`.
402
+[empty][] `struct GLTraits::Members<typename T, typename... Members>` where
403
+each of `Members...` is `GLTraits::Member<typename Value, std::size_t offset>`
404
+that describe the ("member") types above, in the order they occur in `T`.
405
+`Value` is the type of the member and `offset` is the offset of the member in
406
+`T`. Note that `offset` is only correct if the padding in `T` is minimal while
407
+still satisfying the [`alignof`][] of the member types. The author knows of no
408
+compiler that breaks this assumption unless explicitly instructed (e.g. with
409
+[`alignas`][], which are not taken into account), however the standard allows
410
+it.
404 411
 
405 412
 An example use case would be along the lines of:
406 413
 
... ...
@@ -408,26 +415,22 @@ An example use case would be along the lines of:
408 415
 template<
409 416
     typename    T,
410 417
     typename    Value,
411
-    typename... Values
418
+    std::size_t offset,
419
+    typename... Members
412 420
 >
413 421
 void vertex_setup(
414
-    GLTraits::Members<T, Value, Values...>,
415
-    std::size_t offset   = 0,
416
-    GLint       location = 0
422
+    GLTraits::Members<T, GLTraits::Member<Value, offset>, Members...>,
423
+    GLint location = 0
417 424
 )
418 425
 {
419
-    auto unaligned = offset % alignof(Value);
420
-    if (unaligned)
421
-        offset += alignof(Value) - unaligned;
422 426
     GLTraits::Value<Value>::vertex_attrib_pointer(location, offset, sizeof(T));
423 427
     vertex_setup(
424
-        GLTraits::Members<T, Values...>{},
425
-        offset   + sizeof(Value),
428
+        GLTraits::Members<T, Members...>{},
426 429
         location + GLTraits::Value<Value>::columns
427 430
     );
428 431
 }
429 432
 template<typename T>
430
-void vertex_setup(GLTraits::Members<T>, std::size_t, GLint)
433
+void vertex_setup(GLTraits::Members<T>, GLint)
431 434
 {}
432 435
 
433 436
 struct Vertex
... ...
@@ -462,6 +465,8 @@ version [`magic_get`][]) on whose talks this implementation is based:
462 465
 [class]: https://en.cppreference.com/w/cpp/types/is_class
463 466
 [array]: https://en.cppreference.com/w/cpp/types/is_array
464 467
 [scalar]: https://en.cppreference.com/w/cpp/types/is_scalar
468
+[`alignof`]: https://en.cppreference.com/w/cpp/language/alignof
469
+[`alignas`]: https://en.cppreference.com/w/cpp/language/alignas
465 470
 [`tests/vertex_setup.cpp`]: tests/vertex_setup.cpp
466 471
 [`doc/vertex_setup`]: doc/vertex_setup
467 472
 [`doc/vertex_setup.i`]: doc/vertex_setup.i
... ...
@@ -42,7 +42,11 @@ public:
42 42
 
43 43
     #if __cplusplus >= 201402L
44 44
 
45
-    template<typename T, typename... Value>
45
+    template<typename Value, std::size_t offset>
46
+    struct Member
47
+    {};
48
+
49
+    template<typename T, typename... Member>
46 50
     struct Members
47 51
     {};
48 52
 
... ...
@@ -101,7 +105,8 @@ private:
101 105
 
102 106
     struct MemberInfo
103 107
     {
104
-        GLenum id;
108
+        GLenum      id;
109
+        std::size_t offset;
105 110
     };
106 111
 
107 112
     template<std::size_t N>
... ...
@@ -114,11 +119,18 @@ private:
114 119
     {
115 120
         MemberInfo * info;
116 121
 
122
+        constexpr static auto align(std::size_t align, std::size_t offset)
123
+        {
124
+            return ((offset - 1) / align + 1) * align;
125
+        }
126
+
117 127
         template<typename Value>
118 128
         constexpr operator Value()
119 129
         {
120 130
             return (
121
-                info->id = GLTraits::Value<Value>::id,
131
+                info[0].id     = GLTraits::Value<Value>::id,
132
+                info[0].offset = align(alignof(Value), info[0].offset),
133
+                info[1].offset = info[0].offset + sizeof(Value),
122 134
                 Value{}
123 135
             );
124 136
         }
... ...
@@ -144,7 +156,7 @@ private:
144 156
     }
145 157
 
146 158
     template<typename T, std::size_t... Is>
147
-    static constexpr auto member_infos(MemberInfos<sizeof...(Is)> infos = {})
159
+    static constexpr auto member_infos(MemberInfos<sizeof...(Is)+1> infos = {})
148 160
     {
149 161
         return ((void)T{MemberAny{&infos.infos[Is]}...}, infos);
150 162
     }
... ...
@@ -154,7 +166,10 @@ private:
154 166
     {
155 167
         return Members<
156 168
             T,
157
-            typename ValueID<member_infos<T, Is...>().infos[Is].id>::Value...
169
+            Member<
170
+                typename ValueID<member_infos<T, Is...>().infos[Is].id>::Value,
171
+                member_infos<T, Is...>().infos[Is].offset
172
+            >...
158 173
         >{};
159 174
     }
160 175
 
... ...
@@ -113,24 +113,25 @@ struct GLTraitsTest : protected GLBase
113 113
     template<
114 114
         typename    T,
115 115
         typename    Value,
116
-        typename... Values
116
+        std::size_t offset,
117
+        typename... Members
117 118
     >
118 119
     void static test_members(
119
-        GLTraits::Members<T, Value, Values...>,
120
-        std::size_t offset = 0
120
+        GLTraits::Members<T, GLTraits::Member<Value, offset>, Members...>
121 121
     )
122 122
     {
123
-        auto unaligned = offset % alignof(Value);
124
-        if (unaligned)
125
-            offset += alignof(Value) - unaligned;
126
-        auto end = offset + sizeof(Value);
123
+        auto constexpr end = offset + sizeof(Value);
127 124
         using Traits = GLTraits::Value<Value>;
128 125
         static_assert(
129 126
             std::is_empty<GLTraits::Members<
130
-                T, Value, Values...
127
+                T, GLTraits::Member<Value, offset>, Members...
131 128
             >>::value,
132 129
             "GLTraits::Members must be empty"
133 130
         );
131
+        static_assert(
132
+            std::is_empty<GLTraits::Member<Value, offset>>::value,
133
+            "GLTraits::Member must be empty"
134
+        );
134 135
         #define GLTRAITS_TEST_MEMBERS(IND, NAME, OFFSET, END) \
135 136
             std::cout \
136 137
                 << std::left  << std::setw(IND)           << "" \
... ...
@@ -138,10 +139,10 @@ struct GLTraitsTest : protected GLBase
138 139
                 << std::right << std::setw(2) << std::dec << OFFSET << " " \
139 140
                 << std::right << std::setw(3) << std::dec << END    << "\n";
140 141
         GLTRAITS_TEST_MEMBERS(2, Traits::name, offset, end)
141
-        test_members(GLTraits::Members<T, Values...>{}, end);
142
+        test_members(GLTraits::Members<T, Members...>{});
142 143
     }
143 144
     template<typename T>
144
-    void static test_members(GLTraits::Members<T>, std::size_t)
145
+    void static test_members(GLTraits::Members<T>)
145 146
     {}
146 147
     #endif
147 148
 
... ...
@@ -9,26 +9,22 @@
9 9
 template<
10 10
     typename    T,
11 11
     typename    Value,
12
-    typename... Values
12
+    std::size_t offset,
13
+    typename... Members
13 14
 >
14 15
 void vertex_setup(
15
-    GLTraits::Members<T, Value, Values...>,
16
-    std::size_t offset   = 0,
17
-    GLint       location = 0
16
+    GLTraits::Members<T, GLTraits::Member<Value, offset>, Members...>,
17
+    GLint location = 0
18 18
 )
19 19
 {
20
-    auto unaligned = offset % alignof(Value);
21
-    if (unaligned)
22
-        offset += alignof(Value) - unaligned;
23 20
     GLTraits::Value<Value>::vertex_attrib_pointer(location, offset, sizeof(T));
24 21
     vertex_setup(
25
-        GLTraits::Members<T, Values...>{},
26
-        offset   + sizeof(Value),
22
+        GLTraits::Members<T, Members...>{},
27 23
         location + GLTraits::Value<Value>::columns
28 24
     );
29 25
 }
30 26
 template<typename T>
31
-void vertex_setup(GLTraits::Members<T>, std::size_t, GLint)
27
+void vertex_setup(GLTraits::Members<T>, GLint)
32 28
 {}
33 29
 
34 30