Browse Source

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	include/stream/streams/source.hpp
Sam Jaffe 3 years ago
parent
commit
01cf108ecb

+ 108 - 0
.clang-format

@@ -0,0 +1,108 @@
+---
+Language:        Cpp
+# BasedOnStyle:  LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Right
+AlignOperands:   true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: true
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:   
+  AfterClass:      false
+  AfterControlStatement: false
+  AfterEnum:       false
+  AfterFunction:   false
+  AfterNamespace:  false
+  AfterObjCDeclaration: false
+  AfterStruct:     false
+  AfterUnion:      false
+  BeforeCatch:     false
+  BeforeElse:      false
+  IndentBraces:    false
+  SplitEmptyFunction: true
+  SplitEmptyRecord: true
+  SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Attach
+BreakBeforeInheritanceComma: false
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeColon
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: true
+ColumnLimit:     80
+CommentPragmas:  '^ IWYU pragma:'
+CompactNamespaces: true
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat:   false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: false
+ForEachMacros:   
+  - foreach
+  - Q_FOREACH
+  - BOOST_FOREACH
+IncludeCategories: 
+  - Regex:           '^"(llvm|llvm-c|clang|clang-c)/'
+    Priority:        2
+  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
+    Priority:        3
+  - Regex:           '.*'
+    Priority:        1
+IncludeIsMainRegex: '(Test)?$'
+IndentCaseLabels: false
+IndentWidth:     2
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: All
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Middle
+ReflowComments:  true
+SortIncludes:    true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles:  false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard:        Cpp11
+TabWidth:        8
+UseTab:          Never
+...
+

+ 31 - 0
.gitignore

@@ -1 +1,32 @@
+# Prerequisites
 *.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app

+ 23 - 0
README.md

@@ -0,0 +1,23 @@
+# Stream
+A lazily evaluated container stream library build around the concept of Java's Stream library.
+
+## Constructs
+### Source Stream
+A series of factory methods that allow the construction of streams from various input objects, such as containers, iterator ranges, and integer ranges.
+
+### Filter Stream
+A stream that only returns the elements of its source that match the given predicate. The predicate is lazily evaluated, meaning that each call to advance the iterator may make multiple calls to advance the underlying value.
+
+### Map Stream
+Provides the ability to transform a stream from one type to another. Two different features are provided here: `map()` and `flatmap()`.  
+Map takes a function `T -> R` and performs the transformation `stream<T> -> stream<R>`.  
+Flatmap takes a function `T -> Container<R>` and performs the transformation `stream<T> -> stream<R>`.
+
+## Fluent Interface
+The fluent interface allows you to link together a stream with comprehensions using some simple
+primitives.
+
+- Map Function:  `stream | function` 
+- Flatmap Function: `stream || function`
+- Filter Stream: `stream % predicate`
+- Collect Stream: `stream > container`

+ 0 - 311
include/stream/stream.hpp

@@ -1,311 +0,0 @@
-/*
- * File stream.hpp
- * 
- * Stream style functional composition
- *
- * @author Sam Jaffe
- *
- */
-
-#pragma once
-
-#include <algorithm>
-#include <utility>
-#include <functional>
-#include <iterator>
-
-namespace stream {
-
-template <typename T> class stream {
-  public:
-    virtual ~stream() = default;
-    //template<template <class...> class C>
-    //C<T> complete() const; 
-};
-
-template <typename T, typename It>
-class iter_stream : public stream<T> {
-  public:
-    virtual ~iter_stream() = default;
-    template<template <class...> class C>
-    C<T> complete() const { 
-      C<T> out;
-      std::copy(begin(), end(), std::back_inserter(out));
-      return out;
-    }
-    typedef It const_iterator;
-    virtual const_iterator begin() const = 0;
-    virtual const_iterator end() const = 0;
-};
-
-template <typename T, template <class...> class C> 
-class cont_stream : public iter_stream<T, typename C<T>::const_iterator> {
-  public:
-    typedef typename C<T>::value_type value_type;
-    typedef iter_stream<T, typename C<T>::const_iterator> super;
-    typedef typename super::const_iterator const_iterator;
-  public:
-    cont_stream(const C<T>& data) : super(), data(&data), owning(false) {}
-    cont_stream(C<T>&& data) : super(), data(new C<T>(std::forward<C<T>>(data))), owning(true) {}
-    virtual ~cont_stream() { if (owning && data) delete data;}
-    virtual const_iterator begin() const { return data->begin(); }
-    virtual const_iterator end() const { return data->end(); }
-  private:
-    const bool owning;
-    const C<T>* data;
-};
-
-template <typename InStream, typename O, typename F>
-struct map_stream_iterator {
-  public:
-    typedef typename InStream::value_type value_type;
-    typedef value_type& reference;
-    typedef value_type* pointer;
-    typedef std::ptrdiff_t difference_type;
-    typedef std::input_iterator_tag iterator_category;
-    typedef typename InStream::const_iterator Impl;
-  public:
-    map_stream_iterator(Impl it, F func) : impl(it), f(func) {}
-
-    O operator*() const {
-      return f(*impl);
-    }
-
-    map_stream_iterator& operator++() {
-      ++impl;
-      return *this;
-    }
-
-    map_stream_iterator operator++(int) {
-      map_stream_iterator tmp(*this);
-      operator++();
-      return tmp;
-    }
-
-    bool operator==(const map_stream_iterator& other) const {
-      return impl == other.impl;
-    }
-
-    bool operator!=(const map_stream_iterator& other) const {
-      return impl != other.impl;
-    }
-
-  private:
-    F f;
-    Impl impl;
-};
-
-template <typename O, typename I, typename InStream> 
-class map_stream : public iter_stream<O, map_stream_iterator<InStream, O, std::function<O(I)> > > {
-  public:
-    typedef O value_type;
-    typedef iter_stream<O, map_stream_iterator<InStream, O, std::function<O(I)> > > super;
-    typedef typename super::const_iterator const_iterator;
-  public:
-    map_stream(const InStream& in, std::function<O(I)> func) : super(), in(in), f(func) {}
-    virtual ~map_stream() = default;
-    virtual const_iterator begin() const { return const_iterator(in.begin(), f); }
-    virtual const_iterator end() const { return const_iterator(in.end(), f); }
-  private:
-    const InStream in;
-    std::function<O(I)> f;
-};
-
-template <typename InStream>
-struct filter_stream_iterator {
-  public:
-    typedef typename InStream::value_type value_type;
-    typedef value_type& reference;
-    typedef value_type* pointer;
-    typedef std::ptrdiff_t difference_type;
-    typedef std::input_iterator_tag iterator_category;
-    typedef typename InStream::const_iterator Impl;
-  public:
-    filter_stream_iterator(Impl it, Impl end, std::function<bool(value_type)> predicate) : impl(it), end(end), pred(predicate) {}
-
-    value_type operator*() const {
-      return *impl;
-    }
-
-    filter_stream_iterator& operator++() {
-      do {
-        ++impl;
-      } while (impl != end && !pred(*impl));
-      return *this;
-    }
-
-    filter_stream_iterator operator++(int) {
-      filter_stream_iterator tmp(*this);
-      operator++();
-      return tmp;
-    }
-
-    bool operator==(const filter_stream_iterator& other) const {
-      return impl == other.impl;
-    }
-
-    bool operator!=(const filter_stream_iterator& other) const {
-      return impl != other.impl;
-    }
-
-  private:
-    std::function<bool(value_type)> pred;
-    Impl impl;
-    Impl end;
-};
-
-template <typename T, typename InStream> 
-class filter_stream : public iter_stream<T, filter_stream_iterator<InStream>> {
-  public:
-    typedef T value_type;
-    typedef iter_stream<T, filter_stream_iterator<InStream>> super;
-    typedef typename super::const_iterator const_iterator;
-  public:
-    filter_stream(const InStream& in, std::function<bool(T)> predicate) : super(), in(in), pred(predicate) {}
-    virtual ~filter_stream() = default;
-    virtual const_iterator begin() const { return const_iterator(in.begin(), in.end(), pred); }
-    virtual const_iterator end() const { return const_iterator(in.end(), in.end(), pred); }
-  private:
-    const InStream in;
-    std::function<bool(T)> pred;
-};
-
-template <typename Cons>
-struct cons_stream_iterator {
-  public:
-    typedef typename Cons::value_type InStream;
-    typedef typename InStream::value_type value_type;
-    typedef value_type& reference;
-    typedef value_type* pointer;
-    typedef std::ptrdiff_t difference_type;
-    typedef std::input_iterator_tag iterator_category;
-
-    typedef typename Cons::const_iterator ConsIter;
-    typedef typename InStream::const_iterator StreamIter;
-  public:
-    cons_stream_iterator(ConsIter iter) : citer(iter) {}
-    
-    cons_stream_iterator& operator++() {
-      if (scurr == send) {
-        ++citer;
-        scurr = citer->begin();
-        send = citer->end();
-      } else {
-        ++scurr;
-      }
-      return *this;
-    }
-
-    cons_stream_iterator operator++(int) {
-      cons_stream_iterator tmp(*this);
-      operator++();
-      return tmp;
-    }
-    
-    bool operator==(const cons_stream_iterator& other) const {
-      return citer == other.citer && scurr == other.scurr;
-    }
-
-    bool operator!=(const cons_stream_iterator& other) const {
-      return citer != other.citer || scurr != other.scurr;
-    }
-  private:
-    ConsIter citer;
-    StreamIter scurr;
-    StreamIter send;
-};
-
-template <typename T, typename InStream>
-class cons_stream : public iter_stream<T, cons_stream_iterator<std::vector<InStream>>> {
-  public:
-    typedef T value_type;
-    typedef iter_stream<T, cons_stream_iterator<std::list<InStream>>> super;
-    typedef typename super::const_iterator const_iterator;
-  public:
-    virtual ~cons_stream() = default;
-    virtual const_iterator begin() const { return const_iterator(in.begin()); }
-    virtual const_iterator end() const { return const_iterator(in.end()); }
-  private:
-    std::list<InStream> in;
-};
-
-template <typename GenIter, typename It>
-struct flatmap_stream_iterator {
-  public:
-    typedef typename GenIter::value_type MapStream;
-    typedef typename It::value_type value_type;
-    typedef value_type& reference;
-    typedef value_type* pointer;
-    typedef std::ptrdiff_t difference_type;
-    typedef std::input_iterator_tag iterator_category;
-  public:
-    flatmap_stream_iterator(GenIter gen) : generator(gen) {}
-    
-    value_type operator*() {
-      if (!mapped) {
-        mapped = new MapStream(std::forward<MapStream>(*generator));
-        curr = mapped->begin();
-        end = mapped->end();
-      }
-      return *curr;
-    }
-
-    flatmap_stream_iterator& operator++() {
-      ++curr;
-      if (curr == end) {
-        ++generator;
-        delete mapped;
-        mapped = nullptr;
-      }
-      return *this;
-    }
-
-    flatmap_stream_iterator operator++(int) {
-      flatmap_stream_iterator tmp(*this);
-      operator++();
-      return tmp;
-    }
-  private:
-    GenIter generator;
-    MapStream* mapped = nullptr;
-    It curr;
-    It end;
-};
-
-template <typename O, typename I, typename InStream, typename MapStream>
-class flatmap_stream : public iter_stream<O, flatmap_stream_iterator<typename InStream::const_iterator, typename MapStream::const_iterator>> {
-};
-
-template <typename T, template <class...> class C>
-cont_stream<T, C> make_stream(const C<T>& data) {
-  return cont_stream<T, C>(data);
-}
-
-template <typename F, typename InStream>
-auto map(const InStream& stream, F func) -> map_stream<decltype(func(std::declval<typename InStream::value_type>())), typename InStream::value_type, InStream>  {
-  using I = typename InStream::value_type;
-  using O = decltype(func(std::declval<I>()));
-  return map_stream<O, I, InStream>(stream, func);
-}
-
-template <typename P, typename InStream>
-auto filter(const InStream& stream, P predicate) -> filter_stream<typename InStream::value_type, InStream> {
-  using T = typename InStream::value_type;
-  return filter_stream<T, InStream>(stream, predicate);
-}
-
-template <typename P, typename F, typename InStream>
-auto map_if(const InStream& stream, P predicate, F func) -> decltype(map(std::declval<decltype(filter(stream, predicate))>(), func)) {
-  return map(filter(stream, predicate), func);
-}
-
-//void flatMap(const InStream& stream, F func)
-
-template <typename F, typename InStream, typename Arg1>
-auto reduce(const InStream& stream, F func, Arg1 accum) -> Arg1 {
-  std::for_each(stream.begin(), stream.end(), [&accum, func](typename InStream::value_type i) { accum = func(accum, i); });
-  return accum;
-}
-
-}
-

+ 2 - 1
include/stream/streams.hpp

@@ -2,10 +2,11 @@
 
 #include "streams/forward.hpp"
 
+#include "streams/make_stream.hpp"
 #include "streams/streams.hpp"
 
 #include "streams/source.hpp"
 
-#include "streams/map.hpp"
 #include "streams/filter.hpp"
 #include "streams/join.hpp"
+#include "streams/map.hpp"

+ 48 - 0
include/stream/streams/detail/ifd_pointer.hpp

@@ -0,0 +1,48 @@
+#pragma once
+
+namespace stream { namespace detail {
+  class ifd_pointer {
+  private:
+    void * (*copy)(void *){nullptr};
+    void (*destroy)(void *){nullptr};
+    void * ptr{nullptr};
+
+  public:
+    template <typename T>
+    ifd_pointer(T && value)
+        : copy(&ifd_pointer::copy_<T>), destroy(&ifd_pointer::destroy_<T>),
+          ptr(copy(&value)) {}
+
+    ifd_pointer() = default;
+    ifd_pointer(ifd_pointer const & other)
+        : copy(other.copy), destroy(other.destroy), ptr(copy(other.ptr)) {}
+    ifd_pointer(ifd_pointer && other) {
+      *this = std::forward<ifd_pointer>(other);
+    }
+    ifd_pointer & operator=(ifd_pointer const & other) {
+      return *this = ifd_pointer(other);
+    }
+    ~ifd_pointer() {
+      if (destroy) destroy(ptr);
+    }
+
+    ifd_pointer & operator=(ifd_pointer && other) {
+      swap(*this, other);
+      return *this;
+    }
+
+    void * get() const { return ptr; }
+
+  private:
+    friend void swap(ifd_pointer & lhs, ifd_pointer & rhs) {
+      using ::std::swap;
+      swap(lhs.copy, rhs.copy);
+      swap(lhs.destroy, rhs.destroy);
+      swap(lhs.ptr, rhs.ptr);
+    }
+    template <typename T> static void * copy_(void * p) {
+      return (void *)new T(*(T *)(p));
+    }
+    template <typename T> static void destroy_(void * p) { delete (T *)(p); }
+  };
+}}

+ 59 - 0
include/stream/streams/detail/self_iterating_container.hpp

@@ -0,0 +1,59 @@
+#pragma once
+
+namespace stream { namespace detail {
+  template <typename C, typename It = typename C::const_iterator>
+  class self_iterating_container {
+  private:
+    std::ptrdiff_t offset{0};
+    C container;
+    It current;
+    It end;
+
+  public:
+    self_iterating_container() = default;
+    self_iterating_container(C const & container)
+        : container(container), current(container.cbegin()),
+          end(container.cend()) {}
+
+    self_iterating_container(C && container)
+        : container(std::move(container)), current(container.cbegin()),
+          end(container.cend()) {}
+
+    self_iterating_container(self_iterating_container const & other) {
+      *this = other;
+    }
+
+    self_iterating_container(self_iterating_container && other) {
+      *this = std::move(other);
+    }
+
+    self_iterating_container &
+    operator=(self_iterating_container const & other) {
+      offset = other.offset;
+      container = other.container;
+      setup();
+      return *this;
+    }
+
+    self_iterating_container & operator=(self_iterating_container && other) {
+      offset = other.offset;
+      container = std::move(other.container);
+      setup();
+      return *this;
+    }
+
+    void operator++() {
+      ++offset;
+      ++current;
+    }
+    auto & operator*() const { return *current; }
+    operator bool() const { return current != end; }
+
+  private:
+    void setup() {
+      current = container.cbegin();
+      end = container.cend();
+      std::advance(current, offset);
+    }
+  };
+}}

+ 44 - 43
include/stream/streams/filter.hpp

@@ -1,66 +1,67 @@
 #pragma once
 
 namespace stream { namespace detail {
-  namespace filter {
-    template <typename T>
-    class iterator {
-    public:
-      iterator(std::function<bool(T const&)> f, ::stream::iterator<T>&& impl, ::stream::iterator<T>&& end)
-      : pred_(f)
-      , impl_(std::forward<::stream::iterator<T>>(impl))
-      , end_(std::forward<::stream::iterator<T>>(end)) {
-        advance();
-      }
+  template <typename T> class filter_iterator {
+  public:
+    filter_iterator(std::function<bool(T const &)> f, iterator<T> && impl,
+                    iterator<T> && end)
+        : pred_(f), impl_(std::forward<iterator<T>>(impl)),
+          end_(std::forward<iterator<T>>(end)) {
+      advance();
+    }
+
+    T operator*() { return mem_; }
+
+    filter_iterator & operator++() {
+      ++impl_;
+      advance();
+      return *this;
+    }
 
-      T operator*() { return mem_; }
-      
-      iterator& operator++() {
+    bool operator==(filter_iterator const & rhs) const {
+      return impl_ == rhs.impl_;
+    }
+
+  private:
+    void advance() {
+      while (impl_ != end_ && !pred_(mem_ = *impl_)) {
         ++impl_;
-        advance();
-        return *this;
       }
-      
-      DELEGATE_ITERATOR_IMPL_BASE(impl_)
-    private:
-      void advance() {
-        while (impl_ != end_ && !pred_(mem_ = *impl_)) {
-          ++impl_;
-        }
-      }
-      
-      std::function<bool(T const&)> pred_;
-      ref_or_val<T> mem_; // To avoid re-calcs, we store this
-      ::stream::iterator<T> impl_, end_;
-    };
-  }
-  
-  template <typename T>
-  class filter_stream {
+    }
+
+    std::function<bool(T const &)> pred_;
+    ref_or_val<T> mem_; // To avoid re-calcs, we store this
+    iterator<T> impl_, end_;
+  };
+
+  template <typename T> class filter_stream {
   public:
     template <typename F>
-    filter_stream(F&& func, stream_base<T> const& sb) : pred_(func), source_(sb) {}
-    
+    filter_stream(F && func, stream_base<T> const & sb)
+        : pred_(func), source_(sb) {}
+
     iterator<T> begin() {
-      return {filter::iterator<T>{pred_, source_.begin(), source_.end()}};
+      return {filter_iterator<T>{pred_, source_.begin(), source_.end()}};
     }
-    
+
     iterator<T> end() {
-      return {filter::iterator<T>{pred_, source_.end(), source_.end()}};
+      return {filter_iterator<T>{pred_, source_.end(), source_.end()}};
     }
+
   private:
-    std::function<bool(T const&)> pred_;
+    std::function<bool(T const &)> pred_;
     stream_base<T> source_;
   };
-  
+
   template <typename T>
   template <typename F>
-  auto stream_base<T>::filter(F&& pred) && -> stream_base<T>  {
+  auto stream_base<T>::filter(F && pred) && -> stream_base<T> {
     return std::make_shared<filter_stream<T>>(pred, std::move(*this));
   }
-  
+
   template <typename T>
   template <typename F>
-  auto stream_base<T>::filter(F&& pred) const & -> stream_base<T>  {
+  auto stream_base<T>::filter(F && pred) const & -> stream_base<T> {
     return std::make_shared<filter_stream<T>>(pred, *this);
   }
-} }
+}}

+ 32 - 24
include/stream/streams/fluent.hpp

@@ -11,50 +11,58 @@
 
 namespace stream { namespace traits {
   template <typename T, typename P>
-  using is_filter = std::is_same<bool, decltype(std::declval<P>()(std::declval<T>()))>;
-  
+  using is_filter =
+      std::is_same<bool, decltype(std::declval<P>()(std::declval<T>()))>;
+
   template <typename C, typename T, typename = void>
   struct is_collection : public std::false_type {};
-  
+
   template <typename C, typename T>
-  struct is_collection<C, T, typename std::enable_if<std::is_constructible<typename C::value_type, T>::value>::type> : public std::true_type {};
-} }
+  struct is_collection<C, T,
+                       typename std::enable_if<std::is_constructible<
+                           typename C::value_type, T>::value>::type>
+      : public std::true_type {};
+}}
 
 namespace stream { namespace detail {
   template <typename T, typename F>
-  auto operator||(stream_base<T> const&s, F && f) -> decltype(s.flatmap(f)) {
+  auto operator||(stream_base<T> const & s, F && f) -> decltype(s.flatmap(f)) {
     return s.flatmap(f);
   }
-  
-  template <typename T, typename F, typename = typename std::enable_if<!traits::is_filter<T, F>::value>::type>
-  auto operator|(stream_base<T> const&s, F && f) -> decltype(s.map(f)) {
+
+  template <typename T, typename F>
+  auto operator|(stream_base<T> const & s, F && f) -> decltype(s.map(f)) {
     return s.map(f);
   }
-  
-  template <typename T, typename P, typename = typename std::enable_if<traits::is_filter<T, P>::value>::type>
-  stream_base<T> operator|(stream_base<T> const&s, P && f) {
+
+  template <
+      typename T, typename P,
+      typename = typename std::enable_if<traits::is_filter<T, P>::value>::type>
+  stream_base<T> operator%(stream_base<T> const & s, P && f) {
     return s.filter(f);
   }
-  
-  template <typename R>
-  R operator >(stream_base<R> const &s, R const & val) {
+
+  template <typename R> R operator>(stream_base<R> const & s, R const & val) {
     return s.accumulate(val);
   }
 
   template <typename L, typename R, typename F>
-  L operator >(stream_base<R> const &s, std::pair<L, F> const & pair) {
+  L operator>(stream_base<R> const & s, std::pair<L, F> const & pair) {
     return s.accumulate(pair.second, pair.first);
   }
-  
-  template <typename T, typename F, typename = typename std::enable_if<!traits::is_collection<F, T>::value>::type>
-  typename std::decay<T>::type operator >(stream_base<T> const &s, F && f) {
+
+  template <typename T, typename F,
+            typename = typename std::enable_if<
+                !traits::is_collection<F, T>::value>::type>
+  typename std::decay<T>::type operator>(stream_base<T> const & s, F && f) {
     return s.accumulate(f, typename std::decay<T>::type());
   }
-  
-  template <typename T, typename C, typename = typename std::enable_if<traits::is_collection<C, T>::value>::type>
-  C & operator >(stream_base<T> const & s, C & c) {
+
+  template <typename T, typename C,
+            typename = typename std::enable_if<
+                traits::is_collection<C, T>::value>::type>
+  C & operator>(stream_base<T> const & s, C & c) {
     s.collect(c);
     return c;
   }
-} }
-
+}}

+ 4 - 6
include/stream/streams/forward.hpp

@@ -2,12 +2,10 @@
 
 #include "traits.hpp"
 
-namespace stream {
-  namespace detail {
-    template <typename> class stream_base;
-    template <typename> class iterator_impl;
-  }
-}
+namespace stream { namespace detail {
+  template <typename> class stream_base;
+  template <typename> class iterator_impl;
+}}
 
 namespace stream {
   template <typename> class iterator;

+ 51 - 76
include/stream/streams/join.hpp

@@ -2,102 +2,77 @@
 
 #include <iterator>
 
+#include "detail/self_iterating_container.hpp"
+
 namespace stream { namespace detail {
-#define JOIN_CTOR( mod ) \
-  start_ = mod(other.start_); \
-  finish_ = mod(other.finish_); \
-  std::ptrdiff_t n = std::distance(other.mem_.cbegin(), other.curr_); \
-  mem_ = mod(other.mem_); \
-  curr_ = mem_.begin(); \
-  std::advance(curr_, n); \
-  end_ = mem_.end();
+  template <typename C> class join_iterator {
+  public:
+    using reference = typename C::const_iterator::reference;
 
-  namespace join {
-    template <typename C>
-    class iterator {
-    private:
-      using impl_t = ::stream::iterator<C>;
-      using local_iterator = typename C::const_iterator;
-    public:
-      using reference = typename local_iterator::reference;
-    public:
-      iterator(impl_t && f, impl_t && l)
-      : start_(std::move(f)), finish_(std::move(l)) {
-        if (start_ != finish_) {
-          mem_ = *(start_);
-          curr_ = mem_.begin();
-          end_ = mem_.end();
-          advance();
-        }
-      }
-      
-      iterator(iterator const & other) { JOIN_CTOR( ) }
-      iterator(iterator && other) { JOIN_CTOR( std::move ) }
-      
-      iterator & operator=(iterator const & other) {
-        JOIN_CTOR( )
-        return *this;
-      }
-      
-      iterator & operator=(iterator && other) {
-        JOIN_CTOR( std::move )
-        return *this;
-      }
-      
-      reference operator*() { return *curr_; }
-      
-      iterator& operator++() {
-        ++curr_;
+  public:
+    join_iterator(iterator<C> && f, iterator<C> && l)
+        : start_(std::move(f)), finish_(std::move(l)) {
+      if (start_ != finish_) {
+        current_ = *start_;
         advance();
-        return *this;
       }
-      
-      DELEGATE_ITERATOR_IMPL_BASE(start_)
-    private:
-      void advance() {
-        while (curr_ == end_ && start_ != finish_) {
-          if ( ++start_ == finish_ ) { break; }
-          mem_ = *start_;
-          curr_ = mem_.begin();
-          end_ = mem_.end();
-        }
+    }
+
+    reference operator*() { return *current_; }
+
+    join_iterator & operator++() {
+      ++current_;
+      advance();
+      return *this;
+    }
+
+    bool operator==(join_iterator const & rhs) const {
+      return start_ == rhs.start_;
+    }
+
+  private:
+    void advance() {
+      while (!current_ && start_ != finish_) {
+        if (++start_ == finish_) { break; }
+        current_ = *start_;
       }
-      impl_t start_, finish_;
-      C mem_;
-      local_iterator curr_, end_;
-    };
-  }
-  
-  template <typename C>
-  class join_stream {
+    }
+    iterator<C> start_;
+    iterator<C> finish_;
+    self_iterating_container<C> current_;
+  };
+
+  template <typename C> class join_stream {
   public:
     using T = typename C::value_type;
-    explicit join_stream(stream_base<C> const& sb) : source_(sb) {}
-    
-    ::stream::iterator<T> begin() {
-      return {join::iterator<C>{source_.begin(), source_.end()}};
+    explicit join_stream(stream_base<C> const & sb) : source_(sb) {}
+
+    iterator<T> begin() {
+      return {join_iterator<C>{source_.begin(), source_.end()}};
     }
-    ::stream::iterator<T> end() {
-      return {join::iterator<C>{source_.end(), source_.end()}};
+    iterator<T> end() {
+      return {join_iterator<C>{source_.end(), source_.end()}};
     }
+
   private:
     stream_base<C> source_;
   };
-  
+
   template <typename C>
-  stream_base<typename C::value_type> make_join(stream_base<C> const& sb) {
+  stream_base<typename C::value_type> make_join(stream_base<C> const & sb) {
     return std::make_shared<join_stream<C>>(sb);
   }
-  
+
   template <typename T>
   template <typename F>
-  stream_base<traits::fmapped_t<T, F>> stream_base<T>::flatmap(F&& func) && {
+  stream_base<traits::fmapped_t<T, F>> stream_base<T>::flatmap(F && func) && {
     return make_join(std::move(*this).map(func));
   }
-  
+
   template <typename T>
   template <typename F>
-  stream_base<traits::fmapped_t<T, F>> stream_base<T>::flatmap(F&& func) const & {
+  stream_base<traits::fmapped_t<T, F>>
+  stream_base<T>::flatmap(F && func) const & {
     return make_join(map(func));
   }
-} }
+}}

+ 68 - 0
include/stream/streams/make_stream.hpp

@@ -0,0 +1,68 @@
+#pragma once
+
+#include "source.hpp"
+
+namespace stream {
+  /**
+   * Construct a stream out of the given container. If C && is an rvalue
+   * reference, the returned object will take ownership of cont. Otherwise, we
+   * capture cont by reference to maximise performance.
+   */
+  template <typename C>
+  auto make_stream(C && cont) -> detail::stream_base<decltype(*cont.begin())> {
+    return std::make_shared<detail::source_stream<C>>(std::forward<C>(cont));
+  }
+
+  template <typename T>
+  detail::stream_base<T&> make_empty_stream() {
+    return std::make_shared<detail::range_stream<T*, T&>>(nullptr, nullptr);
+  }
+
+  /**
+   * Construct a single element stream containing the pointer given
+   */
+  template <typename T> detail::stream_base<T &> make_stream(T * ptr) {
+    return std::make_shared<detail::range_stream<T *, T &>>(ptr, ptr + 1);
+  }
+
+  /**
+   * Construct a stream from input iterators representing the start and end
+   * Requirements: It must be an iterator type that provides the trait
+   * 'reference'
+   */
+  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);
+  }
+
+  /**
+   * Construct a stream given certain start and end bounds.
+   * e.g. stream::make_range_stream(0, 10)
+   */
+  template <typename T>
+  detail::stream_base<T &> make_range_stream(T start, T const & end) {
+    std::vector<T> vec;
+    vec.reserve(end - start);
+    while (start < end) {
+      vec.emplace_back(start++);
+    }
+    return make_stream(std::move(vec));
+  }
+
+  /**
+   * Construct a stream given certain start and end bounds, as well as an
+   * increment amount. e.g. stream::make_range_stream(0, 10, 2)
+   */
+  template <typename T>
+  detail::stream_base<T &> make_range_stream(T start, T const & end,
+                                             T const & increment) {
+    int elems{(end - start) / increment};
+    if (elems < 0 || end == start) { return {}; }
+    std::vector<T> vec{start};
+    vec.reserve(elems + 1);
+    while (elems-- > 0) {
+      vec.emplace_back(start += increment);
+    }
+    return make_stream(std::move(vec));
+  }
+}

+ 34 - 32
include/stream/streams/map.hpp

@@ -1,48 +1,50 @@
 #pragma once
 
 namespace stream { namespace detail {
-  namespace map {
-    template <typename T, typename R>
-    class iterator {
-    public:
-      iterator(std::function<R(T const&)> f, ::stream::iterator<T>&& impl)
-      : fun_(f), impl_(std::forward<::stream::iterator<T>>(impl)) {}
-
-      R operator*() { return fun_(*impl_); }
-      DELEGATE_ITERATOR_IMPL(impl_)
-    private:
-      std::function<R(T const&)> fun_;
-      ::stream::iterator<T> impl_;
-    };
-  }
-  
-  template <typename T, typename R>
-  class map_stream {
+  template <typename T, typename R> class map_iterator {
   public:
-    template <typename F>
-    map_stream(F&& func, stream_base<T> const& sb) : fun_(func), source_(sb) {}
-    
-    iterator<R> begin() {
-      return {map::iterator<T, R>{fun_, source_.begin()}};
+    map_iterator(std::function<R(T const &)> f, iterator<T> && impl)
+        : fun_(f), impl_(std::forward<iterator<T>>(impl)) {}
+
+    R operator*() { return fun_(*impl_); }
+    map_iterator & operator++() {
+      ++impl_;
+      return *this;
     }
-    
-    iterator<R> end() {
-      return {map::iterator<T, R>{fun_, source_.end()}};
+    bool operator==(map_iterator const & rhs) const {
+      return impl_ == rhs.impl_;
     }
+
+  private:
+    std::function<R(T const &)> fun_;
+    iterator<T> impl_;
+  };
+
+  template <typename T, typename R> class map_stream {
+  public:
+    template <typename F>
+    map_stream(F && func, stream_base<T> const & sb)
+        : fun_(func), source_(sb) {}
+
+    iterator<R> begin() { return {map_iterator<T, R>{fun_, source_.begin()}}; }
+
+    iterator<R> end() { return {map_iterator<T, R>{fun_, source_.end()}}; }
+
   private:
-    std::function<R(T const&)> fun_;
+    std::function<R(T const &)> fun_;
     stream_base<T> source_;
   };
-  
+
   template <typename T>
   template <typename F>
-  stream_base<traits::mapped_t<T, F>> stream_base<T>::map(F&& func) && {
-    return std::make_shared<map_stream<T, traits::mapped_t<T, F>>>(func, std::move(*this));
+  stream_base<traits::mapped_t<T, F>> stream_base<T>::map(F && func) && {
+    return std::make_shared<map_stream<T, traits::mapped_t<T, F>>>(
+        func, std::move(*this));
   }
-  
+
   template <typename T>
   template <typename F>
-  stream_base<traits::mapped_t<T, F>> stream_base<T>::map(F&& func) const & {
+  stream_base<traits::mapped_t<T, F>> stream_base<T>::map(F && func) const & {
     return std::make_shared<map_stream<T, traits::mapped_t<T, F>>>(func, *this);
   }
-} }
+}}

+ 44 - 78
include/stream/streams/source.hpp

@@ -1,87 +1,53 @@
 #pragma once
 
-namespace stream {
-  namespace detail {
-    namespace source {
-      template <typename Iter>
-      class iterator {
-      public:
-        using value_type = typename std::iterator_traits<Iter>::reference;
-        explicit iterator(Iter it) : impl_(it) {}
+namespace stream { namespace detail {
+  template <typename Iter> class source_iterator {
+  public:
+    using value_type = typename std::iterator_traits<Iter>::reference;
+    explicit source_iterator(Iter it) : impl_(it) {}
 
-        value_type operator*() { return *impl_; }
-        DELEGATE_ITERATOR_IMPL(impl_)
-      private:
-        Iter impl_;
-      };
-      
-      template <typename C>
-      using reference = decltype(*std::declval<C>().begin());
+    value_type operator*() { return *impl_; }
+    source_iterator & operator++() {
+      ++impl_;
+      return *this;
+    }
+    bool operator==(source_iterator const & rhs) const {
+      return impl_ == rhs.impl_;
+    }
+
+  private:
+    Iter impl_;
+  };
+
+  template <typename C> class source_stream {
+  public:
+    typedef decltype(std::declval<C>().begin()) _iterator;
+    typedef decltype(*std::declval<_iterator>()) reference;
+
+    explicit source_stream(C && cont) : source_(std::forward<C>(cont)) {}
+
+    iterator<reference> begin() {
+      return {source_iterator<_iterator>{source_.begin()}};
+    }
+    iterator<reference> end() {
+      return {source_iterator<_iterator>{source_.end()}};
     }
-    
-    template <typename C>
-    class source_stream {
-    public:
-      typedef source::reference<C> reference;
-      typedef decltype(std::declval<C>().begin()) _iterator;
-      
-      explicit source_stream(C && cont) : source_(std::forward<C>(cont)) {}
 
-      iterator<reference> begin() { return {source::iterator<_iterator>{source_.begin()}}; }
-      iterator<reference> end() { return {source::iterator<_iterator>{source_.end()}}; }
-    private:
-      C source_;
-    };
-    
-    template <typename It, typename V = typename It::value_type>
-    class range_stream {
-    public:
-      typedef V & reference;
-      
-      explicit range_stream(It b, It e) : begin_(b), end_(e) {}
+  private:
+    C source_;
+  };
 
-      iterator<reference> begin() { return {source::iterator<It>{begin_}}; }
-      iterator<reference> end() { return {source::iterator<It>{end_}}; }
-    private:
-      It begin_, end_;
-    };
-  }
-  
-  template <typename C>
-  detail::stream_base<detail::source::reference<C>> make_stream(C && cont) {
-    return std::make_shared<detail::source_stream<C>>(std::forward<C>(cont));
-  }
+  template <typename It, typename V = typename It::value_type>
+  class range_stream {
+  public:
+    typedef typename It::reference reference;
 
-  template <typename T>
-  detail::stream_base<T&> make_empty_stream() {
-    return std::make_shared<detail::range_stream<T*, T&>>(nullptr, nullptr);
-  }
+    explicit range_stream(It b, It e) : begin_(b), end_(e) {}
 
-  template <typename T>
-  detail::stream_base<T&> make_stream(T * ptr) {
-    return std::make_shared<detail::range_stream<T*, T&>>(ptr, ptr+1);
-  }
+    iterator<reference> begin() { return {source_iterator<It>{begin_}}; }
+    iterator<reference> end() { return {source_iterator<It>{end_}}; }
 
-  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);
-  }
-  
-  template <typename T>
-  detail::stream_base<T&> make_range_stream(T start, T const & end) {
-    std::vector<T> vec;
-    vec.reserve(end - start);
-    while (start < end) { vec.emplace_back(start++); }
-    return make_stream(std::move(vec));
-  }
-  
-  template <typename T>
-  detail::stream_base<T&> make_range_stream(T start, T const & end, T const & increment) {
-    int elems{(end - start)/increment};
-    if (elems < 0 || end == start) { return {}; }
-    std::vector<T> vec{start};
-    vec.reserve(elems+1);
-    while (elems-- > 0) { vec.emplace_back(start += increment); }
-    return make_stream(std::move(vec));
-  }
-}
+  private:
+    It begin_, end_;
+  };
+}}

+ 84 - 105
include/stream/streams/streams.hpp

@@ -5,188 +5,166 @@
 #include <numeric>
 #include <vector>
 
-#define DELEGATE_ITERATOR_IMPL_BASE(impl) \
-  bool operator==(iterator const&other) const { \
-    return impl == other.impl; \
-  }
-
-#define DELEGATE_ITERATOR_IMPL(impl) \
-  DELEGATE_ITERATOR_IMPL_BASE(impl) \
-  iterator& operator++() { \
-    ++impl; \
-    return *this; \
-  }
+#include "detail/ifd_pointer.hpp"
 
 namespace stream {
-#define STREAM_ITERATOR_COPY() \
-  copy(other.copy), dereference(other.dereference), compare(other.compare), destroy(other.destroy), advance(other.advance), type_(other.type_)
-  
-  template <typename T>
-  class iterator {
+  template <typename T> class iterator {
   public:
     using value_type = typename std::remove_reference<T>::type;
     using reference = value_type &;
     using pointer = value_type *;
     using difference_type = std::ptrdiff_t;
     using iterator_category = std::forward_iterator_tag;
+
+  private:
+    T (*dereference)(void *){nullptr};
+    bool (*compare)(void *, void *){nullptr};
+    void (*advance)(void *){nullptr};
+    char const * type_{nullptr};
+    detail::ifd_pointer impl_{};
+
   public:
     iterator() = default;
-    
+
     template <typename Iter>
-    iterator(Iter impl) {
-      copy = [](void * p) { return (void*) new Iter(*(Iter*)(p)); };
-      dereference = [](void * p) -> T { return **((Iter*)p); };
-      compare = [](void * l, void * r) { return *((Iter*)l) == *((Iter*)r); };
-      destroy = [](void * p) { delete (Iter*)(p); };
-      advance = [](void * p) { ++(*(Iter*)(p)); };
-      type_ = typeid(Iter).name();
-      impl_ = copy(&impl);
-    }
-    
-    iterator(iterator const& other)
-    : STREAM_ITERATOR_COPY()
-    , impl_(copy(other.impl_)) {
-    }
-    
-    iterator(iterator && other)
-    : STREAM_ITERATOR_COPY()
-    , impl_(other.impl_) {
-      other.impl_ = nullptr;
-    }
-    
-    iterator & operator=(iterator const & other) {
-      return *this = iterator{other};
-    }
+    iterator(Iter impl)
+        : dereference(&iterator::dereference_<Iter>),
+          compare(&iterator::compare_<Iter>),
+          advance(&iterator::advance_<Iter>), type_(typeid(Iter).name()),
+          impl_(std::forward<Iter>(impl)) {}
 
-    iterator & operator=(iterator && other) {
-      swap(*this, other);
+    T operator*() const { return dereference(impl_.get()); }
+    iterator & operator++() {
+      advance(impl_.get());
       return *this;
     }
 
-    ~iterator() { if (destroy) destroy(impl_); }
-    
-    T operator*() const { return dereference(impl_); }
-    iterator& operator++() { advance(impl_); return *this; }
-    bool operator==(iterator const&other) const {
+    bool operator==(iterator const & other) const {
       if (strcmp(type_, other.type_)) { return false; }
-      return compare(impl_, other.impl_);
+      return compare(impl_.get(), other.impl_.get());
     }
-    bool operator!=(iterator const&other) const {
+
+    bool operator!=(iterator const & other) const {
       if (strcmp(type_, other.type_)) { return false; }
-      return !compare(impl_, other.impl_);
+      return !compare(impl_.get(), other.impl_.get());
     }
+
   private:
     friend void swap(iterator & lhs, iterator & rhs) {
       using std::swap;
-      swap(lhs.copy, rhs.copy);
       swap(lhs.dereference, rhs.dereference);
       swap(lhs.compare, rhs.compare);
-      swap(lhs.destroy, rhs.destroy);
       swap(lhs.advance, rhs.advance);
       swap(lhs.type_, rhs.type_);
       swap(lhs.impl_, rhs.impl_);
     }
-    using delegate = void(*)(void*);
-    void* (*copy)(void*){nullptr};
-    T (*dereference)(void*){nullptr};
-    bool (*compare)(void*, void*){nullptr};
-    delegate destroy{nullptr}, advance{nullptr};
-    char const * type_{nullptr};
-    void * impl_{nullptr};
+
+    template <typename It> static T dereference_(void * p) {
+      return **((It *)p);
+    }
+    template <typename It> static bool compare_(void * l, void * r) {
+      return *((It *)l) == *((It *)r);
+    }
+    template <typename It> static void advance_(void * p) { ++(*(It *)(p)); }
   };
-  
+
   namespace detail {
-    template <typename T, typename = void>
-    class stream_base_pointer_impl {};
-    
+    template <typename T, typename = void> class stream_base_pointer_impl {};
+
     template <typename T>
-    class stream_base_pointer_impl<T, typename std::enable_if<traits::is_dereferencable<T>::value>::type> {
+    class stream_base_pointer_impl<
+        T, typename std::enable_if<traits::is_dereferencable<T>::value>::type> {
     private:
       using self_t = stream_base<T>;
       using pointer = typename std::remove_reference<T>::type;
       using element_type = typename std::pointer_traits<pointer>::element_type;
+
     public:
       auto deref() const & -> stream_base<element_type &> {
-        return static_cast<self_t const *>(this)->map([](T const & p) -> element_type & { return *p; });
+        return static_cast<self_t const *>(this)->map(
+            [](T const & p) -> element_type & { return *p; });
       }
-      
+
       auto deref() && -> stream_base<element_type &> {
-        return static_cast<self_t &&>(*this).map([](T const & p) -> element_type & { return *p; });
+        return static_cast<self_t &&>(*this).map(
+            [](T const & p) -> element_type & { return *p; });
       }
     };
-    
+
     template <typename T>
     class stream_base : public stream_base_pointer_impl<T> {
     private:
       using value_type = typename std::decay<T>::type;
+
     public:
-      template <typename Stream>
-      stream_base(std::shared_ptr<Stream> && impl) {
-        do_begin = [](std::shared_ptr<void> p) -> iterator<T> { return std::static_pointer_cast<Stream>(p)->begin(); };
-        do_end = [](std::shared_ptr<void> p) -> iterator<T> { return std::static_pointer_cast<Stream>(p)->end(); };
+      template <typename Stream> stream_base(std::shared_ptr<Stream> && impl) {
+        do_begin = [](std::shared_ptr<void> p) -> iterator<T> {
+          return std::static_pointer_cast<Stream>(p)->begin();
+        };
+        do_end = [](std::shared_ptr<void> p) -> iterator<T> {
+          return std::static_pointer_cast<Stream>(p)->end();
+        };
         impl_ = std::static_pointer_cast<void>(impl);
       }
-      
+
       ::stream::iterator<T> begin() const { return do_begin(impl_); }
-      ::stream::iterator<T> end  () const { return do_end  (impl_); }
-      
+      ::stream::iterator<T> end() const { return do_end(impl_); }
+
       bool empty() const { return begin() == end(); }
-      
+
       std::vector<value_type> collect() const {
         std::vector<value_type> coll;
         collect(coll);
         return coll;
       }
-      
-      template <typename C, typename = typename std::enable_if<!std::is_void<typename C::value_type>::value, void>::type>
+
+      template <typename C,
+                typename = typename std::enable_if<
+                    !std::is_void<typename C::value_type>::value, void>::type>
       C & collect(C & coll) const {
         std::copy(begin(), end(), std::inserter(coll, coll.end()));
         return coll;
       }
-      
+
       template <typename F>
-      value_type accumulate(F&& fold, value_type const& accum) const {
+      value_type accumulate(F && fold, value_type const & accum) const {
         return std::accumulate(begin(), end(), accum, fold);
       }
-      
-      value_type accumulate(value_type const& accum) const {
+
+      value_type accumulate(value_type const & accum) const {
         return std::accumulate(begin(), end(), accum);
       }
-      
-      template <typename F>
-      void each(F && consumer) const {
+
+      template <typename F> void each(F && consumer) const {
         std::for_each(begin(), end(), consumer);
       }
-      
-      template <typename F>
-      stream_base<traits::mapped_t<T, F>> map(F&& func) const &;
-      template <typename F>
-      stream_base<T> filter(F&& func) const &;
+
       template <typename F>
-      stream_base<traits::fmapped_t<T, F>> flatmap(F&& func) const &;
-      
+      stream_base<traits::mapped_t<T, F>> map(F && func) const &;
+      template <typename F> stream_base<T> filter(F && func) const &;
       template <typename F>
-      stream_base<traits::mapped_t<T, F>> map(F&& func) &&;
+      stream_base<traits::fmapped_t<T, F>> flatmap(F && func) const &;
+
       template <typename F>
-      stream_base<T> filter(F&& func) &&;
+      stream_base<traits::mapped_t<T, F>> map(F && func) &&;
+      template <typename F> stream_base<T> filter(F && func) &&;
       template <typename F>
-      stream_base<traits::fmapped_t<T, F>> flatmap(F&& func) &&;
-      
-      template <typename Cast>
-      stream_base<Cast const &> cast() const & {
+      stream_base<traits::fmapped_t<T, F>> flatmap(F && func) &&;
+
+      template <typename Cast> stream_base<Cast const &> cast() const & {
         return map([](T const & p) -> Cast const & { return p; });
       }
-      
-      template <typename Cast>
-      stream_base<Cast const &> cast() && {
-        return std::move(*this).map([](T const & p) -> Cast const & { return p; });
+
+      template <typename Cast> stream_base<Cast const &> cast() && {
+        return std::move(*this).map(
+            [](T const & p) -> Cast const & { return p; });
       }
-      
+
       template <typename F, typename = traits::is_memvar_t<F>>
       stream_base<traits::memvar_f<F>> map(F && memvar) const & {
         return map(map_member_object<F>{memvar});
       }
-      
+
       template <typename F, typename = traits::is_memfun_t<F>>
       stream_base<traits::memfun_f<F>> map(F && memvar) const & {
         return map(map_member_function<F>{memvar});
@@ -201,6 +179,7 @@ namespace stream {
       stream_base<traits::memfun_f<F>> map(F && memvar) && {
         return std::move(*this).map(map_member_function<F>{memvar});
       }
+
     private:
       iterator<T> (*do_begin)(std::shared_ptr<void>){nullptr};
       iterator<T> (*do_end)(std::shared_ptr<void>){nullptr};

+ 29 - 22
include/stream/streams/traits.hpp

@@ -10,60 +10,67 @@
 #include <utility>
 
 namespace stream { namespace detail {
-  template <typename T>
-  struct ref_or_val {
-    ref_or_val operator=(T && val) { value = std::move(val); return *this; }
+  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; }
+
+  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;
   };
 
   template <typename F> struct map_member_object;
-  template <typename T, typename R>
-  struct map_member_object<R T::*> {
+  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;
+    R (T::*mem)() const;
   };
-} }
+}}
 
 namespace stream { namespace traits {
   template <typename F>
   using memvar_f = typename detail::map_member_object<F>::type;
   template <typename F>
   using memfun_f = typename detail::map_member_function<F>::type;
-  
+
   template <typename F>
-  using is_memvar_t = typename std::enable_if<std::is_member_object_pointer<F>::value>::type;
+  using is_memvar_t =
+      typename std::enable_if<std::is_member_object_pointer<F>::value>::type;
   template <typename F>
-  using is_memfun_t = typename std::enable_if<std::is_member_function_pointer<F>::value>::type;
+  using is_memfun_t =
+      typename std::enable_if<std::is_member_function_pointer<F>::value>::type;
 
   template <typename T, typename = void>
   struct is_dereferencable : public std::false_type {};
 
-  template <>
-  struct is_dereferencable<void*> : public std::false_type {};
-  
+  template <> struct is_dereferencable<void *> : 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 {};
+  struct is_dereferencable<T, typename std::enable_if<!std::is_void<decltype(
+                                  *std::declval<T>())>::value>::type>
+      : public std::true_type {};
 
   template <typename T, typename F>
   using mapped_t = decltype(std::declval<F>()(std::declval<T>()));
-  
+
   template <typename T, typename F>
-  using fmapped_t = typename decltype(std::declval<F>()(std::declval<T>()))::value_type;
-} }
+  using fmapped_t =
+      typename decltype(std::declval<F>()(std::declval<T>()))::value_type;
+}}

+ 2 - 0
stream.xcodeproj/project.pbxproj

@@ -46,6 +46,7 @@
 /* Begin PBXFileReference section */
 		CD9337281E3CD78B00699FF5 /* stream_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = stream_test.cxx; sourceTree = "<group>"; };
 		CDAA170121A3A738007BBA11 /* stream */ = {isa = PBXFileReference; lastKnownFileType = folder; name = stream; path = include/stream; sourceTree = "<group>"; };
+		CDE8545E24DEBEBF006FE7C7 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
 		CDEC1D5B23514BB50091D9F2 /* GoogleMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GoogleMock.xcodeproj; path = "../../../../gmock-xcode-master/GoogleMock.xcodeproj"; sourceTree = "<group>"; };
 		CDEC1D6E23514BC60091D9F2 /* stream-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "stream-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
 		CDEC1D7223514BC60091D9F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -68,6 +69,7 @@
 			isa = PBXGroup;
 			children = (
 				CDEC1D5B23514BB50091D9F2 /* GoogleMock.xcodeproj */,
+				CDE8545E24DEBEBF006FE7C7 /* README.md */,
 				CDAA170121A3A738007BBA11 /* stream */,
 				CD9337371E3CD88200699FF5 /* test */,
 				CDEC1D6F23514BC60091D9F2 /* stream-test */,

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

@@ -7,7 +7,7 @@
 		<key>stream-test.xcscheme_^#shared#^_</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>57</integer>
+			<integer>55</integer>
 		</dict>
 		<key>stream_tc.xcscheme</key>
 		<dict>

+ 20 - 11
test/stream_fluent_test.cxx

@@ -19,7 +19,7 @@ TEST(FluentStreamTest, CollectToObjectPreservesElements) {
   std::vector<int> input{1, 2, 3, 4, 5};
   auto s = stream::make_stream(input);
   std::set<int> out{};
-  
+
   EXPECT_THAT(s > out, ElementsAreArray(input));
 }
 
@@ -34,40 +34,49 @@ TEST(FluentStreamTest, MapToSelfIsSelfs) {
 TEST(FluentStreamTest, MapCanAlterValues) {
   std::vector<int> input{1, 2, 3, 4, 5};
   std::vector<int> expected{3, 5, 7, 9, 11};
-  auto fmap = [](int i) { return 2*i+1; };
+  auto fmap = [](int i) { return 2 * i + 1; };
   auto s = stream::make_stream(input) | fmap;
 
   EXPECT_THAT(s.collect(), Eq(expected));
 }
 
-TEST(FluentStreamTest, NoOpFilterReturnOriginal) {
+TEST(FluentStreamTest, CanMapElementToBool) {
   std::vector<int> input{1, 2, 3, 4, 5};
-  auto pass = [](int) { return true; };
-  auto s = stream::make_stream(input) | pass;
+  std::vector<bool> expected{false, true, false, true, false};
+  auto even = [](int i) { return i % 2 == 0; };
+  auto s = stream::make_stream(input) | even;
 
-  EXPECT_THAT(s.collect(), Eq(input));
+  EXPECT_THAT(s.collect(), Eq(expected));
 }
 
 TEST(FluentStreamTest, CanFilterOutElements) {
   std::vector<int> input{1, 2, 3, 4, 5};
   std::vector<int> expected{2, 4};
-  auto even = [](int i) { return i%2 == 0; };
-  auto s = stream::make_stream(input) | even;
+  auto even = [](int i) { return i % 2 == 0; };
+  auto s = stream::make_stream(input) % even;
 
   EXPECT_THAT(s.collect(), Eq(expected));
 }
 
+TEST(FluentStreamTest, NoOpFilterReturnOriginal) {
+  std::vector<int> input{1, 2, 3, 4, 5};
+  auto pass = [](int) { return true; };
+  auto s = stream::make_stream(input) % pass;
+
+  EXPECT_THAT(s.collect(), Eq(input));
+}
+
 TEST(FluentStreamTest, AccumulateDefaultsToAdd) {
   std::vector<int> input{1, 2, 3, 4, 5};
-  auto even = [](int i) { return i%2 == 0; };
+  auto even = [](int i) { return i % 2 == 0; };
   auto sum = [](int lhs, int rhs) { return lhs + rhs; };
-  auto s = stream::make_stream(input) | even;
+  auto s = stream::make_stream(input) % even;
   EXPECT_THAT(s > sum, Eq(6));
 }
 
 TEST(FluentStreamTest, FlatmapJoinsIterableOutputs) {
   std::vector<int> vv{1, 2, 3, 4, 5};
-  auto next3 = [](int i) { return std::vector<int>{i, i+1, i+2}; };
+  auto next3 = [](int i) { return std::vector<int>{i, i + 1, i + 2}; };
   std::vector<int> expected{1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7};
   auto s = stream::make_stream(vv) || next3;
 

+ 36 - 29
test/stream_test.cxx

@@ -22,7 +22,7 @@ TEST(StreamTest, IteratorPreservesElements) {
   std::vector<int> input{1, 2, 3, 4, 5};
   auto s = stream::make_stream(input);
   std::vector<int> out{s.begin(), s.end()};
-  
+
   EXPECT_THAT(out, Eq(input));
 }
 
@@ -30,7 +30,7 @@ TEST(StreamTest, CollectPreservesElements) {
   std::vector<int> input{1, 2, 3, 4, 5};
   auto s = stream::make_stream(input);
   std::vector<int> out{s.collect()};
-  
+
   EXPECT_THAT(out, Eq(input));
 }
 
@@ -39,7 +39,7 @@ TEST(StreamTest, CollectToObjectPreservesElements) {
   auto s = stream::make_stream(input);
   std::set<int> out{};
   s.collect(out);
-  
+
   EXPECT_THAT(out, ElementsAreArray(input));
 }
 
@@ -54,25 +54,25 @@ TEST(StreamTest, MapToSelfIsSelfs) {
 TEST(StreamTest, MapCanAlterValues) {
   std::vector<int> input{1, 2, 3, 4, 5};
   std::vector<int> expected{3, 5, 7, 9, 11};
-  auto fmap = [](int i) { return 2*i+1; };
-  auto s = stream::make_stream(input).map( fmap );
+  auto fmap = [](int i) { return 2 * i + 1; };
+  auto s = stream::make_stream(input).map(fmap);
 
   EXPECT_THAT(s.collect(), Eq(expected));
 }
 
 TEST(StreamTest, CanBuildFromSingleElement) {
   int value = 11;
-  auto even = [](int i) { return i%2==0; };
+  auto even = [](int i) { return i % 2 == 0; };
   auto s = stream::make_stream(&value).filter(even);
-  
+
   EXPECT_TRUE(s.empty());
 }
 
 TEST(StreamTest, CanBuildFromIterators) {
   std::vector<int> input{1, 2, 3, 4, 5};
   std::vector<int> expected{5, 7};
-  auto fmap = [](int i) { return 2*i+1; };
-  auto s = stream::make_stream(input.begin()+1, input.begin()+3).map(fmap);
+  auto fmap = [](int i) { return 2 * i + 1; };
+  auto s = stream::make_stream(input.begin() + 1, input.begin() + 3).map(fmap);
 
   EXPECT_THAT(s.collect(), Eq(expected));
 }
@@ -80,15 +80,15 @@ TEST(StreamTest, CanBuildFromIterators) {
 TEST(StreamTest, NoOpFilterReturnOriginal) {
   std::vector<int> input{1, 2, 3, 4, 5};
   auto pass = [](int) { return true; };
-  auto s = stream::make_stream(input).filter( pass );
-  
+  auto s = stream::make_stream(input).filter(pass);
+
   EXPECT_THAT(s.collect(), Eq(input));
 }
 
 TEST(StreamTest, CanFilterOutElements) {
   std::vector<int> input{1, 2, 3, 4, 5};
   std::vector<int> expected{2, 4};
-  auto even = [](int i) { return i%2 == 0; };
+  auto even = [](int i) { return i % 2 == 0; };
   auto s = stream::make_stream(input).filter(even);
 
   EXPECT_THAT(s.collect(), Eq(expected));
@@ -96,53 +96,55 @@ TEST(StreamTest, CanFilterOutElements) {
 
 TEST(StreamTest, AccumulateDefaultsToAdd) {
   std::vector<int> input{1, 2, 3, 4, 5};
-  auto even = [](int i) { return i%2 == 0; };
-  auto s = stream::make_stream(input).filter( even );
+  auto even = [](int i) { return i % 2 == 0; };
+  auto s = stream::make_stream(input).filter(even);
 
   EXPECT_THAT(s.accumulate(0), Eq(6));
 }
 
 TEST(StreamTest, AccumulateCanTakeCustomAccumulator) {
   std::vector<int> input{1, 2, 3, 4, 5};
-  auto even = [](int i) { return i%2 == 0; };
+  auto even = [](int i) { return i % 2 == 0; };
   auto prod = [](int lhs, int rhs) { return lhs * rhs; };
   auto s = stream::make_stream(input).filter(even);
- 
+
   EXPECT_THAT(s.accumulate(prod, 0), Eq(0));
   EXPECT_THAT(s.accumulate(prod, 1), Eq(8));
 }
 
 TEST(StreamTest, FlatmapJoinsIterableOutputs) {
   std::vector<int> vv{1, 2, 3, 4, 5};
-  auto next3 = [](int i) { return std::vector<int>{i, i+1, i+2}; };
+  auto next3 = [](int i) { return std::vector<int>{i, i + 1, i + 2}; };
   std::vector<int> expected{1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7};
   auto s = stream::make_stream(vv).flatmap(next3);
- 
+
   EXPECT_THAT(s.collect(), Eq(expected));
 }
 
 TEST(StreamTest, CanDereferenceElements) {
   int val = 5;
-  std::vector<int*> input{&val};
+  std::vector<int *> input{&val};
   auto data = stream::make_stream(input).deref().collect();
-  
+
   EXPECT_THAT(data.front(), Eq(val));
 }
 
 TEST(StreamTest, CanForEachConsume) {
   int hits = 0;
   std::vector<int> input{1, 2, 3, 4, 5};
-  stream::make_stream(input).each([&hits](int){ ++hits; });
- 
+  stream::make_stream(input).each([&hits](int) { ++hits; });
+
   EXPECT_THAT(hits, Eq(5));
 }
 
 TEST(StreamTest, CanFetchMemPtr) {
-  struct test { int val; };
+  struct test {
+    int val;
+  };
   std::vector<test> input{{1}, {3}, {2}};
   std::vector<int> expected{1, 3, 2};
   auto out = stream::make_stream(input).map(&test::val).collect();
- 
+
   EXPECT_THAT(out, Eq(expected));
 }
 
@@ -155,12 +157,17 @@ TEST(StreamTest, CanMapToMemFn) {
 }
 
 TEST(StreamTest, CastStreamToParentType) {
-  struct base { char cat[4] = "cat"; };
-  struct test : base { test(int v) : val(v) {} int val; };
+  struct base {
+    char cat[4] = "cat";
+  };
+  struct test : base {
+    test(int v) : val(v) {}
+    int val;
+  };
   std::vector<test> input{{1}, {3}, {2}};
-  
-  auto addressof_void = [](auto const & p) { return (void*)&p; };
-  
+
+  auto addressof_void = [](auto const & p) { return (void *)&p; };
+
   auto strm = stream::make_stream(input).cast<base>();
   auto first = stream::make_stream(input).map(addressof_void).collect();
   auto second = strm.map(addressof_void).collect();