Browse Source

Initial commit of a Lazy-Evaluation Stream processing library.

Samuel Jaffe 9 years ago
commit
34abf55736

+ 75 - 0
Makefile

@@ -0,0 +1,75 @@
+WARNINGS := -Wall -pedantic  -pedantic-errors -Wextra -Wcast-align \
+  -Wcast-qual  -Wchar-subscripts  -Wcomment -Wconversion \
+  -Wdisabled-optimization -Werror -Wfloat-equal  -Wformat  -Wformat=2 \
+  -Wformat-nonliteral -Wformat-security  -Wformat-y2k \
+  -Wimport  -Winit-self  -Winline -Winvalid-pch   \
+  -Wunsafe-loop-optimizations  -Wno-long-long -Wmissing-braces \
+  -Wmissing-field-initializers -Wmissing-format-attribute   \
+  -Wmissing-include-dirs -Wmissing-noreturn -Wmissing-declarations \
+  -Wpacked -Wparentheses  -Wpointer-arith \
+  -Wredundant-decls -Wreturn-type \
+  -Wsequence-point  -Wshadow -Wsign-compare  -Wstack-protector \
+  -Wstrict-aliasing -Wstrict-aliasing=2 -Wswitch  -Wswitch-default \
+  -Wswitch-enum -Wtrigraphs  -Wuninitialized \
+  -Wunknown-pragmas  -Wunreachable-code -Wunused \
+  -Wunused-function  -Wunused-label  -Wunused-parameter \
+  -Wunused-value  -Wunused-variable  -Wvariadic-macros \
+  -Wvolatile-register-var  -Wwrite-strings
+
+CWARNINGS := $(WARNINGS) -Wimplicit
+CPPWARNINGS := $(WARNINGS)
+
+CFLAGS   := $(CWARNINGS)
+CPPFLAGS := $(CPPWARNINGS)
+LDFLAGS  :=
+
+HDRFILES := 
+SRCFILES := 
+TSTFILES := 
+
+BINARY   :=
+
+DEPFILES := $(patsubst %.cpp,.%.d,$(SRCFILES))
+OBJFILES := $(patsubst %.cpp,%.o,$(SRCFILES))
+TSTFILES := $(patsubst %.h,%.cpp,$(TSTSUITE))
+TSTDRIVR := $(patsubst %.cpp,%,$(TSTFILES))
+
+ALLFILES := $(SRCFILES) $(HDRFILES) $(AUXFILES)
+
+.PHONY: all clean debug release check coverage
+
+all: $(BINARY) $(LNBINARY)
+
+debug: CFLAGS += -DDEBUG -g
+debug: CPPFLAGS += -DDEBUG -g
+debug: all
+
+release: CFLAGS += -O2
+release: CPPFLAGS += -O2
+release: all
+
+coverage: CFLAGS += -fprofile-arcs -ftest-coverage
+coverage: CPPFLAGS += -fprofile-arcs -ftest-coverage
+coverage: check
+
+clean: check-clean
+	@$(RM) $(BINARY) $(wildcard $(OBJFILES)) $(LNBINARY)
+
+check-clean:
+	@$(RM) $(TSTDRIVR) $(TSTFILES)
+
+check: check-clean $(TSTDRIVR)
+
+.h.cpp:
+	@cxxtestgen --error-printer $< -o $@
+
+.cpp.o: Makefile
+	$(CXX) $(CPPFLAGS) -MMD -MP -MF $(patsubst %.cpp,.%.d,$<) -c $< -o $@
+
+$(BINARY): $(OBJFILES) 
+	$(CXX) $(LDFLAGS) -o $@ $(OBJFILES)
+
+$(TSTDRIVR): $(TSTFILES)
+	@$(CXX) $(CPPFLAGS) -I$(CXXTEST) -w $@.cpp -o $@
+	@echo Running TestDriver: ./$@
+	@./$@

+ 309 - 0
stream.hpp

@@ -0,0 +1,309 @@
+/*
+ * File stream.hpp
+ * 
+ * Stream style functional composition
+ *
+ * @author Sam Jaffe
+ *
+ */
+
+#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;
+}
+
+}
+

+ 160 - 0
stream.xcodeproj/project.pbxproj

@@ -0,0 +1,160 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXFileReference section */
+		0E5DFDC01BB4D3190063976E /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
+		0EB8334D1BBF45FD00DDC844 /* filter.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = filter.hpp; sourceTree = "<group>"; };
+		0EB8334E1BBF45FD00DDC844 /* forward.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = forward.hpp; sourceTree = "<group>"; };
+		0EB8334F1BBF45FD00DDC844 /* join.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = join.hpp; sourceTree = "<group>"; };
+		0EB833501BBF45FD00DDC844 /* map.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map.hpp; sourceTree = "<group>"; };
+		0EB833511BBF45FD00DDC844 /* source.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = source.hpp; sourceTree = "<group>"; };
+		0EB833521BBF45FD00DDC844 /* streams.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = streams.hpp; sourceTree = "<group>"; };
+		0EB833531BBF45FD00DDC844 /* streams.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = streams.cpp; sourceTree = "<group>"; };
+		0EB833541BBF45FD00DDC844 /* streams.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = streams.hpp; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXGroup section */
+		0E5DFDB91BB4D3190063976E = {
+			isa = PBXGroup;
+			children = (
+				0EB8334C1BBF45FD00DDC844 /* streams */,
+				0EB833531BBF45FD00DDC844 /* streams.cpp */,
+				0EB833541BBF45FD00DDC844 /* streams.hpp */,
+				0E5DFDC01BB4D3190063976E /* Makefile */,
+			);
+			sourceTree = "<group>";
+		};
+		0EB8334C1BBF45FD00DDC844 /* streams */ = {
+			isa = PBXGroup;
+			children = (
+				0EB8334D1BBF45FD00DDC844 /* filter.hpp */,
+				0EB8334E1BBF45FD00DDC844 /* forward.hpp */,
+				0EB8334F1BBF45FD00DDC844 /* join.hpp */,
+				0EB833501BBF45FD00DDC844 /* map.hpp */,
+				0EB833511BBF45FD00DDC844 /* source.hpp */,
+				0EB833521BBF45FD00DDC844 /* streams.hpp */,
+			);
+			path = streams;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXLegacyTarget section */
+		0E5DFDBE1BB4D3190063976E /* stream */ = {
+			isa = PBXLegacyTarget;
+			buildArgumentsString = "$(ACTION)";
+			buildConfigurationList = 0E5DFDC21BB4D3190063976E /* Build configuration list for PBXLegacyTarget "stream" */;
+			buildPhases = (
+			);
+			buildToolPath = /usr/bin/make;
+			buildWorkingDirectory = "/Users/leumasjaffe/Documents/Programming/XTools Workspace/C:C++/misc/stream";
+			dependencies = (
+			);
+			name = stream;
+			passBuildSettingsInEnvironment = 1;
+			productName = stream;
+		};
+/* End PBXLegacyTarget section */
+
+/* Begin PBXProject section */
+		0E5DFDBA1BB4D3190063976E /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+			};
+			buildConfigurationList = 0E5DFDBD1BB4D3190063976E /* Build configuration list for PBXProject "stream" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 0E5DFDB91BB4D3190063976E;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				0E5DFDBE1BB4D3190063976E /* stream */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin XCBuildConfiguration section */
+		0E5DFDBB1BB4D3190063976E /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				COPY_PHASE_STRIP = NO;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx10.6;
+			};
+			name = Debug;
+		};
+		0E5DFDBC1BB4D3190063976E /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				COPY_PHASE_STRIP = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				SDKROOT = macosx10.6;
+			};
+			name = Release;
+		};
+		0E5DFDC31BB4D3190063976E /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COPY_PHASE_STRIP = NO;
+				DEBUGGING_SYMBOLS = YES;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				PRODUCT_NAME = stream;
+			};
+			name = Debug;
+		};
+		0E5DFDC41BB4D3190063976E /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				PRODUCT_NAME = stream;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		0E5DFDBD1BB4D3190063976E /* Build configuration list for PBXProject "stream" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				0E5DFDBB1BB4D3190063976E /* Debug */,
+				0E5DFDBC1BB4D3190063976E /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		0E5DFDC21BB4D3190063976E /* Build configuration list for PBXLegacyTarget "stream" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				0E5DFDC31BB4D3190063976E /* Debug */,
+				0E5DFDC41BB4D3190063976E /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 0E5DFDBA1BB4D3190063976E /* Project object */;
+}

+ 80 - 0
stream.xcodeproj/xcuserdata/leumasjaffe.xcuserdatad/xcschemes/stream.xcscheme

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0700"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "0E5DFDBE1BB4D3190063976E"
+               BuildableName = "stream"
+               BlueprintName = "stream"
+               ReferencedContainer = "container:stream.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0E5DFDBE1BB4D3190063976E"
+            BuildableName = "stream"
+            BlueprintName = "stream"
+            ReferencedContainer = "container:stream.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0E5DFDBE1BB4D3190063976E"
+            BuildableName = "stream"
+            BlueprintName = "stream"
+            ReferencedContainer = "container:stream.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 22 - 0
stream.xcodeproj/xcuserdata/leumasjaffe.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>SchemeUserState</key>
+	<dict>
+		<key>stream.xcscheme</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>2</integer>
+		</dict>
+	</dict>
+	<key>SuppressBuildableAutocreation</key>
+	<dict>
+		<key>0E5DFDBE1BB4D3190063976E</key>
+		<dict>
+			<key>primary</key>
+			<true/>
+		</dict>
+	</dict>
+</dict>
+</plist>

+ 80 - 0
stream.xcodeproj/xcuserdata/samjaffe.xcuserdatad/xcschemes/stream.xcscheme

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0720"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "0E5DFDBE1BB4D3190063976E"
+               BuildableName = "stream"
+               BlueprintName = "stream"
+               ReferencedContainer = "container:stream.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0E5DFDBE1BB4D3190063976E"
+            BuildableName = "stream"
+            BlueprintName = "stream"
+            ReferencedContainer = "container:stream.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0E5DFDBE1BB4D3190063976E"
+            BuildableName = "stream"
+            BlueprintName = "stream"
+            ReferencedContainer = "container:stream.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

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

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>SchemeUserState</key>
+	<dict>
+		<key>stream.xcscheme</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>7</integer>
+		</dict>
+	</dict>
+	<key>SuppressBuildableAutocreation</key>
+	<dict>
+		<key>0E5DFDBE1BB4D3190063976E</key>
+		<dict>
+			<key>primary</key>
+			<true/>
+		</dict>
+	</dict>
+</dict>
+</plist>

+ 71 - 0
streams.cpp

@@ -0,0 +1,71 @@
+#include <vector>
+#include <iostream>
+#include <iterator>
+
+#include "streams.hpp"
+
+namespace stream {
+  template <typename T, typename F>
+  auto make_map_t(F&& func) -> map_t<T, decltype(func(std::declval<T>()))> {
+    return map_t<T, decltype(func(std::declval<T>()))>{func};
+  }
+  
+  template <typename T, typename F>
+  auto make_flatmap_t(F&& func) -> flatmap_t<T, decltype(func(std::declval<T>()))> {
+    return flatmap_t<T, decltype(func(std::declval<T>()))>{func};
+  }
+
+  template <typename T, typename F>
+  auto make_filter_t(F&& func) -> filter_t<T> {
+    return filter_t<T>{func};
+  }
+}
+
+#define map(t, x, expr) stream::make_map_t<t>([](t x) { return expr; })
+#define filter(t, x, expr) stream::make_filter_t<t>([](t x) { return expr; })
+#define flatmap(t, x, expr) stream::make_flatmap_t<t>([](t x) { return expr; })
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, std::vector<T> const& tmp) {
+  os << "{ ";
+  for (auto it = tmp.begin(); it != tmp.end(); ++it) {
+    os << *it << ", ";
+  }
+  return os << "\b\b }";
+}
+
+std::vector<int> iota(int max) {
+  std::vector<int> r(3);
+  std::iota(r.begin(), r.end(), max);
+  return r;
+}
+
+int main(int argc, const char**argv) {
+  std::vector<int> vec{1,2,3,4,5};
+//  auto s = stream::make_stream(vec) | stream::map_t<int, int>([](int x) { return x*2; });
+  auto s = stream::make_stream(vec) | filter(int, x, x%2==0) | map(int, x, x*2);
+  std::cout << "The result of the expression 'stream(vec) | filter(x,x%2==0) | map(x,x*2)' is:\n\t";
+  std::cout << "{ ";
+  for (auto it = s.begin(); it != s.end(); ++it) {
+    std::cout << *it << ", ";
+  }
+  std::cout << "\b\b }" << std::endl;
+  std::cout << "The result of the expression 'stream(vec) | filter(x,x%2==0) | map(x,x*2) | fold(i,j,i*j,1)' is:\n\t";
+  std::cout << s.accumulate([](int i, int j){return i*j;},1);
+  std::cout << std::endl;
+  auto t = s | flatmap(int, x, std::vector<double>{1/(double)x});
+  std::cout << "The result of the expression 'stream(vec) | filter(x,x%2==0) | map(x,x*2) | map(x, [1/x])' is:\n\t";
+  std::cout << "{ ";
+  for (auto it = t.begin(); it != t.end(); ++it) {
+    std::cout << *it << ", ";
+  }
+  std::cout << "\b\b }" << std::endl;
+  auto q = stream::make_stream(vec) | filter(int, x, x%2==1) | map(int, x, iota(x));
+  std::cout << "The result of the expression 'stream(vec) | filter(x,x%2==1) | map(x,iota(x))' is:\n\t";
+  std::cout << "{ ";
+  for (auto it = q.begin(); it != q.end(); ++it) {
+    std::cout << *it << ", ";
+  }
+  std::cout << "\b\b }" << std::endl;
+  return 0;
+}

+ 11 - 0
streams.hpp

@@ -0,0 +1,11 @@
+#pragma once
+
+#include "streams/forward.hpp"
+
+#include "streams/streams.hpp"
+
+#include "streams/source.hpp"
+
+#include "streams/map.hpp"
+#include "streams/filter.hpp"
+#include "streams/join.hpp"

+ 82 - 0
streams/filter.hpp

@@ -0,0 +1,82 @@
+#pragma once
+
+namespace stream {
+  template <typename T>
+  struct filter_t {
+    template <typename F>
+    filter_t(F&& f) : pred(f) {}
+    std::function<bool(const T&)> pred;
+  };
+}
+
+template <typename T, bool B>
+stream::detail::stream_base<T, true> operator|(stream::detail::stream_base<T, B> const&s, stream::filter_t<T>&& f) {
+  return s.filter(f.pred);
+}
+template <typename T, bool B>
+stream::detail::stream_base<T, true> operator|(stream::detail::stream_base<T, B> &&s, stream::filter_t<T>&& f) {
+  return std::move(s).filter(f.pred);
+}
+
+namespace stream {
+  namespace detail {
+    template <typename T, bool B>
+    class filter_stream : public stream_impl<T> {
+    public:
+      class iterator : public iterator_impl<T> {
+      public:
+        typedef iterator_impl<T> super;
+        iterator(std::function<bool(T const&)> f, ::stream::iterator<T>&& impl)
+        : pred_(f), impl_(std::forward<::stream::iterator<T>>(impl)), next_(impl_) {
+          advance();
+        }
+        ~iterator() {}
+        T operator*() override { return mem_; }
+        
+        super& operator++() {
+          ++impl_;
+          advance();
+          return *this;
+        }
+        
+        DELEGATE_ITERATOR_IMPL_BASE(impl_)
+      private:
+        void advance() {
+          while (!pred_(mem_ = *impl_)) {
+            ++impl_;
+          }
+        }
+        
+        std::function<bool(T const&)> pred_;
+        T mem_; // To avoid re-calcs, we store this
+        ::stream::iterator<T> impl_, next_;
+      };
+      
+      template <typename F>
+      filter_stream(F&& func, stream_base<T, B> const& sb) : pred_(func), source_(sb) {}
+      template <typename F>
+      filter_stream(F&& func, stream_base<T, B> && sb) : pred_(func), source_(std::forward<stream_base<T, B>>(sb)) { }
+      ~filter_stream() override {}
+      
+      ::stream::iterator<T> begin() override { return new iterator{pred_, source_.begin()};}
+      ::stream::iterator<T> end() override { return new iterator{pred_, source_.end()}; }
+    private:
+      std::function<bool(T const&)> pred_;
+      stream_base<T, B> source_;
+    };
+    
+    template <typename T, bool Own>
+    template <typename F>
+    auto stream_base<T, Own>::filter(F&& pred) const& -> stream_base<T, true>  {
+      using impl_t = filter_stream<T, false>;
+      return stream_base<T, true>{new impl_t{pred, *this}};
+    }
+    
+    template <typename T, bool Own>
+    template <typename F>
+    auto stream_base<T, Own>::filter(F&& pred) && -> stream_base<T, true> {
+      using impl_t = filter_stream<T, Own>;
+      return stream_base<T, true>{new impl_t{pred, std::forward<stream_base<T, Own>>(*this)}};
+    }
+  }
+}

+ 17 - 0
streams/forward.hpp

@@ -0,0 +1,17 @@
+#pragma once
+
+namespace stream {
+  namespace detail {
+    template <typename, bool> class stream_base;
+    template <typename> class iterator_impl;
+  }
+}
+
+namespace stream {
+  template <typename> class iterator;
+  template <typename, typename> struct map_t;
+  template <typename> struct filter_t;
+  template <typename, typename> struct flatmap_t;
+  template <typename T>
+  using stream = detail::stream_base<T, true>; // Should I override instead?
+}

+ 104 - 0
streams/join.hpp

@@ -0,0 +1,104 @@
+#pragma once
+
+template <typename T, typename C, bool B>
+stream::detail::stream_base<typename C::value_type, true> operator|(stream::detail::stream_base<T, B> const&s, stream::flatmap_t<T, C>&& f) {
+  return s.flatmap(f.func);
+}
+template <typename T, typename C, bool B>
+stream::detail::stream_base<typename C::value_type, true> operator|(stream::detail::stream_base<T, B> &&s, stream::flatmap_t<T, C>&& f) {
+  return std::move(s).flatmap(f.func);
+}
+
+namespace stream {
+  template <typename T, typename R>
+  struct flatmap_t {
+    template <typename F>
+    flatmap_t(F&& f) : func(f) {}
+    std::function<R(const T&)> func;
+  };
+}
+
+namespace stream {
+  namespace detail {
+    template <typename C, bool B>
+    class join_stream : public stream_impl<typename C::value_type> {
+    public:
+      using T = typename C::value_type;
+      class iterator : public iterator_impl<T> {
+      public:
+        typedef iterator_impl<T> super;
+        iterator(::stream::iterator<C>&& f, ::stream::iterator<C>&& l)
+        : start_(std::forward<::stream::iterator<C>>(f))
+        , finish_(std::forward<::stream::iterator<C>>(l))
+        {
+          if (start_ != finish_) {
+            mem_ = *(start_);
+            curr_ = mem_.begin();
+            end_ = mem_.end();
+            advance();
+          }
+        }
+        ~iterator() {}
+        T operator*() override { return *curr_; }
+        
+        super& operator++() {
+          ++curr_;
+          advance();
+          return *this;
+        }
+        
+        DELEGATE_ITERATOR_IMPL_BASE(start_)
+      private:
+        void advance() {
+          while (curr_ == end_ && start_ != finish_) {
+            mem_ = *(++start_);
+            curr_ = mem_.begin();
+            end_ = mem_.end();
+          }
+        }
+        ::stream::iterator<C> start_, finish_;
+        C mem_;
+        typename C::iterator curr_, end_;
+      };
+      
+      join_stream(stream_base<C, B> const& sb) : source_(sb) {}
+      join_stream(stream_base<C, B> && sb) : source_(std::forward<stream_base<C, B>>(sb)) { }
+      ~join_stream() override {}
+      
+      ::stream::iterator<T> begin() override {
+        return new iterator{source_.begin(), source_.end()};
+      }
+      ::stream::iterator<T> end() override {
+        return new iterator{source_.end(), source_.end()};
+      }
+    private:
+      stream_base<C, B> source_;
+    };
+    
+    template <typename C, bool Own>
+    auto join(stream_base<C, Own> const& sb) -> stream_base<typename C::value_type, true>  {
+      using T = typename C::value_type;
+      using impl_t = join_stream<C, false>;
+      return stream_base<T, true>{new impl_t{falsify(sb)}};
+    }
+    
+    template <typename C, bool Own>
+    auto join(stream_base<C, Own> && sb) -> stream_base<typename C::value_type, true> {
+      using T = typename C::value_type;
+      using impl_t = join_stream<C, Own>;
+      return stream_base<T, true>{new impl_t(std::forward<stream_base<C, Own>>(sb))};
+    }
+    
+    template <typename T, bool Own>
+    template <typename F>
+    auto stream_base<T, Own>::flatmap(F&& func) const& -> stream_base<flatmap_f<F>, true>  {
+      return join((*this).map(func));
+    }
+    
+    template <typename T, bool Own>
+    template <typename F>
+    auto stream_base<T, Own>::flatmap(F&& func) && -> stream_base<flatmap_f<F>, true> {
+      return join(std::forward<self>(*this).map(func));
+    }
+  }
+}

+ 66 - 0
streams/map.hpp

@@ -0,0 +1,66 @@
+#pragma once
+
+namespace stream {
+  template <typename T, typename R>
+  struct map_t {
+    template <typename F>
+    map_t(F&& f) : func(f) {}
+    std::function<R(const T&)> func;
+  };
+}
+
+template <typename T, typename R, bool B>
+stream::detail::stream_base<R, true> operator|(stream::detail::stream_base<T, B> const&s, stream::map_t<T, R>&& f) {
+  return s.map(f.func);
+}
+template <typename T, typename R, bool B>
+stream::detail::stream_base<R, true> operator|(stream::detail::stream_base<T, B> &&s, stream::map_t<T, R>&& f) {
+  return std::move(s).map(f.func);
+}
+
+namespace stream {
+  namespace detail {
+    template <typename T, typename R, bool B>
+    class map_stream : public stream_impl<R> {
+    public:
+      class iterator : public iterator_impl<R> {
+      public:
+        typedef iterator_impl<R> super;
+        iterator(std::function<R(T const&)> f, ::stream::iterator<T>&& impl)
+        : fun_(f), impl_(std::forward<::stream::iterator<T>>(impl)) {}
+        ~iterator() {}
+        R operator*() override { return fun_(*impl_); }
+        DELEGATE_ITERATOR_IMPL(impl_)
+      private:
+        std::function<R(T const&)> fun_;
+        ::stream::iterator<T> impl_;
+      };
+      
+      template <typename F>
+      map_stream(F&& func, stream_base<T, B> const& sb) : fun_(func), source_(sb) {}
+      template <typename F>
+      map_stream(F&& func, stream_base<T, B> && sb) : fun_(func), source_(std::forward<stream_base<T, B>>(sb)) { }
+      ~map_stream() override {}
+      
+      ::stream::iterator<R> begin() override { return new iterator{fun_, source_.begin()};}
+      ::stream::iterator<R> end() override { return new iterator{fun_, source_.end()}; }
+    private:
+      std::function<R(T const&)> fun_;
+      stream_base<T, B> source_;
+    };
+    
+    template <typename T, bool Own>
+    template <typename F>
+    auto stream_base<T, Own>::map(F&& func) const& -> stream_base<map_f<F>, true>  {
+      using impl_t = map_stream<T, map_f<F>, false>;
+      return stream_base<map_f<F>, true>{new impl_t(func, falsify(*this))};
+    }
+    
+    template <typename T, bool Own>
+    template <typename F>
+    auto stream_base<T, Own>::map(F&& func) && -> stream_base<map_f<F>, true> {
+      using impl_t = map_stream<T, map_f<F>, Own>;
+      return stream_base<map_f<F>, true>{new impl_t(func, std::forward<self>(*this))};
+    }
+  }
+}

+ 34 - 0
streams/source.hpp

@@ -0,0 +1,34 @@
+#pragma once
+
+namespace stream {
+  namespace detail {
+    template <typename C>
+    class source_stream : public stream_impl<typename C::value_type> {
+    public:
+      typedef typename C::value_type value_type;
+      class iterator : public iterator_impl<value_type> {
+      public:
+        typedef iterator_impl<value_type> super;
+        iterator(typename C::iterator it) : impl_(it) {}
+        ~iterator() {}
+        value_type operator*() override { return *impl_; }
+        DELEGATE_ITERATOR_IMPL(impl_)
+      private:
+        typename C::iterator impl_;
+      };
+      
+      source_stream(C const& cont) : source_(cont) {}
+      source_stream(C && cont) : source_(std::forward(cont)) {}
+      ~source_stream() override {}
+      ::stream::iterator<value_type> begin() override { return new iterator{source_.begin()}; }
+      ::stream::iterator<value_type> end() override { return new iterator{source_.end()}; }
+    private:
+      C source_;
+    };
+  }
+  
+  template <typename C>
+  detail::stream_base<typename C::value_type, true> make_stream(C const& cont) {
+    return detail::stream_base<typename C::value_type, true>{new detail::source_stream<C>{cont}};
+  }
+}

+ 115 - 0
streams/streams.hpp

@@ -0,0 +1,115 @@
+#pragma once
+
+#include <memory>
+#include <algorithm>
+
+#define EQ_MEM(x) x == dynamic_cast<iterator const&>(other).x
+
+#define DELEGATE_ITERATOR_IMPL_BASE(impl) \
+super* clone() const override { return new iterator{*this}; } \
+bool operator==(super const&other) const override { return EQ_MEM(impl); } \
+
+#define DELEGATE_ITERATOR_IMPL(impl) \
+super& operator++() override { ++impl; return *this; } \
+DELEGATE_ITERATOR_IMPL_BASE(impl)
+
+namespace stream {
+  template <typename T>
+  class iterator {
+  public:
+    iterator(detail::iterator_impl<T>* impl) : impl_(impl) {}
+    iterator(iterator const& other) : impl_(other.impl_->clone()) { }
+    iterator(iterator&& other) : impl_(nullptr) { std::swap(impl_, other.impl_); }
+    ~iterator() { if (impl_) delete impl_; }
+    T operator*() const { return **impl_; }
+    iterator& operator++() { ++(*impl_); return *this; }
+    bool operator==(iterator const&other) const { return *impl_ == *(other.impl_); }
+    bool operator!=(iterator const&other) const { return *impl_ != *(other.impl_); }
+  private:
+    detail::iterator_impl<T>* impl_;
+  };
+  
+  namespace detail {
+    template <typename T>
+    stream_base<T, false> falsify(stream_base<T, true> const& in);
+    
+    template <typename T>
+    class iterator_impl {
+    public:
+      virtual ~iterator_impl() {}
+      virtual iterator_impl<T>* clone() const = 0;
+      virtual T operator*() = 0;
+      virtual iterator_impl<T>& operator++() = 0;
+      virtual bool operator==(iterator_impl<T> const&other) const = 0;
+      bool operator!=(iterator_impl<T> const&other) const {
+        return !operator==(other);
+      }
+    };
+    
+    template <typename T>
+    class stream_impl {
+    public:
+      virtual ~stream_impl() { }
+      virtual ::stream::iterator<T> begin() = 0;
+      virtual ::stream::iterator<T> end() = 0;
+    };
+    
+    template <typename T, bool Own>
+    class stream_base {
+    private:
+      template <typename F>
+      using map_f = decltype(std::declval<F>()(std::declval<T>()));
+      template <typename F>
+      using flatmap_f = typename decltype(std::declval<F>()(std::declval<T>()))::value_type;
+      
+      using self = stream_base<T, Own>;
+    public:
+      stream_base(stream_impl<T>* impl) : impl_(impl) {}
+      stream_base(stream_base&&other) : impl_(nullptr) { std::swap(impl_, other.impl_); }
+      ~stream_base() { if (Own && impl_) delete 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;
+        collect(coll);
+        return coll;
+      }
+      
+      template <typename C>
+      C& collect(typename std::enable_if<!
+                 std::is_void<typename C::value_type>::value, C>::type& coll) const {
+        std::copy(begin(), end(), std::inserter(coll.end(), coll));
+        return coll;
+      }
+      
+      template <typename F>
+      T accumulate(F&& fold, T const& accum) {
+        return std::accumulate(begin(), end(), accum, fold);
+      }
+      
+      template <typename F>
+      stream_base<map_f<F>, true> map(F&& func) const&;
+      template <typename F>
+      stream_base<map_f<F>, true> map(F&& func) &&;
+      template <typename F>
+      stream_base<T, true> filter(F&& func) const&;
+      template <typename F>
+      stream_base<T, true> filter(F&& func) &&;
+      template <typename F>
+      stream_base<flatmap_f<F>, true> flatmap(F&& func) const&;
+      template <typename F>
+      stream_base<flatmap_f<F>, true> flatmap(F&& func) &&;
+    private:
+      friend stream_base<T, false> falsify<T>(stream_base<T, true>const&);
+      stream_impl<T>* impl_;
+    };
+    
+    template <typename T>
+    stream_base<T, false> const& falsify(stream_base<T, false> const& in) { return in; }
+    template <typename T>
+    stream_base<T, false> falsify(stream_base<T, true> const& in) {
+      return stream_base<T, false>{in.impl_};
+    }
+  }
+}