Files
hack/src/math/matrix.hpp
2022-03-24 16:16:45 +03:00

158 lines
4.0 KiB
C++

#pragma once
#include <memory>
#include <vector>
#include <tuple>
#include <algorithm>
#include <iostream>
#include "utils/utils.hpp"
namespace hack::matrix_utils
{
template<typename T,typename index_data, typename index_t>
class proxy
{
using next_index_t = decltype(std::tuple_cat(index_t{}, std::make_tuple(std::size_t{})));
public:
proxy(const std::weak_ptr<index_data>& local_storage, const index_t& index) : local_storage_ { local_storage }, index_ { index } {};
~proxy() = default;
auto operator[](std::size_t index) const
{
return proxy<T, index_data, next_index_t>{ local_storage_, std::tuple_cat(index_, std::make_tuple(index)) };
}
auto& operator=(const T& value)
{
std::shared_ptr<index_data>(local_storage_)->set_value(index_, value);
return *this;
}
operator T() const
{
return std::shared_ptr<index_data>(local_storage_)->get_value(index_);
}
private:
std::weak_ptr<index_data> local_storage_;
index_t index_;
};
}
namespace hack
{
template <typename... T, std::size_t... I>
auto subtuple_s(const std::tuple<T...>& t, std::index_sequence<I...>)
{
return std::make_tuple(std::get<I>(t)...);
}
template <typename... T>
auto subtuple(const std::tuple<T...>& t)
{
return subtuple_s(t, std::make_index_sequence<sizeof...(T) - 1>());
}
template<typename T, std::size_t dimensions>
class matrix
{
using index_t = typename utils::generate_tuple<std::size_t, dimensions>::type;
using vector_t = decltype(std::tuple_cat(index_t{}, std::make_tuple(T{})));
using index_data_t = std::vector<vector_t>;
public:
matrix() noexcept : local_storage_ { new index_data{} } { }
matrix(std::initializer_list<vector_t> l) noexcept : local_storage_ { new index_data{} }
{
local_storage_->values.insert(local_storage_->values.end(), l.begin(), l.end());
}
matrix(matrix& mt) noexcept : local_storage_ { mt.local_storage_ } { }
matrix(matrix&& mt) noexcept : local_storage_ { mt.local_storage_ } { }
~matrix() = default;
matrix& operator=(matrix&& mt)
{
if (this == &mt) return *this;
local_storage_.reset();
local_storage_ = mt.local_storage_;
return *this;
}
matrix& operator=(const matrix& mt)
{
if (this == &mt) return *this;
local_storage_ = mt.local_storage_;
return *this;
}
auto operator[](std::size_t index)
{
return matrix_utils::proxy<T, index_data, std::tuple<std::size_t>>{ local_storage_, std::make_tuple(index) };
}
int size() const
{
return local_storage_->values.size();
}
auto begin() noexcept
{
return local_storage_->values.begin();
}
auto begin() const noexcept
{
return local_storage_->values.begin();
}
auto end() noexcept
{
return local_storage_->values.end();
}
auto end() const noexcept
{
return local_storage_->values.end();
}
auto cbegin() const noexcept
{
return local_storage_->values.cbegin();
}
auto cend() const noexcept
{
return local_storage_->values.cend();
}
private:
struct index_data
{
void set_value(const index_t& index, const T& v)
{
auto value = std::tuple_cat(index, std::make_tuple(v));
values.push_back(value);
}
auto get_value(const index_t& index)
{
auto it = std::find_if(values.begin(), values.end(), [&](auto a) { return subtuple(a) == index; });
return std::get<dimensions>(*it);
}
index_data_t values;
};
private:
std::shared_ptr<index_data> local_storage_;
};
template <typename T, typename U, std::size_t N>
bool operator==(const matrix<T, N>& lhs, const matrix<U, N>& rhs)
{
return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
}
}