Git commit 71b024e3cddec25750592df20eee2315f981a771 by Andreas Hartmetz. Committed on 28/10/2016 at 18:21. Pushed by ahartmetz into branch 'master'. Allow to restart an array / dict as empty if not yet written to. This is needed in client code where the number of elements is not known at the time beginArray/Dict() is called, but there is enough information for a late fix-up. As happens to be the case in QtDBus. This is just a little hack to solve a specific problem and should not be the first choice when writing possibly empty arrays. M +32 -7 serialization/arguments.cpp M +3 -2 serialization/arguments.h M +1 -0 util/error.h http://commits.kde.org/dferry/71b024e3cddec25750592df20eee2315f981a771 diff --git a/serialization/arguments.cpp b/serialization/arguments.cpp index 8bd2ffd..0e87009 100644 --- a/serialization/arguments.cpp +++ b/serialization/arguments.cpp @@ -2228,9 +2228,34 @@ void Arguments::Writer::advanceState(cstring signatu= reFragment, IoState newState m_state =3D AnyData; } = -void Arguments::Writer::beginArrayOrDict(bool isDict, bool isEmpty) +void Arguments::Writer::beginArrayOrDict(IoState beginWhat, ArrayOption op= tion) { - isEmpty =3D isEmpty || d->m_nilArrayNesting; + assert(beginWhat =3D=3D BeginArray || beginWhat =3D=3D BeginDict); + if (unlikely(option =3D=3D RestartEmptyArrayToWriteTypes)) { + if (!d->m_aggregateStack.empty()) { + Private::AggregateInfo &aggregateInfo =3D d->m_aggregateStack.= back(); + if (aggregateInfo.aggregateType =3D=3D beginWhat) { + // No writes to the array or dict may have occurred yet + if (d->m_signature.length =3D=3D aggregateInfo.arr.contain= edTypeBegin) { + // Fix up state as if beginArray/Dict() had been calle= d with WriteTypesOfEmptyArray + // in the first place. After that small fixup we're do= ne and return. + // The code is a slightly modified version of code bel= ow under: if (isEmpty) { + if (!d->m_nilArrayNesting) { + d->m_nilArrayNesting =3D 1; + d->m_dataElementsCountBeforeNilArray =3D d->m_elem= ents.size() + 1; + d->m_dataPositionBeforeNilArray =3D d->m_dataPosit= ion; + } else { + // The array may be implicitly nil (so our poor AP= I client doesn't notice) because + // an array below in the aggregate stack is nil, s= o just allow this as a no-op. + } + return; + } + } + } + VALID_IF(false, Error::InvalidStateToRestartEmptyArray); + } + + const bool isEmpty =3D (option !=3D NonEmptyArray) || d->m_nilArrayNes= ting; if (isEmpty) { if (!d->m_nilArrayNesting++) { // For simplictiy and performance in the fast path, we keep st= oring the data chunks and any @@ -2241,16 +2266,16 @@ void Arguments::Writer::beginArrayOrDict(bool isDic= t, bool isEmpty) d->m_dataPositionBeforeNilArray =3D d->m_dataPosition; } } - if (isDict) { - advanceState(cstring("a{", strlen("a{")), BeginDict); + if (beginWhat =3D=3D BeginArray) { + advanceState(cstring("a", strlen("a")), beginWhat); } else { - advanceState(cstring("a", strlen("a")), BeginArray); + advanceState(cstring("a{", strlen("a{")), beginWhat); } } = void Arguments::Writer::beginArray(ArrayOption option) { - beginArrayOrDict(false, option =3D=3D WriteTypesOfEmptyArray); + beginArrayOrDict(BeginArray, option); } = void Arguments::Writer::endArray() @@ -2260,7 +2285,7 @@ void Arguments::Writer::endArray() = void Arguments::Writer::beginDict(ArrayOption option) { - beginArrayOrDict(true, option =3D=3D WriteTypesOfEmptyArray); + beginArrayOrDict(BeginDict, option); } = void Arguments::Writer::endDict() diff --git a/serialization/arguments.h b/serialization/arguments.h index 5eb6087..4081e26 100644 --- a/serialization/arguments.h +++ b/serialization/arguments.h @@ -296,7 +296,8 @@ public: enum ArrayOption { NonEmptyArray =3D 0, - WriteTypesOfEmptyArray + WriteTypesOfEmptyArray, + RestartEmptyArrayToWriteTypes }; = void beginArray(ArrayOption option =3D NonEmptyArray); @@ -340,7 +341,7 @@ public: void doWritePrimitiveType(uint32 alignAndSize); void doWriteString(uint32 lengthPrefixSize); void advanceState(cstring signatureFragment, IoState newState); - void beginArrayOrDict(bool isDict, bool isEmpty); + void beginArrayOrDict(IoState beginWhat, ArrayOption option); void finishInternal(); = Private *d; diff --git a/util/error.h b/util/error.h index 38c283d..247da72 100644 --- a/util/error.h +++ b/util/error.h @@ -72,6 +72,7 @@ public: CannotEndArrayOrDictHere, TooFewTypesInArrayOrDict, ExtraIterationInEmptyArray, + InvalidStateToRestartEmptyArray, InvalidKeyTypeInDict, GreaterTwoTypesInDict, ArrayOrDictTooLong,