summaryrefslogtreecommitdiffstats
path: root/include/mm/view.hpp
blob: e701a78472e508bae651ba69d710648e8b681cd6 (plain)
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
112
#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);
	}
}