// MIT License // Copyright (c) 2020 Jonathan R. Madsen // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #pragma once #include #include #include #include namespace PTL { template struct SmallerThanT { static constexpr bool value = sizeof(Tp) < sizeof(Up); }; //======================================================================================// // CTValue == compile-time value // // useful to work with sequences of compile-time values, such as the bounds of a // multidimensional array or indices into another typelist. template struct CTValue { static constexpr Tp value = Value; }; //======================================================================================// template ::value && !std::is_final::value> class TupleElt; //--------------------------------------------------------------------------------------// // specialization that does not satisfy is_class<> and not is_final<> // template class TupleElt { Tp value; public: TupleElt() = default; template TupleElt(Up&& other) : value(std::forward(other)) {} Tp& get() { return value; } Tp const& get() const { return value; } }; //--------------------------------------------------------------------------------------// // specialization that does satisfy is_class<> and not is_final<> // template class TupleElt : private Tp { public: TupleElt() = default; template explicit TupleElt(Up&& other) : Tp(std::forward(other)) {} Tp& get() { return *this; } const Tp& get() const { return *this; } }; //======================================================================================// template T& get_height(TupleElt& te) { return te.get(); } //======================================================================================// template class Tuple; //--------------------------------------------------------------------------------------// // recursive case: template class Tuple : private TupleElt , private Tuple { template friend auto get(Tuple& t) -> decltype(get_height(t)); public: Head& head() { return static_cast(this)->get(); } const Head& head() const { return static_cast(this)->get(); } Tuple& tail() { return *this; } const Tuple& tail() const { return *this; } private: using HeadElt = TupleElt; }; //--------------------------------------------------------------------------------------// // basis case: template <> class Tuple<> { // no storage required }; //--------------------------------------------------------------------------------------// template auto get(Tuple& t) -> decltype(get_height(t)) { return get_height(t); } template using TypeList = Tuple; //======================================================================================// template class IsEmpty { public: static constexpr bool value = false; }; template <> class IsEmpty> { public: static constexpr bool value = true; }; template class PushBackT; template class PushBackT, NewElement> { public: using Type = Tuple; }; template using PushBack = typename PushBackT::Type; template class PopFrontT; template class PopFrontT> { public: using Type = std::tuple; }; template using PopFront = typename PopFrontT::Type; template class PushFrontT; template class PushFrontT, Element> { public: using Type = std::tuple; }; template using PushFront = typename PushFrontT::Type; template PushFront, V> pushFront(std::tuple const& tuple, V const& value) { return PushFront, V>(value, tuple); } template struct Valuelist {}; template struct Front; template struct Front { using Type = FrontT; }; template struct Back; template struct Back { // ERROR: pack expansion not at the end of using Type = BackT; // template argument list }; //======================================================================================// template class MetaFun, bool Empty = IsEmpty::value> class TransformT; // recursive case: template class MetaFun> class TransformT : public PushFrontT, MetaFun>::Type, typename MetaFun>::Type> {}; // basis case: template class MetaFun> class TransformT { public: using Type = List; }; template class MetaFun> using Transform = typename TransformT::Type; template class MetaFun> class TransformT, MetaFun, false> { public: using Type = Tuple::Type...>; }; template struct ForwardTupleAsArgs { template static inline auto forward(Func&& func, Head&& head, Tail&&... tail) -> decltype(ForwardTupleAsArgs::forward( std::forward(func), std::forward(head), std::get(std::forward(head)), std::forward(tail)...)) { return ForwardTupleAsArgs::forward( std::forward(func), std::forward(head), std::get(std::forward(head)), std::forward(tail)...); } }; //======================================================================================// template <> struct ForwardTupleAsArgs<0> { template static inline auto forward(Func&& func, Head&&, Tail&&... tail) -> decltype(std::forward(func)(std::forward(tail)...)) { return std::forward(func)(std::forward(tail)...); } }; //======================================================================================// template struct ForEachTupleArg { template static inline auto apply(Func&& func, Head&& head) { std::forward(func)(std::forward(head)); } template static inline void apply(Func&& func, Head&& head, Tail&&... tail) { std::forward(func)(std::forward(head)); ForEachTupleArg::apply(std::forward(func), std::forward(tail)...); } }; //======================================================================================// template void for_each_tuple_arg(Func&& func, Tuple&& _tuple) { ForEachTupleArg::value>::apply( std::forward(func), std::forward(_tuple)); } //======================================================================================// template inline auto InvokeSequence_impl(const Func& func, const Tuple& data) { func(std::get(data)); } //======================================================================================// template inline auto InvokeSequence_impl(const Func& func, const Tuple& data) { func(std::get(data)); InvokeSequence_impl(func, data); } //======================================================================================// template ::value, typename Indices = std::make_index_sequence> inline auto InvokeSequence(const Func& func, const Tuple& data) { return InvokeSequence_impl(func, data); } //======================================================================================// // Convert array into a tuple template inline auto ContainerToTuple_impl(const Container& tasks, std::index_sequence) { return std::make_tuple(tasks[N]...); } //======================================================================================// template > inline auto ContainerToTuple(const Container& tasks) { return ContainerToTuple_impl(tasks, Indices{}); } //======================================================================================// template struct tuple_subset { static std::tuple<> get(const std::tuple<>&) { return std::tuple<>{}; } template static std::tuple get(const std::tuple& t) { return std::tuple{ std::get(t)... }; } }; template inline void tuple_transform(const std::function& pred, const std::tuple& data) { pred(std::get<0>(data)); } template inline void tuple_transform(const std::function& pred, const std::tuple& data) { pred(std::get<0>(data)); auto subset = tuple_subset::template get(data); tuple_transform(pred, std::forward(subset)); } template struct transform_tuple { using Function = std::function; template static void apply(const Function& func, const TupleType& t) { func(std::get<0>(t)); PopFront nt = std::tuple{ std::get(t)... }; transform_tuple::apply(func, nt); } }; template struct transform_tuple { using Function = std::function; template static void apply(const Function& func, const TupleType& t) { func(std::get<0>(t)); } }; //======================================================================================// template auto applyImpl(Func func, std::tuple const& t, Valuelist) -> decltype(func(std::get(t)...)) { return func(std::get(t)...); } template auto apply(Func func, std::tuple const& t) -> decltype(applyImpl(func, t, std::make_index_sequence())) { return applyImpl(func, t, std::make_index_sequence()); } } // namespace PTL