C++ Library Extensions 2022.12.09
To help learn modern C++ programming
tpf_matrix.hpp
Go to the documentation of this file.
1
12#ifndef _TPF_MATRIX_HPP
13#define _TPF_MATRIX_HPP
14
15#ifndef NOMINMAX
16#define NOMINMAX
17#endif
18
19#ifdef _MSVC_LANG
20 #if _MSVC_LANG < 201703L
21 #error This libary requires C++17 Standard (Visual Studio 2017).
22 #endif
23#else
24
25 #if __cplusplus < 201703
26 #error This library requires C++17 Standard (GNU g++ version 8.0 or clang++ version 8.0 above)
27 #endif // end of __cplusplus
28
29#endif // end of _MSVC_LANG
30
31#include <type_traits>
32#include <string>
33#include <cstring>
34#include <cstdlib>
35
40namespace tpf
41{
46 namespace matrix
47 {
48 template<typename ElementType>
50 {
51 public:
52 using iterator = ElementType*;
53
54 // don't do this
55 // using const_iterator = const iterator;
56 // it will define ElementType* const, it is wrong
57
58 using const_iterator = const ElementType*;
59
60 private:
61 size_t m_size;
62 ElementType *m_ptr;
63
64 void free_memory()
65 {
66 if (m_ptr)
67 {
68 if constexpr (std::is_pod_v<ElementType>)
69 _aligned_free(this->m_ptr);
70 else
71 delete[] this-> m_ptr;
72
73 this->m_ptr = nullptr;
74 }
75 }
76
77 void invalidate()
78 {
79 this->m_ptr = nullptr;
80 }
81
82 ElementType* new_alloc()
83 {
84 ElementType* ptr;
85
86 if constexpr(std::is_pod_v<ElementType>)
87 {
88 ptr = (ElementType*) _aligned_malloc( sizeof(ElementType) * this->m_size, 16);
89 }
90 else
91 {
92 try
93 {
94 ptr = new ElementType[this->m_size];
95 }
96 catch(const std::bad_alloc&)
97 {
98 ptr = nullptr;
99 }
100 }
101
102 return ptr;
103 }
104
105 public:
106
107 // the pointer pointing to the first element
109 {
110 // return this->m_ptr;
111 return this->m_ptr;
112 }
113
114 // the pointer pointing to the element after the last element
116 {
117 return (this->m_ptr + this->m_size);
118 }
119
121 {
122 // we actually do NOT need the cast,
123 // but I want to make the syntax clear
124 return static_cast<const_iterator>(this->m_ptr);
125 }
126
128 {
129 // we actually do NOT need the cast,
130 // but I want to make the syntax clear
131 return static_cast<const_iterator>(this->m_ptr + this->m_size);
132 }
133
134 auto rbegin()
135 {
136 return std::reverse_iterator(end());
137 }
138
139 auto rend()
140 {
141 return std::reverse_iterator(begin());
142 }
143
144 auto crbegin()
145 {
146 return std::reverse_iterator(cend());
147 }
148
149 auto crend()
150 {
151 return std::reverse_iterator(cbegin());
152 }
153
154 size_t size() const { return this->m_size; }
155
156 // we assume count is greater than zero
157 void resize(size_t count)
158 {
159 if(count == this->m_size)
160 return;
161 else
162 {
163 // free existing memory
164 this->free_memory();
165 this->m_size = count;
166 this->m_ptr = new_alloc();
167
168 if(!this->m_ptr)
169 Tpf_ThrowDebugException("Dynamic Allocation Failed");
170 }
171 }
172
173 // this is dangerous practice
174 // if dynamic allocation fails,
175 // this constructor throws std::bad_alloc exception
176 explicit dynamic_array(size_t size = 1)
177 : m_size{size}
178 {
179 this->m_ptr = new_alloc();
180
181 if(!this->m_ptr)
182 Tpf_ThrowDebugException("Dynamic Allocation Failed");
183 }
184
185 // if dynamic allocation fails,
186 // it throws exception
187 dynamic_array(const dynamic_array &right_hand_side) :
188 m_size{right_hand_side.m_size}
189 {
190 this->m_ptr = new_alloc();
191
192 if(!this->m_ptr)
193 Tpf_ThrowDebugException("Dynamic Allocation Failed");
194
195 if constexpr(std::is_pod_v<ElementType>)
196 std::memcpy(this->m_ptr, right_hand_side.m_ptr, m_size * sizeof(ElementType));
197 else
198 {
199 for(size_t i = 0; i < this->m_size; ++i)
200 this->m_ptr[i] = right_hand_side.m_ptr[i];
201 }
202 }
203
204 ElementType *operator&() { return this->m_ptr; }
205
206 ElementType &operator[](size_t index) { return this->m_ptr[index]; }
207
208 const ElementType &operator[](size_t index) const { return this->m_ptr[index]; }
209
210 ElementType &at(size_t index)
211 {
212 if (index < this->m_size && this->m_ptr)
213 return this->m_ptr[index];
214 else
215 Tpf_ThrowDebugException("Index Out of Range");
216 }
217
218 const ElementType &at(size_t index) const
219 {
220 if (index < this->m_size && this->m_ptr)
221 return this->m_ptr[index];
222 else
223 Tpf_ThrowDebugException("Index Out of Range");
224 }
225
226 // if allocation fails,
227 // it can throw std::bad_alloc exception
228 dynamic_array &operator=(const dynamic_array &right_hand_side)
229 {
230 // this code is wrong, because address of operator&()
231 // is defined for class dynamic_array,
232 // so, we cannot use the following code any longer
233 // if(this != &right_hand_side)
234
235 if (this != std::addressof(right_hand_side))
236 {
237 if (this->m_size == right_hand_side.m_size)
238 {
239 // we do not need to reallocate memory
240 // and also, we do not need to free memory
241 // this->free_memory()
242
243 if constexpr(std::is_pod_v<ElementType>)
244 std::memcpy(this->m_ptr, right_hand_side.m_ptr, m_size * sizeof(ElementType));
245 else
246 {
247 for(size_t i = 0; i < this->m_size; ++i)
248 this->m_ptr[i] = right_hand_side.m_ptr[i];
249 }
250 }
251 else
252 {
253 // we have free existing memory
254 this->free_memory();
255 this->m_size = right_hand_side.m_size;
256
257 this->m_ptr = new_alloc();
258
259 if(!this->m_ptr)
260 Tpf_ThrowDebugException("Dynamic Allocation Failed");
261
262 if constexpr(std::is_pod_v<ElementType>)
263 std::memcpy(this->m_ptr, right_hand_side.m_ptr, m_size * sizeof(ElementType));
264 else
265 {
266 for(size_t i = 0; i < this->m_size; ++i)
267 this->m_ptr[i] = right_hand_side.m_ptr[i];
268 }
269 }
270 }
271
272 return *this;
273 }
274
275 dynamic_array(dynamic_array &&right_hand_side) noexcept
276 : m_size{right_hand_side.m_size},
277 m_ptr{right_hand_side.m_ptr}
278 {
279 // IMPORTANT: invalidate right_hand_side
280 // after move, right_hand_side is invalide
281 // so, we should NOT access to right_hand_side after move operation
282 right_hand_side.invalidate();
283 }
284
285 dynamic_array &operator=(dynamic_array &&right_hand_side) noexcept
286 {
287 if (this != std::addressof(right_hand_side))
288 {
289 // delete existing memory
290 this->free_memory();
291 this->m_size = right_hand_side.m_size;
292 this->m_ptr = right_hand_side.m_ptr;
293
294 // IMPORTANT: invalidate right_hand_size after move assignment
295 // since after move operation, right_hand_side is invalid
296 // so, we should NOT access to right_hand_side after move operation
297 right_hand_side.invalidate();
298 }
299
300 return *this;
301 }
302
304 {
305 this->free_memory();
306 }
307
308 friend std::ostream& operator<<(std::ostream& os, const dynamic_array& da)
309 {
310 size_t size = da.size() - 1;
311 os << "{ ";
312
313 for(size_t i = 0; i < size; ++i)
314 os << da[i] << ", ";
315
316 os << da[size] << " }";
317
318 return os;
319 }
320
321 }; // end of class dynamic_array
322
323 } // end of namespace matrix
324
325} // end of namespace tpf
326
327#endif // end of file _TPF_MATRIX_HPP
std::atomic< int > count
Definition: 022-mutex.cpp:10
const ElementType & at(size_t index) const
Definition: tpf_matrix.hpp:218
ElementType & operator[](size_t index)
Definition: tpf_matrix.hpp:206
ElementType & at(size_t index)
Definition: tpf_matrix.hpp:210
ElementType * operator&()
Definition: tpf_matrix.hpp:204
dynamic_array & operator=(const dynamic_array &right_hand_side)
Definition: tpf_matrix.hpp:228
const ElementType * const_iterator
Definition: tpf_matrix.hpp:58
void resize(size_t count)
Definition: tpf_matrix.hpp:157
const_iterator cbegin()
Definition: tpf_matrix.hpp:120
dynamic_array & operator=(dynamic_array &&right_hand_side) noexcept
Definition: tpf_matrix.hpp:285
dynamic_array(const dynamic_array &right_hand_side)
Definition: tpf_matrix.hpp:187
friend std::ostream & operator<<(std::ostream &os, const dynamic_array &da)
Definition: tpf_matrix.hpp:308
dynamic_array(dynamic_array &&right_hand_side) noexcept
Definition: tpf_matrix.hpp:275
const ElementType & operator[](size_t index) const
Definition: tpf_matrix.hpp:208
dynamic_array(size_t size=1)
Definition: tpf_matrix.hpp:176
Includes subnamespace conversion.
Definition: 31-visit.cpp:7
#define Tpf_ThrowDebugException(debug_message)
Throw a debug_exception with message as argument.
Definition: tpf_types.hpp:1416