Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Probably UB but I am finding it hard to give a fuck (C++ swizzle)

156 views
Skip to first unread message

Mr Flibble

unread,
Dec 18, 2019, 4:35:23 PM12/18/19
to
Hi!

The following is the base class of my vector class (the mathematical vector not the container) so I can do things like:

vec3 v1 = { 1.0, 2.0, 3.0 };
vec2 v2 = v1.xy;
double z = v1.z;
vec4 v3 = v1.xyzz;

So we have an anonymous union of an anonymous struct and some swizzles and I suspect it is full of UB but I am finding it hard to care as I cannot see any other way of doing this.

Collective thoughts/wisdom?

// swizzle_array.hpp
/*
neogfx C++ GUI Library
Copyright (c) 2019 Leigh Johnston. All Rights Reserved.

This program is free software: you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <neogfx/neogfx.hpp>
#include <neogfx/core/swizzle.hpp>

namespace neogfx
{
namespace math
{
template <typename V, typename T, uint32_t Size>
struct swizzle_array
{
typedef T value_type;
typedef std::array<value_type, Size> array_type;
typedef V vector_type;

union
{
array_type v;
struct // todo: alignment, padding?
{
value_type x;
value_type y;
value_type z;
};
swizzle<vector_type, array_type, 2, 0, 0> xx;
swizzle<vector_type, array_type, 2, 0, 1> xy;
swizzle<vector_type, array_type, 2, 0, 2> xz;
swizzle<vector_type, array_type, 2, 1, 0> yx;
swizzle<vector_type, array_type, 2, 1, 1> yy;
swizzle<vector_type, array_type, 2, 1, 2> yz;
swizzle<vector_type, array_type, 2, 2, 0> zx;
swizzle<vector_type, array_type, 2, 2, 1> zy;
swizzle<vector_type, array_type, 2, 2, 2> zz;
swizzle<vector_type, array_type, 3, 0, 0, 0> xxx;
swizzle<vector_type, array_type, 3, 0, 0, 1> xxy;
swizzle<vector_type, array_type, 3, 0, 0, 2> xxz;
swizzle<vector_type, array_type, 3, 0, 1, 0> xyx;
swizzle<vector_type, array_type, 3, 0, 1, 1> xyy;
swizzle<vector_type, array_type, 3, 0, 1, 2> xyz;
swizzle<vector_type, array_type, 3, 1, 0, 0> yxx;
swizzle<vector_type, array_type, 3, 1, 0, 1> yxy;
swizzle<vector_type, array_type, 3, 1, 0, 2> yxz;
swizzle<vector_type, array_type, 3, 1, 1, 0> yyx;
swizzle<vector_type, array_type, 3, 1, 1, 1> yyy;
swizzle<vector_type, array_type, 3, 1, 1, 2> yyz;
swizzle<vector_type, array_type, 3, 1, 2, 0> yzx;
swizzle<vector_type, array_type, 3, 1, 2, 1> yzy;
swizzle<vector_type, array_type, 3, 1, 2, 2> yzz;
swizzle<vector_type, array_type, 3, 2, 0, 0> zxx;
swizzle<vector_type, array_type, 3, 2, 0, 1> zxy;
swizzle<vector_type, array_type, 3, 2, 0, 2> zxz;
swizzle<vector_type, array_type, 3, 2, 1, 0> zyx;
swizzle<vector_type, array_type, 3, 2, 1, 1> zyy;
swizzle<vector_type, array_type, 3, 2, 1, 2> zyz;
swizzle<vector_type, array_type, 3, 2, 2, 0> zzx;
swizzle<vector_type, array_type, 3, 2, 2, 1> zzy;
swizzle<vector_type, array_type, 3, 2, 2, 2> zzz;
};
};

template <typename V, typename T>
struct swizzle_array<V, T, 1>
{
typedef T value_type;
typedef std::array<value_type, 1> array_type;
typedef V vector_type;

union
{
array_type v;
struct // todo: alignment, padding?
{
value_type x;
};
swizzle<vector_type, array_type, 2, 0, 0> xx;
swizzle<vector_type, array_type, 3, 0, 0, 0> xxx;
};
};

template <typename V, typename T>
struct swizzle_array<V, T, 2>
{
typedef T value_type;
typedef std::array<value_type, 2> array_type;
typedef V vector_type;

union
{
array_type v;
struct // todo: alignment, padding?
{
value_type x;
value_type y;
};
swizzle<vector_type, array_type, 2, 0, 0> xx;
swizzle<vector_type, array_type, 2, 0, 1> xy;
swizzle<vector_type, array_type, 2, 1, 0> yx;
swizzle<vector_type, array_type, 2, 1, 1> yy;
swizzle<vector_type, array_type, 3, 0, 0, 0> xxx;
swizzle<vector_type, array_type, 3, 0, 0, 1> xxy;
swizzle<vector_type, array_type, 3, 0, 1, 0> xyx;
swizzle<vector_type, array_type, 3, 0, 1, 1> xyy;
swizzle<vector_type, array_type, 3, 1, 0, 0> yxx;
swizzle<vector_type, array_type, 3, 1, 0, 1> yxy;
swizzle<vector_type, array_type, 3, 1, 1, 0> yyx;
swizzle<vector_type, array_type, 3, 1, 1, 1> yyy;
};
};

template <typename V, typename T>
struct swizzle_array<V, T, 3>
{
typedef T value_type;
typedef std::array<value_type, 3> array_type;
typedef V vector_type;

union
{
array_type v;
struct // todo: alignment, padding?
{
value_type x;
value_type y;
value_type z;
};
swizzle<vector_type, array_type, 2, 0, 0> xx;
swizzle<vector_type, array_type, 2, 0, 1> xy;
swizzle<vector_type, array_type, 2, 0, 2> xz;
swizzle<vector_type, array_type, 2, 1, 0> yx;
swizzle<vector_type, array_type, 2, 1, 1> yy;
swizzle<vector_type, array_type, 2, 1, 2> yz;
swizzle<vector_type, array_type, 2, 2, 0> zx;
swizzle<vector_type, array_type, 2, 2, 1> zy;
swizzle<vector_type, array_type, 2, 2, 2> zz;
swizzle<vector_type, array_type, 3, 0, 0, 0> xxx;
swizzle<vector_type, array_type, 3, 0, 0, 1> xxy;
swizzle<vector_type, array_type, 3, 0, 0, 2> xxz;
swizzle<vector_type, array_type, 3, 0, 1, 0> xyx;
swizzle<vector_type, array_type, 3, 0, 1, 1> xyy;
swizzle<vector_type, array_type, 3, 0, 1, 2> xyz;
swizzle<vector_type, array_type, 3, 1, 0, 0> yxx;
swizzle<vector_type, array_type, 3, 1, 0, 1> yxy;
swizzle<vector_type, array_type, 3, 1, 0, 2> yxz;
swizzle<vector_type, array_type, 3, 1, 1, 0> yyx;
swizzle<vector_type, array_type, 3, 1, 1, 1> yyy;
swizzle<vector_type, array_type, 3, 1, 1, 2> yyz;
swizzle<vector_type, array_type, 3, 1, 2, 0> yzx;
swizzle<vector_type, array_type, 3, 1, 2, 1> yzy;
swizzle<vector_type, array_type, 3, 1, 2, 2> yzz;
swizzle<vector_type, array_type, 3, 2, 0, 0> zxx;
swizzle<vector_type, array_type, 3, 2, 0, 1> zxy;
swizzle<vector_type, array_type, 3, 2, 0, 2> zxz;
swizzle<vector_type, array_type, 3, 2, 1, 0> zyx;
swizzle<vector_type, array_type, 3, 2, 1, 1> zyy;
swizzle<vector_type, array_type, 3, 2, 1, 2> zyz;
swizzle<vector_type, array_type, 3, 2, 2, 0> zzx;
swizzle<vector_type, array_type, 3, 2, 2, 1> zzy;
swizzle<vector_type, array_type, 3, 2, 2, 2> zzz;
};
};
}
}

/Flibble

--
"Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin

“You won’t burn in hell. But be nice anyway.” – Ricky Gervais

“I see Atheists are fighting and killing each other again, over who doesn’t believe in any God the most. Oh, no..wait.. that never happens.” – Ricky Gervais

"Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say."

Öö Tiib

unread,
Dec 18, 2019, 5:24:20 PM12/18/19
to
On Wednesday, 18 December 2019 23:35:23 UTC+2, Mr Flibble wrote:
> Hi!
>
> The following is the base class of my vector class (the mathematical vector not the container) so I can do things like:
>
> vec3 v1 = { 1.0, 2.0, 3.0 };
> vec2 v2 = v1.xy;
> double z = v1.z;
> vec4 v3 = v1.xyzz;
>
> So we have an anonymous union of an anonymous struct and some swizzles and I suspect it is full of UB but I am finding it hard to care as I cannot see any other way of doing this.
>
> Collective thoughts/wisdom?

It likely violates strict aliasing, casting between unrelated types
and also how unions are allowed to be used in C++.

So even if it appears to work with your compilers on cases
you did test it might mess it up differently in other use-cases
that you did not test yet. Also it may change with next patch to
any of your compilers.

Can you say what is the issue with typical interface
implementable to work same on all C++11 or better compilers:

vec3 v1 = { 1.0, 2.0, 3.0 };
vec2 v2 = v1.xy();
double z = v1.z();
vec4 v3 = v1.xyzz();

Couple of extra parentheses can't be problem, otherwise we all
would switch to Kotlin (that is *way* less verbose than C++).

Mr Flibble

unread,
Dec 18, 2019, 6:15:06 PM12/18/19
to
Because

v1.set_z(42.0);

is ew and

v1.z() = 42.0

is even more ew.

Öö Tiib

unread,
Dec 18, 2019, 6:36:26 PM12/18/19
to
I trust v1.moveBy(0.0, 0.0, 39.0) or
v1.moveTo(1.0, 2.0, 42.0) depending what was the point
is simpler to understand than v1.z = 42.0 anyway.

Chris M. Thomasson

unread,
Dec 18, 2019, 6:38:58 PM12/18/19
to
On 12/18/2019 1:34 PM, Mr Flibble wrote:
> Hi!
>
> The following is the base class of my vector class (the mathematical
> vector not the container) so I can do things like:
>
> vec3 v1 = { 1.0, 2.0, 3.0 };
> vec2 v2 = v1.xy;
> double z = v1.z;
> vec4 v3 = v1.xyzz;
>
> So we have an anonymous union of an anonymous struct and some swizzles
> and I suspect it is full of UB but I am finding it hard to care as I
> cannot see any other way of doing this.
>
> Collective thoughts/wisdom?
[...]

Are you trying to get close to GLSL? The glm lib for C++ is very close,
but its does not have the .xyz type of functionality. Interesting.

vec4 v4 = vec4(v3.xyz, 1.0);

v4 now equals { v3.x, v3.y, v3.z, 1.0 }



Mr Flibble

unread,
Dec 19, 2019, 1:18:46 AM12/19/19
to
No. v1 += vec3{ 0.0, 0.0, 39.0 } is.

Mr Flibble

unread,
Dec 19, 2019, 1:20:08 AM12/19/19
to
That is the goal, yes.

Alf P. Steinbach

unread,
Dec 19, 2019, 4:49:21 AM12/19/19
to
On 19.12.2019 00:14, Mr Flibble wrote:
> v1.set_z(42.0);
>
> is ew and
>
> v1.z() = 42.0
>
> is even more ew.

#define Z z()

There.


- Alf

Manfred

unread,
Dec 19, 2019, 8:25:44 AM12/19/19
to
On 12/18/2019 10:34 PM, Mr Flibble wrote:
> Hi!
>
> The following is the base class of my vector class (the mathematical
> vector not the container) so I can do things like:
>
> vec3 v1 = { 1.0, 2.0, 3.0 };
> vec2 v2 = v1.xy;
> double z = v1.z;
> vec4 v3 = v1.xyzz;
>
> So we have an anonymous union of an anonymous struct and some swizzles
> and I suspect it is full of UB but I am finding it hard to care as I
> cannot see any other way of doing this.
>
> Collective thoughts/wisdom?

Sounds like a union is not the right tool, unless I am misinterpreting
the purpose.
Possibly xy, z, xyz etc. should be object members that overload the
assignment and type cast (aka user-defined conversion) operators.
Inside the body of the overloads you perform the actions you need on the
vector (so you need a reference to the vector inside the members).

Manfred

unread,
Dec 19, 2019, 8:29:51 AM12/19/19
to
On 12/19/2019 12:14 AM, Mr Flibble wrote:
>> Can you say what is the issue with typical interface
>> implementable to work same on all C++11 or better compilers:
>>
>>   vec3 v1 = { 1.0, 2.0, 3.0 };
>>   vec2 v2 = v1.xy();
>>   double z = v1.z();
>>   vec4 v3 = v1.xyzz();
>>
>> Couple of extra parentheses can't be problem, otherwise we all
>> would switch to Kotlin (that is *way* less verbose than C++).
>
> Because
>
> v1.set_z(42.0);
>
> is ew and
>
> v1.z() = 42.0
>
> is even more ew.
>
> /Flibble

A slightly better (IMO) interface is:
void z(double val);
double z() const;

That doesn't change much, though.

woodb...@gmail.com

unread,
Dec 20, 2019, 11:22:37 AM12/20/19
to

Please don't swear here.


Brian
Ebenezer Enterprises - Enjoying programming again.
https://github.com/Ebenezer-group/onward

Mr Flibble

unread,
Dec 21, 2019, 8:24:14 AM12/21/19
to
On 20/12/2019 16:22, woodb...@gmail.com wrote:
>
> Please don't swear here.

Fuck. Off.

Chris M. Thomasson

unread,
Dec 23, 2019, 1:34:15 PM12/23/19
to
On 12/18/2019 10:19 PM, Mr Flibble wrote:
> On 18/12/2019 23:38, Chris M. Thomasson wrote:
>> On 12/18/2019 1:34 PM, Mr Flibble wrote:
[...]
>> Are you trying to get close to GLSL? The glm lib for C++ is very
>> close, but its does not have the .xyz type of functionality. Interesting.
>>
>> vec4 v4 = vec4(v3.xyz, 1.0);
>>
>> v4 now equals { v3.x, v3.y, v3.z, 1.0 }
>
> That is the goal, yes.

Perfect. Thanks for the work. I would like to use it from time to time.

Fwiw, sometimes get a little pissed when I see a swizzle, and have to
port the damn shader over to my C++ code. Now, going from C++ to GLSL is
"easier", in certain respects...

Sometimes when I see shi% like, just typing this in:
________________
vec2 foo = vec2(1., 2.);
vec3 bar = vec3(foo.xy, 3.);
vec4 foobar = vec4(foo.xy, bar.yz);

foobar = { 1., 2., 2., 3. }
________________

;^)

Chris M. Thomasson

unread,
Dec 28, 2019, 3:31:03 AM12/28/19
to
On 12/18/2019 10:19 PM, Mr Flibble wrote:
> On 18/12/2019 23:38, Chris M. Thomasson wrote:
>> On 12/18/2019 1:34 PM, Mr Flibble wrote:
>>> Hi!
>>>
>>> The following is the base class of my vector class (the mathematical
>>> vector not the container) so I can do things like:
>>>
>>> vec3 v1 = { 1.0, 2.0, 3.0 };
>>> vec2 v2 = v1.xy;
>>> double z = v1.z;
>>> vec4 v3 = v1.xyzz;
>>>
>>> So we have an anonymous union of an anonymous struct and some
>>> swizzles and I suspect it is full of UB but I am finding it hard to
>>> care as I cannot see any other way of doing this.
>>>
>>> Collective thoughts/wisdom?
>> [...]
>>
>> Are you trying to get close to GLSL? The glm lib for C++ is very
>> close, but its does not have the .xyz type of functionality. Interesting.
>>
>> vec4 v4 = vec4(v3.xyz, 1.0);
>>
>> v4 now equals { v3.x, v3.y, v3.z, 1.0 }
>
> That is the goal, yes.

Looking forward to using C++ with swizzles, using your work, to render
something like the following experiment of mine:

https://youtu.be/TLd64a4gdZQ

Mr Flibble

unread,
Dec 28, 2019, 10:53:57 AM12/28/19
to
Probably best waiting until I get SIMD specializations working.

/Flibble

--
“You won’t burn in hell. But be nice anyway.” – Ricky Gervais
“I see Atheists are fighting and killing each other again, over who
doesn’t believe in any God the most. Oh, no..wait.. that never happens.”
– Ricky Gervais
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What

Chris M. Thomasson

unread,
Jan 11, 2020, 6:08:39 PM1/11/20
to
On 12/18/2019 1:34 PM, Mr Flibble wrote:
> Hi!
>
> The following is the base class of my vector class (the mathematical
> vector not the container) so I can do things like:
>
> vec3 v1 = { 1.0, 2.0, 3.0 };
> vec2 v2 = v1.xy;
> double z = v1.z;
> vec4 v3 = v1.xyzz;
[...]

Almost getting enough time to try it out. Its an interesting go at the
problem. Fwiw, here is a new animation that can benefit from this in C++:

https://youtu.be/Q6lJqIl-Nvs

Chris M. Thomasson

unread,
Feb 1, 2020, 12:42:20 AM2/1/20
to
On 12/18/2019 1:34 PM, Mr Flibble wrote:
> Hi!
>
> The following is the base class of my vector class (the mathematical
> vector not the container) so I can do things like:
[...]

I think I saw a swizzle in here:

https://youtu.be/O-1zEo7DD8w

live shader code competition.

Chris M. Thomasson

unread,
Feb 1, 2020, 2:00:30 AM2/1/20
to
No problem. Keep up the great work.

Bonita Montero

unread,
Feb 10, 2020, 12:36:02 PM2/10/20
to
> Almost getting enough time to try it out. Its an interesting go at the
> problem. Fwiw, here is a new animation that can benefit from this in C++:
> https://youtu.be/Q6lJqIl-Nvs

You have diffuse associations.
Not that you'll end up where Aminer is today.

Chris M. Thomasson

unread,
Feb 10, 2020, 5:08:06 PM2/10/20
to
Creating a swizzle in C++ that can behave like GLSL is not a trivial
task. However, it should help anybody who is porting shader code over to
a pure C++ representation.
0 new messages