From 12d401b98bcbef548ce1479c3b5a4a04c9c960c6 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 15 Mar 2018 23:48:21 +1100 Subject: [PATCH] tuple/variadic: split into type/value/pack operations --- CMakeLists.txt | 4 +- coord/ops.hpp | 5 +- iterator.hpp | 2 +- job/queue.hpp | 2 - test/tuple.cpp | 16 +++- tuple.cpp | 19 ---- tuple.hpp | 229 ------------------------------------------------ tuple/type.hpp | 162 ++++++++++++++++++++++++++++++++++ tuple/value.hpp | 75 ++++++++++++++++ types.hpp | 5 +- variadic.hpp | 50 ++++++++--- 11 files changed, 294 insertions(+), 275 deletions(-) delete mode 100644 tuple.cpp delete mode 100644 tuple.hpp create mode 100644 tuple/type.hpp create mode 100644 tuple/value.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b84817fa..5624bc43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -368,8 +368,8 @@ list ( time.hpp time/parse.hpp time/parse8601.cpp - tuple.cpp - tuple.hpp + tuple/type.hpp + tuple/value.hpp typeidx.cpp typeidx.hpp types/bits.hpp diff --git a/coord/ops.hpp b/coord/ops.hpp index 4fe4b2a1..f003a865 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -22,10 +22,9 @@ // we specifically rely on vector to compute a few logical operations #include "../vector.hpp" - +#include "../tuple/value.hpp" #include "../debug.hpp" #include "../maths.hpp" -#include "../tuple.hpp" #include "../preprocessor.hpp" #include "../types/bits.hpp" @@ -495,7 +494,7 @@ namespace util { return RetT { std::apply ( func, - ::util::tuple::convert ( + ::util::tuple::value::map ( static_cast< const value_t& (&)(const part_t&) > ( diff --git a/iterator.hpp b/iterator.hpp index e302129a..0c9a8c10 100644 --- a/iterator.hpp +++ b/iterator.hpp @@ -420,7 +420,7 @@ namespace util { izip (const ContainerT&... data) { return zip ( - ::util::make_indices (::util::variadic::first (data...)), + ::util::make_indices (::util::variadic::get<0> (data...)), data... ); } diff --git a/job/queue.hpp b/job/queue.hpp index f1de0337..ad67059f 100644 --- a/job/queue.hpp +++ b/job/queue.hpp @@ -19,8 +19,6 @@ #include "../pool.hpp" -#include "../tuple.hpp" - #include "ticketlock.hpp" #include "semaphore.hpp" #include "flag.hpp" diff --git a/test/tuple.cpp b/test/tuple.cpp index b76f3f70..37cb0134 100644 --- a/test/tuple.cpp +++ b/test/tuple.cpp @@ -1,4 +1,5 @@ -#include "tuple.hpp" +#include "tuple/type.hpp" +#include "tuple/value.hpp" #include "tap.hpp" @@ -17,12 +18,19 @@ main () { util::TAP::logger tap; + static_assert ( + util::tuple::type::index< + std::tuple, + int + >::value == 1 + ); + { auto tuple = std::make_tuple (1,2,3,4); std::vector expected {{ 1, 2, 3, 4 }}; std::vector actual; - util::tuple::for_each ([&actual] (auto i) { actual.push_back (i); }, tuple); + util::tuple::value::each ([&actual] (auto i) { actual.push_back (i); }, tuple); tap.expect_eq (actual, expected, "value iteration"); } @@ -38,7 +46,7 @@ main () }; std::vector actual; - util::tuple::for_type ([&actual] (auto i) { + util::tuple::type::each ([&actual] (auto i) { actual.push_back (typeid (typename decltype(i)::type)); }); @@ -51,7 +59,7 @@ main () { using src_t = std::tuple; - using dst_t = typename util::tuple::map::type; + using dst_t = typename util::tuple::type::map::type; tap.expect (std::is_same>::value, "tuple type mapping"); } diff --git a/tuple.cpp b/tuple.cpp deleted file mode 100644 index d470aaa9..00000000 --- a/tuple.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2015 Danny Robson - */ - -#include "tuple.hpp" - -// Make sure _someone_ includes the header for syntax checking diff --git a/tuple.hpp b/tuple.hpp deleted file mode 100644 index 640b87e2..00000000 --- a/tuple.hpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2015 Danny Robson - */ - -#ifndef __UTIL_TUPLE_HPP -#define __UTIL_TUPLE_HPP - -#include "types.hpp" -#include "variadic.hpp" - -#include -#include -#include - - -namespace util::tuple { - /////////////////////////////////////////////////////////////////////////// - /// call a provided object with type_tag for each type in a tuple - template < - typename T, - typename F, - size_t S = 0 - > - typename std::enable_if< - S == std::tuple_size::value, - void - >::type - for_type (F) - { } - - - //------------------------------------------------------------------------- - template< - typename T, - typename F, - size_t S = 0 - > - typename std::enable_if< - S < std::tuple_size::value, - void - >::type - for_type (F f) - { - using E = typename std::tuple_element::type; - - f (type_tag {}); - for_type (f); - } - - - //------------------------------------------------------------------------- - template - auto for_type (F f, T t) - { return for_type (f); } - - - /////////////////////////////////////////////////////////////////////////// - /// call a provided object with each value in a tuple - template < - size_t S = 0, - typename F, - typename ...T - > - typename std::enable_if< - S == sizeof...(T), - void - >::type - for_each (F, const std::tuple&) - { } - - - //------------------------------------------------------------------------- - template< - size_t S = 0, - typename F, - typename ...T - > - typename std::enable_if< - S < sizeof...(T), - void - >::type - for_each (F f, const std::tuple &t) - { - f (std::get (t)); - for_each (f, t); - } - - /////////////////////////////////////////////////////////////////////////////// - /// Statically map the member types of a tuple via F<>::type - /// - /// T: tuple type - /// F: type mapping object, conversion uses F<>::type - /// I: tuple indexing helper - template < - typename T, - template < - typename - > class F, - typename I = std::make_index_sequence< - std::tuple_size::value - > - > - struct map; - - - //----------------------------------------------------------------------------- - template < - typename T, - template < - typename - > class F, - size_t ...I - > - struct map< - T, - F, - std::index_sequence - > { - typedef std::tuple< - typename F< - typename std::tuple_element::type - >::type... - > type; - }; - - - /////////////////////////////////////////////////////////////////////////// - namespace detail { - template - auto - convert (std::index_sequence, FuncT &&func, ArgT &&arg) - { - return std::tuple (std::invoke (func, std::get (arg))...); - } - }; - - template < - typename FuncT, - typename ArgT, - typename IndicesV = std::make_index_sequence< - std::tuple_size_v> - > - > - auto convert (FuncT &&func, ArgT &&arg) - { - return detail::convert (IndicesV{}, func, arg); - } - - - /////////////////////////////////////////////////////////////////////////// - /// do nothing with a set of parameters. - /// - /// useful for temporarily silencing unused argument warnings in parameter - /// packs, or for avoiding assignment of [[gnu::warn_unused_result]] to a - /// temporary value we'd just cast to void anyway (GCC#66425). - /// - /// it is guaranteed that this function will never be defined out in - /// debug/release/whatever builds. so it is safe to use to guarantee - /// parameter evaluation. - inline void - ignore (void) noexcept - { ; } - - //------------------------------------------------------------------------- - template - void - ignore (T, const Args&...) noexcept - { ; } - - - /////////////////////////////////////////////////////////////////////////// - /// query the index of the first occurrence of type `T' in the tuple type - /// `TupleT'. - /// - /// if the query type does not occur in the tuple type a compiler error - /// should be generated. - template - struct index; - - - //------------------------------------------------------------------------- - template - struct index> { - static constexpr std::size_t value = 0; - }; - - - //------------------------------------------------------------------------- - template - struct index> { - static constexpr std::size_t value = 1 + index>::value; - }; - - - /////////////////////////////////////////////////////////////////////////// - template - auto - get (HeadT &&head, TailT &&...tail) - { - if constexpr (IndexV == 0) - return std::forward (head); - else - return get (std::forward (tail)...); - } - - - /////////////////////////////////////////////////////////////////////////// - template - auto - nth (Args &&...args) - { - return std::get (std::tuple {std::forward (args)...}); - } -}; - - -#endif diff --git a/tuple/type.hpp b/tuple/type.hpp new file mode 100644 index 00000000..40453e26 --- /dev/null +++ b/tuple/type.hpp @@ -0,0 +1,162 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2015-2018 Danny Robson + */ + +#ifndef CRUFT_UTIL_TUPLE_TYPE_HPP +#define CRUFT_UTIL_TUPLE_TYPE_HPP + +#include "../types.hpp" + +#include "../types/traits.hpp" + +#include +#include + + +namespace util::tuple::type { + /////////////////////////////////////////////////////////////////////////// + /// call a provided FunctorT with type_tag for each type in the + /// tuple-like type TupleT. + template< + typename TupleT, + typename FunctorT, + size_t S = 0 + > + void + each (FunctorT &&func) + { + static_assert (S < std::tuple_size_v); + using value_type = typename std::tuple_element::type; + + func (util::type_tag {}); + + if constexpr (S + 1 < std::tuple_size_v) { + each (std::forward (func)); + } + } + + + /////////////////////////////////////////////////////////////////////////////// + /// Statically map the member types of a tuple via F<>::type + /// + /// TupleT: tuple type + /// FieldT: type mapping object, conversion uses FieldT<>::type + /// Indices: tuple indexing helper + template < + typename TupleT, + template < + typename + > class FieldT, + typename Indices = std::make_index_sequence< + std::tuple_size::value + > + > + struct map; + + + //----------------------------------------------------------------------------- + template < + typename TupleT, + template < + typename + > class FieldT, + size_t ...Indices + > + struct map< + TupleT, + FieldT, + std::index_sequence + > { + typedef std::tuple< + typename FieldT< + typename std::tuple_element::type + >::type... + > type; + }; + + + /////////////////////////////////////////////////////////////////////////// + /// query the index of the first occurrence of type `T' in the tuple-like + /// type `TupleT'. + /// + /// if the query type does not occur in the tuple type a compiler error + /// should be generated. + template< + typename TupleT, + typename ValueT, + typename = std::make_index_sequence< + std::tuple_size_v + > + > + struct index { }; + + + //------------------------------------------------------------------------- + // specialisation for tuples with matching first elements. the index is 0. + template< + typename ValueT, + typename ...TailT, + size_t ...Indices + > + struct index< + std::tuple, + ValueT, + std::index_sequence + > { + static constexpr std::size_t value = 0; + }; + + + //------------------------------------------------------------------------- + // specialisation for tuples with non-matching first elements. + // increment and recurse. + template< + typename ValueT, + typename HeadT, + typename ...TailT, + size_t ...Indices + > + struct index< + std::tuple, + ValueT, + std::index_sequence + > { + static constexpr std::size_t value = 1u + index,ValueT>::value; + }; + + + //------------------------------------------------------------------------- + // convert the tuple type (which is not a tuple or it would have matched + // the tuple specialisation, into the equivalent std::tuple and requery + // against that. + template < + typename TupleT, + typename ValueT, + size_t ...Indices + > struct index< + TupleT, + ValueT, + std::index_sequence + > { + static constexpr std::size_t value = index< + std::tuple...>, + ValueT, + std::index_sequence + >::value; + }; +}; + + +#endif diff --git a/tuple/value.hpp b/tuple/value.hpp new file mode 100644 index 00000000..1fe90f11 --- /dev/null +++ b/tuple/value.hpp @@ -0,0 +1,75 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2015-2018 Danny Robson + */ + +#ifndef CRUFT_UTIL_TUPLE_VALUE_HPP +#define CRUFT_UTIL_TUPLE_VALUE_HPP + +#include "../types.hpp" + +#include +#include +#include +#include + + +namespace util::tuple::value { + /////////////////////////////////////////////////////////////////////////// + /// Call a provided functor of type FunctionT with each value in a + /// provided tuple-like object TupleT + template< + typename FunctionT, + typename TupleT, + std::size_t S = 0 + > + void + each (FunctionT &&func, TupleT &&value) + { + using tuple_t = std::decay_t; + static_assert (S < std::tuple_size_v); + + func (std::get (value)); + + if constexpr (S + 1 < std::tuple_size_v) { + each (std::forward (func), std::forward (value)); + } + } + + + /////////////////////////////////////////////////////////////////////////// + namespace detail { + template + auto + map (std::index_sequence, FuncT &&func, ArgT &&arg) + { + return std::tuple (std::invoke (func, std::get (arg))...); + } + }; + + template < + typename FuncT, + typename ArgT, + typename IndicesV = std::make_index_sequence< + std::tuple_size_v> + > + > + auto map (FuncT &&func, ArgT &&arg) + { + return detail::map (IndicesV{}, func, arg); + } +}; + + +#endif diff --git a/types.hpp b/types.hpp index dcc5b512..c83add55 100644 --- a/types.hpp +++ b/types.hpp @@ -14,13 +14,14 @@ * Copyright 2011-2014 Danny Robson */ -#ifndef __UTIL_TYPES_HPP -#define __UTIL_TYPES_HPP +#ifndef CRUFT_UTIL_TYPES_HPP +#define CRUFT_UTIL_TYPES_HPP #include #include #include #include +#include /////////////////////////////////////////////////////////////////////////////// diff --git a/variadic.hpp b/variadic.hpp index ffacdc13..5c67b975 100644 --- a/variadic.hpp +++ b/variadic.hpp @@ -11,25 +11,49 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2017 Danny Robson + * Copyright 2017-2018 Danny Robson */ -#ifndef __UTIL_VARIADIC_HPP -#define __UTIL_VARIADIC_HPP +#ifndef CRUFT_UTIL_VARIADIC_HPP +#define CRUFT_UTIL_VARIADIC_HPP + +#include +#include +#include + namespace util::variadic { - /// return a reference to the first item in a parameter pack - template - T& - first (T &t, Tail&&...) - { return t; } + /////////////////////////////////////////////////////////////////////////// + /// do nothing with a set of parameters. + /// + /// useful for temporarily silencing unused argument warnings in parameter + /// packs, or for avoiding assignment of [[gnu::warn_unused_result]] to a + /// temporary value we'd just cast to void anyway (GCC#66425). + /// + /// it is guaranteed that this function will never be defined out in + /// debug/release/whatever builds. so it is safe to use to guarantee + /// parameter evaluation. + template + void + ignore (const Args&...) noexcept ((std::is_nothrow_destructible_v && ...)) + { ; } - /// return a reference to the first item in a const parameter pack - template - const T& - first (const T &t, const Tail&&...) - { return t; } + /////////////////////////////////////////////////////////////////////////// + /// Returns the argument at index `IndexV', as if we called: + /// std::get (std::make_tuple (...)) + template + auto + get (HeadT &&head, TailT &&...tail) noexcept ((std::is_nothrow_move_constructible_v && ...)) + { + static_assert (IndexV < sizeof... (TailT) + 1, "Index is out of bounds"); + + if constexpr (IndexV == 0) + return std::forward (head); + else + return get (std::forward (tail)...); + } } + #endif