From 0d9374d3ddcaa76de11ba70a331e6d9057e76371 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 22 Mar 2019 11:54:29 +1100 Subject: [PATCH] coord/base: add `indices` query using supplemental values --- coord/base.hpp | 53 ++++++++++++++++++++++++++++++++++++++++++++------ test/coord.cpp | 11 +++++++++-- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/coord/base.hpp b/coord/base.hpp index bddd2bca..742220df 100644 --- a/coord/base.hpp +++ b/coord/base.hpp @@ -232,22 +232,63 @@ namespace cruft::coord { /////////////////////////////////////////////////////////////////////// - /// returns an instance with elements specified by the Indices + /// Returns an instance with elements specified by the Indices /// parameter. eg, point2f p{}.indices<0,2> would return {p.x, p.z}. /// - /// it's ugly as sin, but simplifies some situations where we don't - /// want a temporary. - template + /// Given we don't take any arguments all indices must be valid for + /// the current object. + template < + std::size_t ...Indices, + typename = std::enable_if_t + > constexpr auto indices (void) const + { + return redim_t { + this->data[Indices]... + }; + } + + + /// Return an instance of the same type where the elements of the new + /// value area specified by the Indices... template parameter. + /// + /// If the index is greater than the maximum index of this type then + /// the value is taken from a pack of supplementary values. + /// + /// eg, vector2f{0,1}.indices<0,2,1> (2) would result in {0,2,1} + template < + std::size_t ...Indices, + typename ...U, + typename = std::enable_if_t< + // At least one index doesn't address our current data + cruft::max (Indices...) >= S && + // The new data type must be the old data type + (std::is_same_v && ...) + > + > + constexpr auto + indices (U&& ...supplementary) const { static_assert ( - all (make_vector ((Indices < S)...)), + cruft::max (Indices...) < S + sizeof...(supplementary), "indices must fall within the defined range for the type" ); + // Expand the pack using either: + // * data from ourselves, + // * or rebasing the index into a tuple of the supplementary values + // + // The index to std::get _must_ be valid even if we don't use the + // result (otherwise we tend to encounter static assertions). Thus + // we conditionally specify a zero index if we know it won't get + // used. return redim_t { - this->data[Indices]... + Indices < S + ? this->data[Indices] + : std::get< + (Indices > S) ? Indices - S : 0 + > (std::tuple (supplementary...))... }; } }; diff --git a/test/coord.cpp b/test/coord.cpp index d9161b44..0ebdd1ad 100644 --- a/test/coord.cpp +++ b/test/coord.cpp @@ -104,9 +104,16 @@ main (void) // ensure that klass::indices appears to link correctly { const cruft::vector3i seq { 0, 1, 2 }; - const cruft::vector4i res { 2, 0, 0, 1 }; - tap.expect_eq (seq.indices<2,0,0,1> (), res, "coord::indices expansion"); + { + const cruft::vector4i res { 2, 0, 0, 1 }; + tap.expect_eq (seq.indices<2,0,0,1> (), res, "coord::indices expansion"); + } + + { + const cruft::vector4i res { 2, 3, 4, 0 }; + tap.expect_eq (seq.indices<2,3,4,0> (3, 4), res, "coord::indices supplemental expansion"); + } }; // ensure that cruft::shift operations appear to operate correctly