diff --git a/src/blackmisc/aviation/atcstation.cpp b/src/blackmisc/aviation/atcstation.cpp index 3bacba943..53317fe87 100644 --- a/src/blackmisc/aviation/atcstation.cpp +++ b/src/blackmisc/aviation/atcstation.cpp @@ -435,7 +435,7 @@ namespace BlackMisc int CAtcStation::comparePropertyByIndex(const CPropertyIndex &index, const CAtcStation &compareValue) const { - if (index.isMyself()) { return this->getCallsign().comparePropertyByIndex(CPropertyIndex::empty(), compareValue.getCallsign()); } + if (index.isMyself()) { return this->getCallsign().comparePropertyByIndex(CPropertyIndexRef::empty(), compareValue.getCallsign()); } const ColumnIndex i = index.frontCasted(); switch (i) { @@ -443,7 +443,7 @@ namespace BlackMisc case IndexBookedUntil: return Compare::compare(this->getBookedUntilUtc(), compareValue.getBookedUntilUtc()); case IndexCallsignString: case IndexCallsignStringCrossCopuled: - return m_callsign.comparePropertyByIndex(CPropertyIndex::empty(), compareValue.getCallsign()); + return m_callsign.comparePropertyByIndex(CPropertyIndexRef::empty(), compareValue.getCallsign()); case IndexCallsign: return m_callsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCallsign()); case IndexController: return m_controller.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getController()); case IndexFrequency: return m_frequency.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getFrequency()); diff --git a/src/blackmisc/propertyindex.cpp b/src/blackmisc/propertyindex.cpp index a1c007722..be640ef2c 100644 --- a/src/blackmisc/propertyindex.cpp +++ b/src/blackmisc/propertyindex.cpp @@ -32,6 +32,11 @@ namespace BlackMisc this->parseFromString(indexes); } + CPropertyIndex::operator CPropertyIndexRef() const + { + return CPropertyIndexRef(m_indexes); + } + CPropertyIndex CPropertyIndex::copyFrontRemoved() const { BLACK_VERIFY_X(!this->isEmpty(), Q_FUNC_INFO, "Empty index"); diff --git a/src/blackmisc/propertyindex.h b/src/blackmisc/propertyindex.h index d24fa8d99..745f81b90 100644 --- a/src/blackmisc/propertyindex.h +++ b/src/blackmisc/propertyindex.h @@ -11,6 +11,7 @@ #ifndef BLACKMISC_PROPERTYINDEX_H #define BLACKMISC_PROPERTYINDEX_H +#include "blackmisc/propertyindexref.h" #include "blackmisc/blackmiscexport.h" #include "blackmisc/mixin/mixincompare.h" #include "blackmisc/mixin/mixindbus.h" @@ -199,6 +200,9 @@ namespace BlackMisc //! From string CPropertyIndex(const QString &indexes); + //! Return a simplified non-owning reference + operator CPropertyIndexRef() const; + //! Copy with first element removed CPropertyIndex copyFrontRemoved() const; diff --git a/src/blackmisc/propertyindexallclasses.h b/src/blackmisc/propertyindexallclasses.h index 9dd53c853..ce380d7c4 100644 --- a/src/blackmisc/propertyindexallclasses.h +++ b/src/blackmisc/propertyindexallclasses.h @@ -11,6 +11,7 @@ #include "blackmisc/propertyindexlist.h" #include "blackmisc/propertyindexvariantmap.h" +#include "blackmisc/propertyindexref.h" #include "blackmisc/propertyindex.h" #endif // guard diff --git a/src/blackmisc/propertyindexref.cpp b/src/blackmisc/propertyindexref.cpp new file mode 100644 index 000000000..030307d70 --- /dev/null +++ b/src/blackmisc/propertyindexref.cpp @@ -0,0 +1,81 @@ +/* Copyright (C) 2013 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, + * or distributed except according to the terms contained in the LICENSE file. + */ + +//! \file + +#include "blackmisc/propertyindexref.h" +#include "blackmisc/propertyindex.h" +#include "blackmisc/verify.h" +#include + +namespace BlackMisc +{ + CPropertyIndexRef::CPropertyIndexRef(int index) : + m_begin(nullptr), + m_sizeOrIndex(index) + {} + + CPropertyIndexRef::CPropertyIndexRef(const QVector &indexes) : + m_begin(indexes.data()), + m_sizeOrIndex(indexes.size()) + {} + + CPropertyIndexRef CPropertyIndexRef::copyFrontRemoved() const + { + BLACK_VERIFY_X(!this->isEmpty(), Q_FUNC_INFO, "Empty index"); + if (this->isEmpty() || !m_begin) { return -1; } + CPropertyIndexRef copy = *this; + ++copy.m_begin; + --copy.m_sizeOrIndex; + return copy; + } + + bool CPropertyIndexRef::isNested() const + { + return m_begin && m_sizeOrIndex > 1; + } + + bool CPropertyIndexRef::isMyself() const + { + return this->isEmpty(); + } + + bool CPropertyIndexRef::isEmpty() const + { + return m_begin ? m_sizeOrIndex < 1 : m_sizeOrIndex < 0; + } + + int CPropertyIndexRef::frontToInt() const + { + Q_ASSERT_X(!this->isEmpty(), Q_FUNC_INFO, "No index"); + return m_begin ? *m_begin : m_sizeOrIndex; + } + + bool CPropertyIndexRef::startsWith(int index) const + { + if (this->isEmpty()) { return false; } + return this->frontToInt() == index; + } + + QString CPropertyIndexRef::toQString(bool i18n) const + { + Q_UNUSED(i18n); + QString s; + if (this->isEmpty()) { return s; } + + auto it = m_begin ? m_begin : &m_sizeOrIndex; + auto end = it + (m_begin ? m_sizeOrIndex : 1); + for (; it != end; ++it) + { + Q_ASSERT(*it >= static_cast(CPropertyIndex::GlobalIndexCValueObject)); + if (!s.isEmpty()) { s.append(";"); } + s.append(QString::number(*it)); + } + return s; + } +} diff --git a/src/blackmisc/propertyindexref.h b/src/blackmisc/propertyindexref.h new file mode 100644 index 000000000..fca735dab --- /dev/null +++ b/src/blackmisc/propertyindexref.h @@ -0,0 +1,114 @@ +/* Copyright (C) 2013 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, + * or distributed except according to the terms contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_PROPERTYINDEXREF_H +#define BLACKMISC_PROPERTYINDEXREF_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/typetraits.h" +#include + +namespace BlackMisc +{ + class CPropertyIndexRef; + + namespace Private + { + //! \private + template + int compareByProperty(const T &a, const T &b, const CPropertyIndexRef &index, std::true_type, X) + { + return a.comparePropertyByIndex(index, b); + } + //! \private + template + int compareByProperty(const T &a, const T &b, const CPropertyIndexRef &index, std::false_type, std::true_type) + { + return compare(a.propertyByIndex(index), b.propertyByIndex(index)); + } + //! \private + template + int compareByProperty(const T &, const T &, const CPropertyIndexRef &, std::false_type, std::false_type) + { + qFatal("Not implemented"); + return 0; + } + } + + /*! + * Non-owning reference to a CPropertyIndex with a subset of its features. + */ + class BLACKMISC_EXPORT CPropertyIndexRef + { + public: + //! Construct from a single index. + CPropertyIndexRef(int index); + + //! Construct from the data of a CPropertyIndex. + explicit CPropertyIndexRef(const QVector &indexes); + + //! Forbid accidental constructor from an rvalue. + explicit CPropertyIndexRef(QVector &&) = delete; + + //! Copy with first element removed + CPropertyIndexRef copyFrontRemoved() const; + + //! Is nested index? + bool isNested() const; + + //! Myself index, used with nesting + bool isMyself() const; + + //! Empty? + bool isEmpty() const; + + //! Front to integer + int frontToInt() const; + + //! Starts with given index? + bool startsWith(int index) const; + + //! \copydoc BlackMisc::Mixin::String::toQString + QString toQString(bool i18n = false) const; + + //! First element casted to given type, usually the PropertIndex enum + template CastType frontCasted() const + { + static_assert(std::is_enum::value || std::is_integral::value, "CastType must be an enum or integer"); + return static_cast(frontToInt()); + } + + //! Compare with index given by enum + template bool startsWithPropertyIndexEnum(EnumType ev) const + { + static_assert(std::is_enum::value, "Argument must be an enum"); + return this->startsWith(static_cast(ev)); + } + + //! Return a predicate function which can compare two objects based on this index + auto comparator() const + { + return [index = *this](const auto & a, const auto & b) + { + using T = std::decay_t; + return Private::compareByProperty(a, b, index, THasComparePropertyByIndex(), THasPropertyByIndex()); + }; + } + + //! an empty property index + static CPropertyIndexRef empty() { return -1; } + + private: + const int *m_begin = nullptr; + int m_sizeOrIndex = -1; + }; +} + +#endif