summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
authorAlan Conway <aconway@apache.org>2008-02-29 22:07:40 +0000
committerAlan Conway <aconway@apache.org>2008-02-29 22:07:40 +0000
commit6dd59f62185ab8547cc1eec0a57731e0ab5a8645 (patch)
tree25539ade95b792d9e8228eb5b24d5a65340bc5d6 /cpp
parent3fb6c758d2d7d7c1822e216e3c22db4630eb19e0 (diff)
downloadqpid-python-6dd59f62185ab8547cc1eec0a57731e0ab5a8645.tar.gz
Template visitors for amqp_0_10::Command, Control and Struct.
Serialization for all str/vbin types. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@632457 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp')
-rwxr-xr-xcpp/rubygen/0-10/specification.rb76
-rwxr-xr-xcpp/rubygen/amqpgen.rb9
-rwxr-xr-xcpp/rubygen/cppgen.rb22
-rw-r--r--cpp/src/Makefile.am3
-rw-r--r--cpp/src/qpid/Serializer.h80
-rw-r--r--cpp/src/qpid/amqp_0_10/Codec.h134
-rw-r--r--cpp/src/qpid/amqp_0_10/Decimal.h5
-rw-r--r--cpp/src/qpid/amqp_0_10/apply.h77
-rw-r--r--cpp/src/qpid/amqp_0_10/built_in_types.h60
-rw-r--r--cpp/src/qpid/amqp_0_10/helpers.cpp3
-rw-r--r--cpp/src/qpid/amqp_0_10/helpers.h7
-rw-r--r--cpp/src/qpid/amqp_0_10/visitors.h15
-rw-r--r--cpp/src/qpid/framing/Uuid.h2
-rw-r--r--cpp/src/tests/Makefile.am2
-rw-r--r--cpp/src/tests/apply.cpp92
-rw-r--r--cpp/src/tests/serialize.cpp30
16 files changed, 385 insertions, 232 deletions
diff --git a/cpp/rubygen/0-10/specification.rb b/cpp/rubygen/0-10/specification.rb
index d4ecfe98ed..acf9e4e6ed 100755
--- a/cpp/rubygen/0-10/specification.rb
+++ b/cpp/rubygen/0-10/specification.rb
@@ -19,10 +19,8 @@ class Specification < CppGen
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 @@ class Specification < CppGen
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 @@ class Specification < CppGen
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 @@ class Specification < CppGen
# 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 @@ class Specification < CppGen
}
}
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
diff --git a/cpp/rubygen/amqpgen.rb b/cpp/rubygen/amqpgen.rb
index 2edc573d00..67b4b1c73c 100755
--- a/cpp/rubygen/amqpgen.rb
+++ b/cpp/rubygen/amqpgen.rb
@@ -131,6 +131,12 @@ class AmqpElement
@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 @@ class AmqpRoot < AmqpElement
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 @@ class AmqpRoot < AmqpElement
def fqname() nil; end
- # TODO aconway 2008-02-21: methods by role.
-
private
# Merge contents of elements.
diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb
index 5d2695c77a..df4ba49ca8 100755
--- a/cpp/rubygen/cppgen.rb
+++ b/cpp/rubygen/cppgen.rb
@@ -57,6 +57,7 @@ class String
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 @@ class CppType
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 @@ class CppGen < Generator
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
diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am
index becccb4224..a3609667d7 100644
--- a/cpp/src/Makefile.am
+++ b/cpp/src/Makefile.am
@@ -104,10 +104,10 @@ libqpidcommon_la_SOURCES = \
$(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 @@ 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 \
qpid/Exception.h \
diff --git a/cpp/src/qpid/Serializer.h b/cpp/src/qpid/Serializer.h
index a2fbf944ae..95cc2d5875 100644
--- a/cpp/src/qpid/Serializer.h
+++ b/cpp/src/qpid/Serializer.h
@@ -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*/
diff --git a/cpp/src/qpid/amqp_0_10/Codec.h b/cpp/src/qpid/amqp_0_10/Codec.h
index e7f35e9288..acfc1e9c81 100644
--- a/cpp/src/qpid/amqp_0_10/Codec.h
+++ b/cpp/src/qpid/amqp_0_10/Codec.h
@@ -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 @@ struct Codec
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 @@ struct Codec
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 @@ struct Codec
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
diff --git a/cpp/src/qpid/amqp_0_10/Decimal.h b/cpp/src/qpid/amqp_0_10/Decimal.h
index 75cde94559..50fc457c76 100644
--- a/cpp/src/qpid/amqp_0_10/Decimal.h
+++ b/cpp/src/qpid/amqp_0_10/Decimal.h
@@ -30,7 +30,7 @@ template <class E, class M> struct Decimal {
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> struct Decimal {
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 << "}";
}
}}
diff --git a/cpp/src/qpid/amqp_0_10/apply.h b/cpp/src/qpid/amqp_0_10/apply.h
new file mode 100644
index 0000000000..e1bd9c3aa6
--- /dev/null
+++ b/cpp/src/qpid/amqp_0_10/apply.h
@@ -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*/
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 445f07459c..13bcdf862e 100644
--- a/cpp/src/qpid/amqp_0_10/built_in_types.h
+++ b/cpp/src/qpid/amqp_0_10/built_in_types.h
@@ -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 uint64_t Uint64;
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 @@ typedef Decimal<Uint8, Int64> Dec64;
/** 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 CodableString<Uint8, Uint32> Vbin32;
+typedef SerializableString<Uint8, Uint16> Vbin16;
+typedef SerializableString<char, Uint16> Str16Latin;
+typedef SerializableString<char, Uint16> Str16;
+typedef SerializableString<Uint16, Uint16> Str16Utf16;
-// 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 {};
diff --git a/cpp/src/qpid/amqp_0_10/helpers.cpp b/cpp/src/qpid/amqp_0_10/helpers.cpp
index 4333a2cd92..457abe2d5f 100644
--- a/cpp/src/qpid/amqp_0_10/helpers.cpp
+++ b/cpp/src/qpid/amqp_0_10/helpers.cpp
@@ -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 {
diff --git a/cpp/src/qpid/amqp_0_10/helpers.h b/cpp/src/qpid/amqp_0_10/helpers.h
index 1769d374d9..fc9a3e16a4 100644
--- a/cpp/src/qpid/amqp_0_10/helpers.h
+++ b/cpp/src/qpid/amqp_0_10/helpers.h
@@ -24,7 +24,6 @@ n * "License"); you may not use this file except in compliance
#include <string>
namespace qpid {
-
namespace amqp_0_10 {
// Look up names by code
@@ -35,19 +34,19 @@ const char* getStructName(uint8_t classCode, uint8_t code);
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;
};
diff --git a/cpp/src/qpid/amqp_0_10/visitors.h b/cpp/src/qpid/amqp_0_10/visitors.h
deleted file mode 100644
index 3835f37f3e..0000000000
--- a/cpp/src/qpid/amqp_0_10/visitors.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Visitors
-template <class Base> struct Visitor;
-template <class Base, class F, class R> FunctorVisitor;
-
-/** Template base implementation for visitables. */
-template <class Base, class Derived>
-struct VisitableBase : public Base {
- virtual void accept(Visitor<Derived>& v) {
- v.visit(static_cast<Derived>&(*this));
- }
- virtual void accept(Visitor<Derived>& v) const {
- v.visit(static_cast<const Derived>&(*this));
- }
-};
-
diff --git a/cpp/src/qpid/framing/Uuid.h b/cpp/src/qpid/framing/Uuid.h
index 278a60c439..bce18f55b3 100644
--- a/cpp/src/qpid/framing/Uuid.h
+++ b/cpp/src/qpid/framing/Uuid.h
@@ -67,7 +67,7 @@ struct Uuid : public boost::array<uint8_t, 16> {
std::string str() const;
template <class S> void serialize(S& s) {
- s(static_cast<boost::array<uint8_t, 16>&>(*this));
+ s.raw(begin(), size());
}
};
diff --git a/cpp/src/tests/Makefile.am b/cpp/src/tests/Makefile.am
index 4a47797350..d25378a519 100644
--- a/cpp/src/tests/Makefile.am
+++ b/cpp/src/tests/Makefile.am
@@ -39,7 +39,7 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \
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
diff --git a/cpp/src/tests/apply.cpp b/cpp/src/tests/apply.cpp
new file mode 100644
index 0000000000..553026a35c
--- /dev/null
+++ b/cpp/src/tests/apply.cpp
@@ -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()
diff --git a/cpp/src/tests/serialize.cpp b/cpp/src/tests/serialize.cpp
index a120be6458..8de2d4ca58 100644
--- a/cpp/src/tests/serialize.cpp
+++ b/cpp/src/tests/serialize.cpp
@@ -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 @@ std::ostream& operator<<(std::ostream& out, const AbsTime& t) {
}
}
-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 @@ typedef concat2<FixedSizeTypes, VariableSizeTypes>::type AllTypes;
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;