OTUS Matrix
 All Classes Namespaces Files Functions Typedefs
matrix.hpp
Go to the documentation of this file.
1 //
2 // +-+-+-+-+
3 // |O|T|U|S|
4 // +-+-+-+-+-+-+
5 // |M|A|T|R|I|X|
6 // +-+-+-+-+-+-+
7 //
8 // Filename: matrix.hpp
9 // Require: C++14 Standard
10 // Author: Alexander Yashkin
11 // Description: The multi-dimensional sparse matrix.
12 //
13 
14 #ifndef OTUS_MATRIX_HPP
15 #define OTUS_MATRIX_HPP
16 
17 #include <cstddef>
18 #include <functional>
19 #include <initializer_list>
20 #include <tuple>
21 #include <unordered_map>
22 #include <utility>
23 
24 namespace otus {
25 
27 template <typename T, T DefaultValue, size_t Dimension = 2>
28 class Matrix {
29  private:
30  static_assert(Dimension > 0, "The dimension of the matrix must be greater than 0");
31 
32  template <typename TupleType, unsigned N, typename... Types>
33  struct generate_tuple_type {
34  using type = typename generate_tuple_type<TupleType, N - 1, TupleType, Types...>::type;
35  };
36 
37  template <typename TupleType, typename... Types>
38  struct generate_tuple_type<TupleType, 0, Types...> {
39  using type = std::tuple<Types...>;
40  };
41 
43  class Iterator;
45  class TupleHash;
47  template <size_t N, typename... Types>
48  class Layout;
50  template <typename... Types>
51  class Layout<0, Types...>;
52 
53  using TupleKey = typename generate_tuple_type<size_t, Dimension>::type;
54  using Contanter = std::unordered_map<TupleKey, T, TupleHash>;
55  using NextLayout = Layout<Dimension - 1, size_t>;
56 
57  Contanter elements_;
58  const T defaultValue_{DefaultValue};
59 
60  public:
61  Matrix() = default;
62  ~Matrix() = default;
63  Matrix(const Matrix &other) noexcept : elements_(other.elements_) {}
64  Matrix(Matrix &&other) noexcept : elements_(std::move(other.elements_)) {}
65 
66  Matrix(std::initializer_list<std::pair<const TupleKey, T>> list) {
67  elements_.reserve(list.size());
68  for (const auto &element : list) {
69  elements_.emplace(element);
70  }
71  }
72 
73  Matrix &operator=(const Matrix &other) {
74  elements_ = other.elements_;
75  return *this;
76  }
77  Matrix &operator=(Matrix &&other) noexcept {
78  elements_ = std::move(other.elements_);
79  return *this;
80  }
81 
82  bool operator==(const Matrix &other) const { return elements_ == other.elements_; }
83  bool operator!=(const Matrix &other) const { return !(*this == other); }
84 
85  NextLayout operator[](size_t idx) { return NextLayout(idx, elements_); }
86  const NextLayout operator[](size_t idx) const { return NextLayout(idx, elements_); }
87 
90  auto begin() const noexcept { return Iterator(elements_.cbegin()); }
91 
94  auto end() const noexcept { return Iterator(elements_.cend()); }
95 
98  size_t size() const noexcept { return elements_.size(); }
99 
101  void clear() noexcept { elements_.clear(); }
102 };
103 
104 // ****************************
105 // * Struct Matrix::TupleHash *
106 // ****************************
107 // Boost for combining hash values
108 // https://www.boost.org/doc/libs/1_38_0/doc/html/hash/reference.html#boost.hash_combine
109 template <typename T, T DefaultValue, size_t Dimension>
110 class Matrix<T, DefaultValue, Dimension>::TupleHash {
111  inline size_t get_hash(size_t &seed, size_t value) const {
112  return std::hash<size_t>()(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
113  }
114 
115  template <std::size_t... Indices>
116  void combine_hash(size_t &seed, const TupleKey &tuple, std::index_sequence<Indices...>) const {
117  using swallow = size_t[];
118  (void)swallow{(seed ^= get_hash(seed, std::get<Indices>(tuple)))...};
119  }
120 
121  public:
122  size_t operator()(const TupleKey &tuple) const {
123  size_t seed = 0;
124  combine_hash(seed, tuple, std::make_index_sequence<Dimension>{});
125 
126  return seed;
127  }
128 };
129 
130 // **************************
131 // * Class Matrix::Iterator *
132 // **************************
133 template <typename T, T DefaultValue, size_t Dimension>
134 class Matrix<T, DefaultValue, Dimension>::Iterator {
135  using MapIteratorType = typename Contanter::const_iterator;
136  MapIteratorType map_iterator_;
137 
138  inline auto get_value() const {
139  return std::tuple_cat((*map_iterator_).first, std::tie((*map_iterator_).second));
140  }
141 
142  public:
143  using value_type =
144  decltype(std::tuple_cat((*map_iterator_).first, std::tie((*map_iterator_).second)));
145  using iterator_category = std::input_iterator_tag;
146 
147  explicit Iterator(MapIteratorType map_iterator) : map_iterator_(map_iterator) {}
148 
150  map_iterator_++;
151  return *this;
152  }
154  Iterator retval = *this;
155  ++(*this);
156  return retval;
157  }
158  bool operator==(Iterator other) const { return map_iterator_ == other.map_iterator_; }
159  bool operator!=(Iterator other) const { return !(*this == other); }
160 
161  value_type operator*() const { return get_value(); }
162 };
163 
164 // ************************
165 // * Class Matrix::Layout *
166 // ************************
167 template <typename T, T DefaultValue, size_t Dimension>
168 template <size_t N, typename... Types>
169 class Matrix<T, DefaultValue, Dimension>::Layout {
170  using NextLayout = Layout<N - 1, Types..., size_t>;
171 
172  const Matrix::Contanter &elements_;
173  std::tuple<Types...> tuple_;
174 
175  public:
176  Layout(std::tuple<Types...> tuple, const Matrix::Contanter &elements)
177  : elements_{elements}, tuple_{tuple} {}
178 
179  NextLayout operator[](size_t idx) {
180  return NextLayout(std::tuple_cat(tuple_, std::tie(idx)), elements_);
181  }
182  const NextLayout operator[](size_t idx) const {
183  return NextLayout(std::tuple_cat(tuple_, std::tie(idx)), elements_);
184  }
185 };
186 
187 // *************************************
188 // * Class Matrix::Layout<0, Types...> *
189 // *************************************
190 template <typename T, T DefaultValue, size_t Dimension>
191 template <typename... Types>
192 class Matrix<T, DefaultValue, Dimension>::Layout<0, Types...> {
193  std::tuple<Types...> tuple_;
194  const Matrix::Contanter &elements_;
195  const T default_{DefaultValue};
196 
197  public:
198  Layout(std::tuple<Types...> tuple, const Matrix::Contanter &elements)
199  : tuple_{tuple}, elements_{elements} {}
200 
201  auto &operator=(const T &value) { // NOLINT
202  if (value != DefaultValue) {
203  const_cast<Matrix::Contanter &>(elements_)[tuple_] = value;
204  } else {
205  auto iter = elements_.find(tuple_);
206  if (iter != elements_.cend()) {
207  const_cast<Matrix::Contanter &>(elements_).erase(iter);
208  }
209  }
210  return *this;
211  }
212 
213  operator const T &() const noexcept { // NOLINT
214  auto iter = elements_.find(tuple_);
215  return (iter != elements_.cend()) ? iter->second : default_;
216  }
217 };
218 
219 } // namespace otus
220 
221 #endif // OTUS_MATRIX_HPP
bool operator!=(Iterator other) const
Definition: matrix.hpp:159
Matrix(Matrix &&other) noexcept
Definition: matrix.hpp:64
Matrix & operator=(Matrix &&other) noexcept
Definition: matrix.hpp:77
decltype(std::tuple_cat((*map_iterator_).first, std::tie((*map_iterator_).second))) value_type
Definition: matrix.hpp:144
Matrix(std::initializer_list< std::pair< const TupleKey, T >> list)
Definition: matrix.hpp:66
auto end() const noexcept
Definition: matrix.hpp:94
auto begin() const noexcept
Definition: matrix.hpp:90
Matrix & operator=(const Matrix &other)
Definition: matrix.hpp:73
std::input_iterator_tag iterator_category
Definition: matrix.hpp:145
Class of The multi-dimensional sparse matrix.
Definition: matrix.hpp:28
Iterator operator++(int)
Definition: matrix.hpp:153
Definition: matrix.hpp:134
value_type operator*() const
Definition: matrix.hpp:161
bool operator!=(const Matrix &other) const
Definition: matrix.hpp:83
size_t operator()(const TupleKey &tuple) const
Definition: matrix.hpp:122
Iterator(MapIteratorType map_iterator)
Definition: matrix.hpp:147
void clear() noexcept
Clears the mapped matrix.
Definition: matrix.hpp:101
Layout(std::tuple< Types...> tuple, const Matrix::Contanter &elements)
Definition: matrix.hpp:198
NextLayout operator[](size_t idx)
Definition: matrix.hpp:85
size_t size() const noexcept
Definition: matrix.hpp:98
const NextLayout operator[](size_t idx) const
Definition: matrix.hpp:86
Definition: matrix.hpp:110
Iterator & operator++()
Definition: matrix.hpp:149
Matrix()=default
auto & operator=(const T &value)
Definition: matrix.hpp:201
bool operator==(Iterator other) const
Definition: matrix.hpp:158
bool operator==(const Matrix &other) const
Definition: matrix.hpp:82
~Matrix()=default
Matrix(const Matrix &other) noexcept
Definition: matrix.hpp:63