diff options
author | Alan Conway <aconway@apache.org> | 2007-10-30 22:39:46 +0000 |
---|---|---|
committer | Alan Conway <aconway@apache.org> | 2007-10-30 22:39:46 +0000 |
commit | 9d32e58f281e6ecefcbde45a897395162395e577 (patch) | |
tree | 2ef6b1a250dbdf634ef4dec0ac98fd64b26693d2 /cpp/rubygen | |
parent | 3667cdd020d46af9c47c1c37998fbed7adae2248 (diff) | |
download | qpid-python-9d32e58f281e6ecefcbde45a897395162395e577.tar.gz |
Client API: fix keyword parameter ambiguities for beta client API.
Classes:
- client::no_keyword::Session_0_10 - plain defaulted signatures
- client::Session_0_10 - keyword API.
Keyword API changes:
- keywords in client::arg namespace, user says: s.bind(arg::queue="x"...)
- user can omit with: using namespace client::arg; s.bind(queue="x"...)
- No trailing "_" required on session functions.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@590498 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/rubygen')
-rwxr-xr-x | cpp/rubygen/cppgen.rb | 13 | ||||
-rw-r--r-- | cpp/rubygen/templates/Session.rb | 333 |
2 files changed, 163 insertions, 183 deletions
diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb index ceda5e039c..2590d48f7b 100755 --- a/cpp/rubygen/cppgen.rb +++ b/cpp/rubygen/cppgen.rb @@ -97,12 +97,13 @@ 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 end class AmqpMethod def cppname() name.lcaps.cppsafe; end def param_names() fields.map { |f| f.cppname }; end - def signature() fields.map { |f| f.cpptype.param+" "+f.cppname }; end + def signature() fields.map { |f| f.signature }; end def body_name() parent.name.caps+name.caps+"Body"; end end @@ -197,7 +198,7 @@ class CppGen < Generator genl yield genl - genl('}'*names.size+" // "+name) + genl('}'*names.size+" // namespace "+name) genl end @@ -236,3 +237,11 @@ class CppGen < Generator end end +# Fully-qualified class name +class FqClass < Struct.new(:fqname,:namespace,:name,:file) + def initialize(fqclass) + names=fqclass.split "::" + super(fqclass, names[0..-2].join('::'), names[-1], names.join("/")) + end +end + diff --git a/cpp/rubygen/templates/Session.rb b/cpp/rubygen/templates/Session.rb index f351710e7d..c61a217682 100644 --- a/cpp/rubygen/templates/Session.rb +++ b/cpp/rubygen/templates/Session.rb @@ -4,209 +4,180 @@ $: << '..' require 'cppgen' -class SessionGen < CppGen - - def initialize(outdir, amqp) - super(outdir, amqp) - @chassis="server" - @classname="Session_#{@amqp.version.bars}" - end - - def return_type(m) - if (m.result) - return "TypedResult<qpid::framing::#{m.result.cpptype.ret}>" - elsif (not m.responses().empty?) - return "Response" - else - return "Completion" - end +class CppGen + def session_methods + excludes = ["channel", "connection", "session", "execution"] + gen_methods=@amqp.methods_on(@chassis).reject { |m| + excludes.include? m.parent.name + } end +end - def declare_method (m) - param_unpackers = m.fields.collect { |f| "args[::qpid::client::#{f.cppname}|#{f.cpptype.default_value}]" } - if (m.content()) - param_names = m.param_names + ["content"] - param_unpackers << "args[content|DefaultContent(\"\")]" - params=m.signature + ["const MethodContent& content"] - else - param_names = m.param_names - params=m.signature - end - - if (params.empty?) - gen "#{return_type(m)} #{m.parent.name.lcaps}#{m.name.caps}();\n\n" - else - genl "template <class ArgumentPack> #{return_type(m)} #{m.parent.name.lcaps}#{m.name.caps}(ArgumentPack const& args)" - genl "{" - indent { - genl "return #{m.parent.name.lcaps}#{m.name.caps}(#{param_unpackers.join(",\n")});" - } - genl "}" - - #generate the 'real' methods signature - gen "#{return_type(m)} #{m.parent.name.lcaps}#{m.name.caps}(" - indent { gen params.join(",\n") } - gen ");\n\n" - - #generate some overloaded methods to handle keyword args - boost_max_arity = 8 - if param_names.length > boost_max_arity - keywords = param_names[1..boost_max_arity].collect { |p| "keyword::#{p}" } - else - keywords = param_names.collect { |p| "keyword::#{p}" } - end - genl "typedef boost::parameter::parameters< #{keywords.join(",")} > #{m.parent.name.caps}#{m.name.caps}Params;\n" - - j = 1 - while j <= params.length && j <= boost_max_arity - dummy_args = Array.new(j) { |i| "P#{i} const& p#{i}"} - dummy_names = Array.new(j) { |i| "p#{i}"} - dummy_types = Array.new(j) { |i| "class P#{i}"} - - genl "template <#{dummy_types.join(',')}> #{return_type(m)} #{m.parent.name.lcaps}#{m.name.caps}_(#{dummy_args.join(',')})" - genl "{" - indent { - genl "return #{m.parent.name.lcaps}#{m.name.caps}(#{m.parent.name.caps}#{m.name.caps}Params()(#{dummy_names.join(',')}));" - } - genl "}" - j = j + 1 - end - end +class ContentField # For extra content parameters + def cppname() "content" end + def signature() "const MethodContent& content" end + def unpack() "p[arg::content|DefaultContent(std::string())]"; end +end - end +class AmqpField + def unpack() "p[arg::#{cppname}|#{cpptype.default_value}]"; end +end - def define_method (m) - if (m.content()) - params=m.signature + ["const MethodContent& content"] - else - params=m.signature - end - if (params.empty?) - gen "#{return_type(m)} #{@classname}::#{m.parent.name.lcaps}#{m.name.caps}(){\n\n" - else - gen "#{return_type(m)} #{@classname}::#{m.parent.name.lcaps}#{m.name.caps}(" - indent { gen params.join(",\n") } - gen "){\n\n" - end - indent (2) { - gen "return #{return_type(m)}(impl->send(#{m.body_name}(" - params = ["version"] + m.param_names - gen params.join(", ") - other_params=[] - if (m.content()) - gen "), content), impl);\n" - else - gen ")), impl);\n" - end - } - gen "}\n\n" +class AmqpMethod + def fields_c() content ? fields+[ContentField.new] : fields end + def param_names_c() fields_c.map { |f| f.cppname} end + def signature_c() fields_c.map { |f| f.signature }; end + def argpack_name() "#{parent.cppname}#{name.caps}Parameters"; end + def argpack_type() + "boost::parameter::parameters<" + + fields_c.map { |f| "arg::keyword_tags::"+f.cppname }.join(',') + + ">" end - - def declare_keywords(classes) - #need to assemble a listof all the field names - keywords = classes.collect { |c| c.methods_on(@chassis).collect { |m| m.param_names } }.flatten().uniq() - keywords.each { |k| genl "BOOST_PARAMETER_KEYWORD(keyword, #{k})" } - genl "BOOST_PARAMETER_KEYWORD(keyword, content)" + def return_type() + return "TypedResult<qpid::framing::#{result.cpptype.ret}>" if (result) + return "Response" if (not responses().empty?) + return "Completion" end + def session_function() "#{parent.name.lcaps}#{name.caps}"; end +end - def declare_class(c) - c.methods_on(@chassis).each { |m| declare_method(m) } - end +class SessionNoKeywordGen < CppGen - def define_class(c) - c.methods_on(@chassis).each { |m| define_method(m) } + def initialize(outdir, amqp) + super(outdir, amqp) + @chassis="server" + @namespace,@classname,@file= + parse_classname "qpid::client::no_keyword::Session_#{@amqp.version.bars}" end def generate() - excludes = ["channel", "connection", "session", "execution"] - - h_file("qpid/client/#{@classname}.h") { - genl "#define BOOST_PARAMETER_MAX_ARITY 8" - - gen <<EOS -#include <sstream> -#include <boost/parameter.hpp> -#include "qpid/framing/amqp_framing.h" -#include "qpid/framing/Uuid.h" -#include "qpid/framing/amqp_structs.h" -#include "qpid/framing/ProtocolVersion.h" -#include "qpid/framing/MethodContent.h" -#include "qpid/framing/TransferContent.h" -#include "qpid/client/Completion.h" -#include "qpid/client/ConnectionImpl.h" -#include "qpid/client/Response.h" -#include "qpid/client/SessionCore.h" -#include "qpid/client/TypedResult.h" -#include "qpid/shared_ptr.h" - -namespace qpid { -namespace client { - -using std::string; -using framing::Content; -using framing::FieldTable; -using framing::MethodContent; -using framing::SequenceNumberSet; -using framing::Uuid; - + h_file(@file) { + include "qpid/framing/amqp_framing.h" + include "qpid/framing/Uuid.h" + include "qpid/framing/amqp_structs.h" + include "qpid/framing/ProtocolVersion.h" + include "qpid/framing/MethodContent.h" + include "qpid/framing/TransferContent.h" + include "qpid/client/Completion.h" + include "qpid/client/ConnectionImpl.h" + include "qpid/client/Response.h" + include "qpid/client/SessionCore.h" + include "qpid/client/TypedResult.h" + include "qpid/shared_ptr.h" + include "<string>" + namespace("qpid::client") { + genl "using std::string;" + genl "using framing::Content;" + genl "using framing::FieldTable;" + genl "using framing::MethodContent;" + genl "using framing::SequenceNumberSet;" + genl "using framing::Uuid;" + genl + namespace("no_keyword") { + cpp_class(@classname) { + public + gen <<EOS +#{@classname}(); +framing::FrameSet::shared_ptr get() { return impl->get(); } +Uuid getId() const { return impl->getId(); } +void setSynchronous(bool sync) { impl->setSync(sync); } +void suspend(); +void close(); +Execution& execution() { return impl->getExecution(); } + +typedef framing::TransferContent DefaultContent; EOS - declare_keywords(@amqp.classes.select { |c| !excludes.include?(c.name) }) - genl - gen <<EOS -class #{@classname} { - shared_ptr<SessionCore> impl; - framing::ProtocolVersion version; - friend class Connection; - #{@classname}(shared_ptr<SessionCore>); -public: - #{@classname}(); - - framing::FrameSet::shared_ptr get() { return impl->get(); } - Uuid getId() const { return impl->getId(); } - void setSynchronous(bool sync) { impl->setSync(sync); } - void suspend(); - void close(); - Execution& execution() { return impl->getExecution(); } - - typedef framing::TransferContent DefaultContent; -EOS - indent { @amqp.classes.each { |c| declare_class(c) if !excludes.include?(c.name) } } - gen <<EOS -}; /* class #{@classname} */ -} -} + session_methods.each { |m| + genl + args=m.signature_c.join(", ") + genl "#{m.return_type} #{m.session_function}(#{args});" + } + genl + protected + gen <<EOS +shared_ptr<SessionCore> impl; +framing::ProtocolVersion version; +friend class Connection; +#{@classname}(shared_ptr<SessionCore>); EOS -} - - # .cpp file - cpp_file("qpid/client/#{@classname}.cpp") { - gen <<EOS -#include "#{@classname}.h" -#include "qpid/framing/all_method_bodies.h" - -using std::string; -using namespace qpid::framing; - -namespace qpid { -namespace client { - + }}}} + + cpp_file(@file) { + include @classname + include "qpid/framing/all_method_bodies.h" + namespace(@namespace) { + gen <<EOS +using namespace framing; #{@classname}::#{@classname}() {} #{@classname}::#{@classname}(shared_ptr<SessionCore> core) : impl(core) {} - void #{@classname}::suspend() { impl->suspend(); } void #{@classname}::close() { impl->close(); } - EOS + session_methods.each { |m| + genl + sig=m.signature_c.join(", ") + func="#{@classname}::#{m.session_function}" + scope("#{m.return_type} #{func}(#{sig}) {") { + args=(["ProtocolVersion()"]+m.param_names).join(", ") + body="#{m.body_name}(#{args})" + sendargs=body + sendargs << ", content" if m.content + genl "return #{m.return_type}(impl->send(#{sendargs}), impl);" + }}}} + end +end - @amqp.classes.each { |c| define_class(c) if !excludes.include?(c.name) } - - gen <<EOS -}} // namespace qpid::client -EOS - } +class SessionGen < CppGen + def initialize(outdir, amqp) + super(outdir, amqp) + @chassis="server" + session="Session_#{@amqp.version.bars}" + @base="no_keyword::#{session}" + @fqclass=FqClass.new "qpid::client::#{session}" + @classname=@fqclass.name + @fqbase=FqClass.new("qpid::client::#{@base}") + end + + def gen_keyword_decl(m, prefix) + return if m.fields_c.empty? # Inherited function will do. + scope("BOOST_PARAMETER_MEMFUN(#{m.return_type}, #{m.session_function}, 0, #{m.fields_c.size}, #{m.argpack_name}) {") { + scope("return #{prefix}#{m.session_function}(",");") { + gen m.fields_c.map { |f| f.unpack() }.join(",\n") + } + } + genl + end + + def generate() + keyword_methods=session_methods.reject { |m| m.fields_c.empty? } + max_arity = keyword_methods.map{ |m| m.fields_c.size }.max + + h_file(@fqclass.file) { + include @fqbase.file + genl + genl "#define BOOST_PARAMETER_MAX_ARITY #{max_arity}" + include "<boost/parameter.hpp>" + genl + namespace("qpid::client") { + # Generate keyword tag declarations. + namespace("arg") { + keyword_methods.map{ |m| m.param_names_c }.flatten.uniq.each { |k| + genl "BOOST_PARAMETER_KEYWORD(keyword_tags, #{k})" + }} + genl + cpp_class(@classname,"public #{@base}") { + private + genl "#{@classname}(shared_ptr<SessionCore> core) : #{ @base}(core) {}" + keyword_methods.each { |m| typedef m.argpack_type, m.argpack_name } + genl "friend class Connection;" + public + genl "#{@classname}() {}" + keyword_methods.each { |m| gen_keyword_decl(m,@base+"::") } + }}} end end +SessionNoKeywordGen.new(ARGV[0], Amqp).generate() SessionGen.new(ARGV[0], Amqp).generate() |