summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp')
-rwxr-xr-xcpp/rubygen/0-10/specification.rb149
-rwxr-xr-xcpp/rubygen/cppgen.rb2
-rw-r--r--cpp/src/Makefile.am5
-rw-r--r--cpp/src/qpid/Serializer.h43
-rw-r--r--cpp/src/qpid/amqp_0_10/Codec.h42
-rw-r--r--cpp/src/qpid/amqp_0_10/Holder.h62
-rw-r--r--cpp/src/qpid/amqp_0_10/apply.h29
-rw-r--r--cpp/src/qpid/amqp_0_10/built_in_types.h33
-rw-r--r--cpp/src/qpid/amqp_0_10/complex_types.cpp65
-rw-r--r--cpp/src/qpid/amqp_0_10/complex_types.h79
-rw-r--r--cpp/src/qpid/amqp_0_10/helpers.cpp33
-rw-r--r--cpp/src/qpid/amqp_0_10/helpers.h81
-rw-r--r--cpp/src/qpid/framing/AMQBody.h3
-rw-r--r--cpp/src/tests/apply.cpp11
-rw-r--r--cpp/src/tests/serialize.cpp56
15 files changed, 477 insertions, 216 deletions
diff --git a/cpp/rubygen/0-10/specification.rb b/cpp/rubygen/0-10/specification.rb
index acf9e4e6ed..c159d9f08b 100755
--- a/cpp/rubygen/0-10/specification.rb
+++ b/cpp/rubygen/0-10/specification.rb
@@ -15,10 +15,11 @@ class Specification < CppGen
genl
typename=d.name.typename
if d.enum
- scope("enum #{typename} {", "};") {
+ scope("enum #{typename}Enum {", "};") {
genl d.enum.choices.map { |c|
"#{c.name.constname} = #{c.value}" }.join(",\n")
}
+ genl "typedef Enum<#{typename}Enum, uint8_t> #{typename};"
else
genl "typedef #{d.amqp2cpp} #{typename};"
end
@@ -42,11 +43,15 @@ class Specification < CppGen
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};"}
+ consts.each {
+ |c| genl "static const uint8_t #{c.upcase}=#{(x.send c) or 0};"
+ }
genl "static const uint8_t CLASS_CODE=#{x.containing_class.nsname}::CODE;"
+ genl "static const char* CLASS_NAME;"
ctor_decl(x.classname,[])
ctor_decl(x.classname, x.parameters) unless x.fields.empty?
- function_decl("void accept", ["Visitor&"], "const")
+ genl "void accept(Visitor&);"
+ genl "void accept(ConstVisitor&) const;"
genl
yield if block
}
@@ -55,13 +60,19 @@ class Specification < CppGen
def action_struct_cpp(x)
genl
genl "const char* #{x.classname}::NAME=\"#{x.fqname}\";"
+ genl "const char* #{x.classname}::CLASS_NAME=#{x.containing_class.nsname}::NAME;"
genl
ctor=x.classname+"::"+x.classname
ctor_defn(ctor) {}
ctor_defn(ctor, x.parameters, x.initializers) {} if not x.fields.empty?
- function_defn("void #{x.classname}::accept", ["Visitor& v"], "const") {
- genl "v.visit(*this);"
- }
+ # FIXME aconway 2008-03-04: struct visitors
+ if x.is_a? AmqpStruct
+ genl "void #{x.classname}::accept(Visitor&) { assert(0); }"
+ genl "void #{x.classname}::accept(ConstVisitor&) const { assert(0); }"
+ else
+ genl "void #{x.classname}::accept(Visitor& v) { v.visit(*this); }"
+ genl "void #{x.classname}::accept(ConstVisitor& v) const { v.visit(*this); }"
+ end
end
# structs
@@ -76,11 +87,13 @@ class Specification < CppGen
function_defn("template <class T> void invoke", ["T& target"]) {
genl "target.#{a.funcname}(#{a.values.join(', ')});"
}
- function_defn("template <class S> void serialize", ["S& s"]) {
- gen "s"
- a.fields.each { |f| gen "(#{f.cppname})"}
- genl ";"
- } unless a.fields.empty?
+ if (a.fields.empty?)
+ genl "template <class S> void serialize(S&) {}"
+ else
+ scope("template <class S> void serialize(S& s) {") {
+ gen "s"; a.fields.each { |f| gen "(#{f.cppname})"}; genl ";"
+ }
+ end
}
end
@@ -93,7 +106,7 @@ class Specification < CppGen
def gen_specification()
h_file("#{@dir}/specification") {
include "#{@dir}/built_in_types"
- include "#{@dir}/helpers"
+ include "#{@dir}/complex_types"
include "<boost/call_traits.hpp>"
genl "using boost::call_traits;"
namespace(@ns) {
@@ -120,12 +133,13 @@ class Specification < CppGen
cpp_file("#{@dir}/specification") {
include "#{@dir}/specification"
- ["Command","Control","Struct"].each { |x| include "#{@dir}/Apply#{x}" }
+ # FIXME aconway 2008-03-04: add Struct visitors.
+ ["Command","Control"].each { |x| include "#{@dir}/Apply#{x}" }
namespace(@ns) {
each_class_ns { |c|
class_cpp c
c.actions.each { |a| action_cpp a}
- c.structs.each { |s| struct_cpp s }
+ c.collect_all(AmqpStruct).each { |s| struct_cpp(s) }
}
}
}
@@ -157,57 +171,98 @@ class Specification < CppGen
}
end
+ def visitor_interface_h(base, subs, is_const)
+ name="#{is_const ? 'Const' : ''}#{base}Visitor"
+ const=is_const ? "const " : ""
+ struct(name) {
+ genl "virtual ~#{name}() {}"
+ genl "typedef #{const}#{base} BaseType;"
+ subs.each{ |s|
+ genl "virtual void visit(#{const}#{s.fqclassname}&) = 0;"
+ }}
+ end
+
+ def visitor_impl(base, subs, is_const)
+ name="#{is_const ? 'Const' : ''}#{base}Visitor"
+ const=is_const ? "const " : ""
+ genl "template <class F>"
+ struct("ApplyVisitor<#{name}, F>", "public ApplyVisitorBase<#{name}, F>") {
+ subs.each{ |s|
+ genl "virtual void visit(#{const}#{s.fqclassname}& x) { this->invoke(x); }"
+ }}
+ 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;"
- }}}}
-
+ visitor_interface_h(base, subs, false)
+ visitor_interface_h(base, subs, true)
+ }}
+
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()
+ visitor_impl(base, subs, false)
+ visitor_impl(base, subs, true)
+ }
+ }
end
-
- def holder(base, derived)
+
+ def gen_holder(base, subs)
name=base.caps+"Holder"
h_file("#{@dir}/#{name}") {
- include "#{@dir}/specification"
- include "qpid/framing/Blob"
- namespace(@ns){
- # TODO aconway 2008-02-29:
- }
- }
+ include "#{@dir}/Apply#{base}"
+ include "#{@dir}/Holder"
+ namespace(@ns){
+ namespace("#{base.downcase}_max") {
+ gen "template <class M, class X> "
+ struct("Max") {
+ genl "static const size_t max=(M::max > sizeof(X)) ? M::max : sizeof(X);"
+ }
+ genl "struct Max000 { static const size_t max=0; };"
+ last="Max000"
+ subs.each { |s|
+ genl "typedef Max<#{last}, #{s.fqclassname}> #{last.succ!};"
+ }
+ genl "static const int MAX=#{last}::max;"
+ }
+ holder_base="amqp_0_10::Holder<#{base}Holder, #{base}, #{base.downcase}_max::MAX>"
+ struct("#{name}", "public #{holder_base}") {
+ genl "#{name}() {}"
+ genl "template <class T> #{name}(const T& t) : #{holder_base}(t) {}"
+ genl "using #{holder_base}::operator=;"
+ genl "void set(uint8_t classCode, uint8_t code);"
+ }}}
+
+ cpp_file("#{@dir}/#{name}") {
+ include "#{@dir}/#{name}"
+ namespace(@ns) {
+ genl "using framing::in_place;"
+ genl
+ scope("void #{name}::set(uint8_t classCode, uint8_t code) {") {
+ genl "uint16_t key=(classCode<<8)+code;"
+ scope ("switch(key) {") {
+ subs.each { |s|
+ genl "case 0x#{s.full_code.to_s(16)}: *this=in_place<#{s.fqclassname}>(); break;"
+ }
+ genl "default: assert(0);"
+ }}}}
end
- def gen_holders()
+ def gen_visitable(base, subs)
+ gen_holder(base, subs)
+ gen_visitor(base, subs)
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))
+ gen_visitable("Command", @amqp.collect_all(AmqpCommand))
+ gen_visitable("Control", @amqp.collect_all(AmqpControl))
+ # FIXME aconway 2008-03-04: sort out visitable structs.
+ # gen_visitable("Struct", @amqp.collect_all(AmqpStruct))
end
end
diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb
index 8e64b06208..63a2e6857e 100755
--- a/cpp/rubygen/cppgen.rb
+++ b/cpp/rubygen/cppgen.rb
@@ -162,7 +162,7 @@ class AmqpAction
def classname() name.typename; end
def funcname() parent.name.funcname + name.caps; end
def fqclassname() parent.name+"::"+classname; end
-
+ def full_code() (containing_class.code.hex << 8)+code.hex; end
include AmqpHasFields
end
diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am
index 080260be02..f15f8d7a91 100644
--- a/cpp/src/Makefile.am
+++ b/cpp/src/Makefile.am
@@ -103,8 +103,10 @@ libqpidcommon_la_LIBADD = \
libqpidcommon_la_SOURCES = \
$(rgen_common_cpp) \
$(platform_src) \
- qpid/amqp_0_10/helpers.cpp \
qpid/amqp_0_10/built_in_types.h \
+ qpid/amqp_0_10/complex_types.h \
+ qpid/amqp_0_10/complex_types.cpp \
+ qpid/amqp_0_10/Holder.h \
qpid/amqp_0_10/Codec.h \
qpid/amqp_0_10/Decimal.h \
qpid/Serializer.h \
@@ -254,7 +256,6 @@ libqpidclient_la_SOURCES = \
nobase_include_HEADERS = \
$(platform_hdr) \
- qpid/amqp_0_10/helpers.h \
qpid/amqp_0_10/apply.h \
qpid/assert.h \
qpid/DataDir.h \
diff --git a/cpp/src/qpid/Serializer.h b/cpp/src/qpid/Serializer.h
index a7194c5095..34b95d3ffd 100644
--- a/cpp/src/qpid/Serializer.h
+++ b/cpp/src/qpid/Serializer.h
@@ -22,37 +22,60 @@
*
*/
-#include <boost/type_traits/remove_const.hpp>
#include <boost/utility/enable_if.hpp>
-#include <boost/type_traits/is_const.hpp>
+#include <boost/static_assert.hpp>
#include <boost/type_traits/is_class.hpp>
-#include <boost/type_traits/add_const.hpp>
#include <algorithm>
namespace qpid {
-/**
- * Base class for serializers.
- */
+// FIXME aconway 2008-03-03: Doc - esp decoding
template <class Derived> class Serializer {
public:
+ typedef Serializer result_type; // unary functor requirement.
+
+ static const bool IS_DECODER=false;
+
+ /** Generic handler for class objects, call serialize() */
template <class T>
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());
+ t.serialize(self());
return self();
}
- template <class Iter> Derived& iterate(Iter begin, Iter end) {
- std::for_each(begin, end, self());
+ /** Generic handler for const class objects, call serialize() */
+ template <class T>
+ typename boost::enable_if<boost::is_class<T>, Derived&>::type
+ operator()(const T& t) {
+ assert(!Derived::IS_DECODER); // We won't modify the value.
+ // const_cast so we don't need 2 serialize() members for every class.
+ const_cast<T&>(t).serialize(self());
return self();
}
+ template <class T, bool=false> struct Split {
+ Split(Derived& s, T& t) { t.encode(s); }
+ };
+
+ template <class T> struct Split<T,true> {
+ Split(Derived& s, T& t) { t.decode(s); }
+ };
+ /**
+ * Called by classes that want to receive separate
+ * encode()/decode() calls.
+ */
+ template <class T>
+ void split(T& t) { Split<T, Derived::IS_DECODER>(self(),t); }
+
private:
Derived& self() { return *static_cast<Derived*>(this); }
};
+
+
+
+
} // namespace qpid
#endif /*!QPID_SERIALIZER_H*/
diff --git a/cpp/src/qpid/amqp_0_10/Codec.h b/cpp/src/qpid/amqp_0_10/Codec.h
index acfc1e9c81..a36004753a 100644
--- a/cpp/src/qpid/amqp_0_10/Codec.h
+++ b/cpp/src/qpid/amqp_0_10/Codec.h
@@ -28,15 +28,14 @@
#include <boost/type_traits/is_float.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/detail/endian.hpp>
-#include <boost/ref.hpp>
namespace qpid {
namespace amqp_0_10 {
/**
* AMQP 0-10 encoding and decoding.
*/
-class Codec {
- public:
+struct Codec { // FIXME aconway 2008-02-29: drop this wrapper?
+
/** Encode to an output byte iterator */
template <class OutIter>
class Encode : public Serializer<Encode<OutIter> > {
@@ -58,6 +57,11 @@ class Codec {
typename boost::enable_if<boost::is_float<T>, Encode&>::type
operator()(const T& x) { raw(&x, sizeof(x)); return *this; }
+ template <class Iter> Encode& operator()(Iter begin, Iter end) {
+ std::for_each(begin, end, *this);
+ return *this;
+ }
+
void raw(const void* p, size_t n) {
std::copy((const char*)p, (const char*)p+n, out);
}
@@ -70,6 +74,8 @@ class Codec {
class Decode : public Serializer<Decode<InIter> > {
public:
Decode(InIter i) : in(i) {}
+
+ static const bool IS_DECODER=true;
using Serializer<Decode<InIter> >::operator();
@@ -94,6 +100,11 @@ class Codec {
return *this;
}
+ template <class Iter> Decode& operator()(Iter begin, Iter end) {
+ std::for_each(begin, end, *this);
+ 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?
@@ -124,30 +135,27 @@ class Codec {
return *this;
}
+ template <class Iter>
+ Size& operator()(const Iter& a, const Iter& b) {
+ size += (b-a)*sizeof(*a);
+ return *this;
+ }
+
void raw(const void*, size_t n){ size += n; }
private:
size_t size;
};
- template <class Out, class T>
- static void encode(Out o, const T& x) {
- Encode<Out> encode(o);
- encode(x);
+ template <class OutIter> static Decode<OutIter> decode(const OutIter &i) {
+ return Decode<OutIter>(i);
}
- template <class In, class T>
- static void decode(In i, T& x) {
- Decode<In> decode(i);
- decode(x);
+ template <class InIter> static Encode<InIter> encode(InIter i) {
+ return Encode<InIter>(i);
}
- template <class T>
- static size_t size(const T& x) {
- Size sz;
- sz(x);
- return sz;
- }
+ template <class T> static size_t size(const T& x) { return Size()(x); }
private:
template <class T> static inline void endianize(T& value) {
diff --git a/cpp/src/qpid/amqp_0_10/Holder.h b/cpp/src/qpid/amqp_0_10/Holder.h
new file mode 100644
index 0000000000..76f8aa52de
--- /dev/null
+++ b/cpp/src/qpid/amqp_0_10/Holder.h
@@ -0,0 +1,62 @@
+#ifndef QPID_AMQP_0_10_HOLDER_H
+#define QPID_AMQP_0_10_HOLDER_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/Blob.h"
+#include "apply.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+
+template <class DerivedHolder, class BaseHeld, size_t Size>
+struct Holder : public framing::Blob<Size, BaseHeld> {
+
+ typedef framing::Blob<Size, BaseHeld> Base;
+
+ Holder() {}
+ template <class T> Holder(const T& value) : Base(value) {}
+
+ using Base::operator=;
+
+ uint8_t getCode() const { return this->get()->getCode(); }
+ uint8_t getClassCode() const { return this->get()->getClassCode(); }
+
+ template <class S> void encode(S& s) {
+ s(getClassCode())(getCode());
+ }
+
+ template <class S> void decode(S& s) {
+ uint8_t code, classCode;
+ s(classCode)(code);
+ static_cast<DerivedHolder*>(this)->set(classCode, code);
+ }
+
+ template <class S> void serialize(S& s) {
+ s.split(*this);
+ apply(s, *this->get());
+ }
+};
+
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_HOLDER_H*/
diff --git a/cpp/src/qpid/amqp_0_10/apply.h b/cpp/src/qpid/amqp_0_10/apply.h
index e1bd9c3aa6..05b7669322 100644
--- a/cpp/src/qpid/amqp_0_10/apply.h
+++ b/cpp/src/qpid/amqp_0_10/apply.h
@@ -31,7 +31,8 @@ template <class F, class R=typename F::result_type> struct FunctionAndResult {
boost::optional<R> result;
FunctionAndResult() : functor(0) {}
- template <class T> void invoke(T t) { result=(*functor)(t); }
+ template <class T> void invoke(T& t) { result=(*functor)(t); }
+ template <class T> void invoke(const T& t) { result=(*functor)(t); }
R getResult() { return *result; }
};
@@ -40,17 +41,23 @@ template <class F> struct FunctionAndResult<F, void> {
F* functor;
FunctionAndResult() : functor(0) {}
- template <class T> void invoke(T t) { (*functor)(t); }
+ 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;
+// Metafunction returning correct abstract visitor for Visitable type.
+template <class Visitable> struct VisitorType {
+ typedef typename Visitable::Visitor type;
};
+template <class Visitable> struct VisitorType<const Visitable> {
+ typedef typename Visitable::ConstVisitor type;
+};
+
+template <class Visitor, class F>
+struct ApplyVisitorBase : public Visitor, public FunctionAndResult<F> {};
// Specialize for each visitor type
-template <class V, class F> struct ApplyVisitor;
+template <class Visitable, class F> struct ApplyVisitor;
/** Apply a functor to a visitable object.
* The functor can have operator() overloads for each visitable type
@@ -58,7 +65,7 @@ template <class V, class F> struct ApplyVisitor;
*/
template <class F, class Visitable>
typename F::result_type apply(F& functor, Visitable& visitable) {
- ApplyVisitor<typename Visitable::Visitor, F> visitor;
+ ApplyVisitor<typename VisitorType<Visitable>::type, F> visitor;
visitor.functor=&functor;
visitable.accept(visitor);
return visitor.getResult();
@@ -66,12 +73,18 @@ typename F::result_type apply(F& functor, Visitable& visitable) {
template <class F, class Visitable>
typename F::result_type apply(const F& functor, Visitable& visitable) {
- ApplyVisitor<typename Visitable::Visitor, const F> visitor;
+ ApplyVisitor<typename VisitorType<Visitable>::type, const F> visitor;
visitor.functor=&functor;
visitable.accept(visitor);
return visitor.getResult();
}
+template <class R, bool Const=false> struct ApplyFunctor {
+ typedef R result_type;
+ static const bool IS_CONST=Const;
+};
+template <class R> struct ConstApplyFunctor : public ApplyFunctor<R, true> {};
+
}} // namespace qpid::amqp_0_10
#endif /*!QPID_AMQP_0_10_APPLY_H*/
diff --git a/cpp/src/qpid/amqp_0_10/built_in_types.h b/cpp/src/qpid/amqp_0_10/built_in_types.h
index 13bcdf862e..6188e259f0 100644
--- a/cpp/src/qpid/amqp_0_10/built_in_types.h
+++ b/cpp/src/qpid/amqp_0_10/built_in_types.h
@@ -82,7 +82,7 @@ template <class T, class SizeType>
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());
+ s(SizeType(this->size()))(this->begin(), this->end());
}
};
@@ -107,16 +107,29 @@ typedef SerializableString<Uint16, Uint16> Str16Utf16;
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 {};
-struct List {};
-struct Struct32 {};
+template <class T> struct Array : public std::vector<T> { template <class S> void serialize(S&) {} };
+struct ByteRanges { template <class S> void serialize(S&) {} };
+struct SequenceSet { template <class S> void serialize(S&) {} };
+struct Map { template <class S> void serialize(S&) {} };
+struct List { template <class S> void serialize(S&) {} };
+struct Struct32 { template <class S> void serialize(S&) {} };
+
+// Serializable enum support
+template <class E, class Store> struct Enum {
+ Store value;
+ Enum() {}
+ Enum(E v) : value(v) {}
+ Enum(Store v) : value(v) {}
+ Enum& operator=(E v) { value=v; return *this; }
+ Enum& operator=(Store v) { value=v; return *this; }
+ operator E() const { return value; }
+ operator Store() const { return value; }
+ template <class S> void serialize(S& s) { s(value); }
+};
-// Top level enum definitions.
-enum SegmentType { CONTROL, COMMAND, HEADER, BODY };
+enum SegmentTypeEnum { CONTROL, COMMAND, HEADER, BODY };
+typedef Enum<SegmentTypeEnum, uint8_t> SegmentType;
}} // namespace qpid::amqp_0_10
-#endif /*!QPID_AMQP_0_10_BUILT_IN_TYPES_H*/
+#endif
diff --git a/cpp/src/qpid/amqp_0_10/complex_types.cpp b/cpp/src/qpid/amqp_0_10/complex_types.cpp
new file mode 100644
index 0000000000..0960db469d
--- /dev/null
+++ b/cpp/src/qpid/amqp_0_10/complex_types.cpp
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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/amqp_0_10/ApplyCommand.h"
+#include "qpid/amqp_0_10/ApplyControl.h"
+// FIXME aconway 2008-03-04: #include "qpid/amqp_0_10/ApplyStruct.h"
+#include "qpid/amqp_0_10/apply.h"
+
+namespace qpid {
+namespace amqp_0_10 {
+// Functors for getting static values from a visitable base type.
+
+#define QPID_STATIC_VALUE_GETTER(NAME, TYPE, VALUE) \
+ struct NAME : public ConstApplyFunctor<TYPE> { \
+ template <class T> TYPE operator()(const T&) const { return T::VALUE; }\
+ }
+
+QPID_STATIC_VALUE_GETTER(GetCode, uint8_t, CODE);
+QPID_STATIC_VALUE_GETTER(GetSize, uint8_t, SIZE);
+QPID_STATIC_VALUE_GETTER(GetPack, uint8_t, PACK);
+QPID_STATIC_VALUE_GETTER(GetClassCode, uint8_t, CLASS_CODE);
+QPID_STATIC_VALUE_GETTER(GetName, const char*, NAME);
+QPID_STATIC_VALUE_GETTER(GetClassName, const char*, CLASS_NAME);
+
+
+uint8_t Command::getCode() const { return apply(GetCode(), *this); }
+uint8_t Command::getClassCode() const { return apply(GetClassCode(), *this); }
+const char* Command::getName() const { return apply(GetName(), *this); }
+const char* Command::getClassName() const { return apply(GetClassName(), *this); }
+
+uint8_t Control::getCode() const { return apply(GetCode(), *this); }
+uint8_t Control::getClassCode() const { return apply(GetClassCode(), *this); }
+const char* Control::getName() const { return apply(GetName(), *this); }
+const char* Control::getClassName() const { return apply(GetClassName(), *this); }
+
+// FIXME aconway 2008-03-04: Struct visitors
+// uint8_t Struct::getCode() const { return apply(GetCode(), *this); }
+// uint8_t Struct::getPack() const { return apply(GetPack(), *this); }
+// uint8_t Struct::getSize() const { return apply(GetSize(), *this); }
+// uint8_t Struct::getClassCode() const { return apply(GetClassCode(), *this); }
+uint8_t Struct::getCode() const { assert(0); return 0; }
+uint8_t Struct::getPack() const { assert(0); return 0; }
+uint8_t Struct::getSize() const { assert(0); return 0; }
+uint8_t Struct::getClassCode() const { assert(0); return 0; }
+
+}} // namespace qpid::amqp_0_10
+
diff --git a/cpp/src/qpid/amqp_0_10/complex_types.h b/cpp/src/qpid/amqp_0_10/complex_types.h
new file mode 100644
index 0000000000..f4810ba2d7
--- /dev/null
+++ b/cpp/src/qpid/amqp_0_10/complex_types.h
@@ -0,0 +1,79 @@
+#ifndef QPID_AMQP_0_10_COMPLEX_TYPES_H
+#define QPID_AMQP_0_10_COMPLEX_TYPES_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.
+ *
+ */
+
+namespace qpid {
+namespace amqp_0_10 {
+
+// Base classes for complex types.
+
+template <class V, class CV, class H> struct Visitable {
+ typedef V Visitor;
+ typedef CV ConstVisitor;
+ typedef H Holder;
+
+ virtual ~Visitable() {}
+ virtual void accept(Visitor&) = 0;
+ virtual void accept(ConstVisitor&) const = 0;
+};
+
+struct CommandVisitor;
+struct ConstCommandVisitor;
+struct CommandHolder;
+struct Command
+ : public Visitable<CommandVisitor, ConstCommandVisitor, CommandHolder>
+{
+ uint8_t getCode() const;
+ uint8_t getClassCode() const;
+ const char* getName() const;
+ const char* getClassName() const;
+};
+
+struct ControlVisitor;
+struct ConstControlVisitor;
+struct ControlHolder;
+struct Control
+ : public Visitable<ControlVisitor, ConstControlVisitor, ControlHolder>
+{
+ uint8_t getCode() const;
+ uint8_t getClassCode() const;
+ const char* getName() const;
+ const char* getClassName() const;
+};
+
+struct StructVisitor;
+struct ConstStructVisitor;
+struct StructHolder;
+struct Struct
+ : public Visitable<StructVisitor, ConstStructVisitor, StructHolder>
+{
+ uint8_t getCode() const;
+ uint8_t getPack() const;
+ uint8_t getSize() const;
+ uint8_t getClassCode() const;
+};
+
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_COMPLEX_TYPES_H*/
diff --git a/cpp/src/qpid/amqp_0_10/helpers.cpp b/cpp/src/qpid/amqp_0_10/helpers.cpp
deleted file mode 100644
index 457abe2d5f..0000000000
--- a/cpp/src/qpid/amqp_0_10/helpers.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *
- * 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 "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 {
-
-Control::~Control() {}
-Command::~Command() {}
-Struct::~Struct() {}
-
-}} // namespace qpid::amqp_0_10
diff --git a/cpp/src/qpid/amqp_0_10/helpers.h b/cpp/src/qpid/amqp_0_10/helpers.h
deleted file mode 100644
index b5150cd10f..0000000000
--- a/cpp/src/qpid/amqp_0_10/helpers.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef QPID_AMQP_0_10_HELPERS_H
-#define QPID_AMQP_0_10_HELPERS_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
-n * "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/amqp_0_10/built_in_types.h"
-#include <string>
-
-namespace qpid {
-namespace amqp_0_10 {
-
-// Look up names by code
-const char* getClassName(uint8_t code);
-const char* getCommandName(uint8_t classCode, uint8_t code);
-const char* getControlName(uint8_t classCode, uint8_t code);
-const char* getStructName(uint8_t classCode, uint8_t code);
-
-struct Command {
- static const int SEGMENT_TYPE=COMMAND;
- virtual ~Command();
- struct Visitor;
- virtual void accept(Visitor&) const = 0;
-};
-
-struct Control {
- static const int SEGMENT_TYPE=CONTROL;
- virtual ~Control();
- struct Visitor;
- virtual void accept(Visitor&) const = 0;
-};
-
-// Struct
-struct Struct {
- virtual ~Struct();
- struct Visitor;
- virtual void accept(Visitor&) const = 0;
-};
-
-template <class SizeType, bool Coded, uint8_t Code, uint8_t Pack>
-struct SerializableStruct : public Struct {
- static const uint8_t SIZE=sizeof(SizeType);
- static const bool CODED=Coded;
- static const uint8_t CODE=Code;
- static const uint8_t PACK;
- // TODO aconway 2008-02-29: handle common encoding/decoding/size
- // for structs. Support for packing.
-};
-
-
-/** Base class for generated enum domains.
- * Enums map to classes for type safety and to provide separate namespaces
- * for clashing values.
- */
-struct Enum {
- int value;
- Enum(int v=0) : value(v) {}
- operator int() const { return value; }
- template <class S> void serialize(S &s) { s(value); }
-};
-
-}} // namespace qpid::amqp_0_10
-
-#endif /*!QPID_AMQP_0_10_HELPERS_H*/
diff --git a/cpp/src/qpid/framing/AMQBody.h b/cpp/src/qpid/framing/AMQBody.h
index 73c462a427..925f4c46ac 100644
--- a/cpp/src/qpid/framing/AMQBody.h
+++ b/cpp/src/qpid/framing/AMQBody.h
@@ -22,7 +22,8 @@
*
*/
#include "qpid/framing/amqp_types.h"
-#include "qpid/amqp_0_10/helpers.h"
+#include "qpid/amqp_0_10/built_in_types.h"
+#include "qpid/amqp_0_10/complex_types.h"
#include <ostream>
diff --git a/cpp/src/tests/apply.cpp b/cpp/src/tests/apply.cpp
index 553026a35c..1b66d8e3b4 100644
--- a/cpp/src/tests/apply.cpp
+++ b/cpp/src/tests/apply.cpp
@@ -26,11 +26,15 @@ QPID_AUTO_TEST_SUITE(VisitorTestSuite)
using namespace qpid::amqp_0_10;
-struct GetCode {
- typedef uint8_t result_type;
+struct GetCode : public ConstApplyFunctor<uint8_t> {
template <class T> uint8_t operator()(const T&) const { return T::CODE; }
};
+struct SetChannelMax : ApplyFunctor<void> {
+ template <class T> void operator()(T&) const { BOOST_FAIL(""); }
+ void operator()(connection::Tune& t) const { t.channelMax=42; }
+};
+
struct TestFunctor {
typedef bool result_type;
bool operator()(const connection::Tune& tune) {
@@ -57,6 +61,9 @@ BOOST_AUTO_TEST_CASE(testApply) {
connection::Start start;
p = &start;
BOOST_CHECK(!apply(tf, *p));
+
+ apply(SetChannelMax(), tune);
+ BOOST_CHECK_EQUAL(tune.channelMax, 42);
}
struct VoidTestFunctor {
diff --git a/cpp/src/tests/serialize.cpp b/cpp/src/tests/serialize.cpp
index 8de2d4ca58..9eaf78ab78 100644
--- a/cpp/src/tests/serialize.cpp
+++ b/cpp/src/tests/serialize.cpp
@@ -22,6 +22,9 @@
#include "unit_test.h"
#include "qpid/amqp_0_10/built_in_types.h"
#include "qpid/amqp_0_10/Codec.h"
+#include "qpid/amqp_0_10/specification.h"
+#include "qpid/amqp_0_10/ControlHolder.h"
+
#include <boost/test/test_case_template.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/utility/enable_if.hpp>
@@ -62,6 +65,7 @@ QPID_AUTO_TEST_SUITE(SerializeTestSuite)
using namespace std;
namespace mpl=boost::mpl;
using namespace qpid::amqp_0_10;
+using qpid::framing::in_place;
template <class A, class B> struct concat2 { typedef typename mpl::copy<B, typename mpl::back_inserter<A> >::type type; };
template <class A, class B, class C> struct concat3 { typedef typename concat2<A, typename concat2<B, C>::type>::type type; };
@@ -82,14 +86,14 @@ BOOST_AUTO_TEST_CASE(testNetworkByteOrder) {
string data;
uint32_t l = 0x11223344;
- Codec::encode(std::back_inserter(data), l);
+ 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 = 0x1122;
- Codec::encode(std::back_inserter(data), s);
+ Codec::encode(std::back_inserter(data))(s);
uint32_t s2 = ntohs(*reinterpret_cast<const uint32_t*>(data.data()));
BOOST_CHECK_EQUAL(s, s2);
}
@@ -116,14 +120,58 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(testEncodeDecode, T, AllTypes)
string data;
T t;
testValue(t);
- Codec::encode(std::back_inserter(data), t);
+ Codec::encode(std::back_inserter(data))(t);
BOOST_CHECK_EQUAL(Codec::size(t), data.size());
T t2;
- Codec::decode(data.begin(), t2);
+ Codec::decode(data.begin())(t2);
BOOST_CHECK_EQUAL(t,t2);
}
+struct TestMe {
+ bool encoded, decoded;
+ char value;
+ TestMe(char v) : encoded(), decoded(), value(v) {}
+ template <class S> void encode(S& s) { encoded=true; s(value); }
+ template <class S> void decode(S& s) { decoded=true; s(value); }
+ template <class S> void serialize(S& s) { s.split(*this); }
+};
+
+BOOST_AUTO_TEST_CASE(testSplit) {
+ string data;
+ TestMe t1('x');
+ Codec::encode(std::back_inserter(data))(t1);
+ BOOST_CHECK(t1.encoded);
+ BOOST_CHECK(!t1.decoded);
+ BOOST_CHECK_EQUAL(data, "x");
+
+ TestMe t2('y');
+ Codec::decode(data.begin())(t2);
+ BOOST_CHECK(!t2.encoded);
+ BOOST_CHECK(t2.decoded);
+ BOOST_CHECK_EQUAL(t2.value, 'x');
+}
+
+BOOST_AUTO_TEST_CASE(testControlEncodeDecode) {
+ string data;
+ Control::Holder h(in_place<connection::Tune>(1,2,3,4));
+ Codec::encode(std::back_inserter(data))(h);
+
+ BOOST_CHECK_EQUAL(data.size(), Codec::size(h));
+
+ Codec::Decode<string::iterator> decode(data.begin());
+ Control::Holder h2;
+ decode(h2);
+
+ BOOST_REQUIRE(h2.get());
+ BOOST_CHECK_EQUAL(h2.get()->getClassCode(), connection::CODE);
+ BOOST_CHECK_EQUAL(h2.get()->getCode(), uint8_t(connection::Tune::CODE));
+ connection::Tune& tune=static_cast<connection::Tune&>(*h2.get());
+ BOOST_CHECK_EQUAL(tune.channelMax, 1u);
+ BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u);
+}
QPID_AUTO_TEST_SUITE_END()