Browse Source

breaking: implement a category enum instead of using deduction

Sam Jaffe 2 years ago
parent
commit
6fe7f6a52c

+ 4 - 4
include/iterator/capture_iterator.h

@@ -8,7 +8,6 @@
 
 #pragma once
 
-#include <iterator/detail/facade_traits.h>
 #include <iterator/forwards.h>
 #include <iterator/proxy.h>
 
@@ -32,17 +31,18 @@ public:
 
   value_type const & dereference() const { return cache_; }
 
-  SFINAE(detail::has_increment_v<It>) void increment() {
+  SFINAE(super_t::category_enum >= category::forward) void increment() {
     super_t::increment();
     cache_ = super_t::dereference();
   }
 
-  SFINAE(detail::has_decrement_v<It>) void decrement() {
+  SFINAE(super_t::category_enum >= category::bidirectional)
+  void decrement() {
     super_t::decrement();
     cache_ = super_t::dereference();
   }
 
-  SFINAE(detail::is_advanceable_iterator_v<It>)
+  SFINAE(super_t::category_enum >= category::random_access)
   void advance(difference_type off) {
     super_t::advance(off);
     cache_ = super_t::dereference();

+ 0 - 86
include/iterator/detail/facade_traits.h

@@ -1,86 +0,0 @@
-//
-//  facade_traits.h
-//  iterator
-//
-//  Created by Sam Jaffe on 4/1/23.
-//  Copyright © 2023 Sam Jaffe. All rights reserved.
-//
-
-#pragma once
-
-#include <iterator>
-#include <type_traits>
-
-#include <iterator/detail/macro.h>
-#include <iterator/detail/traits.h>
-
-namespace iterator::detail {
-template <typename, typename = void> struct has_equal_to : std::false_type {};
-template <typename T>
-struct has_equal_to<T, EXISTS(VAL(T).equal_to(VAL(T)))> : std::true_type {};
-
-template <typename, typename = void>
-struct has_distance_to : std::false_type {};
-template <typename T>
-struct has_distance_to<T, EXISTS(VAL(T).distance_to(VAL(T)))> : std::true_type {
-};
-
-template <typename, typename = void>
-struct is_advanceable_iterator : std::false_type {};
-template <typename T>
-struct is_advanceable_iterator<T, EXISTS(VAL(T).advance({}))> : std::true_type {
-};
-
-template <typename, typename = void>
-struct is_single_pass_iterator : std::false_type {};
-template <typename T>
-struct is_single_pass_iterator<T, std::void_t<typename T::single_pass_iterator>>
-    : std::true_type {};
-
-template <typename, typename = void> struct has_increment : std::false_type {};
-template <typename T>
-struct has_increment<T, EXISTS(VAL(T).increment())> : std::true_type {};
-
-template <typename, typename = void> struct has_decrement : std::false_type {};
-template <typename T>
-struct has_decrement<T, EXISTS(VAL(T).decrement())> : std::true_type {};
-
-template <typename, typename = void> struct distance_to {
-  using type = std::ptrdiff_t;
-};
-
-template <typename T>
-struct distance_to<T, std::enable_if_t<has_distance_to<T>{}>> {
-  using type = decltype(VAL(T).distance_to(VAL(T)));
-};
-
-template <typename T> using distance_to_t = typename distance_to<T>::type;
-template <typename T> constexpr bool has_equal_to_v = has_equal_to<T>{};
-template <typename T> constexpr bool has_distance_to_v = has_distance_to<T>{};
-template <typename T> constexpr bool has_increment_v = has_increment<T>{};
-template <typename T> constexpr bool has_decrement_v = has_decrement<T>{};
-template <typename T>
-constexpr bool is_advanceable_iterator_v = is_advanceable_iterator<T>{};
-
-template <typename It>
-constexpr bool is_single_pass_iterator_v = is_single_pass_iterator<It>{};
-
-template <typename It> struct facade_category {
-  constexpr static bool has_random_access =
-      has_distance_to_v<It> && is_advanceable_iterator_v<It>;
-  constexpr static bool has_bidirectional =
-      has_decrement_v<It> && has_increment_v<It> && has_equal_to_v<It>;
-
-  using type = std::conditional_t<
-      has_random_access, std::random_access_iterator_tag,
-      std::conditional_t<has_bidirectional, std::bidirectional_iterator_tag,
-                         std::conditional_t<is_single_pass_iterator_v<It>,
-                                            std::input_iterator_tag,
-                                            std::forward_iterator_tag>>>;
-};
-
-template <typename It>
-using facade_category_t = typename facade_category<It>::type;
-}
-
-#include <iterator/detail/undef.h>

+ 1 - 0
include/iterator/detail/macro.h

@@ -20,5 +20,6 @@
 #define DEREF_TYPE(X) decltype(*VAL(X))
 #define TYPE(X, EXPR) decltype(VAL(X).EXPR)
 #define EXISTS(EXPR) std::void_t<decltype(EXPR)>
+#define DEFER(TYPE) (std::is_void_v<TYPE> || true)
 
 #endif

+ 59 - 41
include/iterator/detail/traits.h

@@ -1,34 +1,21 @@
 #pragma once
 
+#include <algorithm>
 #include <iterator>
 #include <type_traits>
 
-namespace iterator {
-struct sentinel_t;
-}
+#include <iterator/forwards.h>
+
+#include <iterator/detail/macro.h>
 
+// Section: Non-Dependant Typedef Helpers
 namespace iterator::detail {
+template <typename Iter>
+using category_t = typename std::iterator_traits<Iter>::iterator_category;
 template <typename C> using iter = decltype(std::begin(std::declval<C>()));
+}
 
-// Type Helper for deducing reference types
-template <typename T, typename = void> struct reference_helper {
-  using type = decltype(*std::declval<T>());
-};
-template <typename T>
-struct reference_helper<T, std::void_t<typename T::reference>> {
-  using type = typename T::reference;
-};
-
-// Type Helper for deducing value types
-template <typename T, typename = void> struct value_type_helper {
-  using reference = typename reference_helper<T>::type;
-  using type = std::remove_cv_t<std::remove_reference_t<reference>>;
-};
-template <typename T>
-struct value_type_helper<T, std::void_t<typename T::value_type>> {
-  using type = typename T::value_type;
-};
-
+namespace iterator::detail {
 // Type Helper for identifying container-like objects
 template <typename C, typename = void> struct is_container : std::false_type {};
 template <typename C>
@@ -39,37 +26,68 @@ struct has_sentinel_type : std::false_type {};
 template <typename It>
 struct has_sentinel_type<It, std::void_t<typename It::sentinel_type>>
     : std::true_type {};
+}
 
-template <typename T> using value_type = typename value_type_helper<T>::type;
-template <typename T> using reference = typename reference_helper<T>::type;
+// Mappings between iterator::category enum and iterator_category tags
+namespace iterator::detail {
+template <typename Tag, category Limit = static_cast<category>(~0)>
+struct category_for {
+  constexpr static category value = category::single_pass;
+};
 
-template <typename C> constexpr bool is_container_v = is_container<C>{};
+template <category Limit>
+struct category_for<std::forward_iterator_tag, Limit> {
+  constexpr static category value = std::min(category::forward, Limit);
+};
 
-template <typename Iter>
-constexpr bool is_rvalue_iterator_v = !std::is_reference_v<reference<Iter>>;
+template <category Limit>
+struct category_for<std::bidirectional_iterator_tag, Limit> {
+  constexpr static category value = std::min(category::bidirectional, Limit);
+};
 
-template <typename Iter>
-using category = typename std::iterator_traits<Iter>::iterator_category;
+template <category Limit>
+struct category_for<std::random_access_iterator_tag, Limit> {
+  constexpr static category value = std::min(category::random_access, Limit);
+};
 
-template <typename Iter>
-constexpr bool is_random_access_v =
-    std::is_same_v<category<Iter>, std::random_access_iterator_tag>;
+template <category> struct tag_for;
+template <> struct tag_for<category::single_pass> {
+  using type = std::input_iterator_tag;
+};
 
-template <typename Iter>
-constexpr bool is_bidirectional_v =
-    std::is_same_v<category<Iter>, std::bidirectional_iterator_tag> ||
-    is_random_access_v<Iter>;
+template <category> struct tag_for;
+template <> struct tag_for<category::forward> {
+  using type = std::forward_iterator_tag;
+};
 
-template <typename Iter>
-constexpr bool is_forward_v =
-    std::is_same_v<category<Iter>, std::forward_iterator_tag> ||
-    is_bidirectional_v<Iter>;
+template <category> struct tag_for;
+template <> struct tag_for<category::bidirectional> {
+  using type = std::bidirectional_iterator_tag;
+};
+
+template <category> struct tag_for;
+template <> struct tag_for<category::random_access> {
+  using type = std::random_access_iterator_tag;
+};
+}
 
-template <typename Iter> constexpr bool is_single_pass_v = !is_forward_v<Iter>;
+namespace iterator::detail {
+template <typename C> constexpr bool is_container_v = is_container<C>{};
+
+template <typename Iter>
+constexpr bool is_rvalue_iterator_v = !std::is_reference_v<DEREF_TYPE(Iter)>;
 
 template <typename It>
 constexpr bool has_sentinel_type_v = has_sentinel_type<It>{};
 
 template <typename It, typename S>
 using sentinel_type = std::conditional_t<std::is_same_v<It, S>, sentinel_t, S>;
+
+template <typename It, category Limit = static_cast<category>(~0)>
+constexpr auto category_for_v = category_for<category_t<It>, Limit>::value;
+
+template <typename It>
+using tag_for_t = typename tag_for<It::category_enum>::type;
 }
+
+#include <iterator/detail/undef.h>

+ 2 - 2
include/iterator/end_aware_iterator.h

@@ -43,13 +43,13 @@ public:
       : super_t(other.impl()), end_(other.end_) {}
 
   bool at_end() const {
-    if constexpr (detail::is_random_access_v<It>) {
+    if constexpr (super_t::category_enum == category::random_access) {
       return super_t::impl() >= end_;
     } else {
       return super_t::impl() == end_;
     }
   }
-  
+
 protected:
   It end() const { return end_; }
 

+ 54 - 41
include/iterator/facade.h

@@ -4,15 +4,35 @@
 #include <type_traits>
 
 #include <iterator/detail/arrow_proxy.h>
-#include <iterator/detail/facade_traits.h>
 #include <iterator/detail/traits.h>
 
+#include <iterator/detail/macro.h>
+
+namespace iterator::detail {
+template <typename, typename = void> struct distance_to {
+  using type = std::ptrdiff_t;
+};
+
+template <typename T>
+struct distance_to<T, EXISTS(VAL(T).distance_to(VAL(T)))> {
+  using type = decltype(VAL(T).distance_to(VAL(T)));
+};
+
+template <typename T> using distance_to_t = typename distance_to<T>::type;
+}
+
 namespace iterator {
 template <typename D, typename T>
 using difference_type_arg_t =
     std::enable_if_t<std::is_convertible_v<D, detail::distance_to_t<T>>>;
 
-template <typename self_type> class facade {
+template <typename CRTP, category C> class facade {
+private:
+  using self_type = CRTP;
+
+public:
+  constexpr static auto category_enum = C;
+
 public:
   decltype(auto) operator*() const { return self().dereference(); }
 
@@ -24,13 +44,14 @@ public:
     }
   }
 
-  template <typename D, typename = difference_type_arg_t<D, self_type>>
+  template <typename D, typename = difference_type_arg_t<D, self_type>,
+            REQUIRES(DEFER(D) && C == category::random_access)>
   decltype(auto) operator[](D off) const {
     return *(self() + off);
   }
 
   self_type & operator++() {
-    if constexpr (detail::is_advanceable_iterator_v<self_type>) {
+    if constexpr (C == category::random_access) {
       self() += 1;
     } else {
       self().increment();
@@ -39,7 +60,7 @@ public:
   }
 
   auto operator++(int) {
-    if constexpr (detail::is_single_pass_iterator_v<self_type>) {
+    if constexpr (C == category::single_pass) {
       ++*this;
     } else {
       auto tmp = self();
@@ -48,8 +69,9 @@ public:
     }
   }
 
+  SFINAE(C >= category::bidirectional)
   self_type & operator--() {
-    if constexpr (detail::is_advanceable_iterator_v<self_type>) {
+    if constexpr (C == category::random_access) {
       self() -= 1;
     } else {
       self().decrement();
@@ -57,55 +79,52 @@ public:
     return self();
   }
 
+  SFINAE(C >= category::bidirectional)
   self_type operator--(int) {
     auto tmp = self();
     --*this;
     return tmp;
   }
 
-  template <typename D, typename = difference_type_arg_t<D, self_type>>
+  template <typename D, typename = difference_type_arg_t<D, self_type>,
+            REQUIRES(DEFER(D) && C == category::random_access)>
   friend self_type & operator+=(self_type & self, D off) {
-    static_assert(detail::is_advanceable_iterator_v<self_type>,
-                  "must be advancable");
     self.advance(off);
     return self;
   }
 
-  template <typename D, typename = difference_type_arg_t<D, self_type>>
+  template <typename D, typename = difference_type_arg_t<D, self_type>,
+            REQUIRES(DEFER(D) && C == category::random_access)>
   friend self_type & operator-=(self_type & self, D off) {
-    static_assert(detail::is_advanceable_iterator_v<self_type>,
-                  "must be advancable");
     self.advance(-off);
     return self;
   }
 
-  template <typename D, typename = difference_type_arg_t<D, self_type>>
+  template <typename D, typename = difference_type_arg_t<D, self_type>,
+            REQUIRES(DEFER(D) && C == category::random_access)>
   friend auto operator+(self_type self, D off) {
-    static_assert(detail::is_advanceable_iterator_v<self_type>,
-                  "must be advancable");
     return self += off;
   }
 
-  template <typename D, typename = difference_type_arg_t<D, self_type>>
+  template <typename D, typename = difference_type_arg_t<D, self_type>,
+            REQUIRES(DEFER(D) && C == category::random_access)>
   friend auto operator+(D off, self_type self) {
-    static_assert(detail::is_advanceable_iterator_v<self_type>,
-                  "must be advancable");
     return self += off;
   }
 
-  template <typename D, typename = difference_type_arg_t<D, self_type>>
+  template <typename D, typename = difference_type_arg_t<D, self_type>,
+            REQUIRES(DEFER(D) && C == category::random_access)>
   friend auto operator-(self_type self, D off) {
-    static_assert(detail::is_advanceable_iterator_v<self_type>,
-                  "must be advancable");
     return self -= off;
   }
 
+  SFINAE(C == category::random_access)
   friend auto operator-(self_type const & left, self_type const & right) {
     return right.distance_to(left);
   }
 
   friend bool operator==(self_type const & left, self_type const & right) {
-    if constexpr (detail::has_distance_to_v<self_type>) {
+    if constexpr (C == category::random_access) {
       return (left - right) == 0;
     } else {
       return left.equal_to(right);
@@ -116,18 +135,22 @@ public:
     return !(left == right);
   }
 
+  SFINAE(C == category::random_access)
   friend bool operator<(self_type const & left, self_type const & right) {
     return (left - right) < 0;
   }
 
+  SFINAE(C == category::random_access)
   friend bool operator<=(self_type const & left, self_type const & right) {
     return (left - right) <= 0;
   }
 
+  SFINAE(C == category::random_access)
   friend bool operator>(self_type const & left, self_type const & right) {
     return (left - right) > 0;
   }
 
+  SFINAE(C == category::random_access)
   friend bool operator>=(self_type const & left, self_type const & right) {
     return (left - right) >= 0;
   }
@@ -140,26 +163,16 @@ protected:
 };
 }
 
-#include <iterator/detail/macro.h>
-
 // In C++20, a concept/requires could be used to eschew the need for the below
 // macros.
-template <typename I> struct std::iterator_traits<::iterator::facade<I>> {
-  using reference = DEREF_TYPE(I);
-  using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
-  using pointer = TYPE(I, operator->());
-  using difference_type = ::iterator::detail::distance_to_t<I>;
-  using iterator_category = ::iterator::detail::facade_category_t<I>;
-};
-
-#define MAKE_ITERATOR_FACADE_TYPEDEFS(type)                                    \
-  template <>                                                                  \
-  struct std::iterator_traits<type>                                            \
-      : std::iterator_traits<::iterator::facade<type>> {}
-
-#define MAKE_ITERATOR_FACADE_TYPEDEFS_T(type)                                  \
-  template <typename... T>                                                     \
-  struct std::iterator_traits<type<T...>>                                      \
-      : std::iterator_traits<::iterator::facade<type<T...>>> {}
+#define MAKE_ITERATOR_FACADE_TYPEDEFS_T(Iter)                                  \
+  template <typename... T> struct std::iterator_traits<Iter<T...>> {           \
+    using type = Iter<T...>;                                                   \
+    using reference = decltype(*std::declval<type>());                         \
+    using value_type = std::decay_t<reference>;                                \
+    using pointer = decltype(std::declval<type>().operator->());               \
+    using difference_type = ::iterator::detail::distance_to_t<type>;           \
+    using iterator_category = ::iterator::detail::tag_for_t<type>;             \
+  }
 
 #include <iterator/detail/undef.h>

+ 3 - 1
include/iterator/filter_iterator.h

@@ -17,8 +17,10 @@
 #include <iterator/detail/macro.h>
 
 namespace iterator {
+// TODO: Support Bidirectional Iterators
 template <typename Iter, typename Pred>
-class filter_iterator : public facade<filter_iterator<Iter, Pred>> {
+class filter_iterator
+    : public facade<filter_iterator<Iter, Pred>, category::forward> {
 public:
   using sentinel_type = sentinel_t;
 

+ 22 - 13
include/iterator/forwards.h

@@ -17,21 +17,30 @@ template <typename, typename = unbounded> class rimpl;
 }
 
 namespace iterator {
+enum class category : unsigned char {
+  single_pass, // input/output iterator, for example
+  forward,
+  bidirectional,
+  random_access
+};
+
 struct sentinel_t;
 
 // Iterator types
-template <typename> class end_aware_iterator;
-template <typename, typename> class filter_iterator;
-template <typename> class joining_iterator;
-template <typename> class unkeyed_iterator;
-template <typename...> class zip_iterator;
-
-template <typename It> using recursive_iterator = recursive::rimpl<It>;
-template <typename It, std::size_t N>
-using recursive_iterator_n = recursive::rimpl<It, recursive::bounded<N>>;
-
-template <typename> class facade;
-template <typename It, typename,
-          typename = typename std::iterator_traits<It>::iterator_category>
+template <typename Iterator> class end_aware_iterator;
+template <typename Iterator, typename Predicate> class filter_iterator;
+template <typename OuterIterator> class joining_iterator;
+template <typename Iterator> class unkeyed_iterator;
+template <typename... Iterators> class zip_iterator;
+
+template <typename Iterator>
+using recursive_iterator = recursive::rimpl<Iterator>;
+template <typename Iterator, std::size_t N>
+using recursive_iterator_n = recursive::rimpl<Iterator, recursive::bounded<N>>;
+
+template <typename CRTP, category C> class facade;
+
+template <typename Iterator, typename CRTP,
+          typename = typename std::iterator_traits<Iterator>::iterator_category>
 class proxy;
 }

+ 3 - 1
include/iterator/indexed_iterator.h

@@ -15,8 +15,10 @@
 #include <iterator/detail/macro.h>
 
 namespace iterator {
+// TODO: I should be respecting the underlying type
 template <typename It>
-class indexed_iterator : public facade<indexed_iterator<It>> {
+class indexed_iterator
+    : public facade<indexed_iterator<It>, category::random_access> {
 public:
   using reference =
       std::pair<size_t, typename std::iterator_traits<It>::reference>;

+ 2 - 1
include/iterator/join_iterator.h

@@ -20,7 +20,8 @@
 
 namespace iterator {
 template <typename It>
-class joining_iterator : public facade<joining_iterator<It>> {
+class joining_iterator
+    : public facade<joining_iterator<It>, category::forward> {
 private:
   template <typename Ot> friend class joining_iterator;
   constexpr static bool requires_caching = detail::is_rvalue_iterator_v<It>;

+ 7 - 7
include/iterator/proxy.h

@@ -7,7 +7,7 @@
 
 namespace iterator {
 template <typename It, typename Self, typename Cat>
-class proxy : public facade<Self> {
+class proxy : public facade<Self, category::single_pass> {
 public:
   using single_pass_iterator = void;
 
@@ -31,7 +31,8 @@ protected:
 };
 
 template <typename It, typename Self>
-class proxy<It, Self, std::forward_iterator_tag> : public facade<Self> {
+class proxy<It, Self, std::forward_iterator_tag>
+    : public facade<Self, category::forward> {
 private:
   It impl_;
 
@@ -52,7 +53,8 @@ protected:
 };
 
 template <typename It, typename Self>
-class proxy<It, Self, std::bidirectional_iterator_tag> : public facade<Self> {
+class proxy<It, Self, std::bidirectional_iterator_tag>
+    : public facade<Self, category::bidirectional> {
 private:
   It impl_;
 
@@ -74,7 +76,8 @@ protected:
 };
 
 template <typename It, typename Self>
-class proxy<It, Self, std::random_access_iterator_tag> : public facade<Self> {
+class proxy<It, Self, std::random_access_iterator_tag>
+    : public facade<Self, category::random_access> {
 public:
   using difference_type = typename std::iterator_traits<It>::difference_type;
 
@@ -88,9 +91,6 @@ public:
 
   decltype(auto) dereference() const { return *impl_; }
   void advance(difference_type off) { impl_ += off; }
-  // This shouldn't need to be implemented, but for some reason my traits
-  // are not correctly deducing here.
-  bool equal_to(Self const & other) const { return distance_to(other) == 0; }
   difference_type distance_to(Self const & other) const {
     return other.impl_ - impl_;
   }

+ 1 - 1
include/iterator/recursive_iterator.h

@@ -84,7 +84,7 @@ struct tuple<It, Bnd, recursion_type::ASSOC> {
  * is willing to delve in the parent object.
  */
 template <typename It, typename Bnd>
-class rimpl : public facade<rimpl<It, Bnd>> {
+class rimpl : public facade<rimpl<It, Bnd>, category::forward> {
 public:
   using sentinel_type = sentinel_t;
   using iters_t = typename tuple<It, Bnd>::iter;

+ 8 - 10
include/iterator/zip_iterator.h

@@ -53,9 +53,14 @@ template <typename... Ts>
 using zip_impl =
     detail::zip_iterator_impl<std::tuple<Ts...>, index_sequence<Ts...>>;
 
+template <typename... Iterators>
+constexpr auto
+    zip_category_for = std::min({detail::category_for_v<Iterators>...});
+
 template <typename... Iters>
-class zip_iterator : public zip_impl<Iters...>,
-                     public facade<zip_iterator<Iters...>> {
+class zip_iterator
+    : public zip_impl<Iters...>,
+      public facade<zip_iterator<Iters...>, zip_category_for<Iters...>> {
 public:
   zip_iterator() = default;
   zip_iterator(Iters... iters) : zip_impl<Iters...>(iters...) {}
@@ -64,11 +69,4 @@ public:
 template <typename... It> zip_iterator(It...) -> zip_iterator<It...>;
 }
 
-template <typename... T>
-struct std::iterator_traits<::iterator::zip_iterator<T...>>
-    : std::iterator_traits<::iterator::facade<::iterator::zip_iterator<T...>>> {
-  // This shouldn't need to be implemented, but for some reason my traits
-  // are not correctly deducing here.
-  using iterator_category =
-      common_type_t<typename iterator_traits<T>::iterator_category...>;
-};
+MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::zip_iterator);

+ 0 - 2
iterator.xcodeproj/project.pbxproj

@@ -65,7 +65,6 @@
 		CD3C6DDB26238F8F00548B64 /* xcode_gtest_helper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xcode_gtest_helper.h; sourceTree = "<group>"; };
 		CD5A8E7329D7910D008C2A4F /* sentinel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sentinel.h; sourceTree = "<group>"; };
 		CD5AEAE729D86D8100A390A4 /* ranges.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ranges.h; sourceTree = "<group>"; };
-		CD5AEAE829D86DCD00A390A4 /* facade_traits.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = facade_traits.h; sourceTree = "<group>"; };
 		CD5AEB3129D8885400A390A4 /* macro.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = macro.h; sourceTree = "<group>"; };
 		CD5AEB3229D8886200A390A4 /* undef.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = undef.h; sourceTree = "<group>"; };
 		CD5AEB3329D8956600A390A4 /* capture_iterator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = capture_iterator.h; sourceTree = "<group>"; };
@@ -195,7 +194,6 @@
 			isa = PBXGroup;
 			children = (
 				CDA2B61A2858128C004D5353 /* arrow_proxy.h */,
-				CD5AEAE829D86DCD00A390A4 /* facade_traits.h */,
 				CD5AEB3129D8885400A390A4 /* macro.h */,
 				CDA2B6182858128C004D5353 /* recursive_traits.h */,
 				CDA2B6192858128C004D5353 /* traits.h */,