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/rubygen/0-10/specification.rb | 76 ++++++++++++++---- cpp/rubygen/amqpgen.rb | 9 ++- cpp/rubygen/cppgen.rb | 22 ++++-- cpp/src/Makefile.am | 3 +- 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 +- cpp/src/tests/Makefile.am | 2 +- cpp/src/tests/apply.cpp | 92 ++++++++++++++++++++++ cpp/src/tests/serialize.cpp | 30 +++---- 16 files changed, 385 insertions(+), 232 deletions(-) create mode 100644 cpp/src/qpid/amqp_0_10/apply.h delete mode 100644 cpp/src/qpid/amqp_0_10/visitors.h create mode 100644 cpp/src/tests/apply.cpp (limited to 'cpp') diff --git a/cpp/rubygen/0-10/specification.rb b/cpp/rubygen/0-10/specification.rb index d4ecfe98ed..acf9e4e6ed 100755 --- a/cpp/rubygen/0-10/specification.rb +++ b/cpp/rubygen/0-10/specification.rb @@ -19,10 +19,8 @@ class Specification < CppGen genl d.enum.choices.map { |c| "#{c.name.constname} = #{c.value}" }.join(",\n") } - elsif (d.type_ == "array") - genl "typedef Array<#{ArrayTypes[d.name].amqp2cpp}> #{typename};" else - genl "typedef #{d.type_.amqp2cpp} #{typename};" + genl "typedef #{d.amqp2cpp} #{typename};" end end @@ -41,7 +39,7 @@ class Specification < CppGen def action_struct_h(x, base, consts, &block) genl struct(x.classname, "public #{base}") { - x.fields.each { |f| genl "#{f.type_.amqp2cpp} #{f.cppname};" } + x.fields.each { |f| genl "#{f.amqp2cpp} #{f.cppname};" } genl genl "static const char* NAME;" consts.each { |c| genl "static const uint8_t #{c.upcase}=#{x.send c or 0};"} @@ -58,10 +56,11 @@ class Specification < CppGen genl genl "const char* #{x.classname}::NAME=\"#{x.fqname}\";" genl - ctor_defn(x.classname) {} - ctor_defn(x.classname, x.parameters, x.initializers) {} if not x.fields.empty? - function_defn("void #{x.classname}::accept", ["Visitor&"], "const") { - genl "// FIXME aconway 2008-02-27: todo" + ctor=x.classname+"::"+x.classname + ctor_defn(ctor) {} + ctor_defn(ctor, x.parameters, x.initializers) {} if not x.fields.empty? + function_defn("void #{x.classname}::accept", ["Visitor& v"], "const") { + genl "v.visit(*this);" } end @@ -107,20 +106,21 @@ class Specification < CppGen # they are used by other definitions: each_class_ns { |c| class_h c - c.domains.each { |d| domain_h d if pregenerate? d } - c.structs.each { |s| struct_h s if pregenerate? s } + c.collect_all(AmqpDomain).each { |d| domain_h d if pregenerate? d } + c.collect_all(AmqpStruct).each { |s| struct_h s if pregenerate? s } } # Now dependent domains/structs and actions each_class_ns { |c| - c.domains.each { |d| domain_h d if not pregenerate? d } - c.structs.each { |s| struct_h s if not pregenerate? s } - c.actions.each { |a| action_h a } + c.collect_all(AmqpDomain).each { |d| domain_h d unless pregenerate? d} + c.collect_all(AmqpStruct).each { |s| struct_h s unless pregenerate? s} + c.collect_all(AmqpAction).each { |a| action_h a } } } } cpp_file("#{@dir}/specification") { include "#{@dir}/specification" + ["Command","Control","Struct"].each { |x| include "#{@dir}/Apply#{x}" } namespace(@ns) { each_class_ns { |c| class_cpp c @@ -156,10 +156,58 @@ class Specification < CppGen } } end - + + def gen_visitor(base, subs) + h_file("#{@dir}/#{base}Visitor.h") { + include "#{@dir}/specification" + namespace("#{@ns}") { + genl + genl "/** Visitor interface for #{base} subclasses. */" + struct("#{base}::Visitor") { + genl "virtual ~Visitor() {}" + genl "typedef #{base} BaseType;" + subs.each{ |s| + genl "virtual void visit(const #{s.fqclassname}&) = 0;" + }}}} + + h_file("#{@dir}/Apply#{base}.h") { + include "#{@dir}/#{base}Visitor.h" + include "#{@dir}/apply.h" + namespace("#{@ns}") { + genl + genl "/** apply() support for #{base} subclasses */" + genl "template " + struct("ApplyVisitor<#{base}::Visitor, F>", + ["public FunctionAndResult", "public #{base}::Visitor"]) { + subs.each{ |s| + function_defn("virtual void visit", ["const #{s.fqclassname}& x"]) { + genl "this->invoke(x);" + }}}}} + end + + def gen_visitors() + end + + def holder(base, derived) + name=base.caps+"Holder" + h_file("#{@dir}/#{name}") { + include "#{@dir}/specification" + include "qpid/framing/Blob" + namespace(@ns){ + # TODO aconway 2008-02-29: + } + } + end + def gen_holders() + + end + def generate gen_specification gen_proxy + gen_visitor("Command", @amqp.collect_all(AmqpCommand)) + gen_visitor("Control", @amqp.collect_all(AmqpControl)) + gen_visitor("Struct", @amqp.collect_all(AmqpStruct)) end end diff --git a/cpp/rubygen/amqpgen.rb b/cpp/rubygen/amqpgen.rb index 2edc573d00..67b4b1c73c 100755 --- a/cpp/rubygen/amqpgen.rb +++ b/cpp/rubygen/amqpgen.rb @@ -131,6 +131,12 @@ class AmqpElement @children.each { |c| c.each_descendant(&block) } end + def collect_all(amqp_type) + collect=[] + each_descendant { |d| collect << d if d.is_a? amqp_type } + collect + end + # Look up child of type elname with attribute name. def child(elname, name) @cache_child[[elname,name]] ||= children(elname).find { |c| c.name==name } @@ -386,6 +392,7 @@ class AmqpRoot < AmqpElement def methods_() classes.map { |c| c.methods_ }.flatten; end + #preview # Return all methods on chassis for all classes. def methods_on(chassis) @methods_on ||= { } @@ -394,8 +401,6 @@ class AmqpRoot < AmqpElement def fqname() nil; end - # TODO aconway 2008-02-21: methods by role. - private # Merge contents of elements. diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb index 5d2695c77a..df4ba49ca8 100755 --- a/cpp/rubygen/cppgen.rb +++ b/cpp/rubygen/cppgen.rb @@ -57,6 +57,7 @@ class String def cppsafe() CppMangle.include?(self) ? self+"_" : self; end def amqp2cpp() + throw 'Invalid "array".amqp2cpp' if self=="array" path=split(".") name=path.pop return name.typename if path.empty? @@ -112,21 +113,28 @@ class CppType def to_s() name; end; end +class AmqpElement + # convert my amqp type_ attribute to a C++ type. + def amqp2cpp() + return "Array<#{ArrayTypes[name].amqp2cpp}> " if type_=="array" + return type_.amqp2cpp + end +end + class AmqpField def cppname() name.lcaps.cppsafe; end def cpptype() domain.cpptype; end def bit?() domain.type_ == "bit"; end def signature() cpptype.param+" "+cppname; end - # FIXME aconway 2008-02-27: qualified - def paramtype() - fqtype=type_ - unless type_.index(".") + def fqtypename() + unless type_.index(".") c=containing_class return c.domain(type_).fqtypename if c.domain(type_) return c.struct(type_).fqclassname if c.struct(type_) end - "call_traits<#{fqtype.amqp2cpp}>::param_type"; + return amqp2cpp end + def paramtype() "call_traits<#{fqtypename}>::param_type"; end end class AmqpMethod @@ -337,8 +345,8 @@ class CppGen < Generator def ctor_decl(name, params=[]) function_decl(name, params); end def ctor_defn(name, params=[], inits=[]) - signature(name+"::"+name, params) - scope(":","") { genl inits.join(",\n")} if not inits.empty? + signature(name, params, inits.empty? ? "" : " :") + indent { gen inits.join(",\n") } if not inits.empty? scope() { yield } end diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am index becccb4224..a3609667d7 100644 --- a/cpp/src/Makefile.am +++ b/cpp/src/Makefile.am @@ -104,10 +104,10 @@ libqpidcommon_la_SOURCES = \ $(rgen_common_cpp) \ $(platform_src) \ qpid/amqp_0_10/helpers.cpp \ - qpid/Serializer.h \ qpid/amqp_0_10/built_in_types.h \ qpid/amqp_0_10/Codec.h \ qpid/amqp_0_10/Decimal.h \ + qpid/Serializer.h \ qpid/framing/AccumulatedAck.cpp \ qpid/framing/AMQBody.cpp \ qpid/framing/AMQMethodBody.cpp \ @@ -254,6 +254,7 @@ libqpidclient_la_SOURCES = \ nobase_include_HEADERS = \ $(platform_hdr) \ qpid/amqp_0_10/helpers.h \ + qpid/amqp_0_10/apply.h \ qpid/assert.h \ qpid/DataDir.h \ qpid/Exception.h \ 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()); } }; diff --git a/cpp/src/tests/Makefile.am b/cpp/src/tests/Makefile.am index 4a47797350..d25378a519 100644 --- a/cpp/src/tests/Makefile.am +++ b/cpp/src/tests/Makefile.am @@ -39,7 +39,7 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \ ISList.cpp IList.cpp \ ClientSessionTest.cpp \ serialize.cpp \ - ProxyTemplate.cpp + ProxyTemplate.cpp apply.cpp # FIXME aconway 2008-02-20: removed RefCountedMap.cpp due to valgrind error. check_LTLIBRARIES += libshlibtest.la diff --git a/cpp/src/tests/apply.cpp b/cpp/src/tests/apply.cpp new file mode 100644 index 0000000000..553026a35c --- /dev/null +++ b/cpp/src/tests/apply.cpp @@ -0,0 +1,92 @@ +/* + * + * 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 "unit_test.h" +#include "qpid/amqp_0_10/specification.h" +#include "qpid/amqp_0_10/ApplyControl.h" + +QPID_AUTO_TEST_SUITE(VisitorTestSuite) + +using namespace qpid::amqp_0_10; + +struct GetCode { + typedef uint8_t result_type; + template uint8_t operator()(const T&) const { return T::CODE; } +}; + +struct TestFunctor { + typedef bool result_type; + bool operator()(const connection::Tune& tune) { + BOOST_CHECK_EQUAL(tune.channelMax, 1u); + BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u); + BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u); + BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u); + return true; + } + template + bool operator()(const T&) { return false; } +}; + +BOOST_AUTO_TEST_CASE(testApply) { + connection::Tune tune(1,2,3,4); + Control* p = &tune; + + // boost oddity - without the cast we get undefined symbol errors. + BOOST_CHECK_EQUAL(apply(GetCode(), *p), (uint8_t)connection::Tune::CODE); + + TestFunctor tf; + BOOST_CHECK(apply(tf, *p)); + + connection::Start start; + p = &start; + BOOST_CHECK(!apply(tf, *p)); +} + +struct VoidTestFunctor { + typedef void result_type; + + int code; + VoidTestFunctor() : code() {} + + void operator()(const connection::Tune& tune) { + BOOST_CHECK_EQUAL(tune.channelMax, 1u); + BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u); + BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u); + BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u); + code=connection::Tune::CODE; + } + template + void operator()(const T&) { code=0xFF; } +}; + +BOOST_AUTO_TEST_CASE(testApplyVoid) { + connection::Tune tune(1,2,3,4); + Control* p = &tune; + VoidTestFunctor tf; + apply(tf, *p); + BOOST_CHECK_EQUAL(uint8_t(connection::Tune::CODE), tf.code); + + connection::Start start; + p = &start; + apply(tf, *p); + BOOST_CHECK_EQUAL(0xFF, tf.code); +} + +QPID_AUTO_TEST_SUITE_END() diff --git a/cpp/src/tests/serialize.cpp b/cpp/src/tests/serialize.cpp index a120be6458..8de2d4ca58 100644 --- a/cpp/src/tests/serialize.cpp +++ b/cpp/src/tests/serialize.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include // Missing operators needed for tests. @@ -52,15 +52,6 @@ std::ostream& operator<<(std::ostream& out, const AbsTime& t) { } } -namespace amqp_0_10 { -template -std::ostream& operator<<(std::ostream& out, const CodableString& str) { - std::ostream_iterator o(out, " "); - std::copy(str.begin(), str.end(), o); - return out; -} -} - } // qpid @@ -90,34 +81,37 @@ typedef concat2::type AllTypes; BOOST_AUTO_TEST_CASE(testNetworkByteOrder) { string data; - uint32_t l = 1234567890; + uint32_t l = 0x11223344; Codec::encode(std::back_inserter(data), l); uint32_t enc=reinterpret_cast(*data.data()); uint32_t l2 = ntohl(enc); BOOST_CHECK_EQUAL(l, l2); data.clear(); - uint16_t s = 12345; + uint16_t s = 0x1122; Codec::encode(std::back_inserter(data), s); uint32_t s2 = ntohs(*reinterpret_cast(data.data())); BOOST_CHECK_EQUAL(s, s2); } +// Assign test values to the various types. void testValue(bool& b) { b = true; } template typename boost::enable_if >::type testValue(T& n) { n=42; } -void testValue(long long& l) { l = 12345; } +void testValue(long long& l) { l = 0x012345; } void testValue(Datetime& dt) { dt = qpid::sys::now(); } void testValue(Uuid& uuid) { uuid=Uuid(true); } -template void testValue(Decimal& d) { d.exponent=2; d.mantissa=1234; } +template void testValue(Decimal& d) { d.exponent=2; d.mantissa=0x1122; } void testValue(SequenceNo& s) { s = 42; } -template void testValue(boost::array& a) { a.assign(42); } -template void testValue(CodableString& s) { +template void testValue(Bin& a) { a.assign(42); } +template void testValue(SerializableString& s) { char msg[]="foobar"; s.assign(msg, msg+sizeof(msg)); } +void testValue(Str16& s) { s = "the quick brown fox jumped over the lazy dog"; } +void testValue(Str8& s) { s = "foobar"; } -// FIXME aconway 2008-02-20: test AllTypes -BOOST_AUTO_TEST_CASE_TEMPLATE(testEncodeDecode, T, FixedSizeTypes) +//typedef mpl::vector::type TestTypes; +BOOST_AUTO_TEST_CASE_TEMPLATE(testEncodeDecode, T, AllTypes) { string data; T t; -- cgit v1.2.1