Last active
August 29, 2015 14:02
-
-
Save Seikilos/3cc68b8aa85e4edad277 to your computer and use it in GitHub Desktop.
Pipeline class utilizing C++11 Features, handles Visual Studio 2012 incompleteness of C++11 standard. Now with conditional items utilizing predicates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <string> | |
#include <functional> | |
#include <vector> | |
#include <utility> | |
/** | |
* Pipeline class. | |
* | |
* Note: This class is not copy assignable or copy constructible but movable! It is sealed per design. | |
* Use a wrapped TItem in order to execute specific operations for a given object prior/after calling the inner element | |
*/ | |
template<typename TDataObject, typename TItem = std::function<void(TDataObject)>> | |
class Pipeline final | |
{ | |
public: | |
typedef typename TDataObject DataType; | |
typedef typename std::function<bool(DataType)> Predicate; | |
bool static ALWAYS_TRUE(DataType) | |
{ | |
return true; | |
} | |
bool static ALWAYS_FALSE(DataType) | |
{ | |
return false; | |
} | |
Pipeline(const std::string name): | |
m_sName(name) | |
{ | |
} | |
/** | |
* Move assignment operator | |
*/ | |
Pipeline& operator=(Pipeline&& other) | |
{ | |
if (this != &other) | |
{ | |
std::swap(m_sName,other.m_sName); | |
other.m_sName.clear(); | |
std::swap(m_vPipeline, other.m_vPipeline); | |
other.m_vPipeline.clear(); | |
} | |
return *this; | |
} | |
/** | |
* Move constructor | |
*/ | |
Pipeline (Pipeline&& other) | |
{ | |
std::swap(m_sName,other.m_sName); | |
other.m_sName.clear(); | |
std::swap(m_vPipeline, other.m_vPipeline); | |
other.m_vPipeline.clear(); | |
} | |
/** | |
* Adds a type of TItem into pipeline | |
*/ | |
void Add(TItem item, Predicate filter = &Pipeline::ALWAYS_TRUE) | |
{ | |
m_vPipeline.push_back(std::make_tuple(item,filter)); | |
} | |
/** | |
* Helper for easier class method addition | |
*/ | |
template<typename TMethodAddress, typename TInstance> | |
void AddInstance(TMethodAddress address, TInstance instance, Predicate filter = &Pipeline::ALWAYS_TRUE) | |
{ | |
Add(std::bind(address, instance, std::placeholders::_1), filter); | |
} | |
/** | |
* Helper returns a TItem to be added via Add(TItem) or with the variadic template argument version of Add(...) | |
*/ | |
template<typename TMethodAddress, typename TInstance> | |
inline TItem Get(TMethodAddress address, TInstance instance) | |
{ | |
return (std::bind(address, instance, std::placeholders::_1)); | |
} | |
#if _MSC_VER >= 1800 | |
// Only with VS 2013 and higher, allows chaining of several arguments | |
template <typename ...Tail> | |
void Add(TItem head, Tail... tail) | |
{ | |
Add(head); | |
Add(std::forward<Tail>(tail)...); | |
} | |
#endif | |
void Execute(TDataObject argument) | |
{ | |
for(auto object : m_vPipeline) | |
{ | |
if(std::get<1>(object)(argument) == true) | |
{ | |
std::get<0>(object)(argument); | |
} | |
} | |
} | |
const std::string & GetName() const { return m_sName; } | |
protected: | |
std::string m_sName; | |
std::vector<std::tuple<TItem, Predicate>> m_vPipeline; | |
private: | |
Pipeline(const Pipeline&); // prevent copy constructor to be used | |
Pipeline& operator=(const Pipeline&); // prevent copy assignment to be used | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Simple example + moving of pipeline | |
{ | |
Pipeline<int> p("Sample path"); | |
p.Add([](int i){std::cout << i+1 << std::endl;}); | |
p.Add([](int i){std::cout << i+42 << std::endl;}); | |
auto f = std::move(p); // moveable class | |
f.Execute(4); | |
} | |
// How to pass a pipeline around without moving | |
{ | |
std::unique_ptr<Pipeline<int>> p2(new Pipeline<int>("second")); | |
auto & p3 = p2; | |
} | |
// Using Wrapper class without altering the Add() signature | |
{ | |
Pipeline<int, Wrapper<FuncType>> p("Wrapped pipeline"); // <-- utilizing Wrapper | |
p.Add([](int i){std::cout << i+1 << std::endl;}); | |
p.Add([](int i){std::cout << i+42 << std::endl;}); | |
p.Execute(4); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Binding methods of class and utilizing C++11 variadic templates (VS 2013) | |
class Dummy | |
{ | |
public: | |
void method(int i) | |
{ | |
} | |
}; | |
Dummy d; | |
Pipeline<int> p("Variading path"); | |
p.Add( | |
[](int i){std::cout << i + 1 << std::endl; }, // Lambda | |
std::bind(&Dummy::method, &d, std::placeholders::_1), // Standard bind | |
p.Get(&Dummy::method, &d) // Helper to remove verbose bindg call and placeholder | |
); | |
// Another helper for directly adding a bind instance (used when compiler does not support variadic template arguments) | |
p.Add(&Dummy::method, &d); | |
p.Execute(4); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Predicate | |
Pipeline<int &> p("Filter"); | |
p.Add([](int & i) {++i;}, Pipeline<int &>::ALWAYS_FALSE); | |
p.Add([](int & i) {i+=2;}, [](int & v) { return v > 10;}); | |
p.Add([](int & i) {i+=2;}); | |
auto number = 42; | |
p.Execute(number); | |
assert(number == 46); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <functional> | |
#include <vector> | |
typedef std::function<void(int)> FuncType; | |
template<class T> | |
class Wrapper | |
{ | |
public: | |
template< | |
typename U, | |
typename std::enable_if< std::is_constructible<T, U>::value, int >::type = 0 | |
> | |
//use template<class U> for VS2012 | |
Wrapper(U t) | |
: _t(std::move(t)) | |
{} | |
void operator()(int i) const | |
{ | |
// Do wrapped code here e.g. benchmark, logging of _t.target_type().name() | |
_t(i); | |
} | |
private: | |
T _t; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment