swift
dictionary.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #ifndef SWIFT_MISC_DICTIONARY_H
7 #define SWIFT_MISC_DICTIONARY_H
8 
9 #include <algorithm>
10 #include <initializer_list>
11 #include <type_traits>
12 #include <utility>
13 
14 #include <QDBusArgument>
15 #include <QHash>
16 #include <QJsonArray>
17 #include <QJsonObject>
18 #include <QJsonValue>
19 #include <QJsonValueRef>
20 #include <QMap>
21 #include <QString>
22 #include <QtGlobal>
23 
24 #include "misc/containerbase.h"
25 #include "misc/iterator.h"
26 #include "misc/jsonexception.h"
28 #include "misc/mixin/mixindbus.h"
29 #include "misc/mixin/mixinjson.h"
30 #include "misc/mixin/mixinstring.h"
31 #include "misc/predicates.h"
32 #include "misc/range.h"
33 #include "misc/typetraits.h"
34 
35 namespace swift::misc
36 {
37  namespace private_ns
38  {
40  template <bool KeySupportsQHash /* = true */, bool KeySupportsQMap>
41  struct TAssociativityTraits
42  {
43  template <class Key, class Value>
44  using DefaultType = QHash<Key, Value>;
45  };
46  template <>
47  struct TAssociativityTraits<false, true>
48  {
49  template <class Key, class Value>
50  using DefaultType = QMap<Key, Value>;
51  };
52  template <>
53  struct TAssociativityTraits<false, false>
54  {
55  template <class Key, class>
56  struct DefaultType
57  {
58  static_assert(std::is_void_v<Key>, "Key does not support either QHash or QMap");
59  };
60  };
62  } // namespace private_ns
63 
67  template <typename K, typename V>
69  typename private_ns::TAssociativityTraits<TModelsQHashKey<K>::value,
70  TModelsQMapKey<K>::value>::template DefaultType<K, V>;
71 
75  template <class Key, class Value, template <class...> class Impl = TDefaultAssociativeType>
76  class CDictionary :
77  public mixin::DBusOperators<CDictionary<Key, Value, Impl>>,
78  public mixin::DataStreamOperators<CDictionary<Key, Value, Impl>>,
79  public mixin::JsonOperators<CDictionary<Key, Value, Impl>>,
80  public mixin::String<CDictionary<Key, Value, Impl>>
81  {
83  friend int compare(const CDictionary &a, const CDictionary &b)
84  {
85  if (a.m_impl.size() < b.m_impl.size()) { return -1; }
86  if (a.m_impl.size() > b.m_impl.size()) { return 1; }
87  return 0;
88  }
89 
90  public:
92  using impl_type = Impl<Key, Value>;
93 
95  typedef Key key_type;
96 
98  typedef Value value_type;
99 
101  typedef Value &reference;
102 
104  typedef const Value &const_reference;
105 
107  typedef typename Impl<Key, Value>::size_type size_type;
108 
110  typedef typename Impl<Key, Value>::iterator iterator;
111 
113  typedef typename Impl<Key, Value>::const_iterator const_iterator;
114 
117  template <class Predicate>
118  CDictionary findKeyBy(Predicate p) const
119  {
120  CDictionary result = *this;
121  for (auto it = result.begin(); it != result.end();)
122  {
123  if (!p(it.key())) { it = result.erase(it); }
124  else { ++it; }
125  }
126  return result;
127  }
128 
131  template <class... Pairs>
132  CDictionary findKeyBy(Pairs... pairs) const
133  {
135  }
136 
138  template <class Predicate>
139  CDictionary findValueBy(Predicate p) const
140  {
141  CDictionary result = *this;
142  for (auto it = result.begin(); it != result.end();)
143  {
144  if (!p(it.value())) { it = result.erase(it); }
145  else { ++it; }
146  }
147  return result;
148  }
149 
152  template <class... Pairs>
153  CDictionary findValueBy(Pairs... pairs) const
154  {
156  }
157 
159  template <class Predicate>
160  bool containsByKey(Predicate p) const
161  {
162  auto keys = m_impl.keys();
163  return std::any_of(keys.cbegin(), keys.cend(), p);
164  }
165 
167  template <class MembFunc, class ReturnValue>
168  bool containsByKey(MembFunc membFunc, ReturnValue returnValue) const
169  {
170  return containsByKey(swift::misc::predicates::MemberEqual(membFunc, returnValue));
171  }
172 
174  template <class Predicate>
175  bool containsByValue(Predicate p) const
176  {
177  return std::any_of(m_impl.cbegin(), m_impl.cend(), p);
178  }
179 
181  template <class MembFunc, class ReturnValue>
182  bool containsByValue(MembFunc membFunc, ReturnValue returnValue) const
183  {
184  return containsByValue(swift::misc::predicates::MemberEqual(membFunc, returnValue));
185  }
186 
188  template <class Predicate>
189  void removeByKeyIf(Predicate p)
190  {
191  for (auto it = m_impl.begin(); it != m_impl.end();)
192  {
193  if (p(it.key())) { it = m_impl.erase(it); }
194  else { ++it; }
195  }
196  }
197 
199  template <class Predicate>
200  void removeByValueIf(Predicate p)
201  {
202  for (auto it = m_impl.begin(); it != m_impl.end();)
203  {
204  if (p(it.value())) { it = m_impl.erase(it); }
205  else { ++it; }
206  }
207  }
208 
210  template <class MembFunc, class ReturnValue>
211  void removeByKeyIf(MembFunc membFunc, ReturnValue returnValue)
212  {
213  removeByKeyIf(swift::misc::predicates::MemberEqual(membFunc, returnValue));
214  }
215 
217  template <class MembFunc, class ReturnValue>
218  void removeByValueIf(MembFunc membFunc, ReturnValue returnValue)
219  {
221  }
222 
224  void removeDuplicates(const CDictionary &other)
225  {
226  for (auto it = begin(); it != end();)
227  {
228  auto it2 = other.find(it.key());
229  if (it2 != other.end() && it.value() == it2.value()) { it = erase(it); }
230  else { ++it; }
231  }
232  }
233 
236  {
237  QJsonArray array;
238  QJsonObject json;
239 
240  for (auto it = m_impl.cbegin(); it != m_impl.cend(); ++it) { array << it.key() << it.value(); }
241  json.insert("associativecontainerbase", array);
242  return json;
243  }
244 
246  void convertFromJson(const QJsonObject &json)
247  {
248  QJsonValue value = json.value("associativecontainerbase");
249  if (value.isUndefined()) { throw CJsonException("Missing 'associativecontainerbase'"); }
250  QJsonArray array = value.toArray();
251  int index = 0;
252  for (auto it = array.begin(); it != array.end(); ++it)
253  {
254  QJsonValueRef jsonKey = (*it);
255  ++it;
256  if (it == array.end())
257  {
258  qWarning("Odd number of elements in CDictionary::convertFromJson");
259  return;
260  }
261  QJsonValueRef jsonValue = (*it);
262  Key key;
263  Value val;
264  {
265  CJsonScope scope("associativecontainerbase", 2 * index);
266  Q_UNUSED(scope);
267  jsonKey >> key;
268  }
269  {
270  CJsonScope scope("associativecontainerbase", 2 * index++ + 1);
271  Q_UNUSED(scope);
272  jsonValue >> val;
273  }
274  m_impl.insert(std::move(key), std::move(val));
275  }
276  }
277 
280 
282  CDictionary(std::initializer_list<std::pair<Key, Value>> il) : m_impl(il) {}
283 
285  CDictionary(const CDictionary &) = default;
286 
288  CDictionary(CDictionary &&other) noexcept : m_impl(std::move(other.m_impl)) {}
289 
291  ~CDictionary() = default;
292 
294  iterator begin() { return m_impl.begin(); }
295 
297  const_iterator begin() const { return m_impl.begin(); }
298 
300  const_iterator cbegin() const { return m_impl.cbegin(); }
301 
303  iterator end() { return m_impl.end(); }
304 
306  const_iterator end() const { return m_impl.end(); }
307 
309  const_iterator cend() const { return m_impl.cend(); }
310 
312  auto keyBegin() const { return m_impl.keyBegin(); }
313 
315  auto keyEnd() const { return m_impl.keyEnd(); }
316 
318  auto keyValueBegin() { return m_impl.keyValueBegin(); }
319 
321  auto keyValueEnd() { return m_impl.keyValueEnd(); }
322 
324  auto keyValueBegin() const { return m_impl.keyValueBegin(); }
325 
327  auto constKeyValueBegin() const { return m_impl.constKeyValueBegin(); }
328 
330  auto keyValueEnd() const { return m_impl.keyValueEnd(); }
331 
333  auto constKeyValueEnd() const { return m_impl.constKeyValueEnd(); }
334 
336  void clear() { m_impl.clear(); }
337 
339  const_iterator constBegin() const { return m_impl.constBegin(); }
340 
342  const_iterator constEnd() const { return m_impl.constEnd(); }
343 
346  const_iterator constFind(const Key &key) const { return m_impl.constFind(key); }
347 
350  const_iterator find(const Key &key) const { return m_impl.find(key); }
351 
354  iterator find(const Key &key) { return m_impl.find(key); }
355 
357  bool contains(const Key &key) const { return m_impl.contains(key); }
358 
360  int count(const Key &key) const { return m_impl.count(key); }
361 
363  int count() const { return m_impl.count(); }
364 
366  bool empty() const { return m_impl.empty(); }
367 
369  iterator erase(iterator pos) { return m_impl.erase(pos); }
370 
372  iterator insert(const Key &key, const Value &value) { return m_impl.insert(key, value); }
373 
375  void insert(const CDictionary &other)
376  {
377  for (auto i = other.cbegin(); i != other.cend(); ++i) { insert(i.key(), i.value()); }
378  }
379 
381  bool isEmpty() const { return m_impl.isEmpty(); }
382 
384  const Key key(const Value &value) const { return m_impl.key(value); }
385 
387  const Key key(const Value &value, const Key &defaultKey) const { return m_impl.key(value, defaultKey); }
388 
390  auto keys() const { return makeRange(keyBegin(), keyEnd()); }
391 
393  int remove(const Key &key) { return m_impl.remove(key); }
394 
396  int size() const { return m_impl.size(); }
397 
399  void swap(CDictionary &other) noexcept { m_impl.swap(other.m_impl); }
400 
402  const Value value(const Key &key) const { return m_impl.value(key); }
403 
405  const Value value(const Key &key, const Value &defaultValue) const { return m_impl.value(key, defaultValue); }
406 
408  CRange<const_iterator> values() const { return makeRange(begin(), end()); }
409 
412  {
413  m_impl = other.m_impl;
414  return *this;
415  }
416 
418  CDictionary &operator=(CDictionary &&other) noexcept
419  {
420  m_impl = std::move(other.m_impl);
421  return *this;
422  }
423 
425  friend impl_type &implementationOf(CDictionary &dict) { return dict.m_impl; }
426 
428  friend const impl_type &implementationOf(const CDictionary &dict) { return dict.m_impl; }
429 
432  Value &operator[](const Key &key) { return m_impl[key]; }
433 
435  const Value operator[](const Key &key) const { return m_impl[key]; }
436 
438  friend bool operator==(const CDictionary &a, const CDictionary &b) { return a.m_impl == b.m_impl; }
439 
441  friend bool operator!=(const CDictionary &a, const CDictionary &b) { return !(a == b); }
442 
444  QString convertToQString(bool i18n = false) const
445  {
446  QString str;
447  for (auto it = m_impl.cbegin(); it != m_impl.end(); ++it)
448  {
449  str += "{";
450  str +=
451  CContainerHelper::stringify(it.key(), i18n) + "," + CContainerHelper::stringify(it.value(), i18n);
452  str += "}";
453  }
454  return "{" + str + "}";
455  }
456 
457  public:
459  void marshallToDbus(QDBusArgument &argument) const { argument << m_impl; }
460 
462  void unmarshallFromDbus(const QDBusArgument &argument) { argument >> m_impl; }
463 
465  void marshalToDataStream(QDataStream &stream) const { stream << m_impl; }
466 
468  void unmarshalFromDataStream(QDataStream &stream) { stream >> m_impl; }
469 
470  private:
471  Impl<Key, Value> m_impl;
472  };
473 
477  template <class Key, class Value>
479  {
480  return dict;
481  }
482 
486  template <class Key, class Value>
488  {
489  return dict;
490  }
491 
495  template <class Map1, class Map2, class F>
496  void forEachIntersection(const Map1 &map1, const Map2 &map2, F functor)
497  {
498  static_assert(std::is_same_v<typename Map1::key_type, typename Map2::key_type>,
499  "Maps must have the same key type");
500  if (map1.empty() || map2.empty()) { return; }
501  auto it1 = implementationOf(map1).lowerBound(map2.cbegin().key());
502  auto end1 = implementationOf(map1).upperBound((map2.cend() - 1).key());
503  auto it2 = implementationOf(map2).lowerBound(map1.cbegin().key());
504  auto end2 = implementationOf(map2).upperBound((map1.cend() - 1).key());
505  while (it1 != end1 && it2 != end2)
506  {
507  if (it1.key() < it2.key()) { ++it1; }
508  else if (it2.key() < it1.key()) { ++it2; }
509  else
510  {
511  functor(it1.key(), it1.value(), it2);
512  ++it1;
513  ++it2;
514  }
515  }
516  }
517 } // namespace swift::misc
518 
519 #endif // SWIFT_MISC_DICTIONARY_H
static QString stringify(const U &obj, bool i18n)
Stringify value object.
Definition: containerbase.h:30
Associative container with value semantics, chooses a sensible default implementation container type.
Definition: dictionary.h:81
int count(const Key &key) const
Returns the number of items with key.
Definition: dictionary.h:360
void removeByKeyIf(Predicate p)
Remove elements for which a given predicate for value returns true.
Definition: dictionary.h:189
CDictionary findValueBy(Predicate p) const
Return a copy containing only those elements for which a given predicate returns true.
Definition: dictionary.h:139
void clear()
Removes all items from the dictionary.
Definition: dictionary.h:336
const Value value(const Key &key) const
Returns the value associated with the key.
Definition: dictionary.h:402
Impl< Key, Value >::size_type size_type
STL compatibility.
Definition: dictionary.h:107
~CDictionary()=default
Destructor.
CDictionary & operator=(const CDictionary &other)
Copy assignment.
Definition: dictionary.h:411
void marshalToDataStream(QDataStream &stream) const
Marshal a value to a QDataStream.
Definition: dictionary.h:465
const_iterator constEnd() const
Returns const iterator at the end of the dictionary.
Definition: dictionary.h:342
Value value_type
STL compatibility.
Definition: dictionary.h:98
const Value & const_reference
STL compatibility.
Definition: dictionary.h:104
CDictionary findValueBy(Pairs... pairs) const
Return a copy containing only those elements which value matches a particular pair.
Definition: dictionary.h:153
CDictionary(std::initializer_list< std::pair< Key, Value >> il)
Initializer list constructor.
Definition: dictionary.h:282
auto keyEnd() const
Returns const iterator for iterating over keys.
Definition: dictionary.h:315
friend const impl_type & implementationOf(const CDictionary &dict)
Return reference to the internal implementation object.
Definition: dictionary.h:428
void convertFromJson(const QJsonObject &json)
Assign from JSON object.
Definition: dictionary.h:246
friend bool operator==(const CDictionary &a, const CDictionary &b)
Test for equality.
Definition: dictionary.h:438
void unmarshallFromDbus(const QDBusArgument &argument)
Unmarshall without begin/endStructure, for when composed within another object.
Definition: dictionary.h:462
void marshallToDbus(QDBusArgument &argument) const
Marshall without begin/endStructure, for when composed within another object.
Definition: dictionary.h:459
const_iterator end() const
Returns const iterator at the end of the dictionary.
Definition: dictionary.h:306
int size() const
Returns the number of items in the hash.
Definition: dictionary.h:396
const_iterator constBegin() const
Returns const iterator at the beginning of the dictionary.
Definition: dictionary.h:339
Value & operator[](const Key &key)
Access an element by its key.
Definition: dictionary.h:432
friend int compare(const CDictionary &a, const CDictionary &b)
Return negative, zero, or positive if a is less than, equal to, or greater than b.
Definition: dictionary.h:83
QJsonObject toJson() const
Cast to JSON object.
Definition: dictionary.h:235
auto constKeyValueBegin() const
Returns const iterator for iterating over keys and values together.
Definition: dictionary.h:327
auto keyValueBegin()
Returns iterator for iterating over keys and values together.
Definition: dictionary.h:318
void insert(const CDictionary &other)
Insert all items of other dictionary into this dictionary.
Definition: dictionary.h:375
CDictionary findKeyBy(Pairs... pairs) const
Return a copy containing only those elements which key matches a particular pair.
Definition: dictionary.h:132
auto keyValueBegin() const
Returns const iterator for iterating over keys and values together.
Definition: dictionary.h:324
void removeDuplicates(const CDictionary &other)
Remove elements for which the same key/value pair is present in an other dictionary.
Definition: dictionary.h:224
void removeByValueIf(MembFunc membFunc, ReturnValue returnValue)
Remove elements for which value matches a particular pair.
Definition: dictionary.h:218
const Value value(const Key &key, const Value &defaultValue) const
Returns the value associated with the key or if key is not found defaultValue.
Definition: dictionary.h:405
QString convertToQString(bool i18n=false) const
Cast as QString.
Definition: dictionary.h:444
CDictionary findKeyBy(Predicate p) const
Return a copy containing only those elements for which the dictionary keys return true for a given pr...
Definition: dictionary.h:118
const_iterator constFind(const Key &key) const
Returns an const iterator pointing to the item with the key.
Definition: dictionary.h:346
auto keyValueEnd() const
Returns const iterator for iterating over keys and values together.
Definition: dictionary.h:330
iterator end()
Returns iterator at the end of the dictionary.
Definition: dictionary.h:303
auto keys() const
Return a range of all keys (does not allocate a temporary container)
Definition: dictionary.h:390
bool containsByValue(MembFunc membFunc, ReturnValue returnValue) const
Return true if there is an element which value matches a given pair.
Definition: dictionary.h:182
Key key_type
STL compatibility.
Definition: dictionary.h:95
const_iterator find(const Key &key) const
Returns an const iterator pointing to the item with the key.
Definition: dictionary.h:350
auto keyBegin() const
Returns const iterator for iterating over keys.
Definition: dictionary.h:312
int remove(const Key &key)
Remove all items with key from the dictionary.
Definition: dictionary.h:393
friend bool operator!=(const CDictionary &a, const CDictionary &b)
Test for inequality.
Definition: dictionary.h:441
CDictionary & operator=(CDictionary &&other) noexcept
Move assignment.
Definition: dictionary.h:418
const_iterator cbegin() const
Returns const iterator at the beginning of the dictionary.
Definition: dictionary.h:300
bool isEmpty() const
Returns true if dictionary is empty.
Definition: dictionary.h:381
auto keyValueEnd()
Returns iterator for iterating over keys and values together.
Definition: dictionary.h:321
Impl< Key, Value > impl_type
The implementation container.
Definition: dictionary.h:92
const_iterator begin() const
Returns const iterator at the beginning of the dictionary.
Definition: dictionary.h:297
CDictionary(CDictionary &&other) noexcept
Move constructor.
Definition: dictionary.h:288
auto constKeyValueEnd() const
Returns const iterator for iterating over keys and values together.
Definition: dictionary.h:333
iterator insert(const Key &key, const Value &value)
Insert new item with key and value.
Definition: dictionary.h:372
Impl< Key, Value >::iterator iterator
STL compatibility.
Definition: dictionary.h:110
CDictionary()
Default constructor.
Definition: dictionary.h:279
void removeByValueIf(Predicate p)
Remove elements for which a given predicate for key returns true.
Definition: dictionary.h:200
CRange< const_iterator > values() const
Return a range of all values (does not allocate a temporary container)
Definition: dictionary.h:408
bool empty() const
Returns true if the.
Definition: dictionary.h:366
const Value operator[](const Key &key) const
Access an element by its key.
Definition: dictionary.h:435
void unmarshalFromDataStream(QDataStream &stream)
Unmarshal a value from a QDataStream.
Definition: dictionary.h:468
friend impl_type & implementationOf(CDictionary &dict)
Return reference to the internal implementation object.
Definition: dictionary.h:425
iterator find(const Key &key)
Returns an iterator pointing to the item with the key.
Definition: dictionary.h:354
bool contains(const Key &key) const
Returns true if dictionary contains an item with key, otherwise false.
Definition: dictionary.h:357
const Key key(const Value &value) const
Return key assigned to value.
Definition: dictionary.h:384
bool containsByValue(Predicate p) const
Return true if there is an element for which a given predicate returns true.
Definition: dictionary.h:175
Value & reference
STL compatibility.
Definition: dictionary.h:101
const_iterator cend() const
Returns const iterator at the end of the dictionary.
Definition: dictionary.h:309
iterator erase(iterator pos)
Removes the key/value pair iterator is currently pointing to and returns an iterator to the next item...
Definition: dictionary.h:369
void removeByKeyIf(MembFunc membFunc, ReturnValue returnValue)
Remove elements for which key matches a particular pair.
Definition: dictionary.h:211
CDictionary(const CDictionary &)=default
Copy constructor.
int count() const
Returns the size of the dictionary.
Definition: dictionary.h:363
Impl< Key, Value >::const_iterator const_iterator
STL compatibility.
Definition: dictionary.h:113
bool containsByKey(Predicate p) const
Return true if there is an element for which a given predicate returns true.
Definition: dictionary.h:160
const Key key(const Value &value, const Key &defaultKey) const
Return key assigned to value or if key is not found defaultKey.
Definition: dictionary.h:387
bool containsByKey(MembFunc membFunc, ReturnValue returnValue) const
Return true if there is an element which key matches a given pair.
Definition: dictionary.h:168
void swap(CDictionary &other) noexcept
Swaps hash other with this hash. This operation is very fast and never fails.
Definition: dictionary.h:399
iterator begin()
Returns iterator at the beginning of the dictionary.
Definition: dictionary.h:294
Thrown when a convertFromJson method encounters an unrecoverable error in JSON data.
Definition: jsonexception.h:24
Pseudo-RAII pattern that tracks the current JSON value being converted.
Definition: jsonexception.h:50
A range is a conceptual container which does not contain any elements of its own, but is constructed ...
Definition: range.h:190
CRTP class template which will generate marshalling operators for a derived class with its own marsha...
Definition: mixindbus.h:39
CRTP class template to generate non-member QDataStream streaming operators.
CRTP class template which will generate marshalling operators for a derived class with its own marsha...
Definition: mixinjson.h:37
CRTP class template from which a derived class can inherit string streaming operations.
Definition: mixinstring.h:29
auto MemberEqual(Ts... vs)
Predicate which tests whether some member functions return some values.
Definition: predicates.h:26
Free functions in swift::misc.
auto makeRange(I begin, I2 end) -> CRange< I >
Returns a CRange constructed from begin and end iterators of deduced types.
Definition: range.h:316
typename private_ns::TAssociativityTraits< TModelsQHashKey< K >::value, TModelsQMapKey< K >::value >::template DefaultType< K, V > TDefaultAssociativeType
Trait to select the appropriate default associative container type depending on what the key type sup...
Definition: dictionary.h:70
void forEachIntersection(const Map1 &map1, const Map2 &map2, F functor)
Call a functor for each {key,value1,value2} triple in the keywise intersection of two maps.
Definition: dictionary.h:496
QMap< Key, Value > & implementationOf(QMap< Key, Value > &dict)
Identity function for API consistency with CDictionary::implementationOf.
Definition: dictionary.h:478
QJsonArray::iterator begin()
QJsonArray::iterator end()
QJsonObject::iterator insert(QLatin1StringView key, const QJsonValue &value)
QJsonValue value(QLatin1StringView key) const const
Trait to detect whether a class T can be used as a key in a QMap.
Definition: typetraits.h:109