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  // *INDENT-OFF*
76  template <class Key, class Value, template <class...> class Impl = TDefaultAssociativeType>
77  class CDictionary :
78  public mixin::DBusOperators<CDictionary<Key, Value, Impl>>,
79  public mixin::DataStreamOperators<CDictionary<Key, Value, Impl>>,
80  public mixin::JsonOperators<CDictionary<Key, Value, Impl>>,
81  public mixin::String<CDictionary<Key, Value, Impl>>
82  // *INDENT-ON*
83  {
85  friend int compare(const CDictionary &a, const CDictionary &b)
86  {
87  if (a.m_impl.size() < b.m_impl.size()) { return -1; }
88  if (a.m_impl.size() > b.m_impl.size()) { return 1; }
89  return 0;
90  }
91 
92  public:
94  using impl_type = Impl<Key, Value>;
95 
97  typedef Key key_type;
98 
100  typedef Value value_type;
101 
103  typedef Value &reference;
104 
106  typedef const Value &const_reference;
107 
109  typedef typename Impl<Key, Value>::size_type size_type;
110 
112  typedef typename Impl<Key, Value>::iterator iterator;
113 
115  typedef typename Impl<Key, Value>::const_iterator const_iterator;
116 
119  template <class Predicate>
120  CDictionary findKeyBy(Predicate p) const
121  {
122  CDictionary result = *this;
123  for (auto it = result.begin(); it != result.end();)
124  {
125  if (!p(it.key())) { it = result.erase(it); }
126  else { ++it; }
127  }
128  return result;
129  }
130 
133  template <class... Pairs>
134  CDictionary findKeyBy(Pairs... pairs) const
135  {
137  }
138 
140  template <class Predicate>
141  CDictionary findValueBy(Predicate p) const
142  {
143  CDictionary result = *this;
144  for (auto it = result.begin(); it != result.end();)
145  {
146  if (!p(it.value())) { it = result.erase(it); }
147  else { ++it; }
148  }
149  return result;
150  }
151 
154  template <class... Pairs>
155  CDictionary findValueBy(Pairs... pairs) const
156  {
158  }
159 
161  template <class Predicate>
162  bool containsByKey(Predicate p) const
163  {
164  auto keys = m_impl.keys();
165  return std::any_of(keys.cbegin(), keys.cend(), p);
166  }
167 
169  template <class MembFunc, class ReturnValue>
170  bool containsByKey(MembFunc membFunc, ReturnValue returnValue) const
171  {
172  return containsByKey(swift::misc::predicates::MemberEqual(membFunc, returnValue));
173  }
174 
176  template <class Predicate>
177  bool containsByValue(Predicate p) const
178  {
179  return std::any_of(m_impl.cbegin(), m_impl.cend(), p);
180  }
181 
183  template <class MembFunc, class ReturnValue>
184  bool containsByValue(MembFunc membFunc, ReturnValue returnValue) const
185  {
186  return containsByValue(swift::misc::predicates::MemberEqual(membFunc, returnValue));
187  }
188 
190  template <class Predicate>
191  void removeByKeyIf(Predicate p)
192  {
193  for (auto it = m_impl.begin(); it != m_impl.end();)
194  {
195  if (p(it.key())) { it = m_impl.erase(it); }
196  else { ++it; }
197  }
198  }
199 
201  template <class Predicate>
202  void removeByValueIf(Predicate p)
203  {
204  for (auto it = m_impl.begin(); it != m_impl.end();)
205  {
206  if (p(it.value())) { it = m_impl.erase(it); }
207  else { ++it; }
208  }
209  }
210 
212  template <class MembFunc, class ReturnValue>
213  void removeByKeyIf(MembFunc membFunc, ReturnValue returnValue)
214  {
215  removeByKeyIf(swift::misc::predicates::MemberEqual(membFunc, returnValue));
216  }
217 
219  template <class MembFunc, class ReturnValue>
220  void removeByValueIf(MembFunc membFunc, ReturnValue returnValue)
221  {
223  }
224 
226  void removeDuplicates(const CDictionary &other)
227  {
228  for (auto it = begin(); it != end();)
229  {
230  auto it2 = other.find(it.key());
231  if (it2 != other.end() && it.value() == it2.value()) { it = erase(it); }
232  else { ++it; }
233  }
234  }
235 
237  QJsonObject toJson() const
238  {
239  QJsonArray array;
240  QJsonObject json;
241 
242  for (auto it = m_impl.cbegin(); it != m_impl.cend(); ++it) { array << it.key() << it.value(); }
243  json.insert("associativecontainerbase", array);
244  return json;
245  }
246 
248  void convertFromJson(const QJsonObject &json)
249  {
250  QJsonValue value = json.value("associativecontainerbase");
251  if (value.isUndefined()) { throw CJsonException("Missing 'associativecontainerbase'"); }
252  QJsonArray array = value.toArray();
253  int index = 0;
254  for (auto it = array.begin(); it != array.end(); ++it)
255  {
256  QJsonValueRef jsonKey = (*it);
257  ++it;
258  if (it == array.end())
259  {
260  qWarning("Odd number of elements in CDictionary::convertFromJson");
261  return;
262  }
263  QJsonValueRef jsonValue = (*it);
264  Key key;
265  Value val;
266  {
267  CJsonScope scope("associativecontainerbase", 2 * index);
268  Q_UNUSED(scope);
269  jsonKey >> key;
270  }
271  {
272  CJsonScope scope("associativecontainerbase", 2 * index++ + 1);
273  Q_UNUSED(scope);
274  jsonValue >> val;
275  }
276  m_impl.insert(std::move(key), std::move(val));
277  }
278  }
279 
282 
284  CDictionary(std::initializer_list<std::pair<Key, Value>> il) : m_impl(il) {}
285 
287  CDictionary(const CDictionary &) = default;
288 
290  CDictionary(CDictionary &&other) noexcept : m_impl(std::move(other.m_impl)) {}
291 
293  ~CDictionary() = default;
294 
296  iterator begin() { return m_impl.begin(); }
297 
299  const_iterator begin() const { return m_impl.begin(); }
300 
302  const_iterator cbegin() const { return m_impl.cbegin(); }
303 
305  iterator end() { return m_impl.end(); }
306 
308  const_iterator end() const { return m_impl.end(); }
309 
311  const_iterator cend() const { return m_impl.cend(); }
312 
314  auto keyBegin() const { return m_impl.keyBegin(); }
315 
317  auto keyEnd() const { return m_impl.keyEnd(); }
318 
320  auto keyValueBegin() { return m_impl.keyValueBegin(); }
321 
323  auto keyValueEnd() { return m_impl.keyValueEnd(); }
324 
326  auto keyValueBegin() const { return m_impl.keyValueBegin(); }
327 
329  auto constKeyValueBegin() const { return m_impl.constKeyValueBegin(); }
330 
332  auto keyValueEnd() const { return m_impl.keyValueEnd(); }
333 
335  auto constKeyValueEnd() const { return m_impl.constKeyValueEnd(); }
336 
338  void clear() { m_impl.clear(); }
339 
341  const_iterator constBegin() const { return m_impl.constBegin(); }
342 
344  const_iterator constEnd() const { return m_impl.constEnd(); }
345 
348  const_iterator constFind(const Key &key) const { return m_impl.constFind(key); }
349 
352  const_iterator find(const Key &key) const { return m_impl.find(key); }
353 
356  iterator find(const Key &key) { return m_impl.find(key); }
357 
359  bool contains(const Key &key) const { return m_impl.contains(key); }
360 
362  int count(const Key &key) const { return m_impl.count(key); }
363 
365  int count() const { return m_impl.count(); }
366 
368  bool empty() const { return m_impl.empty(); }
369 
371  iterator erase(iterator pos) { return m_impl.erase(pos); }
372 
374  iterator insert(const Key &key, const Value &value) { return m_impl.insert(key, value); }
375 
377  void insert(const CDictionary &other)
378  {
379  for (auto i = other.cbegin(); i != other.cend(); ++i) { insert(i.key(), i.value()); }
380  }
381 
383  bool isEmpty() const { return m_impl.isEmpty(); }
384 
386  const Key key(const Value &value) const { return m_impl.key(value); }
387 
389  const Key key(const Value &value, const Key &defaultKey) const { return m_impl.key(value, defaultKey); }
390 
392  auto keys() const { return makeRange(keyBegin(), keyEnd()); }
393 
395  int remove(const Key &key) { return m_impl.remove(key); }
396 
398  int size() const { return m_impl.size(); }
399 
401  void swap(CDictionary &other) noexcept { m_impl.swap(other.m_impl); }
402 
404  const Value value(const Key &key) const { return m_impl.value(key); }
405 
407  const Value value(const Key &key, const Value &defaultValue) const { return m_impl.value(key, defaultValue); }
408 
410  CRange<const_iterator> values() const { return makeRange(begin(), end()); }
411 
414  {
415  m_impl = other.m_impl;
416  return *this;
417  }
418 
420  CDictionary &operator=(CDictionary &&other) noexcept
421  {
422  m_impl = std::move(other.m_impl);
423  return *this;
424  }
425 
427  friend impl_type &implementationOf(CDictionary &dict) { return dict.m_impl; }
428 
430  friend const impl_type &implementationOf(const CDictionary &dict) { return dict.m_impl; }
431 
434  Value &operator[](const Key &key) { return m_impl[key]; }
435 
437  const Value operator[](const Key &key) const { return m_impl[key]; }
438 
440  friend bool operator==(const CDictionary &a, const CDictionary &b) { return a.m_impl == b.m_impl; }
441 
443  friend bool operator!=(const CDictionary &a, const CDictionary &b) { return !(a == b); }
444 
446  QString convertToQString(bool i18n = false) const
447  {
448  QString str;
449  for (auto it = m_impl.cbegin(); it != m_impl.end(); ++it)
450  {
451  str += "{";
452  str +=
453  CContainerHelper::stringify(it.key(), i18n) + "," + CContainerHelper::stringify(it.value(), i18n);
454  str += "}";
455  }
456  return "{" + str + "}";
457  }
458 
459  public:
461  void marshallToDbus(QDBusArgument &argument) const { argument << m_impl; }
462 
464  void unmarshallFromDbus(const QDBusArgument &argument) { argument >> m_impl; }
465 
467  void marshalToDataStream(QDataStream &stream) const { stream << m_impl; }
468 
470  void unmarshalFromDataStream(QDataStream &stream) { stream >> m_impl; }
471 
472  private:
473  Impl<Key, Value> m_impl;
474  };
475 
479  template <class Key, class Value>
481  {
482  return dict;
483  }
484 
488  template <class Key, class Value>
490  {
491  return dict;
492  }
493 
497  template <class Map1, class Map2, class F>
498  void forEachIntersection(const Map1 &map1, const Map2 &map2, F functor)
499  {
500  static_assert(std::is_same_v<typename Map1::key_type, typename Map2::key_type>,
501  "Maps must have the same key type");
502  if (map1.empty() || map2.empty()) { return; }
503  auto it1 = implementationOf(map1).lowerBound(map2.cbegin().key());
504  auto end1 = implementationOf(map1).upperBound((map2.cend() - 1).key());
505  auto it2 = implementationOf(map2).lowerBound(map1.cbegin().key());
506  auto end2 = implementationOf(map2).upperBound((map1.cend() - 1).key());
507  while (it1 != end1 && it2 != end2)
508  {
509  if (it1.key() < it2.key()) { ++it1; }
510  else if (it2.key() < it1.key()) { ++it2; }
511  else
512  {
513  functor(it1.key(), it1.value(), it2);
514  ++it1;
515  ++it2;
516  }
517  }
518  }
519 } // namespace swift::misc
520 
521 #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:83
int count(const Key &key) const
Returns the number of items with key.
Definition: dictionary.h:362
void removeByKeyIf(Predicate p)
Remove elements for which a given predicate for value returns true.
Definition: dictionary.h:191
CDictionary findValueBy(Predicate p) const
Return a copy containing only those elements for which a given predicate returns true.
Definition: dictionary.h:141
void clear()
Removes all items from the dictionary.
Definition: dictionary.h:338
const Value value(const Key &key) const
Returns the value associated with the key.
Definition: dictionary.h:404
Impl< Key, Value >::size_type size_type
STL compatibility.
Definition: dictionary.h:109
~CDictionary()=default
Destructor.
CDictionary & operator=(const CDictionary &other)
Copy assignment.
Definition: dictionary.h:413
void marshalToDataStream(QDataStream &stream) const
Marshal a value to a QDataStream.
Definition: dictionary.h:467
const_iterator constEnd() const
Returns const iterator at the end of the dictionary.
Definition: dictionary.h:344
Value value_type
STL compatibility.
Definition: dictionary.h:100
const Value & const_reference
STL compatibility.
Definition: dictionary.h:106
CDictionary findValueBy(Pairs... pairs) const
Return a copy containing only those elements which value matches a particular pair.
Definition: dictionary.h:155
CDictionary(std::initializer_list< std::pair< Key, Value >> il)
Initializer list constructor.
Definition: dictionary.h:284
auto keyEnd() const
Returns const iterator for iterating over keys.
Definition: dictionary.h:317
friend const impl_type & implementationOf(const CDictionary &dict)
Return reference to the internal implementation object.
Definition: dictionary.h:430
void convertFromJson(const QJsonObject &json)
Assign from JSON object.
Definition: dictionary.h:248
friend bool operator==(const CDictionary &a, const CDictionary &b)
Test for equality.
Definition: dictionary.h:440
void unmarshallFromDbus(const QDBusArgument &argument)
Unmarshall without begin/endStructure, for when composed within another object.
Definition: dictionary.h:464
void marshallToDbus(QDBusArgument &argument) const
Marshall without begin/endStructure, for when composed within another object.
Definition: dictionary.h:461
const_iterator end() const
Returns const iterator at the end of the dictionary.
Definition: dictionary.h:308
int size() const
Returns the number of items in the hash.
Definition: dictionary.h:398
const_iterator constBegin() const
Returns const iterator at the beginning of the dictionary.
Definition: dictionary.h:341
Value & operator[](const Key &key)
Access an element by its key.
Definition: dictionary.h:434
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:85
QJsonObject toJson() const
Cast to JSON object.
Definition: dictionary.h:237
auto constKeyValueBegin() const
Returns const iterator for iterating over keys and values together.
Definition: dictionary.h:329
auto keyValueBegin()
Returns iterator for iterating over keys and values together.
Definition: dictionary.h:320
void insert(const CDictionary &other)
Insert all items of other dictionary into this dictionary.
Definition: dictionary.h:377
CDictionary findKeyBy(Pairs... pairs) const
Return a copy containing only those elements which key matches a particular pair.
Definition: dictionary.h:134
auto keyValueBegin() const
Returns const iterator for iterating over keys and values together.
Definition: dictionary.h:326
void removeDuplicates(const CDictionary &other)
Remove elements for which the same key/value pair is present in an other dictionary.
Definition: dictionary.h:226
void removeByValueIf(MembFunc membFunc, ReturnValue returnValue)
Remove elements for which value matches a particular pair.
Definition: dictionary.h:220
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:407
QString convertToQString(bool i18n=false) const
Cast as QString.
Definition: dictionary.h:446
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:120
const_iterator constFind(const Key &key) const
Returns an const iterator pointing to the item with the key.
Definition: dictionary.h:348
auto keyValueEnd() const
Returns const iterator for iterating over keys and values together.
Definition: dictionary.h:332
iterator end()
Returns iterator at the end of the dictionary.
Definition: dictionary.h:305
auto keys() const
Return a range of all keys (does not allocate a temporary container)
Definition: dictionary.h:392
bool containsByValue(MembFunc membFunc, ReturnValue returnValue) const
Return true if there is an element which value matches a given pair.
Definition: dictionary.h:184
Key key_type
STL compatibility.
Definition: dictionary.h:97
const_iterator find(const Key &key) const
Returns an const iterator pointing to the item with the key.
Definition: dictionary.h:352
auto keyBegin() const
Returns const iterator for iterating over keys.
Definition: dictionary.h:314
int remove(const Key &key)
Remove all items with key from the dictionary.
Definition: dictionary.h:395
friend bool operator!=(const CDictionary &a, const CDictionary &b)
Test for inequality.
Definition: dictionary.h:443
CDictionary & operator=(CDictionary &&other) noexcept
Move assignment.
Definition: dictionary.h:420
const_iterator cbegin() const
Returns const iterator at the beginning of the dictionary.
Definition: dictionary.h:302
bool isEmpty() const
Returns true if dictionary is empty.
Definition: dictionary.h:383
auto keyValueEnd()
Returns iterator for iterating over keys and values together.
Definition: dictionary.h:323
Impl< Key, Value > impl_type
The implementation container.
Definition: dictionary.h:94
const_iterator begin() const
Returns const iterator at the beginning of the dictionary.
Definition: dictionary.h:299
CDictionary(CDictionary &&other) noexcept
Move constructor.
Definition: dictionary.h:290
auto constKeyValueEnd() const
Returns const iterator for iterating over keys and values together.
Definition: dictionary.h:335
iterator insert(const Key &key, const Value &value)
Insert new item with key and value.
Definition: dictionary.h:374
Impl< Key, Value >::iterator iterator
STL compatibility.
Definition: dictionary.h:112
CDictionary()
Default constructor.
Definition: dictionary.h:281
void removeByValueIf(Predicate p)
Remove elements for which a given predicate for key returns true.
Definition: dictionary.h:202
CRange< const_iterator > values() const
Return a range of all values (does not allocate a temporary container)
Definition: dictionary.h:410
bool empty() const
Returns true if the.
Definition: dictionary.h:368
const Value operator[](const Key &key) const
Access an element by its key.
Definition: dictionary.h:437
void unmarshalFromDataStream(QDataStream &stream)
Unmarshal a value from a QDataStream.
Definition: dictionary.h:470
friend impl_type & implementationOf(CDictionary &dict)
Return reference to the internal implementation object.
Definition: dictionary.h:427
iterator find(const Key &key)
Returns an iterator pointing to the item with the key.
Definition: dictionary.h:356
bool contains(const Key &key) const
Returns true if dictionary contains an item with key, otherwise false.
Definition: dictionary.h:359
const Key key(const Value &value) const
Return key assigned to value.
Definition: dictionary.h:386
bool containsByValue(Predicate p) const
Return true if there is an element for which a given predicate returns true.
Definition: dictionary.h:177
Value & reference
STL compatibility.
Definition: dictionary.h:103
const_iterator cend() const
Returns const iterator at the end of the dictionary.
Definition: dictionary.h:311
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:371
void removeByKeyIf(MembFunc membFunc, ReturnValue returnValue)
Remove elements for which key matches a particular pair.
Definition: dictionary.h:213
CDictionary(const CDictionary &)=default
Copy constructor.
int count() const
Returns the size of the dictionary.
Definition: dictionary.h:365
Impl< Key, Value >::const_iterator const_iterator
STL compatibility.
Definition: dictionary.h:115
bool containsByKey(Predicate p) const
Return true if there is an element for which a given predicate returns true.
Definition: dictionary.h:162
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:389
bool containsByKey(MembFunc membFunc, ReturnValue returnValue) const
Return true if there is an element which key matches a given pair.
Definition: dictionary.h:170
void swap(CDictionary &other) noexcept
Swaps hash other with this hash. This operation is very fast and never fails.
Definition: dictionary.h:401
iterator begin()
Returns iterator at the beginning of the dictionary.
Definition: dictionary.h:296
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:31
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:498
QMap< Key, Value > & implementationOf(QMap< Key, Value > &dict)
Identity function for API consistency with CDictionary::implementationOf.
Definition: dictionary.h:480
Trait to detect whether a class T can be used as a key in a QMap.
Definition: typetraits.h:109