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/10 18:26:02 UTC

[32/38] incubator-quickstep git commit: More updates, refactor names

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/f9e32e6a/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/f9e32e6a/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/f9e32e6a/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/f9e32e6a/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/f9e32e6a/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/f9e32e6a/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/f9e32e6a/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;