Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qndeffilter.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qndeffilter.h"
5#include "qndefmessage.h"
6
7#include <QtCore/QList>
8#include <QtCore/QMap>
9
11
222{
223public:
225
227 QList<QNdefFilter::Record> filterRecords;
228};
229
231: orderMatching(false)
232{
233}
234
242
250
257
262{
263 if (d != other.d)
264 d = other.d;
265
266 return *this;
267}
268
278{
279 // empty filter matches only empty message
280 if (d->filterRecords.isEmpty())
281 return message.isEmpty();
282
283 bool matched = true;
284 int totalCount = 0;
285
286 if (!d->orderMatching) {
287 // Order is not important. The most reliable way is to merge all the
288 // similar records, and then simply check the amount of occurrences.
289 using MapKey = QPair<QNdefRecord::TypeNameFormat, QByteArray>;
290
291 // Creating a map from the list of filter records.
292 QMap<MapKey, Record> joinedFilterRecords;
293 for (const auto &rec : d->filterRecords) {
294 const auto key = qMakePair(rec.typeNameFormat, rec.type);
295 if (joinedFilterRecords.contains(key)) {
296 joinedFilterRecords[key].minimum += rec.minimum;
297 joinedFilterRecords[key].maximum += rec.maximum;
298 } else {
299 joinedFilterRecords.insert(key, rec);
300 }
301 }
302 // Checking the message, calculate occurrences.
303 QMap<MapKey, unsigned int> counts; // current number of occurrences
304 for (const auto &record : message) {
305 const auto key = qMakePair(record.typeNameFormat(), record.type());
306 // Do not forget that we handle an empty type as "any type".
307 const auto emptyTypeKey = qMakePair(record.typeNameFormat(), QByteArray());
308
309 if (joinedFilterRecords.contains(key))
310 counts[key] += 1;
311 else if (joinedFilterRecords.contains(emptyTypeKey))
312 counts[emptyTypeKey] += 1;
313 }
314 // Check that the occurrences match [min; max] range.
315 for (auto it = joinedFilterRecords.cbegin(); it != joinedFilterRecords.cend(); ++it) {
316 const auto count = counts.value(it.key(), 0);
317 totalCount += count;
318 if (count < it.value().minimum || count > it.value().maximum) {
319 matched = false;
320 break;
321 }
322 }
323 } else {
324 // Order *is* important. Need to iterate the list.
325
326 // Here we need to merge consecutive records with the same parameters.
327 QList<Record> mergedRecords;
328 // we know that filer is not empty here
329 Record currentRecord = d->filterRecords.first();
330 for (qsizetype i = 1; i < d->filterRecords.size(); ++i) {
331 const auto &rec = d->filterRecords.at(i);
332 if (rec.typeNameFormat == currentRecord.typeNameFormat
333 && rec.type == currentRecord.type) {
334 currentRecord.minimum += rec.minimum;
335 currentRecord.maximum += rec.maximum;
336 } else {
337 mergedRecords.push_back(currentRecord);
338 currentRecord = rec;
339 }
340 }
341 mergedRecords.push_back(currentRecord);
342
343 // The list contains the current number of occurrences of each record.
344 QList<unsigned int> counts(mergedRecords.size(), 0);
345
346 // Iterate through the messages and calculate the number of occurrences.
347 qsizetype filterIndex = 0;
348 for (qsizetype messageIndex = 0; matched && messageIndex < message.size(); ++messageIndex) {
349 const auto &messageRec = message.at(messageIndex);
350 // Try to find a filter record that matches the message record.
351 // We start from the last processed filter record, not from the very
352 // beginning (because the order matters).
353 qsizetype idx = filterIndex;
354 for (; idx < mergedRecords.size(); ++idx) {
355 const auto &filterRec = mergedRecords.at(idx);
356 if (filterRec.typeNameFormat == messageRec.typeNameFormat()
357 && (filterRec.type == messageRec.type() || filterRec.type.isEmpty())) {
358 counts[idx] += 1;
359 break;
360 } else if (counts[idx] < filterRec.minimum || counts[idx] > filterRec.maximum) {
361 // The current message record does not match the current
362 // filter record, but we didn't get enough records to
363 // fulfill the filter => that's an error.
364 matched = false;
365 break;
366 }
367 }
368 filterIndex = idx;
369 }
370
371 if (matched) {
372 // Check that the occurrences match [min; max] range.
373 for (qsizetype i = 0; i < mergedRecords.size(); ++i) {
374 const auto &rec = mergedRecords.at(i);
375 totalCount += counts[i];
376 if (counts[i] < rec.minimum || counts[i] > rec.maximum) {
377 matched = false;
378 break;
379 }
380 }
381 }
382 }
383
384 // Check if the message has records that do not match any record from the
385 // filter. To do it we just need to compare the total count of records,
386 // detected by filter, with the full message size. If they do not match,
387 // we have some records, that are not covered by the filter.
388 if (matched && (totalCount != message.size())) {
389 matched = false;
390 }
391
392 return matched;
393}
394
399{
400 d->orderMatching = false;
401 d->filterRecords.clear();
402}
403
413{
414 d->orderMatching = on;
415}
416
422{
423 return d->orderMatching;
424}
425
435 unsigned int min, unsigned int max)
436{
438
439 record.typeNameFormat = typeNameFormat;
440 record.type = type;
441 record.minimum = min;
442 record.maximum = max;
443
444 return appendRecord(record);
445}
446
448{
449 return record.minimum <= record.maximum;
450}
451
459{
460 if (verifyRecord(record)) {
462 return true;
463 }
464 return false;
465}
466
478
483{
484 return d->filterRecords.size();
485}
486
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
T & first()
Definition qlist.h:645
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
QList< QNdefFilter::Record > filterRecords
The QNdefFilter class provides a filter for matching NDEF messages.
Definition qndeffilter.h:17
QNdefFilter & operator=(const QNdefFilter &other)
Assigns other to this filter and returns a reference to this filter.
bool orderMatch() const
Returns true if the filter takes NDEF record order into account when matching.
bool match(const QNdefMessage &message) const
void setOrderMatch(bool on)
Sets the ordering requirements of the filter.
QNdefFilter()
Constructs a new NDEF filter.
Record recordAt(qsizetype i) const
Returns the NDEF record at index i.
qsizetype recordCount() const
Returns the number of NDEF records in the filter.
bool appendRecord(unsigned int min=1, unsigned int max=1)
Appends a record matching the template parameter to the NDEF filter.
Definition qndeffilter.h:53
void clear()
Clears the filter.
~QNdefFilter()
Destroys the NDEF filter.
The QNdefMessage class provides an NFC NDEF message.
TypeNameFormat
This enum describes the type name format of an NDEF record.
Definition qndefrecord.h:18
const_iterator cend() const noexcept
Definition qset.h:142
const_iterator cbegin() const noexcept
Definition qset.h:138
\inmodule QtCore
Definition qshareddata.h:19
QSet< QString >::iterator it
Combined button and popup list for selecting options.
static bool verifyRecord(const QNdefFilter::Record &record)
GLuint64 key
GLenum GLenum GLsizei count
GLenum type
GLuint GLsizei const GLchar * message
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
ptrdiff_t qsizetype
Definition qtypes.h:165
MyRecord record(int row) const
[0]
QSharedPointer< T > other(t)
[5]
The QNdefFilter::Record struct contains the information about a filter record.
Definition qndeffilter.h:28
unsigned int minimum
Definition qndeffilter.h:31