├── LICENSE ├── README.md ├── compose.hpp ├── map.hpp └── mixin.hpp /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 LoopPerfect 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mixor 2 | functional template library 3 | 4 | The goal of this minimalistic library is to provide tools to compose and transform data in a declarative way. Using templates, this is implemented with zero run-time overhead. 5 | 6 | It relies on functional concepts and data-driven design. 7 | 8 | ```c++ 9 | #include "mixin.hpp" 10 | #include "compose.hpp" 11 | #include 12 | 13 | struct Position { 14 | float x=0.0f; 15 | float y=0.0f; 16 | }; 17 | 18 | struct Speed { 19 | float vx=0.0f; 20 | float vy=0.0f; 21 | }; 22 | 23 | struct Size { 24 | float sizeX= 0.0f; 25 | float sizeY= 0.0f; 26 | } 27 | 28 | struct Image { 29 | std::string ImagePath=""; 30 | } 31 | 32 | using namespace mixor; 33 | auto bird = mix( Pos{10,10} , Image{"bird.png"} , Size{10,10} ); 34 | auto movingBird = mix( bird, Speed{0,10} ); 35 | float dt = 1; 36 | 37 | auto move = [dt](auto const& object) { 38 | // lets define default values in case object has no Position or Speed 39 | auto defaults = mix(Position{0,0}, Speed{0,0}); 40 | auto o = mix(defaults, object); // or mix( Position{}, Speed{}, object ) 41 | return mix(object, Position{ 42 | o.x + o.vx*dt , o.y + o.vy *dt } 43 | }); 44 | }; 45 | 46 | auto applyGravity = [dt](auto const& object) { 47 | return mix(object, Speed{ 48 | object.vx, object.vy - 2*dt } 49 | }); 50 | } 51 | 52 | auto clipToGround = [](auto const& o) { 53 | return mix(o, Position{o.x, (o.y>0) * o.y }); // make sure object is above ground 54 | } 55 | 56 | auto simulationStep = compose(move, applyGravity, clipToGround ); 57 | using Drawable = decltype( mix( Position{}, Image{} ) ); 58 | 59 | auto draw( Drawable const& obj) { std::cout << obj.y << std::endl; }; 60 | 61 | while(bird.y!=0) { 62 | draw(obj); 63 | bird = simulationStep(bird); 64 | } // prints 10 , 20 , 10 , 0 65 | 66 | ``` 67 | 68 | In case you have many iterable objects: 69 | ```c++ 70 | 71 | using Object = decltype(mix(Position{}, Speed{}, Image{})); 72 | 73 | std::vector objects; 74 | 75 | auto simulationStepforAll = compose( 76 | map(move), 77 | map(applyGravity), 78 | map(clipToGround) 79 | ); //or map(compose(move, applyGravity, clipToGround)); 80 | 81 | objects = simulationStepforAll(objects); 82 | 83 | ``` 84 | 85 | You can see it in action: 86 | - https://github.com/LoopPerfect/boids 87 | - https://www.youtube.com/watch?v=viVroGmeQDw 88 | -------------------------------------------------------------------------------- /compose.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MIXOR_COMPOSE_HPP 2 | #define MIXOR_COMPOSE_HPP 3 | 4 | #include 5 | 6 | namespace mixor { 7 | 8 | template 9 | auto compose(F...) { 10 | return [](auto const& x) { 11 | return x; 12 | }; 13 | } 14 | 15 | 16 | template 17 | auto compose(F const& f, Fs const&...fs) { 18 | return [=](auto const& x) { 19 | return compose(fs...)(f(x)); 20 | }; 21 | } 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MIXOR_MIXIN_HPP 2 | #define MIXOR_MIXIN_HPP 3 | #include 4 | 5 | namespace mixor { 6 | template 7 | auto map(F const& f) { 8 | return [=](auto const& v){ 9 | std::vector w.reserve(v.size()); 10 | for(auto const& x : v) { 11 | w.push_back(f(x)); 12 | } 13 | return w; 14 | }; 15 | } 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /mixin.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MIXOR_MIXIN_HPP 2 | #define MIXOR_MIXIN_HPP 3 | #include 4 | 5 | #define REQUIRES(C) std::enable_if_t<(C), int> = 0 6 | 7 | namespace mixor { 8 | 9 | template 10 | constexpr bool any(X const& x) { 11 | return (bool)x; 12 | } 13 | 14 | template 15 | constexpr bool any(X const& x, Y const& y) { 16 | return x || y; 17 | } 18 | 19 | template 20 | constexpr bool any(X const& x, Xs const&...xs) { 21 | return any(x, any(xs...) ); 22 | } 23 | 24 | template::value) )> 26 | B either(L const&, R const& r) { 27 | return r; 28 | } 29 | 30 | template::value) )> 32 | B either(L const& l, R const&) { 33 | return l; 34 | } 35 | 36 | 37 | 38 | template 39 | struct Mixin 40 | {}; 41 | 42 | template 43 | struct Mixin 44 | : B { 45 | 46 | Mixin(B const& b) 47 | : B{b} 48 | {} 49 | 50 | template 51 | Mixin( Mixin const& rhs) 52 | : B{ either(B{}, rhs) } 53 | {} 54 | 55 | Mixin()=default; 56 | Mixin(Mixin const&)=default; 57 | }; 58 | 59 | template 60 | struct Mixin 61 | : B 62 | , Mixin { 63 | 64 | Mixin(B const& b, Bs const&...bs) 65 | : B{b}, Mixin{bs...} 66 | {} 67 | 68 | template 69 | Mixin( Mixin const& rhs) 70 | : B{ either(B{}, rhs) } 71 | , Mixin{ either(Bs{}, rhs)... } 72 | {} 73 | 74 | Mixin()=default; 75 | Mixin(Mixin const&)=default; 76 | }; 77 | 78 | 79 | template 80 | constexpr auto mergeFragment( 81 | Mixin const& b 82 | ) { 83 | return b; 84 | } 85 | 86 | template::value... 89 | ))> 90 | constexpr auto mergeFragment( 91 | Mixin const& b, 92 | X const& x 93 | ) { 94 | return Mixin{ 95 | (B const&)b..., x 96 | }; 97 | } 98 | 99 | template::value... 102 | ))> 103 | constexpr auto mergeFragment(Mixin const& b, X const& x) { 104 | return Mixin { 105 | either(b, x)... 106 | }; 107 | } 108 | 109 | template 110 | constexpr auto mergeFragment(Mixin const& b, X const& x, Xs const&...xs) { 111 | return mergeFragment(mergeFragment(b,x), xs...); 112 | } 113 | 114 | 115 | 116 | template 117 | constexpr auto merge(L const& l) { 118 | return Mixin{l}; 119 | } 120 | 121 | template 122 | constexpr auto merge(Mixin const& l) { 123 | return l; 124 | } 125 | 126 | 127 | template 128 | constexpr auto merge(Mixin const& l, Mixin const& r) { 129 | return mergeFragment( 130 | l, (R)r... 131 | ); 132 | } 133 | 134 | 135 | template 136 | constexpr auto merge(X const& x, Xs const&...xs) { 137 | return merge( 138 | merge(x), 139 | merge(xs...) 140 | ); 141 | } 142 | 143 | static auto mix= [](auto const&...x) { 144 | return merge(x...); 145 | }; 146 | 147 | template 148 | constexpr Mixin strip(Mixin const& m) { 149 | return { 150 | either(B{},m)... 151 | }; 152 | } 153 | 154 | template 155 | constexpr Mixin strip(Mixin base, Mixin const& m) { 156 | return { 157 | either(base, m)... 158 | }; 159 | } 160 | 161 | } 162 | 163 | #endif 164 | --------------------------------------------------------------------------------