Author: aconway
Date: Tue Aug  7 15:28:06 2007
New Revision: 563683

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

        * Summary: new Frame type to replace AMQFrame. Instead of holding
          a shared_ptr to a heap-allocated AMQBody subclass, it holds the
          body in-line in a boost::variant of all the concrete AMQBody
          subclasses. Actually there are nested variants, the compiler
          does not cope well with a single variant of 130-some types.

          Creating, encoding and decoding a local Frame doess 0 heap
          allocation apart from that done by the concrete
          AMQBody::encode/decode - e.g. method bodies with std::string
          fields.  for method bodies

          All variants contain type boost::blank. This guarantees 0 heap
          alloocation by the variant and represents the "uninitialized"
          state. variant.h provides NoBlankVisitor to help write visitors
          for variants containing blank. 
        
        * src/qpid/framing/MethodHolder.h, .cpp: Holds a variant
          containing a method body. 

        * src/qpid/framing/Frame.h, .cpp: New Frame holds body in a
          variant rather than via heap allocation.

        * src/qpid/framing/variant.h: Utilities for using boost::variant.

        * src/qpid/framing/amqp_types.h: Added FrameType typedef.

        * src/qpid/framing/AMQMethodBody.h: Friends with MethodHolder.

        * src/Makefile.am:
         - Improved ruby generation rule.
         - Run method_variants template.
         - Added new source files
         - Pre-compiled header rule for method_variants.h

        * rubygen/templates/method_variants.rb: Generate variants
          to hold methods of each class, and MethodVariant to hold all
          the class variants.

        * rubygen/cppgen.rb: variant, tuple methods.

        * MethodBodyClass.h.tmpl: Added default constructor to method bodies.

        * amqpgen.rb (AmqpRoot::merge): fix bug in merge.

Added:
    incubator/qpid/trunk/qpid/cpp/rubygen/templates/method_variants.rb   (with 
props)
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.cpp   (with props)
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.h   (with props)
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp   (with 
props)
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h   (with props)
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/variant.h   (with props)
    incubator/qpid/trunk/qpid/cpp/src/tests/Frame.cpp   (with props)
Modified:
    incubator/qpid/trunk/qpid/cpp/gentools/templ.cpp/MethodBodyClass.h.tmpl
    incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb
    incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb
    incubator/qpid/trunk/qpid/cpp/src/   (props changed)
    incubator/qpid/trunk/qpid/cpp/src/Makefile.am
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/   (props changed)
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/AMQMethodBody.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/amqp_types.h
    incubator/qpid/trunk/qpid/cpp/src/tests/   (props changed)
    incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am

Modified: 
incubator/qpid/trunk/qpid/cpp/gentools/templ.cpp/MethodBodyClass.h.tmpl
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/gentools/templ.cpp/MethodBodyClass.h.tmpl?view=diff&rev=563683&r1=563682&r2=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/gentools/templ.cpp/MethodBodyClass.h.tmpl 
(original)
+++ incubator/qpid/trunk/qpid/cpp/gentools/templ.cpp/MethodBodyClass.h.tmpl Tue 
Aug  7 15:28:06 2007
@@ -63,7 +63,7 @@
 
 ${mb_constructor_with_initializers}
 
-    ${CLASS}${METHOD}Body(ProtocolVersion version): ${mb_base_class}(version) 
{}
+    ${CLASS}${METHOD}Body(ProtocolVersion version=ProtocolVersion()    ): 
${mb_base_class}(version) {}
     virtual ~${CLASS}${METHOD}Body() {}
     
     // Attribute get methods

Modified: incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb?view=diff&rev=563683&r1=563682&r2=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/amqpgen.rb Tue Aug  7 15:28:06 2007
@@ -155,7 +155,7 @@
     from.elements.each { |from_child|
       tag,name = from_child.name, from_child.attributes["name"]
       to_child=to.elements["./[EMAIL PROTECTED]'#{name}']"]
-      to_child ? merge(to_child, from_child) : to.add(from_child.clone) }
+      to_child ? merge(to_child, from_child) : to.add(from_child.deep_clone) }
   end
 
   private :merge

Modified: incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb?view=diff&rev=563683&r1=563682&r2=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb Tue Aug  7 15:28:06 2007
@@ -128,6 +128,7 @@
 
   # Write a .cpp file.
   def cpp_file(path)
+    path = (/\.cpp$/ === path ? path : path+".cpp")
     file(path) do
       gen Copyright
       yield
@@ -157,14 +158,18 @@
     genl
     gen "#{type} #{name}"
     gen ": #{bases.join(', ')}" unless bases.empty?
-    genl "{"
-    yield
-    genl "};"
-    genl
+    scope(" {","};", &block)
   end
 
   def struct(name, *bases, &block) struct_class("struct", name, bases, 
&block); end
   def class_(name, *bases, &block) struct_class("class", name, bases, &block); 
end
-  def typedef(type, name) genl "typedef #{type} #{name};" end
+
+  def typedef(type, name) genl "typedef #{type} #{name};\n" end
+
+  def variant(types) "boost::variant<#{types.join(", ")}>"; end
+  def variantl(types) "boost::variant<#{types.join(", \n")}>"; end
+  def blank_variant(types) variant(["boost::blank"]+types); end
+  def tuple(types) "boost::tuple<#{types.join(', ')}>"; end
+  
 end
 

Added: incubator/qpid/trunk/qpid/cpp/rubygen/templates/method_variants.rb
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/templates/method_variants.rb?view=auto&rev=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/templates/method_variants.rb (added)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/templates/method_variants.rb Tue Aug  
7 15:28:06 2007
@@ -0,0 +1,72 @@
+#!/usr/bin/env ruby
+$: << ".."                      # Include .. in load path
+require 'cppgen'
+
+# Generate the full AMQP class/method model as C++ types.
+class AmqpCppModelGen < CppGen
+  
+  def initialize(outdir, amqp)
+    super(outdir, amqp)
+  end
+
+  def gen_set_variant(varname, idtype, pairs, errmsg)
+    pairs.sort!
+    scope("inline void setVariant(#{varname}& var, #{idtype} id) {") {
+      scope("switch (id) {") {
+        pairs.each { |i,t| 
+          genl "case #{i}: var=#{t}(); break;";
+        }
+        genl "default: THROW_QPID_ERROR(FRAMING_ERROR, 
(boost::format(\"#{errmsg}\")%id).str());"
+      }
+    }
+    genl
+  end
+
+  def gen_class(c)
+    varname="#{c.name.caps}Variant"
+    mtypes=c.methods.map { |m| m.body_name }
+    typedef(blank_variant(mtypes), varname)
+    genl
+    pairs=c.methods.map { |m| [m.index.to_i,m.body_name] }
+    gen_set_variant(varname, "MethodId", pairs,
+                    "%d is not a valid method index in class #{c.name}")
+    mtypes.each { |t|
+      genl "template<> struct ClassVariant<#{t}> { typedef #{varname} value; 
};"
+    }
+    genl
+  end
+
+  def gen_all()
+    varname="MethodVariant"
+    [EMAIL PROTECTED] { |c| "#{c.name.caps}Variant" }
+    [EMAIL PROTECTED] { |c| [c.index.to_i,"#{c.name.caps}Variant"] }
+    typedef(blank_variant(types), varname) 
+    genl
+    gen_set_variant(varname, "ClassId", pairs,
+                    "%d is not a valid class index.")
+  end
+
+  def generate()
+    h_file("qpid/framing/method_variants.h") {
+      @amqp.methods.each { |m| include "qpid/framing/#{m.body_name}.h"}
+      include "qpid/framing/amqp_types.h"
+      include "qpid/QpidError.h"
+      include "qpid/framing/variant.h"
+      include "<boost/format.hpp>"
+      genl
+      namespace("qpid::framing") {
+        genl "// Metafunction returns class variant containing method T."
+        genl "template <class T> struct ClassVariant {};"
+        genl
+        @amqp.classes.each { |c| gen_class c }
+      }
+      namespace("qpid::framing") {
+        gen_all
+        genl
+      }
+    }
+  end
+end
+
+AmqpCppModelGen.new(Outdir, Amqp).generate();
+

Propchange: incubator/qpid/trunk/qpid/cpp/rubygen/templates/method_variants.rb
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/rubygen/templates/method_variants.rb
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/qpid/trunk/qpid/cpp/src/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Aug  7 15:28:06 2007
@@ -9,3 +9,4 @@
 stamp-h1
 generate.mk
 rubygen.mk
+method_variants.h

Modified: incubator/qpid/trunk/qpid/cpp/src/Makefile.am
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/Makefile.am?view=diff&rev=563683&r1=563682&r2=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/Makefile.am (original)
+++ incubator/qpid/trunk/qpid/cpp/src/Makefile.am Tue Aug  7 15:28:06 2007
@@ -43,13 +43,15 @@
 
 rgen_dir=$(top_srcdir)/rubygen
 rgen_tdir=$(rgen_dir)/templates
-rgen_script=$(rgen_dir)/generate
-rgen_cmd=ruby -I $(rgen_dir) $(rgen_script)
+rgen_generator=$(rgen_dir)/generate $(rgen_dir)/amqpgen.rb 
$(rgen_dir)/cppgen.rb
 
-rgen_templates=$(rgen_tdir)/frame_body_lists.rb $(rgen_tdir)/Session.rb
+rgen_cmd=ruby -I $(rgen_dir) $(rgen_dir)/generate
+rgen_templates=$(rgen_tdir)/method_variants.rb 
$(rgen_tdir)/frame_body_lists.rb  $(rgen_tdir)/Session.rb
 
-rubygen.mk: $(rgen_script) $(specs) $(rgen_templates)
-       gen=`$(rgen_cmd) . $(specs) $(rgen_templates)` ; echo Generated $$gen; 
echo rgen_srcs=$$gen > $@
+rubygen.mk: $(rgen_generator) $(specs) $(rgen_templates)
+       { echo "rgen_srcs= \\"; \
+       for f in `$(rgen_cmd) . $(specs) $(rgen_templates) `; do echo " $$f 
\\"; done; \
+       echo; } > $@
 
 $(rgen_srcs): rubygen.mk
 
@@ -172,7 +174,11 @@
   qpid/log/Selector.h \
   qpid/log/Statement.cpp \
   qpid/log/Statement.h \
-  qpid/memory.h
+  qpid/memory.h \
+  qpid/framing/Frame.cpp qpid/framing/Frame.h \
+  qpid/framing/method_variants.h \
+  qpid/framing/MethodHolder.cpp qpid/framing/MethodHolder.h
+
 
 libqpidbroker_la_LIBADD = libqpidcommon.la -lboost_iostreams
 libqpidbroker_la_SOURCES = \
@@ -410,3 +416,16 @@
 
 # Force build of qpidd during dist phase so help2man will work.
 dist-hook: qpidd
+
+# FIXME aconway 2007-08-06: Use of gch should be conditional on gcc version.
+
+# Pre compiled headers - use BUILT_SOURCES to get them built first.
+BUILT_SOURCES=qpid/framing/method_variants.h.gch
+sinclude qpid/framing/method_variants.h.gch.deps
+CLEANFILES=qpid/framing/method_variants.h.gch 
qpid/framing/method_variants.h.gch.deps
+
+SUFFIXES=.h.gch
+.h.h.gch:
+       rm -f $@
+       $(CXXCOMPILE) -MT $@ -MD -MP -MF [EMAIL PROTECTED] -fPIC -DPIC -x 
c++-header -c -o $@ $<
+

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Aug  7 15:28:06 2007
@@ -2,3 +2,6 @@
 .libs
 .dirstamp
 frame_body_lists.h
+method_variants.h.gch.deps
+method_variants.h.gch
+method_variants.h

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/AMQMethodBody.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/AMQMethodBody.h?view=diff&rev=563683&r1=563682&r2=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/AMQMethodBody.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/AMQMethodBody.h Tue Aug  7 
15:28:06 2007
@@ -80,6 +80,7 @@
 
     virtual void printPrefix(std::ostream&) const {}
 
+  friend class MethodHolder;
 };
 
 

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.cpp?view=auto&rev=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.cpp (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.cpp Tue Aug  7 
15:28:06 2007
@@ -0,0 +1,119 @@
+/*
+ *
+ * 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/format.hpp>
+
+#include "Frame.h"
+#include "qpid/QpidError.h"
+#include "AMQRequestBody.h"
+#include "AMQResponseBody.h"
+
+
+namespace qpid {
+namespace framing {
+
+namespace {
+struct GetBodyVisitor : public NoBlankVisitor<AMQBody*> {
+    QPID_USING_NOBLANK(AMQBody*);
+    AMQBody* operator()(MethodHolder& h) const { return h.getMethod(); }
+    template <class T> AMQBody* operator()(T& t) const { return &t; }
+};
+}
+
+AMQBody* Frame::getBody() {
+    return boost::apply_visitor(GetBodyVisitor(), body);
+}
+
+const AMQBody* Frame::getBody() const {
+    return boost::apply_visitor(GetBodyVisitor(), const_cast<Variant&>(body));
+}
+
+void Frame::encode(Buffer& buffer)
+{
+    buffer.putOctet(getBody()->type());
+    buffer.putShort(channel);    
+    buffer.putLong(getBody()->size());
+    getBody()->encode(buffer);
+    buffer.putOctet(0xCE);
+}
+
+uint32_t Frame::size() const{
+    return 1/*type*/ + 2/*channel*/ + 4/*body size*/ + getBody()->size()
+        + 1/*0xCE*/;
+}
+
+bool Frame::decode(Buffer& buffer)
+{    
+    if(buffer.available() < 7)
+        return false;
+    buffer.record();
+    uint32_t frameSize = decodeHead(buffer);
+    if(buffer.available() < frameSize + 1){
+        buffer.restore();
+        return false;
+    }
+    decodeBody(buffer, frameSize);
+    uint8_t end = buffer.getOctet();
+    if(end != 0xCE) THROW_QPID_ERROR(FRAMING_ERROR, "Frame end not found");
+    return true;
+}
+
+uint32_t Frame::decodeHead(Buffer& buffer){    
+    type = buffer.getOctet();
+    channel = buffer.getShort();
+    return buffer.getLong();
+}
+
+void Frame::decodeBody(Buffer& buffer, uint32_t size)
+{    
+    switch(type)
+    {
+      case METHOD_BODY:
+      case REQUEST_BODY:
+      case RESPONSE_BODY: {
+        ClassId c=buffer.getShort();
+        MethodId m=buffer.getShort();
+        body = MethodHolder(c,m);
+        break;
+      }
+      case HEADER_BODY: 
+       body = AMQHeaderBody();
+       break;
+      case CONTENT_BODY: 
+       body = AMQContentBody();
+       break;
+      case HEARTBEAT_BODY: 
+       body = AMQHeartbeatBody();
+       break;
+      default:
+       THROW_QPID_ERROR(
+            FRAMING_ERROR,
+            boost::format("Unknown frame type %d") % type);
+    }
+    getBody()->decode(buffer, size);
+}
+
+std::ostream& operator<<(std::ostream& out, const Frame& f)
+{
+    return out << "Frame[channel=" << f.getChannel() << "; " << f.body << "]";
+}
+
+
+}} // namespace qpid::framing

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.cpp
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.h?view=auto&rev=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.h (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Frame.h Tue Aug  7 15:28:06 
2007
@@ -0,0 +1,72 @@
+#ifndef _AMQFrame_
+#define _AMQFrame_
+
+/*
+ *
+ * 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 "AMQDataBlock.h"
+#include "AMQHeaderBody.h"
+#include "AMQContentBody.h"
+#include "AMQHeartbeatBody.h"
+#include "MethodHolder.h"
+
+namespace qpid {
+namespace framing {
+
+class Frame : public AMQDataBlock {
+  public:
+    typedef boost::variant<boost::blank,
+                           AMQHeaderBody,
+                           AMQContentBody,
+                           AMQHeartbeatBody,
+                           MethodHolder> Variant;
+
+    Frame(ChannelId channel_=0, const Variant& body_=Variant())
+        : body(body_), channel(channel_) {}
+
+    void encode(Buffer& buffer);
+    bool decode(Buffer& buffer); 
+    uint32_t size() const;
+
+    uint16_t getChannel() const { return channel; }
+
+    AMQBody* getBody();
+    const AMQBody* getBody() const;
+
+    template <class T> T* castBody() {
+        return boost::polymorphic_downcast<T*>(getBody());
+    }
+
+    Variant body;
+
+  private:
+    uint32_t decodeHead(Buffer& buffer); 
+    void decodeBody(Buffer& buffer, uint32_t size); 
+
+    uint8_t type;
+    uint16_t channel;
+};
+
+std::ostream& operator<<(std::ostream&, const Frame&);
+
+}} // namespace qpid::framing
+
+
+#endif

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

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

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp?view=auto&rev=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp Tue Aug  7 
15:28:06 2007
@@ -0,0 +1,93 @@
+/*
+ *
+ * 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 "MethodHolder.h"
+#include "amqp_types.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/variant.h"
+
+using namespace boost;
+
+namespace qpid {
+namespace framing {
+
+struct SetVariantVisitor : public NoBlankVisitor<> {
+    QPID_USING_NOBLANK();
+    MethodId id;
+    SetVariantVisitor(MethodId m) : id(m) {}
+    template <class T> void operator()(T& t) const { setVariant(t, id); }
+};
+
+inline void setVariant(MethodVariant& var, ClassId c, MethodId m) {
+    setVariant(var,c);
+    boost::apply_visitor(SetVariantVisitor(m), var);
+}
+
+void MethodHolder::setMethod(ClassId c, MethodId m) {
+    setVariant(method, c, m);
+}
+
+MethodHolder::MethodHolder(ClassId c, MethodId m) {
+    setMethod(c,m);
+}
+
+struct GetClassId : public NoBlankVisitor<ClassId> {
+    QPID_USING_NOBLANK(ClassId);
+    template <class T> ClassId operator()(const T&) const {
+        return T::CLASS_ID;
+    }
+};
+
+struct GetMethodId : public NoBlankVisitor<MethodId> {
+    QPID_USING_NOBLANK(ClassId);
+    template <class T> MethodId operator()(const T&) const {
+        return T::METHOD_ID;
+    }
+};
+
+void MethodHolder::encode(Buffer& b) const {
+    const AMQMethodBody* body = getMethod();
+    b.putShort(body->amqpClassId());
+    b.putShort(body->amqpMethodId());
+    body->encodeContent(b);
+}
+
+void MethodHolder::decode(Buffer& b) {
+    ClassId classId = b.getShort();
+    ClassId methodId = b.getShort();
+    setVariant(method, classId, methodId);
+    getMethod()->decodeContent(b);
+}
+
+uint32_t  MethodHolder::size() const {
+    return sizeof(ClassId)+sizeof(MethodId)+getMethod()->size();
+}
+
+
+AMQMethodBody* MethodHolder::getMethod() {
+    return applyApplyVisitor(AddressVisitor<AMQMethodBody*>(), method);
+}
+
+const AMQMethodBody* MethodHolder::getMethod() const {
+    return const_cast<MethodHolder*>(this)->getMethod();
+}
+
+}} // namespace qpid::framing

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h?view=auto&rev=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h Tue Aug  7 
15:28:06 2007
@@ -0,0 +1,80 @@
+#ifndef QPID_FRAMING_METHODBODYHOLDER_H
+#define QPID_FRAMING_METHODBODYHOLDER_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/method_variants.h"
+
+#include <boost/type_traits/has_nothrow_copy.hpp>
+
+namespace qpid {
+namespace framing {
+
+class AMQMethodBody;
+
+/**
+ * Holder for arbitrary method body.
+ */
+class MethodHolder
+{
+  public:
+    MethodHolder() {}
+    MethodHolder(const MethodVariant& mv) : method(mv) {}
+
+    /** Construct from a concrete method body type.
+     * ClassVariant<T>::value is the containing class variant.
+     */
+    template <class T>
+    MethodHolder(const T& t)
+        : method(typename ClassVariant<T>::value(t)) {}
+
+    /** Construct from class/method ID, set the method accordingly. */
+    MethodHolder(ClassId, MethodId);
+
+    /** Set the method to the type corresponding to ClassId, MethodId */
+    void setMethod(ClassId, MethodId);
+    
+    AMQMethodBody* getMethod();
+    const AMQMethodBody* getMethod() const;
+    
+    MethodVariant method;
+
+    void encode(Buffer&) const;
+    void decode(Buffer&);
+    uint32_t size() const;
+};
+
+inline std::ostream& operator<<(std::ostream& out, const MethodHolder& h) {
+    return out << h.method;
+}
+
+
+}} // namespace qpid::framing
+
+namespace boost {
+template<> struct has_nothrow_copy<qpid::framing::MethodHolder> 
+    : public boost::true_type {};
+}
+
+
+
+#endif  /*!QPID_FRAMING_METHODBODYHOLDER_H*/

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

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

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/amqp_types.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/amqp_types.h?view=diff&rev=563683&r1=563682&r2=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/amqp_types.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/amqp_types.h Tue Aug  7 
15:28:06 2007
@@ -42,6 +42,7 @@
 namespace framing {
 
 using std::string;
+typedef uint8_t FrameType;
 typedef uint16_t ChannelId;
 typedef uint64_t RequestId;
 typedef uint64_t ResponseId;

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/variant.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/variant.h?view=auto&rev=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/variant.h (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/variant.h Tue Aug  7 
15:28:06 2007
@@ -0,0 +1,92 @@
+#ifndef QPID_FRAMING_VARIANT_H
+#define QPID_FRAMING_VARIANT_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.
+ *
+ */
+
+/[EMAIL PROTECTED] Tools for using boost::variant */
+
+#include "qpid/QpidError.h"
+
+#include <boost/variant.hpp>
+
+namespace qpid {
+namespace framing {
+class Buffer;
+
+/** boost::static_visitor that throws exception if variant contains blank.
+ * Sublclasses need to have a using() declaration, can be generated
+ * with QPID_USING_BLANK_THROW(R)
+ */
+template <class R=void>
+struct NoBlankVisitor : public boost::static_visitor<R> {
+    R foundBlank() const {
+        assert(0);
+        THROW_QPID_ERROR(INTERNAL_ERROR, "Invalid variant value.");
+    }
+    R operator()(const boost::blank&) const { return foundBlank(); }
+    R operator()(boost::blank&) const { return foundBlank(); }
+};
+
+
+}} // qpid::framing
+
+
+/** Generate using statement needed in visitors inheriting NoBlankVisitor
+ *  @param R return type.
+ */
+#define QPID_USING_NOBLANK(R) using 
::qpid::framing::NoBlankVisitor<R>::operator()
+
+namespace qpid {
+namespace framing {
+
+/** Convert the variant value to type R. */
+template <class R> struct ConvertVisitor : public NoBlankVisitor<R> {
+    QPID_USING_NOBLANK(R);
+    template <class T> R operator()(T& t) const { return t; }
+};
+
+/** Convert address of variant value to type R. */
+template <class R> struct AddressVisitor : public NoBlankVisitor<R> {
+    QPID_USING_NOBLANK(R);
+    template <class T> R operator()(T& t) const { return &t; }
+};
+
+/** Apply a visitor to the nested variant in a variant of variants */
+template<class V>
+struct ApplyVisitor : public NoBlankVisitor<typename V::result_type> {
+    QPID_USING_NOBLANK(typename V::result_type);
+    const V& visitor;
+    ApplyVisitor(const V& v) : visitor(v) {}
+    template <class T> typename V::result_type operator()(T& t) const {
+        return boost::apply_visitor(visitor, t);
+    }
+};
+
+/** Convenience function to construct and apply an ApplyVisitor */
+template <class Visitor, class Visitable>
+typename Visitor::result_type applyApplyVisitor(const Visitor& visitor, 
Visitable& visitable) {
+    return boost::apply_visitor(ApplyVisitor<Visitor>(visitor), visitable);
+}
+
+}} // namespace qpid::framing
+
+    
+#endif  /*!QPID_FRAMING_VARIANT_H*/

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

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

Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Aug  7 15:28:06 2007
@@ -32,3 +32,4 @@
 ais_tests
 Visitor
 qpidd.vglog
+Frame

Added: incubator/qpid/trunk/qpid/cpp/src/tests/Frame.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/Frame.cpp?view=auto&rev=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/Frame.cpp (added)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/Frame.cpp Tue Aug  7 15:28:06 2007
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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/Frame.h"
+
+#define BOOST_AUTO_TEST_MAIN    // Must come before #include<boost/test/*>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+using namespace qpid::framing;
+using namespace boost;
+
+BOOST_AUTO_TEST_CASE(testContentBody) {
+    Frame f(42, AMQContentBody("foobar"));
+    AMQBody* body=f.getBody();
+    BOOST_CHECK(dynamic_cast<AMQContentBody*>(body));
+    Buffer b(f.size());
+    f.encode(b);
+    b.flip();
+    Frame g;
+    g.decode(b);
+    AMQContentBody* content=dynamic_cast<AMQContentBody*>(g.getBody());
+    BOOST_REQUIRE(content);
+    BOOST_CHECK_EQUAL(content->getData(), "foobar");
+}
+
+BOOST_AUTO_TEST_CASE(testMethodBody) {
+    FieldTable args;
+    args.setString("foo", "bar");
+    Frame f(
+        42, QueueDeclareBody(ProtocolVersion(), 1, "q", "altex",
+                             true, false, true, false, true, args));
+    BOOST_CHECK_EQUAL(f.getChannel(), 42);
+    Buffer b(f.size());
+    f.encode(b);
+    b.flip();
+    Frame g;
+    g.decode(b);
+    BOOST_CHECK_EQUAL(f.getChannel(), g.getChannel());
+    QueueDeclareBody* declare=dynamic_cast<QueueDeclareBody*>(g.getBody());
+    BOOST_REQUIRE(declare);
+    BOOST_CHECK_EQUAL(declare->getAlternateExchange(), "altex");
+    BOOST_CHECK_EQUAL(lexical_cast<string>(*f.getBody()), 
lexical_cast<string>(*g.getBody()));
+}
+
+BOOST_AUTO_TEST_CASE(testLoop) {
+    // Run in a loop so heap profiler can spot any allocations.
+    Buffer b(1024);
+    for (int i = 0; i < 100; ++i) {
+        Frame ctor(2, AccessRequestOkBody(ProtocolVersion(), 42));
+        Frame assign(3);
+        assign.body = AccessRequestOkBody(ProtocolVersion(), 42);
+        assign.encode(b);
+        b.flip();
+        Frame g;
+        g.decode(b);
+        
BOOST_REQUIRE(dynamic_cast<AccessRequestOkBody*>(g.getBody())->getTicket() == 
42);
+    }
+}

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

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

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?view=diff&rev=563683&r1=563682&r2=563683
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am Tue Aug  7 15:28:06 2007
@@ -43,6 +43,15 @@
 Shlib_SOURCES=Shlib.cpp
 Shlib_LDADD=-lboost_unit_test_framework $(lib_common)
 
+TESTS+=Frame
+check_PROGRAMS+=Frame
+Frame_SOURCES=Frame.cpp
+Frame_LDADD=-lboost_unit_test_framework $(lib_common)
+
+
+
+# TODO aconway 2007-08-07: Why aren't these tests run automatically?
+
 check_PROGRAMS+=ConcurrentQueue
 ConcurrentQueue_SOURCES=ConcurrentQueue.cpp
 ConcurrentQueue_LDADD=-lboost_test_exec_monitor $(lib_common)


Reply via email to