From 84963aacf80c27a606bf4cbcf503c2af1d3348c5 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 14:32:58 +1000 Subject: [PATCH] coord/ops: make 'all' and 'any' constexpr --- coord/ops.hpp | 70 +++++++++++++++++++++++++++++++++++++++++++------- test/coord.cpp | 12 +++++++++ 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/coord/ops.hpp b/coord/ops.hpp index c02a8700..2e488311 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -899,38 +899,90 @@ namespace util { #undef SCALAR_OP - //------------------------------------------------------------------------- + /////////////////////////////////////////////////////////////////////////// + namespace detail { + template < + std::size_t S, + template class K, + std::size_t ...I, + typename = std::enable_if_t< + is_coord_v>, + void + > + > + constexpr bool + any (const K k, std::index_sequence) + { + return (k[I] || ...); + } + }; + + + ///--------------------------------------------------------------------------- + /// returns true if any element is true. + /// + /// this function must be suitable for use in static_assert, so it must remain + /// constexpr. + /// + /// we would ideally use std::any_of, but it is not constexpr. + /// we would ideally use range-for, but cbegin is not constexpr. + /// so... moar templates. template < size_t S, template class K, typename = std::enable_if_t< is_coord_v>, void - > + >, + typename Indices = std::make_index_sequence > constexpr bool any (const K k) { - return std::any_of (std::cbegin (k), - std::cend (k), - identity); + return detail::any (k, Indices{}); + } + + + /////////////////////////////////////////////////////////////////////////// + namespace detail { + template < + std::size_t S, + template class K, + std::size_t ...I, + typename = std::enable_if_t< + is_coord_v>, + void + > + > + constexpr bool + all (const K k, std::index_sequence) + { + return (k[I] && ...); + } } //------------------------------------------------------------------------- + /// returns true if all elements are true. + /// + /// this function must be suitable for use in static_assert, so it must be + /// constexpr. + /// + /// we would ideally use std::all_of, but it is not constexpr. + /// we would ideally use range-for, but cbegin is not constexpr. + /// so... moar templates. template < size_t S, template class K, typename = std::enable_if_t< is_coord_v>, void - > + >, + typename Indices = std::make_index_sequence > constexpr bool all (const K k) { - return std::all_of (std::cbegin (k), - std::cend (k), - identity); + return detail::all (k, Indices {}); } diff --git a/test/coord.cpp b/test/coord.cpp index c2b9f183..593cc0ec 100644 --- a/test/coord.cpp +++ b/test/coord.cpp @@ -54,6 +54,18 @@ main (void) ); } + // test expected outputs for various logical operations + { + constexpr util::point3i a { 0, -1, 2 }; + constexpr util::point3i b { 0, 1, -2 }; + constexpr util::point3i c { -9, -9, -9 }; + + tap.expect (!all (a <= b), "all, expected failure"); + tap.expect ( all (a <= a), "all, expected success"); + tap.expect (!any (a <= c), "any, expected failure"); + tap.expect ( any (a <= b), "any, expected success"); + }; + // ensure the util::select function behaves as expected { const util::point3f a { -1, 2, 0 };