Similarly as done in Aug 2024 in Corrade. When these were a part of the
function signature, they ended up being encoded into the exported
symbol. There are still cases of StridedArrayView slice() having
enable_if in the signature, which amounts to about 18 kB symbols in all
libMagnum*-d.so libraries, but apart from that this is the state before:
$ strings libMagnum*-d.so | grep enable_if | grep -v slice | wc -c
29591
And this is after. All of those are coming from STL, thus from
old or deprecated APIs that still use std::vector, std::tuple and such,
and from the few std::sort() uses.
$ strings libMagnum*-d.so | grep enable_if | grep -v slice | wc -c
4103
In a non-deprecated build it's just this, which is a 10x reduction.
Can't really do much about these maybe exceút for implementing my own
swap() specializations (sigh?), but I think it's fine.
$ strings libMagnum*-d.so | grep enable_if | grep -v slice | wc -c
2904
I also made it consistently use
typename std::enable_if<..., int>::type = 0
instead of
class = typename std::enable_if<...>::type
because the former works correctly also in presence of overloads and
having it used consistently everywhere makes it easier to grep & change
later. All SFINAE is now also excluded from Doxygen output, because it
doesn't make much sense there. It's better to just explain the
restriction in words than with this nasty hack.
While branching on a compiler is rather common, checking a particular
compiler version should be needed only rarely. Thus minimize use of such
macros to make them easier to grep for.
As implementation-specific index types cause the index buffer to be
strided. which is not allowed by default, these work only if
InterleaveFlag::PreserveStridedIndices is set. Originally I thought
about straight-out disallowing implementation-specific types here,
unfortunately that broke some valid use cases so I backtracked on that
decision.
In the future I might change the default to preserve
implementation-specific indices with sane strides (i.e., positive powers
of 2), but that will only be done once similar treatment is finished for
attributes (currently zero and negative strides are just disallowed
completely).
Otherwise it makes a tightly-packed copy. This also means that arbitrary
padding before/after the index buffer is preserved only in case it would
mean the data can be transferred without a copy -- otherwise it's faster
to just drop the padding and copy only the used part.
I tried, I really did, but the downsides eventually just outweighed the
potential of this feature and I gave up. May try to tackle this again in
the future, but not now.
This took me quite a while to realize -- not always it's desirable to
have the original layout unconditionally preserved, especially if for
example filtering a MeshData to just a subset of attributes.
Haha, I even had a TODO here. An exception in this case is when the mesh
is already interleaved -- then the layout is kept intact and thus it's
not needed to know what vertex format sizes to repack.
Originally this was done in order to make handling of deserialized data
much simpler (as for those attributes also need to only contain an
offset into some unknown data array), but seems this could be very
useful elsewhere as well -- for example when the layout is known
beforehand but the actual data not yet -- such as in the Line and
Gradient primitives (going to switch them to this in the next commit).
What still unfortunately has to be known in advance is the actual vertex
count (as supplying it directly to MeshData would mean adding 6 new
constructor overloads, and there's enough of those already). Might
revisit later.
This was originally meant to be an interleave() that operates on
MeshData, but later I realized I need the same logic in duplicate(), so
turned it into a private function. Now I am pretty sure I'll be using
this function in *many* importer plugins :D