Skip to content

Instantly share code, notes, and snippets.

@hryniuk
Last active March 26, 2017 13:35
Show Gist options
  • Save hryniuk/e0141e2994d07745c1ed to your computer and use it in GitHub Desktop.
Save hryniuk/e0141e2994d07745c1ed to your computer and use it in GitHub Desktop.
Reduce
#include <iostream>
#include <vector>
#include "Op.hpp"
#include "Reduce.hpp"
int main()
{
std::vector<double> values{1.0, 2.0, 5.0, 4.0, 5.5};
Reduce<SumOp, SumFloorOp, ProductOp, SumSquareOp> r;
std::for_each(std::begin(values), std::end(values), [&r](auto&& v){r(v);});
auto v = r.GetResult();
for (const auto& i : v) {
std::cout << i << '\n';
}
}
#ifndef OP_HPP
#define OP_HPP
#include <array>
#include <cmath>
#include <functional>
template <typename T1, typename T2, typename T3=void>
using _RefFunTemplate = std::function<T3(T1, T2)>;
using DoubleRefFun = _RefFunTemplate<double&,double>;
template<typename T>
const std::array<T, 4> ref_funs
{
[](auto&& rAccum, auto&& v){rAccum += v;},
[](auto&& rAccum, auto&& v){rAccum += std::floor(v);},
[](auto&& rAccum, auto&& v){rAccum += v * v;},
[](auto&& rAccum, auto&& v){rAccum *= v;}
};
template<int i, int init, typename TRefFun=DoubleRefFun>
struct _RefOp
{
using F = std::decay_t<typename TRefFun::first_argument_type>;
static constexpr F init_val{static_cast<F>(init)};
TRefFun op_{ref_funs<TRefFun>[i]};
F getInitVal() const
{
return init_val;
}
void operator()(F& rAccum, F v)
{
op_(rAccum, v);
}
};
using SumOp = _RefOp<0,0,DoubleRefFun>;
using SumFloorOp = _RefOp<1,0,DoubleRefFun>;
using SumSquareOp = _RefOp<2,0,DoubleRefFun>;
using ProductOp = _RefOp<3,1,DoubleRefFun>;
#endif
#ifndef REDUCE_HPP
#define REDUCE_HPP
#include <algorithm>
#include <functional>
#include <iostream>
#include <tuple>
#include <type_traits>
#include <vector>
template<typename... TOp>
struct Reduce
{
static constexpr int N{sizeof...(TOp)};
std::tuple<TOp...> op_;
std::vector<double> result_;
Reduce()
: op_{std::tuple<TOp...>{}}, result_(N)
{
initialize(result_);
}
std::vector<double> GetResult() const
{
return result_;
}
template<int i=0>
void initialize(std::vector<double>& v, bool) {}
template<int i=0>
void initialize(std::vector<double>& v, int={})
{
result_[i] = std::get<i>(op_).getInitVal();
initialize<i+1>(v, std::conditional_t< (i+1 < N), int, bool>{});
}
template<int i=0>
void operator()(double a, bool) {}
template<int i=0>
void operator()(double a, int _k=0)
{
std::get<i>(op_)(result_[i], a);
operator()<i+1>(a, std::conditional_t< (i+1 < N), int, bool>{});
}
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment