Browse Source

Perform some cleanup on either-stream.
Apply clang-format to the code.

Sam Jaffe 5 years ago
parent
commit
81c93c4cb6
3 changed files with 212 additions and 89 deletions
  1. 108 0
      .clang-format
  2. 85 66
      include/stream/either_stream.hpp
  3. 19 23
      test/either_stream_test.cxx

+ 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
+...
+

+ 85 - 66
include/stream/either_stream.hpp

@@ -8,83 +8,102 @@
 #pragma once
 
 #include <type_traits>
-
-#if __cplusplus > 201402L
 #include <variant>
-template <typename T, typename E>
-using either = std::variant<T, E>;
-#else
-#include "variant/variant.hpp"
-template <typename T, typename E>
-using either = variant<T, E>;
-#endif
+
+template <typename T, typename E> using either = std::variant<T, E>;
+
+namespace stream {
+  template <typename T> class either_stream;
+
+  template <typename T> struct either_left;
+  template <typename T, typename E> struct either_left<::either<T, E>> {
+    using type = T;
+  };
+
+  template <typename T> using either_left_t = typename either_left<T>::type;
+
+  template <typename T, typename E> class either_stream<::either<T, E>> {
+  private:
+    template <typename F, typename T2 = T>
+    using map_f = decltype(std::declval<F>()(std::declval<T2>()));
+
+    template <typename F, typename T2 = T>
+    using flatmap_f = either_left_t<map_f<F, T2>>;
+
+  private:
+    ::either<T, E> value_;
+
+  public:
+    either_stream(E const & v) : value_(v) {}
+    either_stream(E && v) : value_(std::forward<E>(v)) {}
+
+    either_stream(T const & v) : value_(v) {}
+    either_stream(T && v) : value_(std::forward<T>(v)) {}
+    either_stream(::either<T, E> const & v) : value_(v) {}
+    either_stream(::either<T, E> && v)
+        : value_(std::forward<::either<T, E>>(v)) {}
+
+    template <typename F>
+    either_stream<::either<map_f<F>, E>> map(F && fun) const {
+      using next_t = either_stream<::either<map_f<F>, E>>;
+      return value_.index() == 0 ? next_t{fun(std::get<0>(value_))}
+                                 : next_t{std::get<1>(value_)};
+    }
+
+    template <typename F>
+    either_stream<::either<flatmap_f<F>, E>> flatmap(F && fun) const {
+      using next_t = either_stream<::either<flatmap_f<F>, E>>;
+      return value_.index() == 0 ? next_t{fun(std::get<0>(value_))}
+                                 : next_t{std::get<1>(value_)};
+    }
+
+    template <typename FT, typename FE,
+              typename = typename std::enable_if<
+                  !(std::is_void<map_f<FT>>::value &&
+                    std::is_void<map_f<FE, E>>::value)>::type>
+    typename std::common_type<map_f<FT>, map_f<FE, E>>::type
+    match(FT && left, FE && right) {
+      return value_.index() == 0 ? left(std::get<0>(value_))
+                                 : right(std::get<1>(value_));
+    }
+
+    template <typename FT, typename FE,
+              typename = typename std::enable_if<
+                  std::is_void<map_f<FT>>::value &&
+                  std::is_void<map_f<FE, E>>::value>::type>
+    void match(FT && left, FE && right) {
+      value_.index() == 0 ? left(std::get<0>(value_))
+                          : right(std::get<1>(value_));
+    }
+
+    ::either<T, E> const & value() const { return value_; }
+  };
+}
 
 namespace stream { namespace either {
-  namespace detail {
-    template <typename T> class either_stream;
-    
-    template <typename T> struct either_left;
-    template <typename T, typename E>
-    struct either_left<::either<T, E>> { using type = T; };
-    
-    template <typename T, typename E>
-    class either_stream<::either<T, E>> {
-    private:
-      template <typename F, typename T2>
-      using map_f = decltype(std::declval<F>()(std::declval<T2>()));
-      
-      template <typename F, typename T2>
-      using flatmap_f = typename either_left<decltype(std::declval<F>()(std::declval<T2>()))>::type;
-
-    public:
-      either_stream(E const & v) : value_(v) {}
-      either_stream(E && v) : value_(std::forward<E>(v)) {}
-      
-      either_stream(T const & v) : value_(v) {}
-      either_stream(T && v) : value_(std::forward<T>(v)) {}
-      either_stream(::either<T, E> const & v) : value_(v) {}
-      either_stream(::either<T, E> && v) : value_(std::forward<::either<T, E>>(v)) {}
-      
-      template <typename F>
-      either_stream<::either<map_f<F, T>, E>> map(F && fun) const {
-        using next_t = either_stream<::either<map_f<F, T>, E>>;
-        return value_.index() == 0 ? next_t{fun(std::get<0>(value_))} : next_t{std::get<1>(value_)};
-      }
-      
-      template <typename F>
-      either_stream<::either<flatmap_f<F, T>, E>> flatmap(F && fun) const {
-        using next_t = either_stream<::either<flatmap_f<F, T>, E>>;
-        return value_.index() == 0 ? next_t{fun(std::get<0>(value_))} : next_t{std::get<1>(value_)};
-      }
-      
-      template <typename FT, typename FE, typename = typename std::enable_if<!(std::is_void<map_f<FT, T>>::value && std::is_void<map_f<FE, E>>::value)>::type>
-      typename std::common_type<map_f<FT, T>, map_f<FE, E>>::type match(FT && left, FE && right) {
-        return value_.index() == 0 ? left(std::get<0>(value_)) : right(std::get<1>(value_));
-      }
-
-      template <typename FT, typename FE, typename = typename std::enable_if<std::is_void<map_f<FT, T>>::value && std::is_void<map_f<FE, E>>::value>::type>
-      void match(FT && left, FE && right) {
-        value_.index() == 0 ? left(std::get<0>(value_)) : right(std::get<1>(value_));
-      }
-      
-      ::either<T, E> const & value() const { return value_; }
-    private:
-      ::either<T, E> value_;
-    };
-  }
-  
+  /**
+   * Construct a stream from the given type while explicitly providing both the
+   * type and the error class
+   */
   template <typename T, typename E>
-  auto make_stream(T const & opt) -> detail::either_stream<::either<T, E>> {
+  auto make_stream(T const & opt) -> either_stream<::either<T, E>> {
     return {{opt}};
   }
 
+  /**
+   * Construct a stream from the given type where the real type is an inferred
+   * property
+   */
   template <typename E, typename T>
-  auto make_stream(T const & opt) -> detail::either_stream<::either<T, E>> {
+  auto make_stream(T const & opt) -> either_stream<::either<T, E>> {
     return {{opt}};
   }
 
+  /**
+   * Construct a stream with the given either-type as a template parameter.
+   */
   template <typename E>
-  auto make_stream(typename detail::either_left<E>::type const & opt) -> detail::either_stream<E> {
+  auto make_stream(either_left_t<E> const & opt) -> either_stream<E> {
     return {{opt}};
   }
-} }
+}}

+ 19 - 23
test/either_stream_test.cxx

@@ -5,16 +5,12 @@
 //  Created by Sam Jaffe on 1/30/17.
 //
 
-#include <gmock/gmock.h>
 #include <cmath>
+#include <gmock/gmock.h>
 
 #include "stream/either_stream.hpp"
 
-enum class MathError {
-  OutOfBounds,
-  DivideByZero,
-  DomainError
-};
+enum class MathError { OutOfBounds, DivideByZero, DomainError };
 
 using MathObject = either<double, MathError>;
 
@@ -40,34 +36,34 @@ using ::testing::DoubleNear;
 using ::testing::Eq;
 
 TEST(EitherStreamTest, ContainsErrorValue) {
-  auto strm = stream::either::make_stream<MathObject>(1.0)
-      .flatmap([](double d) { return divide(d, 0); });
-  
+  auto strm = stream::either::make_stream<MathObject>(1.0).flatmap(
+      [](double d) { return divide(d, 0); });
+
   EXPECT_THAT(strm.value().index(), Eq(1));
   EXPECT_THAT(std::get<MathError>(strm.value()), Eq(MathError::DivideByZero));
 }
 
 TEST(EitherStreamTest, ErrorValueMatchesToErrorHandler) {
   auto bad_value = [](double) { throw std::logic_error("Expected error"); };
-  auto strm = stream::either::make_stream<MathObject>(1.0)
-      .flatmap([](double d) { return divide(d, 0); });
-  
+  auto strm = stream::either::make_stream<MathObject>(1.0).flatmap(
+      [](double d) { return divide(d, 0); });
+
   EXPECT_NO_THROW(strm.match(bad_value, [](MathError e) {}));
 }
 
 TEST(EitherStreamTest, ConcreteValueMatchesToConreteHandler) {
   auto bad_error = [](MathError) { throw std::logic_error("Expected value"); };
-  auto strm = stream::either::make_stream<MathObject>(1.0)
-      .map([](double d) { return multiply(d, 10.0); });
-  
+  auto strm = stream::either::make_stream<MathObject>(1.0).map(
+      [](double d) { return multiply(d, 10.0); });
+
   EXPECT_NO_THROW(strm.match([](double d) {}, bad_error));
 }
 
 TEST(EitherStreamTest, ErrorPropogatesBypassingMap) {
   auto bad_value = [](double) { throw std::logic_error("Expected error"); };
-  auto strm = stream::either::make_stream<MathObject>(1.0)
-      .flatmap([](double d) { return divide(d, 0); });
-  
+  auto strm = stream::either::make_stream<MathObject>(1.0).flatmap(
+      [](double d) { return divide(d, 0); });
+
   EXPECT_NO_THROW(strm = strm.map([](double) {
     throw std::runtime_error("Mapping while invalid");
     return 0.0;
@@ -76,14 +72,14 @@ TEST(EitherStreamTest, ErrorPropogatesBypassingMap) {
 }
 
 TEST(EitherStreamTest, ErrorPropogatesBypassingFlatmap) {
-  auto ex = stream::either::make_stream<MathObject>(1.0)
-      .flatmap([](double d) { return log(0.0, d); });
+  auto ex = stream::either::make_stream<MathObject>(1.0).flatmap(
+      [](double d) { return log(0.0, d); });
   EXPECT_THAT(std::get<MathError>(ex.value()), Eq(MathError::DomainError));
 
-  auto strm = stream::either::make_stream<MathObject>(1.0)
-      .flatmap([](double d) { return log(1.0, d); });
+  auto strm = stream::either::make_stream<MathObject>(1.0).flatmap(
+      [](double d) { return log(1.0, d); });
   EXPECT_THAT(std::get<MathError>(strm.value()), Eq(MathError::DivideByZero));
-  
+
   strm = strm.flatmap([](double d) { return log(0.0, d); });
   EXPECT_THAT(std::get<MathError>(strm.value()), Eq(MathError::DivideByZero));
 }