浏览代码

Adding member variable and member function versions of map that project references.
Adding cast<S> and dereference stream maps that project references.
Fixing streams to be reference-compatible to minimize copies.

Samuel Jaffe 8 年之前
父节点
当前提交
6cab3fc366

+ 7 - 0
stream.t.h

@@ -95,4 +95,11 @@ public:
     vec_t o{s.begin(), s.end()};
     TS_ASSERT_EQUALS(expected, o);
   }
+  
+  void test_dereference() {
+    int val = 5;
+    std::vector<int*> v{&val};
+    auto data = stream::make_stream(v).deref().collect();
+    TS_ASSERT_EQUALS(data.front(), val);
+  }
 };

+ 1 - 1
stream.xcodeproj/project.pbxproj

@@ -82,9 +82,9 @@
 		CD9337371E3CD88200699FF5 /* test */ = {
 			isa = PBXGroup;
 			children = (
-				CD9337271E3CD78B00699FF5 /* stream_tc.cpp */,
 				CD9337281E3CD78B00699FF5 /* stream.t.h */,
 				CDF9374E1E3D9AD7003E5D5C /* stream_fluent.t.h */,
+				CD9337271E3CD78B00699FF5 /* stream_tc.cpp */,
 			);
 			name = test;
 			sourceTree = "<group>";

+ 1 - 1
stream.xcodeproj/xcuserdata/samjaffe.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -7,7 +7,7 @@
 		<key>stream_tc.xcscheme</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>20</integer>
+			<integer>19</integer>
 		</dict>
 	</dict>
 	<key>SuppressBuildableAutocreation</key>

+ 15 - 1
streams/filter.hpp

@@ -1,6 +1,20 @@
 #pragma once
 
 namespace stream { namespace detail {
+  template <typename T>
+  struct ref_or_val {
+    ref_or_val operator=(T && val) { value = std::move(val); return *this; }
+    operator T const &() const { return value; }
+    T value;
+  };
+
+  template <typename T>
+  struct ref_or_val<T&> {
+    ref_or_val operator=(T & val) { value = &val; return *this; }
+    operator T &() const { return *value; }
+    T * value;
+  };
+
   namespace filter {
     template <typename T>
     class iterator : public iterator_impl<T> {
@@ -30,7 +44,7 @@ namespace stream { namespace detail {
       }
       
       std::function<bool(T const&)> pred_;
-      T mem_; // To avoid re-calcs, we store this
+      ref_or_val<T> mem_; // To avoid re-calcs, we store this
       ::stream::iterator<T> impl_, end_;
     };
   }

+ 4 - 4
streams/fluent.hpp

@@ -44,22 +44,22 @@ namespace stream {
 
 namespace stream { namespace detail {
   template <typename T, typename R>
-  stream_base<R> operator|(stream_base<T> const&s, ::stream::map<T, R>&& f) {
+  stream_base<R> operator|(stream_base<T> const&s, ::stream::map<typename std::decay<T>::type, R>&& f) {
     return s.map(f.func);
   }
   
   template <typename T, typename C>
-  stream_base<typename C::value_type> operator|(stream_base<T> const&s, ::stream::flatmap<T, C>&& f) {
+  stream_base<typename C::value_type> operator|(stream_base<T> const&s, ::stream::flatmap<typename std::decay<T>::type, C>&& f) {
     return s.flatmap(f.func);
   }
   
   template <typename T>
-  stream_base<T> operator|(stream_base<T> const&s, ::stream::filter<T>&& f) {
+  stream_base<T> operator|(stream_base<T> const&s, ::stream::filter<typename std::decay<T>::type>&& f) {
     return s.filter(f.pred);
   }
 
   template <typename L, typename R>
-  L operator >(stream_base<R> const &s, ::stream::fold_left<L, R> && f) {
+  L operator >(stream_base<R> const &s, ::stream::fold_left<L, typename std::decay<R>::type> && f) {
     return std::accumulate(s.begin(), s.end(), f.init, f.fold);
   }
   

+ 40 - 13
streams/source.hpp

@@ -3,36 +3,63 @@
 namespace stream {
   namespace detail {
     namespace source {
-      template <typename C>
-      class iterator : public iterator_impl<typename C::value_type> {
+      template <typename Iter>
+      class iterator : public iterator_impl<typename std::iterator_traits<Iter>::reference> {
       public:
-        typedef iterator_impl<typename C::value_type> super;
-        explicit iterator(typename C::iterator it) : impl_(it) {}
+        using value_type = typename std::iterator_traits<Iter>::reference;
+        typedef iterator_impl<value_type> super;
+        explicit iterator(Iter it) : impl_(it) {}
         ~iterator() {}
-        typename C::value_type operator*() override { return *impl_; }
+        value_type operator*() override { return *impl_; }
         DELEGATE_ITERATOR_IMPL(impl_)
       private:
-        typename C::const_iterator impl_;
+        Iter impl_;
       };
+      
+      template <typename C>
+      using reference = decltype(*std::declval<C>().begin());
     }
     
     template <typename C>
-    class source_stream : public stream_impl<typename C::value_type> {
+    class source_stream : public stream_impl<source::reference<C>> {
     public:
-      typedef typename C::value_type value_type;
+      typedef source::reference<C> reference;
+      typedef decltype(std::declval<C>().begin()) _iterator;
       
-      explicit source_stream(C const& cont) : source_(cont) {}
-      explicit source_stream(C && cont) : source_(std::forward(cont)) {}
+      explicit source_stream(C && cont) : source_(std::forward<C>(cont)) {}
       ~source_stream() override {}
-      iterator<value_type> begin() override { return {new source::iterator<C>{source_.begin()}}; }
-      iterator<value_type> end() override { return {new source::iterator<C>{source_.end()}}; }
+      iterator<reference> begin() override { return {new source::iterator<_iterator>{source_.begin()}}; }
+      iterator<reference> end() override { return {new source::iterator<_iterator>{source_.end()}}; }
     private:
       C source_;
     };
+    
+    template <typename It, typename V = typename It::value_type>
+    class range_stream : public stream_impl<V &> {
+    public:
+      typedef V & reference;
+      
+      explicit range_stream(It b, It e) : begin_(b), end_(e) {}
+      ~range_stream() override {}
+      iterator<reference> begin() override { return {new source::iterator<It>{begin_}}; }
+      iterator<reference> end() override { return {new source::iterator<It>{end_}}; }
+    private:
+      It begin_, end_;
+    };
   }
   
   template <typename C>
-  detail::stream_base<typename C::value_type> make_stream(C const& cont) {
+  detail::stream_base<detail::source::reference<C>> make_stream(C && cont) {
     return {std::make_shared<detail::source_stream<C>>(cont)};
   }
+  
+  template <typename T>
+  detail::stream_base<T&> make_stream(T * ptr) {
+    return {std::make_shared<detail::range_stream<T*, T>>(ptr, ptr+1)};
+  }
+
+  template <typename It>
+  detail::stream_base<typename It::reference> make_stream(It begin, It end) {
+    return {std::make_shared<detail::range_stream<It>>(begin, end)};
+  }
 }

+ 71 - 5
streams/streams.hpp

@@ -15,10 +15,33 @@ super& operator++() override { ++impl; return *this; } \
 DELEGATE_ITERATOR_IMPL_BASE(impl)
 
 namespace stream {
+  namespace detail {
+    template <typename F> struct map_member_object;
+    template <typename T, typename R>
+    struct map_member_object<R T::*> {
+      using type = R const &;
+      type operator()(T const & val) const { return val.*mem; }
+      R T::*mem;
+    };
+    template <typename F> struct map_member_function;
+    template <typename T, typename R>
+    struct map_member_function<R (T::*)() const> {
+      using type = R;
+      type operator()(T const & val) const { return val.*mem(); }
+      R (T::* mem)() const;
+    };
+    
+    template <typename T, typename = void>
+    struct is_dereferencable : public std::false_type {};
+    
+    template <typename T>
+    struct is_dereferencable<T, typename std::enable_if<!std::is_void<decltype(*std::declval<T>())>::value>::type> : public std::true_type {};
+  }
+  
   template <typename T>
   class iterator {
   public:
-    using value_type = T;
+    using value_type = typename std::remove_reference<T>::type;
     using reference = value_type &;
     using pointer = value_type *;
     using difference_type = std::ptrdiff_t;
@@ -58,8 +81,23 @@ namespace stream {
       virtual ::stream::iterator<T> end() = 0;
     };
     
+    template <typename T, typename = void>
+    class stream_base_pointer_impl {};
+    
+    template <typename T>
+    class stream_base_pointer_impl<T, typename std::enable_if<detail::is_dereferencable<typename std::remove_reference<T>::type>::value>::type> {
+    private:
+      using self = stream_base<T>;
+      using noref = typename std::remove_reference<T>::type;
+      using element_type = typename std::pointer_traits<noref>::element_type;
+    public:
+      auto deref() const -> stream_base<element_type &> {
+        return static_cast<stream_base<T> const *>(this)->map([](T const & p) -> element_type & { return *p; });
+      }
+    };
+
     template <typename T>
-    class stream_base {
+    class stream_base : public stream_base_pointer_impl<T> {
     private:
       template <typename F>
       using map_f = decltype(std::declval<F>()(std::declval<T>()));
@@ -67,13 +105,17 @@ namespace stream {
       using flatmap_f = typename decltype(std::declval<F>()(std::declval<T>()))::value_type;
 
       using self = stream_base<T>;
+      using noref = typename std::remove_reference<T>::type;
+      using clean = typename std::decay<T>::type;
     public:
       stream_base(std::shared_ptr<stream_impl<T>> const & impl) : impl_(impl) {}
       ::stream::iterator<T> begin() const { return impl_->begin(); }
       ::stream::iterator<T> end  () const { return impl_->end  (); }
       
-      std::vector<T> collect() const {
-        std::vector<T> coll;
+      bool empty() const { return begin() == end(); }
+      
+      std::vector<clean> collect() const {
+        std::vector<clean> coll;
         collect(coll);
         return coll;
       }
@@ -85,13 +127,37 @@ namespace stream {
       }
       
       template <typename F>
-      T accumulate(F&& fold, T const& accum) {
+      clean accumulate(F&& fold, clean const& accum) {
         return std::accumulate(begin(), end(), accum, fold);
       }
       
+      clean accumulate(clean const& accum) {
+        return std::accumulate(begin(), end(), accum);
+      }
+      
+      template <typename F>
+      void each(F && consumer) {
+        std::for_each(begin(), end(), consumer);
+      }
+      
       template <typename F>
       stream_base<map_f<F>> map(F&& func) const;
+
+      template <typename F, typename = typename std::enable_if<std::is_member_object_pointer<F>::value>::type>
+      auto map(F && memvar) const -> stream_base<typename map_member_object<F>::type> {
+        return map(map_member_object<F>{memvar});
+      }
+
+      template <typename F, typename = typename std::enable_if<std::is_member_function_pointer<F>::value>::type>
+      auto map(F && memvar) const -> stream_base<typename map_member_function<F>::type> {
+        return map(map_member_function<F>{memvar});
+      }
       
+      template <typename Cast>
+      auto cast() const -> stream_base<Cast const &> {
+        return map([](T const & p) -> Cast const & { return p; });
+      }
+
       template <typename F>
       stream_base<T> filter(F&& func) const;