swift
callsignobjectlist.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (C) 2015 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_AVIATION_CALLSIGNOBJECTLIST_H
7 #define SWIFT_MISC_AVIATION_CALLSIGNOBJECTLIST_H
8 
9 #include <QHash>
10 #include <QMap>
11 #include <QtGlobal>
12 
14 #include "misc/predicates.h"
16 
17 namespace swift::misc::aviation
18 {
20  template <class OBJ, class CONTAINER>
22  {
23  public:
25  bool containsCallsign(const CCallsign &callsign) const
26  {
27  return this->container().contains(&OBJ::getCallsign, callsign);
28  }
29 
31  int applyIfCallsign(const CCallsign &callsign, const CPropertyIndexVariantMap &variantMap,
32  bool skipEqualValues = true)
33  {
34  return this->container().applyIf(&OBJ::getCallsign, callsign, variantMap, skipEqualValues);
35  }
36 
39  {
40  CCallsignSet cs;
41  for (const OBJ &obj : this->container()) { cs.push_back(obj.getCallsign()); }
42  return cs;
43  }
44 
46  QStringList getCallsignStrings(bool sorted = false) const
47  {
48  return this->getCallsigns().getCallsignStrings(sorted);
49  }
50 
52  QString getCallsignsAsString(const QString &separator, bool sorted = false) const
53  {
54  if (this->container().isEmpty()) { return QString(); }
55  const QStringList callsigns = this->getCallsignStrings(sorted);
56  return callsigns.join(separator);
57  }
58 
60  CONTAINER findByCallsign(const CCallsign &callsign) const
61  {
62  return this->container().findBy(&OBJ::getCallsign, callsign);
63  }
64 
66  CONTAINER findByCallsigns(const CCallsignSet &callsigns) const
67  {
68  return this->container().findBy(predicates::MemberIsAnyOf(&OBJ::getCallsign, callsigns));
69  }
70 
72  OBJ findFirstByCallsign(const CCallsign &callsign, const OBJ &ifNotFound = {}) const
73  {
74  return this->container().findFirstByOrDefault(&OBJ::getCallsign, callsign, ifNotFound);
75  }
76 
78  OBJ findLastByCallsign(const CCallsign &callsign, const OBJ &ifNotFound = {}) const
79  {
80  for (auto current = container().end(); current != container().begin(); /* Do nothing */)
81  {
82  --current;
83  if (current->getCallsign() == callsign) { return *current; }
84  }
85  return ifNotFound;
86  }
87 
89  CONTAINER findBySuffix(const QString &suffix) const
90  {
91  CONTAINER r;
92  if (suffix.isEmpty()) { return r; }
93  const QString sfxUpper(suffix.trimmed().toUpper());
94  r = this->container().findBy(
95  [=](const OBJ &csObj) { return (csObj.getCallsign().getSuffix() == sfxUpper); });
96  return r;
97  }
98 
100  int firstIndexOfCallsign(const CCallsign &callsign)
101  {
102  for (int i = 0; i < this->container().size(); i++)
103  {
104  if (this->container()[i].getCallsign() == callsign) { return i; }
105  }
106  return -1;
107  }
108 
110  int removeByCallsign(const CCallsign &callsign)
111  {
112  return this->container().removeIf(&OBJ::getCallsign, callsign);
113  }
114 
116  int removeByCallsigns(const CCallsignSet &callsigns)
117  {
118  return this->container().removeIf([&](const OBJ &obj) { return callsigns.contains(obj.getCallsign()); });
119  }
120 
124  {
125  QMap<QString, int> r; // sorted by key
126  for (const OBJ &csObj : this->container())
127  {
128  const QString s = csObj.getCallsign().getSuffix();
129  if (s.isEmpty()) { continue; }
130  if (r.contains(s)) { r[s] = r[s] + 1; }
131  else { r.insert(s, 1); }
132  }
133  return r;
134  }
135 
138  QStringList getSuffixes() const
139  {
140  QStringList suffixes;
141  for (const OBJ &csObj : this->container())
142  {
143  const QString s = csObj.getCallsign().getSuffix();
144  if (s.isEmpty() || suffixes.contains(s, Qt::CaseInsensitive)) { continue; }
145  suffixes << s;
146  }
147  return suffixes;
148  }
149 
152  {
153  CONTAINER copyContainer(container());
154  copyContainer.sortByCallsign();
156  CCallsign cs;
157  for (const OBJ &csObj : copyContainer)
158  {
159  if (csObj.getCallsign().isEmpty())
160  {
161  Q_ASSERT(false); // there should be no empty callsigns
162  continue;
163  }
164  if (cs != csObj.getCallsign())
165  {
166  cs = csObj.getCallsign();
167  CONTAINER perCallsign({ csObj });
168  result.insert(cs, perCallsign);
169  }
170  else { result[cs].push_back(csObj); }
171  }
172  return result;
173  }
174 
176  int replaceOrAddObjectByCallsign(const OBJ &otherObject)
177  {
178  const CCallsign cs(otherObject.getCallsign());
179  if (cs.isEmpty()) { return 0; }
180  CONTAINER &copy(this->container());
181  copy.removeByCallsign(cs);
182  copy.push_back(otherObject);
183  return 1;
184  }
185 
187  int replaceOrAddObjectsByCallsign(const CONTAINER &others)
188  {
189  if (others.isEmpty()) { return 0; }
190  int c = 0;
191  CONTAINER copy(this->container());
192  for (const OBJ &obj : others)
193  {
194  const CCallsign cs(obj.getCallsign());
195  if (cs.isEmpty()) { continue; }
196  copy.removeByCallsign(cs);
197  copy.push_back(obj);
198  c++;
199  }
200  *this = copy;
201  return c;
202  }
203 
205  int incrementalUpdateOrAdd(const OBJ &objectBeforeChanges, const CPropertyIndexVariantMap &changedValues)
206  {
207  int c;
208  const CCallsign cs = objectBeforeChanges.getCallsign();
209  if (this->containsCallsign(cs))
210  {
211  if (changedValues.isEmpty()) { return 0; }
212  c = this->container().applyIf(&OBJ::getCallsign, cs, changedValues);
213  }
214  else
215  {
216  c = 1;
217  if (changedValues.isEmpty()) { this->container().push_back(objectBeforeChanges); }
218  else
219  {
220  OBJ objectAdded(objectBeforeChanges);
221  objectAdded.apply(changedValues);
222  this->container().push_back(objectAdded);
223  }
224  }
225  return c;
226  }
227 
229  void sortByCallsign() { container().sortBy(&OBJ::getCallsign); }
230 
233  {
235  for (const OBJ &obj : this->container()) { map.insert(obj.getCallsign(), obj); }
236  return map;
237  }
238 
241  {
243  for (const OBJ &obj : this->container())
244  {
245  if (obj.getCallsign().isEmpty()) { continue; }
246  hash.insert(obj.getCallsign(), obj);
247  }
248  return hash;
249  }
250 
252  CONTAINER sortedByCallsign() const
253  {
254  CONTAINER copy(this->container());
255  copy.sortByCallsign();
256  return copy;
257  }
258 
259  protected:
262 
264  const CONTAINER &container() const { return static_cast<const CONTAINER &>(*this); }
265 
267  CONTAINER &container() { return static_cast<CONTAINER &>(*this); }
268  };
269 } // namespace swift::misc::aviation
270 
271 #endif // SWIFT_MISC_AVIATION_CALLSIGNOBJECTLIST_H
iterator push_back(const T &value)
Synonym for insert.
Definition: collection.h:238
Specialized value object compliant map for variants, based on indexes.
bool contains(const T &object) const
Return true if there is an element equal to given object. Uses the most efficient implementation avai...
Definition: range.h:109
Value object encapsulating information of a callsign.
Definition: callsign.h:30
bool isEmpty() const
Is empty?
Definition: callsign.h:63
Value object for a set of callsigns.
Definition: callsignset.h:26
QStringList getCallsignStrings(bool sorted=false) const
The callsign strings.
Definition: callsignset.cpp:37
int removeByCallsigns(const CCallsignSet &callsigns)
Remove all objects with callsigns.
int firstIndexOfCallsign(const CCallsign &callsign)
First found index of callsign, otherwise -1.
int replaceOrAddObjectsByCallsign(const CONTAINER &others)
Replace or add objects by callsign.
CONTAINER findByCallsign(const CCallsign &callsign) const
Find 0..n stations by callsign.
OBJ findLastByCallsign(const CCallsign &callsign, const OBJ &ifNotFound={}) const
Find the back object by callsign, if none return given one.
const CONTAINER & container() const
Container.
OBJ findFirstByCallsign(const CCallsign &callsign, const OBJ &ifNotFound={}) const
Find the first aircraft by callsign, if none return given one.
QMap< QString, int > getSuffixesAndCount() const
All suffixes with their respective count.
QHash< CCallsign, CONTAINER > splitPerCallsign() const
Split into 0..n containers as per callsign.
int applyIfCallsign(const CCallsign &callsign, const CPropertyIndexVariantMap &variantMap, bool skipEqualValues=true)
Apply for given callsign.
QStringList getSuffixes() const
All suffixes, in the order of the list.
CONTAINER findBySuffix(const QString &suffix) const
All with given suffix, empty suffixes ignored.
int removeByCallsign(const CCallsign &callsign)
Remove all objects with callsign.
int replaceOrAddObjectByCallsign(const OBJ &otherObject)
Replace or add objects by callsign.
CONTAINER sortedByCallsign() const
Copy of list sorted by callsign.
int incrementalUpdateOrAdd(const OBJ &objectBeforeChanges, const CPropertyIndexVariantMap &changedValues)
Incremental update or add object.
QString getCallsignsAsString(const QString &separator, bool sorted=false) const
Get callsigns as strings.
swift::misc::aviation::CCallsignSet getCallsigns() const
All callsigns.
bool containsCallsign(const CCallsign &callsign) const
Contains callsign?
CONTAINER findByCallsigns(const CCallsignSet &callsigns) const
Find 0..n aircraft matching any of a set of callsigns.
QHash< CCallsign, OBJ > asCallsignHash() const
Turn into callsign hash.
QMap< CCallsign, OBJ > asCallsignMap() const
Turn into callsign map.
QStringList getCallsignStrings(bool sorted=false) const
Get callsign string list.
auto MemberIsAnyOf(T memberFunc, const C &container)
Returns a predicate that returns true if the value returned by its argument's member function can be ...
Definition: predicates.h:75
T::const_iterator end(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
Definition: lockfree.h:338