CuteHMI - Modbus (CuteHMI.Modbus.2)
DataContainer.hpp
1 #ifndef H_EXTENSIONS_CUTEHMI_MODBUS_2_INCLUDE_CUTEHMI_MODBUS_INTERNAL_DATACONTAINER_HPP
2 #define H_EXTENSIONS_CUTEHMI_MODBUS_2_INCLUDE_CUTEHMI_MODBUS_INTERNAL_DATACONTAINER_HPP
3 
4 #include "common.hpp"
5 
6 #include <QLinkedList>
7 #include <QReadWriteLock>
8 
9 #include <array>
10 #include <algorithm>
11 #include <memory>
12 
13 namespace cutehmi {
14 namespace modbus {
15 namespace internal {
16 
20 template <typename T, std::size_t N = 65536>
22 {
24  friend class KeysIterator;
25 
26  public:
27  typedef T value_type;
28  typedef T & reference;
29  typedef const T & const_reference;
30  typedef T * pointer;
31  typedef const T * const_pointer;
32  // <Qt-Qt_5_11_2_Reference_Documentation-Qt_Core-Container_Classes-The_Container_Classes-QLinkedList_iterator_semantics.principle>
33  // "Iterators pointing to an item in a QLinkedList remain valid as long as the item exists, whereas iterators to a QList can
34  // become invalid after any insertion or removal."
36  // </Qt-Qt_5_11_2_Reference_Documentation-Qt_Core-Container_Classes-The_Container_Classes-QLinkedList_iterator_semantics.principle>
37 
38  static constexpr std::size_t ADDRESS_SPACE = N;
39 
45  {
46  public:
47  KeysIterator(const DataContainer<T, N> * container);
48 
49  bool hasNext() const;
50 
52 
54 
55  private:
56  mutable QReadWriteLock * m_lock;
58  };
59 
60  DataContainer();
61 
68  constexpr std::size_t size() const noexcept;
69 
79  const T * at(std::size_t i) const;
80 
90  T * at(std::size_t i);
91 
103  T * value(std::size_t i);
104 
114  void insert(std::size_t i, T * value);
115 
123  void clear();
124 
132  void free();
133 
140  const KeysContainer & keys() const;
141 
142  protected:
143  QReadWriteLock & lock() const;
144 
145  void insertKey(std::size_t i);
146 
150 };
151 
152 template <typename T, std::size_t N>
153 DataContainer<T, N>::KeysIterator::KeysIterator(const DataContainer<T, N> * container):
154  m_lock(& container->lock()),
155  m_it(container->keys())
156 {
157 }
158 
159 template <typename T, std::size_t N>
161 {
162  QReadLocker locker(m_lock);
163 
164  return m_it.hasNext();
165 }
166 
167 template <typename T, std::size_t N>
169 {
170  QReadLocker locker(m_lock);
171 
172  return m_it.next();
173 }
174 
175 template <typename T, std::size_t N>
177 {
178  QReadLocker locker(m_lock);
179 
180  return m_it.previous();
181 }
182 
183 template <typename T, std::size_t N>
184 
186  m_array()
187 {
188 }
189 
190 template <typename T, std::size_t N>
191 constexpr 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 
200 template <typename T, std::size_t N>
202 {
203  QReadLocker locker(& m_lock);
204 
205  return m_array.at(i);
206 }
207 
208 template <typename T, std::size_t N>
210 {
211  QReadLocker locker(& m_lock);
212 
213  return m_array.at(i);
214 }
215 
216 template <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 
243 template <typename T, std::size_t N>
245 {
246  QWriteLocker locker(& m_lock);
247 
248  m_array[i] = value;
249  insertKey(i);
250 }
251 
252 template <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 
262 template <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 
275 template <typename T, std::size_t N>
277 {
278  return m_keys;
279 }
280 
281 template <typename T, std::size_t N>
283 {
284  return m_lock;
285 }
286 
287 template <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 © 2019-2020, Michał Policht <michal@policht.pl>. All rights reserved.
308 //(c)C: This file is a part of CuteHMI.
309 //(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.
310 //(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.
311 //(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/>.
cutehmi::modbus::internal::DataContainer::lock
QReadWriteLock & lock() const
Definition: DataContainer.hpp:282
cutehmi::modbus::internal::DataContainer::KeysIterator::hasNext
bool hasNext() const
Definition: DataContainer.hpp:160
cutehmi::modbus::internal::DataContainer::size
constexpr std::size_t size() const noexcept
Get container size.
Definition: DataContainer.hpp:191
cutehmi::modbus::internal::DataContainer::const_pointer
const typedef T * const_pointer
Definition: DataContainer.hpp:31
cutehmi::modbus::internal::DataContainer::KeysIterator::previous
KeysContainer::value_type previous()
Definition: DataContainer.hpp:176
cutehmi::modbus::internal::DataContainer::insertKey
void insertKey(std::size_t i)
Definition: DataContainer.hpp:288
cutehmi::modbus::internal::DataContainer::free
void free()
Delete container contents.
Definition: DataContainer.hpp:263
cutehmi::modbus::internal::DataContainer::KeysIterator::KeysIterator
KeysIterator(const DataContainer< T, N > *container)
Definition: DataContainer.hpp:153
cutehmi::modbus::internal::DataContainer::KeysIterator::next
KeysContainer::value_type next()
Definition: DataContainer.hpp:168
std::fill
T fill(T... args)
cutehmi::modbus::internal::DataContainer::KeysContainer
QLinkedList< std::size_t > KeysContainer
Definition: DataContainer.hpp:35
QReadLocker
cutehmi::modbus::internal::DataContainer::m_lock
QReadWriteLock m_lock
Definition: DataContainer.hpp:149
QLinkedList< std::size_t >
cutehmi
cutehmi::modbus::internal::DataContainer::DataContainer
DataContainer()
Definition: DataContainer.hpp:185
QLinkedList::const_iterator
cutehmi::modbus::internal::DataContainer::KeysIterator
Keys iterator.
Definition: DataContainer.hpp:44
cutehmi::modbus::internal::DataContainer::const_reference
const typedef T & const_reference
Definition: DataContainer.hpp:29
std::array
cutehmi::modbus::internal::DataContainer::clear
void clear()
Clear container.
Definition: DataContainer.hpp:253
QLinkedList::iterator
cutehmi::modbus::internal::DataContainer::ADDRESS_SPACE
static constexpr std::size_t ADDRESS_SPACE
Definition: DataContainer.hpp:38
cutehmi::modbus::internal::DataContainer::m_array
InternalContainer m_array
Definition: DataContainer.hpp:147
cutehmi::modbus::internal::DataContainer::insert
void insert(std::size_t i, T *value)
Insert value.
Definition: DataContainer.hpp:244
std::internal
T internal(T... args)
std
QLinkedList::value_type
typedef value_type
QWriteLocker
cutehmi::modbus::internal::DataContainer::value_type
T value_type
Definition: DataContainer.hpp:27
QLinkedListIterator< KeysContainer::value_type >
cutehmi::modbus::internal::DataContainer::at
const T * at(std::size_t i) const
Get value at given index.
Definition: DataContainer.hpp:201
cutehmi::modbus::internal::DataContainer::keys
const KeysContainer & keys() const
Get keys container.
Definition: DataContainer.hpp:276
cutehmi::modbus::internal::DataContainer
Data container.
Definition: DataContainer.hpp:21
std::size_t
cutehmi::modbus::internal::DataContainer::m_keys
KeysContainer m_keys
Definition: DataContainer.hpp:148
QReadWriteLock
cutehmi::modbus::internal::DataContainer::pointer
T * pointer
Definition: DataContainer.hpp:30
cutehmi::modbus::internal::DataContainer::value
T * value(std::size_t i)
Get value at given index.
Definition: DataContainer.hpp:217
cutehmi::modbus::internal::DataContainer::reference
T & reference
Definition: DataContainer.hpp:28