You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@quickstep.apache.org by ji...@apache.org on 2017/10/05 22:17:27 UTC
[22/40] incubator-quickstep git commit: More updates, refactor names
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/701751c8/types/operations/utility/OperationSynthesizeUtil.hpp
----------------------------------------------------------------------
diff --git a/types/operations/utility/OperationSynthesizeUtil.hpp b/types/operations/utility/OperationSynthesizeUtil.hpp
new file mode 100644
index 0000000..2b910b3
--- /dev/null
+++ b/types/operations/utility/OperationSynthesizeUtil.hpp
@@ -0,0 +1,335 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ **/
+
+#ifndef QUICKSTEP_TYPES_OPERATIONS_OPERATION_SYNTHESIZE_UTIL_HPP_
+#define QUICKSTEP_TYPES_OPERATIONS_OPERATION_SYNTHESIZE_UTIL_HPP_
+
+#include <cstddef>
+#include <list>
+#include <string>
+#include <type_traits>
+
+#include "catalog/CatalogTypedefs.hpp"
+#include "types/Type.hpp"
+#include "types/TypedValue.hpp"
+#include "types/containers/ColumnVector.hpp"
+
+namespace quickstep {
+
+/** \addtogroup Types
+ * @{
+ */
+
+template <typename FunctorT, typename ...SpecArgs>
+struct FunctorSpecializer {
+ template <bool specialize = (sizeof...(SpecArgs) != 0),
+ typename EnableT = void>
+ struct Implementation;
+
+ typedef Implementation<> type;
+};
+
+template <typename FunctorT, typename ...SpecArgs>
+template <bool specialize>
+struct FunctorSpecializer<FunctorT, SpecArgs...>
+ ::Implementation<specialize, std::enable_if_t<specialize>> {
+ template <typename ...FuncArgs>
+ inline static auto Invoke(const FunctorT &functor, FuncArgs &&...args) {
+ return functor.template apply<SpecArgs...>(std::forward<FuncArgs>(args)...);
+ }
+ typedef FunctorT FunctorType;
+};
+
+template <typename FunctorT, typename ...SpecArgs>
+template <bool specialize>
+struct FunctorSpecializer<FunctorT, SpecArgs...>
+ ::Implementation<specialize, std::enable_if_t<!specialize>> {
+ template <typename ...FuncArgs>
+ inline static auto Invoke(const FunctorT &functor, FuncArgs &&...args) {
+ return functor.apply(std::forward<FuncArgs>(args)...);
+ }
+ typedef FunctorT FunctorType;
+};
+
+template <typename ColumnVectorT>
+struct ColumnVectorValueAccessor {
+ explicit ColumnVectorValueAccessor(const ColumnVectorT &column_vector_in)
+ : column_vector(column_vector_in),
+ length(column_vector.size()) {}
+
+ inline void beginIteration() {
+ pos = static_cast<std::size_t>(-1);
+ }
+
+ inline bool next() {
+ return (++pos) < length;
+ }
+
+ inline std::size_t getNumTuples() const {
+ return length;
+ }
+
+ template <bool nullable>
+ inline const void* getUntypedValue(const attribute_id) const {
+ return column_vector.template getUntypedValue<nullable>(pos);
+ }
+
+ inline TypedValue getTypedValue(const attribute_id) const {
+ return column_vector.getTypedValue(pos);
+ }
+
+ const ColumnVectorT &column_vector;
+ const std::size_t length;
+ std::size_t pos;
+};
+
+template <typename FuncSpec, typename T, typename EnableT = void>
+struct OperationCodegen;
+
+template <typename FuncSpec, typename T>
+struct OperationCodegen<FuncSpec, T,
+ std::enable_if_t<T::kMemoryLayout == kCxxInlinePod>> {
+ using ColumnVectorType = NativeColumnVector;
+ using FunctorSpecializer = FuncSpec;
+
+ using NativeType = typename T::cpptype;
+ using NativeTypeConst = const typename T::cpptype;
+ using NativeTypeConstRef = const NativeType&;
+ using NativeTypeConstPtr = const NativeType*;
+
+ template <typename ArgumentGen>
+ inline static TypedValue ApplyUnaryTypedValue(
+ typename ArgumentGen::NativeTypeConstRef argument,
+ const Type &result_type,
+ const typename FuncSpec::FunctorType &functor) {
+ return TypedValue(FuncSpec::Invoke(functor, argument));
+ }
+
+ template <typename ArgumentGen>
+ inline static void ApplyUnaryColumnVector(
+ const typename ArgumentGen::NativeTypeConstRef argument,
+ const typename FuncSpec::FunctorType &functor,
+ ColumnVectorType *cv) {
+ *static_cast<NativeType *>(cv->getPtrForDirectWrite()) =
+ FuncSpec::Invoke(functor, argument);
+ }
+
+ template <typename LeftGen, typename RightGen>
+ inline static TypedValue ApplyBinaryTypedValue(
+ typename LeftGen::NativeTypeConstRef left,
+ typename RightGen::NativeTypeConstRef right,
+ const Type &result_type,
+ const typename FuncSpec::FunctorType &functor) {
+ return TypedValue(FuncSpec::Invoke(functor, left, right));
+ }
+
+ template <typename LeftGen, typename RightGen>
+ inline static void ApplyBinaryColumnVector(
+ const typename LeftGen::NativeTypeConstRef left,
+ const typename RightGen::NativeTypeConstRef right,
+ const typename FuncSpec::FunctorType &functor,
+ ColumnVectorType *cv) {
+ *static_cast<NativeType *>(cv->getPtrForDirectWrite()) =
+ FuncSpec::Invoke(functor, left, right);
+ }
+
+ template <bool nullable, typename AccessorT>
+ inline static NativeTypeConstPtr GetValuePtr(const AccessorT *accessor,
+ const attribute_id attr_id) {
+ return static_cast<NativeTypeConstPtr>(
+ accessor->template getUntypedValue<nullable>(attr_id));
+ }
+
+ inline static bool IsNull(const NativeType *value) {
+ return value == nullptr;
+ }
+
+ // Dereference: NativeTypeConstPtr& -> const NativeType&
+ inline static const NativeType& Dereference(const NativeType *value) {
+ return *value;
+ }
+
+ inline static const NativeType ToNativeValueConst(const TypedValue &value) {
+ return value.getLiteral<NativeType>();
+ }
+};
+
+template <typename FuncSpec, typename T>
+struct OperationCodegen<FuncSpec, T,
+ std::enable_if_t<T::kMemoryLayout == kParInlinePod>> {
+ using ColumnVectorType = NativeColumnVector;
+ using FunctorSpecializer = FuncSpec;
+
+ using NativeType = const void*;
+ using NativeTypeConst = const void*;
+ using NativeTypeConstRef = const void*;
+ using NativeTypeConstPtr = const void*;
+
+ template <typename ArgumentGen>
+ inline static TypedValue ApplyUnaryTypedValue(
+ typename ArgumentGen::NativeTypeConstRef argument,
+ const Type &result_type,
+ const typename FuncSpec::FunctorType &functor) {
+ void *result = std::malloc(result_type.maximumByteLength());
+ FuncSpec::Invoke(functor, argument, result);
+ return TypedValue::CreateWithOwnedData(T::kStaticTypeID,
+ result,
+ result_type.maximumByteLength());
+ }
+
+ template <typename ArgumentGen>
+ inline static void ApplyUnaryColumnVector(
+ const typename ArgumentGen::NativeTypeConstRef argument,
+ const typename FuncSpec::FunctorType &functor,
+ ColumnVectorType *cv) {
+ FuncSpec::Invoke(functor, argument, cv->getPtrForDirectWrite());
+ }
+
+ template <typename LeftGen, typename RightGen>
+ inline static TypedValue ApplyBinaryTypedValue(
+ typename LeftGen::NativeTypeConstRef left,
+ typename RightGen::NativeTypeConstRef right,
+ const Type &result_type,
+ const typename FuncSpec::FunctorType &functor) {
+ void *result = std::malloc(result_type.maximumByteLength());
+ FuncSpec::Invoke(functor, left, right, result);
+ return TypedValue::CreateWithOwnedData(T::kStaticTypeID,
+ result,
+ result_type.maximumByteLength());
+ }
+
+ template <typename LeftGen, typename RightGen>
+ inline static void ApplyBinaryColumnVector(
+ const typename LeftGen::NativeTypeConstRef left,
+ const typename RightGen::NativeTypeConstRef right,
+ const typename FuncSpec::FunctorType &functor,
+ ColumnVectorType *cv) {
+ FuncSpec::Invoke(functor, left, right, cv->getPtrForDirectWrite());
+ }
+
+ template <bool nullable, typename AccessorT>
+ inline static NativeTypeConstPtr GetValuePtr(const AccessorT *accessor,
+ const attribute_id attr_id) {
+ return accessor->template getUntypedValue<nullable>(attr_id);
+ }
+
+ inline static bool IsNull(const void *value) {
+ return value == nullptr;
+ }
+
+ // Dereference: NativeTypeConstPtr& -> const NativeType&
+ inline static const void* Dereference(const void *value) {
+ return value;
+ }
+
+ inline static const void* ToNativeValueConst(const TypedValue &value) {
+ return value.getDataPtr();
+ }
+};
+
+template <typename FuncSpec, typename T>
+struct OperationCodegen<FuncSpec, T,
+ std::enable_if_t<T::kMemoryLayout == kParOutOfLinePod>> {
+ using ColumnVectorType = IndirectColumnVector;
+ using FunctorSpecializer = FuncSpec;
+
+ using NativeType = TypedValue;
+ using NativeTypeConst = const TypedValue;
+ using NativeTypeConstRef = const TypedValue&;
+ using NativeTypeConstPtr = const TypedValue;
+
+ template <typename ArgumentGen>
+ inline static TypedValue ApplyUnaryTypedValue(
+ typename ArgumentGen::NativeTypeConstRef argument,
+ const Type &result_type,
+ const typename FuncSpec::FunctorType &functor) {
+ return FuncSpec::Invoke(functor, argument);
+ }
+
+ template <typename ArgumentGen>
+ inline static void ApplyUnaryColumnVector(
+ const typename ArgumentGen::NativeTypeConstRef argument,
+ const typename FuncSpec::FunctorType &functor,
+ ColumnVectorType *cv) {
+ cv->appendTypedValue(FuncSpec::Invoke(functor, argument));
+ }
+
+ template <typename LeftGen, typename RightGen>
+ inline static TypedValue ApplyBinaryTypedValue(
+ typename LeftGen::NativeTypeConstRef left,
+ typename RightGen::NativeTypeConstRef right,
+ const Type &result_type,
+ const typename FuncSpec::FunctorType &functor) {
+ return FuncSpec::Invoke(functor, left, right);
+ }
+
+ template <typename LeftGen, typename RightGen>
+ inline static void ApplyBinaryColumnVector(
+ const typename LeftGen::NativeTypeConstRef left,
+ const typename RightGen::NativeTypeConstRef right,
+ const typename FuncSpec::FunctorType &functor,
+ ColumnVectorType *cv) {
+ cv->appendTypedValue(FuncSpec::Invoke(functor, left, right));
+ }
+
+ template <bool nullable, typename AccessorT>
+ inline static NativeTypeConstPtr GetValuePtr(
+ const AccessorT *accessor,
+ const attribute_id attr_id) {
+ return accessor->getTypedValue(attr_id);
+ }
+
+ inline static bool IsNull(NativeTypeConstPtr &value) {
+ return value.isNull();
+ }
+
+ // Dereference: NativeTypeConstPtr& -> const NativeType&
+ inline static const NativeType& Dereference(NativeTypeConstPtr &value) {
+ return value;
+ }
+
+ inline static const NativeType& ToNativeValueConst(const TypedValue &value) {
+ return value;
+ }
+};
+
+template <typename ...FunctorTypes>
+struct FunctorPack {
+ template <typename Dispatcher>
+ inline static std::list<OperationPtr> GenerateOperations() {
+ std::vector<std::list<OperationPtr>> op_list_groups =
+ { Dispatcher::template Generate<FunctorTypes>()... };
+
+ std::list<OperationPtr> operations;
+ for (std::list<OperationPtr> &op_list : op_list_groups) {
+ operations.splice(operations.end(), std::move(op_list));
+ }
+ return operations;
+ }
+};
+
+struct OperationPack {
+ virtual std::vector<OperationPtr> generateOperations() = 0;
+};
+
+/** @} */
+
+} // namespace quickstep
+
+#endif // QUICKSTEP_TYPES_OPERATIONS_OPERATION_SYNTHESIZE_UTIL_HPP_
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/701751c8/utility/meta/Common.hpp
----------------------------------------------------------------------
diff --git a/utility/meta/Common.hpp b/utility/meta/Common.hpp
index 901b65c..cbad665 100644
--- a/utility/meta/Common.hpp
+++ b/utility/meta/Common.hpp
@@ -23,7 +23,7 @@
namespace quickstep {
namespace meta {
-/** \addtogroup Utility
+/** \addtogroup Meta
* @{
*/
@@ -99,6 +99,19 @@ struct IsWellFormed<T, Op, std::enable_if_t<std::is_same<Op<T>, Op<T>>::value>>
};
+namespace internal {
+
+template <typename T, std::size_t = sizeof(T)>
+std::true_type IsCompleteTypeImpl(T *);
+
+std::false_type IsCompleteTypeImpl(...);
+
+} // namespace internal
+
+template <typename T>
+using IsCompleteType = decltype(internal::IsCompleteTypeImpl(std::declval<T*>()));
+
+
template <typename LeftT, typename RightT>
struct PairSelectorLeft {
typedef LeftT type;
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/701751c8/utility/meta/Dispatchers.hpp
----------------------------------------------------------------------
diff --git a/utility/meta/Dispatchers.hpp b/utility/meta/Dispatchers.hpp
index 5b0ee48..1624bea 100644
--- a/utility/meta/Dispatchers.hpp
+++ b/utility/meta/Dispatchers.hpp
@@ -25,7 +25,7 @@
namespace quickstep {
namespace meta {
-/** \addtogroup Utility
+/** \addtogroup Meta
* @{
*/
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/701751c8/utility/meta/MetaprogrammingModule.hpp
----------------------------------------------------------------------
diff --git a/utility/meta/MetaprogrammingModule.hpp b/utility/meta/MetaprogrammingModule.hpp
new file mode 100644
index 0000000..912fdef
--- /dev/null
+++ b/utility/meta/MetaprogrammingModule.hpp
@@ -0,0 +1,24 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ **/
+
+/** @defgroup Meta
+ * @ingroup Utility
+ *
+ * Template metaprogramming utilities.
+ **/
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/701751c8/utility/meta/TransitiveClosure.hpp
----------------------------------------------------------------------
diff --git a/utility/meta/TransitiveClosure.hpp b/utility/meta/TransitiveClosure.hpp
index a5362bb..d5bb0ca 100644
--- a/utility/meta/TransitiveClosure.hpp
+++ b/utility/meta/TransitiveClosure.hpp
@@ -25,7 +25,7 @@
namespace quickstep {
namespace meta {
-/** \addtogroup Utility
+/** \addtogroup Meta
* @{
*/
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/701751c8/utility/meta/TypeList.hpp
----------------------------------------------------------------------
diff --git a/utility/meta/TypeList.hpp b/utility/meta/TypeList.hpp
index fac3ce5..5f4c4d9 100644
--- a/utility/meta/TypeList.hpp
+++ b/utility/meta/TypeList.hpp
@@ -26,15 +26,19 @@
namespace quickstep {
namespace meta {
-/** \addtogroup Utility
+/** \addtogroup Meta
* @{
*/
template <typename ...Ts>
class TypeList;
+namespace internal {
+
+using EmptyList = TypeList<>;
+
template <typename ...Ts>
-class TypeListCommon {
+class TypeListBase {
private:
template <typename ...Tail> struct AppendHelper {
using type = TypeList<Ts..., Tail...>;
@@ -44,13 +48,20 @@ class TypeListCommon {
static constexpr std::size_t length = sizeof...(Ts);
using type = TypeList<Ts...>;
+ using self = type;
template <template <typename ...> class Host>
using bind_to = Host<Ts...>;
template <std::size_t ...pos>
- using at = typename internal::ElementAtImpl<
- TypeList<Ts...>, TypeList<std::integral_constant<std::size_t, pos>...>>::type;
+ using at = typename ElementAtImpl<
+ self, TypeList<std::integral_constant<std::size_t, pos>...>>::type;
+
+ template <std::size_t n>
+ using take = typename TakeImpl<self, EmptyList, n>::type;
+
+ template <std::size_t n>
+ using skip = typename SkipImpl<self, n>::type;
template <typename T>
using push_front = TypeList<T, Ts...>;
@@ -62,59 +73,59 @@ class TypeListCommon {
using contains = EqualsAny<T, Ts...>;
template <typename ...DumbT>
- using unique = typename internal::UniqueImpl<TypeList<>, TypeList<Ts...>, DumbT...>::type;
+ using unique = typename UniqueImpl<EmptyList, self, DumbT...>::type;
template <typename TL>
using append = typename TL::template bind_to<AppendHelper>::type;
template <typename TL>
- using cartesian_product = typename internal::CartesianProductImpl<TypeList<Ts...>, TL>::type;
+ using cartesian_product = typename CartesianProductImpl<self, TL>::type;
template <typename Subtrahend>
- using subtract = typename internal::SubtractImpl<TypeList<>, TypeList<Ts...>, Subtrahend>::type;
+ using subtract = typename SubtractImpl<EmptyList, self, Subtrahend>::type;
template <template <typename ...> class Op>
using map = TypeList<typename Op<Ts>::type...>;
template <template <typename ...> class Op>
- using flatmap = typename internal::FlatmapImpl<TypeList<>, TypeList<Ts...>, Op>::type;
+ using flatmap = typename FlatmapImpl<EmptyList, self, Op>::type;
template <template <typename ...> class Op>
- using filter = typename internal::FilterImpl<TypeList<>, TypeList<Ts...>, Op>::type;
+ using filter = typename FilterImpl<EmptyList, self, Op>::type;
template <template <typename ...> class Op>
- using filtermap = typename internal::FiltermapImpl<TypeList<>, TypeList<Ts...>, Op>::type;
+ using filtermap = typename FiltermapImpl<EmptyList, self, Op>::type;
+
+ template <typename ...DumbT>
+ using flatten = typename FlattenImpl<EmptyList, self, DumbT...>::type;
template <typename ...DumbT>
- using flatten_once = typename internal::FlattenOnceImpl<TypeList<>, TypeList<Ts...>, DumbT...>::type;
+ using flatten_once = typename FlattenOnceImpl<EmptyList, self, DumbT...>::type;
+
+ template <template <typename ...> class Op, typename InitT>
+ using foldl = typename FoldlImpl<InitT, self, Op>::type;
template <typename TL>
- using zip = typename internal::ZipImpl<TypeList<>, TypeList<Ts...>, TL>::type;
+ using zip = typename ZipImpl<EmptyList, self, TL>::type;
template <typename TL, template <typename ...> class Op>
- using zip_with = typename internal::ZipWithImpl<TypeList<>, TypeList<Ts...>, TL, Op>::type;
+ using zip_with = typename ZipWithImpl<EmptyList, self, TL, Op>::type;
template <typename T>
- using as_sequence = typename internal::AsSequenceImpl<T, Ts...>::type;
+ using as_sequence = typename AsSequenceImpl<T, Ts...>::type;
};
-template <typename ...Ts>
-class TypeList : public TypeListCommon<Ts...> {
- private:
- template <typename Head, typename ...Tail>
- struct HeadTailHelper {
- using head = Head;
- using tail = TypeList<Tail...>;
- };
+} // namespace internal
+template <typename T, typename ...Ts>
+class TypeList<T, Ts...> : public internal::TypeListBase<T, Ts...> {
public:
- using head = typename HeadTailHelper<Ts...>::head;
- using tail = typename HeadTailHelper<Ts...>::tail;
+ using head = T;
+ using tail = TypeList<Ts...>;
};
template <>
-class TypeList<> : public TypeListCommon<> {
-};
+class TypeList<> : public internal::TypeListBase<> {};
/** @} */
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/701751c8/utility/meta/TypeListMetaFunctions.hpp
----------------------------------------------------------------------
diff --git a/utility/meta/TypeListMetaFunctions.hpp b/utility/meta/TypeListMetaFunctions.hpp
index d908493..baebe91 100644
--- a/utility/meta/TypeListMetaFunctions.hpp
+++ b/utility/meta/TypeListMetaFunctions.hpp
@@ -25,13 +25,24 @@
namespace quickstep {
namespace meta {
-/** \addtogroup Utility
+/** \addtogroup Meta
* @{
*/
template <typename ...Ts>
class TypeList;
+
+template <typename T>
+struct IsTypeList {
+ constexpr static bool value = false;
+};
+template <typename ...Ts>
+struct IsTypeList<TypeList<Ts...>> {
+ constexpr static bool value = true;
+};
+
+
namespace internal {
template <typename TL, typename PosTL, typename Enable = void>
@@ -52,6 +63,34 @@ struct ElementAtImpl<TL, PosTL,
typename PosTL::tail> {};
+template <typename TL, typename Out, std::size_t rest, typename Enable = void>
+struct TakeImpl;
+
+template <typename TL, typename Out, std::size_t rest>
+struct TakeImpl<TL, Out, rest, std::enable_if_t<rest == 0>> {
+ using type = Out;
+};
+
+template <typename TL, typename Out, std::size_t rest>
+struct TakeImpl<TL, Out, rest, std::enable_if_t<rest != 0>>
+ : TakeImpl<typename TL::tail,
+ typename Out::template push_back<typename TL::head>,
+ rest - 1> {};
+
+
+template <typename TL, std::size_t rest, typename Enable = void>
+struct SkipImpl;
+
+template <typename TL, std::size_t rest>
+struct SkipImpl<TL, rest, std::enable_if_t<rest == 0>> {
+ using type = TL;
+};
+
+template <typename TL, std::size_t rest>
+struct SkipImpl<TL, rest, std::enable_if_t<rest != 0>>
+ : SkipImpl<typename TL::tail, rest - 1> {};
+
+
template <typename Out, typename Rest, typename Enable = void>
struct UniqueImpl;
@@ -174,6 +213,30 @@ struct FiltermapImpl<Out, Rest, Op,
template <typename Out, typename Rest, typename Enable = void>
+struct FlattenImpl;
+
+template <typename Out, typename Rest>
+struct FlattenImpl<Out, Rest,
+ std::enable_if_t<Rest::length == 0>> {
+ using type = Out;
+};
+
+template <typename Out, typename Rest>
+struct FlattenImpl<Out, Rest,
+ std::enable_if_t<Rest::length != 0 &&
+ IsTypeList<typename Rest::head>::value>>
+ : FlattenImpl<typename Out::template append<typename Rest::head::template flatten<>>,
+ typename Rest::tail> {};
+
+template <typename Out, typename Rest>
+struct FlattenImpl<Out, Rest,
+ std::enable_if_t<Rest::length != 0 &&
+ !IsTypeList<typename Rest::head>::value>>
+ : FlattenImpl<typename Out::template push_back<typename Rest::head>,
+ typename Rest::tail> {};
+
+
+template <typename Out, typename Rest, typename Enable = void>
struct FlattenOnceImpl;
template <typename Out, typename Rest>
@@ -188,6 +251,21 @@ struct FlattenOnceImpl<Out, Rest,
: FlattenOnceImpl<typename Out::template append<typename Rest::head>,
typename Rest::tail> {};
+template <typename Out, typename Rest, template <typename ...> class Op,
+ typename Enable = void>
+struct FoldlImpl;
+
+template <typename Out, typename Rest, template <typename ...> class Op>
+struct FoldlImpl<Out, Rest, Op,
+ std::enable_if_t<Rest::length == 0>> {
+ using type = Out;
+};
+
+template <typename Out, typename Rest, template <typename ...> class Op>
+struct FoldlImpl<Out, Rest, Op,
+ std::enable_if_t<Rest::length != 0>>
+ : FoldlImpl<typename Op<Out, typename Rest::head>::type,
+ typename Rest::tail, Op> {};
template <typename Out, typename RestL, typename RestR, typename Enable = void>
struct ZipImpl;