[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