tuple/variadic: split into type/value/pack operations

This commit is contained in:
Danny Robson 2018-03-15 23:48:21 +11:00
parent f3f3666877
commit 12d401b98b
11 changed files with 294 additions and 275 deletions

View File

@ -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

View File

@ -22,10 +22,9 @@
// we specifically rely on vector<bool> 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&)
> (

View File

@ -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...
);
}

View File

@ -19,8 +19,6 @@
#include "../pool.hpp"
#include "../tuple.hpp"
#include "ticketlock.hpp"
#include "semaphore.hpp"
#include "flag.hpp"

View File

@ -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<float,int,void>,
int
>::value == 1
);
{
auto tuple = std::make_tuple (1,2,3,4);
std::vector<int> expected {{ 1, 2, 3, 4 }};
std::vector<int> 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<std::type_index> actual;
util::tuple::for_type<decltype(tuple)> ([&actual] (auto i) {
util::tuple::type::each<decltype(tuple)> ([&actual] (auto i) {
actual.push_back (typeid (typename decltype(i)::type));
});
@ -51,7 +59,7 @@ main ()
{
using src_t = std::tuple<std::string>;
using dst_t = typename util::tuple::map<src_t, int_mapper>::type;
using dst_t = typename util::tuple::type::map<src_t, int_mapper>::type;
tap.expect (std::is_same<dst_t, std::tuple<int>>::value, "tuple type mapping");
}

View File

@ -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 <danny@nerdcruft.net>
*/
#include "tuple.hpp"
// Make sure _someone_ includes the header for syntax checking

229
tuple.hpp
View File

@ -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 <danny@nerdcruft.net>
*/
#ifndef __UTIL_TUPLE_HPP
#define __UTIL_TUPLE_HPP
#include "types.hpp"
#include "variadic.hpp"
#include <tuple>
#include <type_traits>
#include <functional>
namespace util::tuple {
///////////////////////////////////////////////////////////////////////////
/// call a provided object with type_tag<T> for each type in a tuple
template <
typename T,
typename F,
size_t S = 0
>
typename std::enable_if<
S == std::tuple_size<T>::value,
void
>::type
for_type (F)
{ }
//-------------------------------------------------------------------------
template<
typename T,
typename F,
size_t S = 0
>
typename std::enable_if<
S < std::tuple_size<T>::value,
void
>::type
for_type (F f)
{
using E = typename std::tuple_element<S,T>::type;
f (type_tag<E> {});
for_type<T,F,S+1> (f);
}
//-------------------------------------------------------------------------
template <typename T, typename F>
auto for_type (F f, T t)
{ return for_type<decltype(t)> (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<T...>&)
{ }
//-------------------------------------------------------------------------
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...> &t)
{
f (std::get<S> (t));
for_each<S+1,F,T...> (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<T>::value
>
>
struct map;
//-----------------------------------------------------------------------------
template <
typename T,
template <
typename
> class F,
size_t ...I
>
struct map<
T,
F,
std::index_sequence<I...>
> {
typedef std::tuple<
typename F<
typename std::tuple_element<I, T>::type
>::type...
> type;
};
///////////////////////////////////////////////////////////////////////////
namespace detail {
template <typename FuncT, typename ArgT, std::size_t ...Indices>
auto
convert (std::index_sequence<Indices...>, FuncT &&func, ArgT &&arg)
{
return std::tuple (std::invoke (func, std::get<Indices> (arg))...);
}
};
template <
typename FuncT,
typename ArgT,
typename IndicesV = std::make_index_sequence<
std::tuple_size_v<std::decay_t<ArgT>>
>
>
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 <typename T, typename ...Args>
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 <class T, class TupleT>
struct index;
//-------------------------------------------------------------------------
template <class T, class ...Types>
struct index<T, std::tuple<T, Types...>> {
static constexpr std::size_t value = 0;
};
//-------------------------------------------------------------------------
template <class T, class U, class ...Types>
struct index<T,std::tuple<U, Types...>> {
static constexpr std::size_t value = 1 + index<T, std::tuple<Types...>>::value;
};
///////////////////////////////////////////////////////////////////////////
template <size_t IndexV, typename HeadT, typename ...TailT>
auto
get (HeadT &&head, TailT &&...tail)
{
if constexpr (IndexV == 0)
return std::forward<HeadT> (head);
else
return get<IndexV-1> (std::forward<TailT> (tail)...);
}
///////////////////////////////////////////////////////////////////////////
template <std::size_t Idx, typename ...Args>
auto
nth (Args &&...args)
{
return std::get<Idx> (std::tuple {std::forward<Args> (args)...});
}
};
#endif

162
tuple/type.hpp Normal file
View File

@ -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 <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_TUPLE_TYPE_HPP
#define CRUFT_UTIL_TUPLE_TYPE_HPP
#include "../types.hpp"
#include "../types/traits.hpp"
#include <cstddef>
#include <tuple>
namespace util::tuple::type {
///////////////////////////////////////////////////////////////////////////
/// call a provided FunctorT with type_tag<T> 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<TupleT>);
using value_type = typename std::tuple_element<S,TupleT>::type;
func (util::type_tag<value_type> {});
if constexpr (S + 1 < std::tuple_size_v<TupleT>) {
each<TupleT,FunctorT,S+1> (std::forward<FunctorT> (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<TupleT>::value
>
>
struct map;
//-----------------------------------------------------------------------------
template <
typename TupleT,
template <
typename
> class FieldT,
size_t ...Indices
>
struct map<
TupleT,
FieldT,
std::index_sequence<Indices...>
> {
typedef std::tuple<
typename FieldT<
typename std::tuple_element<Indices, TupleT>::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<TupleT>
>
>
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, TailT...>,
ValueT,
std::index_sequence<Indices...>
> {
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<HeadT, TailT...>,
ValueT,
std::index_sequence<Indices...>
> {
static constexpr std::size_t value = 1u + index<std::tuple<TailT...>,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<Indices...>
> {
static constexpr std::size_t value = index<
std::tuple<std::tuple_element_t<Indices,TupleT>...>,
ValueT,
std::index_sequence<Indices...>
>::value;
};
};
#endif

75
tuple/value.hpp Normal file
View File

@ -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 <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_TUPLE_VALUE_HPP
#define CRUFT_UTIL_TUPLE_VALUE_HPP
#include "../types.hpp"
#include <cstddef>
#include <functional>
#include <tuple>
#include <utility>
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<TupleT>;
static_assert (S < std::tuple_size_v<tuple_t>);
func (std::get<S> (value));
if constexpr (S + 1 < std::tuple_size_v<tuple_t>) {
each<FunctionT,TupleT,S+1> (std::forward<FunctionT> (func), std::forward<TupleT> (value));
}
}
///////////////////////////////////////////////////////////////////////////
namespace detail {
template <typename FuncT, typename ArgT, std::size_t ...Indices>
auto
map (std::index_sequence<Indices...>, FuncT &&func, ArgT &&arg)
{
return std::tuple (std::invoke (func, std::get<Indices> (arg))...);
}
};
template <
typename FuncT,
typename ArgT,
typename IndicesV = std::make_index_sequence<
std::tuple_size_v<std::decay_t<ArgT>>
>
>
auto map (FuncT &&func, ArgT &&arg)
{
return detail::map (IndicesV{}, func, arg);
}
};
#endif

View File

@ -14,13 +14,14 @@
* Copyright 2011-2014 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_TYPES_HPP
#define __UTIL_TYPES_HPP
#ifndef CRUFT_UTIL_TYPES_HPP
#define CRUFT_UTIL_TYPES_HPP
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <stdexcept>
#include <tuple>
///////////////////////////////////////////////////////////////////////////////

View File

@ -11,25 +11,49 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
* Copyright 2017-2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_VARIADIC_HPP
#define __UTIL_VARIADIC_HPP
#ifndef CRUFT_UTIL_VARIADIC_HPP
#define CRUFT_UTIL_VARIADIC_HPP
#include <cstddef>
#include <type_traits>
#include <utility>
namespace util::variadic {
/// return a reference to the first item in a parameter pack
template <typename T, typename ...Tail>
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 <typename ...Args>
void
ignore (const Args&...) noexcept ((std::is_nothrow_destructible_v<Args> && ...))
{ ; }
/// return a reference to the first item in a const parameter pack
template <typename T, typename ...Tail>
const T&
first (const T &t, const Tail&&...)
{ return t; }
///////////////////////////////////////////////////////////////////////////
/// Returns the argument at index `IndexV', as if we called:
/// std::get<N> (std::make_tuple (...))
template <std::size_t IndexV, typename HeadT, typename ...TailT>
auto
get (HeadT &&head, TailT &&...tail) noexcept ((std::is_nothrow_move_constructible_v<TailT> && ...))
{
static_assert (IndexV < sizeof... (TailT) + 1, "Index is out of bounds");
if constexpr (IndexV == 0)
return std::forward<HeadT> (head);
else
return get<IndexV-1> (std::forward<TailT> (tail)...);
}
}
#endif