CuteHMI - Modbus (CuteHMI.Modbus.4)
DataContainer.hpp
1#ifndef H_EXTENSIONS_CUTEHMI_MODBUS_4_INCLUDE_CUTEHMI_MODBUS_INTERNAL_DATACONTAINER_HPP
2#define H_EXTENSIONS_CUTEHMI_MODBUS_4_INCLUDE_CUTEHMI_MODBUS_INTERNAL_DATACONTAINER_HPP
3
4#include <QReadWriteLock>
5
6#include <array>
7#include <algorithm>
8#include <memory>
9#include <list>
10
11namespace cutehmi {
12namespace modbus {
13namespace internal {
14
18template <typename T, std::size_t N = 65536>
20{
22 friend class KeysIterator;
23
24 public:
25 typedef T value_type;
26 typedef T & reference;
27 typedef const T & const_reference;
28 typedef T * pointer;
29 typedef const T * const_pointer;
30 // <Qt-Qt_5_11_2_Reference_Documentation-Qt_Core-Container_Classes-The_Container_Classes-QLinkedList_iterator_semantics.principle>
31 // "Iterators pointing to an item in a QLinkedList remain valid as long as the item exists, whereas iterators to a QList can
32 // become invalid after any insertion or removal."
34 // </Qt-Qt_5_11_2_Reference_Documentation-Qt_Core-Container_Classes-The_Container_Classes-QLinkedList_iterator_semantics.principle>
35
36 static constexpr std::size_t ADDRESS_SPACE = N;
37
43 {
44 public:
45 KeysIterator(const DataContainer<T, N> * container);
46
47 bool hasNext() const;
48
49 KeysContainer::value_type next();
50
51 KeysContainer::value_type previous();
52
53 private:
54 mutable QReadWriteLock * m_lock;
55 const KeysContainer * m_keysContainer;
56 KeysContainer::const_iterator m_it;
57 };
58
60
67 constexpr std::size_t size() const noexcept;
68
78 const T * at(std::size_t i) const;
79
89 T * at(std::size_t i);
90
102 T * value(std::size_t i);
103
113 void insert(std::size_t i, T * value);
114
122 void clear();
123
131 void free();
132
139 const KeysContainer & keys() const;
140
141 protected:
142 QReadWriteLock & lock() const;
143
144 void insertKey(std::size_t i);
145
149};
150
151template <typename T, std::size_t N>
152DataContainer<T, N>::KeysIterator::KeysIterator(const DataContainer<T, N> * container):
153 m_lock(& container->lock()),
154 m_keysContainer(& container->keys()),
155 m_it(container->keys().begin())
156{
157}
158
159template <typename T, std::size_t N>
161{
162 QReadLocker locker(m_lock);
163
164 return m_it != m_keysContainer->end();
165}
166
167template <typename T, std::size_t N>
169{
170 QReadLocker locker(m_lock);
171
172 return *(m_it)++;
173}
174
175template <typename T, std::size_t N>
177{
178 QReadLocker locker(m_lock);
179
180 return *(--m_it);
181}
182
183template <typename T, std::size_t N>
184
186 m_array()
187{
188}
189
190template <typename T, std::size_t N>
191constexpr std::size_t DataContainer<T, N>::size() const noexcept
192{
193 // <cppreference.com-C++-Containers_library-Thread_safety-2.principle>
194 // "2. All const member functions can be called concurrently by different threads on the same container."
195 // -- https://en.cppreference.com/w/cpp/container
196 return m_array.size();
197 // </cppreference.com-C++-Containers_library-Thread_safety-2.principle>
198}
199
200template <typename T, std::size_t N>
202{
203 QReadLocker locker(& m_lock);
204
205 return m_array.at(i);
206}
207
208template <typename T, std::size_t N>
210{
211 QReadLocker locker(& m_lock);
212
213 return m_array.at(i);
214}
215
216template <typename T, std::size_t N>
218{
219 T * result;
220
221 {
222 QReadLocker readLocker(& m_lock);
223
224 result = m_array.at(i);
225 }
226
227 if (result == nullptr) {
228 QWriteLocker writeLocker(& m_lock);
229
230 // In a meanwhile value may have been created from another thread, so perform a lookup again - this time it is serialized by write locker.
231 result = m_array.at(i);
232
233 if (result == nullptr) {
234 result = new T;
235 m_array[i] = result;
236 insertKey(i);
237 }
238 }
239
240 return result;
241}
242
243template <typename T, std::size_t N>
245{
246 QWriteLocker locker(& m_lock);
247
248 m_array[i] = value;
249 insertKey(i);
250}
251
252template <typename T, std::size_t N>
254{
255 QWriteLocker locker(& m_lock);
256
257 m_keys.clear();
258
259 std::fill(m_array.begin(), m_array.end(), nullptr);
260}
261
262template <typename T, std::size_t N>
264{
265 QWriteLocker locker(& m_lock);
266
267 for (typename DataContainer<T, N>::KeysContainer::const_iterator it = keys().begin(); it != keys().end(); ++it)
268 delete m_array.at(*it);
269
270 m_keys.clear();
271
272 std::fill(m_array.begin(), m_array.end(), nullptr);
273}
274
275template <typename T, std::size_t N>
277{
278 return m_keys;
279}
280
281template <typename T, std::size_t N>
283{
284 return m_lock;
285}
286
287template <typename T, std::size_t N>
289{
290 KeysContainer::iterator it = m_keys.begin();
291 while (it != m_keys.end()) {
292 if (*it < i)
293 ++it;
294 else
295 break;
296 }
297
298 m_keys.insert(it, i);
299}
300
301}
302}
303}
304
305#endif
306
307//(c)C: Copyright © 2022, Michał Policht <michal@policht.pl>. All rights reserved.
308//(c)C: SPDX-License-Identifier: LGPL-3.0-or-later OR MIT
309//(c)C: This file is a part of CuteHMI.
310//(c)C: CuteHMI is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
311//(c)C: CuteHMI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
312//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI. If not, see <https://www.gnu.org/licenses/>.
313//(c)C: Additionally, this file is licensed under terms of MIT license as expressed below.
314//(c)C: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
315//(c)C: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
316//(c)C: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Keys iterator.
Definition: DataContainer.hpp:43
KeysIterator(const DataContainer< T, N > *container)
Definition: DataContainer.hpp:152
KeysContainer::value_type next()
Definition: DataContainer.hpp:168
bool hasNext() const
Definition: DataContainer.hpp:160
KeysContainer::value_type previous()
Definition: DataContainer.hpp:176
Data container.
Definition: DataContainer.hpp:20
const T * at(std::size_t i) const
Get value at given index.
Definition: DataContainer.hpp:201
const T * const_pointer
Definition: DataContainer.hpp:29
static constexpr std::size_t ADDRESS_SPACE
Definition: DataContainer.hpp:36
T * value(std::size_t i)
Get value at given index.
Definition: DataContainer.hpp:217
void clear()
Clear container.
Definition: DataContainer.hpp:253
const KeysContainer & keys() const
Get keys container.
Definition: DataContainer.hpp:276
InternalContainer m_array
Definition: DataContainer.hpp:146
void insertKey(std::size_t i)
Definition: DataContainer.hpp:288
T * pointer
Definition: DataContainer.hpp:28
std::list< std::size_t > KeysContainer
Definition: DataContainer.hpp:33
KeysContainer m_keys
Definition: DataContainer.hpp:147
QReadWriteLock m_lock
Definition: DataContainer.hpp:148
const T & const_reference
Definition: DataContainer.hpp:27
DataContainer()
Definition: DataContainer.hpp:185
T & reference
Definition: DataContainer.hpp:26
void free()
Delete container contents.
Definition: DataContainer.hpp:263
void insert(std::size_t i, T *value)
Insert value.
Definition: DataContainer.hpp:244
QReadWriteLock & lock() const
Definition: DataContainer.hpp:282
T value_type
Definition: DataContainer.hpp:25
constexpr std::size_t size() const noexcept
Get container size.
Definition: DataContainer.hpp:191
T fill(T... args)
T internal(T... args)