[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [dferry] /: WIP: Arguments::{Reader, Writer}: Remove Next{Array, Dict}Entry states.
From: Andreas Hartmetz <ahartmetz () gmail ! com>
Date: 2016-10-12 0:57:07
Message-ID: E1bu7r1-0007PZ-Qw () code ! kde ! org
[Download RAW message or body]
Git commit 8af1260a7b38befa847ad79606f18583b561c4ec by Andreas Hartmetz.
Committed on 09/10/2016 at 20:51.
Pushed by ahartmetz into branch 'master'.
WIP: Arguments::{Reader,Writer}: Remove Next{Array,Dict}Entry states.
They were meant to be self-documentation and a small help in certain
cases, but they are not required for the API to work and they also
make things a few percent slower in the average case.
The real reason for this change is compatibility with QDBus API,
though.
WIP because:
- need to fix pretty-printing where NextDictEntry was previously used
- found some missing input validation that should be added
M +0 -6 applications/analyzer/argumentsmodel.cpp
M +95 -154 serialization/arguments.cpp
M +3 -14 serialization/arguments.h
M +1 -2 serialization/message.cpp
M +36 -101 tests/serialization/tst_arguments.cpp
http://commits.kde.org/dferry/8af1260a7b38befa847ad79606f18583b561c4ec
diff --git a/applications/analyzer/argumentsmodel.cpp \
b/applications/analyzer/argumentsmodel.cpp index 1de5e00..0dc97b6 100644
--- a/applications/analyzer/argumentsmodel.cpp
+++ b/applications/analyzer/argumentsmodel.cpp
@@ -116,9 +116,6 @@ QAbstractItemModel* createArgumentsModel(Message *message)
parent = descend(parent, hasData ? "Array" : "Array (no elements, \
showing just types)"); emptyNesting += hasData ? 0 : 1;
break; }
- case Arguments::NextArrayEntry:
- reader.nextArrayEntry();
- break;
case Arguments::EndArray:
reader.endArray();
parent = ascend(parent, model);
@@ -129,9 +126,6 @@ QAbstractItemModel* createArgumentsModel(Message *message)
parent = descend(parent, hasData ? "Dict" : "Dict (no elements, showing \
just types)"); emptyNesting += hasData ? 0 : 1;
break; }
- case Arguments::NextDictEntry:
- reader.nextDictEntry();
- break;
case Arguments::EndDict:
reader.endDict();
parent = ascend(parent, model);
diff --git a/serialization/arguments.cpp b/serialization/arguments.cpp
index 9e002a2..c4e8751 100644
--- a/serialization/arguments.cpp
+++ b/serialization/arguments.cpp
@@ -353,10 +353,8 @@ static cstring printableState(Arguments::IoState state)
"AnyData",
"DictKey",
"BeginArray",
- "NextArrayEntry",
"EndArray",
"BeginDict",
- "NextDictEntry",
"EndDict",
"BeginStruct",
"EndStruct",
@@ -554,9 +552,6 @@ std::string Arguments::prettyPrint() const
nestingPrefix += "[ ";
}
break;
- case Arguments::NextArrayEntry:
- reader.nextArrayEntry();
- break;
case Arguments::EndArray:
reader.endArray();
emptyNesting = std::max(emptyNesting - 1, 0);
@@ -569,6 +564,7 @@ std::string Arguments::prettyPrint() const
ret << nestingPrefix << "begin dict\n";
nestingPrefix += "{K ";
break; }
+#if 0 // TODO
case Arguments::NextDictEntry:
reader.nextDictEntry();
if (strEndsWith(nestingPrefix, "V ")) {
@@ -576,6 +572,7 @@ std::string Arguments::prettyPrint() const
assert(strEndsWith(nestingPrefix, "{"));
}
break;
+#endif
case Arguments::EndDict:
reader.endDict();
emptyNesting = std::max(emptyNesting - 1, 0);
@@ -1135,6 +1132,7 @@ void Arguments::Reader::advanceState()
// check if we are about to close any aggregate or even the whole argument list
if (d->m_aggregateStack.empty()) {
+ // TODO check if there is still data left, if so it's probably an error
if (d->m_signaturePosition >= d->m_signature.length) {
m_state = Finished;
return;
@@ -1156,18 +1154,40 @@ void Arguments::Reader::advanceState()
return;
}
break;
- case BeginDict:
- if (d->m_signaturePosition > aggregateInfo.arr.containedTypeBegin + 2) {
- m_state = NextDictEntry;
- return;
- }
- break;
case BeginArray:
- if (d->m_signaturePosition > aggregateInfo.arr.containedTypeBegin + 1) {
- m_state = NextArrayEntry;
- return;
+ case BeginDict: {
+ const bool isDict = aggregateInfo.aggregateType == BeginDict;
+ if (d->m_signaturePosition > aggregateInfo.arr.containedTypeBegin + \
(isDict ? 1 : 0)) { + const Private::ArrayInfo &arrayInfo = \
aggregateInfo.arr; + bool moreElements = false;
+ if (unlikely(d->m_nilArrayNesting)) {
+ // we're done iterating over it once
+ // TODO unit-test this
+ d->m_nilArrayNesting--;
+ } else if (d->m_dataPosition < arrayInfo.dataEnd) {
+ if (isDict) {
+ d->m_dataPosition = align(d->m_dataPosition, 8); // align to \
dict entry + }
+ // rewind to start of contained type and read the type info \
there + d->m_signaturePosition = arrayInfo.containedTypeBegin;
+ moreElements = true;
+ }
+ if (!moreElements) {
+ // TODO check that final data position is where it should be \
according to the + // serialized array length
+ m_state = isDict ? EndDict : EndArray;
+ if (isDict) {
+ d->m_nesting.endParen();
+ d->m_signaturePosition++; // skip '}'
+ }
+ // fix up for the pre-increment of d->m_signaturePosition in \
advanceState() + d->m_signaturePosition--;
+ d->m_nesting.endArray();
+ d->m_aggregateStack.pop_back();
+ return;
+ }
}
- break;
+ break; }
default:
break;
}
@@ -1298,13 +1318,12 @@ void Arguments::Reader::advanceState()
VALID_IF(d->m_nesting.beginArray(), Error::MalformedMessageData);
if (firstElementTy.state() == BeginDict) {
d->m_signaturePosition++;
+ // TODO check whether the first type is a primitive or string type!
// only closed at end of dict - there is no observable difference for \
clients
VALID_IF(d->m_nesting.beginParen(), Error::MalformedMessageData);
}
- // position at the 'a' or '{' because we increment d->m_signaturePosition \
before reading contents -
- // this saves a special case in that more generic code
- arrayInfo.containedTypeBegin = d->m_signaturePosition;
+ arrayInfo.containedTypeBegin = d->m_signaturePosition + 1;
if (!arrayLength) {
d->m_nilArrayNesting++;
@@ -1338,33 +1357,29 @@ void Arguments::Reader::advanceStateFrom(IoState \
expectedState)
void Arguments::Reader::beginArrayOrDict(bool isDict, EmptyArrayOption option)
{
- assert(!d->m_aggregateStack.empty());
if (unlikely(d->m_nilArrayNesting)) {
if (option == SkipIfEmpty) {
skipArrayOrDictSignature(isDict);
if (m_state == InvalidData) {
return;
}
- // open them again so the end-of-array handling code can close them \
again...
- d->m_nesting.beginArray();
- if (isDict) {
- d->m_nesting.beginParen();
- }
}
}
- m_state = isDict ? NextDictEntry : NextArrayEntry;
+ advanceState();
}
void Arguments::Reader::skipArrayOrDictSignature(bool isDict)
{
- // fix up nesting and parse position before parsing the array signature
+ // Note that we cannot just pass a dummy Nesting instance to \
parseSingleCompleteType, it must + // actually check the nesting because an array \
may contain other nested aggregates. So we must + // compensate for the already \
raised nesting levels from BeginArray handling in advanceState(). + \
d->m_nesting.endArray(); if (isDict) {
d->m_nesting.endParen();
// the Reader ad-hoc parsing code moved at ahead by one to skip the '{', but \
parseSingleCompleteType() // needs to see the full dict signature, so fix it up
d->m_signaturePosition--;
}
- d->m_nesting.endArray();
// parse the full (i.e. starting with the 'a') array (or dict) signature in \
order to skip it -
// barring bugs, must have been too deep nesting inside variants if parsing \
fails @@ -1373,9 +1388,14 @@ void Arguments::Reader::skipArrayOrDictSignature(bool \
isDict)
VALID_IF(parseSingleCompleteType(&remainingSig, &d->m_nesting), \
Error::MalformedMessageData); d->m_signaturePosition = d->m_signature.length - \
remainingSig.length;
- // fix up signature position again - parseSingleCompleteType() and the ad-hoc \
parsing code in Reader
- // have different conventions about where they expect and where they leave \
m_signaturePosition + // Compensate for pre-increment in advanceState()
+ d->m_signaturePosition--;
+
+ d->m_nesting.beginArray();
if (isDict) {
+ d->m_nesting.beginParen();
+ // Compensate for code in advanceState() that kind of ignores the '}' at the \
end of a dict. + // Unlike advanceState(), parseSingleCompleteType() does \
properly parse that one. d->m_signaturePosition--;
}
}
@@ -1391,82 +1411,40 @@ bool Arguments::Reader::beginArray(EmptyArrayOption option)
return !d->m_nilArrayNesting;
}
-bool Arguments::Reader::nextArrayOrDictEntry(bool isDict)
+void Arguments::Reader::skipArrayOrDict(bool isDict)
{
+ // fast-forward the signature position
+ skipArrayOrDictSignature(isDict);
+
+ // fast-forward the data position
assert(!d->m_aggregateStack.empty());
- Private::AggregateInfo &aggregateInfo = d->m_aggregateStack.back();
- assert(aggregateInfo.aggregateType == (isDict ? BeginDict : BeginArray));
- Private::ArrayInfo &arrayInfo = aggregateInfo.arr;
+ Private::AggregateInfo &arrayInfo = d->m_aggregateStack.back();
+ assert(arrayInfo.aggregateType == (isDict ? BeginDict : BeginArray));
+ d->m_dataPosition = arrayInfo.arr.dataEnd;
+
+ // end the dict / array
if (unlikely(d->m_nilArrayNesting)) {
- if (d->m_signaturePosition <= arrayInfo.containedTypeBegin) {
- // do one iteration to read the types; read the next type...
- advanceState();
- // theoretically, nothing can go wrong: the signature is pre-validated \
and we are not going
- // to read any data. also theoretically, there are no bugs in \
advanceState() :)
- return m_state != InvalidData;
- } else {
- // second iteration or skipping an empty array
- d->m_nilArrayNesting--;
- }
- } else {
- if (d->m_dataPosition < arrayInfo.dataEnd) {
- if (isDict) {
- d->m_dataPosition = align(d->m_dataPosition, 8); // align to dict \
entry
- }
- // rewind to start of contained type and read the type info there
- d->m_signaturePosition = arrayInfo.containedTypeBegin;
- advanceState();
- return m_state != InvalidData;
- }
+ // we're done iterating over it once
+ // TODO: unit-test this
+ d->m_nilArrayNesting--;
}
- // no more iterations
- m_state = isDict ? EndDict : EndArray;
- d->m_signaturePosition--; // this was increased in advanceState() before sending \
us here + // m_state = isDict ? EndDict : EndArray; // nobody looks at it
if (isDict) {
d->m_nesting.endParen();
d->m_signaturePosition++; // skip '}'
}
d->m_nesting.endArray();
d->m_aggregateStack.pop_back();
- return false;
-}
-
-void Arguments::Reader::skipArrayOrDict(bool isDict)
-{
- assert(isDict ? (m_state == BeginDict) : (m_state == BeginArray));
- // fast-forward the signature position
- skipArrayOrDictSignature(isDict);
- if (!isDict) {
- d->m_signaturePosition--;
- }
-
- // fast-forward the data position
- assert(!d->m_aggregateStack.empty());
- Private::AggregateInfo &aggregateInfo = d->m_aggregateStack.back();
- assert(aggregateInfo.aggregateType == (isDict ? BeginDict : BeginArray));
- d->m_dataPosition = aggregateInfo.arr.dataEnd;
-
- // end the dict / array and proceed with next element
- d->m_aggregateStack.pop_back();
+ // proceed to next element
advanceState();
}
-bool Arguments::Reader::nextArrayEntry()
-{
- if (m_state == NextArrayEntry) {
- return nextArrayOrDictEntry(false);
- } else {
- m_state = InvalidData;
- d->m_error.setCode(Error::ReadWrongType);
- return false;
- }
-}
-
void Arguments::Reader::skipArray()
{
if (unlikely(m_state != BeginArray)) {
+ // TODO test this
m_state = InvalidData;
d->m_error.setCode(Error::ReadWrongType);
} else {
@@ -1517,12 +1495,18 @@ std::pair<Arguments::IoState, chunk> \
Arguments::Reader::readPrimitiveArray() }
ret.first = elementType.state();
- // set things up for nextArrayOrDictEntry() and use it to move past the array
+ if (unlikely(d->m_nilArrayNesting)) {
+ // we're done iterating over it once
+ d->m_nilArrayNesting--;
+ }
+ m_state = EndArray;
+ d->m_signaturePosition += 1;
d->m_dataPosition = d->m_aggregateStack.back().arr.dataEnd;
- d->m_signaturePosition += 2;
- nextArrayOrDictEntry(false);
+ d->m_nesting.endArray();
+ d->m_aggregateStack.pop_back();
+
// ... leave the array, there is nothing more to do in it
- endArray();
+ advanceState();
return ret;
}
@@ -1557,20 +1541,10 @@ bool Arguments::Reader::beginDict(EmptyArrayOption option)
return !d->m_nilArrayNesting;
}
-bool Arguments::Reader::nextDictEntry()
-{
- if (m_state == NextDictEntry) {
- return nextArrayOrDictEntry(true);
- } else {
- m_state = InvalidData;
- d->m_error.setCode(Error::ReadWrongType);
- return false;
- }
-}
-
void Arguments::Reader::skipDict()
{
if (unlikely(m_state != BeginDict)) {
+ // TODO test this
m_state = InvalidData;
d->m_error.setCode(Error::ReadWrongType);
} else {
@@ -1670,18 +1644,12 @@ void Arguments::Reader::skipCurrentAggregate()
case Arguments::BeginArray:
skipArray();
break;
- case Arguments::NextArrayEntry:
- assert(false); // can't happen because we skip all arrays
- break;
case Arguments::EndArray:
assert(false); // can't happen because we skip all arrays
break;
case Arguments::BeginDict:
skipDict();
break;
- case Arguments::NextDictEntry:
- assert(false); // can't happen because we skip all dicts
- break;
case Arguments::EndDict:
assert(false); // can't happen because we skip all dicts
break;
@@ -1952,8 +1920,13 @@ void Arguments::Writer::advanceState(cstring \
signatureFragment, IoState newState }
break;
case BeginArray:
- if (d->m_signaturePosition >= aggregateInfo.arr.containedTypeBegin + \
1) {
- VALID_IF(m_state == EndArray, \
Error::NotSingleCompleteTypeInArray); + if (d->m_signaturePosition >= \
aggregateInfo.arr.containedTypeBegin + 1 + && m_state != EndArray) \
{ + // we are not at start of contained type's signature, the \
array is at top of stack + // -> we are at the end of the single \
complete type inside the array, start the next + // entry. TODO: \
check compatibility (essentially what's in the else branch below) + \
d->m_signaturePosition = aggregateInfo.arr.containedTypeBegin; + \
isWritingSignature = false; }
break;
case BeginDict:
@@ -1962,21 +1935,30 @@ void Arguments::Writer::advanceState(cstring \
signatureFragment, IoState newState }
// first type has been checked already, second must be present \
(checked in EndDict // state handler). no third type allowed.
- if (d->m_signaturePosition >= aggregateInfo.arr.containedTypeBegin + \
2) {
- VALID_IF(m_state == EndDict, Error::GreaterTwoTypesInDict);
+ if (d->m_signaturePosition >= aggregateInfo.arr.containedTypeBegin + \
2 + && m_state != EndDict) {
+ // Start the next dict entry
+ d->m_nesting.parenCount += 1;
+ // align to dict entry
+ d->m_elements.push_back(Private::ElementInfo(structAlignment, \
0)); + d->m_signaturePosition = \
aggregateInfo.arr.containedTypeBegin; + isWritingSignature = \
false; }
break;
default:
break;
}
}
+ }
- // finally, extend the signature
+ if (isWritingSignature) {
+ // extend the signature
for (uint32 i = 0; i < signatureFragment.length; i++) {
d->m_signature.ptr[d->m_signaturePosition++] = signatureFragment.ptr[i];
}
d->m_signature.length += signatureFragment.length;
} else {
+ VALID_IF(likely(!d->m_nilArrayNesting), \
Error::SubsequentIterationInNilArray); // signature must match first iteration (of \
an array/dict)
VALID_IF(d->m_signaturePosition + signatureFragment.length <= \
d->m_signature.length, Error::TypeMismatchInSubsequentArrayIteration);
@@ -2153,42 +2135,6 @@ void Arguments::Writer::beginArray(ArrayOption option)
beginArrayOrDict(false, option == WriteTypesOfEmptyArray);
}
-void Arguments::Writer::nextArrayOrDictEntry(bool isDict)
-{
- // TODO sanity / syntax checks, data length check too?
-
- VALID_IF(!d->m_aggregateStack.empty(), \
Error::CannotStartNextArrayOrDictEntryHere);
- Private::AggregateInfo &aggregateInfo = d->m_aggregateStack.back();
- VALID_IF(aggregateInfo.aggregateType == (isDict ? BeginDict : BeginArray),
- Error::CannotStartNextArrayOrDictEntryHere);
-
- if (unlikely(d->m_nilArrayNesting)) {
- // allow one iteration to write the types
- VALID_IF(d->m_signaturePosition == aggregateInfo.arr.containedTypeBegin,
- Error::SubsequentIterationInNilArray);
- } else {
- if (d->m_signaturePosition == aggregateInfo.arr.containedTypeBegin) {
- // first iteration, nothing to do.
- // this is due to the feature that nextFooEntry() is not required before \
the first element.
- } else if (isDict) {
- // a dict must have a key and value
- VALID_IF(d->m_signaturePosition > aggregateInfo.arr.containedTypeBegin + \
1,
- Error::TooFewTypesInArrayOrDict);
-
- d->m_nesting.parenCount += 1; // for alignment blowup accounting
- d->m_elements.push_back(Private::ElementInfo(structAlignment, 0)); // \
align to dict entry
- }
- // array case: we are not at start of contained type's signature, the array \
is at top of stack
- // -> we *are* at the end of a single complete type inside the array, syntax \
check passed
- d->m_signaturePosition = aggregateInfo.arr.containedTypeBegin;
- }
-}
-
-void Arguments::Writer::nextArrayEntry()
-{
- nextArrayOrDictEntry(false);
-}
-
void Arguments::Writer::endArray()
{
advanceState(cstring(), EndArray);
@@ -2199,11 +2145,6 @@ void Arguments::Writer::beginDict(ArrayOption option)
beginArrayOrDict(true, option == WriteTypesOfEmptyArray);
}
-void Arguments::Writer::nextDictEntry()
-{
- nextArrayOrDictEntry(true);
-}
-
void Arguments::Writer::endDict()
{
advanceState(cstring("}", strlen("}")), EndDict);
diff --git a/serialization/arguments.h b/serialization/arguments.h
index 19d0cd6..2a1f576 100644
--- a/serialization/arguments.h
+++ b/serialization/arguments.h
@@ -99,12 +99,10 @@ public:
// states pertaining to aggregates
BeginArray,
- NextArrayEntry,
EndArray,
BeginDict,
- NextDictEntry, // 10
EndDict,
- BeginStruct,
+ BeginStruct, // 10
EndStruct,
BeginVariant,
EndVariant,
@@ -113,9 +111,9 @@ public:
Byte,
Int16,
Uint16,
- Int32, // 20
+ Int32,
Uint32,
- Int64,
+ Int64, // 20
Uint64,
Double,
String,
@@ -197,13 +195,10 @@ public:
// The return value is false if the array is empty (has 0 elements), true if \
it has >= 1 elements. // The return value is not affected by @p option.
bool beginArray(EmptyArrayOption option = SkipIfEmpty);
- // call this before reading each entry; when it returns false the array has \
ended.
- bool nextArrayEntry();
void skipArray(); // skips the current array; only call this in state \
BeginArray!
void endArray(); // leaves the current array; only call this in state \
EndArray!
bool beginDict(EmptyArrayOption option = SkipIfEmpty);
- bool nextDictEntry(); // like nextArrayEntry()
void skipDict(); // like skipArray()
void endDict(); // like endArray()
@@ -259,7 +254,6 @@ public:
void advanceStateFrom(IoState expectedState);
void beginArrayOrDict(bool isDict, EmptyArrayOption option);
void skipArrayOrDictSignature(bool isDict);
- bool nextArrayOrDictEntry(bool isDict);
void skipArrayOrDict(bool isDict);
void skipCurrentAggregate();
@@ -299,13 +293,9 @@ public:
};
void beginArray(ArrayOption option = NonEmptyArray);
- // call this before writing each entry; calling it before the first entry is \
optional for
- // the convenience of client code.
- void nextArrayEntry();
void endArray();
void beginDict(ArrayOption option = NonEmptyArray);
- void nextDictEntry();
void endDict();
void beginStruct();
@@ -343,7 +333,6 @@ public:
void doWriteString(uint32 lengthPrefixSize);
void advanceState(cstring signatureFragment, IoState newState);
void beginArrayOrDict(bool isDict, bool isEmpty);
- void nextArrayOrDictEntry(bool isDict);
void finishInternal();
Private *d;
diff --git a/serialization/message.cpp b/serialization/message.cpp
index b8e6423..32b5054 100644
--- a/serialization/message.cpp
+++ b/serialization/message.cpp
@@ -964,7 +964,7 @@ bool MessagePrivate::deserializeVariableHeaders()
}
reader.beginArray();
- while (reader.nextArrayEntry()) {
+ while (reader.state() == Arguments::BeginStruct) {
reader.beginStruct();
const byte headerField = reader.readByte();
if (headerField < Message::PathHeader || headerField > \
Message::UnixFdsHeader) { @@ -1099,7 +1099,6 @@ void \
MessagePrivate::serializeFixedHeaders()
static void doVarHeaderPrologue(Arguments::Writer *writer, Message::VariableHeader \
field) {
- writer->nextArrayEntry();
writer->beginStruct();
writer->writeByte(byte(field));
writer->beginVariant();
diff --git a/tests/serialization/tst_arguments.cpp \
b/tests/serialization/tst_arguments.cpp index a158194..8f6ec98 100644
--- a/tests/serialization/tst_arguments.cpp
+++ b/tests/serialization/tst_arguments.cpp
@@ -78,7 +78,6 @@ public:
int skipAggregatesFromLevel, int skipNilArraysFromLevel)
: m_nestingLevel(0),
m_nilArrayNesting(0),
- m_calledNextOnCurrentNilArray(true), // intentionally "wrong" value to \
tease out errors m_skipAggregatesFromLevel(skipAggregatesFromLevel),
m_skipNilArraysFromLevel(skipNilArraysFromLevel),
m_reader(reader),
@@ -128,39 +127,17 @@ public:
(*m_skippingReader.*skipFunc)();
} else if (m_nilArrayNesting == m_skipNilArraysFromLevel) {
(*m_skippingReader.*beginFunc)(Arguments::Reader::SkipIfEmpty);
- // it's not necessary to track nesting levels for this because next must \
be called only
- // exactly once and directly after begin, for which a simple bool is \
sufficient
- m_calledNextOnCurrentNilArray = false;
} else {
(*m_skippingReader.*beginFunc)(Arguments::Reader::ReadTypesOnlyIfEmpty);
}
}
template<typename F>
- void nextArrayEntry(F nextFunc)
- {
- (*m_reader.*nextFunc)();
- // when skipping a nil array, the sequence is beginArray(), nexArrayEntry(), \
endArray(),
- // so still call next*Entry() once when skipping the current nil array
-
- if (m_nestingLevel < m_skipAggregatesFromLevel) {
- if (m_nilArrayNesting < m_skipNilArraysFromLevel) {
- (*m_skippingReader.*nextFunc)();
- } else if (m_nilArrayNesting == m_skipNilArraysFromLevel && \
!m_calledNextOnCurrentNilArray) {
- // when skipping a nil array, the sequence is beginArray(), \
nexArrayEntry(), endArray(),
- // so still call next*Entry() once when skipping the current nil \
array
- m_calledNextOnCurrentNilArray = true;
- (*m_skippingReader.*nextFunc)();
- }
- }
- }
-
- template<typename F>
void endAggregate(F endFunc, bool isArrayType)
{
(*m_reader.*endFunc)();
- // when skipping a nil array: do the last part of the beginArray(), \
nextArrayEntry(), endArray() sequence + // when skipping a nil array: do the \
last part of the beginArray(), endArray() sequence
// when using skip*(): do not call end() on that level, skip*() moves right \
past the aggregate if (m_nestingLevel < m_skipAggregatesFromLevel &&
(m_nilArrayNesting < m_skipNilArraysFromLevel ||
@@ -178,7 +155,6 @@ public:
int m_nestingLevel;
int m_nilArrayNesting;
- bool m_calledNextOnCurrentNilArray;
const int m_skipAggregatesFromLevel;
const int m_skipNilArraysFromLevel;
@@ -243,18 +219,12 @@ static void testReadWithSkip(const Arguments &arg, bool \
debugPrint) case Arguments::BeginArray:
checker.beginArrayAggregate(&Arguments::Reader::beginArray, \
&Arguments::Reader::skipArray); break;
- case Arguments::NextArrayEntry:
- checker.nextArrayEntry(&Arguments::Reader::nextArrayEntry);
- break;
case Arguments::EndArray:
checker.endAggregate(&Arguments::Reader::endArray, true);
break;
case Arguments::BeginDict:
checker.beginArrayAggregate(&Arguments::Reader::beginDict, \
&Arguments::Reader::skipDict); break;
- case Arguments::NextDictEntry:
- checker.nextArrayEntry(&Arguments::Reader::nextDictEntry);
- break;
case Arguments::EndDict:
checker.endAggregate(&Arguments::Reader::endDict, true);
break;
@@ -312,8 +282,7 @@ static void testReadWithSkip(const Arguments &arg, bool \
debugPrint) }
}
-static void doRoundtripForReal(const Arguments &original, bool \
skipNextEntryAtArrayStart,
- uint32 dataIncrement, bool debugPrint)
+static void doRoundtripForReal(const Arguments &original, uint32 dataIncrement, bool \
debugPrint) {
Arguments::Reader reader(original);
Arguments::Writer writer;
@@ -322,7 +291,6 @@ static void doRoundtripForReal(const Arguments &original, bool \
skipNextEntryAtAr chunk shortData;
bool isDone = false;
uint32 emptyNesting = 0;
- bool isFirstEntry = false;
while (!isDone) {
TEST(writer.state() != Arguments::InvalidData);
@@ -370,42 +338,22 @@ static void doRoundtripForReal(const Arguments &original, bool \
skipNextEntryAtAr writer.endVariant();
break;
case Arguments::BeginArray: {
- isFirstEntry = true;
const bool hasData = \
reader.beginArray(Arguments::Reader::ReadTypesOnlyIfEmpty); \
writer.beginArray(hasData ? Arguments::Writer::NonEmptyArray
: Arguments::Writer::WriteTypesOfEmptyArray);
emptyNesting += hasData ? 0 : 1;
break; }
- case Arguments::NextArrayEntry:
- if (reader.nextArrayEntry()) {
- if (isFirstEntry && skipNextEntryAtArrayStart) {
- isFirstEntry = false;
- } else {
- writer.nextArrayEntry();
- }
- }
- break;
case Arguments::EndArray:
reader.endArray();
writer.endArray();
emptyNesting = std::max(emptyNesting - 1, 0u);
break;
case Arguments::BeginDict: {
- isFirstEntry = true;
const bool hasData = \
reader.beginDict(Arguments::Reader::ReadTypesOnlyIfEmpty); writer.beginDict(hasData \
? Arguments::Writer::NonEmptyArray
: Arguments::Writer::WriteTypesOfEmptyArray);
emptyNesting += hasData ? 0 : 1;
break; }
- case Arguments::NextDictEntry:
- if (reader.nextDictEntry()) {
- if (isFirstEntry && skipNextEntryAtArrayStart) {
- isFirstEntry = false;
- } else {
- writer.nextDictEntry();
- }
- }
- break;
case Arguments::EndDict:
reader.endDict();
writer.endDict();
@@ -518,35 +466,34 @@ static void shallowAssign(Arguments *copy, const Arguments \
&original)
*copy = Arguments(nullptr, signature, data);
}
-static void doRoundtripWithCopyAssignEtc(const Arguments &arg_in, bool \
skipNextEntryAtArrayStart,
- uint32 dataIncrement, bool debugPrint)
+static void doRoundtripWithCopyAssignEtc(const Arguments &arg_in, uint32 \
dataIncrement, bool debugPrint) {
{
// just pass through
- doRoundtripForReal(arg_in, skipNextEntryAtArrayStart, dataIncrement, \
debugPrint); + doRoundtripForReal(arg_in, dataIncrement, debugPrint);
}
{
// shallow copy
Arguments *shallowDuplicate = shallowCopy(arg_in);
- doRoundtripForReal(*shallowDuplicate, skipNextEntryAtArrayStart, \
dataIncrement, debugPrint); + doRoundtripForReal(*shallowDuplicate, \
dataIncrement, debugPrint); delete shallowDuplicate;
}
{
// assignment from shallow copy
Arguments shallowAssigned;
shallowAssign(&shallowAssigned, arg_in);
- doRoundtripForReal(shallowAssigned, skipNextEntryAtArrayStart, \
dataIncrement, debugPrint); + doRoundtripForReal(shallowAssigned, \
dataIncrement, debugPrint); }
{
// deep copy
Arguments original(arg_in);
- doRoundtripForReal(original, skipNextEntryAtArrayStart, dataIncrement, \
debugPrint); + doRoundtripForReal(original, dataIncrement, debugPrint);
}
{
// move construction from shallow copy
Arguments *shallowDuplicate = shallowCopy(arg_in);
Arguments shallowMoveConstructed(std::move(*shallowDuplicate));
- doRoundtripForReal(shallowMoveConstructed, skipNextEntryAtArrayStart, \
dataIncrement, debugPrint); + doRoundtripForReal(shallowMoveConstructed, \
dataIncrement, debugPrint); delete shallowDuplicate;
}
{
@@ -554,21 +501,21 @@ static void doRoundtripWithCopyAssignEtc(const Arguments \
&arg_in, bool skipNextE Arguments *shallowDuplicate = shallowCopy(arg_in);
Arguments shallowMoveAssigned;
shallowMoveAssigned = std::move(*shallowDuplicate);
- doRoundtripForReal(shallowMoveAssigned, skipNextEntryAtArrayStart, \
dataIncrement, debugPrint); + doRoundtripForReal(shallowMoveAssigned, \
dataIncrement, debugPrint); delete shallowDuplicate;
}
{
// move construction from deep copy
Arguments duplicate(arg_in);
Arguments moveConstructed(std::move(duplicate));
- doRoundtripForReal(moveConstructed, skipNextEntryAtArrayStart, \
dataIncrement, debugPrint); + doRoundtripForReal(moveConstructed, \
dataIncrement, debugPrint); }
{
// move assignment (hopefully, may the compiler optimize this to \
move-construction?) from deep copy Arguments duplicate(arg_in);
Arguments moveAssigned;
moveAssigned = std::move(duplicate);
- doRoundtripForReal(moveAssigned, skipNextEntryAtArrayStart, dataIncrement, \
debugPrint); + doRoundtripForReal(moveAssigned, dataIncrement, debugPrint);
}
}
@@ -576,8 +523,7 @@ static void doRoundtrip(const Arguments &arg, bool debugPrint = \
false) {
const uint32 maxIncrement = arg.data().length;
for (uint32 i = 1; i <= maxIncrement; i++) {
- doRoundtripWithCopyAssignEtc(arg, false, i, debugPrint);
- doRoundtripWithCopyAssignEtc(arg, true, i, debugPrint);
+ doRoundtripWithCopyAssignEtc(arg, i, debugPrint);
}
testReadWithSkip(arg, debugPrint);
@@ -689,7 +635,6 @@ static void test_nesting()
Arguments::Writer writer;
for (int i = 0; i < 32; i++) {
writer.beginArray();
- writer.nextArrayEntry();
}
TEST(writer.state() != Arguments::InvalidData);
writer.beginArray();
@@ -699,7 +644,6 @@ static void test_nesting()
Arguments::Writer writer;
for (int i = 0; i < 32; i++) {
writer.beginDict();
- writer.nextDictEntry();
writer.writeInt32(i); // key, next nested dict is value
}
TEST(writer.state() != Arguments::InvalidData);
@@ -710,7 +654,6 @@ static void test_nesting()
Arguments::Writer writer;
for (int i = 0; i < 32; i++) {
writer.beginDict();
- writer.nextDictEntry();
writer.writeInt32(i); // key, next nested dict is value
}
TEST(writer.state() != Arguments::InvalidData);
@@ -833,30 +776,26 @@ static void test_writerMisuse()
{
Arguments::Writer writer;
writer.beginArray();
- writer.writeByte(1); // in Writer, calling nextArrayEntry() after \
beginArray() is optional + writer.writeByte(1);
writer.endArray();
TEST(writer.state() != Arguments::InvalidData);
}
{
Arguments::Writer writer;
writer.beginArray();
- writer.nextArrayEntry(); // optional and may not trigger an error
- TEST(writer.state() != Arguments::InvalidData);
writer.endArray(); // wrong, must contain exactly one type
TEST(writer.state() == Arguments::InvalidData);
}
{
Arguments::Writer writer;
writer.beginArray();
- writer.nextArrayEntry();
writer.writeByte(1);
- writer.writeByte(2); // wrong, must contain exactly one type
+ writer.writeUint16(2); // wrong, different from first element
TEST(writer.state() == Arguments::InvalidData);
}
{
Arguments::Writer writer;
writer.beginArray(Arguments::Writer::WriteTypesOfEmptyArray);
- writer.nextArrayEntry();
writer.beginVariant();
writer.endVariant(); // empty variants are okay if and only if inside an \
empty array writer.endArray();
@@ -872,7 +811,6 @@ static void test_writerMisuse()
{
Arguments::Writer writer;
writer.beginDict();
- writer.nextDictEntry();
writer.writeByte(1);
writer.endDict(); // wrong, a dict must contain exactly two types
TEST(writer.state() == Arguments::InvalidData);
@@ -888,17 +826,28 @@ static void test_writerMisuse()
{
Arguments::Writer writer;
writer.beginDict();
- writer.nextDictEntry();
writer.writeByte(1);
writer.writeByte(2);
+ // second key-value pair
+ TEST(writer.state() != Arguments::InvalidData);
+ writer.writeUint16(3); // wrong, incompatible with first element
+ TEST(writer.state() == Arguments::InvalidData);
+ }
+ {
+ Arguments::Writer writer;
+ writer.beginDict();
+ writer.writeByte(1);
+ writer.writeByte(2);
+ // second key-value pair
+ writer.writeByte(3);
TEST(writer.state() != Arguments::InvalidData);
- writer.writeByte(3); // wrong, a dict contains only exactly two types
+ writer.writeUint16(4); // wrong, incompatible with first element
TEST(writer.state() == Arguments::InvalidData);
}
+
{
Arguments::Writer writer;
writer.beginDict();
- writer.nextDictEntry();
writer.beginVariant(); // wrong, key type must be basic
TEST(writer.state() == Arguments::InvalidData);
}
@@ -991,23 +940,21 @@ static void test_complicated()
writer.beginVariant();
writer.writeString(cstring("twenty-three"));
writer.endVariant();
- writer.nextDictEntry();
+ // key-value pair 2
writer.writeByte(83);
writer.beginVariant();
writer.writeObjectPath(cstring("/foo/bar/object"));
writer.endVariant();
- writer.nextDictEntry();
+ // key-value pair 3
writer.writeByte(234);
writer.beginVariant();
writer.beginArray();
writer.writeUint16(234);
- writer.nextArrayEntry();
writer.writeUint16(234);
- writer.nextArrayEntry();
writer.writeUint16(234);
writer.endArray();
writer.endVariant();
- writer.nextDictEntry();
+ // key-value pair 4
writer.writeByte(25);
writer.beginVariant();
addSomeVariantStuff(&writer);
@@ -1017,11 +964,8 @@ static void test_complicated()
writer.writeString("Hello D-Bus!");
writer.beginArray();
writer.writeDouble(1.567898);
- writer.nextArrayEntry();
writer.writeDouble(1.523428);
- writer.nextArrayEntry();
writer.writeDouble(1.621133);
- writer.nextArrayEntry();
writer.writeDouble(1.982342);
writer.endArray();
TEST(writer.state() != Arguments::InvalidData);
@@ -1040,8 +984,7 @@ static void test_alignment()
writer.beginArray();
writer.writeByte(64);
writer.endArray();
- writer.writeByte(123);
- for (int i = 124; i < 150; i++) {
+ for (int i = 123; i < 150; i++) {
writer.writeByte(i);
}
@@ -1239,7 +1182,6 @@ void test_primitiveArray()
byte *testDataPtr = testData;
if (arraySize) {
for (uint m = 0; m < arraySize; m++) {
- writer.nextArrayEntry();
writeValue(&writer, typeInArray, testDataPtr);
testDataPtr += 1 << (typeInArray - 1);
}
@@ -1278,21 +1220,18 @@ void test_primitiveArray()
if (arraySize) {
for (uint m = 0; m < arraySize; m++) {
TEST(reader.state() != Arguments::InvalidData);
- TEST(reader.nextArrayEntry());
TEST(checkValue(&reader, typeInArray, \
testDataPtr));
TEST(reader.state() != Arguments::InvalidData);
testDataPtr += 1 << (typeInArray - 1);
}
} else {
- TEST(reader.nextArrayEntry());
TEST(reader.state() == arrayTypes[typeInArray]);
// next: dummy read, necessary to move forward; \
value is ignored
checkValue(&reader, typeInArray, testDataPtr);
TEST(reader.state() != Arguments::InvalidData);
}
- TEST(!reader.nextArrayEntry());
- TEST(reader.state() != Arguments::InvalidData);
+ TEST(reader.state() == Arguments::EndArray);
reader.endArray();
TEST(reader.state() != Arguments::InvalidData);
}
@@ -1329,16 +1268,15 @@ void test_signatureLengths()
// The full doRoundtrip() just here makes this whole file take several \
seconds to execute // instead of a fraction of a second. This way is much quicker.
- doRoundtripForReal(arg, false, 2048, false);
+ doRoundtripForReal(arg, 2048, false);
Arguments argCopy = arg;
- doRoundtripForReal(argCopy, false, 2048, false);
+ doRoundtripForReal(argCopy, 2048, false);
}
}
void test_emptyArrayAndDict()
{
// Arrays
-
{
Arguments::Writer writer;
writer.beginArray(Arguments::Writer::WriteTypesOfEmptyArray);
@@ -1436,7 +1374,6 @@ void test_emptyArrayAndDict()
writer.beginArray(i ? Arguments::Writer::NonEmptyArray
: Arguments::Writer::WriteTypesOfEmptyArray);
for (int j = 0; j < std::max(i, 1); j++) {
- writer.nextArrayEntry();
writer.writeUint16(52345);
}
writer.endArray();
@@ -1456,7 +1393,6 @@ void test_emptyArrayAndDict()
if (j == 32) {
TEST(writer.state() == Arguments::InvalidData);
}
- writer.nextArrayEntry();
}
if (i == 32) {
TEST(writer.state() == Arguments::InvalidData);
@@ -1505,7 +1441,7 @@ void test_emptyArrayAndDict()
writer.beginVariant();
writer.endVariant();
TEST(writer.state() != Arguments::InvalidData);
- writer.nextDictEntry();
+ writer.writeString(cstring("a"));
TEST(writer.state() == Arguments::InvalidData);
}
{
@@ -1531,7 +1467,6 @@ void test_emptyArrayAndDict()
if (j == 32) {
TEST(writer.state() == Arguments::InvalidData);
}
- writer.nextDictEntry();
writer.writeUint16(12345);
}
if (i == 32) {
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic