├── include ├── .ignore ├── fpcpp.h ├── fp_composition_compound.h ├── fp_prelude.h ├── fp_prelude_infix.h ├── fp_maybe.h ├── fp_prelude_objects.h ├── fp_composition.h ├── fp_defines.h ├── fp_io.h ├── fp_curry_defines.h ├── fp_prelude_strings.h ├── fp_common.h ├── fp_prelude_math.h ├── fp_curry.h ├── fp_template_utils.h ├── fp_composition_utils.h ├── fp_prelude_lazy.h └── fp_prelude_lists.h ├── samples ├── .gitignore ├── CMakeLists.txt ├── benchmark_common.h ├── simple.cpp ├── game_of_life.cpp ├── composition.cpp ├── sudoku.cpp ├── euler.cpp ├── timer.h ├── benchmarks.cpp ├── playlist.cpp ├── flocking.cpp ├── fun.cpp └── benchmark.cpp ├── tests ├── .gitignore ├── CMakeLists.txt ├── common.h └── fp_test.cpp ├── .gitignore ├── LICENSE ├── .gitmodules ├── INSTALL.md ├── README.md ├── externals └── rapidxml │ ├── rapidxml_utils.hpp │ ├── rapidxml_iterators.hpp │ └── rapidxml_print.hpp └── CMakeLists.txt /include/.ignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /samples/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /bin 3 | /build_64 4 | /TAGS 5 | /build_64_11 6 | /build_clang64 7 | /build_mingw -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Jared Duke. 2 | 3 | This code is released under the MIT License. 4 | 5 | www.opensource.org/licenses/mit-license.php -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "externals/tthread"] 2 | path = externals/tthread 3 | url = git://github.com/jdduke/tthread.git 4 | [submodule "externals/googletest"] 5 | path = externals/googletest 6 | url = git@github.com:jdduke/googletest.git 7 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | enable_testing(true) 2 | 3 | include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) 4 | 5 | add_executable(fpTest fp_test.cpp) 6 | target_link_libraries(fpTest gtest gtest_main) 7 | add_test(testFp fpTest) 8 | -------------------------------------------------------------------------------- /samples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(fpFun fun.cpp) 2 | add_executable(fpGameOfLife game_of_life.cpp) 3 | add_executable(fpFlocking flocking.cpp) 4 | add_executable(fpComposition composition.cpp) 5 | add_executable(fpBenchmarks benchmarks.cpp) 6 | add_executable(fpBenchmark benchmark.cpp) 7 | add_executable(fpPlaylist playlist.cpp) 8 | add_executable(fpSimple simple.cpp) 9 | add_executable(fpEuler euler.cpp) 10 | add_executable(fpSudoku sudoku.cpp) 11 | -------------------------------------------------------------------------------- /include/fpcpp.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FPCPP_H_ 8 | #define _FPCPP_H_ 9 | 10 | #include "fp_defines.h" 11 | #include "fp_common.h" 12 | 13 | #include "fp_prelude.h" 14 | #include "fp_prelude_lists.h" 15 | #include "fp_prelude_lazy.h" 16 | #include "fp_prelude_math.h" 17 | #include "fp_prelude_strings.h" 18 | #include "fp_prelude_objects.h" 19 | //#include "fp_prelude_infix.h" 20 | 21 | #include "fp_curry.h" 22 | 23 | #include "fp_composition.h" 24 | #include "fp_composition_compound.h" 25 | 26 | #include "fp_io.h" 27 | 28 | #include "fp_maybe.h" 29 | 30 | #endif /* _FPCPP_H_ */ 31 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | FunctionalProgrammingWithCPP 2 | ============================ 3 | 4 | Usage 5 | ----- 6 | 7 | fpcpp is a header-only library; just include and forget. All relevant functions and structures live 8 | within the fp namespace. 9 | 10 | Compilation 11 | -------- 12 | fpcpp itself requires no compilation: it is header-only. All that is required is support for a certain 13 | subset of C++11 functionality. It was developed with VC10 support at the minimum; variadic 14 | templates are used where supported, as well as other C++11 features that significantly reduce 15 | the code necessary to achieve the basic functionality. 16 | 17 | 18 | Samples 19 | ------- 20 | 21 | To come. 22 | 23 | Tests 24 | ----- 25 | 26 | Tests are also built using CMake, and are dependent on the google unit testing framework (http://code.google.com/p/googletest/) 27 | Several options for building are documented within CMake itself, make sure BUILD_TESTS is enabled. 28 | These were not meant as exhaustive unit tests; they are primarily to 29 | 1) test compilation 30 | 2) verify basic functionality 31 | 3) provide some simple examples of usage 32 | 33 | 34 | fpcppTest - Contains all tests -------------------------------------------------------------------------------- /samples/benchmark_common.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _BENCHMARK_COMMON_H_ 8 | #define _BENCHMARK_COMMON_H_ 9 | 10 | #include "timer.h" 11 | 12 | #if defined(_DEBUG) 13 | #define ITER_MULT 1 14 | #else 15 | #define ITER_MULT 2 16 | #endif 17 | 18 | #if !defined(ENABLE_BENCHMARK) 19 | #define ENABLE_BENCHMARK 1 20 | #endif 21 | 22 | #if ENABLE_BENCHMARK 23 | #define BENCHMARK(desc,func,iters) { \ 24 | timed_run timed(desc); \ 25 | for (size_t i = 0; i < iters; ++i) { \ 26 | func; \ 27 | } \ 28 | } 29 | 30 | #define run_impl(func,iters) BENCHMARK(#func,func,iters) 31 | #define run(func,iters) run_impl(func,iters) 32 | #else 33 | #define run(func,iters) { fp::print(#func); let result = func; fp::print(result); fp::print("");} typedef int FP_CONCAT(RETURNS_,__LINE__) 34 | #endif 35 | 36 | #endif /* _BENCHMARK_COMMON_H_ */ 37 | -------------------------------------------------------------------------------- /samples/simple.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void simple(); 6 | 7 | int main(int argc, char** argv) { 8 | 9 | simple(); 10 | 11 | return 0; 12 | 13 | } 14 | 15 | 16 | #if defined(_MSC_VER) 17 | template 18 | typename std::add_rvalue_reference::type declval(); 19 | #endif 20 | 21 | template 22 | struct Wrapper { 23 | Wrapper(F f, G g): mF(f), mG(g) { } 24 | 25 | #if !defined(_MSC_VER) 26 | 27 | template< typename... Args > 28 | inline auto operator()(Args... args) -> decltype(std::declval()(std::declval()(args...))) { 29 | return mF(mG(args...)); 30 | } 31 | 32 | #else 33 | 34 | template< typename Arg0 > 35 | inline auto operator()(Arg0 arg0) -> decltype(declval()(declval()(arg0))) { 36 | return mF(mG(arg0)); 37 | } 38 | 39 | template< typename Arg0, typename Arg1 > 40 | inline auto operator()(Arg0 arg0, Arg1 arg1) -> decltype(declval()(declval()(arg0,arg1))) { 41 | return mF(mG(arg0, arg1)); 42 | } 43 | 44 | template< typename Arg0, typename Arg1, typename Arg2 > 45 | inline auto operator()(Arg0 arg0, Arg1 arg1, Arg2 arg2) -> decltype(declval()(declval()(arg0, arg1, arg2))) { 46 | return mF(mG(arg0, arg1, arg2)); 47 | } 48 | 49 | #endif 50 | 51 | F mF; 52 | G mG; 53 | }; 54 | 55 | template< typename F, typename G > 56 | Wrapper compose(F f, G g) { 57 | return Wrapper(f, g); 58 | } 59 | 60 | void simple() { 61 | 62 | std::cout << compose(sinf, asinf)(0.5f) << std::endl; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /include/fp_composition_compound.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_COMPOSITION_COMPOUND_H_ 8 | #define _FP_COMPOSITION_COMPOUND_H_ 9 | 10 | #include "fp_defines.h" 11 | 12 | namespace fp { 13 | 14 | /////////////////////////////////////////////////////////////////////////// 15 | 16 | template 17 | class composed2 : public composed { 18 | public: 19 | typedef composed parent_type; 20 | typedef composed2 this_type; 21 | 22 | explicit composed2(F f_, G0 g_, G1 g1_) 23 | : composed(f_,g_), g1(g1_) { } 24 | explicit composed2(F&& f_, G0&& g_, G1&& g1_) 25 | : composed(std::forward(f_),std::forward(g_)), g1(std::forward(g1_)) { } 26 | 27 | template 28 | inline auto operator()(const T0& t0, const T1& t1) 29 | -> decltype(declval()(declval()(declval()), declval()(declval()))) { 30 | return this->f(this->g(t0), this->g1(t1)); 31 | } 32 | 33 | protected: 34 | composed2(); 35 | 36 | G1 g1; 37 | }; 38 | 39 | 40 | /////////////////////////////////////////////////////////////////////////// 41 | 42 | template 43 | inline composed2 compose2(F f, G0 g0, G1 g1) { 44 | return composed2(f, g0, g1); 45 | } 46 | 47 | /////////////////////////////////////////////////////////////////////////// 48 | 49 | } /* namespace fp */ 50 | 51 | #endif /* _FP_COMPOSITION_COMPOUND_H_ */ 52 | -------------------------------------------------------------------------------- /samples/game_of_life.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #if WIN32 13 | #include 14 | inline void idle(DWORD milliseconds) { Sleep(milliseconds); } 15 | #else 16 | #include 17 | inline void idle(size_t microseconds) { usleep(microseconds*1000); } 18 | #endif 19 | 20 | template 21 | C life(const C& grid, size_t x, size_t y) { 22 | using namespace fp; 23 | const let size = x * y; 24 | return map([=,&grid](size_t i) -> value_type_of(C) { 25 | const let neighbors = grid[(i-x-1)%size] + grid[(i-x)%size] + grid[(i-x+1)%size] + 26 | grid[(i -1)%size] + grid[(i +1)%size] + 27 | grid[(i+x-1)%size] + grid[(i+x)%size] + grid[(i+x+1)%size]; 28 | return ((grid[i]==1 && (neighbors==2 || neighbors==3)) || (grid[i]==0 && neighbors == 3)) ? 1 : 0; 29 | }, (0 x*y-1)); 30 | } 31 | 32 | int main(int argc, char **argv) { 33 | 34 | srand((unsigned)time((time_t*)NULL)); 35 | 36 | enum { 37 | X = 80, 38 | Y = 20, 39 | }; 40 | 41 | let grid = fp::map([](float f) { return f < 0.f ? 0 : 1; }, 42 | fp::uniformN(X*Y, -1.f, 1.f)); 43 | 44 | while (true) { 45 | grid = life(grid, X, Y); 46 | size_t i = 0; 47 | std::stringstream ss; 48 | let showGrid = [=,&ss](int x) mutable { 49 | if(i++ % X == 0) 50 | ss << std::endl; 51 | const char c = (x ? 'X' : ' '); 52 | ss << c; 53 | }; 54 | fp::mapV(showGrid, grid); 55 | std::cout << ss.str(); 56 | } 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /include/fp_prelude.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.Phip 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_PRELUDE_H_ 8 | #define _FP_PRELUDE_H_ 9 | 10 | #include "fp_defines.h" 11 | #include "fp_common.h" 12 | #include "fp_composition.h" 13 | #include "fp_composition_compound.h" 14 | 15 | namespace fp { 16 | 17 | /////////////////////////////////////////////////////////////////////////// 18 | // succ 19 | template 20 | inline T succ(const T& t) { 21 | return static_cast(t + 1); 22 | } 23 | 24 | /////////////////////////////////////////////////////////////////////////// 25 | // succ 26 | template 27 | inline T pred(const T& t) { 28 | return static_cast(t - 1); 29 | } 30 | 31 | /////////////////////////////////////////////////////////////////////////// 32 | // comparing 33 | 34 | #if 0 35 | 36 | template 37 | inline auto comparing(F f) FP_RETURNS( fp::compose2(std::less(), f, f) ); 38 | 39 | #else 40 | 41 | template 42 | struct comparing_helper { 43 | comparing_helper(F f_) : f(f_) { } 44 | 45 | template 46 | inline bool operator()(const T& u, const T& v) { 47 | return f(u) < f(v); 48 | } 49 | 50 | F f; 51 | }; 52 | 53 | template 54 | inline comparing_helper comparing(F f) { 55 | return comparing_helper(f); 56 | } 57 | 58 | #endif /* FP_COMPOUND */ 59 | 60 | /////////////////////////////////////////////////////////////////////////// 61 | // flip 62 | 63 | template 64 | inline auto flip(F f) FP_RETURNS( std::bind(f, std::placeholders::_2, std::placeholders::_1) ); 65 | 66 | //RETURNS( [=](const argument_type_of(F,1) & v, const argument_type_of(F,0) & u) { return f(u,v); } ); 67 | 68 | } /* namespace fp */ 69 | 70 | #endif /* _FP_PRELUDE_H_ */ 71 | -------------------------------------------------------------------------------- /tests/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _FC_TEST_COMMON_H_ 2 | #define _FC_TEST_COMMON_H_ 3 | 4 | #define f(f_) fp::make_function(f_) 5 | 6 | inline void Void_Void () { } 7 | struct S_Void_Void{ void operator()() { }; }; 8 | auto L_Void_Void = []() { }; 9 | 10 | inline float Float_Void () { return 1.f; } 11 | struct S_Float_Void { float operator()() { return Float_Void(); } }; 12 | auto L_Float_Void = []() { return Float_Void(); }; 13 | 14 | inline void Void_Float (float x) { x = 1.f; } 15 | struct S_Void_Float { void operator()(float x) { Void_Float(x); } }; 16 | auto L_Void_Float = [](float x) { Void_Float(x); }; 17 | 18 | inline void Void_Float2 (float x, float y) { Void_Float(x); Void_Float(y); } 19 | struct S_Void_Float2 { void operator()(float x, float y) { Void_Float2(x,y); } }; 20 | auto L_Void_Float2 = [](float x, float y) { Void_Float2(x,y); }; 21 | 22 | inline float Float_Float (float x) { return x; } 23 | struct S_Float_Float { float operator()(float x) { return Float_Float(x); } }; 24 | auto L_Float_Float = [](float x) { return Float_Float(x); }; 25 | 26 | inline float Float_Float2 (float x, float y) { return x + y; } 27 | struct S_Float_Float2 { float operator()(float x, float y) { return Float_Float2(x,y); } }; 28 | auto L_Float_Float2 = [](float x, float y) { return Float_Float2(x,y); }; 29 | 30 | inline float Float_Float3 (float x, float y, float z) { return x + y + z; } 31 | struct S_Float_Float3 { float operator()(float x, float y, float z) { return Float_Float3(x,y,z); } }; 32 | auto L_Float_Float3 = [](float x, float y, float z) { return Float_Float3(x,y,z); }; 33 | 34 | inline float Float_Float4 (float x, float y, float z, float w) { return x + y + z + w; } 35 | struct S_Float_Float4 { float operator()(float x, float y, float z, float w) { return Float_Float4(x,y,z,w); } }; 36 | auto L_Float_Float4 = [](float x, float y, float z, float w) { return Float_Float4(x,y,z,w); }; 37 | 38 | auto add_2 = [](float x) { return x + 2; }; 39 | auto sub_3 = [](double x) { return x - 3; }; 40 | auto mult_4 = [](int x) { return x * 4; }; 41 | auto div_5 = [](int x) { return x / 5.f; }; 42 | 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /samples/composition.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | template void print(const char* prefix, const T& result) { 16 | std::cout << prefix << result << std::endl; 17 | } 18 | 19 | void test() { 20 | 21 | using namespace fp; 22 | using namespace fp_operators; 23 | 24 | /////////////////////////////////////////////////////////////////////////// 25 | 26 | { 27 | auto g = [](float x, float y, float z) -> float { return x*x + y*y + z*z; }; 28 | auto f = [](float l2) -> float { return std::sqrt(l2); }; 29 | auto fg = compose(f, g); 30 | auto fg2 = f< float { return std::sqrt(l2); } 32 | + [](float x, float y, float z) -> float { return x*x + y*y + z*z; }; 33 | auto fg4 = compose([](float l2) -> float { return std::sqrt(l2); }, 34 | [](float x, float y, float z) -> float { return x*x + y*y + z*z; }); 35 | 36 | float v[] = {1.f, 2.f, -1.f}; 37 | 38 | /////////////////////////////////////////////////////////////////////////// 39 | 40 | print( "Length (compose(f,g)) = ", fg( v[0], v[1], v[2]) ); 41 | print( "Length (f+g) = ", fg2( v[0], v[1], v[2]) ); 42 | print( "Length (f_lam + g_lam) = ", fg3( v[0], v[1], v[2]) ); 43 | print( "Length (compose(f_lam,g_lam)) = ", fg4( v[0], v[1], v[2]) ); 44 | print( "Length = ", fg( v[0], v[1], v[2]) ); 45 | } 46 | } 47 | 48 | void test2() { 49 | using namespace fp; 50 | using namespace fp::math; 51 | 52 | let square = [](float x) { return x*x; }; 53 | 54 | let l1 = fp::compose2(addF(), absF(), absF()); 55 | print( l1(1.f, -2.f) == 3.f ); 56 | 57 | let l2 = compose(sqrtF(), compose2(addF(), square, square)); 58 | print( l2(3.f, 4.f) == 5.f ); 59 | 60 | //let test = 5 10; 61 | } 62 | 63 | int main(int argc, char** argv) { 64 | 65 | test(); 66 | 67 | test2(); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /include/fp_prelude_infix.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_PRELUDE_INFIX_H_ 8 | #define _FP_PRELUDE_INFIX_H_ 9 | 10 | #include "fpcpp.h" 11 | 12 | #define FP_DEFINE_FUNCTION_INFIX_HELPER(func) \ 13 | static struct FP_CONCAT(__infixHelper,func) { } FP_CONCAT(func,_i); \ 14 | template struct FP_CONCAT(func, __Value) { \ 15 | FP_CONCAT(func, __Value) (T t) : mValue(t) { } \ 16 | T mValue; \ 17 | }; 18 | 19 | #define FP_DEFINE_FUNCTION_INFIX_HELPER_OPERATORS(func) \ 20 | template \ 21 | inline auto operator>(FP_CONCAT(func,__Value) t0, T1 t1) FP_RETURNS( func(t0.mValue, t1) ); \ 22 | template \ 23 | inline auto operator<(T0 t0, FP_CONCAT(__infixHelper,func)) FP_RETURNS( FP_CONCAT(func,__Value) (t0) ); 24 | 25 | 26 | #define FP_DEFINE_FUNCTION_INFIX(func) \ 27 | FP_DEFINE_FUNCTION_INFIX_HELPER(func) \ 28 | FP_DEFINE_FUNCTION_INFIX_HELPER_OPERATORS(func) 29 | 30 | namespace fp { 31 | 32 | /////////////////////////////////////////////////////////////////////////// 33 | // common 34 | 35 | /////////////////////////////////////////////////////////////////////////// 36 | // prelude 37 | 38 | /////////////////////////////////////////////////////////////////////////// 39 | // math 40 | 41 | namespace math { 42 | 43 | FP_DEFINE_FUNCTION_INFIX(add); 44 | FP_DEFINE_FUNCTION_INFIX(subtract); 45 | FP_DEFINE_FUNCTION_INFIX(divide); 46 | FP_DEFINE_FUNCTION_INFIX(multiply); 47 | FP_DEFINE_FUNCTION_INFIX(mod); 48 | FP_DEFINE_FUNCTION_INFIX(logicalAnd); 49 | FP_DEFINE_FUNCTION_INFIX(logicalOr); 50 | FP_DEFINE_FUNCTION_INFIX(logicalNot); 51 | FP_DEFINE_FUNCTION_INFIX(equals); 52 | FP_DEFINE_FUNCTION_INFIX(notEquals); 53 | FP_DEFINE_FUNCTION_INFIX(greaterEquals); 54 | FP_DEFINE_FUNCTION_INFIX(greater); 55 | FP_DEFINE_FUNCTION_INFIX(lessEquals); 56 | FP_DEFINE_FUNCTION_INFIX(less); 57 | } 58 | 59 | } /* namespace fp */ 60 | 61 | #undef FP_DEFINE_FUNCTION_INFIX_HELPER_OPERATORS 62 | #undef FP_DEFINE_FUNCTION_INFIX_HELPER 63 | #undef FP_DEFINE_FUNCTION_INFIX 64 | 65 | #endif /* _FP_PRELUDE_INFIX_H_ */ 66 | -------------------------------------------------------------------------------- /samples/sudoku.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "fpcpp.h" 8 | 9 | #include 10 | 11 | #define ENABLE_BENCHMARK 1 12 | #include "benchmark_common.h" 13 | 14 | using namespace fp; 15 | 16 | /////////////////////////////////////////////////////////////////////////// 17 | 18 | typedef types::list strings; 19 | 20 | strings cross( const string& s0, const string& s1 ) { 21 | types::list result; 22 | for( size_t i = 0; i < s0.size(); ++i ) { 23 | for ( size_t j = 0; j < s1.size(); ++j ) { 24 | result.emplace_back( cons(show(s0[i]), show(s1[j])) ); 25 | } 26 | } 27 | return result; 28 | } 29 | 30 | auto mapCross( const strings& s0, const strings& s1 ) -> strings { 31 | types::list result; 32 | for( size_t i = 0; i < s0.size(); ++i ) { 33 | for ( size_t j = 0; j < s1.size(); ++j ) { 34 | auto r = cross( s0[i], s0[j] ); 35 | result.insert( end(result), extent(r) ); 36 | } 37 | } 38 | return result; 39 | }; 40 | 41 | auto mapCrossInner(const string& s0, const string& s1) -> strings { 42 | strings result; 43 | for(size_t i = 0; i < s0.size(); ++i) { 44 | auto r = cross(s1, show(s0[i])); 45 | result.insert( end(result), extent(r) ); 46 | } 47 | return result; 48 | }; 49 | 50 | /////////////////////////////////////////////////////////////////////////// 51 | 52 | static const let digits = show("123456789"); 53 | static const let rows = show("ABCDEFGHI"); 54 | static const let cols = digits; 55 | static const let squares = cross(rows, cols); 56 | static const let unitlist = concat( concat( mapCrossInner(cols, rows), 57 | mapCrossInner(rows, cols) ), 58 | mapCross( cons(show("ABC"), cons(show("DEF"), cons(show("GHI"), strings()))), 59 | cons(show("123"), cons(show("456"), cons(show("789"), strings()))) ) ); 60 | 61 | /////////////////////////////////////////////////////////////////////////// 62 | 63 | int main(int argc, char **argv) { 64 | 65 | using namespace fp; 66 | 67 | print( "" ); 68 | 69 | /////////////////////////////////////////////////////////////////////////// 70 | 71 | 72 | #if defined(_MSC_VER) 73 | static const std::string filePrefix( "./../../../samples" ); 74 | #else 75 | static const std::string filePrefix( "./../../samples" ); 76 | #endif 77 | 78 | //run( ); 79 | print( "" ); 80 | 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fpcpp 2 | =========================== 3 | 4 | fpcpp (functional programming in C++) is a lightweight, header-based C++ library for enabling functional programming style and features 5 | in modern C++ programs. 6 | 7 | 8 | Example 9 | ------------- 10 | 11 | Generate pi using Monte Carlo sampling: 12 | 13 | double pi(size_t samples = 1000) { 14 | 15 | return 4.0 * length(filter([](double d) { return d <= 1.0; }, 16 | map([](const pair& p) { return fst(p)*fst(p) + snd(p)*snd(p); }, 17 | zip(take(samples, uniform(-1.0,1.0)), 18 | take(samples, uniform(-1.0,1.0))))) / samples; 19 | 20 | } 21 | or 22 | 23 | double pi(size_t samples = 1000) { 24 | 25 | let sampler = []() -> int { 26 | let x = uniform(-1.,1.); 27 | let y = uniform(-1.,1.); 28 | let dist2 = x*x + y*y; 29 | return dist2 < 1. ? 1 : 0; 30 | }; 31 | 32 | return 4. * foldl1(addF(), take(samples, sampler)) / samples; 33 | 34 | } 35 | 36 | Map an operation across a filtered source and check for success: 37 | 38 | template { 39 | bool filteredMap(SuccessOp, MapOp mapOp, FilterOp filterOp, Source source) { 40 | using namespace fp; 41 | return all(successOp, 42 | map(mapOp, 43 | filter(filterOp, 44 | source))); 45 | 46 | Curry functions: 47 | 48 | let multiplyBy4 = curry(multiplyF()), 4); 49 | let twentyEight = multiplyBy4(7); 50 | 51 | Compose functions: 52 | 53 | // l1 norm = |x|+|y| = f(g(x),g(y)) where f = add, g = abs 54 | 55 | let l1 = compose2(addF(), absF(), absF()); 56 | assert( l1(1.f, -2.f) == 3.f ); 57 | 58 | 59 | // l2 norm = sqrt(x*x + y*y) = f(g(h(x),h(y))) where f = sqrt, g = plus, h = square 60 | 61 | let square = [](float x) { return x*x; }; 62 | let l2 = compose(sqrtf, compose2(addF(), square, square)); 63 | assert( l2(3.f, 4.f) == 5.f ); 64 | 65 | 66 | 67 | Documentation 68 | ------------- 69 | 70 | Please see the file called INSTALL for usage details. 71 | Several samples and tests are included with the source; together with CMake, these can be built and run 72 | with any compatible compiler (developed with VC10, tested on GCC 4.6). 73 | 74 | Licensing 75 | --------- 76 | 77 | MIT. 78 | Please see the file called LICENSE. 79 | 80 | Contributions 81 | ------------- 82 | 83 | This project was directly inspired by late-night encounters with Haskell. FC++ (http://sourceforge.net/projects/fcpp/) 84 | is an excellent library for pre-C++11 functional programming endeavors. -------------------------------------------------------------------------------- /samples/euler.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #include 8 | 9 | #include 10 | 11 | using namespace std; 12 | using namespace fp; 13 | using namespace fp::math; 14 | 15 | size_t s1(); 16 | size_t s2(); 17 | size_t s3(); 18 | size_t s4(); 19 | size_t s5(); 20 | size_t s6(); 21 | size_t s7(); 22 | 23 | /////////////////////////////////////////////////////////////////////////// 24 | 25 | typedef function solution; 26 | 27 | types::list solutions( ) { 28 | types::list ss; 29 | ss.push_back(s1); 30 | ss.push_back(s2); 31 | ss.push_back(s3);/* 32 | ss.push_back(s4); 33 | ss.push_back(s5); 34 | ss.push_back(s6); 35 | ss.push_back(s7);*/ 36 | return ss; 37 | } 38 | 39 | /////////////////////////////////////////////////////////////////////////// 40 | 41 | int main(int argc, char **argv) { 42 | 43 | size_t x = 0; 44 | mapV( [=](solution s) mutable { std::cout << x++ << ": " << s() << std::endl; }, 45 | solutions() ); 46 | 47 | return 0; 48 | } 49 | 50 | /////////////////////////////////////////////////////////////////////////// 51 | // Find the sum of all the multiples of 3 or 5 below 1000. 52 | 53 | size_t s1() { 54 | return sum(filter([](size_t x) { return (x % 3) == 0 || (x % 5) == 0; }, fp::increasingN(999, 1))); 55 | } 56 | 57 | /////////////////////////////////////////////////////////////////////////// 58 | // By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms. 59 | 60 | size_t s2() { 61 | size_t x0 = 0, x1 = 1; 62 | let fibs = [=]() mutable -> size_t { 63 | size_t result = x0; 64 | std::swap(x0+=x1, x1); 65 | return result; 66 | }; 67 | return sum(filter([](size_t x) { return x % 2 == 0; }, 68 | takeWhileT(curry(math::greater, 4000000), fibs))); 69 | } 70 | 71 | /////////////////////////////////////////////////////////////////////////// 72 | // What is the largest prime factor of the number 600851475143 ? 73 | 74 | size_t s3() { 75 | 76 | const unsigned long long factoredValue = 600851475143; 77 | 78 | let primeFactor = [](long long factoredValue) -> long long { 79 | unsigned long long value = factoredValue; 80 | unsigned long long largest = 0; 81 | unsigned long long counter = 2; 82 | while (counter * counter < value) { 83 | if (value % counter == 0) { 84 | value = value / counter; 85 | largest = counter; 86 | } else { 87 | ++counter; 88 | } 89 | } 90 | return std::max(largest, value); 91 | }; 92 | 93 | return primeFactor(factoredValue); 94 | } 95 | 96 | ///////////////////////////////////////////////////////////////////////// 97 | -------------------------------------------------------------------------------- /samples/timer.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _TIMER_H_ 8 | #define _TIMER_H_ 9 | 10 | #include 11 | #if defined(_WIN32) 12 | #include 13 | #else 14 | #include 15 | #include 16 | #endif 17 | 18 | class sample_timer { 19 | public: 20 | 21 | sample_timer(); 22 | ~sample_timer(); 23 | void restart(); 24 | double elapsed(); 25 | 26 | private: 27 | 28 | #if defined(_WIN32) 29 | long long int startTime; 30 | long long int frequency; 31 | #else 32 | unsigned long startTime[2]; 33 | #endif 34 | }; 35 | 36 | /////////////////////////////////////////////////////////////////////////// 37 | 38 | #if defined(_WIN32) 39 | 40 | sample_timer::sample_timer() { 41 | DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR)1); 42 | QueryPerformanceFrequency((LARGE_INTEGER *)&this->frequency); 43 | SetThreadAffinityMask(GetCurrentThread(), oldmask); 44 | restart(); 45 | } 46 | 47 | sample_timer::~sample_timer() { 48 | 49 | } 50 | 51 | void sample_timer::restart() { 52 | DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR)1); 53 | QueryPerformanceCounter((LARGE_INTEGER *)&this->startTime); 54 | SetThreadAffinityMask(GetCurrentThread(), oldmask); 55 | } 56 | 57 | double sample_timer::elapsed() { 58 | long long int tempTime; 59 | DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR)1); 60 | QueryPerformanceCounter((LARGE_INTEGER *)&tempTime); 61 | SetThreadAffinityMask(GetCurrentThread(), oldmask); 62 | if (tempTimefrequency; 65 | } 66 | 67 | #else 68 | 69 | static inline void get_clock_count(unsigned long cc[2]) { 70 | struct timeval tv; 71 | gettimeofday (&tv,0); 72 | cc[0] = tv.tv_usec; 73 | cc[1] = tv.tv_sec; 74 | } 75 | 76 | static inline double load_clock_count (unsigned long a[2]) { 77 | return a[1]*1.0e6 + a[0]; 78 | } 79 | 80 | double ticks_per_second() { 81 | return 1000000; 82 | } 83 | 84 | sample_timer::sample_timer() { 85 | restart(); 86 | } 87 | 88 | sample_timer::~sample_timer() { 89 | 90 | } 91 | 92 | void sample_timer::restart() { 93 | get_clock_count(startTime); 94 | } 95 | 96 | double sample_timer::elapsed() { 97 | unsigned long tempTime[2]; 98 | get_clock_count(tempTime); 99 | 100 | double t1 = load_clock_count(startTime); 101 | double t2 = load_clock_count(tempTime); 102 | if (t2 9 | class Maybe : public std::pair { 10 | public: 11 | typedef std::pair pair; 12 | 13 | ///////////////////////////////////////////////////////////////////////// 14 | // Construction 15 | 16 | Maybe() : pair(false, T()) { } 17 | Maybe(const Maybe& other) : pair(other) { } 18 | Maybe(Maybe&& other) : pair(std::move(other)) { } 19 | Maybe(Nothing) : pair(false, T()) { } 20 | Maybe(T value) : pair(true, std::move(value)) { } 21 | Maybe(bool valid, const T& t) : pair(valid, t) { } 22 | 23 | 24 | ///////////////////////////////////////////////////////////////////////// 25 | // Assignment 26 | 27 | Maybe& operator=(const Maybe& o) { *static_cast(this) = o; return *this; } 28 | Maybe& operator=(Maybe&& o) { *static_cast(this) = std::move(o); return *this; } 29 | 30 | ///////////////////////////////////////////////////////////////////////// 31 | // Accessors 32 | 33 | inline bool valid() const { return pair::first; } 34 | inline operator bool() const { return pair::first; } 35 | 36 | inline const T& get() const { check(); return pair::second; } 37 | inline T& get() { check(); return pair::second; } 38 | inline const T& operator*() const { check(); return pair::second; } 39 | inline T& operator*() { check(); return pair::second; } 40 | 41 | private: 42 | inline void check() const { /* TODO: throw; */ } 43 | }; 44 | 45 | 46 | template 47 | bool operator==(const Maybe& opt, Nothing) { return !opt.valid(); } 48 | 49 | ///////////////////////////////////////////////////////////////////////// 50 | // just 51 | 52 | template 53 | Maybe just(T t) { return Maybe(std::move(t)); } 54 | 55 | 56 | ///////////////////////////////////////////////////////////////////////// 57 | // isNothing 58 | 59 | template 60 | bool isNothing(const Maybe& t) { return !t.valid(); } 61 | 62 | template 63 | bool isNothing(Maybe&& t) { return !t.valid(); } 64 | 65 | 66 | ///////////////////////////////////////////////////////////////////////// 67 | // isJust 68 | 69 | template 70 | bool isJust(const Maybe& t) { return t.valid(); } 71 | 72 | template 73 | bool isJust(Maybe&& t) { return t.valid(); } 74 | 75 | 76 | ///////////////////////////////////////////////////////////////////////// 77 | // fromJust 78 | 79 | template 80 | T fromJust(const Maybe& opt) { return *opt; } 81 | 82 | template 83 | T fromJust(Maybe&& opt) { return *opt; } 84 | 85 | 86 | ///////////////////////////////////////////////////////////////////////// 87 | // fromMaybe 88 | 89 | template 90 | T fromMaybe(const Maybe& opt) { return isJust(opt) ? *opt : T(); } 91 | 92 | template 93 | T fromMaybe(Maybe&& opt) { return isJust(opt) ? *opt : T(); } 94 | 95 | } // namespace fp 96 | 97 | #endif // _FP_MAYBE_H_ 98 | -------------------------------------------------------------------------------- /include/fp_prelude_objects.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_PRELUDE_OBJECTS_H_ 8 | #define _FP_PRELUDE_OBJECTS_H_ 9 | 10 | #include "fpcpp.h" 11 | 12 | namespace fp { 13 | 14 | /////////////////////////////////////////////////////////////////////////// 15 | // common 16 | 17 | FP_DEFINE_FUNCTION_OBJECT(head, headF); 18 | FP_DEFINE_FUNCTION_OBJECT(tail, tailF); 19 | FP_DEFINE_FUNCTION_OBJECT(last, lastF); 20 | FP_DEFINE_FUNCTION_OBJECT(length, lengthF); 21 | FP_DEFINE_FUNCTION_OBJECT(null, nullF); 22 | FP_DEFINE_FUNCTION_OBJECT(list, listF); 23 | FP_DEFINE_FUNCTION_OBJECT(fromString, fromStringF); 24 | FP_DEFINE_FUNCTION_OBJECT(fromIntegral, fromIntegralF); 25 | 26 | 27 | /////////////////////////////////////////////////////////////////////////// 28 | // prelude 29 | 30 | FP_DEFINE_FUNCTION_OBJECT(lines, linesF); 31 | FP_DEFINE_FUNCTION_OBJECT(unlines, unlinesF); 32 | FP_DEFINE_FUNCTION_OBJECT(words, wordsF); 33 | FP_DEFINE_FUNCTION_OBJECT(unwords, unwordsF); 34 | FP_DEFINE_FUNCTION_OBJECT(show, showF); 35 | FP_DEFINE_FUNCTION_OBJECT(putStr, putStrF); 36 | FP_DEFINE_FUNCTION_OBJECT(putStrLen, putStrLenF); 37 | FP_DEFINE_FUNCTION_OBJECT(print, printF); 38 | FP_DEFINE_FUNCTION_OBJECT(sort, sortF); 39 | FP_DEFINE_FUNCTION_OBJECT(enumFrom, enumFromF); 40 | FP_DEFINE_FUNCTION_OBJECT(concat, concatF); 41 | FP_DEFINE_FUNCTION_OBJECT(append, appendF); 42 | FP_DEFINE_FUNCTION_OBJECT(cons, consF); 43 | FP_DEFINE_FUNCTION_OBJECT(fst, fstF); 44 | FP_DEFINE_FUNCTION_OBJECT(snd, sndF); 45 | FP_DEFINE_FUNCTION_OBJECT(swap, swapF); 46 | 47 | 48 | /////////////////////////////////////////////////////////////////////////// 49 | // math 50 | 51 | namespace math { 52 | FP_DEFINE_FUNCTION_OBJECT(add, addF); 53 | FP_DEFINE_FUNCTION_OBJECT(subtract, subtractF); 54 | FP_DEFINE_FUNCTION_OBJECT(divide, divideF); 55 | FP_DEFINE_FUNCTION_OBJECT(multiply, multiplyF); 56 | FP_DEFINE_FUNCTION_OBJECT(negate, negateF); 57 | FP_DEFINE_FUNCTION_OBJECT(mod, modF); 58 | FP_DEFINE_FUNCTION_OBJECT(sqrt, sqrtF); 59 | FP_DEFINE_FUNCTION_OBJECT(abs, absF); 60 | FP_DEFINE_FUNCTION_OBJECT(logicalAnd, logicalAndF); 61 | FP_DEFINE_FUNCTION_OBJECT(logicalOr, logicalOrF); 62 | FP_DEFINE_FUNCTION_OBJECT(logicalNot, logicalNotF); 63 | FP_DEFINE_FUNCTION_OBJECT(equals, equalsF); 64 | FP_DEFINE_FUNCTION_OBJECT(notEquals, notEqualsF); 65 | FP_DEFINE_FUNCTION_OBJECT(greaterEquals, greaterEqualsF); 66 | FP_DEFINE_FUNCTION_OBJECT(greater, greaterF); 67 | FP_DEFINE_FUNCTION_OBJECT(lessEquals, lessEqualsF); 68 | FP_DEFINE_FUNCTION_OBJECT(less, lessF); 69 | FP_DEFINE_FUNCTION_OBJECT(even, evenF); 70 | FP_DEFINE_FUNCTION_OBJECT(odd, oddF); 71 | FP_DEFINE_FUNCTION_OBJECT(powerOfTwo, powerOfTwoF); 72 | FP_DEFINE_FUNCTION_OBJECT(uniform, uniformF); 73 | 74 | } 75 | 76 | 77 | } /* namespace fp */ 78 | 79 | #endif /* _FP_PRELUDE_OBJECTS_H_ */ 80 | -------------------------------------------------------------------------------- /include/fp_composition.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_COMPOSITION_H_ 8 | #define _FP_COMPOSITION_H_ 9 | 10 | #include "fp_defines.h" 11 | #include "fp_composition_utils.h" 12 | 13 | namespace fp { 14 | 15 | /////////////////////////////////////////////////////////////////////////// 16 | 17 | using std::declval; 18 | 19 | template 20 | class composed { 21 | public: 22 | 23 | composed(F f_, G g_) : f(f_), g(g_) { } 24 | composed(F&& f_, G&& g_) : f(std::move(f_)), g(std::move(g_)) { } 25 | 26 | #if FP_VARIADIC 27 | template 28 | inline auto operator()(const Args&... args) -> decltype(declval()(declval()(args...))){ 29 | return f(g(args...)); 30 | } 31 | #else 32 | template 33 | inline auto operator()(const T0& t0) -> decltype( declval()(declval()(t0)) ) { 34 | return f(this->g(t0)); 35 | } 36 | 37 | template 38 | inline auto operator()(const T0& t0, const T1& t1) -> decltype( declval()(declval()(t0,t1)) ) { 39 | return f(g(t0,t1)); 40 | } 41 | 42 | template 43 | inline auto operator()(const T0& t0, const T1& t1, const T2& t2) -> decltype( declval()(declval()(t0,t1,t2)) ) { 44 | return f(g(t0,t1,t2)); 45 | } 46 | 47 | template 48 | inline auto operator()(const T0& t0, const T1& t1, const T2& t2, const T3& t3) -> decltype( declval()(declval()(t0,t1,t2,t3)) ) { 49 | return f(g(t0,t1,t2,t3)); 50 | } 51 | #endif 52 | 53 | protected: 54 | 55 | F& f1() { return f; } 56 | G& f2() { return g; }; 57 | 58 | composed(); 59 | 60 | F f; 61 | G g; 62 | }; 63 | 64 | /////////////////////////////////////////////////////////////////////////// 65 | 66 | template 67 | inline composed compose(F f, G g) { 68 | return composed(f,g); 69 | } 70 | 71 | /////////////////////////////////////////////////////////////////////////// 72 | 73 | } /* namespace fp */ 74 | 75 | namespace fp_operators { 76 | #if FP_PLUS_OPERATOR 77 | // Example: (f + g)(Args) == (compose(f,g)(Args) 78 | template 79 | inline auto operator+(F f, G g) FP_RETURNS( fp::compose(f,g) ); 80 | #endif 81 | 82 | #if FP_DOT_OPERATOR 83 | // Example: (f g)(Args) == (compose(f,g)(args)) 84 | static class compose_dot_helper { } o; 85 | template 86 | inline auto operator>(F f, G g) FP_RETURNS( fp::compose(f,g) ); 87 | template 88 | inline F operator<(F f, compose_dot_helper) { 89 | ((void)o); 90 | return f; 91 | } 92 | #endif 93 | 94 | #if FP_SHIFT_OPERATOR 95 | template 96 | inline auto operator <<(F f, G g) -> typename std::enable_if::value&&fp::is_functor::value, decltype( fp::compose(f,g) )>::type { 97 | return fp::compose(f,g); 98 | } 99 | template 100 | inline auto operator >>(G g, F f) FP_RETURNS( f << g ); 101 | #endif 102 | 103 | } /* namespace fp_operators */ 104 | 105 | #endif /* _FP_COMPOSITION_H_ */ 106 | -------------------------------------------------------------------------------- /samples/benchmarks.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "fpcpp.h" 8 | 9 | #include 10 | #include 11 | #define _USE_MATH_DEFINES 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "benchmark_common.h" 18 | 19 | using namespace fp; 20 | 21 | /////////////////////////////////////////////////////////////////////////// 22 | 23 | template 24 | inline C unique1( const C& rands ) { 25 | let sorted = fp::sort( rands ); 26 | sorted.erase( std::unique( extent(sorted) ), fp::end(sorted) ); 27 | return move(sorted); 28 | } 29 | template 30 | inline C unique2( C rands ) { 31 | rands = move( fp::sort( move(rands) ) ); 32 | rands.resize( std::unique( extent(rands) ) - fp::begin(rands) ); 33 | return move(rands); 34 | } 35 | template 36 | inline void unique3( C& rands ) { 37 | std::sort( extent(rands) ); 38 | rands.resize( std::unique( extent(rands) ) - fp::begin(rands) ); 39 | } 40 | template 41 | inline C unique4( const C& rands ) { 42 | typedef nonconstref_type_of(decltype(head(rands))) T; 43 | std::set s; 44 | const size_t size = fp::length(rands); 45 | for( unsigned i = 0; i < size; ++i ) 46 | s.insert( rands[i] ); 47 | return C( extent(s) ); 48 | } 49 | template 50 | inline void unique5( C& rands ) { 51 | typedef nonconstref_type_of(decltype(head(rands))) T; 52 | std::set s( extent(rands) ); 53 | rands.assign( extent(s) ); 54 | } 55 | template 56 | inline C unique6( const C& rands ) { 57 | typedef nonconstref_type_of(decltype(head(rands))) T; 58 | std::unordered_set s( extent(rands) ); 59 | return C( extent(s) ); 60 | } 61 | template 62 | inline C unique7( C rands ) { 63 | rands = move( fp::sort( move(rands) ) ); 64 | return C( fp::begin(rands), std::unique( extent(rands) ) ); 65 | } 66 | 67 | template 68 | void unique_impl(const C& rands, size_t iters) { 69 | print( "Length = " + show(length(rands)) + " - Iters = " + show(iters)); 70 | run( let t = unique1( rands ); (void)fp::length(t), iters ); 71 | run( let t = unique2( rands ); (void)fp::length(t), iters ); 72 | run( let t = rands; unique3(t); (void)fp::length(t), iters ); 73 | run( let t = unique4( rands ); (void)fp::length(t), iters ); 74 | run( let t = rands; unique5(t); (void)fp::length(t), iters ); 75 | run( let t = unique6( rands ); (void)fp::length(t), iters ); 76 | run( let t = unique7( rands ); (void)fp::length(t), iters ); 77 | } 78 | 79 | void unique( size_t count, size_t iters = ITER_MULT ) { 80 | { 81 | const let rands = fp::uniformN( count, 0, 100 ); 82 | unique_impl(rands, iters); 83 | } 84 | { 85 | types::list rands; 86 | for (size_t i = 0; i < count; ++i) 87 | rands.emplace_back( show( uniformN( 10, 'a', 'z' ) ) ); 88 | unique_impl(rands, iters); 89 | } 90 | } 91 | 92 | /////////////////////////////////////////////////////////////////////////// 93 | 94 | int main(int argc, char **argv) { 95 | 96 | print( "" ); 97 | 98 | unique( 100, 1000 * ITER_MULT ); 99 | unique( 1000, 100 * ITER_MULT ); 100 | unique( 10000, 10 * ITER_MULT ); 101 | unique( 100000, 1 * ITER_MULT ); 102 | 103 | print( "" ); 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /include/fp_defines.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_DEFINES_H_ 8 | 9 | #define _FP_DEFINES_H_ 10 | 11 | // Compiler specific defines 12 | // FP_DECLVAL - Whether the compiler has a built-in declval function 13 | // FP_VARIADIC - Whether the compiler supports variadic templates 14 | // FP_COMPOUND - Whether the compiler properly compiles compound composition 15 | 16 | #if defined(_MSC_VER) 17 | #define FP_INITIALIZER 0 18 | #define FP_VARIADIC 0 19 | #define FP_THIS_IN_RET 1 20 | #if _MSC_VER >= 1700 21 | #define FP_DECLVAL 1 22 | #define FP_NOEXCEPT noexcept 23 | #else 24 | #define FP_DECLVAL 1 25 | #define FP_NOEXCEPT noexcept 26 | #endif 27 | #elif defined(__INTEL_COMPILER) 28 | #define FP_INITIALIZER 1 29 | #define FP_DECLVAL 0 30 | #define FP_VARIADIC 1 31 | #define FP_THIS_IN_RET 1 32 | #define FP_NOEXCEPT noexcept 33 | else 34 | #define FP_INITIALIZER 1 35 | #define FP_DECLVAL 1 36 | #define FP_VARIADIC 1 37 | #define FP_THIS_IN_RET 0 38 | #define FP_NOEXCEPT noexcept 39 | #endif 40 | 41 | #define USE_DEQUE_FOR_LISTS 0 42 | #if USE_DEQUE_FOR_LISTS 43 | #define fp_list std::deque 44 | #else 45 | #define fp_list std::vector 46 | //#define fp_list std::list 47 | #endif 48 | 49 | // Composition operator defines 50 | #if !defined(FP_OPERATORS) 51 | #define FP_OPERATORS 1 52 | #endif 53 | #if FP_OPERATORS 54 | #define FP_PLUS_OPERATOR 1 55 | #define FP_DOT_OPERATOR 1 56 | #define FP_SHIFT_OPERATOR 1 57 | #else 58 | #define FP_PLUS_OPERATOR 0 59 | #define FP_DOT_OPERATOR 0 60 | #define FP_SHIFT_OPERATOR 0 61 | #endif 62 | 63 | // Keywords 64 | #define let auto 65 | #define extent(c) fp::begin((c)), fp::end((c)) 66 | #define rextent(c) fp::rbegin((c)), fp::rend((c)) 67 | 68 | // Template type helpers 69 | #define value_type_of(TYPE) typename fp::traits::value_type 70 | #define result_type_of(TYPE) typename fp::function_traits::result_type 71 | #define argument_type_of(TYPE,ARGC) typename fp::function_traits::t ## ARGC ## _type 72 | #define nonconstref_type_of(TYPE) typename fp::remove_const_ref::type 73 | #define ref_type_of(TYPE) typename fp::traits::ref_type 74 | 75 | // Template conditional type helpers 76 | #define fp_enable_if(CONDITION,RTYPE) typename std::enable_if::type 77 | #define fp_enable_if_container(TYPE,RTYPE) fp_enable_if(fp::is_container::value, RTYPE) 78 | #define fp_enable_if_not_container(TYPE,RTYPE) fp_enable_if(!fp::is_container::value, RTYPE) 79 | #define fp_enable_if_void(TYPE) fp_enable_if(std::is_same::value, void) 80 | #define fp_enable_if_nonvoid(TYPE,RTYPE) fp_enable_if(!std::is_same::value, RTYPE) 81 | #define fp_enable_if_arithmetic(TYPE) fp_enable_if(std::is_arithmetic::value, TYPE) 82 | #define fp_enable_if_integral(TYPE) fp_enable_if(std::is_integral::value, TYPE) 83 | 84 | // Join helpers 85 | #define FP_CONCAT_IMPL(x, y) x ## y 86 | #define FP_CONCAT(x, y) FP_CONCAT_IMPL(x,y) 87 | 88 | // auto function() RETURNS(); 89 | #define FP_RETURNS(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); } \ 90 | typedef int FP_CONCAT(RETURNS_ON_, FP_CONCAT(__LINE__,__COUNTER__)) 91 | #define FP_RETURNS_NONREF(...) -> nonconstref_type_of(decltype(__VA_ARGS__)) { return (__VA_ARGS__); } \ 92 | typedef int FP_CONCAT(RETURNS_ON_, FP_CONCAT(__LINE__,__COUNTER__)) 93 | 94 | #endif /* _FP_DEFINES_H_ */ 95 | -------------------------------------------------------------------------------- /include/fp_io.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_IO_H_ 8 | #define _FP_IO_H_ 9 | 10 | #include "fp_defines.h" 11 | #include "fp_common.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #define USE_PLATFORM_SPECIFIC_CODE 0 18 | 19 | #if USE_PLATFORM_SPECIFIC_CODE 20 | #if defined(FP_WINDOWS) 21 | #include 22 | #else 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #endif 30 | #endif /* USE_PLATFORM_SPECIFIC_CODE */ 31 | 32 | namespace fp { 33 | 34 | typedef std::string FilePath; 35 | 36 | std::ifstream& readFile( const FilePath& filePath, std::ifstream& ifs ) { 37 | ifs.open( filePath ); 38 | return ifs; 39 | } 40 | 41 | bool removeFile( const FilePath& filePath ) { 42 | return remove( fromString(filePath) ) == 0; 43 | } 44 | 45 | bool renameFile( const FilePath& srcPath, const std::string& dstFileName ) { 46 | return ::rename( fromString(srcPath), fromString(dstFileName) ) == 0; 47 | } 48 | 49 | bool copyFile( const FilePath& srcPath, const FilePath& dstPath ) { 50 | #if USE_PLATFORM_SPECIFIC_CODE 51 | #if defined(PU_WINDOWS) 52 | return CopyFile( fromString(srcPath), fromString(dstPath), false ) != 0; 53 | #else 54 | bool success = false; 55 | int read_fd, write_fd; 56 | struct stat stat_buf; 57 | off_t offset = 0; 58 | 59 | read_fd = open( fromString(srcPath), O_RDONLY ); 60 | if( read_fd != -1 ) { 61 | if ( fstat(read_fd, &stat_buf) == 0 ) { 62 | write_fd = open( fromString(dstPath), O_WRONLY | O_CREAT, stat_buf.st_mode ); 63 | if ( write_fd != -1 ) { 64 | success = sendfile( write_fd, read_fd, &offset, stat_buf.st_size ) != -1; 65 | close( write_fd ); 66 | } 67 | } 68 | close(read_fd); 69 | } 70 | return success; 71 | } 72 | #endif /* defined(FP_WINDOWS) */ 73 | #else /* USE_PLATFORM_SPECIFIC_CODE */ 74 | std::ifstream ifs( srcPath, std::ios::in | std::ios::binary ); 75 | if ( ifs.is_open() ) { 76 | std::ofstream ofs( dstPath, std::ios::out | std::ios::binary ); 77 | if ( ofs.is_open() ) { 78 | ofs << ifs.rdbuf(); 79 | return !ofs.bad() /* && ifs.eof() */ ; 80 | } 81 | } 82 | return false; 83 | #endif 84 | } 85 | 86 | bool moveFile( const FilePath& srcPath, const FilePath& dstPath ) { 87 | return copyFile( srcPath, dstPath ) && removeFile( srcPath ); 88 | } 89 | 90 | bool doesFileExist( const FilePath& filePath ) { 91 | #if USE_PLATFORM_SPECIFIC_CODE 92 | #if defined(FP_WINDOWS) 93 | DWORD attributes = GetFileAttributes( fromString(filePath) ); 94 | if (attributes != INVALID_FILE_ATTRIBUTES && 95 | attributes & FILE_ATTRIBUTE_DIRECTORY) 96 | return true; 97 | else 98 | return false; 99 | #else 100 | struct stat sb; 101 | return (stat( fromString(filePath), &sb ) == 0) && S_ISDIR(sb.st_mode); 102 | #endif /* defined(FP_WINDOWS) */ 103 | #else /* USE_PLATFORM_SPECIFIC_CODE */ 104 | std::ifstream ifs( filePath ); 105 | return !(!ifs); 106 | #endif 107 | } 108 | 109 | size_t fileSize( const FilePath& filePath ) { 110 | std::streampos fsize = 0; 111 | std::ifstream file(filePath, std::ios::binary); 112 | if (file.is_open()) { 113 | fsize = file.tellg(); 114 | file.seekg( 0, std::ios::end ); 115 | fsize = file.tellg() - fsize; 116 | } 117 | return (size_t)fsize; 118 | } 119 | 120 | } 121 | 122 | #endif /* _FP_IO_H */ 123 | -------------------------------------------------------------------------------- /externals/rapidxml/rapidxml_utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RAPIDXML_UTILS_HPP_INCLUDED 2 | #define RAPIDXML_UTILS_HPP_INCLUDED 3 | 4 | // Copyright (C) 2006, 2009 Marcin Kalicinski 5 | // Version 1.13 6 | // Revision $DateTime: 2009/05/13 01:46:17 $ 7 | //! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful 8 | //! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. 9 | 10 | #include "rapidxml.hpp" 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace rapidxml 17 | { 18 | 19 | //! Represents data loaded from a file 20 | template 21 | class file 22 | { 23 | 24 | public: 25 | 26 | //! Loads file into the memory. Data will be automatically destroyed by the destructor. 27 | //! \param filename Filename to load. 28 | file(const char *filename) 29 | { 30 | using namespace std; 31 | 32 | // Open stream 33 | basic_ifstream stream(filename, ios::binary); 34 | if (!stream) 35 | throw runtime_error(string("cannot open file ") + filename); 36 | stream.unsetf(ios::skipws); 37 | 38 | // Determine stream size 39 | stream.seekg(0, ios::end); 40 | size_t size = stream.tellg(); 41 | stream.seekg(0); 42 | 43 | // Load data and add terminating 0 44 | m_data.resize(size + 1); 45 | stream.read(&m_data.front(), static_cast(size)); 46 | m_data[size] = 0; 47 | } 48 | 49 | //! Loads file into the memory. Data will be automatically destroyed by the destructor 50 | //! \param stream Stream to load from 51 | file(std::basic_istream &stream) 52 | { 53 | using namespace std; 54 | 55 | // Load data and add terminating 0 56 | stream.unsetf(ios::skipws); 57 | m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); 58 | if (stream.fail() || stream.bad()) 59 | throw runtime_error("error reading stream"); 60 | m_data.push_back(0); 61 | } 62 | 63 | //! Gets file data. 64 | //! \return Pointer to data of file. 65 | Ch *data() 66 | { 67 | return &m_data.front(); 68 | } 69 | 70 | //! Gets file data. 71 | //! \return Pointer to data of file. 72 | const Ch *data() const 73 | { 74 | return &m_data.front(); 75 | } 76 | 77 | //! Gets file data size. 78 | //! \return Size of file data, in characters. 79 | std::size_t size() const 80 | { 81 | return m_data.size(); 82 | } 83 | 84 | private: 85 | 86 | std::vector m_data; // File data 87 | 88 | }; 89 | 90 | //! Counts children of node. Time complexity is O(n). 91 | //! \return Number of children of node 92 | template 93 | inline std::size_t count_children(xml_node *node) 94 | { 95 | xml_node *child = node->first_node(); 96 | std::size_t count = 0; 97 | while (child) 98 | { 99 | ++count; 100 | child = child->next_sibling(); 101 | } 102 | return count; 103 | } 104 | 105 | //! Counts attributes of node. Time complexity is O(n). 106 | //! \return Number of attributes of node 107 | template 108 | inline std::size_t count_attributes(xml_node *node) 109 | { 110 | xml_attribute *attr = node->first_attribute(); 111 | std::size_t count = 0; 112 | while (attr) 113 | { 114 | ++count; 115 | attr = attr->next_attribute(); 116 | } 117 | return count; 118 | } 119 | 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /include/fp_curry_defines.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_CURRY_DEFINES_H_ 8 | #define _FP_CURRY_DEFINES_H_ 9 | 10 | #include "fp_defines.h" 11 | 12 | #define FP_PREFIX1 f, t 13 | #define FP_PREFIX2 FP_PREFIX1 , t1 14 | #define FP_PREFIX3 FP_PREFIX2 , t2 15 | #define FP_PREFIX4 FP_PREFIX3 , t3 16 | 17 | #define FP_TYPE_PREFIX1 F f, T t 18 | #define FP_TYPE_PREFIX2 FP_TYPE_PREFIX1 , T1 t1 19 | #define FP_TYPE_PREFIX3 FP_TYPE_PREFIX2 , T2 t2 20 | #define FP_TYPE_PREFIX4 FP_TYPE_PREFIX3 , T3 t3 21 | 22 | #define FP_TTYPE_PREFIX1 typename F, typename T 23 | #define FP_TTYPE_PREFIX2 FP_TYPE_PREFIX1 , typename T1 24 | #define FP_TTYPE_PREFIX3 FP_TYPE_PREFIX2 , typename T2 25 | #define FP_TTYPE_PREFIX4 FP_TYPE_PREFIX3 , typename T3 26 | 27 | #define FP_CURRY1(a) std::bind(a) 28 | #define FP_CURRY2(a) std::bind(a, std::placeholders::_1) 29 | #define FP_CURRY3(a) std::bind(a, std::placeholders::_1, std::placeholders::_2) 30 | #define FP_CURRY4(a) std::bind(a, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3) 31 | #define FP_CURRY5(a) std::bind(a, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4) 32 | 33 | #define FP_CURRY_HELPER(FUNC,PREFIX) FUNC(PREFIX) 34 | #define FP_CURRY(ARG,PREFIX) FP_CURRY_HELPER(FP_CURRY##ARG, PREFIX) 35 | 36 | #define FP_DEFINE_FUNCTION_OBJECT(func,funcObj) \ 37 | struct funcObj { \ 38 | template \ 39 | inline auto operator()(T&& t) const FP_RETURNS( func(t) ); \ 40 | template \ 41 | inline auto operator()(const T& t) const FP_RETURNS( func(t) ); \ 42 | template \ 43 | inline auto operator()(F&& f, T&& t) const FP_RETURNS( func(f,t) ); \ 44 | template \ 45 | inline auto operator()(const F& f, const T& t) const FP_RETURNS( func(f,t) ); \ 46 | template \ 47 | inline auto operator()(F f, T t, const C& c) const FP_RETURNS( func(f,t,c) );\ 48 | } 49 | 50 | 51 | #define FP_DEFINE_CURRIED_HELPER(a,b) \ 52 | template \ 53 | inline auto b(F f) FP_RETURNS(a); 54 | #define FP_DEFINE_CURRIED_HELPER2(a,b) \ 55 | template \ 56 | inline auto b(F f, T t) FP_RETURNS(a); 57 | 58 | #define FP_CURRIED(func0,func1) \ 59 | fp::curry(func0::t0_type>::type> >, \ 60 | func1) 61 | #define FP_CURRIED2(func0,func2,value) \ 62 | fp::curry2(func0::t0_type>::type> >, \ 63 | func2, \ 64 | value) 65 | 66 | #define FP_DEFINE_CURRIED(funcName, funcName2) \ 67 | FP_DEFINE_FUNCTION_OBJECT( funcName, funcName ## F ); \ 68 | FP_DEFINE_CURRIED_HELPER( FP_CURRIED(funcName, f), funcName2 ) 69 | #define FP_DEFINE_CURRIED_T(funcName, funcName2, funcName3) \ 70 | FP_DEFINE_FUNCTION_OBJECT( funcName, funcName ## F ); \ 71 | FP_DEFINE_CURRIED_HELPER( FP_CURRIED( funcName, f), funcName2 ) \ 72 | FP_DEFINE_CURRIED_HELPER2( FP_CURRIED2(funcName, f, t), funcName3 ) 73 | 74 | #endif /* _FP_CURRY_DEFINES_H_ */ 75 | -------------------------------------------------------------------------------- /include/fp_prelude_strings.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_PRELUDE_STRINGS_H_ 8 | #define _FP_PRELUDE_STRINGS_H_ 9 | 10 | #include "fp_defines.h" 11 | #include "fp_prelude.h" 12 | #include "fp_prelude_lists.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace fp { 19 | 20 | /////////////////////////////////////////////////////////////////////////// 21 | // String operations 22 | /////////////////////////////////////////////////////////////////////////// 23 | 24 | template 25 | inline typename types::list& split_helper(const T& s, char delim, typename types::list& elems) { 26 | std::stringstream ss(s); 27 | T item; 28 | while(std::getline(ss, item, delim)) { 29 | elems.push_back(item); 30 | } 31 | return elems; 32 | } 33 | 34 | template 35 | inline typename types::list split(const T& s, char delim) { 36 | typename types::list elems; 37 | return split_helper(s, delim, elems); 38 | }; 39 | 40 | template 41 | string concat(const C& c, const char* infix = " ", const char* prefix = "", const char* suffix = "") { 42 | if (length(c) == 0) 43 | return ""; 44 | 45 | std::stringstream ss; 46 | ss << prefix; 47 | let it = begin(c); 48 | if (it != end(c)) { 49 | while (true) { 50 | ss << show(*it); 51 | if (++it == end(c)) break; 52 | ss << infix; 53 | } 54 | } 55 | ss << suffix; 56 | 57 | return ss.str(); 58 | } 59 | 60 | inline bool istrue(bool b) { return b; } 61 | 62 | /////////////////////////////////////////////////////////////////////////// 63 | // lines 64 | 65 | template 66 | inline typename types::list lines(const T& s) { 67 | return split(s, '\n'); 68 | } 69 | inline types::list lines(std::ifstream& ifs) { 70 | types::list ifsLines; 71 | string line; 72 | while (getline(ifs, line)) 73 | ifsLines.push_back(line); 74 | return ifsLines; 75 | } 76 | 77 | /////////////////////////////////////////////////////////////////////////// 78 | // unlines 79 | 80 | template 81 | auto unlines(const C& elems) -> value_type_of(C) { 82 | return concat(elems, '\n'); 83 | } 84 | 85 | /////////////////////////////////////////////////////////////////////////// 86 | // words 87 | template 88 | inline typename types::list words(const T& s) { 89 | return split(s, ' '); 90 | } 91 | 92 | /////////////////////////////////////////////////////////////////////////// 93 | // unwords 94 | 95 | template 96 | auto unwords(const T& elems) -> decltype(concat(elems, ' ')) { 97 | return concat(elems, ' '); 98 | } 99 | 100 | /////////////////////////////////////////////////////////////////////////// 101 | // show 102 | template 103 | inline fp_enable_if_not_container(T,string) show(const T& t) { 104 | std::stringstream ss; 105 | ss << t; 106 | return ss.str(); 107 | } 108 | 109 | inline string show(const types::list& c) { 110 | return string(extent(c)); 111 | } 112 | 113 | inline string show(const string& s) { 114 | return s; 115 | } 116 | 117 | template 118 | inline fp_enable_if_container(C,string) show(const C& c) { 119 | 120 | typedef value_type_of(C) T; 121 | const bool is_nonstring_container = is_container::value && !std::is_same::value; 122 | const char* infix = is_nonstring_container ? ",\n" : ", "; 123 | const char* prefix = is_nonstring_container ? "[" : "["; 124 | const char* suffix = is_nonstring_container ? "]\n" : "]"; 125 | 126 | return concat( c, infix, prefix, suffix ); 127 | } 128 | 129 | 130 | /////////////////////////////////////////////////////////////////////////// 131 | // print 132 | 133 | inline void putStr(const string& s) { 134 | std::cout << s; 135 | } 136 | 137 | inline void putStr(string&& s) { 138 | std::cout << s; 139 | } 140 | 141 | inline void putStrLen(const string& s) { 142 | std::cout << s << std::endl; 143 | } 144 | 145 | inline void putStrLen(string&& s) { 146 | std::cout << s << std::endl; 147 | } 148 | 149 | template 150 | inline void print(const T& t) { 151 | putStrLen( show(t) ); 152 | } 153 | 154 | } /* namespace fp */ 155 | 156 | #endif /* _FP_PRELUDE_STRINGS_H_ */ 157 | -------------------------------------------------------------------------------- /externals/rapidxml/rapidxml_iterators.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RAPIDXML_ITERATORS_HPP_INCLUDED 2 | #define RAPIDXML_ITERATORS_HPP_INCLUDED 3 | 4 | // Copyright (C) 2006, 2009 Marcin Kalicinski 5 | // Version 1.13 6 | // Revision $DateTime: 2009/05/13 01:46:17 $ 7 | //! \file rapidxml_iterators.hpp This file contains rapidxml iterators 8 | 9 | #include "rapidxml.hpp" 10 | 11 | namespace rapidxml 12 | { 13 | 14 | //! Iterator of child nodes of xml_node 15 | template 16 | class node_iterator 17 | { 18 | 19 | public: 20 | 21 | typedef typename xml_node value_type; 22 | typedef typename xml_node &reference; 23 | typedef typename xml_node *pointer; 24 | typedef std::ptrdiff_t difference_type; 25 | typedef std::bidirectional_iterator_tag iterator_category; 26 | 27 | node_iterator() 28 | : m_node(0) 29 | { 30 | } 31 | 32 | node_iterator(xml_node *node) 33 | : m_node(node->first_node()) 34 | { 35 | } 36 | 37 | reference operator *() const 38 | { 39 | assert(m_node); 40 | return *m_node; 41 | } 42 | 43 | pointer operator->() const 44 | { 45 | assert(m_node); 46 | return m_node; 47 | } 48 | 49 | node_iterator& operator++() 50 | { 51 | assert(m_node); 52 | m_node = m_node->next_sibling(); 53 | return *this; 54 | } 55 | 56 | node_iterator operator++(int) 57 | { 58 | node_iterator tmp = *this; 59 | ++this; 60 | return tmp; 61 | } 62 | 63 | node_iterator& operator--() 64 | { 65 | assert(m_node && m_node->previous_sibling()); 66 | m_node = m_node->previous_sibling(); 67 | return *this; 68 | } 69 | 70 | node_iterator operator--(int) 71 | { 72 | node_iterator tmp = *this; 73 | ++this; 74 | return tmp; 75 | } 76 | 77 | bool operator ==(const node_iterator &rhs) 78 | { 79 | return m_node == rhs.m_node; 80 | } 81 | 82 | bool operator !=(const node_iterator &rhs) 83 | { 84 | return m_node != rhs.m_node; 85 | } 86 | 87 | private: 88 | 89 | xml_node *m_node; 90 | 91 | }; 92 | 93 | //! Iterator of child attributes of xml_node 94 | template 95 | class attribute_iterator 96 | { 97 | 98 | public: 99 | 100 | typedef typename xml_attribute value_type; 101 | typedef typename xml_attribute &reference; 102 | typedef typename xml_attribute *pointer; 103 | typedef std::ptrdiff_t difference_type; 104 | typedef std::bidirectional_iterator_tag iterator_category; 105 | 106 | attribute_iterator() 107 | : m_attribute(0) 108 | { 109 | } 110 | 111 | attribute_iterator(xml_node *node) 112 | : m_attribute(node->first_attribute()) 113 | { 114 | } 115 | 116 | reference operator *() const 117 | { 118 | assert(m_attribute); 119 | return *m_attribute; 120 | } 121 | 122 | pointer operator->() const 123 | { 124 | assert(m_attribute); 125 | return m_attribute; 126 | } 127 | 128 | attribute_iterator& operator++() 129 | { 130 | assert(m_attribute); 131 | m_attribute = m_attribute->next_attribute(); 132 | return *this; 133 | } 134 | 135 | attribute_iterator operator++(int) 136 | { 137 | attribute_iterator tmp = *this; 138 | ++this; 139 | return tmp; 140 | } 141 | 142 | attribute_iterator& operator--() 143 | { 144 | assert(m_attribute && m_attribute->previous_attribute()); 145 | m_attribute = m_attribute->previous_attribute(); 146 | return *this; 147 | } 148 | 149 | attribute_iterator operator--(int) 150 | { 151 | attribute_iterator tmp = *this; 152 | ++this; 153 | return tmp; 154 | } 155 | 156 | bool operator ==(const attribute_iterator &rhs) 157 | { 158 | return m_attribute == rhs.m_attribute; 159 | } 160 | 161 | bool operator !=(const attribute_iterator &rhs) 162 | { 163 | return m_attribute != rhs.m_attribute; 164 | } 165 | 166 | private: 167 | 168 | xml_attribute *m_attribute; 169 | 170 | }; 171 | 172 | } 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /include/fp_common.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_COMMON_H_ 8 | #define _FP_COMMON_H_ 9 | 10 | #include "fp_defines.h" 11 | #include "fp_template_utils.h" 12 | #include "fp_curry_defines.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #if FP_INITIALIZER 21 | #include 22 | #endif 23 | 24 | namespace fp { 25 | 26 | using std::string; 27 | 28 | /////////////////////////////////////////////////////////////////////////// 29 | // List helpers 30 | /////////////////////////////////////////////////////////////////////////// 31 | 32 | using std::begin; 33 | using std::end; 34 | using std::pair; 35 | using std::move; 36 | using std::forward; 37 | 38 | template 39 | struct thunk : std::function { }; 40 | 41 | template 42 | std::back_insert_iterator back(C& c) { 43 | return std::back_inserter(c); 44 | } 45 | 46 | template 47 | std::front_insert_iterator front(C& c) { 48 | return std::front_inserter(c); 49 | } 50 | 51 | /////////////////////////////////////////////////////////////////////////// 52 | // head 53 | 54 | template 55 | inline auto head(const C& c) -> nonconstref_type_of(decltype(*begin(c))) { 56 | return *begin(c); 57 | } 58 | inline char head(const char* c) { 59 | return c[0]; 60 | } 61 | //template 62 | //inline T head(std::function t) { return t(); } 63 | 64 | /////////////////////////////////////////////////////////////////////////// 65 | // tail 66 | 67 | template 68 | inline C tail(C&& c) { 69 | return move(drop(1, c)); 70 | } 71 | template 72 | inline C tail(const C& c) { 73 | return move(drop(1, c)); 74 | } 75 | template 76 | inline thunk tail(thunk t) { 77 | t(); return t; 78 | } 79 | 80 | /////////////////////////////////////////////////////////////////////////// 81 | // last 82 | 83 | template 84 | inline auto last(C&& c) FP_RETURNS( *(--end(c)) ); 85 | template 86 | inline auto last(const C& c) FP_RETURNS( *(--end(c)) ); 87 | 88 | /////////////////////////////////////////////////////////////////////////// 89 | 90 | template 91 | inline size_t length(const C& c) { 92 | return c.size(); 93 | } 94 | 95 | /////////////////////////////////////////////////////////////////////////// 96 | 97 | template 98 | inline size_t null(const C& c) { 99 | return length(c) == 0; 100 | } 101 | template 102 | inline size_t null(T (&A)[S]) { 103 | return S==0; 104 | } 105 | 106 | /////////////////////////////////////////////////////////////////////////// 107 | 108 | template 109 | inline typename types::list list(const std::array& a) { 110 | typename types::list result(extent(a)); 111 | return move(result); 112 | } 113 | template 114 | inline typename types::list list() { 115 | return typename types::list(); 116 | } 117 | inline types::list list(const string& s) { 118 | return move(types::list(extent(s))); 119 | } 120 | #if FP_INITIALIZER 121 | template 122 | inline typename types::list list(const std::initializer_list& il) { 123 | typename types::list result(extent(il)); 124 | return move(result); 125 | } 126 | #endif 127 | 128 | /////////////////////////////////////////////////////////////////////////// 129 | // index 130 | 131 | template 132 | inline fp_enable_if_container(C,value_type_of(C)) index(Index i, const C& c) { 133 | return c[i]; 134 | } 135 | 136 | template 137 | inline T index(Index i, const std::list& l) { 138 | let it = begin(l); 139 | std::advance(it, i); 140 | return it != end(l) ? *it : T(); 141 | } 142 | 143 | /////////////////////////////////////////////////////////////////////////// 144 | 145 | // Thunk from list... careful, no bounds check 146 | /* 147 | template 148 | inline std::function fromList(const C& c) { 149 | size_t i = 0; 150 | return [=]() mutable { return fp::index(i++, c); }; 151 | }*/ 152 | 153 | template 154 | inline fp_enable_if_not_container(T,string) show(const T& t); 155 | template 156 | inline fp_enable_if_container(C,string) show(const C& c); 157 | inline string show(const types::list& c); 158 | inline string show(const string& s); 159 | 160 | // C-string from string 161 | inline const char* fromString( const string& s ) { return s.c_str(); } 162 | 163 | // Float from whatever 164 | template 165 | float fromIntegral(T t) { return static_cast(t); } 166 | 167 | } /* namespace fp */ 168 | 169 | #endif /* _FP_COMMON_H_ */ 170 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | project(fpcpp) 3 | 4 | set(CMAKE_DEBUG_POSTFIX "d") 5 | 6 | # Treat warnings as errors cmake option 7 | set(TREAT_WARNINGS_AS_ERRORS TRUE CACHE BOOL "Treat warnings as errors") 8 | SET(BUILD_FPCPP_SAMPLES TRUE CACHE BOOL "Build FPCPP samples") 9 | set(BUILD_FPCPP_TESTS FALSE CACHE BOOL "Build FPCPP unit tests") 10 | 11 | if(MSVC10) 12 | set(FPCPP_SUFFIX _vc10) 13 | elseif(MSVC11) 14 | set(FPCPP_SUFFIX _vc11) 15 | else() 16 | set(FPCPP_SUFFIX) 17 | endif() 18 | 19 | if(CMAKE_SIZEOF_VOID_P MATCHES 4) 20 | set(FPCPP_SIZE_TYPE x86) 21 | else() 22 | set(FPCPP_SIZE_TYPE x64) 23 | endif() 24 | 25 | set(FPCPP_BINARY_PATH ${CMAKE_HOME_DIRECTORY}/bin/${FPCPP_SIZE_TYPE}${FPCPP_SUFFIX}) 26 | 27 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY 28 | ${FPCPP_BINARY_PATH} 29 | CACHE PATH 30 | "Single Directory for all Executables.") 31 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY 32 | ${FPCPP_BINARY_PATH} 33 | CACHE PATH 34 | "Single Directory for all Libraries") 35 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY 36 | ${FPCPP_LIBRARY_PATH} 37 | CACHE PATH 38 | "Single Directory for all static libraries.") 39 | 40 | if(UNIX OR MINGW) 41 | set(STOP_ON_FIRST_ERROR TRUE CACHE BOOL "Stop compilation on first error") 42 | if(TREAT_WARNINGS_AS_ERRORS) 43 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") 44 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") 45 | endif() 46 | if (STOP_ON_FIRST_ERROR) 47 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wfatal-errors") 48 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wfatal-errors") 49 | endif() 50 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -std=c++0x -Wall -Wno-missing-braces") 51 | if(MINGW) 52 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -U__STRICT_ANSI__") 53 | endif() 54 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 55 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wno-deprecated") 56 | else() 57 | add_definitions( "-DDEBUG" ) 58 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DNDEBUG -fomit-frame-pointer -Wno-deprecated -fno-omit-frame-pointer") 59 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -DNDEBUG -fomit-frame-pointer -Wno-deprecated -fno-omit-frame-pointer") 60 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") 61 | endif() 62 | endif() 63 | 64 | if(MSVC) 65 | SET(LINK_STATIC_RUNTIME OFF CACHE BOOL "Link statically against C++ runtime") 66 | if(TREAT_WARNINGS_AS_ERRORS) 67 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") 68 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") 69 | endif() 70 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /DNOMINMAX /MP /W3") 71 | if(MSVC10 OR MSVC11) 72 | SET(ITERATOR_DEBUG TRUE CACHE BOOL "Use iterator debug level 2") 73 | #add_definitions("-D_ITERATOR_DEBUG_LEVEL=0") 74 | if (ITERATOR_DEBUG) 75 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_ITERATOR_DEBUG_LEVEL=2") 76 | else() 77 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_ITERATOR_DEBUG_LEVEL=0") 78 | endif() 79 | #add_definitions("-D_ITERATOR_DEBUG_LEVEL=0") 80 | endif() 81 | # Extra speed optimisation options 82 | set(MSVC_EXTRA_OPTIMIZE ON CACHE BOOL "Use extra optimization flags in release builds") 83 | if(MSVC_EXTRA_OPTIMIZE) 84 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Ox /GL /GS- /fp:fast") 85 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ox /GL /GS- /fp:fast") 86 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF /LTCG") 87 | set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF /LTCG") 88 | endif() 89 | # Even more speed optimisations 90 | set(MSVC_OPTIMIZE_SSE2 ON CACHE BOOL "Use SSE2 instruction set in release builds") 91 | if(MSVC_OPTIMIZE_SSE2) 92 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /arch:SSE2") 93 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /arch:SSE2") 94 | endif() 95 | #ADD_DEFINITIONS("-D_SCL_SECURE_NO_WARNINGS") 96 | #ADD_DEFINITIONS("-D_CRT_SECURE_NO_WARNINGS") 97 | if(LINK_STATIC_RUNTIME AND NOT BUILD_SHARED_LIBS) 98 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") 99 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 100 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:msvcrt /NODEFAULTLIB:msvcrtd") 101 | set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:msvcrt /NODEFAULTLIB:msvcrtd") 102 | endif() 103 | endif() 104 | 105 | include_directories(include) 106 | include_directories(externals) 107 | 108 | if(BUILD_FPCPP_SAMPLES OR BUILD_FPCPP_TESTS) 109 | include_directories(common) 110 | include_directories(external) 111 | include_directories(samples) 112 | endif() 113 | 114 | if(BUILD_FPCPP_SAMPLES) 115 | add_subdirectory(samples) 116 | endif() 117 | 118 | if(BUILD_FPCPP_TESTS) 119 | include_directories(${FPCPP_SOURCE_DIR}/tests) 120 | add_subdirectory(externals/googletest) 121 | add_subdirectory(tests) 122 | endif() 123 | -------------------------------------------------------------------------------- /include/fp_prelude_math.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_PRELUDE_MATH_H_ 8 | #define _FP_PRELUDE_MATH_H_ 9 | 10 | #include "fp_defines.h" 11 | 12 | #define _USE_MATH_DEFINES 13 | #include 14 | #undef _USE_MATH_DEFINES 15 | 16 | #if defined(_MSC_VER) 17 | #include 18 | #else 19 | #include 20 | #endif 21 | 22 | namespace fp { 23 | namespace math { 24 | 25 | /////////////////////////////////////////////////////////////////////////// 26 | // Arithmetic operations 27 | 28 | template 29 | inline T add(const T& t0, const T& t1) { 30 | return t0 + t1; 31 | } 32 | 33 | template 34 | inline T subtract(const T& t0, const T& t1) { 35 | return t0 - t1; 36 | } 37 | 38 | template 39 | inline T multiply(const T& t0, const T& t1) { 40 | return t0 * t1; 41 | } 42 | 43 | template 44 | inline T divide(const T& t0, const T& t1) { 45 | return t0 / t1; 46 | } 47 | 48 | template 49 | inline T negate(const T& t0) { 50 | return -t0; 51 | } 52 | 53 | template 54 | inline fp_enable_if_integral(T) mod(T t0, T t1) { 55 | return t0 % t1; 56 | } 57 | 58 | template 59 | inline fp_enable_if_arithmetic(T) sqrt(T t) { 60 | return std::sqrt(t); 61 | } 62 | 63 | template 64 | inline fp_enable_if_arithmetic(T) abs(T t0) { 65 | return std::abs(t0); 66 | } 67 | 68 | 69 | /////////////////////////////////////////////////////////////////////////// 70 | // Logical operations 71 | 72 | template 73 | inline fp_enable_if_integral(T) logicalAnd(const T& t0, const T& t1) { 74 | return t0 && t1; 75 | } 76 | 77 | template 78 | inline fp_enable_if_integral(T) logicalOr(const T& t0, const T& t1) { 79 | return t0 || t1; 80 | } 81 | 82 | template 83 | inline fp_enable_if_integral(T) logicalNot(const T& t0) { 84 | return !t0; 85 | } 86 | 87 | 88 | /////////////////////////////////////////////////////////////////////////// 89 | // Comparison operations 90 | 91 | template 92 | inline bool equals(const T& t0, const T& t1) { 93 | return t0 == t1; 94 | } 95 | 96 | template 97 | inline bool notEquals(const T& t0, const T& t1) { 98 | return !equals(t0,t1); 99 | } 100 | 101 | template 102 | inline bool greaterEquals(const T& t0, const T& t1) { 103 | return t0 >= t1; 104 | } 105 | 106 | template 107 | inline bool lessEquals(const T& t0, const T& t1) { 108 | return t0 <= t1; 109 | } 110 | 111 | template 112 | inline bool less(const T& t0, const T& t1) { 113 | return t0 < t1; 114 | } 115 | 116 | template 117 | inline bool greater(const T& t0, const T& t1) { 118 | return t0 > t1; 119 | } 120 | 121 | template 122 | inline fp_enable_if_integral(T) even(T t) { 123 | return mod(t, 2) == 0; 124 | } 125 | 126 | template 127 | inline fp_enable_if_integral(T) odd(T t) { 128 | return mod(t, 2) == 1; 129 | } 130 | 131 | template 132 | inline fp_enable_if_integral(T) powerOfTwo(T t) { 133 | return (t != 0) && (((t-1) & t) == 0); 134 | } 135 | 136 | 137 | ///////////////////////////////////////////////////////////////////////// 138 | // Random operations 139 | 140 | #if defined(_MSC_VER) 141 | using std::uniform_real; 142 | using std::uniform_int; 143 | using std::mt19937; 144 | using std::random_device; 145 | #else 146 | using std::tr1::uniform_real; 147 | using std::tr1::uniform_int; 148 | using std::tr1::mt19937; 149 | using std::tr1::random_device; 150 | #endif 151 | 152 | // /////////////////////////////////////////////////////////////////////////// 153 | // uniform 154 | 155 | #if !defined(__MINGW32__) 156 | 157 | typedef mt19937 uniform_gen; 158 | 159 | template 160 | inline typename std::enable_if< std::is_floating_point::value, T>::type 161 | uniform(T t0, T t1) { 162 | static uniform_gen generator; 163 | return uniform_real(t0, t1)(generator); 164 | } 165 | 166 | template 167 | inline typename std::enable_if< !std::is_floating_point::value, T>::type 168 | uniform(T t0, T t1) { 169 | static uniform_gen generator; 170 | return uniform_int(t0, t1)(generator); 171 | } 172 | 173 | template 174 | struct uniform_ { 175 | uniform_(T t0, T t1, unsigned long long seed) 176 | : mUniform(t0, t1), mGenerator(seed) { } 177 | uniform_(T t0, T t1) 178 | : mUniform(t0, t1), mGenerator(random_device()()) { } 179 | 180 | T operator()() const { return mUniform(mGenerator); } 181 | 182 | uniform_real mUniform; 183 | mutable uniform_gen mGenerator; 184 | }; 185 | 186 | #else 187 | 188 | template 189 | inline T uniform(T t0, T t1) { 190 | return (T)(t0 + static_cast(rand())/((unsigned long long)RAND_MAX+1) * (t1 - t0)); 191 | } 192 | template 193 | struct uniform_ { 194 | uniform_(T t0_, T t1_) : t0(t0_), t1(t1_) { } 195 | T operator()() { return uniform(t0,t1); } 196 | T t0, t1; 197 | }; 198 | 199 | #endif 200 | 201 | } /* namespace math */ 202 | } /* namespace fp */ 203 | 204 | #endif /* _FP_PRELUDE_MATH_H_ */ 205 | -------------------------------------------------------------------------------- /include/fp_curry.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_CURRY_H_ 8 | #define _FP_CURRY_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | namespace fp { 17 | 18 | template struct curry_helper_impl; 19 | 20 | // When all arguments are given, we can uniquely determine the function type (useful for template/overloaded functions) 21 | 22 | template<> struct curry_helper_impl<1> { 23 | template 24 | static inline auto bind(F f, T t) -> std::function< decltype( f(t) ) (void) > { 25 | typedef decltype( f(t) ) result_type; 26 | return std::bind( static_cast< std::function< result_type (T) > >(f), t ); 27 | } 28 | }; 29 | template<> struct curry_helper_impl<2> { 30 | template 31 | static inline auto bind(F f, T t) FP_RETURNS( FP_CURRY2(FP_PREFIX1) ); 32 | template 33 | static inline auto bind2(F f, T t, T1 t1) -> std::function< decltype( f(t,t1) ) (void) > { 34 | typedef decltype( f(t,t1) ) result_type; 35 | return std::bind( static_cast< std::function< result_type (T,T1) > >(f), t, t1 ); 36 | } 37 | }; 38 | template<> struct curry_helper_impl<3> { 39 | template 40 | static inline auto bind(F f, T t) FP_RETURNS( FP_CURRY3(FP_PREFIX1) ); 41 | template 42 | static inline auto bind2(F f, T t, T1 t1) FP_RETURNS( FP_CURRY2(FP_PREFIX2) ); 43 | template 44 | static inline auto bind3(F f, T t, T1 t1, T2 t2) -> std::function< decltype( f(t,t1,t2) ) (void) > { 45 | typedef decltype( f(t,t1,t2) ) result_type; 46 | return std::bind( static_cast< std::function< result_type (T,T1,T2) > >(f), t, t1, t2 ); 47 | } 48 | }; 49 | template<> struct curry_helper_impl<4> { 50 | template 51 | static inline auto bind(F f, T t) FP_RETURNS( FP_CURRY4(FP_PREFIX1) ); 52 | template 53 | static inline auto bind2(F f, T t, T1 t1) FP_RETURNS( FP_CURRY3(FP_PREFIX2) ); 54 | template 55 | static inline auto bind3(F f, T t, T1 t1, T2 t2) FP_RETURNS( FP_CURRY2(FP_PREFIX3) ); 56 | template 57 | static inline auto bind4(F f, T t, T1 t1, T2 t2, T3 t3) -> std::function< decltype( f(t,t1,t2,t3) ) (void) > { 58 | typedef decltype( f(t,t1,t2,t3) ) result_type; 59 | return std::bind( static_cast< std::function< result_type (T,T1,T2,T3) > >(f), t, t1, t2, t3 ); 60 | } 61 | }; 62 | 63 | template struct curry_helper : public curry_helper_impl::arity> { }; 64 | 65 | template 66 | inline auto curry(F f, T t) FP_RETURNS( fp::curry_helper::bind(f,t) ); 67 | 68 | template 69 | inline auto curry2(F f, T t, T1 t1) FP_RETURNS( fp::curry_helper::bind2(f,t,t1) ); 70 | 71 | template 72 | inline auto curry3(F f, T t, T1 t1, T2 t2) FP_RETURNS( fp::curry_helper::bind3(f,t,t1,t2) ); 73 | 74 | template 75 | inline auto curry4(F f, T t, T1 t1, T2 t2, T3 t3) FP_RETURNS( fp::curry_helper::bind4(f,t,t1,t2,t3) ); 76 | 77 | // This is useful for template/overloaded functions... using the arguments, we can uniquely determine the 78 | // the function template instance, and in turn curry the arguments 79 | template 80 | inline auto curryAll(F f, T t) FP_RETURNS( std::bind(f,t) ); 81 | 82 | template 83 | inline auto curryAll2(F f, T t, T1 t1) FP_RETURNS( std::bind(f,t,t1) ); 84 | 85 | template 86 | inline auto curryAll3(F f, T t, T1 t1, T2 t2) FP_RETURNS( std::bind(f,t,t1,t2) ); 87 | 88 | template 89 | inline auto curryAll4(F f, T t, T1 t1, T2 t2, T3 t3) FP_RETURNS( std::bind(f,t,t1,t2,t3) ); 90 | 91 | 92 | /////////////////////////////////////////////////////////////////////////// 93 | // uncurry 94 | 95 | template 96 | struct uncurryF { 97 | 98 | uncurryF(F f_) : f(f_) { } 99 | 100 | template 101 | inline auto operator()(const std::pair& p2) -> decltype( declval()( p2.first, p2.second ) ) { 102 | return f( p2.first, p2.second ); 103 | } 104 | template 105 | inline auto operator()(const std::tuple& p3) -> decltype( declval()( std::get<0>(p3), std::get<1>(p3), std::get<2>(p3) ) ) { 106 | return f( std::get<0>(p3), std::get<1>(p3), std::get<2>(p3) ); 107 | } 108 | template 109 | inline auto operator()(const std::tuple& p4) -> decltype( declval()( std::get<0>(p4), std::get<1>(p4), std::get<2>(p4), std::get<3>(p4) ) ) { 110 | return f( std::get<0>(p4), std::get<1>(p4), std::get<2>(p4), std::get<3>(p4) ); 111 | } 112 | 113 | private: 114 | F f; 115 | }; 116 | 117 | template 118 | inline uncurryF uncurry(F f) { 119 | return uncurryF(f); 120 | } 121 | 122 | } /* namespace fp */ 123 | 124 | #endif /* _FP_CURRY_H_ */ 125 | -------------------------------------------------------------------------------- /samples/playlist.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | // Clang has compilation issues with the regex include 8 | #if !defined(__clang__) 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | using std::string; 20 | using std::regex; 21 | using std::regex_match; 22 | 23 | regex extensionRegex(const string& extension) { 24 | string result("^.*.\\.("); 25 | result.append(extension).append(")$"); 26 | return regex(result, regex::icase); 27 | } 28 | 29 | template 30 | regex extensionsRegex(const C& extensions) { 31 | let extensionsString = fp::foldl1( [](const string& a, const string& b) -> string { 32 | let result = a; 33 | return result.append("|").append(b); 34 | }, extensions ); 35 | return extensionRegex(extensionsString); 36 | } 37 | 38 | /////////////////////////////////////////////////////////////////////////// 39 | 40 | enum OpType { 41 | REMOVE = 0, 42 | COPY, 43 | MOVE, 44 | RENAME, 45 | NUM_OP_TYPES, 46 | INVALID_OP_TYPE, 47 | }; 48 | 49 | std::array OpTypeNames = { 50 | "remove", 51 | "copy", 52 | "move" 53 | }; 54 | std::array OpTypeArgs = { 55 | 1, 56 | 2, 57 | 2, 58 | }; 59 | let invalidOp = [](const fp::FilePath&) { return false; }; 60 | 61 | ///////////////////////////////////////////////////////////////////////////// 62 | 63 | enum SongType { 64 | MP3 = 0, 65 | WAV, 66 | OGG, 67 | WMA, 68 | FLAC, 69 | NUM_SONG_TYPES 70 | }; 71 | 72 | std::array SongTypeExtensions = { 73 | "mp3", 74 | "wav", 75 | "ogg", 76 | "wma", 77 | "flac" 78 | }; 79 | bool songFilter( const fp::FilePath& filePath ) { 80 | static const let songRegex = extensionsRegex( SongTypeExtensions ); 81 | return regex_match( filePath, songRegex ); 82 | }; 83 | 84 | ///////////////////////////////////////////////////////////////////////////// 85 | 86 | enum PlaylistType { 87 | M3U = 0, 88 | WPL, 89 | NUM_PLAYLIST_TYPES 90 | }; 91 | 92 | std::array PlaylistTypeExtensions = { 93 | "m3u", 94 | "wpl" 95 | }; 96 | 97 | typedef fp::types< string >::list Playlist; 98 | 99 | /////////////////////////////////////////////////////////////////////////// 100 | 101 | template struct PlaylistUtils; 102 | 103 | template<> struct PlaylistUtils { 104 | static Playlist create( const fp::FilePath& filePath ) { 105 | let m3uLineFilter = []( const string& line ) { 106 | return (!line.empty()) && 107 | ( line[0] != '#') && 108 | ( line.find_first_of(".mp3") != std::string::npos ); 109 | }; 110 | 111 | std::ifstream ifs( filePath ); 112 | return fp::filter( m3uLineFilter, fp::lines(filePath) ); 113 | } 114 | }; 115 | 116 | template<> struct PlaylistUtils { 117 | static Playlist create( const fp::FilePath& filePath ) { 118 | using namespace rapidxml; 119 | file xmlFile( fp::fromString(filePath) ); 120 | xml_document<> doc; 121 | doc.parse<0>(xmlFile.data()); 122 | let node = doc.first_node("media"); 123 | let wplLines = [&]() mutable -> string { 124 | if (node) { 125 | let mp3Attribute = node->first_attribute("src"); 126 | if (mp3Attribute) 127 | return mp3Attribute->value(); 128 | else 129 | return "invalid"; 130 | node = node->next_sibling("media"); 131 | } else { 132 | return ""; 133 | } 134 | }; 135 | return fp::takeWhileT( [](const string& s) { 136 | return !s.empty(); 137 | }, wplLines ); 138 | } 139 | }; 140 | 141 | ///////////////////////////////////////////////////////////////////////////// 142 | 143 | template 144 | bool filteredMap( MapOp mapOp, FilterOp filterOp, Source source ) { 145 | using namespace fp; 146 | return all(istrue, 147 | map(mapOp, 148 | filter(filterOp, 149 | source))); 150 | } 151 | 152 | Playlist songs( const fp::FilePath& filePath ) { 153 | if ( std::regex_match( filePath, extensionRegex( PlaylistTypeExtensions[M3U] ) ) ) { 154 | return PlaylistUtils::create( filePath ); 155 | } else if ( std::regex_match( filePath, extensionRegex( PlaylistTypeExtensions[WPL] ) ) ) { 156 | return PlaylistUtils::create( filePath ); 157 | } else { 158 | return Playlist(); 159 | } 160 | } 161 | 162 | typedef std::function SongOp; 163 | OpType opType( const string& opName ) { 164 | for (size_t op = 0; op < NUM_OP_TYPES; ++op) { 165 | if ( OpTypeNames[op] == opName ) 166 | return OpType(op); 167 | } 168 | return INVALID_OP_TYPE; 169 | } 170 | SongOp operation( int argc, char **argv ) { 171 | 172 | let op = opType( argv[1] ); 173 | if (INVALID_OP_TYPE == op) 174 | return invalidOp; 175 | 176 | let opArgC = OpTypeArgs[op]; 177 | if (int(opArgC + 2) < argc) 178 | return invalidOp; 179 | 180 | switch ( op ) { 181 | case REMOVE: 182 | case COPY: 183 | case MOVE: 184 | default: 185 | return invalidOp; 186 | }; 187 | } 188 | 189 | int main(int argc, char **argv) { 190 | 191 | if (argc < 2) 192 | return 0; 193 | 194 | let songOperation = operation(argc, argv); 195 | 196 | filteredMap( songOperation, &songFilter, songs(argv[2]) ); 197 | 198 | //TODO: parse args 199 | //TODO: dispatch commands 200 | 201 | return 0; 202 | } 203 | 204 | #else 205 | 206 | int main(int argc, char **argv) { 207 | return 0; 208 | } 209 | 210 | #endif // !defined(__clang__) -------------------------------------------------------------------------------- /samples/flocking.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #define _USE_MATH_DEFINES 12 | #include 13 | #include 14 | 15 | #if WIN32 16 | #include 17 | inline void idle(DWORD milliseconds) { Sleep(milliseconds); } 18 | #else 19 | #include 20 | inline void idle(size_t microseconds) { usleep(microseconds*1000); } 21 | #endif 22 | 23 | /////////////////////////////////////////////////////////////////////////// 24 | 25 | enum { 26 | BOIDS = 25, 27 | X = 80, 28 | Y = 30, 29 | NEIGHBORHOOD = 15, 30 | AVOIDANCE = 5, 31 | }; 32 | 33 | /////////////////////////////////////////////////////////////////////////// 34 | 35 | using fp::fst; 36 | using fp::snd; 37 | using fp::index; 38 | using fp::types; 39 | typedef types::pair P; 40 | typedef types::pair D; 41 | typedef types::pair Boid; 42 | typedef types::list Boids; 43 | 44 | P pos(const Boid& b) { return fst(b); } 45 | D dir(const Boid& b) { return snd(b); } 46 | 47 | namespace std { 48 | template< typename T > 49 | std::pair operator+(const std::pair& a, const std::pair& b) { 50 | return std::make_pair( fst(a) + fst(b), snd(b) + snd(b) ); 51 | } 52 | template< typename T > 53 | std::pair operator-(const std::pair& a, const std::pair& b) { 54 | return std::make_pair( fst(a) - fst(b), snd(b) - snd(b) ); 55 | } 56 | template< typename T > 57 | std::pair operator*(const std::pair& a, T b) { 58 | return std::make_pair( fst(a) * b, snd(a) * b ); 59 | } 60 | template< typename T > 61 | std::pair operator/(const std::pair& a, T b) { 62 | return std::make_pair( fst(a) / b, snd(a) / b ); 63 | } 64 | } 65 | using namespace std; 66 | 67 | template 68 | inline float length( const T& t ) { 69 | const let x = fst(t); 70 | const let y = snd(t); 71 | return sqrtf( (float)x*x + (float)y*y ); 72 | } 73 | 74 | template 75 | inline T normalize( const T& t ) { 76 | const let tLength = length( t ); 77 | return tLength > 0.f ? t / tLength : t; 78 | } 79 | 80 | template 81 | inline float dist( const T& a, const T& b) { 82 | return length( a - b ); 83 | } 84 | 85 | template 86 | inline T clamp(const T& value, const U& low, const V& high) { 87 | return value < low ? low : (value > high ? high : value); 88 | } 89 | 90 | template 91 | inline T fmod_(T t, T modulus) { 92 | return t >= (T)0 ? fmod(t, modulus) : modulus - fmod(-t, modulus); 93 | } 94 | 95 | template 96 | inline T pmod( const T& t, U fstMod, U sndMod ) { 97 | return T( fmod_( fst(t), fstMod ), fmod_( snd(t), sndMod ) ); 98 | } 99 | 100 | /////////////////////////////////////////////////////////////////////////// 101 | 102 | D avoidance( const Boid& boid, const Boids& neighbors ) { 103 | return fp::sum( fp::map( [&](const Boid& otherBoid) -> D { 104 | const let avoidanceWeight = 1.f - (dist( pos(boid), pos(otherBoid) ) / NEIGHBORHOOD); 105 | return normalize( pos(boid) - pos(otherBoid) ) * avoidanceWeight + 106 | dir( boid ) * (1.f - avoidanceWeight); 107 | }, neighbors) ) / (float)neighbors.size(); 108 | } 109 | 110 | D alignment( const Boid& boid, const Boids& neighbors ) { 111 | const let avgDir = fp::sum( fp::map( &dir, neighbors )) / (float)neighbors.size(); 112 | return (avgDir + dir( boid )) *.5f; 113 | } 114 | 115 | D cohesion( const Boid& boid, const Boids& neighbors ) { 116 | const let avgPos = fp::sum( fp::map( &pos, neighbors) ) / (float)neighbors.size(); 117 | return (normalize( avgPos - pos( boid ) ) + dir( boid )) *.5f; 118 | } 119 | 120 | Boid evolve( const Boid& boid, const Boids& neighbors ) { 121 | 122 | let newDir = dir( boid ); 123 | 124 | if ( fp::length(neighbors) != 0) { 125 | 126 | std::array weights = { .5f, .2f, .3f }; 127 | 128 | newDir = normalize( avoidance( boid, neighbors ) * weights[0] + 129 | alignment( boid, neighbors ) * weights[1] + 130 | cohesion( boid, neighbors ) * weights[2] ); 131 | 132 | } 133 | 134 | let newPos = pmod( pos( boid ) + newDir, (float)X, (float)Y); 135 | 136 | return Boid( newPos, newDir ); 137 | } 138 | 139 | /////////////////////////////////////////////////////////////////////////// 140 | 141 | Boids evolve( const Boids& boids, size_t x, size_t y ) { 142 | 143 | return fp::map( [=,&boids]( const Boid& boid ) -> Boid { 144 | 145 | let neighbors = fp::filter( [=,&boid]( const Boid& otherBoid ) { 146 | return ( boid != otherBoid ) && 147 | ( dist( pos(boid), pos(otherBoid) ) < NEIGHBORHOOD ); 148 | }, boids ); 149 | 150 | return evolve( boid, neighbors ); 151 | 152 | }, boids); 153 | } 154 | 155 | #ifndef M_PI 156 | #define M_PI 3.14159265358979323846 157 | #endif 158 | 159 | int main(int argc, char **argv) { 160 | 161 | srand((unsigned)time((time_t*)NULL)); 162 | 163 | std::array cardinalToChar = { '-', '/', '|', '\\', '-', '/', '|', '\\' }; 164 | let showCell = [&]( const D& v ) -> char { 165 | if (length(v) < .25) 166 | return ' '; 167 | let theta = atan2f( snd(v), fst(v) ); 168 | theta = theta < 0.f ? theta + 2.f*(float)M_PI : theta; 169 | let const index = (int)(theta * (4.f/M_PI)) % cardinalToChar.size(); 170 | return cardinalToChar[index]; 171 | }; 172 | 173 | let boids = fp::zip(fp::zip(fp::uniformN(BOIDS, 0.f, (float)X), 174 | fp::uniformN(BOIDS, 0.f, (float)Y)), 175 | fp::zip(fp::uniformN(BOIDS, -1.f,1.f), 176 | fp::uniformN(BOIDS, -1.f,1.f))); 177 | 178 | typedef std::array< D, X > Row; 179 | typedef std::array< Row, Y > Grid; 180 | 181 | while (true) { 182 | boids = evolve(boids, X, Y); 183 | 184 | Grid grid; 185 | for (size_t i = 0; i < fp::length(boids); ++i) { 186 | let x = (int)fst( pos(index(i,boids)) ) % X; 187 | let y = (int)snd( pos(index(i,boids)) ) % Y; 188 | grid[y][x] = grid[y][x] + dir( index(i,boids) ); 189 | } 190 | let showRow = [=](const Row& r) -> std::string { return fp::show(fp::map( showCell, r) ); }; 191 | std::cout << std::endl << fp::foldl1( [](const std::string& a, const std::string& b) { 192 | return a + "\n" + b; 193 | }, fp::map( showRow, grid )) << std::endl << std::endl; 194 | } 195 | 196 | return 0; 197 | } 198 | -------------------------------------------------------------------------------- /include/fp_template_utils.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_TEMPLATE_UTILS_H_ 8 | #define _FP_TEMPLATE_UTILS_H_ 9 | 10 | #include "fp_defines.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #if !FP_DECLVAL 21 | namespace std { 22 | template 23 | typename std::add_rvalue_reference::type declval() FP_NOEXCEPT; 24 | } 25 | #endif 26 | 27 | namespace fp { 28 | 29 | /////////////////////////////////////////////////////////////////////////// 30 | // is_container 31 | 32 | template 33 | class is_container { 34 | typedef char true_type; 35 | struct false_type{ true_type _[2]; }; 36 | template static true_type has_iterator_checker(typename C::iterator *); 37 | template static false_type has_iterator_checker(...); 38 | public: 39 | static const size_t value = (sizeof(has_iterator_checker(0)) == sizeof(true_type)); 40 | }; 41 | 42 | template 43 | class is_functor { 44 | typedef char true_type; 45 | struct false_type{ true_type _[2]; }; 46 | template static true_type has_operator(decltype(&T::operator())); 47 | template static false_type has_operator(...); 48 | 49 | public: 50 | static const size_t value = (sizeof(has_operator(0)) == sizeof(true_type)); 51 | }; 52 | 53 | /////////////////////////////////////////////////////////////////////////// 54 | // remove_const_ref 55 | 56 | template 57 | struct remove_const_ref { 58 | typedef typename std::remove_const< typename std::remove_reference::type >::type type; 59 | }; 60 | 61 | 62 | /////////////////////////////////////////////////////////////////////////// 63 | // int_to_type/type_to_type/select 64 | 65 | template 66 | struct int_to_type { 67 | enum { value = v }; 68 | }; 69 | 70 | template 71 | struct type_to_type { 72 | typedef T type; 73 | }; 74 | 75 | template 76 | struct select { 77 | typedef T result_type; 78 | }; 79 | template 80 | struct select { 81 | typedef U result_type; 82 | }; 83 | 84 | /////////////////////////////////////////////////////////////////////////// 85 | // traits 86 | 87 | template struct traits_helper { }; 88 | 89 | template 90 | struct traits_helper { 91 | typedef T& ref_type; 92 | typedef decltype( begin( std::declval() ) ) iterator; 93 | typedef decltype( begin( std::declval() ) ) const_iterator; 94 | typedef typename remove_const_ref< decltype( *begin( std::declval() ) ) >::type value_type; 95 | }; 96 | 97 | template 98 | struct traits_helper { 99 | typedef typename select::value, T, T&>::result_type ref_type; 100 | typedef T* iterator; 101 | typedef const T* const_iterator; 102 | typedef typename remove_const_ref< T >::type value_type; 103 | }; 104 | 105 | template 106 | struct traits : public traits_helper::value> { }; 107 | 108 | template 109 | struct tuple_traits { 110 | typedef typename traits::value_type t; 111 | typedef typename traits::value_type u; 112 | typedef std::pair type; 113 | }; 114 | 115 | template 116 | struct traits { 117 | typedef T value_type; 118 | typedef T* iterator; 119 | typedef const T* const_iterator; 120 | }; 121 | 122 | template 123 | struct triple_traits { 124 | typedef typename traits::value_type t; 125 | typedef typename traits::value_type u; 126 | typedef typename traits::value_type v; 127 | typedef std::tuple type; 128 | }; 129 | 130 | /////////////////////////////////////////////////////////////////////////// 131 | // types 132 | 133 | template 134 | struct types { 135 | typedef fp_list list; 136 | typedef std::pair pair; 137 | }; 138 | 139 | /////////////////////////////////////////////////////////////////////////// 140 | // has_find 141 | 142 | template 143 | struct has_find { 144 | typedef char Yes[1]; 145 | typedef char No[2]; 146 | typedef typename traits::iterator It; 147 | 148 | template struct Check; 149 | 150 | template static Yes& Test(Check*); 151 | template static No& Test(...); 152 | 153 | static const bool value = sizeof(Test(0)) == sizeof(Yes); 154 | }; 155 | 156 | /////////////////////////////////////////////////////////////////////////// 157 | // transform3 158 | 159 | template 161 | OutputIterator transform3(InputIterator1 first1, 162 | InputIterator1 last1, 163 | InputIterator2 first2, 164 | InputIterator3 first3, 165 | OutputIterator d_first, 166 | TernaryOperation ternary_op) 167 | { 168 | while (first1 != last1) { 169 | *d_first++ = ternary_op(*first1++, *first2++, *first3++); 170 | } 171 | return d_first; 172 | } 173 | 174 | /////////////////////////////////////////////////////////////////////////// 175 | // copyWhile 176 | 177 | template 178 | inline InputIterator copyWhile(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation unary_op) { 179 | while ((first != last) && unary_op(*first)) { 180 | *result++ = *first++; 181 | } 182 | return first; 183 | } 184 | 185 | /////////////////////////////////////////////////////////////////////////// 186 | // rbegin/rend 187 | 188 | template 189 | inline auto rbegin(C& c) -> decltype(c.rbegin()) { 190 | return c.rbegin(); 191 | } 192 | 193 | template 194 | inline auto rend(C& c) -> decltype(c.rend()) { 195 | return c.rend(); 196 | } 197 | 198 | /////////////////////////////////////////////////////////////////////////// 199 | 200 | template 201 | auto iter_value(I i, const C& c) -> value_type_of(C) { 202 | typedef value_type_of(C) value_type; 203 | return (i != end(c)) ? *i : value_type(); 204 | } 205 | 206 | 207 | } /* namespace fp */ 208 | 209 | #endif /* _FP_TEMPLATE_UTILS_H_ */ 210 | -------------------------------------------------------------------------------- /include/fp_composition_utils.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_COMPOSITION_UTILS_H_ 8 | #define _FP_COMPOSITION_UTILS_H_ 9 | 10 | #include "fp_defines.h" 11 | #include "fp_template_utils.h" 12 | 13 | #include 14 | 15 | namespace fp { 16 | 17 | template class composed; 18 | template class composed2; 19 | 20 | /////////////////////////////////////////////////////////////////////////// 21 | 22 | template 23 | struct make_function_traits { 24 | typedef std::function::value, T>::type> type; 25 | }; 26 | 27 | template 28 | auto make_function(T *t) -> typename make_function_traits::type { 29 | return t; 30 | } 31 | 32 | /////////////////////////////////////////////////////////////////////////// 33 | 34 | 35 | /////////////////////////////////////////////////////////////////////////// 36 | 37 | template struct function_traits; 38 | template struct function_traits2; 39 | template struct function_traits3; 40 | 41 | /////////////////////////////////////////////////////////////////////////// 42 | 43 | #if FP_VARIADIC 44 | 45 | template 46 | struct function_traits : public function_traits< decltype( &T::operator() )> {}; 47 | 48 | template 49 | struct function_traits : public function_traits< typename make_function_traits::type > { }; 50 | 51 | template 52 | struct function_traits { 53 | static const size_t arity = sizeof...(Args); 54 | typedef R result_type; 55 | template 56 | struct arg { 57 | typedef typename std::tuple_element>::type type; 58 | }; 59 | }; 60 | 61 | template 62 | struct function_traits { 63 | static const size_t arity = sizeof...(Args); 64 | typedef R result_type; 65 | template 66 | struct arg { 67 | typedef typename std::tuple_element>::type type; 68 | }; 69 | }; 70 | 71 | template 72 | struct results; 73 | 74 | template 75 | struct results { 76 | typedef typename std::result_of< F(Args...) >::type type; 77 | }; 78 | 79 | template 80 | struct compound_result { 81 | typedef typename results::type U; 82 | typedef typename results::type type; 83 | }; 84 | 85 | #else 86 | 87 | template 88 | struct function_traits : public function_traits< decltype( &T::operator() ) > {}; 89 | 90 | template 91 | struct function_traits : public function_traits< typename make_function_traits::type > { }; 92 | 93 | template 94 | struct function_traits2 { 95 | static const size_t arity = function_traits::arity + function_traits::arity; 96 | typedef typename function_traits::result_type result_type; 97 | }; 98 | 99 | template 100 | struct function_traits3 { 101 | static const size_t arity = function_traits2::arity + function_traits::arity; 102 | typedef typename function_traits::result_type result_type; 103 | }; 104 | 105 | template 106 | struct function_traits< composed > : public function_traits {}; 107 | 108 | template 109 | struct function_traits< composed2 > : public function_traits2 {}; 110 | 111 | template 112 | struct function_traits { 113 | static const size_t arity = 0; 114 | typedef R result_type; 115 | }; 116 | 117 | template 118 | struct function_traits { 119 | static const size_t arity = 1; 120 | typedef R result_type; 121 | typedef T0 t0_type; 122 | }; 123 | 124 | template 125 | struct function_traits { 126 | static const size_t arity = 2; 127 | typedef R result_type; 128 | typedef T0 t0_type; 129 | typedef T1 t1_type; 130 | }; 131 | 132 | template 133 | struct function_traits { 134 | static const size_t arity = 3; 135 | typedef R result_type; 136 | typedef T0 t0_type; 137 | typedef T1 t1_type; 138 | typedef T2 t2_type; 139 | }; 140 | 141 | template 142 | struct function_traits { 143 | static const size_t arity = 4; 144 | typedef R result_type; 145 | typedef T0 t0_type; 146 | typedef T1 t1_type; 147 | typedef T2 t2_type; 148 | typedef T3 t3_type; 149 | }; 150 | 151 | template 152 | struct function_traits { 153 | static const size_t arity = 5; 154 | typedef R result_type; 155 | typedef T0 t0_type; 156 | typedef T1 t1_type; 157 | typedef T2 t2_type; 158 | typedef T3 t3_type; 159 | typedef T4 t4_type; 160 | }; 161 | 162 | template 163 | struct function_traits { 164 | static const size_t arity = 0; 165 | typedef R result_type; 166 | }; 167 | 168 | template 169 | struct function_traits { 170 | static const size_t arity = 1; 171 | typedef R result_type; 172 | typedef T0 t0_type; 173 | }; 174 | 175 | template 176 | struct function_traits { 177 | static const size_t arity = 2; 178 | typedef R result_type; 179 | typedef T0 t0_type; 180 | typedef T1 t1_type; 181 | }; 182 | 183 | template 184 | struct function_traits { 185 | static const size_t arity = 3; 186 | typedef R result_type; 187 | typedef T0 t0_type; 188 | typedef T1 t1_type; 189 | typedef T2 t2_type; 190 | }; 191 | 192 | template 193 | struct function_traits { 194 | static const size_t arity = 4; 195 | typedef R result_type; 196 | typedef T0 t0_type; 197 | typedef T1 t1_type; 198 | typedef T2 t2_type; 199 | typedef T3 t3_type; 200 | }; 201 | 202 | template 203 | struct function_traits { 204 | static const size_t arity = 5; 205 | typedef R result_type; 206 | typedef T0 t0_type; 207 | typedef T1 t1_type; 208 | typedef T2 t2_type; 209 | typedef T3 t3_type; 210 | typedef T4 t4_type; 211 | }; 212 | 213 | #endif 214 | 215 | /////////////////////////////////////////////////////////////////////////// 216 | 217 | } /* namespace fp */ 218 | 219 | #endif /* _FP_COMPOSITION_UTILS_H */ 220 | -------------------------------------------------------------------------------- /include/fp_prelude_lazy.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_PRELUDE_LAZY_H_ 8 | #define _FP_PRELUDE_LAZY_H_ 9 | 10 | #include "fp_common.h" 11 | #include "fp_prelude_lists.h" 12 | 13 | namespace fp { 14 | 15 | /////////////////////////////////////////////////////////////////////////// 16 | // map 17 | 18 | template 19 | inline auto map(F f, thunk t) -> thunk< decltype(f(t())) > { 20 | return [=]() mutable { return f(t()); }; 21 | } 22 | 23 | /////////////////////////////////////////////////////////////////////////// 24 | // filter 25 | 26 | template 27 | inline thunk filter(F f, thunk t) { 28 | return [=]() -> T { 29 | let value = t(); 30 | while ( !f(value) ) { 31 | value = t(); 32 | } 33 | return value; 34 | }; 35 | } 36 | 37 | ////////////////////////////////////////////////////////////////////////// 38 | // scanl 39 | 40 | template 41 | thunk scanl(F f, T t0, thunk t) { 42 | return [=]() mutable -> T { 43 | let result = t0; 44 | t0 = f(result, t()); 45 | return result; 46 | }; 47 | } 48 | 49 | ////////////////////////////////////////////////////////////////////////// 50 | // scanl1 51 | 52 | template 53 | thunk scanl1(F f, thunk t) { 54 | let t0 = t(); 55 | return scanl(f, t0, t); 56 | } 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // zipWith 60 | 61 | template 62 | inline auto zipWith(F f, thunk t, thunk u) -> thunk< decltype( f(t(),u()) ) > { 63 | return [=]() mutable -> decltype( f(t(), u()) ) { 64 | return f(t(), u()); 65 | }; 66 | } 67 | 68 | template 69 | inline auto zipWith3(F f, thunk t, thunk u, thunk v) -> thunk< decltype( f(t(),u(),v()) ) > { 70 | return [=]() mutable -> decltype( f(t(),u(),v()) ) { 71 | return f(t(), u()); 72 | }; 73 | } 74 | 75 | /////////////////////////////////////////////////////////////////////////// 76 | // zip 77 | 78 | #if 0 79 | template 80 | inline thunk< std::pair > zip(thunk t, thunk u) { 81 | return zipWith( &make_pair, t, u ); 82 | } 83 | 84 | template 85 | inline thunk< std::pair > zip(thunk t, thunk u, thunk v) { 86 | return zipWith( &make_tuple, t, u, v ); 87 | } 88 | #endif 89 | 90 | /////////////////////////////////////////////////////////////////////////// 91 | // dropWhile 92 | 93 | template 94 | inline thunk dropWhile(F f, thunk t) { 95 | bool dropped = false; 96 | return [=]() mutable -> T { 97 | // If no values have been dropped, drop while f holds 98 | if (!dropped) { 99 | let result = t(); 100 | for ( ; !f(result); result = t() ) ; 101 | dropped = true; 102 | return result; 103 | } 104 | return t(); 105 | }; 106 | } 107 | 108 | /////////////////////////////////////////////////////////////////////////// 109 | // drop 110 | 111 | template 112 | inline thunk drop(size_t n, thunk t) { 113 | let dropN = [=](...) mutable { 114 | return n-- > 0; 115 | }; 116 | return dropWhile(dropN, t); 117 | } 118 | 119 | /////////////////////////////////////////////////////////////////////////// 120 | // splitAt 121 | 122 | // Does this even make sense? 123 | template 124 | inline pair< thunk, thunk > splitAt(size_t n, thunk t) { 125 | return make_pair( t, drop(n, t) ); 126 | } 127 | 128 | /////////////////////////////////////////////////////////////////////////// 129 | // span 130 | 131 | template 132 | inline pair< thunk, thunk > span(F f, thunk t) { 133 | return std::make_pair( t, dropWhile(f, t) ); 134 | } 135 | 136 | /////////////////////////////////////////////////////////////////////////// 137 | // break 138 | 139 | template 140 | inline std::pair< thunk, thunk > spanNot(F f, thunk t) { 141 | return span( std::not1(f), t ); 142 | } 143 | 144 | /////////////////////////////////////////////////////////////////////////// 145 | // index 146 | 147 | template 148 | inline T index(Index i, thunk t) { 149 | while( i-- > 0 ) t(); 150 | return t(); 151 | } 152 | 153 | #if defined(TODO_IMPLEMENT_LAZY) 154 | 155 | /////////////////////////////////////////////////////////////////////////// 156 | // concat 157 | template 158 | inline fp_enable_if_container(T,T) 159 | concat(const T& t0, const T& t1) { 160 | T result(t0); 161 | std::copy(extent(t1), back(result)); 162 | return result; 163 | } 164 | template 165 | inline fp_enable_if_not_container(T,typename types::list) 166 | concat(const T& t0, const T& t1) { 167 | typename types::list result(1, t0); 168 | return result.append(t1); 169 | } 170 | FP_DEFINE_FUNCTION_OBJECT(concat, concatF); 171 | 172 | /////////////////////////////////////////////////////////////////////////// 173 | // append 174 | template 175 | inline C append(C c, const T& t) { 176 | c.insert(end(c), t); 177 | return c; 178 | } 179 | FP_DEFINE_FUNCTION_OBJECT(append, appendF); 180 | 181 | /////////////////////////////////////////////////////////////////////////// 182 | // cons 183 | template 184 | inline C cons(const T& t, const C& c) { 185 | return concat( append(C(), t), c ); 186 | } 187 | template 188 | inline std::deque cons(const T& t, std::deque c) { 189 | c.push_front(t); 190 | return c; 191 | } 192 | inline string cons(char t, string s) { 193 | return s.insert(0, 1, t); 194 | } 195 | inline string cons(string s0, const string& s1) { 196 | return s0.append(s1); 197 | } 198 | FP_DEFINE_FUNCTION_OBJECT(cons, consF); 199 | 200 | /////////////////////////////////////////////////////////////////////////// 201 | // Pair/Tuple 202 | 203 | using std::pair; 204 | using std::make_pair; 205 | 206 | template 207 | inline nonconstref_type_of(T) fst(const pair& p) { 208 | return p.first; 209 | } 210 | FP_DEFINE_FUNCTION_OBJECT(fst, fstF); 211 | 212 | template 213 | inline nonconstref_type_of(U) snd(const pair& p) { 214 | return p.second; 215 | } 216 | FP_DEFINE_FUNCTION_OBJECT(snd, sndF); 217 | 218 | template 219 | inline pair swap(const pair& p) { 220 | return make_pair(p.first,p.second); 221 | } 222 | 223 | template 224 | inline auto mapPair(F0 f0, F1 f1, const std::pair& p) FP_RETURNS( make_pair( f0(p.first), f1(p.second) ) ); 225 | 226 | template 227 | inline auto mapFst(F f, const std::pair& p) FP_RETURNS( make_pair( f(p.first), p.second ) ); 228 | 229 | template 230 | inline auto mapArrow(F0 f0, F1 f1, const T& T) FP_RETURNS( make_pair( f0(t), f1(t) ) ); 231 | 232 | // TODO: Factor this out into some nice common code for re-use 233 | template 234 | struct mapArrowF { 235 | mapArrowF(F0 f0_, F1 f1_) : f0(f0_), f1(f1_) { } 236 | template 237 | inline auto operator()(const T& t) FP_RETURNS( make_pair( f0(t), f1(t) ) ); 238 | 239 | F0 f0; 240 | F1 f1; 241 | }; 242 | template 243 | mapArrowF mapArrowF_(F0 f0, F1 f1) { return mapArrowF(f0,f1); } 244 | 245 | #endif /* defined(TODO_IMPLEMENT_LAZY) */ 246 | 247 | } /* namespace fp */ 248 | 249 | #endif /* _FP_PRELUDE_LAZY_H_ */ 250 | -------------------------------------------------------------------------------- /samples/fun.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "fpcpp.h" 8 | 9 | #include 10 | #include 11 | #define _USE_MATH_DEFINES 12 | #include 13 | #include 14 | #include 15 | 16 | #define ENABLE_BENCHMARK 1 17 | #include "benchmark_common.h" 18 | 19 | using fp::string; 20 | using fp::types; 21 | using fp::pair; 22 | 23 | typedef types::list Row; 24 | typedef types::list Rows; 25 | 26 | typedef pair StringPair; 27 | typedef types::list StringList; 28 | typedef types::list StringLists; 29 | typedef types::list StringPairList; 30 | 31 | 32 | Rows pascalsTriangle( size_t count ) { 33 | 34 | using namespace fp; 35 | 36 | let nextRow = []( const Row& r ) -> Row { 37 | return fp::zipWith( fp::math::addF(), fp::cons( (int)0, r ), fp::append( r, 0 ) ); 38 | }; 39 | 40 | let pascals = iterate( nextRow, Row(1,1) ); 41 | 42 | return takeF( count, pascals ); 43 | 44 | } 45 | 46 | /////////////////////////////////////////////////////////////////////////// 47 | 48 | StringLists anagrams( const fp::FilePath& filePath ) { 49 | 50 | using namespace fp; 51 | 52 | typedef StringPair sp; 53 | typedef StringPairList spl; 54 | 55 | std::ifstream ifs; 56 | let& f = readFile( filePath, ifs ); 57 | let words = lines( f ); 58 | let groupon = compose2( math::equalsF(), fstF(), fstF() ); 59 | let wix = groupBy( groupon, sort( zip( map( sortF(), words ), words) ) ); 60 | let mxl = maximum( map( lengthF(), wix ) ); 61 | 62 | return map( []( const spl& sl ) { 63 | return fp::map( fp::sndF(), sl ); 64 | }, filter( [=]( const spl& sl ) { return fp::length( sl ) == mxl; }, wix) ); 65 | 66 | /* Compare with Haskell: 67 | 68 | import Data.List 69 | groupon f x y = f x == f y 70 | 71 | main = do 72 | f <- readFile "./../Puzzels/Rosetta/unixdict.txt" 73 | let words = lines f 74 | wix = groupBy (groupon fst) . sort $ zip (map sort words) words 75 | mxl = maximum $ map length wix 76 | mapM_ (print . map snd) . filter ((==mxl).length) $ wix 77 | */ 78 | } 79 | 80 | /////////////////////////////////////////////////////////////////////////// 81 | 82 | template 83 | T nthRoot( int n, T x ) { 84 | 85 | using namespace fp; 86 | 87 | typedef std::pair Guess; 88 | 89 | return fst( until( uncurry( math::equalsF() ), [=]( Guess g ) -> Guess { 90 | T x0 = fp::snd( g ); return Guess( x0, (x0*(n-1)+(x/pow(x0,n-1)))*(1./n) ); 91 | }, Guess( x, x/n ) ) ); 92 | 93 | /* Compare with Haskell: 94 | n `nthRoot` x = fst $ until (uncurry(==)) (\(_,x0) -> (x0,((n-1)*x0+x/x0**(n-1))/n)) (x,x/n) 95 | */ 96 | 97 | } 98 | 99 | /////////////////////////////////////////////////////////////////////////// 100 | 101 | template< typename T > 102 | typename types< typename types::list, typename types::list >::pair fftSplit( const typename types::list& s ) { 103 | using namespace fp; 104 | typedef typename types::list FFTVec; 105 | 106 | if ( length(s) == 0 ) return make_pair( FFTVec(), FFTVec() ); 107 | else if ( length(s) == 1 ) return make_pair( FFTVec(1, head(s)), FFTVec() ); 108 | else { 109 | let xt_yt = fftSplit( drop(2, s) ); 110 | return make_pair( cons( index(0,s), fst(move(xt_yt))), cons( index(1,s), snd(move(xt_yt)) ) ); 111 | } 112 | } 113 | 114 | #ifndef M_PI 115 | #define M_PI 3.14159265358979323846 116 | #endif 117 | 118 | template 119 | auto fft( V v ) -> typename types< std::complex< value_type_of(V) > >::list { 120 | typedef value_type_of(V) T; 121 | using namespace fp; 122 | 123 | typedef std::complex CT; 124 | typedef typename types< CT >::list FFTVec; 125 | 126 | let const n = length( v ); 127 | 128 | if ( n == 0 ) return FFTVec(); 129 | if ( n == 1 ) return FFTVec( 1, head(v) ); 130 | 131 | let const evenOdds = fftSplit( v ); 132 | let const ys = fft( fst( evenOdds) ); 133 | let const cx = [=](CT z, T k) { return z*std::polar((T)1, (T)(-2. * M_PI * (double)k/n)); }; 134 | let const ts = zipWith( cx, fft( snd( evenOdds) ), increasingN( n/2, (T)0 ) ); 135 | 136 | return concat( zipWith( std::plus< CT >(), ys, ts ), 137 | zipWith( std::minus< CT >(), ys, ts ) ); 138 | 139 | /* Compare with Haskell: 140 | 141 | fft [] = [] 142 | fft [x] = [x] 143 | fft xs = zipWith (+) ys ts ++ zipWith (-) ys ts 144 | where n = length xs 145 | ys = fft evens 146 | zs = fft odds 147 | (evens, odds) = split xs 148 | split [] = ([], []) 149 | split [x] = ([x], []) 150 | split (x:y:xs) = (x:xt, y:yt) where (xt, yt) = split xs 151 | ts = zipWith (\z k -> exp' k n * z) zs [0..] 152 | exp' k n = cis $ -2 * pi * (fromIntegral k) / (fromIntegral n) 153 | 154 | */ 155 | } 156 | 157 | /////////////////////////////////////////////////////////////////////////// 158 | 159 | typedef pair Code; 160 | typedef pair Freq; 161 | typedef types< Code >::list Codes; 162 | typedef types< Freq >::list Frequencies; 163 | typedef fp::pair FreqCodes; 164 | 165 | Codes reduce( fp::types< FreqCodes >::list buf ) { 166 | 167 | using namespace fp; 168 | 169 | if (length(buf) == 1) return snd(head(buf)); 170 | 171 | let consC = (string(*)(char,string))cons; 172 | let cons0 = curry(consC, '0'); 173 | let cons1 = curry(consC, '1'); 174 | 175 | let add = [&]( const FreqCodes& a, const FreqCodes& b ) { 176 | return FreqCodes(a.first+b.first, 177 | fp::concat(fp::map(fp::mapSndF_(cons0), fp::snd(a)), 178 | fp::map(fp::mapSndF_(cons1), fp::snd(b)))); 179 | }; 180 | 181 | return reduce( insertBy( comparing(fstF()), 182 | add( index(0, buf), 183 | index(1, buf) ), 184 | drop(2, buf) ) ); 185 | } 186 | 187 | StringList huffman( string s ) { 188 | 189 | using namespace fp; 190 | 191 | let freq = []( types::list s ) { 192 | return fp::map( fp::mapArrowF_( fp::lengthF(), fp::headF() ), fp::group( fp::sort( std::move(s) ) ) ); 193 | }; 194 | 195 | let result = reduce( map( []( const Freq& f ) { 196 | return fp::make_pair( fp::fst(f), Codes(1, fp::make_pair( fp::snd(f), "" )) ); 197 | }, sortBy( comparing(fstF()), freq(list(s)) ) ) ); 198 | 199 | return map( [](const Code& c) { 200 | return fp::show("\'") + fp::fst(c) + "\' : " + fp::snd(c) + "\n"; 201 | }, result ); 202 | 203 | /* 204 | huffman :: [(Int, Char)] -> [(Char, String)] 205 | huffman = reduce . map (\(p, c) -> (p, [(c ,"")])) . sortBy (comparing fst) 206 | where 207 | reduce [(_, ys)] = ys 208 | reduce (x1:x2:xs) = reduce $ insertBy (comparing fst) (add x1 x2) xs 209 | add (p1, xs1) (p2, xs2) = (p1 + p2, map (second ('0':)) xs1 ++ map (second ('1':)) xs2) 210 | 211 | test s = mapM_ (\(a,b)->putStrLn ('\'' : a : "\' : " ++ b)) . huffman . freq $ s 212 | */ 213 | 214 | } 215 | 216 | /////////////////////////////////////////////////////////////////////////// 217 | 218 | int main(int argc, char **argv) { 219 | 220 | using namespace fp; 221 | 222 | print( "" ); 223 | 224 | 225 | /////////////////////////////////////////////////////////////////////////// 226 | 227 | run( pascalsTriangle( 6 ), 10000 * ITER_MULT ); 228 | 229 | /////////////////////////////////////////////////////////////////////////// 230 | 231 | #if defined(_MSC_VER) 232 | static const char* unixdict = "./../../../samples/unixdict.txt"; 233 | #else 234 | static const char* unixdict = "./../../samples/unixdict.txt"; 235 | #endif 236 | run( anagrams( unixdict ), 5 * ITER_MULT ); 237 | 238 | /////////////////////////////////////////////////////////////////////////// 239 | 240 | std::array fftValues = {1, 1, 1, 1, 0, 0, 0, 0}; 241 | let fftIn = fp::list( fftValues ); 242 | run( fft( fftIn /*=1,1,1,1,0,0,0,0*/ ), 5000 * ITER_MULT ); 243 | 244 | /////////////////////////////////////////////////////////////////////////// 245 | 246 | run( nthRoot( 5, 34. ), 100000 * ITER_MULT ); 247 | run( nthRoot( 6, 25. ), 100000 * ITER_MULT ); 248 | run( nthRoot( 7, 100. ), 100000 * ITER_MULT ); 249 | 250 | /////////////////////////////////////////////////////////////////////////// 251 | 252 | run( huffman( "this is an example for huffman encoding" ), 50 * ITER_MULT ); 253 | 254 | print( "" ); 255 | 256 | return 0; 257 | } 258 | -------------------------------------------------------------------------------- /samples/benchmark.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #if defined(_MSC_VER) 8 | #pragma warning( disable : 4244 ) 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include "timer.h" 20 | 21 | /////////////////////////////////////////////////////////////////////////// 22 | 23 | static const size_t RAND_VEC_SIZE = 1000; 24 | static const float RAND_VEC_RANGE = 10.0f; 25 | #if defined(_DEBUG) 26 | static const size_t VEC_ITERS = 1000; 27 | #else 28 | static const size_t VEC_ITERS = 100000; 29 | #endif 30 | 31 | /////////////////////////////////////////////////////////////////////////// 32 | 33 | template < class InputIterator1, class InputIterator2, class InputIterator3, class InputIterator4, class OutputIterator, class Op> 34 | OutputIterator transform_4(InputIterator1 first1, InputIterator1 last1, 35 | InputIterator2 first2, 36 | InputIterator3 first3, 37 | InputIterator4 first4, 38 | OutputIterator result, Op op ) { 39 | while (first1 != last1) 40 | *result++ = op(*first1++, *first2++, *first3++, *first4++); 41 | return result; 42 | } 43 | 44 | /////////////////////////////////////////////////////////////////////////// 45 | 46 | float test_func1(float x, float y, float z, float w) { 47 | return (x * y) + (z * w); 48 | } 49 | 50 | float test_func2(float x, float y, float z, float w) { 51 | return (x + y + z) * (2.0f * w); 52 | } 53 | 54 | float test_func3() { 55 | return logf(sqrtf(fp::math::uniform(0.f, RAND_VEC_RANGE) * fp::math::uniform(0.f, RAND_VEC_RANGE))); 56 | } 57 | 58 | float test_func4(float x) { 59 | return ((((((((((((((((x + 2.f) - 3.f) * 4.f) / 5.f) + 2.f) - 3.f) * 4.f) / 5.f) + 2.f) - 3.f) * 4.f) / 5.f) + 2.f) - 3.f) * 4.f) / 5.f); 60 | } 61 | 62 | template 63 | void benchmark(T& data, T& result, F f, const char* desc, size_t iters = VEC_ITERS) { 64 | timed_run timed(desc); 65 | for (size_t i = 0; i < iters; ++i) 66 | transform_4( 67 | std::begin(data), 68 | std::end( data), 69 | std::begin(data), 70 | std::begin(data), 71 | std::begin(data), 72 | std::begin(result), 73 | f); 74 | } 75 | 76 | template 77 | void benchmark2(F f, const char* desc, size_t iters = VEC_ITERS) { 78 | timed_run timed(desc); 79 | for (size_t i = 0; i < iters; ++i) 80 | f(); 81 | } 82 | 83 | template 84 | void benchmark3(T& data, T& result, F f, const char* desc, size_t iters = VEC_ITERS) { 85 | timed_run timed(desc); 86 | for (size_t i = 0; i < iters; ++i) 87 | transform( 88 | std::begin(data), 89 | std::end( data), 90 | std::begin(result), 91 | f); 92 | } 93 | 94 | void test() { 95 | 96 | #if FP_COMPOUND 97 | 98 | using namespace fp; 99 | using namespace fp_operators; 100 | let rand_vec = fp::randN(RAND_VEC_SIZE, (float)0, (float)RAND_VEC_RANGE); 101 | 102 | { 103 | auto add = [](float x, float y) -> float { return x + y; }; 104 | auto mult = [](float x, float y) -> float { return x * y; }; 105 | auto add_mult_mult = compose2(add, mult, mult); 106 | auto test_lambda1 = [](float x, float y, float z, float w) -> float { 107 | return (x * y) + (z * w); 108 | }; 109 | 110 | fp::types::list result(rand_vec.size()); 111 | fp::types::list test_result(rand_vec.size()); 112 | 113 | // warmup 114 | benchmark(rand_vec, result, test_lambda1, "Warmup - "); 115 | 116 | benchmark(rand_vec, result, add_mult_mult, "COMPOSED: (x * y) + (z * w) - "); 117 | benchmark(rand_vec, result, test_lambda1, "LAMBDA: (x * y) + (z * w) - "); 118 | benchmark(rand_vec, test_result, test_func1, "FUNC: (x * y) + (z * w) - "); 119 | 120 | std::cout << "Success = " << std::equal( result.begin(), result.end(), test_result.begin() ) << std::endl; 121 | } 122 | 123 | { 124 | //auto length_squared = [](float x, float y, float z) -> float { return x*x + y*y + z*z; }; 125 | auto added = [](float x, float y, float z) -> float { return x + y + z; }; 126 | auto doubled = [](float x) -> float { return x * 2.0f; }; 127 | auto multiplied = [](float x, float y) -> float { return x * y; }; 128 | auto mult_add_double = compose2(multiplied, added, doubled); 129 | auto test_lambda2 = [](float x, float y, float z, float w) -> float { 130 | return (x + y + z) * (2.0f * w); 131 | }; 132 | 133 | fp::types::list result(rand_vec.size()); 134 | fp::types::list test_result(rand_vec.size()); 135 | 136 | benchmark(rand_vec, result, mult_add_double, "COMPOSED: (x + y + z) * (2.0f * w) - "); 137 | benchmark(rand_vec, result, test_lambda2, "LAMBDA: (x + y + z) * (2.0f * w) - "); 138 | benchmark(rand_vec, test_result, test_func2, "FUNC: (x + y + z) * (2.0f * w) - "); 139 | 140 | std::cout << "Success = " << std::equal( result.begin(), result.end(), test_result.begin() ) << std::endl; 141 | } 142 | 143 | let rand_gen = fp::curry2(randRange, 0.f, RAND_VEC_RANGE); 144 | //let rand_gen2 = fp::curry2(randRangeF(), 0.f, RAND_VEC_RANGE); 145 | 146 | { 147 | // static inline auto bind2(F f, T t, T1 t1) -> std::function< decltype(f(t,t1)) (T,T1) > { 148 | // //FP_RETURNS( std::bind( static_cast< decltype(F) (T,T1) >(f), t, t1) ); 149 | // typedef decltype(f(t,t1)) result_type; 150 | // 151 | // return std::bind( static_cast< decltype(F) (T,T1) >(f), t, t1 ); 152 | //let func = randRangeF(); 153 | //typedef std::function< decltype(func(0.f, RAND_VEC_RANGE)) ) result_type; 154 | // 155 | let rand_gen2 = fp::curry_helper_impl<2>::bind2(randRangeF(), 0.f, RAND_VEC_RANGE); 156 | rand_gen2(); 157 | 158 | } 159 | 160 | { 161 | //auto length_squared = [](float x, float y, float z) -> float { return x*x + y*y + z*z; }; 162 | auto multiplied = [](float x, float y) -> float { return x * y; }; 163 | auto mult_rand_rand = compose2(multiplied, rand_range_(0.f, RAND_VEC_RANGE), rand_range_(0.f, RAND_VEC_RANGE)); 164 | auto log_sqrt = [](float x) -> float { return logf(sqrtf(x)); }; 165 | auto test_lambda3 = [&]() -> float { return logf(sqrtf(rand_gen() * rand_gen())); }; 166 | auto sqrt_mult_rand_rand = log_sqrt + mult_rand_rand; 167 | auto sqrt_mult_rand_rand2 = [](float x) { return logf(x); } 168 | + [](float x) { return sqrtf(x); } 169 | + [](float x) { return x*x; } 170 | + [&]() { return rand_gen() * rand_gen(); }; 171 | 172 | fp::types::list result(rand_vec.size()); 173 | fp::types::list test_result(rand_vec.size()); 174 | 175 | benchmark2(sqrt_mult_rand_rand, "COMPOSED: log(sqrt(rand()*rand())) - ", VEC_ITERS * 25); 176 | benchmark2(sqrt_mult_rand_rand2, "COMPOSED2: log(sqrt(rand()*rand())) - ", VEC_ITERS * 25); 177 | benchmark2(test_lambda3, "LAMBDA: log(sqrt(rand()*rand())) - ", VEC_ITERS * 25); 178 | benchmark2(test_func3, "FUNC: log(Sqrt(rand()*rand())) - ", VEC_ITERS * 25); 179 | 180 | std::cout << "Success = " << std::equal( result.begin(), result.end(), test_result.begin() ) << std::endl; 181 | } 182 | 183 | { 184 | auto add_2 = [](float x) -> float { return x + 2.f; }; 185 | auto sub_2 = [](float x) -> float { return x - 3.f; }; 186 | auto mult_2 = [](float x) -> float { return x * 4.f; }; 187 | auto div_2 = [](float x) -> float { return x / 5.f; }; 188 | auto chain = div_2 + mult_2 + sub_2 + add_2; 189 | auto chain4 = chain + chain + chain + chain; 190 | auto test_lambda4 = [](float x) -> float { 191 | return ((((((((((((((((x + 2.f) - 3.f) * 4.f) / 5.f) + 2.f) - 3.f) * 4.f) / 5.f) + 2.f) - 3.f) * 4.f) / 5.f) + 2.f) - 3.f) * 4.f) / 5.f); 192 | }; 193 | 194 | fp::types::list result(rand_vec.size()); 195 | fp::types::list test_result(rand_vec.size()); 196 | 197 | benchmark3(rand_vec, result, chain4, "COMPOSED: (f(f(f(f(x)))) with f(x) = ((((x+2)-2)*2)/2) - "); 198 | benchmark3(rand_vec, result, test_lambda4, "LAMBDA: (f(f(f(f(x)))) with f(x) = ((((x+2)-2)*2)/2) - "); 199 | benchmark3(rand_vec, test_result, test_func4, "FUNC: (f(f(f(f(x)))) with f(x) = ((((x+2)-2)*2)/2) - "); 200 | 201 | std::cout << "Success = " << std::equal( result.begin(), result.end(), test_result.begin() ) << std::endl; 202 | } 203 | 204 | #endif /* FP_COMPOUND */ 205 | 206 | } 207 | 208 | int main(int argc, char** argv) { 209 | 210 | test(); 211 | 212 | return 0; 213 | } 214 | -------------------------------------------------------------------------------- /tests/fp_test.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "common.h" 17 | 18 | template T add(T t0, T t1) { return t0 + t1; } 19 | template T sub(T t0, T t1) { return t0 - t1; } 20 | template T mult(T t0, T t1) { return t0 * t1; } 21 | template T div(T t0, T t1) { return t0 / t1; } 22 | 23 | /////////////////////////////////////////////////////////////////////////// 24 | 25 | static const fp::types::list fVec10_1(10, 1.f); 26 | static const fp::types::list dVec10_2(10, 2.f); 27 | let dVec5_1_5 = fp::increasingN(5, 1.); 28 | let iVec5_0_5 = fp::increasingN(6, 0); 29 | let iVec5_5_0 = fp::decreasingN(6, 5); 30 | 31 | template 32 | bool filteredMap(MapOp mapOp, FilterOp filterOp, Source source, std::function successOp = &fp::istrue) { 33 | using namespace fp; 34 | return all(successOp, 35 | map(mapOp, 36 | filter(filterOp, 37 | source))); 38 | } 39 | 40 | double pi(size_t samples = 10000) { 41 | using namespace fp; 42 | using namespace fp::math; 43 | typedef std::pair point; 44 | return 4.* length(filter([](double d) { return d <= 1.0; }, 45 | map([](const point& p) { return p.first*p.first + p.second*p.second; }, 46 | zip(uniformN(samples, -1.0, 1.0), 47 | uniformN(samples, -1.0, 1.0))))) / samples; 48 | } 49 | 50 | double pi_(size_t samples = 10000) { 51 | using namespace fp; 52 | 53 | let sample = []() -> int { 54 | let x = math::uniform(-1.,1.); 55 | let y = math::uniform(-1.,1.); 56 | let dist2 = x*x + y*y; 57 | return dist2 < 1. ? 1 : 0; 58 | }; 59 | 60 | return 4. * foldl1(std::plus(), takeF(samples, sample)) / samples; 61 | } 62 | 63 | TEST(Prelude, Fun) { 64 | using namespace fp; 65 | using std::string; 66 | using std::ifstream; 67 | using std::cout; 68 | using std::string; 69 | 70 | if (false) { 71 | let mp3Filter = [](const string& mp3) { 72 | return (!mp3.empty()) && 73 | ( mp3[0] != '#') && 74 | ( mp3.find_first_of(".mp3") != std::string::npos ); 75 | }; 76 | let mp3Delete = [=](const string& mp3) { 77 | return remove(mp3.c_str()) == 0; 78 | }; 79 | 80 | ifstream ifs("playlist.m3u"); 81 | let successful = filteredMap(mp3Delete, mp3Filter, lines(ifs)); 82 | 83 | cout << "Deleting Playlist..." << (successful ? "Success!" : "Failure!!"); 84 | } 85 | 86 | /////////////////////////////////////////////////////////////////////////// 87 | 88 | EXPECT_NEAR(3.14, pi(), .1); 89 | EXPECT_NEAR(3.14, pi_(), .1); 90 | } 91 | 92 | ///////////////////////////////////////////////////////////////////////////// 93 | 94 | TEST(Prelude, Map) { 95 | using fp::fold; 96 | using fp::map; 97 | using fp::sum; 98 | 99 | EXPECT_EQ(sum( map(add_2, fVec10_1)), 30.0f); 100 | EXPECT_EQ(sum( map(sub_3, dVec10_2)), -10.0 ); 101 | EXPECT_EQ(sum( map(mult_4, iVec5_5_0)), 0*4.f + 1*4.f + 2*4.f + 3*4.f + 4*4.f + 5*4.f); 102 | EXPECT_EQ(sum( map(div_5, iVec5_0_5)), 0/5.f + 1/5.f + 2/5.f + 3/5.f + 4/5.f + 5/5.f); 103 | 104 | /////////////////////////////////////////////////////////////////////////// 105 | 106 | EXPECT_EQ(map(toupper, "abc"), "ABC"); 107 | } 108 | 109 | TEST(Prelude, FoldL) { 110 | using fp::fold; 111 | using fp::foldl; 112 | using fp::foldl1; 113 | using fp::sum; 114 | using fp::product; 115 | 116 | EXPECT_EQ(sum(fVec10_1), 10.f); 117 | EXPECT_EQ(sum(dVec10_2), 20. ); 118 | EXPECT_EQ(sum(iVec5_0_5), 0+1+2+3+4+5); 119 | EXPECT_EQ(sum(iVec5_5_0), 5+4+3+2+1+0); 120 | 121 | EXPECT_EQ(product(dVec10_2), pow(2.,10) ); 122 | EXPECT_EQ(foldl1(std::divides(),dVec10_2), pow(.5,8) ); 123 | 124 | EXPECT_EQ(sum(fp::words(std::string("a b c d e f g h i j"))), "abcdefghij"); 125 | } 126 | 127 | TEST(Prelude, FoldR) { 128 | using fp::foldr; 129 | using fp::foldr_; 130 | using fp::foldr1; 131 | using fp::foldr1_; 132 | 133 | let addf = &add; 134 | let subi = &sub; 135 | 136 | EXPECT_EQ(foldr1(addf, fVec10_1), 10.f); 137 | EXPECT_EQ(foldr1(subi, iVec5_0_5), 5-4-3-2-1-0); 138 | EXPECT_EQ(foldr1(subi, iVec5_5_0), 0-1-2-3-4-5); 139 | 140 | let add_s = [](const std::string& s0, const std::string& s1) { return s0 + s1; }; 141 | let add_s2 = &add; 142 | EXPECT_EQ(foldr1(add_s, fp::words(std::string("a b c d e f g h i j"))), std::string("jihgfedcba")); 143 | EXPECT_EQ(foldr1(add_s2, fp::words(std::string("a b c"))), fp::sum(fp::reverse(fp::words(std::string("a b c"))))); 144 | } 145 | 146 | TEST(Prelude, ScanL) { 147 | using fp::fold; 148 | using fp::foldl; 149 | using fp::foldl1; 150 | using fp::scanl; 151 | using fp::scanl1; 152 | using fp::sum; 153 | using fp::product; 154 | 155 | EXPECT_EQ( foldl1(std::divides(), dVec10_2), 156 | fp::last( scanl1(std::divides(), dVec10_2))); 157 | } 158 | 159 | TEST(Prelude, ScanR) { 160 | using fp::foldr; 161 | using fp::foldr_; 162 | using fp::foldr1; 163 | using fp::foldr1_; 164 | using fp::scanr; 165 | using fp::scanr1; 166 | 167 | let addf = &add; 168 | let subi = &sub; 169 | 170 | EXPECT_EQ(foldr1(addf, fVec10_1), fp::last( scanr1(addf, fVec10_1))); 171 | EXPECT_EQ(foldr1(subi, iVec5_0_5), fp::last( scanr1(subi, iVec5_0_5))); 172 | EXPECT_EQ(foldr1(subi, iVec5_5_0), fp::last( scanr1(subi, iVec5_5_0))); 173 | } 174 | 175 | TEST(Prelude, Filter) { 176 | using fp::filter; 177 | 178 | let lessThanEq2 = fp::sum(filter([](int x) { return x <= 2; }, iVec5_0_5)); 179 | EXPECT_EQ(lessThanEq2, 0+1+2); 180 | let greaterThan2 = fp::sum(filter([](int x) { return x > 2; }, iVec5_0_5)); 181 | EXPECT_EQ(greaterThan2, 3+4+5); 182 | 183 | std::string str("a b c d e f g"); 184 | let strFilter = [](const std::string& s) -> bool { return s[0] < 'd'; }; 185 | EXPECT_EQ(fp::sum(filter(strFilter, fp::words(str))), std::string("abc")); 186 | } 187 | 188 | TEST(Prelude, Zip) { 189 | using fp::zip; 190 | 191 | let ifZip = zip(iVec5_0_5, iVec5_5_0); 192 | let pairSum = [](const std::pair& a) -> int { return a.first + a.second; }; 193 | let pairIs5 = [&](const std::pair& a) -> int { return pairSum(a) == 5 ? 1 : 0; }; 194 | let emptyVec = fp::list(); 195 | EXPECT_EQ(fp::sum(fp::__map__(pairIs5, ifZip, emptyVec)), 6); 196 | 197 | } 198 | 199 | TEST(Prelude, ZipWith) { 200 | using fp::zipWith; 201 | 202 | std::array expectedSum = {4,4,4}; 203 | EXPECT_EQ(fp::list(expectedSum), zipWith(std::plus(), fp::increasingN(3, 1), fp::decreasingN(3, 3))); 204 | 205 | std::array expectedPow = {5.0f,25.0f,125.0f,625.0f,3125.0f}; 206 | EXPECT_EQ(fp::list(expectedPow), zipWith(powf, fp::types::list(5, 5.f), fp::increasingN(5, 1.f))); 207 | 208 | std::array expectedLambda = {7, 10, 13, 16}; 209 | let lambda = [](int x, int y) -> int { return 2*x+y; }; 210 | EXPECT_EQ(fp::list(expectedLambda), zipWith(lambda, fp::increasingN(4, 1), fp::increasingN(4, 5))); 211 | } 212 | 213 | 214 | TEST(Prelude, All) { 215 | using fp::all; 216 | 217 | EXPECT_TRUE( all([](float x) { return x == 1.f; }, fVec10_1)); 218 | EXPECT_FALSE(all([](float x) { return x != 1.f; }, fVec10_1)); 219 | 220 | EXPECT_TRUE( all([](double x) { return x == 2.; }, dVec10_2)); 221 | EXPECT_FALSE(all([](double x) { return x != 2.; }, dVec10_2)); 222 | 223 | EXPECT_TRUE( all([](double x) { return x < 10; }, fp::increasingN(10, 0.))); 224 | } 225 | 226 | TEST(Prelude, MinMax) { 227 | using fp::maximum; 228 | using fp::minimum; 229 | 230 | let zeroToThousand = fp::increasingN(1001, 0); 231 | EXPECT_EQ(1000, maximum(zeroToThousand)); 232 | EXPECT_EQ(0, minimum(zeroToThousand)); 233 | zeroToThousand.pop_back(); 234 | zeroToThousand[0] = 999; 235 | EXPECT_EQ(999, maximum(zeroToThousand)); 236 | EXPECT_EQ(1, minimum(zeroToThousand)); 237 | 238 | /////////////////////////////////////////////////////////////////////////// 239 | 240 | let randFloat = fp::math::uniform_(0.f, 1.f); 241 | fp::types::list randFloats; 242 | randFloats.push_back(randFloat()); 243 | float randMax = randFloats.back(); 244 | while (randFloats.size() < 1000) { 245 | randFloats.push_back(randFloat()); 246 | float newRandMax = maximum(randFloats); 247 | EXPECT_LE(randMax, newRandMax); 248 | newRandMax = randMax; 249 | } 250 | 251 | /////////////////////////////////////////////////////////////////////////// 252 | 253 | std::array testArray = {0, 1, 2, 3, 4}; 254 | EXPECT_EQ(4, maximum(testArray)); 255 | EXPECT_EQ(0, minimum(testArray)); 256 | 257 | /////////////////////////////////////////////////////////////////////////// 258 | 259 | EXPECT_EQ('o', maximum(std::string("Hello"))); 260 | EXPECT_EQ('H', minimum(std::string("Hello"))); 261 | } 262 | 263 | TEST(Prelude, Reverse) { 264 | using fp::reverse; 265 | 266 | EXPECT_EQ("dcba", reverse(std::string("abcd"))); 267 | 268 | EXPECT_EQ(fp::increasingN(5, 0), reverse(fp::decreasingN(5, 4))); 269 | } 270 | 271 | TEST(Prelude, Random) { 272 | using fp::uniformN; 273 | using fp::math::uniform; 274 | using fp::math::uniform_; 275 | 276 | enum { 277 | numRands = 10000, 278 | numRandBins = 10, 279 | minRandsPerBin = (int)((numRands / numRandBins) * .9), 280 | maxRandsPerBin = (int)((numRands / numRandBins) * 1.1) 281 | }; 282 | 283 | static const float minRand = 0.f; 284 | static const float maxRand = (float)numRandBins; 285 | 286 | let randFloats = fp::uniformN(numRands, minRand, maxRand); 287 | EXPECT_GE(maxRand, fp::maximum(randFloats)); 288 | EXPECT_LE(minRand, fp::maximum(randFloats)); 289 | EXPECT_LE(5.f, fp::maximum(randFloats)); 290 | EXPECT_GE(5.f, fp::minimum(randFloats)); 291 | 292 | std::array buckets = {0,0,0,0,0,0,0,0,0,0}; 293 | std::for_each(extent(randFloats), [&buckets](float x) { 294 | ++buckets[(size_t)std::floor(x)]; 295 | }); 296 | 297 | std::for_each(extent(buckets), [=](int x) { 298 | EXPECT_GE(maxRandsPerBin, x); 299 | EXPECT_LE(minRandsPerBin, x); 300 | }); 301 | } 302 | 303 | TEST(Prelude, EnumFrom) { 304 | using fp::enumFrom; 305 | 306 | let Zero_Ten = fp::takeWhileT([](int x) -> bool { return x < 11; }, enumFrom(0)); 307 | let Zero_Ten2 = fp::takeF(11, enumFrom(0)); 308 | EXPECT_EQ(fp::sum(Zero_Ten), 55); 309 | EXPECT_EQ(fp::sum(Zero_Ten2), 55); 310 | 311 | /////////////////////////////////////////////////////////////////////////// 312 | 313 | let a_z = fp::takeWhileT([](char x) -> bool { return x <= 'z'; }, enumFrom('a')); 314 | let a_z2 = fp::takeF(26, enumFrom('a')); 315 | const std::string atoz("abcdefghijklmnopqrstuvwxyz"); 316 | EXPECT_EQ(fp::show(a_z), atoz); 317 | EXPECT_EQ(fp::show(a_z2), atoz); 318 | 319 | /////////////////////////////////////////////////////////////////////////// 320 | 321 | let charEnumFrom0 = enumFrom('0'); 322 | EXPECT_EQ(charEnumFrom0(), '0'); 323 | EXPECT_EQ(charEnumFrom0(), '1'); 324 | 325 | enum TestEnum { 326 | First=0, 327 | Last=1, 328 | }; 329 | 330 | let enumEnumFrom = enumFrom(First); 331 | EXPECT_EQ(enumEnumFrom(), First); 332 | EXPECT_EQ(enumEnumFrom(), Last); 333 | 334 | let floatEnumFromNeg10 = enumFrom(-10.f); 335 | EXPECT_EQ(floatEnumFromNeg10(), -10.f); 336 | EXPECT_EQ(floatEnumFromNeg10(), -9.f); 337 | 338 | let ptrEnumFromNull = enumFrom(NULL); 339 | EXPECT_EQ(ptrEnumFromNull(), 0); 340 | EXPECT_EQ(ptrEnumFromNull(), 1); 341 | } 342 | 343 | TEST(Prelude, Elem) { 344 | using fp::elem; 345 | using fp::notElem; 346 | 347 | //bool hasFind = fp::has_find,int>::value; 348 | 349 | EXPECT_TRUE( elem(5, iVec5_0_5)); 350 | EXPECT_FALSE(notElem(5, iVec5_0_5)); 351 | EXPECT_FALSE(elem(-1, iVec5_0_5)); 352 | EXPECT_TRUE( notElem(-1, iVec5_0_5)); 353 | EXPECT_FALSE(elem(0, fp::increasingN(10, 1))); 354 | EXPECT_TRUE( notElem(0, fp::increasingN(10, 1))); 355 | EXPECT_FALSE(elem(-1, iVec5_0_5)); 356 | EXPECT_TRUE( notElem(-1, iVec5_0_5)); 357 | EXPECT_TRUE( elem('o', "Hello")); 358 | EXPECT_FALSE(notElem('o', "Hello")); 359 | EXPECT_FALSE(elem(-1, iVec5_0_5)); 360 | EXPECT_TRUE( notElem(-1, iVec5_0_5)); 361 | EXPECT_FALSE(elem(10, "Hello")); 362 | EXPECT_TRUE( notElem(10, "Hello")); 363 | 364 | let pairs = fp::zip(fp::increasingN(10, 0), fp::decreasingN(10, 9)); 365 | typedef decltype(pairs) PairVec; 366 | typedef PairVec::value_type Pair; 367 | pairs.push_back( Pair(33,33) ); 368 | 369 | EXPECT_TRUE( elem(Pair(0,9), pairs)); 370 | EXPECT_TRUE( elem(Pair(33,33), pairs)); 371 | EXPECT_FALSE(elem(Pair(44,44), pairs)); 372 | } 373 | 374 | TEST(Prelude, Drop) { 375 | using fp::drop; 376 | using fp::dropWhile; 377 | 378 | EXPECT_EQ(0, fp::sum(drop(10, fp::increasingN(10, 0)))); 379 | EXPECT_EQ(9, fp::sum(drop(9, fp::increasingN(10, 0)))); 380 | EXPECT_EQ(9+8, fp::sum(drop(8, fp::increasingN(10, 0)))); 381 | EXPECT_EQ(fp::increasingN(5,0), drop(0, fp::increasingN(5, 0))); 382 | 383 | EXPECT_EQ(0, fp::sum(dropWhile([](int x) { return x < 10; }, fp::increasingN(10, 0)))); 384 | EXPECT_EQ(9, fp::sum(dropWhile([](int x) { return x < 9; }, fp::increasingN(10, 0)))); 385 | EXPECT_EQ(9+8, fp::sum(dropWhile([](int x) { return x < 8; }, fp::increasingN(10, 0)))); 386 | EXPECT_EQ(fp::decreasingN(5, 4), dropWhile([](int x) { return x > 4; }, fp::decreasingN(10, 9))); 387 | 388 | } 389 | 390 | TEST(Prelude, Take) { 391 | using fp::take; 392 | using fp::takeF; 393 | using fp::takeWhile; 394 | using fp::takeWhileF; 395 | 396 | EXPECT_EQ(0, fp::sum(take(0, fp::increasingN(10, 0)))); 397 | EXPECT_EQ(0, fp::sum(take(1, fp::increasingN(10, 0)))); 398 | EXPECT_EQ(1, fp::sum(take(2, fp::increasingN(10, 0)))); 399 | EXPECT_EQ(1+2, fp::sum(take(3, fp::increasingN(10, 0)))); 400 | EXPECT_EQ(fp::increasingN(5,0), take(5, fp::increasingN(10, 0))); 401 | 402 | EXPECT_EQ(0, fp::sum(takeWhile([](int x) { return x < 0; }, fp::increasingN(10, 0)))); 403 | EXPECT_EQ(0, fp::sum(takeWhile([](int x) { return x < 1; }, fp::increasingN(10, 0)))); 404 | EXPECT_EQ(0+1, fp::sum(takeWhile([](int x) { return x < 2; }, fp::increasingN(10, 0)))); 405 | EXPECT_EQ(fp::decreasingN(5, 9), takeWhile([](int x) { return x > 4; }, fp::decreasingN(10, 9))); 406 | } 407 | 408 | 409 | /////////////////////////////////////////////////////////////////////////// 410 | 411 | TEST(General, Comparing) { 412 | using fp::comparing; 413 | 414 | const std::array strings = {"one", "two", "three", "four", "five"}; 415 | std::vector stringVec(extent(strings)); 416 | //let stringVec = fp::list(strings);n 417 | //EXPECT_EQ("three", fp::maximumBy(fp::comparing(fp::length), stringVec)); 418 | 419 | let zippedList = fp::zip(fp::increasingN(10, 0), fp::decreasingN(10, 9)); 420 | let sortedList = fp::sortBy(fp::comparing(&fp::snd), zippedList); 421 | EXPECT_EQ(zippedList.back(), sortedList.front()); 422 | } 423 | 424 | TEST(General, Flip) { 425 | using fp::flip; 426 | EXPECT_EQ(std::divides()(3.f,4.f), flip(std::divides())(4.f,3.f)); 427 | EXPECT_EQ(std::plus()("3", "4"), flip(std::plus())("4", "3")); 428 | } 429 | 430 | /////////////////////////////////////////////////////////////////////////// 431 | 432 | template 433 | T multBy2(T x) { 434 | return x * (T)2; 435 | } 436 | 437 | template 438 | T exor(T x, T y) { 439 | return x ^ y; 440 | } 441 | 442 | template 443 | T mult3(T x, T y, T z) { 444 | return x*y*z; 445 | } 446 | 447 | TEST(Curry, Everything) { 448 | using fp::curry; 449 | using fp::curry2; 450 | using fp::curry3; 451 | using fp::curryAll2; 452 | 453 | // No args 454 | EXPECT_EQ(2.f, curry(&multBy2, 1.f)()); 455 | EXPECT_EQ(2.f, curry2(std::plus(), 1.f, 1.f)()); 456 | EXPECT_EQ(2.f, curry2(std::multiplies(), 1.f, 2.f)()); 457 | EXPECT_EQ(99^77, curry2(&exor, 99, 77)()); 458 | EXPECT_EQ(2.f, curry3(mult3, 8.f, .5f, .5f)()); 459 | 460 | EXPECT_EQ(2.f, curryAll2(fp::math::addF(), 1.f, 1.f)()); 461 | EXPECT_EQ(2.f, curryAll2(fp::math::multiplyF(), 1.f, 2.f)()); 462 | 463 | // 1 arg 464 | EXPECT_EQ(2.f, curry(std::plus(), 1.f)(1.f)); 465 | EXPECT_EQ(2.f, curry(std::multiplies(), 1.f)(2.f)); 466 | EXPECT_EQ(99^77, curry(&exor, 99)(77)); 467 | EXPECT_EQ(2.f, curry2(&mult3, 8.f, .5f)(.5f)); 468 | 469 | // 2 args 470 | EXPECT_EQ(2.f, curry(&mult3, 8.f)(.5f, .5f)); 471 | 472 | EXPECT_EQ((float)1*2*3*4*5, curry(fp::foldl1,fp::types::list >, std::multiplies())(fp::increasingN(5, 1.f))); 473 | #ifndef _MSC_VER 474 | EXPECT_EQ((float)1*2*3*4*5, std::bind(fp::foldl1F(), fp::math::multiplyF(), std::placeholders::_1)(fp::increasingN(5, 1.f))); 475 | #endif 476 | } 477 | -------------------------------------------------------------------------------- /externals/rapidxml/rapidxml_print.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RAPIDXML_PRINT_HPP_INCLUDED 2 | #define RAPIDXML_PRINT_HPP_INCLUDED 3 | 4 | // Copyright (C) 2006, 2009 Marcin Kalicinski 5 | // Version 1.13 6 | // Revision $DateTime: 2009/05/13 01:46:17 $ 7 | //! \file rapidxml_print.hpp This file contains rapidxml printer implementation 8 | 9 | #include "rapidxml.hpp" 10 | 11 | // Only include streams if not disabled 12 | #ifndef RAPIDXML_NO_STREAMS 13 | #include 14 | #include 15 | #endif 16 | 17 | namespace rapidxml 18 | { 19 | 20 | /////////////////////////////////////////////////////////////////////// 21 | // Printing flags 22 | 23 | const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. 24 | 25 | /////////////////////////////////////////////////////////////////////// 26 | // Internal 27 | 28 | //! \cond internal 29 | namespace internal 30 | { 31 | 32 | /////////////////////////////////////////////////////////////////////////// 33 | // Internal character operations 34 | 35 | // Copy characters from given range to given output iterator 36 | template 37 | inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) 38 | { 39 | while (begin != end) 40 | *out++ = *begin++; 41 | return out; 42 | } 43 | 44 | // Copy characters from given range to given output iterator and expand 45 | // characters into references (< > ' " &) 46 | template 47 | inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) 48 | { 49 | while (begin != end) 50 | { 51 | if (*begin == noexpand) 52 | { 53 | *out++ = *begin; // No expansion, copy character 54 | } 55 | else 56 | { 57 | switch (*begin) 58 | { 59 | case Ch('<'): 60 | *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); 61 | break; 62 | case Ch('>'): 63 | *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); 64 | break; 65 | case Ch('\''): 66 | *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); 67 | break; 68 | case Ch('"'): 69 | *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); 70 | break; 71 | case Ch('&'): 72 | *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); 73 | break; 74 | default: 75 | *out++ = *begin; // No expansion, copy character 76 | } 77 | } 78 | ++begin; // Step to next character 79 | } 80 | return out; 81 | } 82 | 83 | // Fill given output iterator with repetitions of the same character 84 | template 85 | inline OutIt fill_chars(OutIt out, int n, Ch ch) 86 | { 87 | for (int i = 0; i < n; ++i) 88 | *out++ = ch; 89 | return out; 90 | } 91 | 92 | // Find character 93 | template 94 | inline bool find_char(const Ch *begin, const Ch *end) 95 | { 96 | while (begin != end) 97 | if (*begin++ == ch) 98 | return true; 99 | return false; 100 | } 101 | 102 | /////////////////////////////////////////////////////////////////////////// 103 | // Internal printing operations 104 | 105 | // Print node 106 | template 107 | inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) 108 | { 109 | // Print proper node type 110 | switch (node->type()) 111 | { 112 | 113 | // Document 114 | case node_document: 115 | out = print_children(out, node, flags, indent); 116 | break; 117 | 118 | // Element 119 | case node_element: 120 | out = print_element_node(out, node, flags, indent); 121 | break; 122 | 123 | // Data 124 | case node_data: 125 | out = print_data_node(out, node, flags, indent); 126 | break; 127 | 128 | // CDATA 129 | case node_cdata: 130 | out = print_cdata_node(out, node, flags, indent); 131 | break; 132 | 133 | // Declaration 134 | case node_declaration: 135 | out = print_declaration_node(out, node, flags, indent); 136 | break; 137 | 138 | // Comment 139 | case node_comment: 140 | out = print_comment_node(out, node, flags, indent); 141 | break; 142 | 143 | // Doctype 144 | case node_doctype: 145 | out = print_doctype_node(out, node, flags, indent); 146 | break; 147 | 148 | // Pi 149 | case node_pi: 150 | out = print_pi_node(out, node, flags, indent); 151 | break; 152 | 153 | // Unknown 154 | default: 155 | assert(0); 156 | break; 157 | } 158 | 159 | // If indenting not disabled, add line break after node 160 | if (!(flags & print_no_indenting)) 161 | *out = Ch('\n'), ++out; 162 | 163 | // Return modified iterator 164 | return out; 165 | } 166 | 167 | // Print children of the node 168 | template 169 | inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) 170 | { 171 | for (xml_node *child = node->first_node(); child; child = child->next_sibling()) 172 | out = print_node(out, child, flags, indent); 173 | return out; 174 | } 175 | 176 | // Print attributes of the node 177 | template 178 | inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) 179 | { 180 | for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) 181 | { 182 | if (attribute->name() && attribute->value()) 183 | { 184 | // Print attribute name 185 | *out = Ch(' '), ++out; 186 | out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); 187 | *out = Ch('='), ++out; 188 | // Print attribute value using appropriate quote type 189 | if (find_char(attribute->value(), attribute->value() + attribute->value_size())) 190 | { 191 | *out = Ch('\''), ++out; 192 | out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); 193 | *out = Ch('\''), ++out; 194 | } 195 | else 196 | { 197 | *out = Ch('"'), ++out; 198 | out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); 199 | *out = Ch('"'), ++out; 200 | } 201 | } 202 | } 203 | return out; 204 | } 205 | 206 | // Print data node 207 | template 208 | inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent) 209 | { 210 | assert(node->type() == node_data); 211 | if (!(flags & print_no_indenting)) 212 | out = fill_chars(out, indent, Ch('\t')); 213 | out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); 214 | return out; 215 | } 216 | 217 | // Print data node 218 | template 219 | inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent) 220 | { 221 | assert(node->type() == node_cdata); 222 | if (!(flags & print_no_indenting)) 223 | out = fill_chars(out, indent, Ch('\t')); 224 | *out = Ch('<'); ++out; 225 | *out = Ch('!'); ++out; 226 | *out = Ch('['); ++out; 227 | *out = Ch('C'); ++out; 228 | *out = Ch('D'); ++out; 229 | *out = Ch('A'); ++out; 230 | *out = Ch('T'); ++out; 231 | *out = Ch('A'); ++out; 232 | *out = Ch('['); ++out; 233 | out = copy_chars(node->value(), node->value() + node->value_size(), out); 234 | *out = Ch(']'); ++out; 235 | *out = Ch(']'); ++out; 236 | *out = Ch('>'); ++out; 237 | return out; 238 | } 239 | 240 | // Print element node 241 | template 242 | inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent) 243 | { 244 | assert(node->type() == node_element); 245 | 246 | // Print element name and attributes, if any 247 | if (!(flags & print_no_indenting)) 248 | out = fill_chars(out, indent, Ch('\t')); 249 | *out = Ch('<'), ++out; 250 | out = copy_chars(node->name(), node->name() + node->name_size(), out); 251 | out = print_attributes(out, node, flags); 252 | 253 | // If node is childless 254 | if (node->value_size() == 0 && !node->first_node()) 255 | { 256 | // Print childless node tag ending 257 | *out = Ch('/'), ++out; 258 | *out = Ch('>'), ++out; 259 | } 260 | else 261 | { 262 | // Print normal node tag ending 263 | *out = Ch('>'), ++out; 264 | 265 | // Test if node contains a single data node only (and no other nodes) 266 | xml_node *child = node->first_node(); 267 | if (!child) 268 | { 269 | // If node has no children, only print its value without indenting 270 | out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); 271 | } 272 | else if (child->next_sibling() == 0 && child->type() == node_data) 273 | { 274 | // If node has a sole data child, only print its value without indenting 275 | out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); 276 | } 277 | else 278 | { 279 | // Print all children with full indenting 280 | if (!(flags & print_no_indenting)) 281 | *out = Ch('\n'), ++out; 282 | out = print_children(out, node, flags, indent + 1); 283 | if (!(flags & print_no_indenting)) 284 | out = fill_chars(out, indent, Ch('\t')); 285 | } 286 | 287 | // Print node end 288 | *out = Ch('<'), ++out; 289 | *out = Ch('/'), ++out; 290 | out = copy_chars(node->name(), node->name() + node->name_size(), out); 291 | *out = Ch('>'), ++out; 292 | } 293 | return out; 294 | } 295 | 296 | // Print declaration node 297 | template 298 | inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent) 299 | { 300 | // Print declaration start 301 | if (!(flags & print_no_indenting)) 302 | out = fill_chars(out, indent, Ch('\t')); 303 | *out = Ch('<'), ++out; 304 | *out = Ch('?'), ++out; 305 | *out = Ch('x'), ++out; 306 | *out = Ch('m'), ++out; 307 | *out = Ch('l'), ++out; 308 | 309 | // Print attributes 310 | out = print_attributes(out, node, flags); 311 | 312 | // Print declaration end 313 | *out = Ch('?'), ++out; 314 | *out = Ch('>'), ++out; 315 | 316 | return out; 317 | } 318 | 319 | // Print comment node 320 | template 321 | inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent) 322 | { 323 | assert(node->type() == node_comment); 324 | if (!(flags & print_no_indenting)) 325 | out = fill_chars(out, indent, Ch('\t')); 326 | *out = Ch('<'), ++out; 327 | *out = Ch('!'), ++out; 328 | *out = Ch('-'), ++out; 329 | *out = Ch('-'), ++out; 330 | out = copy_chars(node->value(), node->value() + node->value_size(), out); 331 | *out = Ch('-'), ++out; 332 | *out = Ch('-'), ++out; 333 | *out = Ch('>'), ++out; 334 | return out; 335 | } 336 | 337 | // Print doctype node 338 | template 339 | inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent) 340 | { 341 | assert(node->type() == node_doctype); 342 | if (!(flags & print_no_indenting)) 343 | out = fill_chars(out, indent, Ch('\t')); 344 | *out = Ch('<'), ++out; 345 | *out = Ch('!'), ++out; 346 | *out = Ch('D'), ++out; 347 | *out = Ch('O'), ++out; 348 | *out = Ch('C'), ++out; 349 | *out = Ch('T'), ++out; 350 | *out = Ch('Y'), ++out; 351 | *out = Ch('P'), ++out; 352 | *out = Ch('E'), ++out; 353 | *out = Ch(' '), ++out; 354 | out = copy_chars(node->value(), node->value() + node->value_size(), out); 355 | *out = Ch('>'), ++out; 356 | return out; 357 | } 358 | 359 | // Print pi node 360 | template 361 | inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent) 362 | { 363 | assert(node->type() == node_pi); 364 | if (!(flags & print_no_indenting)) 365 | out = fill_chars(out, indent, Ch('\t')); 366 | *out = Ch('<'), ++out; 367 | *out = Ch('?'), ++out; 368 | out = copy_chars(node->name(), node->name() + node->name_size(), out); 369 | *out = Ch(' '), ++out; 370 | out = copy_chars(node->value(), node->value() + node->value_size(), out); 371 | *out = Ch('?'), ++out; 372 | *out = Ch('>'), ++out; 373 | return out; 374 | } 375 | 376 | } 377 | //! \endcond 378 | 379 | /////////////////////////////////////////////////////////////////////////// 380 | // Printing 381 | 382 | //! Prints XML to given output iterator. 383 | //! \param out Output iterator to print to. 384 | //! \param node Node to be printed. Pass xml_document to print entire document. 385 | //! \param flags Flags controlling how XML is printed. 386 | //! \return Output iterator pointing to position immediately after last character of printed text. 387 | template 388 | inline OutIt print(OutIt out, const xml_node &node, int flags = 0) 389 | { 390 | return internal::print_node(out, &node, flags, 0); 391 | } 392 | 393 | #ifndef RAPIDXML_NO_STREAMS 394 | 395 | //! Prints XML to given output stream. 396 | //! \param out Output stream to print to. 397 | //! \param node Node to be printed. Pass xml_document to print entire document. 398 | //! \param flags Flags controlling how XML is printed. 399 | //! \return Output stream. 400 | template 401 | inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) 402 | { 403 | print(std::ostream_iterator(out), node, flags); 404 | return out; 405 | } 406 | 407 | //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. 408 | //! \param out Output stream to print to. 409 | //! \param node Node to be printed. 410 | //! \return Output stream. 411 | template 412 | inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) 413 | { 414 | return print(out, node); 415 | } 416 | 417 | #endif 418 | 419 | } 420 | 421 | #endif 422 | -------------------------------------------------------------------------------- /include/fp_prelude_lists.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2012, Jared Duke. 3 | // This code is released under the MIT License. 4 | // www.opensource.org/licenses/mit-license.php 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef _FP_PRELUDE_LISTS_H_ 8 | #define _FP_PRELUDE_LISTS_H_ 9 | 10 | #include "fp_defines.h" 11 | #include "fp_curry.h" 12 | #include "fp_prelude_math.h" 13 | #include "fp_prelude.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace fp { 24 | 25 | /////////////////////////////////////////////////////////////////////////// 26 | // List operations 27 | /////////////////////////////////////////////////////////////////////////// 28 | 29 | /////////////////////////////////////////////////////////////////////////// 30 | // map 31 | 32 | template 33 | inline R& __map__(F f, const C& c, R& r) { 34 | std::transform(extent(c), back(r), f); 35 | return r; 36 | } 37 | 38 | // This code is abominable... 39 | template 40 | inline auto 41 | map(F f, const C& c) 42 | -> typename std::enable_if< !std::is_same::value_type>()))>::value, 43 | typename types< nonconstref_type_of(decltype(f(declval::value_type>()))) >::list >::type { 44 | typedef typename types< nonconstref_type_of(decltype(f(head(c)))) >::list result_type; 45 | result_type result; 46 | result.reserve(c.size()); 47 | return move(__map__(f, c, result)); 48 | } 49 | 50 | template 51 | void mapV(F f, const C& c) { 52 | std::for_each(extent(c), f); 53 | } 54 | 55 | template 56 | inline string map(F f, const string& s) { 57 | typedef typename types::list char_list; 58 | char_list charList; 59 | __map__(f, char_list(extent(s)), charList); 60 | return move(show(charList)); 61 | } 62 | 63 | template 64 | inline string map(F f, const char* s) { 65 | return move(map(f, string(s))); 66 | } 67 | FP_DEFINE_CURRIED(map, map_); 68 | 69 | /////////////////////////////////////////////////////////////////////////// 70 | // filter 71 | 72 | template 73 | inline C filter(F f, const C& c) { 74 | C result; result.reserve(c.size()); 75 | std::copy_if(extent(c), back(result), f); 76 | return move(result); 77 | } 78 | FP_DEFINE_CURRIED(filter, filter_); 79 | 80 | template 81 | typename types::list operator|(const typename types::list& l, F f) { 82 | return move(filter(f, l)); 83 | } 84 | 85 | /////////////////////////////////////////////////////////////////////////// 86 | // Reducing lists 87 | /////////////////////////////////////////////////////////////////////////// 88 | 89 | /////////////////////////////////////////////////////////////////////////// 90 | // fold 91 | 92 | #if 1 93 | template 94 | inline auto fold(It first, It last, Op op) -> nonconstref_type_of(decltype(op(*first, *first))) { 95 | typedef nonconstref_type_of(decltype(op(*first, *first))) T; 96 | if (first != last) { 97 | auto value = T(*first); 98 | return move(std::accumulate(++first, last, value, op)); 99 | } else { 100 | return T(); 101 | } 102 | } 103 | #else 104 | template 105 | inline auto fold(It first, It last, Op op) -> typename std::iterator_traits::value_type { 106 | if (first != last) { 107 | auto value = *first; 108 | return std::accumulate(++first, last, value, op); 109 | } else { 110 | return typename std::iterator_traits::value_type(); 111 | } 112 | } 113 | #endif 114 | 115 | template 116 | inline T fold(It first, It last, T t, Op op) { 117 | return move(std::accumulate(first, last, t, op)); 118 | } 119 | 120 | ///////////////////////////////////////////////////////////////////////////// 121 | // foldl 122 | 123 | template 124 | inline T foldl(F f, T t, const C& c) { 125 | return move(fold(extent(c), t, f)); 126 | } 127 | FP_DEFINE_CURRIED_T(foldl, foldl_, _foldl_); 128 | 129 | template 130 | inline auto foldl1(F f, const C& c) -> value_type_of(C) { 131 | return move(fold(extent(c), f)); 132 | } 133 | FP_DEFINE_CURRIED(foldl1, foldl1_); 134 | 135 | ///////////////////////////////////////////////////////////////////////////// 136 | // foldr 137 | 138 | template 139 | inline T foldr(F f, T t, const C& c) { 140 | return move(fold(rextent(c), t, f)); 141 | } 142 | FP_DEFINE_CURRIED_T(foldr, foldr_, _foldr_); 143 | 144 | template 145 | inline auto foldr1(F f, const C& c) -> value_type_of(C) { 146 | return move(fold(rextent(c), f)); 147 | } 148 | FP_DEFINE_CURRIED(foldr1, foldr1_); 149 | 150 | /////////////////////////////////////////////////////////////////////////// 151 | // Special folds 152 | /////////////////////////////////////////////////////////////////////////// 153 | 154 | /////////////////////////////////////////////////////////////////////////// 155 | // sum 156 | 157 | template 158 | auto sum(const C& c) -> value_type_of(C) { 159 | return std::accumulate(extent(c), value_type_of(C)()); 160 | } 161 | 162 | /////////////////////////////////////////////////////////////////////////// 163 | // product 164 | 165 | template 166 | auto product(const C& c) -> value_type_of(C) { 167 | return fold(extent(c), std::multiplies< value_type_of(C)>()); 168 | } 169 | 170 | /////////////////////////////////////////////////////////////////////////// 171 | // all 172 | 173 | template 174 | inline bool all(F f, const C& c) { 175 | return std::all_of(extent(c), f); 176 | } 177 | 178 | /////////////////////////////////////////////////////////////////////////// 179 | // any 180 | 181 | template 182 | inline bool any(F f, const C& c) { 183 | return std::any_of(extent(c), f); 184 | } 185 | 186 | /////////////////////////////////////////////////////////////////////////// 187 | // and 188 | 189 | template 190 | inline bool andAll(const C& c) { 191 | return fold(extent(c), std::logical_and< value_type_of(C) >()); 192 | } 193 | 194 | /////////////////////////////////////////////////////////////////////////// 195 | // or 196 | 197 | template 198 | inline bool orAll(const C& c) { 199 | return fold(extent(c), std::logical_or< value_type_of(C) >()); 200 | } 201 | 202 | /////////////////////////////////////////////////////////////////////////// 203 | // Building lists 204 | /////////////////////////////////////////////////////////////////////////// 205 | 206 | template 207 | inline void scan(InputIt first, InputIt last, OutIt out, T t0, Op op) { 208 | for(*out = t0; first != last; ) { 209 | *out = t0 = op(t0, *first++); 210 | } 211 | } 212 | 213 | template 214 | inline void scan(InputIt first, InputIt last, OutIt out, Op op) { 215 | if (first != last) { 216 | typename std::iterator_traits::value_type t0 = *first++; 217 | scan(first, last, out, t0, op); 218 | } 219 | } 220 | 221 | ////////////////////////////////////////////////////////////////////////// 222 | // scanl 223 | 224 | template 225 | typename types::list scanl(F f, T t, const C& c) { 226 | typename types::list result(1, t); 227 | scan(extent(c), back(result), t, f); 228 | return move(result); 229 | } 230 | 231 | ////////////////////////////////////////////////////////////////////////// 232 | // scanl1 233 | 234 | template 235 | C scanl1(F f, const C& c) { 236 | C result; 237 | scan(extent(c), back(result), f); 238 | return move(result); 239 | } 240 | 241 | ////////////////////////////////////////////////////////////////////////// 242 | // scanr 243 | 244 | template 245 | typename types::list scanr(F f, T t, const C& c) { 246 | typename types::list result(1, t); 247 | scan(rextent(c), back(result), t, f); 248 | return move(result); 249 | } 250 | 251 | ////////////////////////////////////////////////////////////////////////// 252 | // scanr 253 | 254 | template 255 | C scanr1(F f, const C& c) { 256 | C result; 257 | scan(rextent(c), back(result), f); 258 | return move(result); 259 | } 260 | 261 | /////////////////////////////////////////////////////////////////////////// 262 | // Infinite lists 263 | /////////////////////////////////////////////////////////////////////////// 264 | 265 | /////////////////////////////////////////////////////////////////////////// 266 | // iterate 267 | template 268 | inline std::function< T(void) > iterate(F f, T t) { 269 | return [=]() mutable -> T { T r = t; t = f(t); return r; }; 270 | } 271 | 272 | /////////////////////////////////////////////////////////////////////////// 273 | // repeat 274 | template 275 | inline thunk< T > iterate(T t) { 276 | return [=]() mutable { return t; }; 277 | } 278 | 279 | /////////////////////////////////////////////////////////////////////////// 280 | // replicate 281 | template 282 | inline auto replicate(size_t n, T t) FP_RETURNS( typename types::list(n, t) ); 283 | 284 | /////////////////////////////////////////////////////////////////////////// 285 | // cycle 286 | template 287 | inline auto cycle(const C& c) -> thunk< value_type_of(C) > { 288 | size_t i = 0; 289 | return [=]() mutable { return c[i++ % length(c)]; }; 290 | } 291 | 292 | /////////////////////////////////////////////////////////////////////////// 293 | // until 294 | template 295 | inline T until(P condition, F op, T value) { 296 | while ( !condition( value ) ) { 297 | value = op( value ); 298 | } 299 | return value; 300 | } 301 | 302 | /////////////////////////////////////////////////////////////////////////// 303 | // Zipping and unzipping lists 304 | /////////////////////////////////////////////////////////////////////////// 305 | 306 | ///////////////////////////////////////////////////////////////////////////// 307 | // zipWith 308 | 309 | template 310 | inline R& __zipWith__(F f, const T& t, const U& u, R& r) { 311 | std::transform(extent(t), begin(u), back(r), f); 312 | return r; 313 | } 314 | template 315 | inline R& __zipWith__(F f, T&& t, U&& u, R& r) { 316 | std::transform(extent(t), begin(u), back(r), f); 317 | return r; 318 | } 319 | template 320 | inline R& __zipWith3__(F f, const T& t, const U& u, const V& v, R& r) { 321 | transform3(extent(t), begin(u), begin(v), back(r), f); 322 | return r; 323 | } 324 | template 325 | inline R& __zipWith3__(F f, T&& t, U&& u, V&& v, R& r) { 326 | transform3(extent(t), begin(u), begin(v), back(r), f); 327 | return r; 328 | } 329 | 330 | template 331 | inline auto zipWith(F f, const T& t, const U& u) -> typename types::list { 332 | typedef decltype(f(head(t),head(u))) result_type; 333 | typename types::list result; 334 | return move(__zipWith__(f, t, u, result)); 335 | } 336 | template 337 | inline auto zipWith(F f, T&& t, U&& u) -> typename types::list { 338 | typedef decltype(f(head(t),head(u))) result_type; 339 | typename types::list result; 340 | return move(__zipWith__(f, t, u, result)); 341 | } 342 | FP_DEFINE_CURRIED_T(zipWith, zipWith_, _zipWith_) 343 | 344 | template 345 | inline auto zipWith3(F f, const T& t, const U& u, const V& v) -> typename types::list { 346 | typedef decltype(f(head(t), head(u), head(v))) result_type; 347 | typename types::list result; 348 | return move(__zipWith3__(f, t, u, v, result)); 349 | } 350 | template 351 | inline auto zipWith3(F f, T&& t, U&& u, V&& v) -> typename types::list { 352 | typedef decltype(f(head(t), head(u), head(v))) result_type; 353 | typename types::list result; 354 | return move(__zipWith3__(f, move(t), move(u), move(v), result)); 355 | } 356 | FP_DEFINE_CURRIED_T(zipWith3, zipWith3_, _zipWith3_) 357 | 358 | 359 | /////////////////////////////////////////////////////////////////////////// 360 | // zip 361 | 362 | template 363 | inline typename types< typename tuple_traits::type >::list zip(const C0& c1, const C1& c2) { 364 | typedef value_type_of(C0) T; 365 | typedef value_type_of(C1) U; 366 | typedef typename types< std::pair >::list result_type; 367 | result_type result; 368 | return move(__zipWith__([](const T& t, const U& u) { return std::make_pair(t,u); }, c1, c2, result)); 369 | } 370 | 371 | template 372 | inline typename types< typename triple_traits::type >::list zip3(const C0& c1, const C1& c2, const C2& c3) { 373 | typedef value_type_of(C0) T; 374 | typedef value_type_of(C1) U; 375 | typedef value_type_of(C2) V; 376 | typedef typename types< std::tuple >::list result_type; 377 | result_type result; 378 | return move(__zipWith__([](const T& t, const U& u, const V& v) { return std::make_tuple(t,u,v); }, c1, c2, c3, result)); 379 | } 380 | 381 | /////////////////////////////////////////////////////////////////////////// 382 | // unzip 383 | 384 | template 385 | inline R& __unzip__(F f, const T& t, const U& u, R& r) { 386 | std::transform(extent(t), begin(u), back(r), f); 387 | return r; 388 | } 389 | 390 | template 391 | inline auto unzip(const typename types< std::pair >::list& c) -> std::pair< typename types::list, typename types::list > { 392 | typename types::list t; 393 | typename types::list u; 394 | for_each(extent(c), [&](const std::pair& p) { 395 | t.push_back( fst(p) ); 396 | u.push_back( snd(p) ); 397 | }); 398 | return std::make_pair(t,u); 399 | } 400 | 401 | template 402 | inline std::tuple< typename types::list, typename types::list, typename types::list > unzip3(const typename types< std::tuple >::list& c) { 403 | typename types::list t; 404 | typename types::list u; 405 | typename types::list v; 406 | for_each(extent(c), [&](const std::tuple& val) { 407 | t.push_back( std::get<0>(val) ); 408 | u.push_back( std::get<1>(val) ); 409 | v.push_back( std::get<1>(val) ); 410 | }); 411 | return std::make_tuple(t,u,v); 412 | } 413 | 414 | /////////////////////////////////////////////////////////////////////////// 415 | // maximum 416 | 417 | template 418 | inline value_type_of(C) maximumBy(F f, const C& c) { 419 | return iter_value( std::max_element(extent(c), f), c); 420 | } 421 | 422 | template 423 | inline value_type_of(C) maximum(const C& c) { 424 | return iter_value( std::max_element(extent(c)), c); 425 | } 426 | 427 | /////////////////////////////////////////////////////////////////////////// 428 | // minimum 429 | 430 | template 431 | inline value_type_of(C) minimumBy(F f, const C& c) { 432 | return iter_value( std::min_element(extent(c), f), c); 433 | } 434 | 435 | template 436 | inline value_type_of(C) minimum(const C& c) { 437 | return iter_value( std::min_element(extent(c)), c); 438 | } 439 | 440 | /////////////////////////////////////////////////////////////////////////// 441 | // sortBy 442 | 443 | template 444 | inline C sortBy(F f, C c) { 445 | std::sort(extent(c), f); 446 | return move(c); 447 | } 448 | 449 | /////////////////////////////////////////////////////////////////////////// 450 | // sort 451 | 452 | template 453 | inline C sort(C c) { 454 | std::sort(extent(c)); 455 | return move(c); 456 | } 457 | 458 | #if !USE_DEQUE_FOR_LISTS 459 | template 460 | inline typename std::enable_if::value,std::list >::type sort(std::list l) { 461 | l.sort(); 462 | return move(l); 463 | } 464 | #endif 465 | 466 | /////////////////////////////////////////////////////////////////////////// 467 | // groupBy 468 | 469 | template 470 | inline typename types::list groupBy(F f, const C& c) { 471 | typename types::list result; 472 | let it = begin(c); 473 | while (it != end(c)) { 474 | result.push_back( C() ); 475 | it = copyWhile(it, end(c), back(result.back()), [&]( const value_type_of(C) & t ) { 476 | return f(*it,t); 477 | }); 478 | } 479 | return move(result); 480 | } 481 | 482 | /////////////////////////////////////////////////////////////////////////// 483 | // group 484 | 485 | template 486 | inline typename types::list group(const C& c) { 487 | return groupBy(std::equal_to< value_type_of(C) >(), c); 488 | } 489 | 490 | /////////////////////////////////////////////////////////////////////////// 491 | // insertBy 492 | 493 | template 494 | inline C insertBy(F f, T t, C c) { 495 | let compare = [&](const T& t1) { return f(t, t1); }; 496 | c.insert( std::find_if( extent(c), compare ), t ); 497 | return move(c); 498 | } 499 | 500 | /////////////////////////////////////////////////////////////////////////// 501 | // insert 502 | 503 | template 504 | inline C insert(T t, C c) { 505 | return insertBy( math::less, t, c ); 506 | } 507 | 508 | /////////////////////////////////////////////////////////////////////////// 509 | // Sublists 510 | /////////////////////////////////////////////////////////////////////////// 511 | 512 | ////////////////////////////////////////////////////////////////////////// 513 | // takeWhile 514 | 515 | template 516 | inline C takeWhile(F f, const C& c) { 517 | C result; 518 | //std::copy(begin(t), std::find_if(extent(t), std::not1(f)), back(result)); 519 | copyWhile(extent(c), back(result), f); 520 | return move(result); 521 | } 522 | FP_DEFINE_CURRIED(takeWhile, takeWhile_); 523 | 524 | template 525 | inline auto takeWhileT(F f, T t) -> typename types< decltype(t()) >::list { 526 | typedef decltype(t()) t_type; 527 | typename types::list result; 528 | auto back_iter = back(result); 529 | for (let value = t(); f(value); value=t()) 530 | back_iter = value; 531 | return move(result); 532 | } 533 | FP_DEFINE_CURRIED(takeWhileT, takeWhileT_); 534 | 535 | /////////////////////////////////////////////////////////////////////////// 536 | // take 537 | template 538 | inline C take(size_t n, const C& c) { 539 | let takeN = [=](...) mutable { return n-- > 0; }; 540 | return takeWhile(takeN, c); 541 | } 542 | template 543 | inline typename types::list take(size_t n, const typename types::list& v) { 544 | return n < length(v) ? typename types::list(begin(v), begin(v) + n) : v; 545 | } 546 | template 547 | inline auto takeF(size_t n, F f) -> typename types< decltype(f()) >::list { 548 | typename types< decltype(f()) >::list result(n); 549 | std::generate_n(begin(result), n, f); 550 | return move(result); 551 | } 552 | 553 | /////////////////////////////////////////////////////////////////////////// 554 | // dropWhile 555 | 556 | template 557 | inline C dropWhile(F f, const C& c) { 558 | C result; 559 | std::copy(std::find_if_not(extent(c), f), end(c), back(result)); 560 | return move(result); 561 | } 562 | FP_DEFINE_CURRIED(dropWhile, dropWhile_); 563 | 564 | /////////////////////////////////////////////////////////////////////////// 565 | // drop 566 | 567 | template 568 | inline C drop(size_t n, const C& c) { 569 | #if 1 570 | return n < length(c) ? C( begin(c) + n, end(c) ) : C(); 571 | #else 572 | let dropN = [=](const typename traits::value_type&) mutable { return n-- > 0; }; 573 | return dropWhile(dropN, c); 574 | #endif 575 | } 576 | 577 | /////////////////////////////////////////////////////////////////////////// 578 | // splitAt 579 | 580 | template 581 | inline pair splitAt(size_t n, const C& c) { 582 | return make_pair( take(n, c), drop(n, c) ); 583 | } 584 | 585 | /////////////////////////////////////////////////////////////////////////// 586 | // span 587 | 588 | template 589 | inline pair span(F f, const C& c) { 590 | return make_pair( takeWhile(f, c), dropWhile(f, c) ); 591 | } 592 | 593 | /////////////////////////////////////////////////////////////////////////// 594 | // break 595 | 596 | template 597 | inline pair spanNot(F f, const C& c) { 598 | return span( std::not1(f), c ); 599 | } 600 | 601 | /////////////////////////////////////////////////////////////////////////// 602 | // slice 603 | 604 | template 605 | inline C slice(size_t i, size_t n, const C& c) { 606 | return C(begin(c)+i, begin(c)+i+n); 607 | } 608 | 609 | 610 | /////////////////////////////////////////////////////////////////////////// 611 | // Searching lists 612 | /////////////////////////////////////////////////////////////////////////// 613 | 614 | /////////////////////////////////////////////////////////////////////////// 615 | // elem 616 | 617 | template 618 | inline bool elem(const T& t, const C& c) { 619 | return std::find(extent(c), t) != end(c); 620 | } 621 | 622 | /////////////////////////////////////////////////////////////////////////// 623 | // notElem 624 | 625 | template 626 | inline bool notElem(const T& t, const C& c) { 627 | return !elem(t, c); 628 | } 629 | 630 | /////////////////////////////////////////////////////////////////////////// 631 | // lookup 632 | 633 | template 634 | inline bool lookup(const K& k, const C& c) { 635 | return iter_value( c.find(k), c ); 636 | } 637 | 638 | /////////////////////////////////////////////////////////////////////////// 639 | // Generating lists 640 | /////////////////////////////////////////////////////////////////////////// 641 | 642 | /////////////////////////////////////////////////////////////////////////// 643 | // increasing 644 | template 645 | inline auto increasing(T t0 = (T)0) FP_RETURNS( iterate(&succ, t0) ); 646 | template 647 | inline auto increasingN(size_t n, T t0 = (T)0) FP_RETURNS( takeF(n, increasing(t0)) ); 648 | 649 | /////////////////////////////////////////////////////////////////////////// 650 | // decreasing 651 | template 652 | inline auto decreasing(T t0 = (T)0) FP_RETURNS( iterate(&pred, t0) ); 653 | template 654 | inline auto decreasingN(size_t n, T t0 = (T)0) FP_RETURNS( takeF(n, decreasing(t0)) ); 655 | 656 | /////////////////////////////////////////////////////////////////////////// 657 | // enumFrom 658 | template 659 | inline auto enumFrom(T t0) FP_RETURNS( iterate(&succ, t0) ); 660 | 661 | /////////////////////////////////////////////////////////////////////////// 662 | // uniform 663 | template 664 | inline typename types::list uniformN(size_t n, T t0, T t1) { 665 | return takeF(n, [=]() { return math::uniform(t0,t1); }); 666 | } 667 | 668 | /////////////////////////////////////////////////////////////////////////// 669 | // auto lists 670 | 671 | // Example: (0 9) == increasingN(0, 10) 672 | static struct list_to_helper { } to; 673 | 674 | template 675 | struct list_to_helper_val { 676 | list_to_helper_val(T value_) : value(value_) { } 677 | T value; 678 | }; 679 | 680 | template 681 | inline auto operator>(list_to_helper_val t0, T1 t1) FP_RETURNS( increasingN((T0)(t1-t0.value+1), t0.value) ); 682 | template 683 | inline list_to_helper_val operator<(T t, list_to_helper) { 684 | ((void)to); 685 | return list_to_helper_val(t); 686 | } 687 | 688 | /////////////////////////////////////////////////////////////////////////// 689 | // concat 690 | template 691 | inline fp_enable_if_container(T,T) 692 | concat(T t0, const T& t1) { 693 | std::copy(extent(t1), back(t0)); 694 | return move(t0); 695 | } 696 | template 697 | inline fp_enable_if_not_container(T,typename types::list) 698 | concat(const T& t0, const T& t1) { 699 | typename types::list result(1, t0); 700 | return move(result.append(t1)); 701 | } 702 | 703 | /////////////////////////////////////////////////////////////////////////// 704 | // append 705 | template 706 | inline C append(C c, const T& t) { 707 | c.insert(end(c), t); 708 | return move(c); 709 | } 710 | 711 | /////////////////////////////////////////////////////////////////////////// 712 | // cons 713 | template 714 | inline C cons(const T& t, const C& c) { 715 | return concat( append(C(), t), c ); 716 | } 717 | template 718 | inline std::deque cons(const T& t, std::deque c) { 719 | c.push_front(t); 720 | return move(c); 721 | } 722 | inline string cons(char t, string s) { 723 | return move(s.insert(0, 1, t)); 724 | } 725 | inline string cons(string s0, const string& s1) { 726 | return move(s0.append(s1)); 727 | } 728 | 729 | /////////////////////////////////////////////////////////////////////////// 730 | // reverse 731 | 732 | #if 1 733 | template 734 | inline C reverse( C c ) { 735 | std::reverse( extent(c) ); 736 | return move(c); 737 | } 738 | #else 739 | template 740 | inline C reverse(const C& c) { 741 | return move(foldl( flip( cons ), C(), c )); 742 | } 743 | #endif 744 | 745 | /////////////////////////////////////////////////////////////////////////// 746 | // Pair/Tuple 747 | 748 | using std::pair; 749 | using std::make_pair; 750 | 751 | template 752 | inline nonconstref_type_of(T) fst(const pair& p) { 753 | return p.first; 754 | } 755 | 756 | template 757 | inline nonconstref_type_of(U) snd(const pair& p) { 758 | return p.second; 759 | } 760 | 761 | #if 0 762 | template 763 | inline nonconstref_type_of(T) fst(pair&& p) { 764 | return move(p.first); 765 | } 766 | template 767 | inline nonconstref_type_of(U) snd(pair&& p) { 768 | return move(p.second); 769 | } 770 | #endif 771 | 772 | template 773 | inline pair swap(const pair& p) { 774 | return make_pair(p.first,p.second); 775 | } 776 | 777 | template 778 | inline auto mapPair(F0 f0, F1 f1, const std::pair& p) FP_RETURNS( make_pair( f0(p.first), f1(p.second) ) ); 779 | 780 | template 781 | inline auto mapFst(F f, const std::pair& p) FP_RETURNS( make_pair( f(p.first), p.second ) ); 782 | FP_DEFINE_CURRIED(mapFst, mapFst_); 783 | 784 | /////////////////////////////////////////////////////////////////////////// 785 | // mapSnd 786 | 787 | template 788 | inline auto mapSnd(F f, const std::pair& p) FP_RETURNS( make_pair( p.first, f(p.second) ) ); 789 | template 790 | struct mapSndF { 791 | mapSndF(F0 f0_) : f0(f0_) { } 792 | template 793 | inline auto operator()(const pair& t) -> std::pair()(snd(t)) )> { 794 | return make_pair( fst(t), f0(snd(t)) ); 795 | } 796 | 797 | F0 f0; 798 | }; 799 | template 800 | mapSndF mapSndF_(F0 f0) { return mapSndF(f0); } 801 | 802 | /////////////////////////////////////////////////////////////////////////// 803 | // mapArrow 804 | 805 | template 806 | inline auto mapArrow(F0 f0, F1 f1, const T& t) FP_RETURNS( make_pair( f0(t), f1(t) ) ); 807 | 808 | // TODO: Factor this out into some nice common code for re-use 809 | template 810 | struct mapArrowF { 811 | mapArrowF(F0 f0_, F1 f1_) : f0(f0_), f1(f1_) { } 812 | template 813 | inline auto operator()(const T& t) -> std::pair()(t) ), decltype( declval()(t) )> { 814 | return make_pair( f0(t), f1(t) ); 815 | } 816 | 817 | F0 f0; 818 | F1 f1; 819 | }; 820 | template 821 | mapArrowF mapArrowF_(F0 f0, F1 f1) { return mapArrowF(f0,f1); } 822 | 823 | } /* namespace fp */ 824 | 825 | #endif /* _FP_PRELUDE_LISTS_H_ */ 826 | --------------------------------------------------------------------------------