From 6dd59f62185ab8547cc1eec0a57731e0ab5a8645 Mon Sep 17 00:00:00 2001 From: Alan Conway Date: Fri, 29 Feb 2008 22:07:40 +0000 Subject: Template visitors for amqp_0_10::Command, Control and Struct. Serialization for all str/vbin types. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@632457 13f79535-47bb-0310-9956-ffa450edef68 --- cpp/src/qpid/Serializer.h | 80 ++++--------------- cpp/src/qpid/amqp_0_10/Codec.h | 134 ++++++++++++++------------------ cpp/src/qpid/amqp_0_10/Decimal.h | 5 +- cpp/src/qpid/amqp_0_10/apply.h | 77 ++++++++++++++++++ cpp/src/qpid/amqp_0_10/built_in_types.h | 60 ++++++++------ cpp/src/qpid/amqp_0_10/helpers.cpp | 3 + cpp/src/qpid/amqp_0_10/helpers.h | 7 +- cpp/src/qpid/amqp_0_10/visitors.h | 15 ---- cpp/src/qpid/framing/Uuid.h | 2 +- 9 files changed, 194 insertions(+), 189 deletions(-) create mode 100644 cpp/src/qpid/amqp_0_10/apply.h delete mode 100644 cpp/src/qpid/amqp_0_10/visitors.h (limited to 'cpp/src/qpid') diff --git a/cpp/src/qpid/Serializer.h b/cpp/src/qpid/Serializer.h index a2fbf944ae..95cc2d5875 100644 --- a/cpp/src/qpid/Serializer.h +++ b/cpp/src/qpid/Serializer.h @@ -1,5 +1,5 @@ -#ifndef QPID_SERIALIZERBASE_H -#define QPID_SERIALIZERBASE_H +#ifndef QPID_SERIALIZER_H +#define QPID_SERIALIZER_H /* * @@ -22,88 +22,36 @@ * */ -#include -#include +#include #include -#include +#include +#include +#include namespace qpid { /** - * Base template for serializers, provides generic serialization for - * conmpound types and common encode/decode/size functions. - * - * Derived template must provide - * - Derived& op()(T) for primitive types. - * - Derived& raw(void*, size_t) for raw binary data - * - Derived& byte(char) for single bytes. - * - * Derived templatse may override any of the functions provided by - * this base class. - * - * This class provides templates to break down compound types - * into primitive types and delegate to the derived class. - * + * Base class for serializers. */ template class Serializer { - public: - - /** Call T::serialize() for classes that have their own serialize function */ - template - typename boost::enable_if, Derived>::type - operator()(T& t) { t.serialize(self()); return self(); } - - template - Derived& operator()(boost::array& a) { - std::for_each(a.begin(), a.end(), self()); - return self(); - } - - Derived& operator()(char& x) { return self().byte((char&)x); } - Derived& operator()(int8_t& x) { return self().byte((char&)x); } - Derived& operator()(uint8_t& x) { return self().byte((char&)x); } - - protected: - template Derived& raw(T& t) { - return self().raw(&t, sizeof(T)); - } - - private: - Derived& self() { return *static_cast(this); } -}; - -/** Like Serializer but does not modify the values passed to it. */ -template class ConstSerializer { public: template - typename boost::enable_if, Derived>::type - operator()(const T& t) { - // Const cast so we don't have to write 2 serialize() functions - // for every class. - const_cast(t).serialize(self()); + typename boost::enable_if, Derived&>::type + operator()(T& t) { + // const_cast so we don't need 2 serialize() members for every class. + const_cast::type&>(t).serialize(self()); return self(); } - template - Derived& operator()(const boost::array& a) { - std::for_each(a.begin(), a.end(), self()); + template Derived& iterate(Iter begin, Iter end) { + std::for_each(begin, end, self()); return self(); } - Derived& operator()(char x) { return self().byte(x); } - Derived& operator()(int8_t x) { return self().byte(x); } - Derived& operator()(uint8_t x) { return self().byte(x); } - - protected: - template Derived& raw(const T& t) { - return self().raw(&t, sizeof(T)); - } - private: Derived& self() { return *static_cast(this); } }; - } // namespace qpid -#endif /*!QPID_SERIALIZERBASE_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 e7f35e9288..acfc1e9c81 100644 --- a/cpp/src/qpid/amqp_0_10/Codec.h +++ b/cpp/src/qpid/amqp_0_10/Codec.h @@ -32,70 +32,47 @@ namespace qpid { namespace amqp_0_10 { - /** * AMQP 0-10 encoding and decoding. */ -struct Codec -{ - template - static inline void endianize(T& value) { - -#ifdef BOOST_LITTLE_ENDIAN - std::reverse((char*)&value, (char*)&value+sizeof(value)); -#else - (void)value; // Avoid unused var warnings. -#endif - } - static inline void endianize(char&) {} - static inline void endianize(uint8_t&) {} - static inline void endianize(int8_t&) {} - - - template struct Encode : public ConstSerializer > { - Out out; +class Codec { + public: + /** Encode to an output byte iterator */ + template + class Encode : public Serializer > { + public: + Encode(OutIter o) : out(o) {} - Encode(Out o) : out(o) {} + using Serializer >::operator(); - using ConstSerializer >::operator(); - using ConstSerializer >::raw; - - template + template typename boost::enable_if, Encode&>::type - operator()(const T& x) { T xx(x); endianize(xx); return raw(xx); } + operator()(T x) { + endianize(x); + raw(&x, sizeof(x)); + return *this; + } - // FIXME aconway 2008-02-20: correct float encoading + // FIXME aconway 2008-02-20: correct float encoading? template typename boost::enable_if, Encode&>::type - operator()(const T& x) { return raw(x); } - + operator()(const T& x) { raw(&x, sizeof(x)); return *this; } - template - Encode& operator()(const CodableString& str) { - (*this)(SizeType(str.size())); - std::for_each(str.begin(), str.end(), *this); - return *this; + void raw(const void* p, size_t n) { + std::copy((const char*)p, (const char*)p+n, out); } - + private: - friend class ConstSerializer >; - - Encode& raw(const void* vp, size_t s) { - char* p = (char*) vp; - std::copy(p, p+s, out); - return *this; - } - - Encode& byte(char x) { out++ = x; return *this; } + OutIter out; }; - template struct Decode : public Serializer > { - In in; - Decode(In i) : in(i) {} - - using Serializer >::operator(); - using Serializer >::raw; - + template + class Decode : public Serializer > { + public: + Decode(InIter i) : in(i) {} + + using Serializer >::operator(); + template typename boost::enable_if, Decode&>::type operator()(T& x) { @@ -106,10 +83,10 @@ struct Codec template typename boost::enable_if, Decode&>::type - operator()(T& x) { return raw(&x, sizeof(x)); } + operator()(T& x) { raw(&x, sizeof(x)); return *this; } template - Decode& operator()(CodableString& str) { + Decode& operator()(SerializableString& str) { SizeType n; (*this)(n); str.resize(n); @@ -117,54 +94,45 @@ struct Codec return *this; } - private: - friend class Serializer >; - - Decode& raw(void* vp, size_t s) { - char* p=(char*)vp; - std::copy(in, in+s, p); - return *this; + void raw(void *p, size_t n) { + // FIXME aconway 2008-02-29: requires random access iterator, + // does this optimize to memcpy? Is there a better way? + std::copy(in, in+n, (char*)p); + in += n; } - Decode& byte(char& x) { x = *in++; return *this; } + private: + InIter in; }; - struct Size : public ConstSerializer { + + class Size : public Serializer { + public: Size() : size(0) {} - size_t size; + operator size_t() const { return size; } - using ConstSerializer::operator(); - using ConstSerializer::raw; + using Serializer::operator(); template typename boost::enable_if, Size&>::type operator()(const T&) { size += sizeof(T); return *this; } - template - Size& operator()(const boost::array&) { - size += sizeof(boost::array); - return *this; - } - template - Size& operator()(const CodableString& str) { + Size& operator()(const SerializableString& str) { size += sizeof(SizeType) + str.size()*sizeof(T); return *this; } + void raw(const void*, size_t n){ size += n; } private: - friend class ConstSerializer; - - Size& raw(void*, size_t s) { size += s; return *this; } - - Size& byte(char) { ++size; return *this; } + size_t size; }; template static void encode(Out o, const T& x) { - Encodeencode(o); + Encode encode(o); encode(x); } @@ -180,6 +148,18 @@ struct Codec sz(x); return sz; } + + private: + template static inline void endianize(T& value) { +#ifdef BOOST_LITTLE_ENDIAN + std::reverse((char*)&value, (char*)&value+sizeof(value)); +#else + (void)value; // Avoid unused var warnings. +#endif + } + static inline void endianize(char&) {} + static inline void endianize(uint8_t&) {} + static inline void endianize(int8_t&) {} }; }} // namespace qpid::amqp_0_10 diff --git a/cpp/src/qpid/amqp_0_10/Decimal.h b/cpp/src/qpid/amqp_0_10/Decimal.h index 75cde94559..50fc457c76 100644 --- a/cpp/src/qpid/amqp_0_10/Decimal.h +++ b/cpp/src/qpid/amqp_0_10/Decimal.h @@ -30,7 +30,7 @@ template struct Decimal { E exponent; M mantissa; - Decimal() : exponent(0), mantissa(0) {} + Decimal(E exp=0, M man=0) : exponent(exp), mantissa(man) {} bool operator==(const Decimal& d) const { return exponent == d.exponent && mantissa == d.mantissa; @@ -44,8 +44,7 @@ template struct Decimal { template inline std::ostream& operator<<(std::ostream& o, const Decimal& d) { - M pow10=10^d.exponent; - return o << d.mantissa/pow10 << "." << d.mantissa%pow10; + return o << "Decimal{" << d.mantissa << "/10^" << (int)d.exponent << "}"; } }} diff --git a/cpp/src/qpid/amqp_0_10/apply.h b/cpp/src/qpid/amqp_0_10/apply.h new file mode 100644 index 0000000000..e1bd9c3aa6 --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/apply.h @@ -0,0 +1,77 @@ +#ifndef QPID_AMQP_0_10_APPLY_H +#define QPID_AMQP_0_10_APPLY_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include + +namespace qpid { +namespace amqp_0_10 { + +template struct FunctionAndResult { + F* functor; + boost::optional result; + + FunctionAndResult() : functor(0) {} + template void invoke(T t) { result=(*functor)(t); } + R getResult() { return *result; } +}; + +// void result is special case. +template struct FunctionAndResult { + F* functor; + + FunctionAndResult() : functor(0) {} + template void invoke(T t) { (*functor)(t); } + void getResult() {} +}; + +template +struct ApplyVisitorBase : public V, public FunctionAndResult { + using V::visit; +}; + +// Specialize for each visitor type +template struct ApplyVisitor; + +/** Apply a functor to a visitable object. + * The functor can have operator() overloads for each visitable type + * and/or templated operator(). + */ +template +typename F::result_type apply(F& functor, Visitable& visitable) { + ApplyVisitor visitor; + visitor.functor=&functor; + visitable.accept(visitor); + return visitor.getResult(); +} + +template +typename F::result_type apply(const F& functor, Visitable& visitable) { + ApplyVisitor visitor; + visitor.functor=&functor; + visitable.accept(visitor); + return visitor.getResult(); +} + +}} // namespace qpid::amqp_0_10 + +#endif /*!QPID_AMQP_0_10_APPLY_H*/ 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 445f07459c..13bcdf862e 100644 --- a/cpp/src/qpid/amqp_0_10/built_in_types.h +++ b/cpp/src/qpid/amqp_0_10/built_in_types.h @@ -1,6 +1,5 @@ #ifndef QPID_AMQP_0_10_BUILT_IN_TYPES_H #define QPID_AMQP_0_10_BUILT_IN_TYPES_H -// FIXME aconway 2008-02-20: separate _fwd.h from full include. /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -29,6 +28,7 @@ #include #include #include +#include #include /**@file Mapping from built-in AMQP types to C++ types */ @@ -53,15 +53,19 @@ typedef uint64_t Uint64; typedef uint8_t Bin8; typedef uint8_t Uint8; -typedef boost::array Bin1024; -typedef boost::array Bin128; -typedef boost::array Bin16; -typedef boost::array Bin256; -typedef boost::array Bin32; -typedef boost::array Bin40; -typedef boost::array Bin512; -typedef boost::array Bin64; -typedef boost::array Bin72; +template struct Bin : public boost::array { + template void serialize(S& s) { s.raw(this->begin(), this->size()); } +}; + +typedef Bin<128> Bin1024; +typedef Bin<16> Bin128; +typedef Bin<2> Bin16; +typedef Bin<32> Bin256; +typedef Bin<4> Bin32; +typedef Bin<5> Bin40; +typedef Bin<64> Bin512; +typedef Bin<8> Bin64; +typedef Bin<9> Bin72; typedef double Double; typedef float Float; @@ -75,25 +79,35 @@ typedef Decimal Dec64; /** Template for length-prefixed strings/arrays. */ template -struct CodableString : public std::basic_string {}; +struct SerializableString : public std::basic_string { + using std::basic_string::operator=; + template void serialize(S& s) { + s(SizeType(this->size())).iterate(this->begin(), this->end()); + } +}; + +// TODO aconway 2008-02-29: separate ostream ops +template +std::ostream& operator<<(std::ostream& o, const SerializableString& s) { + const std::basic_string str(s); + return o << str.c_str(); // TODO aconway 2008-02-29: why doesn't o< Vbin8; -typedef CodableString Str8Latin; -typedef CodableString Str8; -typedef CodableString Str8Utf16; - -typedef CodableString Vbin16; -typedef CodableString Str16Latin; -typedef CodableString Str16; -typedef CodableString Str16Utf16; +typedef SerializableString Vbin8; +typedef SerializableString Str8Latin; +typedef SerializableString Str8; +typedef SerializableString Str8Utf16; -typedef CodableString Vbin32; +typedef SerializableString Vbin16; +typedef SerializableString Str16Latin; +typedef SerializableString Str16; +typedef SerializableString Str16Utf16; -// FIXME aconway 2008-02-26: array encoding -template struct Array : public std::vector {}; +typedef SerializableString Vbin32; // FIXME aconway 2008-02-26: Unimplemented types: +template struct Array : public std::vector {}; struct ByteRanges {}; struct SequenceSet {}; struct Map {}; diff --git a/cpp/src/qpid/amqp_0_10/helpers.cpp b/cpp/src/qpid/amqp_0_10/helpers.cpp index 4333a2cd92..457abe2d5f 100644 --- a/cpp/src/qpid/amqp_0_10/helpers.cpp +++ b/cpp/src/qpid/amqp_0_10/helpers.cpp @@ -19,6 +19,9 @@ * */ #include "helpers.h" +#include "qpid/amqp_0_10/CommandVisitor.h" +#include "qpid/amqp_0_10/ControlVisitor.h" +#include "qpid/amqp_0_10/StructVisitor.h" namespace qpid { namespace amqp_0_10 { diff --git a/cpp/src/qpid/amqp_0_10/helpers.h b/cpp/src/qpid/amqp_0_10/helpers.h index 1769d374d9..fc9a3e16a4 100644 --- a/cpp/src/qpid/amqp_0_10/helpers.h +++ b/cpp/src/qpid/amqp_0_10/helpers.h @@ -24,7 +24,6 @@ n * "License"); you may not use this file except in compliance #include namespace qpid { - namespace amqp_0_10 { // Look up names by code @@ -35,19 +34,19 @@ const char* getStructName(uint8_t classCode, uint8_t code); struct Command { virtual ~Command(); - class Visitor; + struct Visitor; virtual void accept(Visitor&) const = 0; }; struct Control { virtual ~Control(); - class Visitor; + struct Visitor; virtual void accept(Visitor&) const = 0; }; struct Struct { virtual ~Struct(); - class Visitor; + struct Visitor; virtual void accept(Visitor&) const = 0; }; diff --git a/cpp/src/qpid/amqp_0_10/visitors.h b/cpp/src/qpid/amqp_0_10/visitors.h deleted file mode 100644 index 3835f37f3e..0000000000 --- a/cpp/src/qpid/amqp_0_10/visitors.h +++ /dev/null @@ -1,15 +0,0 @@ -// Visitors -template struct Visitor; -template FunctorVisitor; - -/** Template base implementation for visitables. */ -template -struct VisitableBase : public Base { - virtual void accept(Visitor& v) { - v.visit(static_cast&(*this)); - } - virtual void accept(Visitor& v) const { - v.visit(static_cast&(*this)); - } -}; - diff --git a/cpp/src/qpid/framing/Uuid.h b/cpp/src/qpid/framing/Uuid.h index 278a60c439..bce18f55b3 100644 --- a/cpp/src/qpid/framing/Uuid.h +++ b/cpp/src/qpid/framing/Uuid.h @@ -67,7 +67,7 @@ struct Uuid : public boost::array { std::string str() const; template void serialize(S& s) { - s(static_cast&>(*this)); + s.raw(begin(), size()); } }; -- cgit v1.2.1