Author: aconway
Date: Thu Apr 10 13:15:08 2008
New Revision: 646943

URL: http://svn.apache.org/viewvc?rev=646943&view=rev
Log:

amqp_0_10: Encoding for packed structs.

Modified:
    incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb
    incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb
    incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.h
    incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp

Modified: incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb?rev=646943&r1=646942&r2=646943&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb Thu Apr 10 
13:15:08 2008
@@ -38,10 +38,13 @@
     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 @@
       }
       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 @@
     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 @@
       include "[EMAIL PROTECTED]/specification_fwd"
       include "[EMAIL PROTECTED]/all_built_in_types"
       include "[EMAIL PROTECTED]/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 @@
       include "[EMAIL PROTECTED]/specification"
       include "[EMAIL PROTECTED]/exceptions"
       include "<iostream>"
-      # FIXME aconway 2008-03-04: add Struct visitors.
-      ["Command","Control"].each { |x| include "[EMAIL PROTECTED]/Apply#{x}" }
+      ["Command","Control", "Struct"].each { |x| include "[EMAIL 
PROTECTED]/Apply#{x}" }
       namespace(@ns) { 
         each_class_ns { |c|
           class_cpp c
@@ -328,8 +327,7 @@
     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
 

Modified: incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb?rev=646943&r1=646942&r2=646943&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb Thu Apr 10 13:15:08 2008
@@ -312,6 +312,7 @@
   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

Modified: incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb?rev=646943&r1=646942&r2=646943&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb Thu Apr 10 13:15:08 2008
@@ -133,7 +133,10 @@
     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 @@
 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 @@
   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

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h?rev=646943&r1=646942&r2=646943&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h Thu Apr 10 
13:15:08 2008
@@ -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 @@
   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 @@
     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) {

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h?rev=646943&r1=646942&r2=646943&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h Thu Apr 
10 13:15:08 2008
@@ -61,14 +61,17 @@
 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

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp?rev=646943&r1=646942&r2=646943&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp 
(original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp Thu Apr 
10 13:15:08 2008
@@ -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 @@
 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 @@
 
 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
 

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.h?rev=646943&r1=646942&r2=646943&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/complex_types.h Thu Apr 10 
13:15:08 2008
@@ -90,6 +90,7 @@
 };
 std::ostream& operator<<(std::ostream&, const Control&);
 
+// Note: only coded structs inherit from Struct.
 struct StructVisitor;
 struct ConstStructVisitor;
 struct StructHolder;

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp?rev=646943&r1=646942&r2=646943&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp Thu Apr 10 
13:15:08 2008
@@ -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 @@
     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 @@
     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);
 }
 
 
@@ -296,6 +300,40 @@
     string data2;
     Codec::encode(back_inserter(data2))(x);
     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 {


Reply via email to