You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2008/02/29 23:07:45 UTC

svn commit: r632457 - in /incubator/qpid/trunk/qpid/cpp: rubygen/ rubygen/0-10/ src/ src/qpid/ src/qpid/amqp_0_10/ src/qpid/framing/ src/tests/

Author: aconway
Date: Fri Feb 29 14:07:40 2008
New Revision: 632457

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

Template visitors for amqp_0_10::Command, Control and Struct.
Serialization for all str/vbin types.

Added:
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/apply.h   (with props)
    incubator/qpid/trunk/qpid/cpp/src/tests/apply.cpp   (with props)
Removed:
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/visitors.h
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/Makefile.am
    incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Decimal.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/helpers.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/helpers.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Uuid.h
    incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am
    incubator/qpid/trunk/qpid/cpp/src/tests/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=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb Fri Feb 29 14:07:40 2008
@@ -19,10 +19,8 @@
         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 @@
   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 @@
     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 @@
         # 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 @@
       }
     }
   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 <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()
+  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
 

Modified: incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb Fri Feb 29 14:07:40 2008
@@ -131,6 +131,12 @@
     @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 @@
   
   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 @@
 
   def fqname() nil; end
 
-  # TODO aconway 2008-02-21: methods by role.
-  
   private
   
   # Merge contents of elements.

Modified: incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb Fri Feb 29 14:07:40 2008
@@ -57,6 +57,7 @@
   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 @@
   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 @@
   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
 

Modified: incubator/qpid/trunk/qpid/cpp/src/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/Makefile.am?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/Makefile.am (original)
+++ incubator/qpid/trunk/qpid/cpp/src/Makefile.am Fri Feb 29 14:07:40 2008
@@ -104,10 +104,10 @@
   $(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 @@
 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 \

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h Fri Feb 29 14:07:40 2008
@@ -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 <boost/cast.hpp>
-#include <boost/array.hpp>
+#include <boost/type_traits/remove_const.hpp>
 #include <boost/utility/enable_if.hpp>
-#include <boost/type_traits/is_class.hpp>
+#include <boost/type_traits/is_const.hpp>
+#include <boost/type_traits/add_const.hpp>
+#include <algorithm>
 
 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 Derived> class Serializer {
   public:
-
-    /** Call T::serialize() for classes that have their own serialize function */
-    template <class T>
-    typename boost::enable_if<boost::is_class<T>, Derived>::type
-    operator()(T& t) { t.serialize(self()); return self(); }
-
-    template <class T, size_t N>
-    Derived& operator()(boost::array<T,N>& 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 <class T> Derived& raw(T& t) {
-        return self().raw(&t, sizeof(T));
-    }
-
-  private:
-    Derived& self() { return *static_cast<Derived*>(this); }
-};
-
-/** Like Serializer but does not modify the values passed to it. */
-template <class Derived> class ConstSerializer {
-  public:
     template <class T>
-    typename boost::enable_if<boost::is_class<T>, Derived>::type
-    operator()(const T& t) {
-        // Const cast so we don't have to write 2 serialize() functions
-        // for every class.
-        const_cast<T&>(t).serialize(self());
+    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());
         return self();
     }
 
-    template <class T, size_t N>
-    Derived& operator()(const boost::array<T,N>& a) {
-        std::for_each(a.begin(), a.end(), self());
+    template <class Iter> 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 <class T> Derived& raw(const T& t) {
-        return self().raw(&t, sizeof(T));
-    }
-
   private:
     Derived& self() { return *static_cast<Derived*>(this); }
 };
 
-
 } // namespace qpid
 
-#endif  /*!QPID_SERIALIZERBASE_H*/
+#endif  /*!QPID_SERIALIZER_H*/

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h Fri Feb 29 14:07:40 2008
@@ -32,70 +32,47 @@
 
 namespace qpid {
 namespace amqp_0_10 {
-
 /**
  * AMQP 0-10 encoding and decoding.
  */
-struct Codec
-{
-    template <class T>
-    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 <class Out> struct Encode : public ConstSerializer<Encode<Out> > {
-        Out out;
+class Codec {
+  public:
+    /** Encode to an output byte iterator */
+    template <class OutIter>
+    class Encode : public Serializer<Encode<OutIter> > {
+      public:
+        Encode(OutIter o) : out(o) {}
 
-        Encode(Out o) : out(o) {}
+        using Serializer<Encode<OutIter> >::operator();
 
-        using ConstSerializer<Encode<Out> >::operator();
-        using ConstSerializer<Encode<Out> >::raw;
-
-        template <class T> 
+        template <class T>
         typename boost::enable_if<boost::is_integral<T>, 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 <class T>
         typename boost::enable_if<boost::is_float<T>, Encode&>::type
-        operator()(const T& x) { return raw(x); }
-
+        operator()(const T& x) { raw(&x, sizeof(x)); return *this; }
 
-        template<class T, class SizeType>
-        Encode& operator()(const CodableString<T,SizeType>& 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<Out> >;
-
-        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 <class In> struct Decode : public Serializer<Decode<In> > {
-        In in;
-        Decode(In i) : in(i) {}
-
-        using Serializer<Decode<In> >::operator();
-        using Serializer<Decode<In> >::raw;
-
+    template <class InIter>
+    class Decode : public Serializer<Decode<InIter> > {
+      public:
+        Decode(InIter i) : in(i) {}
+        
+        using Serializer<Decode<InIter> >::operator();
+        
         template <class T>
         typename boost::enable_if<boost::is_integral<T>, Decode&>::type
         operator()(T& x) {
@@ -106,10 +83,10 @@
 
         template <class T>
         typename boost::enable_if<boost::is_float<T>, Decode&>::type
-        operator()(T& x) { return raw(&x, sizeof(x)); }
+        operator()(T& x) { raw(&x, sizeof(x)); return *this; }
 
         template<class T, class SizeType>
-        Decode& operator()(CodableString<T,SizeType>& str) {
+        Decode& operator()(SerializableString<T,SizeType>& str) {
             SizeType n;
             (*this)(n);
             str.resize(n);
@@ -117,54 +94,45 @@
             return *this;
         }
 
-      private:
-      friend class Serializer<Decode<In> >;
-        
-        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<Size> {
+    
+    class Size : public Serializer<Size> {
+      public:
         Size() : size(0) {}
-        size_t size;
+
         operator size_t() const { return size; }
 
-        using ConstSerializer<Size>::operator();
-        using ConstSerializer<Size>::raw;
+        using Serializer<Size>::operator();
         
         template <class T>
         typename boost::enable_if<boost::is_arithmetic<T>, Size&>::type
         operator()(const T&) { size += sizeof(T); return *this; }
 
-        template <class T, size_t N>
-        Size& operator()(const boost::array<T,N>&) {
-            size += sizeof(boost::array<T,N>);
-            return *this;
-        }
-
         template<class T, class SizeType>
-        Size& operator()(const CodableString<T,SizeType>& str) {
+        Size& operator()(const SerializableString<T,SizeType>& str) {
             size += sizeof(SizeType) + str.size()*sizeof(T);
             return *this;
         }
 
+        void raw(const void*, size_t n){ size += n; }
 
       private:
-      friend class ConstSerializer<Size>;
-
-        Size& raw(void*, size_t s) { size += s; return *this; }
-        
-        Size& byte(char) { ++size; return *this; }        
+        size_t size;
     };
 
     template <class Out, class T>
     static void encode(Out o, const T& x) {
-        Encode<Out>encode(o);
+        Encode<Out> encode(o);
         encode(x);
     }
 
@@ -180,6 +148,18 @@
         sz(x);
         return sz;
     }
+
+  private:
+    template <class T> 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

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Decimal.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Decimal.h?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Decimal.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Decimal.h Fri Feb 29 14:07:40 2008
@@ -30,7 +30,7 @@
     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<class E, class M>
 inline std::ostream& operator<<(std::ostream& o, const Decimal<E,M>& d) {
-    M pow10=10^d.exponent;
-    return o << d.mantissa/pow10 << "." << d.mantissa%pow10;
+    return o << "Decimal{" << d.mantissa << "/10^" << (int)d.exponent << "}";
 }
 }}
 

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/apply.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/apply.h?rev=632457&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/apply.h (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/apply.h Fri Feb 29 14:07:40 2008
@@ -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 <boost/optional.hpp>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+template <class F, class R=typename F::result_type> struct FunctionAndResult {
+    F* functor;
+    boost::optional<R> result;
+
+    FunctionAndResult() : functor(0) {}
+    template <class T> void invoke(T t) { result=(*functor)(t); }
+    R getResult() { return *result; }
+};
+
+// void result is special case.
+template <class F> struct FunctionAndResult<F, void> {
+    F* functor;
+    
+    FunctionAndResult() : functor(0) {}
+    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;
+};
+
+// Specialize for each visitor type
+template <class V, class F> struct ApplyVisitor;
+
+/** Apply a functor to a visitable object.
+ * The functor can have operator() overloads for each visitable type
+ * and/or templated operator().
+ */
+template <class F, class Visitable>
+typename F::result_type apply(F& functor, Visitable& visitable) {
+    ApplyVisitor<typename Visitable::Visitor, F> visitor;
+    visitor.functor=&functor;
+    visitable.accept(visitor);
+    return visitor.getResult();
+}
+
+template <class F, class Visitable>
+typename F::result_type apply(const F& functor, Visitable& visitable) {
+    ApplyVisitor<typename Visitable::Visitor, const F> visitor;
+    visitor.functor=&functor;
+    visitable.accept(visitor);
+    return visitor.getResult();
+}
+
+}} // namespace qpid::amqp_0_10
+
+#endif  /*!QPID_AMQP_0_10_APPLY_H*/

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/apply.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/apply.h
------------------------------------------------------------------------------
    svn:keywords = Rev Date

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=632457&r1=632456&r2=632457&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 Fri Feb 29 14:07:40 2008
@@ -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 <boost/array.hpp>
 #include <stdint.h>
 #include <string>
+#include <ostream>
 #include <vector>
 
 /**@file Mapping from built-in AMQP types to C++ types */
@@ -53,15 +53,19 @@
 typedef uint8_t Bin8;
 typedef uint8_t Uint8;
 
-typedef boost::array<uint8_t,128> Bin1024; 
-typedef boost::array<uint8_t,16> Bin128;
-typedef boost::array<uint8_t,2> Bin16;
-typedef boost::array<uint8_t,32> Bin256;
-typedef boost::array<uint8_t,4> Bin32;
-typedef boost::array<uint8_t,5> Bin40; 
-typedef boost::array<uint8_t,64> Bin512;
-typedef boost::array<uint8_t,8> Bin64;
-typedef boost::array<uint8_t,9> Bin72;
+template <size_t N> struct Bin : public boost::array<char, N> {
+    template <class S> 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 @@
 
 /** Template for length-prefixed strings/arrays. */
 template <class T, class SizeType>
-struct CodableString : public std::basic_string<T> {};
+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());
+    }
+};
+
+// TODO aconway 2008-02-29: separate ostream ops
+template <class T, class SizeType>
+std::ostream& operator<<(std::ostream& o, const SerializableString<T,SizeType>& s) {
+    const std::basic_string<T> str(s);
+    return o << str.c_str();    // TODO aconway 2008-02-29: why doesn't o<<str work?
+}
 
 // Variable width types
-typedef CodableString<Uint8, Uint8> Vbin8;
-typedef CodableString<char, Uint8> Str8Latin;
-typedef CodableString<char, Uint8> Str8;
-typedef CodableString<Uint16, Uint8> Str8Utf16;
-
-typedef CodableString<Uint8, Uint16> Vbin16;
-typedef CodableString<char, Uint16> Str16Latin;
-typedef CodableString<char, Uint16> Str16;
-typedef CodableString<Uint16, Uint16> Str16Utf16;
+typedef SerializableString<Uint8, Uint8> Vbin8;
+typedef SerializableString<char, Uint8> Str8Latin;
+typedef SerializableString<char, Uint8> Str8;
+typedef SerializableString<Uint16, Uint8> Str8Utf16;
+
+typedef SerializableString<Uint8, Uint16> Vbin16;
+typedef SerializableString<char, Uint16> Str16Latin;
+typedef SerializableString<char, Uint16> Str16;
+typedef SerializableString<Uint16, Uint16> Str16Utf16;
 
-typedef CodableString<Uint8, Uint32> Vbin32;
-
-// FIXME aconway 2008-02-26: array encoding
-template <class T> struct Array : public std::vector<T> {};
+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 {};

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/helpers.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/helpers.cpp?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/helpers.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/helpers.cpp Fri Feb 29 14:07:40 2008
@@ -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 {

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/helpers.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/helpers.h?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/helpers.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/helpers.h Fri Feb 29 14:07:40 2008
@@ -24,7 +24,6 @@
 #include <string>
 
 namespace qpid {
-
 namespace amqp_0_10 {
 
 // Look up names by code
@@ -35,19 +34,19 @@
 
 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;
 };
 

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Uuid.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Uuid.h?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Uuid.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Uuid.h Fri Feb 29 14:07:40 2008
@@ -67,7 +67,7 @@
     std::string str() const;
 
     template <class S> void serialize(S& s) {
-        s(static_cast<boost::array<uint8_t, 16>&>(*this));
+        s.raw(begin(), size());
     }
 };
 

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am Fri Feb 29 14:07:40 2008
@@ -39,7 +39,7 @@
 	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

Added: incubator/qpid/trunk/qpid/cpp/src/tests/apply.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/apply.cpp?rev=632457&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/apply.cpp (added)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/apply.cpp Fri Feb 29 14:07:40 2008
@@ -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 <class T> 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 <class T>
+    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 <class T>
+    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()

Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/apply.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/apply.cpp
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/serialize.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/serialize.cpp?rev=632457&r1=632456&r2=632457&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/serialize.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/serialize.cpp Fri Feb 29 14:07:40 2008
@@ -31,7 +31,7 @@
 #include <boost/mpl/empty_sequence.hpp>
 #include <iterator>
 #include <string>
-#include <ostream>
+#include <iostream>
 #include <netinet/in.h>
 
 // Missing operators needed for tests.
@@ -52,15 +52,6 @@
 }
 }
 
-namespace amqp_0_10 {
-template <class T, class SizeType>
-std::ostream& operator<<(std::ostream& out, const CodableString<T,SizeType>& str) {
-    std::ostream_iterator<T> o(out, " ");
-    std::copy(str.begin(), str.end(), o);
-    return out;
-}
-}
-
 } // qpid
 
 
@@ -90,34 +81,37 @@
 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<const uint32_t&>(*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<const uint32_t*>(data.data()));
     BOOST_CHECK_EQUAL(s, s2);
 }
 
+// Assign test values to the various types.
 void testValue(bool& b) { b = true; }
 template <class T> typename boost::enable_if<boost::is_arithmetic<T> >::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 <class E, class M> void testValue(Decimal<E,M>& d) { d.exponent=2; d.mantissa=1234; }
+template <class E, class M> void testValue(Decimal<E,M>& d) { d.exponent=2; d.mantissa=0x1122; }
 void testValue(SequenceNo& s) { s = 42; }
-template <class T, size_t N> void testValue(boost::array<T,N>& a) { a.assign(42); }
-template <class T, class SizeType> void testValue(CodableString<T, SizeType>& s) {
+template <size_t N> void testValue(Bin<N>& a) { a.assign(42); }
+template <class T, class S> void testValue(SerializableString<T, S>& 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<Str8, Str16>::type TestTypes;
+BOOST_AUTO_TEST_CASE_TEMPLATE(testEncodeDecode, T, AllTypes)
 {
     string data;
     T t;