Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F91960793
aka_tuple_tools.hh
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Nov 16, 04:00
Size
20 KB
Mime Type
text/x-c
Expires
Mon, Nov 18, 04:00 (2 d)
Engine
blob
Format
Raw Data
Handle
22354704
Attached To
rAKA akantu
aka_tuple_tools.hh
View Options
/**
* @file aka_tuple_tools.hh
*
* @author Nicolas Richart <nicolas.richart@epfl.ch>
*
* @date creation: Fri Aug 11 2017
* @date last modification: Mon Jan 29 2018
*
* @brief iterator interfaces
*
* @section LICENSE
*
* Copyright 2019 EPFL (Ecole Polytechnique Fédérale de Lausanne)
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* Akantu is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* Akantu is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Akantu. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* -------------------------------------------------------------------------- */
#include "aka_compatibilty_with_cpp_standard.hh"
#include "aka_str_hash.hh"
/* -------------------------------------------------------------------------- */
#include <tuple>
/* -------------------------------------------------------------------------- */
#ifndef AKANTU_AKA_TUPLE_TOOLS_HH
#define AKANTU_AKA_TUPLE_TOOLS_HH
#ifndef AKANTU_ITERATORS_NAMESPACE
#define AKANTU_ITERATORS_NAMESPACE akantu
#endif
namespace AKANTU_ITERATORS_NAMESPACE {
namespace tuple {
/* ---------------------------------------------------------------------- */
template <typename tag, typename type> struct named_tag {
using _tag = tag; ///< key
using _type = type; ///< value type
template <
typename T,
std::enable_if_t<not std::is_same<named_tag, T>::value> * = nullptr>
named_tag(T && value) // NOLINT
: _value(std::forward<T>(value)) {}
type _value;
};
namespace details {
/* ---------------------------------------------------------------------- */
#if (defined(__GNUC__) || defined(__GNUG__))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#endif
template <typename tag> struct named_tag_proxy {
using _tag = tag;
template <typename T> decltype(auto) operator=(T && value) {
return named_tag<_tag, T>{std::forward<T>(value)};
}
};
#if (defined(__GNUC__) || defined(__GNUG__))
#pragma GCC diagnostic pop
#endif
} // namespace details
/* ---------------------------------------------------------------------- */
template <typename T> struct is_named_tag : public std::false_type {};
template <typename tag>
struct is_named_tag<details::named_tag_proxy<tag>> : public std::true_type {};
template <typename tag, typename type>
struct is_named_tag<named_tag<tag, type>> : public std::true_type {};
/* ---------------------------------------------------------------------- */
template <class... Params>
struct named_tuple : public std::tuple<typename Params::_type...> {
using Names_t = std::tuple<typename Params::_tag...>;
using parent = std::tuple<typename Params::_type...>;
named_tuple(Params &&... params)
: parent(std::forward<typename Params::_type>(params._value)...) {}
named_tuple(typename Params::_type &&... args)
: parent(std::forward<typename Params::_type>(args)...) {}
private:
template <typename tag, std::size_t Idx,
std::enable_if_t<Idx == sizeof...(Params)> * = nullptr>
static constexpr std::size_t get_element_index_() noexcept {
return std::size_t(-1);
}
template <typename tag, std::size_t Idx,
std::enable_if_t<(Idx < sizeof...(Params))> * = nullptr>
static constexpr std::size_t get_element_index_() noexcept {
using _tag = std::tuple_element_t<Idx, Names_t>;
return (std::is_same<_tag, tag>::value)
? Idx
: get_element_index_<tag, Idx + 1>();
}
public:
template <typename NT>
static constexpr std::size_t get_element_index() noexcept {
return get_element_index_<typename NT::_tag, 0>();
}
template <typename NT>
static constexpr std::size_t get_element_index(NT && /*unused*/) noexcept {
return get_element_index_<typename NT::_tag, 0>();
}
template <typename NT,
std::enable_if_t<is_named_tag<NT>::value> * = nullptr>
constexpr decltype(auto) get(NT && /*unused*/) noexcept {
const auto index = get_element_index<NT>();
static_assert((index != std::size_t(-1)), "wrong named_tag");
return (std::get<index>(*this));
}
template <typename NT,
std::enable_if_t<is_named_tag<NT>::value> * = nullptr>
constexpr decltype(auto) get(NT && /*unused*/) const noexcept {
const auto index = get_element_index<NT>();
static_assert((index != std::size_t(-1)), "wrong named_tag");
return (std::get<index>(*this));
}
template <typename NT,
std::enable_if_t<is_named_tag<NT>::value> * = nullptr>
constexpr auto has(NT && /*unused*/) const noexcept -> bool {
const auto index = get_element_index<NT>();
return (index != std::size_t(-1));
}
};
/* ---------------------------------------------------------------------- */
template <typename T> struct is_named_tuple : public std::false_type {};
template <typename... Params>
struct is_named_tuple<named_tuple<Params...>> : public std::true_type {};
/* ---------------------------------------------------------------------- */
template <typename... Params>
constexpr decltype(auto) make_named_tuple(Params &&... params) noexcept {
return named_tuple<Params...>(std::forward<Params>(params)...);
}
template <typename tag> constexpr decltype(auto) make_named_tag() noexcept {
return details::named_tag_proxy<tag>{};
}
template <size_t HashCode> constexpr decltype(auto) get() {
return make_named_tag<std::integral_constant<size_t, HashCode>>();
}
template <size_t HashCode, class Tuple>
constexpr decltype(auto) get(Tuple && tuple) {
return tuple.get(get<HashCode>());
}
template <size_t HashCode, class Tuple> constexpr bool has(Tuple && tuple) {
return tuple.has(get<HashCode>());
}
template <typename Param, typename Tuple,
std::enable_if_t<is_named_tag<Param>::value> * = nullptr>
constexpr decltype(auto) get(Tuple && tuple) noexcept {
return tuple.template get<typename Param::hash>();
}
template <size_t I, class Tuple> struct tuple_name_tag {
using type = std::tuple_element_t<I, typename Tuple::Names_t>;
};
template <size_t I, class Tuple>
using tuple_name_tag_t = typename tuple_name_tag<I, Tuple>::type;
template <size_t I, class Tuple> struct tuple_element {
using type = std::tuple_element_t<I, typename Tuple::parent>;
};
template <size_t I, class Tuple>
using tuple_element_t = typename tuple_element<I, Tuple>::type;
#if defined(__INTEL_COMPILER)
// intel warnings here
#elif defined(__clang__)
// clang warnings here
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template"
#elif (defined(__GNUC__) || defined(__GNUG__))
// gcc warnings here
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#endif
/// this is a GNU exstension
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3599.html
template <class CharT, CharT... chars>
constexpr decltype(auto) operator"" _n() {
return make_named_tag<std::integral_constant<
std::size_t, string_literal<CharT, chars...>::hash>>();
}
#if defined(__INTEL_COMPILER)
#elif defined(__clang__)
#pragma clang diagnostic pop
#elif (defined(__GNUC__) || defined(__GNUG__))
#pragma GCC diagnostic pop
#endif
/* ------------------------------------------------------------------------
*/
namespace details {
template <std::size_t N> struct Foreach {
template <class Tuple>
static inline bool not_equal(Tuple && a, Tuple && b) {
if (std::get<N - 1>(std::forward<Tuple>(a)) ==
std::get<N - 1>(std::forward<Tuple>(b))) {
return false;
}
return Foreach<N - 1>::not_equal(std::forward<Tuple>(a),
std::forward<Tuple>(b));
}
};
/* ----------------------------------------------------------------------
*/
template <> struct Foreach<0> {
template <class Tuple>
static inline bool not_equal(Tuple && a, Tuple && b) {
return std::get<0>(std::forward<Tuple>(a)) !=
std::get<0>(std::forward<Tuple>(b));
}
};
template <typename... Ts>
decltype(auto) make_tuple_no_decay(Ts &&... args) {
return std::tuple<Ts...>(std::forward<Ts>(args)...);
}
template <typename... Names, typename... Ts>
decltype(auto) make_named_tuple_no_decay(std::tuple<Names...> /*unused*/,
Ts &&... args) {
return named_tuple<named_tag<Names, Ts>...>(std::forward<Ts>(args)...);
}
template <class F, class Tuple, std::size_t... Is>
void foreach_impl(F && func, Tuple && tuple,
std::index_sequence<Is...> && /*unused*/) {
(void)std::initializer_list<int>{
(std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(tuple))),
0)...};
}
template <class F, class Tuple, std::size_t... Is>
decltype(auto) transform_impl(F && func, Tuple && tuple,
std::index_sequence<Is...> && /*unused*/) {
return make_tuple_no_decay(
std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(tuple)))...);
}
template <class F, class Tuple, std::size_t... Is>
decltype(auto)
transform_named_impl(F && func, Tuple && tuple,
std::index_sequence<Is...> && /*unused*/) {
return make_named_tuple_no_decay(
typename std::decay_t<Tuple>::Names_t{},
std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(tuple)))...);
}
template <class Tuple, std::size_t... Is>
decltype(auto) flatten(Tuple && tuples,
std::index_sequence<Is...> /*unused*/) {
return std::tuple_cat(std::get<Is>(tuples)...);
}
template <class Tuple, class... Vals, std::size_t... Is>
decltype(auto) append_impl(std::index_sequence<Is...> && /*unused*/,
Tuple && tuple, Vals &&... other_vals) {
return make_tuple_no_decay(std::get<Is>(std::forward<Tuple>(tuple))...,
std::forward<Vals>(other_vals)...);
}
template <class Tuple, class... Vals, std::size_t... Is>
decltype(auto) append_named_impl(std::index_sequence<Is...> && /*unused*/,
Tuple && tuple, Vals &&... other_vals) {
return make_named_tuple_no_decay(
std::tuple<tuple_name_tag<Is, Tuple>..., Vals...>{},
std::get<Is>(std::forward<Tuple>(tuple))...,
std::forward<Vals>(other_vals)...);
}
template <std::size_t nth, class Tuple, std::size_t... Is_before,
std::size_t... Is_after>
decltype(auto) remove_impl(std::index_sequence<Is_before...> && /*unused*/,
std::index_sequence<Is_after...> && /*unused*/,
Tuple && tuple) {
return make_tuple_no_decay(
std::get<Is_before>(std::forward<Tuple>(tuple))...,
std::get<Is_after + nth + 1>(std::forward<Tuple>(tuple))...);
}
template <std::size_t nth, class Tuple, std::size_t... Is_before,
std::size_t... Is_after>
decltype(auto)
remove_named_impl(std::index_sequence<Is_before...> && /*unused*/,
std::index_sequence<Is_after...> && /*unused*/,
Tuple && tuple) {
return make_named_tuple_no_decay(
std::tuple<tuple::tuple_name_tag_t<Is_before, std::decay_t<Tuple>>...,
tuple::tuple_name_tag_t<Is_after + nth + 1,
std::decay_t<Tuple>>...>{},
std::get<Is_before>(std::forward<Tuple>(tuple))...,
std::get<Is_after + nth + 1>(std::forward<Tuple>(tuple))...);
}
template <std::size_t nth, class Tuple, class Value,
std::size_t... Is_before, std::size_t... Is_after>
decltype(auto) replace_impl(std::index_sequence<Is_before...> && /*unused*/,
std::index_sequence<Is_after...> && /*unused*/,
Tuple && tuple, Value && value) {
return make_tuple_no_decay(
std::get<Is_before>(std::forward<Tuple>(tuple))...,
std::forward<Value>(value),
std::get<Is_after + nth + 1>(std::forward<Tuple>(tuple))...);
}
template <std::size_t nth, size_t HashCode, class Tuple, class Value,
std::size_t... Is_before, std::size_t... Is_after>
decltype(auto)
replace_named_impl(std::index_sequence<Is_before...> && /*unused*/,
std::index_sequence<Is_after...> && /*unused*/,
Tuple && tuple, Value && value) {
using tuple_type = std::decay_t<Tuple>;
return make_named_tuple_no_decay(
std::tuple<
tuple::tuple_name_tag_t<Is_before, tuple_type>...,
decltype(get<HashCode>()),
tuple::tuple_name_tag_t<Is_after + nth + 1, tuple_type>...>{},
std::get<Is_before>(std::forward<Tuple>(tuple))...,
std::forward<Value>(value),
std::get<Is_after + nth + 1>(std::forward<Tuple>(tuple))...);
}
} // namespace details
/* ------------------------------------------------------------------------ */
template <class Tuple,
std::enable_if_t<not is_named_tuple<std::decay_t<Tuple>>::value> * =
nullptr>
bool are_not_equal(Tuple && a, Tuple && b) {
return details::Foreach<std::tuple_size<std::decay_t<Tuple>>::value>::
not_equal(std::forward<Tuple>(a), std::forward<Tuple>(b));
}
template <
class Tuple,
std::enable_if_t<is_named_tuple<std::decay_t<Tuple>>::value> * = nullptr>
bool are_not_equal(Tuple && a, Tuple && b) {
return details::Foreach<
std::tuple_size<typename std::decay_t<Tuple>::parent>::value>::
not_equal(std::forward<Tuple>(a), std::forward<Tuple>(b));
}
/* ------------------------------------------------------------------------ */
template <class F, class Tuple,
std::enable_if_t<not is_named_tuple<std::decay_t<Tuple>>::value> * =
nullptr>
void foreach (F && func, Tuple && tuple) {
return details::foreach_impl(
std::forward<F>(func), std::forward<Tuple>(tuple),
std::make_index_sequence<
std::tuple_size<std::decay_t<Tuple>>::value>{});
}
template <
class F, class Tuple,
std::enable_if_t<is_named_tuple<std::decay_t<Tuple>>::value> * = nullptr>
void foreach (F && func, Tuple && tuple) {
return details::foreach_impl(
std::forward<F>(func), std::forward<Tuple>(tuple),
std::make_index_sequence<
std::tuple_size<typename std::decay_t<Tuple>::parent>::value>{});
}
/* ------------------------------------------------------------------------ */
template <class F, class Tuple,
std::enable_if_t<not is_named_tuple<std::decay_t<Tuple>>::value> * =
nullptr>
decltype(auto) transform(F && func, Tuple && tuple) {
return details::transform_impl(
std::forward<F>(func), std::forward<Tuple>(tuple),
std::make_index_sequence<
std::tuple_size<std::decay_t<Tuple>>::value>{});
}
template <
class F, class Tuple,
std::enable_if_t<is_named_tuple<std::decay_t<Tuple>>::value> * = nullptr>
decltype(auto) transform(F && func, Tuple && tuple) {
return details::transform_named_impl(
std::forward<F>(func), std::forward<Tuple>(tuple),
std::make_index_sequence<
std::tuple_size<typename std::decay_t<Tuple>::parent>::value>{});
}
/* ------------------------------------------------------------------------ */
template <class Tuple> decltype(auto) flatten(Tuple && tuples) {
return details::flatten(std::forward<Tuple>(tuples),
std::make_index_sequence<
std::tuple_size<std::decay_t<Tuple>>::value>());
}
/* ------------------------------------------------------------------------ */
template <typename... Ts> struct cat {
using type = decltype(std::tuple_cat(std::declval<Ts>()...));
};
template <typename... T> using cat_t = typename cat<T...>::type;
/* ------------------------------------------------------------------------ */
template <template <typename> class Pred, typename... Ts> struct filter {};
template <template <typename> class Pred, typename T>
struct filter<Pred, std::tuple<T>> {
using type =
std::conditional_t<Pred<T>::value, std::tuple<T>, std::tuple<>>;
};
template <template <typename> class Pred, typename T, typename... Ts>
struct filter<Pred, std::tuple<T, Ts...>> {
using type = cat_t<typename filter<Pred, std::tuple<T>>::type,
typename filter<Pred, std::tuple<Ts...>>::type>;
};
template <template <typename> class Pred, typename... Ts>
using filter_t = typename filter<Pred, Ts...>::type;
/* ------------------------------------------------------------------------ */
template <class Tuple, class... Vals,
std::enable_if_t<not is_named_tuple<std::decay_t<Tuple>>::value> * =
nullptr>
decltype(auto) append(Tuple && tuple, Vals &&... vals) {
return details::append_impl(
std::make_index_sequence<std::tuple_size<Tuple>::value>{},
std::forward<decltype(tuple)>(tuple), std::forward<Vals>(vals)...);
}
template <
class Tuple, class... Vals,
std::enable_if_t<is_named_tuple<std::decay_t<Tuple>>::value> * = nullptr>
decltype(auto) append(Tuple && tuple, Vals &&... vals) {
return details::append_named_impl(
std::make_index_sequence<
std::tuple_size<typename std::decay_t<Tuple>::parent>::value>{},
std::forward<decltype(tuple)>(tuple), std::forward<Vals>(vals)...);
}
/* ------------------------------------------------------------------------ */
template <size_t nth, class Tuple,
std::enable_if_t<not is_named_tuple<std::decay_t<Tuple>>::value> * =
nullptr>
decltype(auto) remove(Tuple && tuple) {
return details::remove_impl<nth>(
std::make_index_sequence<nth>{},
std::make_index_sequence<std::tuple_size<Tuple>::value - nth - 1>{},
std::forward<Tuple>(tuple));
}
template <
size_t HashCode, class Tuple,
std::enable_if_t<is_named_tuple<std::decay_t<Tuple>>::value> * = nullptr>
decltype(auto) remove(Tuple && tuple) {
constexpr auto nth =
tuple.template get_element_index(tuple::get<HashCode>());
return details::remove_named_impl<nth>(
std::make_index_sequence<nth>{},
std::make_index_sequence<
std::tuple_size<typename std::decay_t<Tuple>::parent>::value - nth -
1>{},
std::forward<Tuple>(tuple));
}
template <size_t nth, class Tuple, class Value,
std::enable_if_t<not is_named_tuple<std::decay_t<Tuple>>::value> * =
nullptr>
decltype(auto) replace(Tuple && tuple, Value && value) {
return details::replace_impl<nth>(
std::make_index_sequence<nth>{},
std::make_index_sequence<std::tuple_size<Tuple>::value - nth - 1>{},
std::forward<Tuple>(tuple), std::forward<Value>(value));
}
template <
size_t HashCode, class Tuple, class Value,
std::enable_if_t<is_named_tuple<std::decay_t<Tuple>>::value> * = nullptr>
decltype(auto) replace(Tuple && tuple, Value && value) {
constexpr auto nth =
tuple.template get_element_index(tuple::get<HashCode>());
return details::replace_named_impl<nth, HashCode>(
std::make_index_sequence<nth>{},
std::make_index_sequence<
std::tuple_size<typename std::decay_t<Tuple>::parent>::value - nth -
1>{},
std::forward<Tuple>(tuple), std::forward<Value>(value));
}
} // namespace tuple
} // namespace AKANTU_ITERATORS_NAMESPACE
namespace aka {
template <typename tag, typename type_>
struct size_type<AKANTU_ITERATORS_NAMESPACE::tuple::named_tag<tag, type_>> {
using type = typename std::decay_t<type_>::size_type;
};
} // namespace aka
/* -------------------------------------------------------------------------- */
#include <iterator>
/* -------------------------------------------------------------------------- */
namespace std {
template <typename tag, typename type>
struct iterator_traits<
::AKANTU_ITERATORS_NAMESPACE::tuple::named_tag<tag, type>> {
using iterator_category = typename type::iterator_category;
using value_type = typename type::value_type;
using difference_type = typename type::difference_type;
using pointer = typename type::pointer;
using reference = typename type::reference;
};
} // namespace std
#endif /* AKANTU_AKA_TUPLE_TOOLS_HH */
Event Timeline
Log In to Comment