diff options
author | Alan Conway <aconway@apache.org> | 2008-04-10 20:15:08 +0000 |
---|---|---|
committer | Alan Conway <aconway@apache.org> | 2008-04-10 20:15:08 +0000 |
commit | 26473ff13bc938af2893200fea7e62e3d79d173f (patch) | |
tree | a32d0de908837cc8378822472ccdb3726f61e896 /cpp | |
parent | e583c70d5bb452cc13c6e76372a2b7b681498d8c (diff) | |
download | qpid-python-26473ff13bc938af2893200fea7e62e3d79d173f.tar.gz |
amqp_0_10: Encoding for packed structs.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@646943 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp')
-rwxr-xr-x | cpp/rubygen/0-10/specification.rb | 34 | ||||
-rwxr-xr-x | cpp/rubygen/amqpgen.rb | 1 | ||||
-rwxr-xr-x | cpp/rubygen/cppgen.rb | 12 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Packer.h | 30 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/built_in_types.h | 15 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/complex_types.cpp | 19 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/complex_types.h | 1 | ||||
-rw-r--r-- | cpp/src/tests/amqp_0_10/serialize.cpp | 44 |
8 files changed, 108 insertions, 48 deletions
diff --git a/cpp/rubygen/0-10/specification.rb b/cpp/rubygen/0-10/specification.rb index 020cb63c89..7e73d1c91e 100755 --- a/cpp/rubygen/0-10/specification.rb +++ b/cpp/rubygen/0-10/specification.rb @@ -38,10 +38,13 @@ class Specification < CppGen genl "const char* NAME=\"#{c.fqname}\";" end + def visitable?(x) x.code and x.size=="4" end + # Used by structs, commands and controls. def action_struct_h(x, base, consts, &block) genl - struct(x.classname, "public #{base}") { + base = visitable?(x) ? ["public #{base}"] : [] + struct(x.classname, *base) { x.fields.each { |f| genl "#{f.amqp2cpp} #{f.cppname};" } genl genl "static const char* NAME;" @@ -50,10 +53,13 @@ class Specification < CppGen } 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? - genl "void accept(Visitor&);" - genl "void accept(ConstVisitor&) const;" + ctor_decl("explicit #{x.classname}", x.parameters(true)) + + if visitable? x + genl "void accept(Visitor&);" + genl "void accept(ConstVisitor&) const;" + end + if (x.fields.empty?) genl "template <class S> void serialize(S&) {}" else @@ -75,13 +81,9 @@ class Specification < CppGen 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? - # 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 + ctor_defn(ctor, x.parameters, x.initializers) {} + + if visitable? x genl "void #{x.classname}::accept(Visitor& v) { v.visit(*this); }" genl "void #{x.classname}::accept(ConstVisitor& v) const { v.visit(*this); }" end @@ -169,9 +171,7 @@ class Specification < CppGen include "#{@dir}/specification_fwd" include "#{@dir}/all_built_in_types" include "#{@dir}/Packer.h" - include "<boost/call_traits.hpp>" include "<iosfwd>" - genl "using boost::call_traits;" namespace(@ns) { # Structs that must be generated early because # they are used by other definitions: @@ -190,8 +190,7 @@ class Specification < CppGen include "#{@dir}/specification" include "#{@dir}/exceptions" include "<iostream>" - # FIXME aconway 2008-03-04: add Struct visitors. - ["Command","Control"].each { |x| include "#{@dir}/Apply#{x}" } + ["Command","Control", "Struct"].each { |x| include "#{@dir}/Apply#{x}" } namespace(@ns) { each_class_ns { |c| class_cpp c @@ -328,8 +327,7 @@ class Specification < CppGen gen_proxy 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)) + gen_visitable("Struct", @amqp.collect_all(AmqpStruct).select { |s| s.code}) end end diff --git a/cpp/rubygen/amqpgen.rb b/cpp/rubygen/amqpgen.rb index 9e4bb7c22c..bf473506d4 100755 --- a/cpp/rubygen/amqpgen.rb +++ b/cpp/rubygen/amqpgen.rb @@ -312,6 +312,7 @@ class AmqpAction < AmqpElement def initialize(xml,amqp) super; end amqp_child_reader :implement, :field, :response amqp_attr_reader :code + def size() "4" end # Encoded as a size 4 Struct end class AmqpControl < AmqpAction diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb index 0c17b68335..757894163d 100755 --- a/cpp/rubygen/cppgen.rb +++ b/cpp/rubygen/cppgen.rb @@ -133,7 +133,10 @@ class AmqpField end return amqp2cpp end - def paramtype() "call_traits<#{fqtypename}>::param_type"; end + def paramtype() + /^(int|uint|char|boolean|bit)/ === type_ ? fqtypename : "const #{fqtypename}&" + end + def param_default() "=#{fqtypename}()" end end class AmqpMethod @@ -151,7 +154,11 @@ class AmqpMethod end module AmqpHasFields - def parameters() fields.map { |f| "#{f.paramtype} #{f.cppname}_"} end + def parameters(with_default=nil) + fields.map { |f| + "#{f.paramtype} #{f.cppname}_#{f.param_default if with_default}" + } + end def unused_parameters() fields.map { |f| "#{f.paramtype} /*#{f.cppname}_*/"} end def arguments() fields.map { |f| "#{f.cppname}_"} end def values() fields.map { |f| "#{f.cppname}"} end @@ -239,6 +246,7 @@ class AmqpStruct def cppname() cpptype.name; end # preview def fqclassname() containing_class.nsname+"::"+name.typename; end def classname() name.typename; end + def full_code() (containing_class.code.hex << 8)+code.hex; end end class CppGen < Generator diff --git a/cpp/src/qpid/amqp_0_10/Packer.h b/cpp/src/qpid/amqp_0_10/Packer.h index 8943dc4c51..90d72408b5 100644 --- a/cpp/src/qpid/amqp_0_10/Packer.h +++ b/cpp/src/qpid/amqp_0_10/Packer.h @@ -24,6 +24,7 @@ #include <boost/optional.hpp> #include <boost/none.hpp> +#include "qpid/amqp_0_10/built_in_types.h" namespace qpid { namespace amqp_0_10 { @@ -60,17 +61,21 @@ class PackBits { public: PackBits() : bit(1), bits(0) {} - void setBit() { bits |= bit; bit <<= 1; } - void skipBit() { bit <<= 1; } - + void setBit(bool b) { if (b) bits |= bit; bit <<= 1; } uint32_t getBits() { return bits; } - - template <class T> PackBits& operator()(const T&) { setBit(); return *this; } + /** The bit is always set for non-optional values. */ + template <class T> + PackBits& operator()(const T&) { setBit(1); return *this; } + + /** For optional values the bit is set if the value is present. */ template <class T> PackBits& operator()(const boost::optional<T>& opt) { - opt ? setBit() : skipBit(); return *this; + setBit(opt); return *this; } + /** Bits are special optional values */ + PackBits& operator()(Bit b) { setBit(b); return *this; } + private: uint32_t bit; uint32_t bits; @@ -83,12 +88,23 @@ template<class T> uint32_t packBits(const T& t) { return pack.getBits(); } +/** Decode members enabled by Bits */ template <class Decoder, class Bits> class PackedDecoder { public: PackedDecoder(Decoder& d, Bits b) : decode(d), bits(b) {} - template <class T> PackedDecoder& operator()(T& t) { decode(t); return *this; } + template <class T> PackedDecoder& operator()(T& t) { + if (bits & 1) + decode(t); + else + t = T(); + // FIXME aconway 2008-04-10: When we have all optionals + // represented by boost::optional the line above should be: + // throw CommandInvalidException("A required value was omitted."); + bits >>= 1; + return *this; + } template <class T> PackedDecoder& operator()(boost::optional<T>& opt) { if (bits & 1) { 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 5b79faef36..dccb6a4785 100644 --- a/cpp/src/qpid/amqp_0_10/built_in_types.h +++ b/cpp/src/qpid/amqp_0_10/built_in_types.h @@ -61,14 +61,17 @@ inline std::ostream& operator<<(std::ostream& o, const Wrapper<T>& w) { struct Void { template <class S> void serialize(S&) {} }; inline std::ostream& operator<<(std::ostream& o, const Void&) { return o; } -/** Bit type - bool value with no encoding. */ -struct Bit : Wrapper<bool> { - template <class S> void serialize(S& s) { s.split(*this); } - template <class S> void encode(S&) const {} - template <class S> void decode(S&) { value=true; } +/** Bit is a presence indicator - an optional value with no encoding. */ +struct Bit : public Wrapper<bool> { + Bit(bool b=false) : Wrapper<bool>(b) {} + using Wrapper<bool>::operator=; + template <class S> void serialize(S& s) { s.split(*this); } + template <class S> void encode(S&) const { } + template <class S> void decode(S&) { *this = true; } }; + inline std::ostream& operator<<(std::ostream& o, const Bit& b) { - return o << b.value; + return o << bool(b); } // Fixed size types diff --git a/cpp/src/qpid/amqp_0_10/complex_types.cpp b/cpp/src/qpid/amqp_0_10/complex_types.cpp index 93550b9c20..78ddfeb026 100644 --- a/cpp/src/qpid/amqp_0_10/complex_types.cpp +++ b/cpp/src/qpid/amqp_0_10/complex_types.cpp @@ -21,7 +21,7 @@ #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/ApplyStruct.h" #include "qpid/amqp_0_10/apply.h" #include <iostream> @@ -52,15 +52,11 @@ 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; } + +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); } struct PrintVisitor { typedef std::ostream& result_type; @@ -71,8 +67,7 @@ struct PrintVisitor { std::ostream& operator<<(std::ostream& o, const Command& x) { return apply(PrintVisitor(o), x); } std::ostream& operator<<(std::ostream& o, const Control& x) { return apply(PrintVisitor(o), x); } -// FIXME aconway 2008-04-07: -// std::ostream& operator<<(std::ostream& o, const Struct& x) { apply(PrintVisitor(o), x); } +std::ostream& operator<<(std::ostream& o, const Struct& x) { return apply(PrintVisitor(o), x); } }} // 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 index c8080b867d..5d327cc46e 100644 --- a/cpp/src/qpid/amqp_0_10/complex_types.h +++ b/cpp/src/qpid/amqp_0_10/complex_types.h @@ -90,6 +90,7 @@ struct Control }; std::ostream& operator<<(std::ostream&, const Control&); +// Note: only coded structs inherit from Struct. struct StructVisitor; struct ConstStructVisitor; struct StructHolder; diff --git a/cpp/src/tests/amqp_0_10/serialize.cpp b/cpp/src/tests/amqp_0_10/serialize.cpp index 2e1f2c40a8..8928a9fbc9 100644 --- a/cpp/src/tests/amqp_0_10/serialize.cpp +++ b/cpp/src/tests/amqp_0_10/serialize.cpp @@ -30,6 +30,7 @@ #include "qpid/amqp_0_10/Codec.h" #include "qpid/amqp_0_10/specification.h" #include "qpid/amqp_0_10/ControlHolder.h" +#include "qpid/amqp_0_10/StructHolder.h" #include "qpid/amqp_0_10/FrameHeader.h" #include "qpid/amqp_0_10/Map.h" #include "qpid/amqp_0_10/Unit.h" @@ -216,8 +217,9 @@ struct DummyPacked { static const uint8_t PACK=1; boost::optional<char> i, j; char k; - DummyPacked(char a=0, char b=0, char c=0) : i(a), j(b), k(c) {} - template <class S> void serialize(S& s) { s(i)(j)(k); } + Bit l,m; + DummyPacked(char a=0, char b=0, char c=0) : i(a), j(b), k(c), l(), m() {} + template <class S> void serialize(S& s) { s(i)(j)(k)(l)(m); } }; Packer<DummyPacked> serializable(DummyPacked& d) { return Packer<DummyPacked>(d); } @@ -226,7 +228,9 @@ BOOST_AUTO_TEST_CASE(testPackBits) { DummyPacked d('a','b','c'); BOOST_CHECK_EQUAL(packBits(d), 7u); d.j = boost::none; - BOOST_CHECK_EQUAL(packBits(d), 5u); + BOOST_CHECK_EQUAL(packBits(d), 5u); + d.m = true; + BOOST_CHECK_EQUAL(packBits(d), 0x15u); } @@ -298,6 +302,40 @@ BOOST_AUTO_TEST_CASE(testArray) { BOOST_CHECK_EQUAL(data,data2); } +BOOST_AUTO_TEST_CASE(testStruct) { + string data; + + message::DeliveryProperties dp; + BOOST_CHECK(!dp.discardUnroutable); + dp.immediate = true; + dp.redelivered = false; + dp.priority = message::MEDIUM; + dp.exchange = "foo"; + + Codec::encode(back_inserter(data))(dp); + uint16_t encodedBits=uint8_t(data[1]); // Little-endian + encodedBits <<= 8; + encodedBits += uint8_t(data[0]); + BOOST_CHECK_EQUAL(encodedBits, packBits(dp)); + + data.clear(); + Struct::Holder h(dp); + Codec::encode(back_inserter(data))(h); + + Struct::Holder h2; + Codec::decode(data.begin())(h2); + BOOST_CHECK_EQUAL(h2.getClassCode(), Uint8(message::DeliveryProperties::CLASS_CODE)); + BOOST_CHECK_EQUAL(h2.getCode(), Uint8(message::DeliveryProperties::CODE)); + message::DeliveryProperties* dp2 = + dynamic_cast<message::DeliveryProperties*>(h2.get()); + BOOST_CHECK(dp2); + BOOST_CHECK(!dp2->discardUnroutable); + BOOST_CHECK(dp2->immediate); + BOOST_CHECK(!dp2->redelivered); + BOOST_CHECK_EQUAL(dp2->priority, message::MEDIUM); + BOOST_CHECK_EQUAL(dp2->exchange, "foo"); +} + struct RecodeUnit { template <class T> void operator() (const T& t) { |