QCborValue: refactor extended types so isTag() is true

This makes QCborValue more future compatible, as code written today for
tags that QCborValue does not recognize will continue to work if
QCborValue gains support for it in the future.

This change also obviates the need for reinterpretAsTag(), which I had
not written unit tests for as I knew this change was coming.

Change-Id: I052407b777ec43f78378fffd15302bdc34f66755
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Thiago Macieira 2018-05-19 17:21:38 -05:00
parent 22c1a46a03
commit 340472534c
3 changed files with 36 additions and 60 deletions

View File

@ -543,12 +543,12 @@ QT_BEGIN_NAMESPACE
Returns true if this QCborValue is of the tag type. The tag value can be Returns true if this QCborValue is of the tag type. The tag value can be
retrieved using tag() and the tagged value using taggedValue(). retrieved using tag() and the tagged value using taggedValue().
This function does not return true for extended types that the API This function also returns true for extended types that the API
recognizes. For code that handles extended types directly before the Qt API recognizes. For code that handles extended types directly before the Qt API
is updated to support them, it is possible to recreate the tag + tagged is updated to support them, it is possible to recreate the tag + tagged
value pair by using reinterpretAsTag(). value pair by using taggedValue().
\sa type(), tag(), taggedValue(), reinterpretAsTag() \sa type(), tag(), taggedValue(), taggedValue()
*/ */
/*! /*!
@ -862,7 +862,7 @@ static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::E
static inline int typeOrder(Element e1, Element e2) static inline int typeOrder(Element e1, Element e2)
{ {
auto comparable = [](Element e) { auto comparable = [](Element e) {
if (e.type >= 0x10000) if (e.type >= 0x10000) // see QCborValue::isTag_helper()
return QCborValue::Tag; return QCborValue::Tag;
return e.type; return e.type;
}; };
@ -976,17 +976,6 @@ QString DiagnosticNotation::createFromValue(const QCborValue &v)
return QLatin1Char('[') + createFromArray(v.toArray()) + indent + QLatin1Char(']'); return QLatin1Char('[') + createFromArray(v.toArray()) + indent + QLatin1Char(']');
case QCborValue::Map: case QCborValue::Map:
return QLatin1Char('{') + createFromMap(v.toMap()) + indent + QLatin1Char('}'); return QLatin1Char('{') + createFromMap(v.toMap()) + indent + QLatin1Char('}');
case QCborValue::Tag: {
bool byteArrayFormat = opts & QCborValue::ExtendedFormat && isByteArrayEncodingTag(v.tag());
if (byteArrayFormat)
byteArrayFormatStack.push(int(v.tag()));
QString result = QString::fromLatin1("%1(%2)").arg(quint64(v.tag())).arg(createFromValue(v.taggedValue()));
if (byteArrayFormat)
byteArrayFormatStack.pop();
return result;
}
case QCborValue::SimpleType:
break;
case QCborValue::False: case QCborValue::False:
return QStringLiteral("false"); return QStringLiteral("false");
case QCborValue::True: case QCborValue::True:
@ -997,13 +986,23 @@ QString DiagnosticNotation::createFromValue(const QCborValue &v)
return QStringLiteral("undefined"); return QStringLiteral("undefined");
case QCborValue::Double: case QCborValue::Double:
return makeFpString(v.toDouble()); return makeFpString(v.toDouble());
case QCborValue::DateTime:
case QCborValue::Url:
case QCborValue::RegularExpression:
case QCborValue::Uuid:
return createFromValue(v.reinterpretAsTag());
case QCborValue::Invalid: case QCborValue::Invalid:
return QStringLiteral("<invalid>"); return QStringLiteral("<invalid>");
case QCborValue::Tag:
case QCborValue::SimpleType:
default: // tags and other simple types that are recognized
break; // are all handled below
}
if (v.isTag()) {
bool byteArrayFormat = opts & QCborValue::ExtendedFormat && isByteArrayEncodingTag(v.tag());
if (byteArrayFormat)
byteArrayFormatStack.push(int(v.tag()));
QString result = QString::fromLatin1("%1(%2)").arg(quint64(v.tag())).arg(createFromValue(v.taggedValue()));
if (byteArrayFormat)
byteArrayFormatStack.pop();
return result;
} }
// must be a simple type // must be a simple type
@ -1912,7 +1911,7 @@ QCborValue::QCborValue(const QCborValue &other)
\l{QCborKnownTags}{UnixTime_t}. When parsing CBOR streams, QCborValue will \l{QCborKnownTags}{UnixTime_t}. When parsing CBOR streams, QCborValue will
convert \l{QCborKnownTags}{UnixTime_t} to the string-based type. convert \l{QCborKnownTags}{UnixTime_t} to the string-based type.
\sa toDateTime(), isDateTime(), reinterpretAsTag() \sa toDateTime(), isDateTime(), taggedValue()
*/ */
QCborValue::QCborValue(const QDateTime &dt) QCborValue::QCborValue(const QDateTime &dt)
: QCborValue(QCborKnownTags::DateTimeString, dt.toString(Qt::ISODateWithMs).toLatin1()) : QCborValue(QCborKnownTags::DateTimeString, dt.toString(Qt::ISODateWithMs).toLatin1())
@ -1929,7 +1928,7 @@ QCborValue::QCborValue(const QDateTime &dt)
The CBOR URL type is an extended type represented by a string tagged as an The CBOR URL type is an extended type represented by a string tagged as an
\l{QCborKnownTags}{Url}. \l{QCborKnownTags}{Url}.
\sa toUrl(), isUrl(), reinterpretAsTag() \sa toUrl(), isUrl(), taggedValue()
*/ */
QCborValue::QCborValue(const QUrl &url) QCborValue::QCborValue(const QUrl &url)
: QCborValue(QCborKnownTags::Url, url.toString(QUrl::DecodeReserved).toUtf8()) : QCborValue(QCborKnownTags::Url, url.toString(QUrl::DecodeReserved).toUtf8())
@ -1949,7 +1948,7 @@ QCborValue::QCborValue(const QUrl &url)
regular expressions only store the patterns, so any flags that the regular expressions only store the patterns, so any flags that the
QRegularExpression object may carry will be lost. QRegularExpression object may carry will be lost.
\sa toRegularExpression(), isRegularExpression(), reinterpretAsTag() \sa toRegularExpression(), isRegularExpression(), taggedValue()
*/ */
QCborValue::QCborValue(const QRegularExpression &rx) QCborValue::QCborValue(const QRegularExpression &rx)
: QCborValue(QCborKnownTags::RegularExpression, rx.pattern()) : QCborValue(QCborKnownTags::RegularExpression, rx.pattern())
@ -1966,7 +1965,7 @@ QCborValue::QCborValue(const QRegularExpression &rx)
The CBOR UUID type is an extended type represented by a byte array tagged The CBOR UUID type is an extended type represented by a byte array tagged
as an \l{QCborKnownTags}{Uuid}. as an \l{QCborKnownTags}{Uuid}.
\sa toUuid(), isUuid(), reinterpretAsTag() \sa toUuid(), isUuid(), taggedValue()
*/ */
QCborValue::QCborValue(const QUuid &uuid) QCborValue::QCborValue(const QUuid &uuid)
: QCborValue(QCborKnownTags::Uuid, uuid.toRfc4122()) : QCborValue(QCborKnownTags::Uuid, uuid.toRfc4122())
@ -2005,12 +2004,7 @@ QCborValue &QCborValue::operator=(const QCborValue &other)
stored representation. This function returns that number. To retrieve the stored representation. This function returns that number. To retrieve the
representation, use taggedValue(). representation, use taggedValue().
This function does not directly return the tag associated with extended \sa isTag(), taggedValue(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
types. In order to do that, first convert the extended type to tag type
using reinterpretAsTag().
\sa isTag(), taggedValue(), reinterpretAsTag(),
isDateTime(), isUrl(), isRegularExpression(), isUuid()
*/ */
QCborTag QCborValue::tag(QCborTag defaultValue) const QCborTag QCborValue::tag(QCborTag defaultValue) const
{ {
@ -2026,12 +2020,7 @@ QCborTag QCborValue::tag(QCborTag defaultValue) const
stored representation. This function returns that representation. To stored representation. This function returns that representation. To
retrieve the tag, use tag(). retrieve the tag, use tag().
This function does not directly return the representation associated with \sa isTag(), tag(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
extended types. In order to do that, first convert the extended type to tag
type using reinterpretAsTag().
\sa isTag(), tag(), reinterpretAsTag(),
isDateTime(), isUrl(), isRegularExpression(), isUuid()
*/ */
QCborValue QCborValue::taggedValue(const QCborValue &defaultValue) const QCborValue QCborValue::taggedValue(const QCborValue &defaultValue) const
{ {
@ -2039,24 +2028,6 @@ QCborValue QCborValue::taggedValue(const QCborValue &defaultValue) const
container->valueAt(1) : defaultValue; container->valueAt(1) : defaultValue;
} }
/*!
Returns the equivalent representation of a QCborValue extended type, in the
form of a tag object. If this object is not an extended type, this function
returns an invalid QCborValue object (not undefined).
\sa isTag(), tag(), taggedValue(), isInvalid(),
isDateTime(), isUrl(), isRegularExpression(), isUuid()
*/
QCborValue QCborValue::reinterpretAsTag() const
{
QCborValue result = *this;
if (t >= 0x10000)
result.t = Tag;
else
result.t = Invalid;
return result;
}
/*! /*!
Returns the byte array value stored in this QCborValue, if it is of the byte Returns the byte array value stored in this QCborValue, if it is of the byte
array type. Otherwise, it returns \a defaultValue. array type. Otherwise, it returns \a defaultValue.

View File

@ -192,7 +192,7 @@ public:
bool isString() const { return type() == String; } bool isString() const { return type() == String; }
bool isArray() const { return type() == Array; } bool isArray() const { return type() == Array; }
bool isMap() const { return type() == Map; } bool isMap() const { return type() == Map; }
bool isTag() const { return type() == Tag; } bool isTag() const { return isTag_helper(type()); }
bool isFalse() const { return type() == False; } bool isFalse() const { return type() == False; }
bool isTrue() const { return type() == True; } bool isTrue() const { return type() == True; }
bool isBool() const { return isFalse() || isTrue(); } bool isBool() const { return isFalse() || isTrue(); }
@ -228,7 +228,6 @@ public:
QCborTag tag(QCborTag defaultValue = QCborTag(-1)) const; QCborTag tag(QCborTag defaultValue = QCborTag(-1)) const;
QCborValue taggedValue(const QCborValue &defaultValue = QCborValue()) const; QCborValue taggedValue(const QCborValue &defaultValue = QCborValue()) const;
QCborValue reinterpretAsTag() const;
QByteArray toByteArray(const QByteArray &defaultValue = {}) const; QByteArray toByteArray(const QByteArray &defaultValue = {}) const;
QString toString(const QString &defaultValue = {}) const; QString toString(const QString &defaultValue = {}) const;
@ -311,6 +310,11 @@ private:
{ {
return Type(quint8(st) | SimpleType); return Type(quint8(st) | SimpleType);
} }
Q_DECL_CONSTEXPR static bool isTag_helper(Type t)
{
return t == Tag || t >= 0x10000;
}
}; };
Q_DECLARE_SHARED(QCborValue) Q_DECLARE_SHARED(QCborValue)
@ -328,7 +332,7 @@ public:
bool isString() const { return type() == QCborValue::String; } bool isString() const { return type() == QCborValue::String; }
bool isArray() const { return type() == QCborValue::Array; } bool isArray() const { return type() == QCborValue::Array; }
bool isMap() const { return type() == QCborValue::Map; } bool isMap() const { return type() == QCborValue::Map; }
bool isTag() const { return type() == QCborValue::Tag; } bool isTag() const { return QCborValue::isTag_helper(type()); }
bool isFalse() const { return type() == QCborValue::False; } bool isFalse() const { return type() == QCborValue::False; }
bool isTrue() const { return type() == QCborValue::True; } bool isTrue() const { return type() == QCborValue::True; }
bool isBool() const { return isFalse() || isTrue(); } bool isBool() const { return isFalse() || isTrue(); }

View File

@ -308,12 +308,13 @@ void tst_QCborValue::extendedTypes()
{ {
QFETCH(QCborValue, extended); QFETCH(QCborValue, extended);
QFETCH(QCborValue, tagged); QFETCH(QCborValue, tagged);
QVERIFY(!extended.isTag()); QVERIFY(extended.isTag());
QVERIFY(tagged.isTag()); QVERIFY(tagged.isTag());
// despite that, they actually compare equal
QVERIFY(extended == tagged); QVERIFY(extended == tagged);
QVERIFY(tagged == extended); QVERIFY(tagged == extended);
QCOMPARE(extended.tag(), tagged.tag());
QCOMPARE(extended.taggedValue(), tagged.taggedValue());
} }
void tst_QCborValue::copyCompare() void tst_QCborValue::copyCompare()