diff options
author | Alan Conway <aconway@apache.org> | 2008-03-04 16:34:01 +0000 |
---|---|---|
committer | Alan Conway <aconway@apache.org> | 2008-03-04 16:34:01 +0000 |
commit | 24435b9c62976e0a4c0857f86057d3c93389b79f (patch) | |
tree | ce9c88040f27fee8fc5f980e09c4ee487686cb4b /cpp | |
parent | 089d3974d9555658f79e4ef02232877dab4dcad3 (diff) | |
download | qpid-python-24435b9c62976e0a4c0857f86057d3c93389b79f.tar.gz |
Completed holders, visitors and serialization for 0-10 commands and controls.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@633533 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp')
-rwxr-xr-x | cpp/rubygen/0-10/specification.rb | 149 | ||||
-rwxr-xr-x | cpp/rubygen/cppgen.rb | 2 | ||||
-rw-r--r-- | cpp/src/Makefile.am | 5 | ||||
-rw-r--r-- | cpp/src/qpid/Serializer.h | 43 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Codec.h | 42 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Holder.h | 62 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/apply.h | 29 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/built_in_types.h | 33 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/complex_types.cpp | 65 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/complex_types.h | 79 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/helpers.cpp | 33 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/helpers.h | 81 | ||||
-rw-r--r-- | cpp/src/qpid/framing/AMQBody.h | 3 | ||||
-rw-r--r-- | cpp/src/tests/apply.cpp | 11 | ||||
-rw-r--r-- | cpp/src/tests/serialize.cpp | 56 |
15 files changed, 477 insertions, 216 deletions
diff --git a/cpp/rubygen/0-10/specification.rb b/cpp/rubygen/0-10/specification.rb index acf9e4e6ed..c159d9f08b 100755 --- a/cpp/rubygen/0-10/specification.rb +++ b/cpp/rubygen/0-10/specification.rb @@ -15,10 +15,11 @@ class Specification < CppGen genl typename=d.name.typename if d.enum - scope("enum #{typename} {", "};") { + scope("enum #{typename}Enum {", "};") { genl d.enum.choices.map { |c| "#{c.name.constname} = #{c.value}" }.join(",\n") } + genl "typedef Enum<#{typename}Enum, uint8_t> #{typename};" else genl "typedef #{d.amqp2cpp} #{typename};" end @@ -42,11 +43,15 @@ class Specification < CppGen 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};"} + consts.each { + |c| genl "static const uint8_t #{c.upcase}=#{(x.send c) or 0};" + } genl "static const uint8_t CLASS_CODE=#{x.containing_class.nsname}::CODE;" + genl "static const char* CLASS_NAME;" ctor_decl(x.classname,[]) ctor_decl(x.classname, x.parameters) unless x.fields.empty? - function_decl("void accept", ["Visitor&"], "const") + genl "void accept(Visitor&);" + genl "void accept(ConstVisitor&) const;" genl yield if block } @@ -55,13 +60,19 @@ class Specification < CppGen def action_struct_cpp(x) genl genl "const char* #{x.classname}::NAME=\"#{x.fqname}\";" + genl "const char* #{x.classname}::CLASS_NAME=#{x.containing_class.nsname}::NAME;" genl 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);" - } + # FIXME aconway 2008-03-04: struct visitors + if x.is_a? AmqpStruct + genl "void #{x.classname}::accept(Visitor&) { assert(0); }" + genl "void #{x.classname}::accept(ConstVisitor&) const { assert(0); }" + else + genl "void #{x.classname}::accept(Visitor& v) { v.visit(*this); }" + genl "void #{x.classname}::accept(ConstVisitor& v) const { v.visit(*this); }" + end end # structs @@ -76,11 +87,13 @@ class Specification < CppGen function_defn("template <class T> void invoke", ["T& target"]) { genl "target.#{a.funcname}(#{a.values.join(', ')});" } - function_defn("template <class S> void serialize", ["S& s"]) { - gen "s" - a.fields.each { |f| gen "(#{f.cppname})"} - genl ";" - } unless a.fields.empty? + if (a.fields.empty?) + genl "template <class S> void serialize(S&) {}" + else + scope("template <class S> void serialize(S& s) {") { + gen "s"; a.fields.each { |f| gen "(#{f.cppname})"}; genl ";" + } + end } end @@ -93,7 +106,7 @@ class Specification < CppGen def gen_specification() h_file("#{@dir}/specification") { include "#{@dir}/built_in_types" - include "#{@dir}/helpers" + include "#{@dir}/complex_types" include "<boost/call_traits.hpp>" genl "using boost::call_traits;" namespace(@ns) { @@ -120,12 +133,13 @@ class Specification < CppGen cpp_file("#{@dir}/specification") { include "#{@dir}/specification" - ["Command","Control","Struct"].each { |x| include "#{@dir}/Apply#{x}" } + # FIXME aconway 2008-03-04: add Struct visitors. + ["Command","Control"].each { |x| include "#{@dir}/Apply#{x}" } namespace(@ns) { each_class_ns { |c| class_cpp c c.actions.each { |a| action_cpp a} - c.structs.each { |s| struct_cpp s } + c.collect_all(AmqpStruct).each { |s| struct_cpp(s) } } } } @@ -157,57 +171,98 @@ class Specification < CppGen } end + def visitor_interface_h(base, subs, is_const) + name="#{is_const ? 'Const' : ''}#{base}Visitor" + const=is_const ? "const " : "" + struct(name) { + genl "virtual ~#{name}() {}" + genl "typedef #{const}#{base} BaseType;" + subs.each{ |s| + genl "virtual void visit(#{const}#{s.fqclassname}&) = 0;" + }} + end + + def visitor_impl(base, subs, is_const) + name="#{is_const ? 'Const' : ''}#{base}Visitor" + const=is_const ? "const " : "" + genl "template <class F>" + struct("ApplyVisitor<#{name}, F>", "public ApplyVisitorBase<#{name}, F>") { + subs.each{ |s| + genl "virtual void visit(#{const}#{s.fqclassname}& x) { this->invoke(x); }" + }} + 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;" - }}}} - + visitor_interface_h(base, subs, false) + visitor_interface_h(base, subs, true) + }} + 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 <class F>" - struct("ApplyVisitor<#{base}::Visitor, F>", - ["public FunctionAndResult<F>", "public #{base}::Visitor"]) { - subs.each{ |s| - function_defn("virtual void visit", ["const #{s.fqclassname}& x"]) { - genl "this->invoke(x);" - }}}}} - end - - def gen_visitors() + visitor_impl(base, subs, false) + visitor_impl(base, subs, true) + } + } end - - def holder(base, derived) + + def gen_holder(base, subs) name=base.caps+"Holder" h_file("#{@dir}/#{name}") { - include "#{@dir}/specification" - include "qpid/framing/Blob" - namespace(@ns){ - # TODO aconway 2008-02-29: - } - } + include "#{@dir}/Apply#{base}" + include "#{@dir}/Holder" + namespace(@ns){ + namespace("#{base.downcase}_max") { + gen "template <class M, class X> " + struct("Max") { + genl "static const size_t max=(M::max > sizeof(X)) ? M::max : sizeof(X);" + } + genl "struct Max000 { static const size_t max=0; };" + last="Max000" + subs.each { |s| + genl "typedef Max<#{last}, #{s.fqclassname}> #{last.succ!};" + } + genl "static const int MAX=#{last}::max;" + } + holder_base="amqp_0_10::Holder<#{base}Holder, #{base}, #{base.downcase}_max::MAX>" + struct("#{name}", "public #{holder_base}") { + genl "#{name}() {}" + genl "template <class T> #{name}(const T& t) : #{holder_base}(t) {}" + genl "using #{holder_base}::operator=;" + genl "void set(uint8_t classCode, uint8_t code);" + }}} + + cpp_file("#{@dir}/#{name}") { + include "#{@dir}/#{name}" + namespace(@ns) { + genl "using framing::in_place;" + genl + scope("void #{name}::set(uint8_t classCode, uint8_t code) {") { + genl "uint16_t key=(classCode<<8)+code;" + scope ("switch(key) {") { + subs.each { |s| + genl "case 0x#{s.full_code.to_s(16)}: *this=in_place<#{s.fqclassname}>(); break;" + } + genl "default: assert(0);" + }}}} end - def gen_holders() + def gen_visitable(base, subs) + gen_holder(base, subs) + gen_visitor(base, subs) 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)) + gen_visitable("Command", @amqp.collect_all(AmqpCommand)) + gen_visitable("Control", @amqp.collect_all(AmqpControl)) + # FIXME aconway 2008-03-04: sort out visitable structs. + # gen_visitable("Struct", @amqp.collect_all(AmqpStruct)) end end diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb index 8e64b06208..63a2e6857e 100755 --- a/cpp/rubygen/cppgen.rb +++ b/cpp/rubygen/cppgen.rb @@ -162,7 +162,7 @@ class AmqpAction def classname() name.typename; end def funcname() parent.name.funcname + name.caps; end def fqclassname() parent.name+"::"+classname; end - + def full_code() (containing_class.code.hex << 8)+code.hex; end include AmqpHasFields end diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am index 080260be02..f15f8d7a91 100644 --- a/cpp/src/Makefile.am +++ b/cpp/src/Makefile.am @@ -103,8 +103,10 @@ libqpidcommon_la_LIBADD = \ libqpidcommon_la_SOURCES = \ $(rgen_common_cpp) \ $(platform_src) \ - qpid/amqp_0_10/helpers.cpp \ qpid/amqp_0_10/built_in_types.h \ + qpid/amqp_0_10/complex_types.h \ + qpid/amqp_0_10/complex_types.cpp \ + qpid/amqp_0_10/Holder.h \ qpid/amqp_0_10/Codec.h \ qpid/amqp_0_10/Decimal.h \ qpid/Serializer.h \ @@ -254,7 +256,6 @@ 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 \ diff --git a/cpp/src/qpid/Serializer.h b/cpp/src/qpid/Serializer.h index a7194c5095..34b95d3ffd 100644 --- a/cpp/src/qpid/Serializer.h +++ b/cpp/src/qpid/Serializer.h @@ -22,37 +22,60 @@ * */ -#include <boost/type_traits/remove_const.hpp> #include <boost/utility/enable_if.hpp> -#include <boost/type_traits/is_const.hpp> +#include <boost/static_assert.hpp> #include <boost/type_traits/is_class.hpp> -#include <boost/type_traits/add_const.hpp> #include <algorithm> namespace qpid { -/** - * Base class for serializers. - */ +// FIXME aconway 2008-03-03: Doc - esp decoding template <class Derived> class Serializer { public: + typedef Serializer result_type; // unary functor requirement. + + static const bool IS_DECODER=false; + + /** Generic handler for class objects, call serialize() */ template <class T> typename boost::enable_if<boost::is_class<T>, Derived&>::type operator()(T& t) { - // const_cast so we don't need 2 serialize() members for every class. - const_cast<typename boost::remove_const<T>::type&>(t).serialize(self()); + t.serialize(self()); return self(); } - template <class Iter> Derived& iterate(Iter begin, Iter end) { - std::for_each(begin, end, self()); + /** Generic handler for const class objects, call serialize() */ + template <class T> + typename boost::enable_if<boost::is_class<T>, Derived&>::type + operator()(const T& t) { + assert(!Derived::IS_DECODER); // We won't modify the value. + // const_cast so we don't need 2 serialize() members for every class. + const_cast<T&>(t).serialize(self()); return self(); } + template <class T, bool=false> struct Split { + Split(Derived& s, T& t) { t.encode(s); } + }; + + template <class T> struct Split<T,true> { + Split(Derived& s, T& t) { t.decode(s); } + }; + /** + * Called by classes that want to receive separate + * encode()/decode() calls. + */ + template <class T> + void split(T& t) { Split<T, Derived::IS_DECODER>(self(),t); } + private: Derived& self() { return *static_cast<Derived*>(this); } }; + + + + } // namespace qpid #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 acfc1e9c81..a36004753a 100644 --- a/cpp/src/qpid/amqp_0_10/Codec.h +++ b/cpp/src/qpid/amqp_0_10/Codec.h @@ -28,15 +28,14 @@ #include <boost/type_traits/is_float.hpp> #include <boost/type_traits/is_arithmetic.hpp> #include <boost/detail/endian.hpp> -#include <boost/ref.hpp> namespace qpid { namespace amqp_0_10 { /** * AMQP 0-10 encoding and decoding. */ -class Codec { - public: +struct Codec { // FIXME aconway 2008-02-29: drop this wrapper? + /** Encode to an output byte iterator */ template <class OutIter> class Encode : public Serializer<Encode<OutIter> > { @@ -58,6 +57,11 @@ class Codec { typename boost::enable_if<boost::is_float<T>, Encode&>::type operator()(const T& x) { raw(&x, sizeof(x)); return *this; } + template <class Iter> Encode& operator()(Iter begin, Iter end) { + std::for_each(begin, end, *this); + return *this; + } + void raw(const void* p, size_t n) { std::copy((const char*)p, (const char*)p+n, out); } @@ -70,6 +74,8 @@ class Codec { class Decode : public Serializer<Decode<InIter> > { public: Decode(InIter i) : in(i) {} + + static const bool IS_DECODER=true; using Serializer<Decode<InIter> >::operator(); @@ -94,6 +100,11 @@ class Codec { return *this; } + template <class Iter> Decode& operator()(Iter begin, Iter end) { + std::for_each(begin, end, *this); + 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? @@ -124,30 +135,27 @@ class Codec { return *this; } + template <class Iter> + Size& operator()(const Iter& a, const Iter& b) { + size += (b-a)*sizeof(*a); + return *this; + } + void raw(const void*, size_t n){ size += n; } private: size_t size; }; - template <class Out, class T> - static void encode(Out o, const T& x) { - Encode<Out> encode(o); - encode(x); + template <class OutIter> static Decode<OutIter> decode(const OutIter &i) { + return Decode<OutIter>(i); } - template <class In, class T> - static void decode(In i, T& x) { - Decode<In> decode(i); - decode(x); + template <class InIter> static Encode<InIter> encode(InIter i) { + return Encode<InIter>(i); } - template <class T> - static size_t size(const T& x) { - Size sz; - sz(x); - return sz; - } + template <class T> static size_t size(const T& x) { return Size()(x); } private: template <class T> static inline void endianize(T& value) { diff --git a/cpp/src/qpid/amqp_0_10/Holder.h b/cpp/src/qpid/amqp_0_10/Holder.h new file mode 100644 index 0000000000..76f8aa52de --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/Holder.h @@ -0,0 +1,62 @@ +#ifndef QPID_AMQP_0_10_HOLDER_H +#define QPID_AMQP_0_10_HOLDER_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 "qpid/framing/Blob.h" +#include "apply.h" + +namespace qpid { +namespace amqp_0_10 { + +template <class DerivedHolder, class BaseHeld, size_t Size> +struct Holder : public framing::Blob<Size, BaseHeld> { + + typedef framing::Blob<Size, BaseHeld> Base; + + Holder() {} + template <class T> Holder(const T& value) : Base(value) {} + + using Base::operator=; + + uint8_t getCode() const { return this->get()->getCode(); } + uint8_t getClassCode() const { return this->get()->getClassCode(); } + + template <class S> void encode(S& s) { + s(getClassCode())(getCode()); + } + + template <class S> void decode(S& s) { + uint8_t code, classCode; + s(classCode)(code); + static_cast<DerivedHolder*>(this)->set(classCode, code); + } + + template <class S> void serialize(S& s) { + s.split(*this); + apply(s, *this->get()); + } +}; + + +}} // namespace qpid::amqp_0_10 + +#endif /*!QPID_AMQP_0_10_HOLDER_H*/ diff --git a/cpp/src/qpid/amqp_0_10/apply.h b/cpp/src/qpid/amqp_0_10/apply.h index e1bd9c3aa6..05b7669322 100644 --- a/cpp/src/qpid/amqp_0_10/apply.h +++ b/cpp/src/qpid/amqp_0_10/apply.h @@ -31,7 +31,8 @@ template <class F, class R=typename F::result_type> struct FunctionAndResult { boost::optional<R> result; FunctionAndResult() : functor(0) {} - template <class T> void invoke(T t) { result=(*functor)(t); } + template <class T> void invoke(T& t) { result=(*functor)(t); } + template <class T> void invoke(const T& t) { result=(*functor)(t); } R getResult() { return *result; } }; @@ -40,17 +41,23 @@ template <class F> struct FunctionAndResult<F, void> { F* functor; FunctionAndResult() : functor(0) {} - template <class T> void invoke(T t) { (*functor)(t); } + template <class T> void invoke(T& t) { (*functor)(t); } void getResult() {} }; -template <class V, class F> -struct ApplyVisitorBase : public V, public FunctionAndResult<F> { - using V::visit; +// Metafunction returning correct abstract visitor for Visitable type. +template <class Visitable> struct VisitorType { + typedef typename Visitable::Visitor type; }; +template <class Visitable> struct VisitorType<const Visitable> { + typedef typename Visitable::ConstVisitor type; +}; + +template <class Visitor, class F> +struct ApplyVisitorBase : public Visitor, public FunctionAndResult<F> {}; // Specialize for each visitor type -template <class V, class F> struct ApplyVisitor; +template <class Visitable, class F> struct ApplyVisitor; /** Apply a functor to a visitable object. * The functor can have operator() overloads for each visitable type @@ -58,7 +65,7 @@ template <class V, class F> struct ApplyVisitor; */ template <class F, class Visitable> typename F::result_type apply(F& functor, Visitable& visitable) { - ApplyVisitor<typename Visitable::Visitor, F> visitor; + ApplyVisitor<typename VisitorType<Visitable>::type, F> visitor; visitor.functor=&functor; visitable.accept(visitor); return visitor.getResult(); @@ -66,12 +73,18 @@ typename F::result_type apply(F& functor, Visitable& visitable) { template <class F, class Visitable> typename F::result_type apply(const F& functor, Visitable& visitable) { - ApplyVisitor<typename Visitable::Visitor, const F> visitor; + ApplyVisitor<typename VisitorType<Visitable>::type, const F> visitor; visitor.functor=&functor; visitable.accept(visitor); return visitor.getResult(); } +template <class R, bool Const=false> struct ApplyFunctor { + typedef R result_type; + static const bool IS_CONST=Const; +}; +template <class R> struct ConstApplyFunctor : public ApplyFunctor<R, true> {}; + }} // 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 13bcdf862e..6188e259f0 100644 --- a/cpp/src/qpid/amqp_0_10/built_in_types.h +++ b/cpp/src/qpid/amqp_0_10/built_in_types.h @@ -82,7 +82,7 @@ template <class T, class SizeType> struct SerializableString : public std::basic_string<T> { using std::basic_string<T>::operator=; template <class S> void serialize(S& s) { - s(SizeType(this->size())).iterate(this->begin(), this->end()); + s(SizeType(this->size()))(this->begin(), this->end()); } }; @@ -107,16 +107,29 @@ typedef SerializableString<Uint16, Uint16> Str16Utf16; typedef SerializableString<Uint8, Uint32> Vbin32; // FIXME aconway 2008-02-26: Unimplemented types: -template <class T> struct Array : public std::vector<T> {}; -struct ByteRanges {}; -struct SequenceSet {}; -struct Map {}; -struct List {}; -struct Struct32 {}; +template <class T> struct Array : public std::vector<T> { template <class S> void serialize(S&) {} }; +struct ByteRanges { template <class S> void serialize(S&) {} }; +struct SequenceSet { template <class S> void serialize(S&) {} }; +struct Map { template <class S> void serialize(S&) {} }; +struct List { template <class S> void serialize(S&) {} }; +struct Struct32 { template <class S> void serialize(S&) {} }; + +// Serializable enum support +template <class E, class Store> struct Enum { + Store value; + Enum() {} + Enum(E v) : value(v) {} + Enum(Store v) : value(v) {} + Enum& operator=(E v) { value=v; return *this; } + Enum& operator=(Store v) { value=v; return *this; } + operator E() const { return value; } + operator Store() const { return value; } + template <class S> void serialize(S& s) { s(value); } +}; -// Top level enum definitions. -enum SegmentType { CONTROL, COMMAND, HEADER, BODY }; +enum SegmentTypeEnum { CONTROL, COMMAND, HEADER, BODY }; +typedef Enum<SegmentTypeEnum, uint8_t> SegmentType; }} // namespace qpid::amqp_0_10 -#endif /*!QPID_AMQP_0_10_BUILT_IN_TYPES_H*/ +#endif diff --git a/cpp/src/qpid/amqp_0_10/complex_types.cpp b/cpp/src/qpid/amqp_0_10/complex_types.cpp new file mode 100644 index 0000000000..0960db469d --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/complex_types.cpp @@ -0,0 +1,65 @@ +/* + * + * 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 "qpid/amqp_0_10/ApplyCommand.h" +#include "qpid/amqp_0_10/ApplyControl.h" +// FIXME aconway 2008-03-04: #include "qpid/amqp_0_10/ApplyStruct.h" +#include "qpid/amqp_0_10/apply.h" + +namespace qpid { +namespace amqp_0_10 { +// Functors for getting static values from a visitable base type. + +#define QPID_STATIC_VALUE_GETTER(NAME, TYPE, VALUE) \ + struct NAME : public ConstApplyFunctor<TYPE> { \ + template <class T> TYPE operator()(const T&) const { return T::VALUE; }\ + } + +QPID_STATIC_VALUE_GETTER(GetCode, uint8_t, CODE); +QPID_STATIC_VALUE_GETTER(GetSize, uint8_t, SIZE); +QPID_STATIC_VALUE_GETTER(GetPack, uint8_t, PACK); +QPID_STATIC_VALUE_GETTER(GetClassCode, uint8_t, CLASS_CODE); +QPID_STATIC_VALUE_GETTER(GetName, const char*, NAME); +QPID_STATIC_VALUE_GETTER(GetClassName, const char*, CLASS_NAME); + + +uint8_t Command::getCode() const { return apply(GetCode(), *this); } +uint8_t Command::getClassCode() const { return apply(GetClassCode(), *this); } +const char* Command::getName() const { return apply(GetName(), *this); } +const char* Command::getClassName() const { return apply(GetClassName(), *this); } + +uint8_t Control::getCode() const { return apply(GetCode(), *this); } +uint8_t Control::getClassCode() const { return apply(GetClassCode(), *this); } +const char* Control::getName() const { return apply(GetName(), *this); } +const char* Control::getClassName() const { return apply(GetClassName(), *this); } + +// FIXME aconway 2008-03-04: Struct visitors +// uint8_t Struct::getCode() const { return apply(GetCode(), *this); } +// uint8_t Struct::getPack() const { return apply(GetPack(), *this); } +// uint8_t Struct::getSize() const { return apply(GetSize(), *this); } +// uint8_t Struct::getClassCode() const { return apply(GetClassCode(), *this); } +uint8_t Struct::getCode() const { assert(0); return 0; } +uint8_t Struct::getPack() const { assert(0); return 0; } +uint8_t Struct::getSize() const { assert(0); return 0; } +uint8_t Struct::getClassCode() const { assert(0); return 0; } + +}} // namespace qpid::amqp_0_10 + diff --git a/cpp/src/qpid/amqp_0_10/complex_types.h b/cpp/src/qpid/amqp_0_10/complex_types.h new file mode 100644 index 0000000000..f4810ba2d7 --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/complex_types.h @@ -0,0 +1,79 @@ +#ifndef QPID_AMQP_0_10_COMPLEX_TYPES_H +#define QPID_AMQP_0_10_COMPLEX_TYPES_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. + * + */ + +namespace qpid { +namespace amqp_0_10 { + +// Base classes for complex types. + +template <class V, class CV, class H> struct Visitable { + typedef V Visitor; + typedef CV ConstVisitor; + typedef H Holder; + + virtual ~Visitable() {} + virtual void accept(Visitor&) = 0; + virtual void accept(ConstVisitor&) const = 0; +}; + +struct CommandVisitor; +struct ConstCommandVisitor; +struct CommandHolder; +struct Command + : public Visitable<CommandVisitor, ConstCommandVisitor, CommandHolder> +{ + uint8_t getCode() const; + uint8_t getClassCode() const; + const char* getName() const; + const char* getClassName() const; +}; + +struct ControlVisitor; +struct ConstControlVisitor; +struct ControlHolder; +struct Control + : public Visitable<ControlVisitor, ConstControlVisitor, ControlHolder> +{ + uint8_t getCode() const; + uint8_t getClassCode() const; + const char* getName() const; + const char* getClassName() const; +}; + +struct StructVisitor; +struct ConstStructVisitor; +struct StructHolder; +struct Struct + : public Visitable<StructVisitor, ConstStructVisitor, StructHolder> +{ + uint8_t getCode() const; + uint8_t getPack() const; + uint8_t getSize() const; + uint8_t getClassCode() const; +}; + + +}} // namespace qpid::amqp_0_10 + +#endif /*!QPID_AMQP_0_10_COMPLEX_TYPES_H*/ diff --git a/cpp/src/qpid/amqp_0_10/helpers.cpp b/cpp/src/qpid/amqp_0_10/helpers.cpp deleted file mode 100644 index 457abe2d5f..0000000000 --- a/cpp/src/qpid/amqp_0_10/helpers.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * 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 "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 { - -Control::~Control() {} -Command::~Command() {} -Struct::~Struct() {} - -}} // namespace qpid::amqp_0_10 diff --git a/cpp/src/qpid/amqp_0_10/helpers.h b/cpp/src/qpid/amqp_0_10/helpers.h deleted file mode 100644 index b5150cd10f..0000000000 --- a/cpp/src/qpid/amqp_0_10/helpers.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef QPID_AMQP_0_10_HELPERS_H -#define QPID_AMQP_0_10_HELPERS_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 -n * "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 "qpid/amqp_0_10/built_in_types.h" -#include <string> - -namespace qpid { -namespace amqp_0_10 { - -// Look up names by code -const char* getClassName(uint8_t code); -const char* getCommandName(uint8_t classCode, uint8_t code); -const char* getControlName(uint8_t classCode, uint8_t code); -const char* getStructName(uint8_t classCode, uint8_t code); - -struct Command { - static const int SEGMENT_TYPE=COMMAND; - virtual ~Command(); - struct Visitor; - virtual void accept(Visitor&) const = 0; -}; - -struct Control { - static const int SEGMENT_TYPE=CONTROL; - virtual ~Control(); - struct Visitor; - virtual void accept(Visitor&) const = 0; -}; - -// Struct -struct Struct { - virtual ~Struct(); - struct Visitor; - virtual void accept(Visitor&) const = 0; -}; - -template <class SizeType, bool Coded, uint8_t Code, uint8_t Pack> -struct SerializableStruct : public Struct { - static const uint8_t SIZE=sizeof(SizeType); - static const bool CODED=Coded; - static const uint8_t CODE=Code; - static const uint8_t PACK; - // TODO aconway 2008-02-29: handle common encoding/decoding/size - // for structs. Support for packing. -}; - - -/** Base class for generated enum domains. - * Enums map to classes for type safety and to provide separate namespaces - * for clashing values. - */ -struct Enum { - int value; - Enum(int v=0) : value(v) {} - operator int() const { return value; } - template <class S> void serialize(S &s) { s(value); } -}; - -}} // namespace qpid::amqp_0_10 - -#endif /*!QPID_AMQP_0_10_HELPERS_H*/ diff --git a/cpp/src/qpid/framing/AMQBody.h b/cpp/src/qpid/framing/AMQBody.h index 73c462a427..925f4c46ac 100644 --- a/cpp/src/qpid/framing/AMQBody.h +++ b/cpp/src/qpid/framing/AMQBody.h @@ -22,7 +22,8 @@ * */ #include "qpid/framing/amqp_types.h" -#include "qpid/amqp_0_10/helpers.h" +#include "qpid/amqp_0_10/built_in_types.h" +#include "qpid/amqp_0_10/complex_types.h" #include <ostream> diff --git a/cpp/src/tests/apply.cpp b/cpp/src/tests/apply.cpp index 553026a35c..1b66d8e3b4 100644 --- a/cpp/src/tests/apply.cpp +++ b/cpp/src/tests/apply.cpp @@ -26,11 +26,15 @@ QPID_AUTO_TEST_SUITE(VisitorTestSuite) using namespace qpid::amqp_0_10; -struct GetCode { - typedef uint8_t result_type; +struct GetCode : public ConstApplyFunctor<uint8_t> { template <class T> uint8_t operator()(const T&) const { return T::CODE; } }; +struct SetChannelMax : ApplyFunctor<void> { + template <class T> void operator()(T&) const { BOOST_FAIL(""); } + void operator()(connection::Tune& t) const { t.channelMax=42; } +}; + struct TestFunctor { typedef bool result_type; bool operator()(const connection::Tune& tune) { @@ -57,6 +61,9 @@ BOOST_AUTO_TEST_CASE(testApply) { connection::Start start; p = &start; BOOST_CHECK(!apply(tf, *p)); + + apply(SetChannelMax(), tune); + BOOST_CHECK_EQUAL(tune.channelMax, 42); } struct VoidTestFunctor { diff --git a/cpp/src/tests/serialize.cpp b/cpp/src/tests/serialize.cpp index 8de2d4ca58..9eaf78ab78 100644 --- a/cpp/src/tests/serialize.cpp +++ b/cpp/src/tests/serialize.cpp @@ -22,6 +22,9 @@ #include "unit_test.h" #include "qpid/amqp_0_10/built_in_types.h" #include "qpid/amqp_0_10/Codec.h" +#include "qpid/amqp_0_10/specification.h" +#include "qpid/amqp_0_10/ControlHolder.h" + #include <boost/test/test_case_template.hpp> #include <boost/type_traits/is_arithmetic.hpp> #include <boost/utility/enable_if.hpp> @@ -62,6 +65,7 @@ QPID_AUTO_TEST_SUITE(SerializeTestSuite) using namespace std; namespace mpl=boost::mpl; using namespace qpid::amqp_0_10; +using qpid::framing::in_place; template <class A, class B> struct concat2 { typedef typename mpl::copy<B, typename mpl::back_inserter<A> >::type type; }; template <class A, class B, class C> struct concat3 { typedef typename concat2<A, typename concat2<B, C>::type>::type type; }; @@ -82,14 +86,14 @@ BOOST_AUTO_TEST_CASE(testNetworkByteOrder) { string data; uint32_t l = 0x11223344; - Codec::encode(std::back_inserter(data), l); + Codec::encode(std::back_inserter(data))(l); uint32_t enc=reinterpret_cast<const uint32_t&>(*data.data()); uint32_t l2 = ntohl(enc); BOOST_CHECK_EQUAL(l, l2); data.clear(); uint16_t s = 0x1122; - Codec::encode(std::back_inserter(data), s); + Codec::encode(std::back_inserter(data))(s); uint32_t s2 = ntohs(*reinterpret_cast<const uint32_t*>(data.data())); BOOST_CHECK_EQUAL(s, s2); } @@ -116,14 +120,58 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(testEncodeDecode, T, AllTypes) string data; T t; testValue(t); - Codec::encode(std::back_inserter(data), t); + Codec::encode(std::back_inserter(data))(t); BOOST_CHECK_EQUAL(Codec::size(t), data.size()); T t2; - Codec::decode(data.begin(), t2); + Codec::decode(data.begin())(t2); BOOST_CHECK_EQUAL(t,t2); } +struct TestMe { + bool encoded, decoded; + char value; + TestMe(char v) : encoded(), decoded(), value(v) {} + template <class S> void encode(S& s) { encoded=true; s(value); } + template <class S> void decode(S& s) { decoded=true; s(value); } + template <class S> void serialize(S& s) { s.split(*this); } +}; + +BOOST_AUTO_TEST_CASE(testSplit) { + string data; + TestMe t1('x'); + Codec::encode(std::back_inserter(data))(t1); + BOOST_CHECK(t1.encoded); + BOOST_CHECK(!t1.decoded); + BOOST_CHECK_EQUAL(data, "x"); + + TestMe t2('y'); + Codec::decode(data.begin())(t2); + BOOST_CHECK(!t2.encoded); + BOOST_CHECK(t2.decoded); + BOOST_CHECK_EQUAL(t2.value, 'x'); +} + +BOOST_AUTO_TEST_CASE(testControlEncodeDecode) { + string data; + Control::Holder h(in_place<connection::Tune>(1,2,3,4)); + Codec::encode(std::back_inserter(data))(h); + + BOOST_CHECK_EQUAL(data.size(), Codec::size(h)); + + Codec::Decode<string::iterator> decode(data.begin()); + Control::Holder h2; + decode(h2); + + BOOST_REQUIRE(h2.get()); + BOOST_CHECK_EQUAL(h2.get()->getClassCode(), connection::CODE); + BOOST_CHECK_EQUAL(h2.get()->getCode(), uint8_t(connection::Tune::CODE)); + connection::Tune& tune=static_cast<connection::Tune&>(*h2.get()); + BOOST_CHECK_EQUAL(tune.channelMax, 1u); + BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u); + BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u); + BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u); +} QPID_AUTO_TEST_SUITE_END() |