Forráskód Böngészése

Fixing some compiler errors due to explicit constructor.
Fixing SFINAE glitch in flatmap_t.
Fixing OOB iteration in join_iterator.
Fixing flatmap, signature should be
flatmap :: (iterable (iterable T)) -> (T -> R) -> (iterable R)
Adding test case.

Samuel Jaffe 8 éve
szülő
commit
2cf66132a7

+ 96 - 0
stream.t.h

@@ -0,0 +1,96 @@
+//
+//  stream_td.hpp
+//  stream
+//
+//  Created by Sam Jaffe on 1/28/17.
+//
+
+#pragma once
+
+#include <cxxtest/TestSuite.h>
+
+#include <vector>
+
+#include "streams.hpp"
+
+
+class stream_TestSuite : public CxxTest::TestSuite {
+public:
+  using vec_t = std::vector<int>;
+public:
+  void test_preserved() {
+    vec_t v{1, 2, 3, 4, 5};
+    auto s = stream::make_stream(v);
+    vec_t o{s.begin(), s.end()};
+    TS_ASSERT_EQUALS(v, o);
+  }
+  
+  void test_collect_preserves() {
+    vec_t v{1, 2, 3, 4, 5};
+    auto s = stream::make_stream(v);
+    vec_t o{s.begin(), s.end()};
+    vec_t o2{s.collect()};
+    TS_ASSERT_EQUALS(v, o);
+    TS_ASSERT_EQUALS(v, o2);
+  }
+
+  void test_collect_arg_preserves() {
+    vec_t v{1, 2, 3, 4, 5};
+    auto s = stream::make_stream(v);
+    std::set<int> o{};
+    s.collect(o);
+    for ( int i : v ) {
+      TS_ASSERT_EQUALS(o.count( i ), 1);
+    }
+  }
+  
+  void test_map_identity() {
+    vec_t v{1, 2, 3, 4, 5};
+    auto identity = [](int const & i) { return i; };
+    auto s = stream::make_stream(v).map( identity );
+    vec_t o{s.begin(), s.end()};
+    TS_ASSERT_EQUALS(v, o);
+  }
+  
+  void test_map_change() {
+    vec_t v{1, 2, 3, 4, 5};
+    vec_t expected{3, 5, 7, 9, 11};
+    auto fmap = [](int const & i) { return 2*i+1; };
+    auto s = stream::make_stream(v).map( fmap );
+    vec_t o{s.begin(), s.end()};
+    TS_ASSERT_EQUALS(expected, o);
+  }
+  
+  void test_filter_noop() {
+    vec_t v{1, 2, 3, 4, 5};
+    auto pass = [](int const & i) { return true; };
+    auto s = stream::make_stream(v).filter( pass );
+    vec_t o{s.begin(), s.end()};
+    TS_ASSERT_EQUALS(v, o);
+  }
+  
+  void test_filter_value() {
+    vec_t v{1, 2, 3, 4, 5};
+    vec_t expected{2, 4};
+    auto even = [](int const & i) { return i%2 == 0; };
+    auto s = stream::make_stream(v).filter( even );
+    vec_t o{s.begin(), s.end()};
+    TS_ASSERT_EQUALS(expected, o);
+  }
+  
+  void test_accumulate() {
+    vec_t v{1, 2, 3, 4, 5};
+    auto even = [](int const & i) { return i%2 == 0; };
+    auto s = stream::make_stream(v).filter( even );
+    TS_ASSERT_EQUALS( 6 , s.accumulate([](int const & lhs, int const & rhs) { return lhs + rhs; }, 0) );
+  }
+  
+  void test_flatmap_joins_lists() {
+    std::vector<vec_t> vv{{1, 2, 3}, {2, 3, 4}, {3, 4, 5}, {4, 5, 6}, {5, 6, 7}};
+    vec_t expected{1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7};
+    auto identity = [](int const & i) { return i; };
+    auto s = stream::make_stream(vv).flatmap( identity );
+    vec_t o{s.begin(), s.end()};
+    TS_ASSERT_EQUALS(expected, o);
+  }
+};

+ 175 - 33
stream.xcodeproj/project.pbxproj

@@ -6,6 +6,22 @@
 	objectVersion = 46;
 	objects = {
 
+/* Begin PBXBuildFile section */
+		CD9337351E3CD7B700699FF5 /* stream_tc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD9337271E3CD78B00699FF5 /* stream_tc.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		CD93372B1E3CD79E00699FF5 /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
 /* 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>"; };
@@ -14,19 +30,31 @@
 		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>"; };
 		CD35DCF21D61385F00BE3686 /* fold.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = fold.hpp; sourceTree = "<group>"; };
+		CD9337271E3CD78B00699FF5 /* stream_tc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = stream_tc.cpp; sourceTree = "<group>"; };
+		CD9337281E3CD78B00699FF5 /* stream.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stream.t.h; sourceTree = "<group>"; };
+		CD93372D1E3CD79E00699FF5 /* stream_tc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stream_tc; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
+/* Begin PBXFrameworksBuildPhase section */
+		CD93372A1E3CD79E00699FF5 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
 /* Begin PBXGroup section */
 		0E5DFDB91BB4D3190063976E = {
 			isa = PBXGroup;
 			children = (
-				0EB8334C1BBF45FD00DDC844 /* streams */,
-				0EB833531BBF45FD00DDC844 /* streams.cpp */,
-				0EB833541BBF45FD00DDC844 /* streams.hpp */,
+				CD9337381E3CD88A00699FF5 /* src */,
+				CD9337371E3CD88200699FF5 /* test */,
 				0E5DFDC01BB4D3190063976E /* Makefile */,
+				CD93372E1E3CD79E00699FF5 /* Products */,
 			);
 			sourceTree = "<group>";
 		};
@@ -44,30 +72,65 @@
 			path = streams;
 			sourceTree = "<group>";
 		};
+		CD93372E1E3CD79E00699FF5 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CD93372D1E3CD79E00699FF5 /* stream_tc */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		CD9337371E3CD88200699FF5 /* test */ = {
+			isa = PBXGroup;
+			children = (
+				CD9337271E3CD78B00699FF5 /* stream_tc.cpp */,
+				CD9337281E3CD78B00699FF5 /* stream.t.h */,
+			);
+			name = test;
+			sourceTree = "<group>";
+		};
+		CD9337381E3CD88A00699FF5 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				0EB8334C1BBF45FD00DDC844 /* streams */,
+				0EB833541BBF45FD00DDC844 /* streams.hpp */,
+			);
+			name = src;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
-/* Begin PBXLegacyTarget section */
-		0E5DFDBE1BB4D3190063976E /* stream */ = {
-			isa = PBXLegacyTarget;
-			buildArgumentsString = "$(ACTION)";
-			buildConfigurationList = 0E5DFDC21BB4D3190063976E /* Build configuration list for PBXLegacyTarget "stream" */;
+/* Begin PBXNativeTarget section */
+		CD93372C1E3CD79E00699FF5 /* stream_tc */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = CD9337321E3CD79E00699FF5 /* Build configuration list for PBXNativeTarget "stream_tc" */;
 			buildPhases = (
+				CD9337361E3CD81000699FF5 /* ShellScript */,
+				CD9337291E3CD79E00699FF5 /* Sources */,
+				CD93372A1E3CD79E00699FF5 /* Frameworks */,
+				CD93372B1E3CD79E00699FF5 /* CopyFiles */,
+			);
+			buildRules = (
 			);
-			buildToolPath = /usr/bin/make;
-			buildWorkingDirectory = /Users/samjaffe/Documents/Programming/XTools/misc/stream;
 			dependencies = (
 			);
-			name = stream;
-			passBuildSettingsInEnvironment = 1;
-			productName = stream;
+			name = stream_tc;
+			productName = stream_tc;
+			productReference = CD93372D1E3CD79E00699FF5 /* stream_tc */;
+			productType = "com.apple.product-type.tool";
 		};
-/* End PBXLegacyTarget section */
+/* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
 		0E5DFDBA1BB4D3190063976E /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
 				LastUpgradeCheck = 0720;
+				TargetAttributes = {
+					CD93372C1E3CD79E00699FF5 = {
+						CreatedOnToolsVersion = 7.2.1;
+					};
+				};
 			};
 			buildConfigurationList = 0E5DFDBD1BB4D3190063976E /* Build configuration list for PBXProject "stream" */;
 			compatibilityVersion = "Xcode 3.2";
@@ -77,14 +140,44 @@
 				en,
 			);
 			mainGroup = 0E5DFDB91BB4D3190063976E;
+			productRefGroup = CD93372E1E3CD79E00699FF5 /* Products */;
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				0E5DFDBE1BB4D3190063976E /* stream */,
+				CD93372C1E3CD79E00699FF5 /* stream_tc */,
 			);
 		};
 /* End PBXProject section */
 
+/* Begin PBXShellScriptBuildPhase section */
+		CD9337361E3CD81000699FF5 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+				"$(SRCROOT)/stream.t.h",
+			);
+			outputPaths = (
+				"$(SRCROOT)/stream_tc.cpp",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "cxxtestgen --error-printer -o stream_tc.cpp stream.t.h";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		CD9337291E3CD79E00699FF5 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CD9337351E3CD7B700699FF5 /* stream_tc.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
 /* Begin XCBuildConfiguration section */
 		0E5DFDBB1BB4D3190063976E /* Debug */ = {
 			isa = XCBuildConfiguration;
@@ -108,30 +201,79 @@
 			};
 			name = Release;
 		};
-		0E5DFDC31BB4D3190063976E /* Debug */ = {
+		CD9337331E3CD79E00699FF5 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				COPY_PHASE_STRIP = NO;
-				DEBUGGING_SYMBOLS = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "-";
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
-				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
-				OTHER_CFLAGS = "";
-				OTHER_LDFLAGS = "";
-				PRODUCT_NAME = stream;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				HEADER_SEARCH_PATHS = /usr/local/include/;
+				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
 			name = Debug;
 		};
-		0E5DFDC41BB4D3190063976E /* Release */ = {
+		CD9337341E3CD79E00699FF5 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				COPY_PHASE_STRIP = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				GCC_ENABLE_FIX_AND_CONTINUE = NO;
-				OTHER_CFLAGS = "";
-				OTHER_LDFLAGS = "";
-				PRODUCT_NAME = stream;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				HEADER_SEARCH_PATHS = /usr/local/include/;
+				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
 			name = Release;
 		};
@@ -147,11 +289,11 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		0E5DFDC21BB4D3190063976E /* Build configuration list for PBXLegacyTarget "stream" */ = {
+		CD9337321E3CD79E00699FF5 /* Build configuration list for PBXNativeTarget "stream_tc" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				0E5DFDC31BB4D3190063976E /* Debug */,
-				0E5DFDC41BB4D3190063976E /* Release */,
+				CD9337331E3CD79E00699FF5 /* Debug */,
+				CD9337341E3CD79E00699FF5 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;

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

@@ -1,80 +0,0 @@
-<?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>

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

@@ -4,10 +4,10 @@
 <dict>
 	<key>SchemeUserState</key>
 	<dict>
-		<key>stream.xcscheme</key>
+		<key>stream_tc.xcscheme</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>4</integer>
+			<integer>20</integer>
 		</dict>
 	</dict>
 	<key>SuppressBuildableAutocreation</key>
@@ -17,6 +17,11 @@
 			<key>primary</key>
 			<true/>
 		</dict>
+		<key>CD93372C1E3CD79E00699FF5</key>
+		<dict>
+			<key>primary</key>
+			<true/>
+		</dict>
 	</dict>
 </dict>
 </plist>

+ 0 - 72
streams.cpp

@@ -1,72 +0,0 @@
-#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; })
-#define fold(t, x, y, expr, init) stream::make_fold_t<t>([](t x, t y) { 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;
-}

+ 2 - 2
streams/filter.hpp

@@ -58,8 +58,8 @@ namespace stream {
       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()}; }
+      ::stream::iterator<T> begin() override { return ::stream::iterator<T>{new iterator{pred_, source_.begin()}};}
+      ::stream::iterator<T> end() override { return ::stream::iterator<T>{new iterator{pred_, source_.end()}}; }
     private:
       std::function<bool(T const&)> pred_;
       stream_base<T, B> source_;

+ 6 - 5
streams/join.hpp

@@ -51,7 +51,8 @@ namespace stream {
       private:
         void advance() {
           while (curr_ == end_ && start_ != finish_) {
-            mem_ = *(++start_);
+            if ( ++start_ == finish_ ) { break; }
+            mem_ = *start_;
             curr_ = mem_.begin();
             end_ = mem_.end();
           }
@@ -66,10 +67,10 @@ namespace stream {
       ~join_stream() override {}
       
       ::stream::iterator<T> begin() override {
-        return new iterator{source_.begin(), source_.end()};
+        return ::stream::iterator<T>{new iterator{source_.begin(), source_.end()}};
       }
       ::stream::iterator<T> end() override {
-        return new iterator{source_.end(), source_.end()};
+        return ::stream::iterator<T>{new iterator{source_.end(), source_.end()}};
       }
     private:
       stream_base<C, B> source_;
@@ -92,13 +93,13 @@ namespace stream {
     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));
+      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));
+      return join(std::forward<self>(*this)).map(func);
     }
   }
 }

+ 2 - 2
streams/map.hpp

@@ -42,8 +42,8 @@ namespace stream {
       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()}; }
+      ::stream::iterator<R> begin() override { return ::stream::iterator<R>{new iterator{fun_, source_.begin()}};}
+      ::stream::iterator<R> end() override { return ::stream::iterator<R>{new iterator{fun_, source_.end()}}; }
     private:
       std::function<R(T const&)> fun_;
       stream_base<T, B> source_;

+ 2 - 2
streams/source.hpp

@@ -20,8 +20,8 @@ namespace stream {
       explicit source_stream(C const& cont) : source_(cont) {}
       explicit 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()}; }
+      ::stream::iterator<value_type> begin() override { return ::stream::iterator<value_type>{new iterator{source_.begin()}}; }
+      ::stream::iterator<value_type> end() override { return ::stream::iterator<value_type>{new iterator{source_.end()}}; }
     private:
       C source_;
     };

+ 23 - 6
streams/streams.hpp

@@ -17,6 +17,12 @@ DELEGATE_ITERATOR_IMPL_BASE(impl)
 namespace stream {
   template <typename T>
   class iterator {
+  public:
+    using value_type = T;
+    using reference = value_type &;
+    using pointer = value_type *;
+    using difference_type = std::ptrdiff_t;
+    using iterator_category = std::forward_iterator_tag;
   public:
     explicit iterator(detail::iterator_impl<T>* impl) : impl_(impl) {}
     iterator(iterator const& other) : impl_(other.impl_->clone()) { }
@@ -55,14 +61,26 @@ namespace stream {
       virtual ::stream::iterator<T> end() = 0;
     };
     
+    template <typename T, typename = void>
+    struct has_value_type {
+      template <typename F>
+      using flatmap_f = void;
+    };
+    
+    template <typename T>
+    struct has_value_type<T, typename std::enable_if<!std::is_void<typename T::value_type>::value>::type> {
+      template <typename F>
+      using flatmap_f = decltype(std::declval<F>()(std::declval<typename T::value_type>()));
+    };
+    
     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 flatmap_f = typename has_value_type<T>::template flatmap_f<F>;
+
       using self = stream_base<T, Own>;
     public:
       explicit stream_base(stream_impl<T>* impl) : impl_(impl) {}
@@ -77,10 +95,9 @@ namespace stream {
         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));
+      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;
       }