From kde-commits Thu Nov 17 01:34:24 2016 From: Andreas Hartmetz Date: Thu, 17 Nov 2016 01:34:24 +0000 To: kde-commits Subject: [dferry] /: Help reduce boilerplate when copying from Reader to Writer. Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=147934647601200 Git commit 73cef05cdc1655cb0d1e0f6cbe8873d5548c82c7 by Andreas Hartmetz. Committed on 17/11/2016 at 00:46. Pushed by ahartmetz into branch 'master'. Help reduce boilerplate when copying from Reader to Writer. This is not only useful in the tests. M +107 -0 serialization/arguments.cpp M +5 -0 serialization/arguments.h M +14 -46 tests/serialization/tst_arguments.cpp http://commits.kde.org/dferry/73cef05cdc1655cb0d1e0f6cbe8873d5548c82c7 diff --git a/serialization/arguments.cpp b/serialization/arguments.cpp index 731f23b..3d61e3d 100644 --- a/serialization/arguments.cpp +++ b/serialization/arguments.cpp @@ -51,6 +51,113 @@ static byte alignmentLog2(uint32 alignment) return alignLog[alignment]; } = +// When using this to iterate over the reader, it will make an exact copy = using the Writer. +// You need to do something only in states where something special should = happen. +// To check errors, "simply" (sorry!) check the reader->state() and writer= ()->state(). +// Note that you don't have to check the state before each element, it is = fine to call +// read / write functions in error state, including with garbage data from= the possibly +// invalid reader, and the reader / writer state will remain frozen in the= state in which +// the first error occurred +// TODO: that text above belongs into a "Reader and Writer state / errors"= explanation of the docs + +// static +void Arguments::copyOneElement(Arguments::Reader *reader, Arguments::Write= r *writer) +{ + switch(reader->state()) { + case Arguments::BeginStruct: + reader->beginStruct(); + writer->beginStruct(); + break; + case Arguments::EndStruct: + reader->endStruct(); + writer->endStruct(); + break; + case Arguments::BeginVariant: + reader->beginVariant(); + writer->beginVariant(); + break; + case Arguments::EndVariant: + reader->endVariant(); + writer->endVariant(); + break; + case Arguments::BeginArray: { + // Application note: to avoid handling arrays as primitive (where = applicable), just don't + // call this function in BeginArray state and do as in the else ca= se. + const Arguments::IoState primitiveType =3D reader->peekPrimitiveAr= ray(); + if (primitiveType !=3D BeginArray) { // InvalidData can't happen b= ecause the state *is* BeginArray + const std::pair arrayData =3D reade= r->readPrimitiveArray(); + writer->writePrimitiveArray(arrayData.first, arrayData.second); + } else { + const bool hasData =3D reader->beginArray(Arguments::Reader::R= eadTypesOnlyIfEmpty); + writer->beginArray(hasData ? Arguments::Writer::NonEmptyArray + : Arguments::Writer::WriteTypesOfEm= ptyArray); + } + break; } + case Arguments::EndArray: + reader->endArray(); + writer->endArray(); + break; + case Arguments::BeginDict: { + const bool hasData =3D reader->beginDict(Arguments::Reader::ReadTy= pesOnlyIfEmpty); + writer->beginDict(hasData ? Arguments::Writer::NonEmptyArray + : Arguments::Writer::WriteTypesOfEmpty= Array); + break; } + case Arguments::EndDict: + reader->endDict(); + writer->endDict(); + break; + case Arguments::Byte: + writer->writeByte(reader->readByte()); + break; + case Arguments::Boolean: + writer->writeBoolean(reader->readBoolean()); + break; + case Arguments::Int16: + writer->writeInt16(reader->readInt16()); + break; + case Arguments::Uint16: + writer->writeUint16(reader->readUint16()); + break; + case Arguments::Int32: + writer->writeInt32(reader->readInt32()); + break; + case Arguments::Uint32: + writer->writeUint32(reader->readUint32()); + break; + case Arguments::Int64: + writer->writeInt64(reader->readInt64()); + break; + case Arguments::Uint64: + writer->writeUint64(reader->readUint64()); + break; + case Arguments::Double: + writer->writeDouble(reader->readDouble()); + break; + case Arguments::String: { + const cstring s =3D reader->readString(); + writer->writeString(s); + break; } + case Arguments::ObjectPath: { + const cstring objectPath =3D reader->readObjectPath(); + writer->writeObjectPath(objectPath); + break; } + case Arguments::Signature: { + const cstring signature =3D reader->readSignature(); + writer->writeSignature(signature); + break; } + case Arguments::UnixFd: + writer->writeUnixFd(reader->readUnixFd()); + break; + // special cases follow + case Arguments::Finished: + break; // You *probably* want to handle that one in the caller, bu= t you don't have to + case Arguments::NeedMoreData: + break; // No way to handle that one here + default: + break; // dito + } +} + // helper to verify the max nesting requirements of the d-bus spec struct Nesting { diff --git a/serialization/arguments.h b/serialization/arguments.h index 5d86866..781baed 100644 --- a/serialization/arguments.h +++ b/serialization/arguments.h @@ -37,6 +37,9 @@ class Message; class DFERRY_EXPORT Arguments { public: + class Reader; + class Writer; + enum SignatureType { MethodSignature =3D 0, @@ -126,6 +129,8 @@ public: static bool isObjectPathElementValid(cstring pathElement); static bool isSignatureValid(cstring signature, SignatureType type =3D= MethodSignature); = + static void copyOneElement(Reader *reader, Writer *writer); + private: struct podCstring // Same as cstring but without ctor. // Can't put the cstring type into a union because i= t has a constructor :/ diff --git a/tests/serialization/tst_arguments.cpp b/tests/serialization/ts= t_arguments.cpp index c8a04fd..d2dabf9 100644 --- a/tests/serialization/tst_arguments.cpp +++ b/tests/serialization/tst_arguments.cpp @@ -288,66 +288,34 @@ static void defaultReadToWrite(Arguments::Reader *rea= der, Arguments::Writer *wri { switch(reader->state()) { case Arguments::BeginStruct: - reader->beginStruct(); - writer->beginStruct(); - break; case Arguments::EndStruct: - reader->endStruct(); - writer->endStruct(); - break; case Arguments::BeginVariant: - reader->beginVariant(); - writer->beginVariant(); - break; case Arguments::EndVariant: - reader->endVariant(); - writer->endVariant(); - break; - case Arguments::BeginArray: { - const bool hasData =3D reader->beginArray(Arguments::Reader::ReadT= ypesOnlyIfEmpty); - writer->beginArray(hasData ? Arguments::Writer::NonEmptyArray - : Arguments::Writer::WriteTypesOfEmpty= Array); - break; } case Arguments::EndArray: - reader->endArray(); - writer->endArray(); - break; - case Arguments::BeginDict: { - const bool hasData =3D reader->beginDict(Arguments::Reader::ReadTy= pesOnlyIfEmpty); - writer->beginDict(hasData ? Arguments::Writer::NonEmptyArray - : Arguments::Writer::WriteTypesOfEmpty= Array); - break; } case Arguments::EndDict: - reader->endDict(); - writer->endDict(); - break; case Arguments::Byte: - writer->writeByte(reader->readByte()); - break; case Arguments::Boolean: - writer->writeBoolean(reader->readBoolean()); - break; case Arguments::Int16: - writer->writeInt16(reader->readInt16()); - break; case Arguments::Uint16: - writer->writeUint16(reader->readUint16()); - break; case Arguments::Int32: - writer->writeInt32(reader->readInt32()); - break; case Arguments::Uint32: - writer->writeUint32(reader->readUint32()); - break; case Arguments::Int64: - writer->writeInt64(reader->readInt64()); - break; case Arguments::Uint64: - writer->writeUint64(reader->readUint64()); - break; case Arguments::Double: - writer->writeDouble(reader->readDouble()); + case Arguments::UnixFd: + Arguments::copyOneElement(reader, writer); break; + // special handling for BeginArray and BeginDict to avoid "fast copy" = for primitive arrays + case Arguments::BeginArray: { + const bool hasData =3D reader->beginArray(Arguments::Reader::ReadT= ypesOnlyIfEmpty); + writer->beginArray(hasData ? Arguments::Writer::NonEmptyArray + : Arguments::Writer::WriteTypesOfEmpty= Array); + break; } + case Arguments::BeginDict: { + const bool hasData =3D reader->beginDict(Arguments::Reader::ReadTy= pesOnlyIfEmpty); + writer->beginDict(hasData ? Arguments::Writer::NonEmptyArray + : Arguments::Writer::WriteTypesOfEmpty= Array); + break; } case Arguments::String: { const cstring s =3D reader->readString(); if (!reader->isInsideEmptyArray()) { @@ -369,7 +337,7 @@ static void defaultReadToWrite(Arguments::Reader *reade= r, Arguments::Writer *wri } writer->writeSignature(signature); break; } - case Arguments::UnixFd: + writer->writeUnixFd(reader->readUnixFd()); break; // special cases follow