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  private:
146  InternalContainer m_array;
147  KeysContainer m_keys;
148  mutable QReadWriteLock m_lock;
149 };
150 
151 template <typename T, std::size_t N>
152 DataContainer<T, N>::KeysIterator::KeysIterator(const DataContainer<T, N> * container):
153  m_lock(& container->lock()),
154  m_it(container->keys())
155 {
156 }
157 
158 template <typename T, std::size_t N>
160 {
161  QReadLocker locker(m_lock);
162 
163  return m_it.hasNext();
164 }
165 
166 template <typename T, std::size_t N>
168 {
169  QReadLocker locker(m_lock);
170 
171  return m_it.next();
172 }
173 
174 template <typename T, std::size_t N>
176 {
177  QReadLocker locker(m_lock);
178 
179  return m_it.previous();
180 }
181 
182 template <typename T, std::size_t N>
183 
185  m_array()
186 {
187 }
188 
189 template <typename T, std::size_t N>
190 constexpr std::size_t DataContainer<T, N>::size() const noexcept
191 {
192  // <cppreference.com-C++-Containers_library-Thread_safety-2.principle>
193  // "2. All const member functions can be called concurrently by different threads on the same container."
194  // -- https://en.cppreference.com/w/cpp/container
195  return m_array.size();
196  // </cppreference.com-C++-Containers_library-Thread_safety-2.principle>
197 }
198 
199 template <typename T, std::size_t N>
201 {
202  QReadLocker locker(& m_lock);
203 
204  return m_array.at(i);
205 }
206 
207 template <typename T, std::size_t N>
209 {
210  QReadLocker locker(& m_lock);
211 
212  return m_array.at(i);
213 }
214 
215 template <typename T, std::size_t N>
217 {
218  T * result;
219 
220  {
221  QReadLocker readLocker(& m_lock);
222 
223  result = m_array.at(i);
224  }
225 
226  if (result == nullptr) {
227  QWriteLocker writeLocker(& m_lock);
228 
229  // In a meanwhile value may have been created from another thread, so perform a lookup again - this time it is serialized by read-write locker.
230  result = m_array.at(i);
231 
232  if (result == nullptr) {
233  result = new T;
234  m_array[i] = result;
235  m_keys.append(i);
236  }
237  }
238 
239  return result;
240 }
241 
242 template <typename T, std::size_t N>
244 {
245  QWriteLocker locker(& m_lock);
246 
247  m_array[i] = value;
248  m_keys.append(i);
249 }
250 
251 template <typename T, std::size_t N>
253 {
254  QWriteLocker locker(& m_lock);
255 
256  m_keys.clear();
257 
258  std::fill(m_array.begin(), m_array.end(), nullptr);
259 }
260 
261 template <typename T, std::size_t N>
263 {
264  QWriteLocker locker(& m_lock);
265 
266  for (typename DataContainer<T, N>::KeysContainer::const_iterator it = keys().begin(); it != keys().end(); ++it)
267  delete m_array.at(*it);
268 
269  m_keys.clear();
270 
271  std::fill(m_array.begin(), m_array.end(), nullptr);
272 }
273 
274 template <typename T, std::size_t N>
276 {
277  return m_keys;
278 }
279 
280 template <typename T, std::size_t N>
282 {
283  return m_lock;
284 }
285 
286 }
287 }
288 }
289 
290 #endif
291 
292 //(c)C: Copyright © 2019, Michał Policht <michal@policht.pl>. All rights reserved.
293 //(c)C: This file is a part of CuteHMI.
294 //(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.
295 //(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.
296 //(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:281
cutehmi::modbus::internal::DataContainer::KeysIterator::hasNext
bool hasNext() const
Definition: DataContainer.hpp:159
cutehmi::modbus::internal::DataContainer::size
constexpr std::size_t size() const noexcept
Get container size.
Definition: DataContainer.hpp:190
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:175
cutehmi::modbus::internal::DataContainer::free
void free()
Delete container contents.
Definition: DataContainer.hpp:262
cutehmi::modbus::internal::DataContainer::KeysIterator::KeysIterator
KeysIterator(const DataContainer< T, N > *container)
Definition: DataContainer.hpp:152
cutehmi::modbus::internal::DataContainer::KeysIterator::next
KeysContainer::value_type next()
Definition: DataContainer.hpp:167
std::fill
T fill(T... args)
cutehmi::modbus::internal::DataContainer::KeysContainer
QLinkedList< std::size_t > KeysContainer
Definition: DataContainer.hpp:35
QReadLocker
QLinkedList< std::size_t >
cutehmi
cutehmi::modbus::internal::DataContainer::DataContainer
DataContainer()
Definition: DataContainer.hpp:184
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:252
cutehmi::modbus::internal::DataContainer::ADDRESS_SPACE
static constexpr std::size_t ADDRESS_SPACE
Definition: DataContainer.hpp:38
cutehmi::modbus::internal::DataContainer::insert
void insert(std::size_t i, T *value)
Insert value.
Definition: DataContainer.hpp:243
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:200
cutehmi::modbus::internal::DataContainer::keys
const KeysContainer & keys() const
Get keys container.
Definition: DataContainer.hpp:275
cutehmi::modbus::internal::DataContainer
Data container.
Definition: DataContainer.hpp:21
std::size_t
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:216
cutehmi::modbus::internal::DataContainer::reference
T & reference
Definition: DataContainer.hpp:28