1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#pragma once
#include "mm/mmmatrix.hpp"
#include <variant>
#include <tuple>
#include <type_traits>
#include <functional>
namespace mm {
namespace algorithm {
// does nothing
struct visit
{
visit() = default;
template<typename Matrix>
void operator()(Matrix& m) {}
};
struct transpose : public visit
{
/// does not work with non-square matrices
template<typename Matrix>
void operator()(Matrix& m) {
static_assert(Matrix::rows == Matrix::cols);
// naiive impl
for (index r = 0; r < m.rows / 2; r++)
for (index c = 0; c < m.cols; c++)
if (c != r)
std::swap(m.at(r, c), m.at(c, r));
}
};
/// algorithm aliases
using tr = transpose;
}
/// namespace alias
namespace alg = algorithm;
template<typename Matrix>
struct clone
{
Matrix matrix;
explicit clone(Matrix&& m) : matrix(m) {}
explicit clone(const Matrix& m) : matrix(m) {}
operator Matrix() {
return std::move(matrix);
}
};
template<typename Matrix, typename ...Algs>
struct mutate
{
Matrix& matrix;
std::tuple<Algs...> visitors;
explicit mutate(Matrix& m) : matrix(m) {}
template<typename ...OAlgs, typename Alg>
explicit mutate(Matrix& m, std::tuple<OAlgs...>&& t, Alg&& v)
: matrix(m)
{
/// append the new operator
visitors = std::tuple_cat(t, std::make_tuple(v));
}
~mutate() {
visit();
}
void visit() {
std::apply([this](auto&&... v) {
(v(matrix),...);
}, visitors);
}
operator Matrix() {
return std::move(matrix);
}
};
template<typename Matrix, typename Alg>
clone<Matrix> operator|(clone<Matrix>&& cl, Alg&& v) {
static_assert(std::is_convertible<Alg, alg::visit>::value);
/// apply alg operator
v(cl.matrix);
/// forward to next alg
return clone<Matrix>(std::move(cl));
}
template<typename Matrix, typename ...Algs, typename Alg>
mutate<Matrix, Algs..., Alg> operator|(mutate<Matrix, Algs...>&& mut, Alg&& v) {
static_assert(std::is_convertible<Alg, alg::visit>::value);
/// append alg to the visitors tuple
return mutate<Matrix, Algs..., Alg>(
mut.matrix,
std::move(mut.visitors),
v
);
}
template<typename Matrix, typename Alg>
mutate<Matrix, Alg> operator|(Matrix& m, Alg&& v) {
return mutate(m) | std::move(v);
}
}
|