Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc.
3 : *
4 : * Author: Emmanuel Lepage <emmanuel.lepage@savoirfairelinux.com>
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 : */
20 : #pragma once
21 :
22 : #include "logger.h"
23 :
24 : #include <map>
25 : #include <type_traits>
26 : #include <vector>
27 : #include <cassert>
28 :
29 : namespace jami {
30 :
31 : /**
32 : * This function adds a safe way to get an enum class size
33 : */
34 : template<typename A>
35 : constexpr inline size_t
36 504 : enum_class_size()
37 : {
38 504 : return size_t(A::COUNT__);
39 : }
40 :
41 : /**
42 : * This generic class represents a multidimensional enum class array.
43 : * It safely converts them to integers. Each enum class needs a "COUNT__" item
44 : * at the end."
45 : *
46 : * This struct enforces:
47 : * * That the rows are indexed using enum_classes
48 : * * That the size of the matrix matches the enum_class size
49 : * * That the operators are within the matrix boundary
50 : */
51 : template<class Row, typename Value, typename A = Value>
52 : struct Matrix1D
53 : {
54 : Matrix1D(std::initializer_list<std::initializer_list<Value>> s);
55 :
56 : // Row is a built-in type ("int" by default)
57 : Value operator[](Row v);
58 :
59 : const Value operator[](Row v) const;
60 :
61 : /**
62 : * An Iterator for enum classes
63 : */
64 : class EnumClassIter
65 : {
66 : public:
67 : EnumClassIter(const Matrix1D<Row, Value, A>* p_vec, size_t pos)
68 : : pos_(pos)
69 : , p_vec_(p_vec)
70 : {}
71 :
72 : bool operator!=(const EnumClassIter& other) const;
73 : Row operator*() const;
74 : const EnumClassIter& operator++();
75 :
76 : private:
77 : size_t pos_;
78 : const Matrix1D<Row, Value, A>* p_vec_;
79 : };
80 :
81 : // Iterators
82 : EnumClassIter begin();
83 : EnumClassIter end();
84 :
85 : // Only use for single reverse mappable arrays, will ASSERT otherwise
86 : Row fromValue(const Value& value) const;
87 :
88 : static void setReverseMapping(Matrix1D<Row, const char*> names);
89 :
90 : private:
91 : const std::vector<Value> data_;
92 : static std::map<A, Row> reverseMapping_;
93 : };
94 :
95 : /**
96 : * A matrix with no value
97 : *
98 : * This is useful to use enum class in C++11 foreach loops
99 : *
100 : * @usage
101 : * for (const MyEnum& value : Matrix0D<MyEnum>()) {
102 : * std::cout << "Name: " << MyEnumNames[value] << std::endl;
103 : * }
104 : */
105 : template<class EnumClass>
106 : struct Matrix0D
107 : {
108 : /**
109 : * An Iterator for enum classes
110 : */
111 : class EnumClassIter
112 : {
113 : public:
114 0 : EnumClassIter(const Matrix0D<EnumClass>* p_vec, size_t pos)
115 0 : : pos_(pos)
116 0 : , p_vec_(p_vec)
117 0 : {}
118 :
119 : bool operator!=(const EnumClassIter& other) const;
120 : EnumClass operator*() const;
121 : const EnumClassIter& operator++();
122 :
123 : private:
124 : size_t pos_;
125 : const Matrix0D<EnumClass>* p_vec_;
126 : };
127 :
128 : Matrix0D();
129 :
130 : // Iterators
131 : EnumClassIter begin();
132 : EnumClassIter end();
133 : };
134 :
135 : /**
136 : * A helper to type to match serializable string to enum elements
137 : */
138 : template<class Row>
139 : using EnumClassNames = Matrix1D<Row, const char*>;
140 :
141 : /**
142 : * Create a matrix type with 2 enum class dimensions M[I,J] = V
143 : * ^ ^ ^
144 : * | | |
145 : * Rows <--- | |
146 : * Columns <----- |
147 : * Value <----------
148 : */
149 : template<class Row, class Column, typename Value>
150 : using Matrix2D = Matrix1D<Row, Matrix1D<Column, Value>>;
151 :
152 : /**
153 : * Create an array of callbacks.
154 : *
155 : * This type hides all the C++ syntax requirements
156 : */
157 : template<class Row, class Class, typename Result = void, typename... Args>
158 : using CallbackMatrix1D = Matrix1D<Row, Result (Class::*)(Args... args)>;
159 :
160 : /**
161 : * Create a method callback matrix.
162 : *
163 : * This type hides all the C++ syntax requirements
164 : */
165 : template<class Row, class Column, class Class, typename Result = void, typename... Args>
166 : using CallbackMatrix2D = Matrix2D<Row, Column, void (Class::*)(Args... args)>;
167 :
168 : /*
169 : * IMPLEMENTATION
170 : *
171 : */
172 :
173 : template<class Row, typename Value, typename Accessor>
174 504 : Matrix1D<Row, Value, Accessor>::Matrix1D(std::initializer_list<std::initializer_list<Value>> s)
175 504 : : data_(*std::begin(s))
176 : {
177 : static_assert(std::is_enum<Row>(), "Row has to be an enum class");
178 : static_assert((int) Row::COUNT__ > 0, "Row need a COUNT__ element");
179 :
180 : // FIXME C++14, use static_assert and make the ctor constexpr
181 504 : assert(std::begin(s)->size()
182 : == enum_class_size<Row>()); //,"Matrix row have to match the enum class size");
183 504 : }
184 :
185 : template<class Row, typename Value, typename Accessor>
186 : Value Matrix1D<Row, Value, Accessor>::operator[](Row v)
187 : {
188 : // ASSERT(size_t(v) >= size_t(Row::COUNT__),"State Machine Out of Bounds\n");
189 : if (size_t(v) >= enum_class_size<Row>() || static_cast<int>(v) < 0) {
190 : JAMI_ERR("State Machine Out of Bounds %d\n", size_t(v));
191 : assert(false);
192 : throw v;
193 : }
194 : return data_[size_t(v)];
195 : }
196 :
197 : template<class Row, typename Value, typename Accessor>
198 0 : const Value Matrix1D<Row, Value, Accessor>::operator[](Row v) const
199 : {
200 0 : assert(size_t(v) <= enum_class_size<Row>() + 1 && size_t(v) >= 0); // COUNT__ is also valid
201 0 : if (size_t(v) >= enum_class_size<Row>()) {
202 0 : JAMI_ERR("State Machine Out of Bounds %zu\n", size_t(v));
203 0 : assert(false);
204 : throw v;
205 : }
206 0 : return data_[size_t(v)];
207 : }
208 :
209 : template<class E, class T, class A>
210 : std::map<A, E> Matrix1D<E, T, A>::reverseMapping_;
211 :
212 : template<class Row, typename Value, typename Accessor>
213 : void
214 : Matrix1D<Row, Value, Accessor>::setReverseMapping(Matrix1D<Row, const char*> names)
215 : {
216 : for (const Row row : Matrix0D<Row>())
217 : reverseMapping_[names[row]] = row;
218 : }
219 :
220 : template<class Row, typename Value, typename Accessor>
221 : Row
222 : Matrix1D<Row, Value, Accessor>::fromValue(const Value& value) const
223 : {
224 : if (!reverseMapping_.empty()) {
225 : for (int i = 0; i < enum_class_size<Row>(); i++) {
226 : const_cast<Matrix1D*>(this)->reverseMapping_[(*const_cast<Matrix1D*>(this))[(Row) i]]
227 : = static_cast<Row>(i);
228 : }
229 : assert(reverseMapping_.empty() == enum_class_size<Row>());
230 : }
231 : if (reverseMapping_.count(value) == 0) {
232 : throw value;
233 : }
234 : return reverseMapping_[value];
235 : }
236 :
237 : template<class EnumClass>
238 0 : Matrix0D<EnumClass>::Matrix0D()
239 : {
240 : static_assert(std::is_enum<EnumClass>(),
241 : "The first template parameter has to be an enum class\n");
242 0 : }
243 :
244 : template<class EnumClass>
245 0 : EnumClass Matrix0D<EnumClass>::EnumClassIter::operator*() const
246 : {
247 0 : assert(pos_ < enum_class_size<EnumClass>());
248 0 : return static_cast<EnumClass>(pos_);
249 : }
250 :
251 : template<class EnumClass>
252 : const typename Matrix0D<EnumClass>::EnumClassIter&
253 0 : Matrix0D<EnumClass>::EnumClassIter::operator++()
254 : {
255 0 : ++pos_;
256 0 : return *this;
257 : }
258 :
259 : template<class EnumClass>
260 : bool
261 0 : Matrix0D<EnumClass>::EnumClassIter::operator!=(const EnumClassIter& other) const
262 : {
263 0 : return pos_ != other.pos_;
264 : }
265 :
266 : template<class EnumClass>
267 : typename Matrix0D<EnumClass>::EnumClassIter
268 0 : Matrix0D<EnumClass>::begin()
269 : {
270 0 : return Matrix0D<EnumClass>::EnumClassIter(this, 0);
271 : }
272 :
273 : template<class EnumClass>
274 : typename Matrix0D<EnumClass>::EnumClassIter
275 0 : Matrix0D<EnumClass>::end()
276 : {
277 0 : return Matrix0D<EnumClass>::EnumClassIter(this, enum_class_size<EnumClass>());
278 : }
279 :
280 : template<class Row, typename Value, typename Accessor>
281 : const typename Matrix1D<Row, Value, Accessor>::EnumClassIter&
282 : Matrix1D<Row, Value, Accessor>::EnumClassIter::operator++()
283 : {
284 : ++pos_;
285 : return *this;
286 : }
287 :
288 : template<class Row, typename Value, typename Accessor>
289 : bool
290 : Matrix1D<Row, Value, Accessor>::EnumClassIter::operator!=(const EnumClassIter& other) const
291 : {
292 : return pos_ != other.pos_;
293 : }
294 :
295 : template<class Row, typename Value, typename Accessor>
296 : typename Matrix1D<Row, Value, Accessor>::EnumClassIter
297 : Matrix1D<Row, Value, Accessor>::begin()
298 : {
299 : return Matrix1D<Row, Value, Accessor>::EnumClassIter(this, 0);
300 : }
301 :
302 : template<class Row, typename Value, typename Accessor>
303 : typename Matrix1D<Row, Value, Accessor>::EnumClassIter
304 : Matrix1D<Row, Value, Accessor>::end()
305 : {
306 : return Matrix1D<Row, Value, Accessor>::EnumClassIter(this, enum_class_size<Row>());
307 : }
308 :
309 : } // namespace jami
|