summaryrefslogtreecommitdiff
path: root/cpp/rubygen
diff options
context:
space:
mode:
authorAlan Conway <aconway@apache.org>2007-10-16 19:07:54 +0000
committerAlan Conway <aconway@apache.org>2007-10-16 19:07:54 +0000
commit428de9b6fe6f81f2bfc3f47d5db013b4b00da6a2 (patch)
treee3fe772cbe0e08ea84f4b2f54b969dc7471bb8e1 /cpp/rubygen
parent3bd61c1fa1a748789707b502ada85200f6180f5b (diff)
downloadqpid-python-428de9b6fe6f81f2bfc3f47d5db013b4b00da6a2.tar.gz
* Summary: generalized Invoker visitor to all *Operations and
*Handler classes, client and broker. Single template free function invoke(Invocable, const AMQBody&); works for all invocable handlers. * rubygen/templates/OperationsInvoker.rb: Generates invoker visitors for all Operations classes, client and server. * src/qpid/framing/Invoker.h: Invoker base class and template invoke() function. * rubygen/templates/structs.rb: add generic invoke method template to invoke an arbitrary object with the correct memeber function. * src/qpid/framing/AMQMethodBody.cpp, .h: Removed invoke(), replaced by qpid::framing::invoke() * src/qpid/broker/SemanticHandler.cpp, ConnectionHandler.cpp: Replace AMQMethodBody::invoke with invoke() free function. * src/qpid/framing/StructHelper.h: Avoid un-necessary alloc and copy in encode/decode. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@585223 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/rubygen')
-rwxr-xr-xcpp/rubygen/cppgen.rb1
-rw-r--r--cpp/rubygen/templates/InvocationVisitor.rb101
-rwxr-xr-xcpp/rubygen/templates/Operations.rb14
-rwxr-xr-xcpp/rubygen/templates/OperationsInvoker.rb92
-rw-r--r--cpp/rubygen/templates/structs.rb16
5 files changed, 108 insertions, 116 deletions
diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb
index 509cd39295..ceda5e039c 100755
--- a/cpp/rubygen/cppgen.rb
+++ b/cpp/rubygen/cppgen.rb
@@ -202,7 +202,6 @@ class CppGen < Generator
end
def struct_class(type, name, bases, &block)
- genl
gen "#{type} #{name}"
if (!bases.empty?)
genl ":"
diff --git a/cpp/rubygen/templates/InvocationVisitor.rb b/cpp/rubygen/templates/InvocationVisitor.rb
deleted file mode 100644
index 67a0479bb6..0000000000
--- a/cpp/rubygen/templates/InvocationVisitor.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env ruby
-$: << ".." # Include .. in load path
-require 'cppgen'
-
-class InvocationVisitor < CppGen
-
- def initialize(outdir, amqp)
- super(outdir, amqp)
- @namespace="qpid::framing"
- @classname="InvocationVisitor"
- @filename="qpid/framing/InvocationVisitor"
- end
-
- def invocation_args(m)
- m.param_names.collect {|p| "body.get" + p.caps + "()" }.join(",\n")
- end
-
- def null_visit(m)
- genl "void InvocationVisitor::visit(const #{m.body_name}&){}"
- end
-
- def define_visit(m)
- if (m.fields.size > 0)
- body = "body"
- else
- body = "/*body*/"
- end
- gen <<EOS
-void InvocationVisitor::visit(const #{m.body_name}& #{body})
-{
- AMQP_ServerOperations::#{m.parent.cppname}Handler* ptr(0);
- if (invocable) {
- ptr = dynamic_cast<AMQP_ServerOperations::#{m.parent.cppname}Handler*>(invocable);
- } else {
- ptr = ops->get#{m.parent.cppname}Handler();
- }
-
- if (ptr) {
-EOS
- if (m.result)
- indent(2) { genl "encode<#{m.result.struct.cpptype.name}>(ptr->#{m.cppname}(#{invocation_args(m)}), result);" }
- else
- indent(2) { genl "ptr->#{m.cppname}(#{invocation_args(m)});" }
- end
-
- gen <<EOS
- succeeded = true;
- } else {
- succeeded = false;
- }
-}
-EOS
- end
-
- def generate()
- h_file("#{@filename}") {
- include "AMQP_ServerOperations.h"
- include "MethodBodyConstVisitor.h"
- include "qpid/framing/StructHelper.h"
- namespace(@namespace) {
- cpp_class("InvocationVisitor", ["public MethodBodyConstVisitor", "private StructHelper"]) {
- indent {
- genl "AMQP_ServerOperations* const ops;"
- genl "Invocable* const invocable;"
- genl "std::string result;"
- genl "bool succeeded;"
- }
- genl "public:"
- indent {
- genl "InvocationVisitor(AMQP_ServerOperations* _ops) : ops(_ops), invocable(0), succeeded(false) {}"
- genl "InvocationVisitor(Invocable* _invocable) : ops(0), invocable(_invocable), succeeded(false) {}"
- genl "const std::string& getResult() const { return result; }"
- genl "const bool hasResult() const { return !result.empty(); }"
- genl "bool wasHandled() const { return succeeded; }"
- genl "void clear();"
- genl "virtual ~InvocationVisitor() {}"
- }
- @amqp.methods_.each { |m| genl "void visit(const #{m.body_name}&);" }
- }
- }
- }
-
- cpp_file("#{@filename}") {
- include "InvocationVisitor.h"
- @amqp.methods_.each { |m| include m.body_name }
- namespace(@namespace) {
- genl "void InvocationVisitor::clear() {"
- indent {
- genl "succeeded = false;"
- genl "result.clear();"
- }
- genl "}"
- genl
- @amqp.methods_.each { |m| m.on_server? && !m.content() ? define_visit(m) : null_visit(m) }
- }
- }
- end
-end
-
-InvocationVisitor.new(Outdir, Amqp).generate();
-
diff --git a/cpp/rubygen/templates/Operations.rb b/cpp/rubygen/templates/Operations.rb
index 1002bf07a4..91007ef3e1 100755
--- a/cpp/rubygen/templates/Operations.rb
+++ b/cpp/rubygen/templates/Operations.rb
@@ -29,9 +29,11 @@ class OperationsGen < CppGen
handlerclass=handler_classname c
gen <<EOS
// ==================== class #{handlerclass} ====================
-class #{handlerclass} : public virtual Invocable {
+class #{handlerclass} {
// Constructors and destructors
public:
+ class Invoker; // Declared in #{@chassis.caps}Invoker
+
#{handlerclass}(){};
virtual ~#{handlerclass}() {}
// Protocol methods
@@ -64,16 +66,10 @@ namespace framing {
class AMQMethodBody;
-class Invocable
-{
-protected:
- Invocable() {}
- virtual ~Invocable() {}
-};
-
class #{@classname} {
-
public:
+ class Invoker; // Declared in #{@chassis.caps}Invoker
+
virtual ~#{@classname}() {}
virtual ProtocolVersion getVersion() const = 0;
diff --git a/cpp/rubygen/templates/OperationsInvoker.rb b/cpp/rubygen/templates/OperationsInvoker.rb
new file mode 100755
index 0000000000..747dd06189
--- /dev/null
+++ b/cpp/rubygen/templates/OperationsInvoker.rb
@@ -0,0 +1,92 @@
+#!/usr/bin/env ruby
+# Usage: output_directory xml_spec_file [xml_spec_file...]
+#
+$: << '..'
+require 'cppgen'
+
+class OperationsInvokerGen < CppGen
+ def initialize(chassis, outdir, amqp)
+ super(outdir, amqp)
+ @chassis=chassis
+ @ops="AMQP_#{@chassis.caps}Operations"
+ @classname="#{@ops}::Invoker"
+ @filename="qpid/framing/#{@chassis.caps}Invoker"
+ end
+
+ def handler(c) "#{@ops}::#{c.cppname}Handler"; end
+ def getter(c) "get#{c.cppname}Handler"; end
+ def invoker(c) "#{handler(c)}::Invoker"; end
+ def visit_methods(c) c.methods_on(@chassis).select { |m| !m.content } end
+
+ def handler_visits_cpp(c)
+ visit_methods(c).each { |m|
+ scope("void #{invoker(c)}::visit(const #{m.body_name}& body) {") {
+ if (m.result)
+ genl "this->encode(body.invoke(target), result.result);"
+ else
+ genl "body.invoke(target);"
+ end
+ genl "result.handled=true;"
+ }
+ }
+ end
+
+ def ops_visits_cpp()
+ @amqp.classes.each { |c|
+ visit_methods(c).each { |m|
+ scope("void #{@classname}::visit(const #{m.body_name}& body) {") {
+ genl "#{handler(c)}::Invoker invoker(*target.#{getter(c)}());"
+ genl "body.accept(invoker);"
+ genl "result=invoker.getResult();"
+ }
+ }
+ }
+ end
+
+ def invoker_h(invoker, target, methods)
+ return if methods.empty?
+ genl
+ cpp_class(invoker, "public qpid::framing::Invoker") {
+ genl "#{target}& target;"
+ public
+ genl("Invoker(#{target}& target_) : target(target_) {}")
+ genl "using MethodBodyDefaultVisitor::visit;"
+ methods.each { |m| genl "void visit(const #{m.body_name}& body);" }
+ }
+ end
+
+ def generate()
+ h_file(@filename) {
+ include "qpid/framing/#{@ops}"
+ include "qpid/framing/Invoker.h"
+ namespace("qpid::framing") {
+ # AMQP_*Operations invoker.
+ methods=@amqp.classes.map { |c| visit_methods(c).to_a }.flatten
+ invoker_h(@classname, @ops, methods)
+
+ # AMQP_*Operations::*Handler invokers.
+ @amqp.classes.each { |c|
+ invoker_h(invoker(c), handler(c), visit_methods(c))
+ }
+ }
+ }
+
+ cpp_file(@filename) {
+ include @filename
+ @amqp.classes.each { |c|
+ visit_methods(c).each { |m|
+ include "qpid/framing/#{m.body_name}"
+ }}
+ namespace("qpid::framing") {
+ ops_visits_cpp
+ @amqp.classes.each { |c|
+ next if visit_methods(c).empty?
+ handler_visits_cpp(c)
+ }
+ }
+ }
+ end
+end
+
+OperationsInvokerGen.new("client",ARGV[0], Amqp).generate()
+OperationsInvokerGen.new("server",ARGV[0], Amqp).generate()
diff --git a/cpp/rubygen/templates/structs.rb b/cpp/rubygen/templates/structs.rb
index 2f5a3d8365..6a58dfd763 100644
--- a/cpp/rubygen/templates/structs.rb
+++ b/cpp/rubygen/templates/structs.rb
@@ -191,14 +191,20 @@ class StructGen < CppGen
def methodbody_extra_defs(s)
gen <<EOS
+ typedef #{s.result ? s.result.struct.cpptype.name : 'void'} ResultType;
+
+ template <class T> ResultType invoke(T& invocable) const {
+ return invocable.#{s.cppname}(#{s.param_names.join ", "});
+ }
+
using AMQMethodBody::accept;
void accept(MethodBodyConstVisitor& v) const { v.visit(*this); }
- inline ClassId amqpClassId() const { return CLASS_ID; }
- inline MethodId amqpMethodId() const { return METHOD_ID; }
- inline bool isContentBearing() const { return #{s.content ? "true" : "false" }; }
- inline bool resultExpected() const { return #{s.result ? "true" : "false"}; }
- inline bool responseExpected() const { return #{s.responses().empty? ? "false" : "true"}; }
+ ClassId amqpClassId() const { return CLASS_ID; }
+ MethodId amqpMethodId() const { return METHOD_ID; }
+ bool isContentBearing() const { return #{s.content ? "true" : "false" }; }
+ bool resultExpected() const { return #{s.result ? "true" : "false"}; }
+ bool responseExpected() const { return #{s.responses().empty? ? "false" : "true"}; }
EOS
end