summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp')
-rwxr-xr-xcpp/rubygen/0-10/specification.rb34
-rwxr-xr-xcpp/rubygen/amqpgen.rb1
-rwxr-xr-xcpp/rubygen/cppgen.rb12
-rw-r--r--cpp/src/qpid/amqp_0_10/Packer.h30
-rw-r--r--cpp/src/qpid/amqp_0_10/built_in_types.h15
-rw-r--r--cpp/src/qpid/amqp_0_10/complex_types.cpp19
-rw-r--r--cpp/src/qpid/amqp_0_10/complex_types.h1
-rw-r--r--cpp/src/tests/amqp_0_10/serialize.cpp44
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) {