From 9fb7885893067b5924aac26502433cec7212d6c7 Mon Sep 17 00:00:00 2001 From: Alan Conway Date: Thu, 3 Apr 2008 17:23:34 +0000 Subject: src/qpid/amqp_0_10/Map.h,.cpp: use preview encoding temporarily. Misc cleanup for 0-10 encoding. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@644413 13f79535-47bb-0310-9956-ffa450edef68 --- cpp/src/qpid/Serializer.h | 131 +++++++++++++++++++++----------- cpp/src/qpid/amqp_0_10/Codec.h | 42 ++++------ cpp/src/qpid/amqp_0_10/Map.cpp | 13 ++-- cpp/src/qpid/amqp_0_10/Map.h | 23 ++++-- cpp/src/qpid/amqp_0_10/PackedCodec.h | 2 +- cpp/src/qpid/amqp_0_10/Segment.h | 1 + cpp/src/qpid/amqp_0_10/built_in_types.h | 20 ++--- cpp/src/tests/amqp_0_10/Map.cpp | 5 -- cpp/src/tests/serialize.cpp | 7 -- 9 files changed, 129 insertions(+), 115 deletions(-) (limited to 'cpp/src') diff --git a/cpp/src/qpid/Serializer.h b/cpp/src/qpid/Serializer.h index 12bcded0f7..6ff701f346 100644 --- a/cpp/src/qpid/Serializer.h +++ b/cpp/src/qpid/Serializer.h @@ -22,82 +22,121 @@ * */ -#include -#include +#include namespace qpid { -namespace serialize { - -/** Wrapper to pass serializer functors by reference. */ -template struct SRef { - S& s; - SRef(S& ss) : s(ss) {} - template typename S::result_type operator()(T& x) { return s(x); } - template typename S::result_type operator()(const T& x) { return s(x); } -}; - -template SRef ref(S& s) { return SRef(s); } -// FIXME aconway 2008-03-03: Document. -// Encoder/Decoder concept: add op() for primitive types, raw(), -// op()(Iter, Iter). Note split, encode, decode. -// +/** + * Overload for types that do not provide a serialize() member. + * It should retrun a wrapper holding a reference to t that implements + * serialize() + */ +template T& serializable(T& t) { return t; } -// FIXME aconway 2008-03-09: document - non-intrusive serialzation. -// Default rule calls member. Enums must provide an override rule. +/** Serialize std::pair */ +template struct SerializablePair { + std::pair& value; + SerializablePair(std::pair& x) : value(x) {} + template void serialize(S& s) { s(value.first)(value.second); } +}; -/** Overload for types that do not provide a serialize() member.*/ -template T& serializable(T& t) { return t; } +template +SerializablePair serializable(std::pair& p) { + return SerializablePair(p); +} -template class Encoder { +/** + * Base class for all serializers. + * Derived serializers inherit from either Encoder or Decoder. + * Serializers can be used as functors or static_visitors. + */ +template class Serializer { public: typedef Derived& result_type; // unary functor requirement. - /** Default op() calls serializable() free function */ - template - Derived& operator()(const T& t) { + /** Wrapper functor to pass serializer functors by reference. */ + template struct Ref { + typedef typename S::result_type result_type; + S& s; + Ref(S& ss) : s(ss) {} + template result_type operator()(T& x) { return s(x); } + template result_type operator()(const T& x) { return s(x); } + }; + + /** Reference wrapper to pass serializers by reference, + * e.g. to std:: functions that take functors. + */ + template static Ref ref(S& s) { return Ref(s); } + + /** Generic rule to serialize an iterator range */ + template Derived& operator()(Iter begin, Iter end) { + std::for_each(begin, end, ref(this->self())); + return self(); + } + + protected: + Derived& self() { return *static_cast(this); } +}; + +/** + * Base class for encoders, provides generic encode functions. + * + * A derived encoder must provide operator(const T&) to encode all + * primitive types T. + */ +template class EncoderBase : public Serializer { + public: + using Serializer::operator(); + using Serializer::self; + + /** Default op() for non-primitive types. */ + template Derived& operator()(const T& t) { serializable(const_cast(t)).serialize(self()); return self(); } /** Split serialize() into encode()/decode() */ - template - Derived& split(const T& t) { t.encode(self()); return self(); } - - private: - Derived& self() { return *static_cast(this); } + template Derived& split(const T& t) { + t.encode(self()); return self(); + } }; -template class Decoder { +/** + * Base class for decoders, provides generic decode functions. + * + * A derived encoder must provide operator(T&) to encode all + * primitive types T. + */ +template class DecoderBase : public Serializer { public: - typedef Derived& result_type; // unary functor requirement. + using Serializer::operator(); + using Serializer::self; - /** Default op() calls serializable() free function */ - template - Derived& operator()(T& t) { + /** Default op() for non-primitive types. */ + template Derived& operator()(T& t) { serializable(t).serialize(self()); return self(); } /** Split serialize() into encode()/decode() */ - template - Derived& split(T& t) { t.decode(self()); return self(); } - - - private: - Derived& self() { return *static_cast(this); } + template Derived& split(T& t) { + t.decode(self()); return self(); + } }; -/** Serialize a type by converting it to/from another type */ +/** Serialize a type by converting it to/from another type. + * To serialize type Foo by converting to/from type Bar create + * a serializable() overload like this: + * + * SerializeAs serializable(Foo& t) { return SerializeAs(t); } + */ template struct SerializeAs { Type& value; SerializeAs(Type & t) : value(t) {} template void serialize(S& s) { s.split(*this); } template void encode(S& s) const { s(AsType(value)); } - template void decode(S& s) { AsType x; s(x); value=x; } + template void decode(S& s) { AsType x; s(x); value=Type(x); } }; -}} // namespace qpid::serialize +} // namespace qpid -// FIXME aconway 2008-03-09: rename to serialize.h -// #endif /*!QPID_SERIALIZER_H*/ diff --git a/cpp/src/qpid/amqp_0_10/Codec.h b/cpp/src/qpid/amqp_0_10/Codec.h index bd0652716f..a819aec845 100644 --- a/cpp/src/qpid/amqp_0_10/Codec.h +++ b/cpp/src/qpid/amqp_0_10/Codec.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace qpid { namespace amqp_0_10 { @@ -46,17 +47,14 @@ template void endianize(T&) {} * AMQP 0-10 encoding and decoding. */ struct Codec { - // FIXME aconway 2008-02-29: drop this wrapper, rename to - // IteratorEncoder, IteratorDecoder? - /** Encode to an output byte iterator */ template - class Encoder : public serialize::Encoder > + class Encoder : public EncoderBase > { public: Encoder(OutIter o) : out(o) {} - using serialize::Encoder >::operator(); + using EncoderBase >::operator(); // FIXME aconway 2008-03-10: wrong encoding, need packing support Encoder& operator()(bool x) { *out++=x; return *this;} @@ -77,14 +75,8 @@ struct Codec { Encoder& operator()(double x) { return endian(x); } - template Encoder& operator()(Iter begin, Iter end) { - std::for_each(begin, end, serialize::ref(*this)); - return *this; - } - void raw(const void* p, size_t n) { - std::copy((const char*)p, (const char*)p+n, out); - out += n; + out = std::copy((const char*)p, (const char*)p+n, out); } OutIter pos() const { return out; } @@ -99,11 +91,13 @@ struct Codec { }; template - class Decoder : public serialize::Decoder > { + class Decoder : public DecoderBase > { public: + typedef InIter Iterator; + Decoder(InIter i) : in(i) {} - using serialize::Decoder >::operator(); + using DecoderBase >::operator(); // FIXME aconway 2008-03-10: wrong encoding, need packing support Decoder& operator()(bool& x) { x=*in++; return *this; } @@ -123,14 +117,9 @@ struct Codec { Decoder& operator()(float& x) { return endian(x); } Decoder& operator()(double& x) { return endian(x); } - template Decoder& operator()(Iter begin, Iter end) { - std::for_each(begin, end, serialize::ref(*this)); - return *this; - } - void raw(void *p, size_t n) { std::copy(in, in+n, (char*)p); - in += n; + std::advance(in, n); } InIter pos() const { return in; } @@ -145,13 +134,13 @@ struct Codec { }; - class Size : public serialize::Encoder { + class Size : public EncoderBase { public: Size() : size(0) {} operator size_t() const { return size; } - using serialize::Encoder::operator(); + using EncoderBase::operator(); // FIXME aconway 2008-03-10: wrong encoding, need packing support Size& operator()(bool x) { size += sizeof(x); return *this; } @@ -171,12 +160,9 @@ struct Codec { Size& operator()(float x) { size += sizeof(x); return *this; } Size& operator()(double x) { size += sizeof(x); return *this; } - // FIXME aconway 2008-04-02: enable-if optimized (iter,iter) for - // iter on fixed-size type. - template Size& operator()(Iter begin, Iter end) { - std::for_each(begin, end, serialize::ref(*this)); - return *this; - } + // FIXME aconway 2008-04-03: optimize op()(Iter,Iter) + // for Iter with fixed-size value_type: + // distance(begin,end)*sizeof(value_type) void raw(const void*, size_t n){ size += n; } diff --git a/cpp/src/qpid/amqp_0_10/Map.cpp b/cpp/src/qpid/amqp_0_10/Map.cpp index 1bfc2f6c85..480b439e40 100644 --- a/cpp/src/qpid/amqp_0_10/Map.cpp +++ b/cpp/src/qpid/amqp_0_10/Map.cpp @@ -18,6 +18,7 @@ * under the License. * */ +#include "qpid/amqp_0_10/specification.h" // for error constants. #include "Map.h" #include @@ -57,12 +58,12 @@ std::ostream& operator<<(std::ostream& o, const Map& map) { } uint32_t Map::contentSize() const { - uint32_t result=4; // uint32_t count - for (const_iterator i=begin(); i != end(); ++i) { - result += Codec::size(i->first); - result += Codec::size(i->second); - } - return result; + // FIXME aconway 2008-04-03: preview to 0-10 mapping: +4 for count. + return /*4 +*/ Codec::Size()(begin(), end()); +} + +void Map::throwInvalidArg() { + throw SessionException(execution::INVALID_ARGUMENT, "Invalid map encoding"); } }} // namespace qpid::amqp_0_10 diff --git a/cpp/src/qpid/amqp_0_10/Map.h b/cpp/src/qpid/amqp_0_10/Map.h index e9b95ed0f2..c23b4e37db 100644 --- a/cpp/src/qpid/amqp_0_10/Map.h +++ b/cpp/src/qpid/amqp_0_10/Map.h @@ -85,14 +85,13 @@ class Map : public std::map { public: template void serialize(S& s) { s.split(*this); } template void encode(S& s) const; - - // FIXME aconway 2008-04-02: better separation for size calcultion - // support for static size, optimized iterator size calc. + // Shortcut calculation for size. void encode(Codec::Size& s) const { s.raw(0, contentSize() + 4/*size*/); } template void decode(S& s); private: + static void throwInvalidArg(); uint32_t contentSize() const; }; @@ -157,18 +156,26 @@ template typename V::result_type MapValue::apply_visitor(const V& v) { } template void Map::encode(S& s) const { - s(contentSize())(uint32_t(size())); // size, count + // FIXME aconway 2008-04-03: replace preview mapping with 0-10 mapping: + // s(contentSize())(uint32_t(size())); // size, count + s(contentSize()); for (const_iterator i = begin(); i != end(); ++i) s(i->first)(i->second); // key (type value) } template void Map::decode(S& s) { - uint32_t cSize, count; - // FIXME aconway 2008-04-02: runtime check that we consume exactly cSize. - s(cSize)(count); - for ( ; count > 0; --count) { + uint32_t cSize /*, count*/; + // FIXME aconway 2008-04-03: replace preview mapping with 0-10 mapping: + // s(contentSize())(uint32_t(size())); // size, count + // s(cSize)(count); + s(cSize); + typename S::Iterator start = s.pos(); + // FIXME aconway 2008-04-03: replace preview with 0-10: + // for ( ; count > 0; --count) { + while (uint32_t(std::distance(start, s.pos())) < cSize) { key_type k; MapValue v; s(k)(v); + if (uint32_t(std::distance(start, s.pos())) > cSize) throwInvalidArg(); insert(value_type(k,v)); } } diff --git a/cpp/src/qpid/amqp_0_10/PackedCodec.h b/cpp/src/qpid/amqp_0_10/PackedCodec.h index f6290e76a1..408c20cb0b 100644 --- a/cpp/src/qpid/amqp_0_10/PackedCodec.h +++ b/cpp/src/qpid/amqp_0_10/PackedCodec.h @@ -34,7 +34,7 @@ namespace amqp_0_10 { struct PackedCodec { template class Decoder : - public serialize::Decoder > + public DecoderBase > { public: Decoder(Bits b, const InnerDecoder& d) diff --git a/cpp/src/qpid/amqp_0_10/Segment.h b/cpp/src/qpid/amqp_0_10/Segment.h index b779b98dd1..650573802b 100644 --- a/cpp/src/qpid/amqp_0_10/Segment.h +++ b/cpp/src/qpid/amqp_0_10/Segment.h @@ -106,6 +106,7 @@ class Segment::const_iterator : public boost::iterator_facade< p += n; skip_empty(); } + void skip_empty() { invariant(); while (p == i->end() && i != frames->end()) diff --git a/cpp/src/qpid/amqp_0_10/built_in_types.h b/cpp/src/qpid/amqp_0_10/built_in_types.h index 0b9ed4168b..c9ce27bda0 100644 --- a/cpp/src/qpid/amqp_0_10/built_in_types.h +++ b/cpp/src/qpid/amqp_0_10/built_in_types.h @@ -21,11 +21,12 @@ * */ -#include "Decimal.h" -#include "SerializableString.h" +#include "qpid/Serializer.h" #include "qpid/framing/SequenceNumber.h" #include "qpid/framing/Uuid.h" #include "qpid/sys/Time.h" +#include "Decimal.h" +#include "SerializableString.h" #include #include #include @@ -153,22 +154,13 @@ inline std::ostream& operator<<(std::ostream& o, const SequenceSet&) { return o; inline std::ostream& operator<<(std::ostream& o, const List&) { return o; } inline std::ostream& operator<<(std::ostream& o, const Struct32&) { return o; } -/** Serialization helper for enums */ -template -struct SerializableEnum { - Enum& value; - SerializableEnum(Enum & e) : value(e) {} - template void serialize(S& s) { s.split(*this); } - template void encode(S& s) const { s(Int(value)); } - template void decode(S& s) { Int i; s(i); value=Enum(i); } -}; - enum SegmentType { CONTROL, COMMAND, HEADER, BODY }; -inline SerializableEnum serializable(SegmentType& st) { - return SerializableEnum(st); +inline SerializeAs serializable(SegmentType& st) { + return SerializeAs(st); } + }} // namespace qpid::amqp_0_10 #endif diff --git a/cpp/src/tests/amqp_0_10/Map.cpp b/cpp/src/tests/amqp_0_10/Map.cpp index 0a58a2134a..ad6f38b5d7 100644 --- a/cpp/src/tests/amqp_0_10/Map.cpp +++ b/cpp/src/tests/amqp_0_10/Map.cpp @@ -26,11 +26,6 @@ using namespace qpid::amqp_0_10; using namespace std; -namespace std { -// Dummy += for back inserters so we can use them with the decoder. -template back_insert_iterator& operator+=(back_insert_iterator& bi, size_t) { return bi; } -} - QPID_AUTO_TEST_SUITE(MapTestSuite) BOOST_AUTO_TEST_CASE(testGetSet) { diff --git a/cpp/src/tests/serialize.cpp b/cpp/src/tests/serialize.cpp index 1f576d6ee1..386f721338 100644 --- a/cpp/src/tests/serialize.cpp +++ b/cpp/src/tests/serialize.cpp @@ -60,15 +60,8 @@ std::ostream& operator<<(std::ostream& out, const AbsTime& t) { } // qpid -namespace std { -// Dummy += for back inserters so we can use them with the decoder. -template back_insert_iterator& operator+=(back_insert_iterator& bi, size_t) { return bi; } -} - QPID_AUTO_TEST_SUITE(SerializeTestSuite) - - using namespace std; namespace mpl=boost::mpl; using namespace qpid::amqp_0_10; -- cgit v1.2.1