summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Conway <aconway@apache.org>2008-04-02 17:56:14 +0000
committerAlan Conway <aconway@apache.org>2008-04-02 17:56:14 +0000
commitc6bd8565ecc054fa3a393f7df04b1d44836c3a79 (patch)
treea6e237fab1bba4ec6ea868ff719d5068fdc6f5c5
parent735fbf00f9ddae479c6a4e682fd3fa4224b6131f (diff)
downloadqpid-python-c6bd8565ecc054fa3a393f7df04b1d44836c3a79.tar.gz
Encoding/decoding for new types: amqp_0_10::Map, amqp_0_10:UnknownType
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@643995 13f79535-47bb-0310-9956-ffa450edef68
-rwxr-xr-xqpid/cpp/rubygen/0-10/specification.rb1
-rwxr-xr-xqpid/cpp/rubygen/0-10/typecode.rb85
-rwxr-xr-xqpid/cpp/rubygen/cppgen.rb11
-rw-r--r--qpid/cpp/src/Makefile.am5
-rw-r--r--qpid/cpp/src/qpid/Serializer.h10
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Codec.h12
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Map.cpp68
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Map.h179
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/SerializableString.h62
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp56
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/UnknownType.h86
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/built_in_types.h80
-rw-r--r--qpid/cpp/src/tests/Makefile.am3
-rw-r--r--qpid/cpp/src/tests/amqp_0_10/Map.cpp99
-rw-r--r--qpid/cpp/src/tests/serialize.cpp15
15 files changed, 716 insertions, 56 deletions
diff --git a/qpid/cpp/rubygen/0-10/specification.rb b/qpid/cpp/rubygen/0-10/specification.rb
index a11abdb877..dbb05fb752 100755
--- a/qpid/cpp/rubygen/0-10/specification.rb
+++ b/qpid/cpp/rubygen/0-10/specification.rb
@@ -117,6 +117,7 @@ class Specification < CppGen
h_file("#{@dir}/specification") {
include "#{@dir}/built_in_types"
include "#{@dir}/complex_types"
+ include "#{@dir}/Map.h"
include "<boost/call_traits.hpp>"
include "<iosfwd>"
genl "using boost::call_traits;"
diff --git a/qpid/cpp/rubygen/0-10/typecode.rb b/qpid/cpp/rubygen/0-10/typecode.rb
new file mode 100755
index 0000000000..459516e51c
--- /dev/null
+++ b/qpid/cpp/rubygen/0-10/typecode.rb
@@ -0,0 +1,85 @@
+#!/usr/bin/env ruby
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class TypeCode < CppGen
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @ns="qpid::amqp_#{@amqp.version.bars}"
+ @dir="qpid/amqp_#{@amqp.version.bars}"
+ @types = @amqp.collect_all(AmqpType).select { |t| t.code }
+
+ end
+
+ def type_for_code_h()
+ h_file("#{@dir}/TypeForCode") {
+ include "#{@dir}/UnknownType.h"
+ namespace(@ns) {
+ genl
+ genl "template <uint8_t Code> struct TypeForCode;"
+ genl
+ @types.each { |t|
+ genl "template <> struct TypeForCode<#{t.code}> { typedef #{t.typename} type; };"
+ }
+ genl
+ genl "template <class V> typename V::result_type"
+ scope("apply_visitor(V& visitor, uint8_t code) {") {
+ scope("switch (code) {", "}") {
+ @types.each { |t|
+ genl "case #{t.code}: return visitor((#{t.typename}*)0);"
+ }
+ genl "default: return visitor((UnknownType*)0);"
+ }
+ }
+ genl
+ genl "std::string typeName(uint8_t code);"
+ }
+ }
+ end
+
+ def type_for_code_cpp()
+ cpp_file("#{@dir}/TypeForCode") {
+ include "<string>"
+ include "<sstream>"
+ namespace(@ns) {
+ namespace("") {
+ struct("Names") {
+ scope("Names() {") {
+ scope("for (int i =0; i < 256; ++i) {") {
+ genl "std::ostringstream os;"
+ genl "os << \"UnknownType<\" << i << \">\";"
+ genl "names[i] = os.str();"
+ }
+ @types.each { |t| genl "names[#{t.code}] = \"#{t.name}\";" }
+ }
+ genl "std::string names[256];"
+ }
+ genl "Names names;"
+ }
+ genl "std::string typeName(uint8_t code) { return names.names[code]; }"
+ }}
+ end
+
+ def code_for_type_h()
+ h_file("#{@dir}/CodeForType") {
+ namespace(@ns) {
+ genl
+ genl "template <class T> struct CodeForType;"
+ genl
+ @types.each { |t|
+ genl "template <> struct CodeForType<#{t.typename}> { static const uint8_t value=#{t.code}; };"
+ }
+ genl
+ genl "template <class T> uint8_t codeFor(const T&) { return CodeForType<T>::value; }"
+ }}
+ end
+
+ def generate
+ type_for_code_h
+ type_for_code_cpp
+ code_for_type_h
+ end
+end
+
+TypeCode.new($outdir, $amqp).generate();
+
diff --git a/qpid/cpp/rubygen/cppgen.rb b/qpid/cpp/rubygen/cppgen.rb
index 63a2e6857e..d0f31a8ba8 100755
--- a/qpid/cpp/rubygen/cppgen.rb
+++ b/qpid/cpp/rubygen/cppgen.rb
@@ -57,7 +57,6 @@ 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?
@@ -116,7 +115,7 @@ end
class AmqpElement
# convert my amqp type_ attribute to a C++ type.
def amqp2cpp()
- return "Array<#{ArrayTypes[name].amqp2cpp}> " if type_=="array"
+ return "ArrayDomain<#{ArrayTypes[name].amqp2cpp}> " if type_=="array"
return type_.amqp2cpp
end
end
@@ -166,6 +165,11 @@ class AmqpAction
include AmqpHasFields
end
+class AmqpType
+ def typename() name.typename; end
+ def fixed?() fixed_width; end
+end
+
class AmqpCommand < AmqpAction
def base() "Command"; end
end
@@ -281,10 +285,11 @@ class CppGen < Generator
genl
names = name.split("::")
names.each { |n| genl "namespace #{n} {" }
+ genl "namespace {" if (names.empty?)
genl
yield
genl
- genl('}'*names.size+" // namespace "+name)
+ genl('}'*([names.size, 1].max)+" // namespace "+name)
genl
end
diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am
index 72f63ae48e..05efcb2a71 100644
--- a/qpid/cpp/src/Makefile.am
+++ b/qpid/cpp/src/Makefile.am
@@ -113,8 +113,13 @@ libqpidcommon_la_SOURCES = \
qpid/amqp_0_10/Frame.h \
qpid/amqp_0_10/Segment.h \
qpid/amqp_0_10/Segment.cpp \
+ qpid/amqp_0_10/SerializableString.h \
qpid/amqp_0_10/Assembly.h \
qpid/amqp_0_10/Assembly.cpp \
+ qpid/amqp_0_10/Map.h \
+ qpid/amqp_0_10/Map.cpp \
+ qpid/amqp_0_10/UnknownType.h \
+ qpid/amqp_0_10/UnknownType.cpp \
qpid/Serializer.h \
qpid/framing/AccumulatedAck.cpp \
qpid/framing/AMQBody.cpp \
diff --git a/qpid/cpp/src/qpid/Serializer.h b/qpid/cpp/src/qpid/Serializer.h
index e0e29e24fd..12bcded0f7 100644
--- a/qpid/cpp/src/qpid/Serializer.h
+++ b/qpid/cpp/src/qpid/Serializer.h
@@ -28,6 +28,16 @@
namespace qpid {
namespace serialize {
+/** Wrapper to pass serializer functors by reference. */
+template <class S> struct SRef {
+ S& s;
+ SRef(S& ss) : s(ss) {}
+ template <class T> typename S::result_type operator()(T& x) { return s(x); }
+ template <class T> typename S::result_type operator()(const T& x) { return s(x); }
+};
+
+template <class S> SRef<S> ref(S& s) { return SRef<S>(s); }
+
// FIXME aconway 2008-03-03: Document.
// Encoder/Decoder concept: add op() for primitive types, raw(),
// op()(Iter, Iter). Note split, encode, decode.
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Codec.h b/qpid/cpp/src/qpid/amqp_0_10/Codec.h
index 04112cc4d1..138de8c96e 100644
--- a/qpid/cpp/src/qpid/amqp_0_10/Codec.h
+++ b/qpid/cpp/src/qpid/amqp_0_10/Codec.h
@@ -46,7 +46,6 @@ template <class T> void endianize(T&) {}
* AMQP 0-10 encoding and decoding.
*/
struct Codec {
-
// FIXME aconway 2008-02-29: drop this wrapper, rename to
// IteratorEncoder, IteratorDecoder?
@@ -79,7 +78,7 @@ struct Codec {
template <class Iter> Encode& operator()(Iter begin, Iter end) {
- std::for_each(begin, end, *this);
+ std::for_each(begin, end, serialize::ref(*this));
return *this;
}
@@ -125,7 +124,7 @@ struct Codec {
Decode& operator()(double& x) { return endian(x); }
template <class Iter> Decode& operator()(Iter begin, Iter end) {
- std::for_each(begin, end, *this);
+ std::for_each(begin, end, serialize::ref(*this));
return *this;
}
@@ -172,9 +171,10 @@ struct Codec {
Size& operator()(float x) { size += sizeof(x); return *this; }
Size& operator()(double x) { size += sizeof(x); return *this; }
- template <class Iter>
- Size& operator()(const Iter& a, const Iter& b) {
- size += (b-a)*sizeof(*a);
+ // FIXME aconway 2008-04-02: enable-if optimized (iter,iter) for
+ // iter on fixed-size type.
+ template <class Iter> Size& operator()(Iter begin, Iter end) {
+ std::for_each(begin, end, serialize::ref(*this));
return *this;
}
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Map.cpp b/qpid/cpp/src/qpid/amqp_0_10/Map.cpp
new file mode 100644
index 0000000000..1bfc2f6c85
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Map.cpp
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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 "Map.h"
+#include <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+MapValue::MapValue() : code(codeFor(uint8_t(0))), blob(in_place<uint8_t>(0)) {}
+
+MapValue::MapValue(const MapValue& x) : code(x.code), blob(x.blob) {}
+
+bool MapValue::operator==(const MapValue& x) const {
+ return code == x.code; // FIXME aconway 2008-04-01: incomplete
+}
+
+struct OstreamVisitor : public MapValue::Visitor<std::ostream&> {
+ std::ostream& out;
+ OstreamVisitor(std::ostream& o) : out(o) {}
+ template <class T> std::ostream& operator()(const T& t) {
+ return out << t;
+ }
+};
+
+std::ostream& operator<<(std::ostream& o, const MapValue& m) {
+ o << typeName(m.getCode()) << ":";
+ const_cast<MapValue&>(m).apply_visitor(OstreamVisitor(o));
+ return o;
+}
+
+std::ostream& operator<<(std::ostream& o, const Map::value_type& v) {
+ return o << v.first << "=" << v.second;
+}
+std::ostream& operator<<(std::ostream& o, const Map& map) {
+ o << "map[";
+ std::ostream_iterator<Map::value_type> i(o, " ");
+ std::copy(map.begin(), map.end(), i);
+ return o << "]";
+}
+
+uint32_t Map::contentSize() const {
+ uint32_t result=4; // uint32_t count
+ for (const_iterator i=begin(); i != end(); ++i) {
+ result += Codec::size(i->first);
+ result += Codec::size(i->second);
+ }
+ return result;
+}
+
+}} // namespace qpid::amqp_0_10
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Map.h b/qpid/cpp/src/qpid/amqp_0_10/Map.h
new file mode 100644
index 0000000000..ce8cd4bd08
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Map.h
@@ -0,0 +1,179 @@
+#ifndef QPID_AMQP_0_10_MAP_H
+#define QPID_AMQP_0_10_MAP_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/Exception.h"
+#include "qpid/amqp_0_10/built_in_types.h"
+#include "qpid/amqp_0_10/UnknownType.h"
+#include "qpid/amqp_0_10/CodeForType.h"
+#include "qpid/amqp_0_10/TypeForCode.h"
+#include "qpid/amqp_0_10/Codec.h"
+#include "qpid/framing/Blob.h"
+#include <map>
+#include <string>
+#include <iosfwd>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+class Map;
+
+class MapValue {
+ public:
+ struct BadTypeException : public Exception {};
+
+ template <class R> struct Visitor { typedef R result_type; };
+
+ MapValue();
+ MapValue(const MapValue& x);
+ template <class T> explicit MapValue(const T& t);
+ template <class T> MapValue& operator=(const T& t);
+
+ template <class T> T* get();
+ template <class T> const T* get() const;
+
+ template <class V> typename V::result_type apply_visitor(V&);
+ template <class V> typename V::result_type apply_visitor(const V&);
+
+ uint8_t getCode() const { return code; }
+
+ bool operator==(const MapValue&) const;
+
+ template <class S> void serialize(S& s) { s(code); s.split(*this); }
+ template <class S> void encode(S& s) const {
+ const_cast<MapValue*>(this)->apply_visitor(s);
+ }
+ template <class S> void decode(S& s) {
+ DecodeVisitor<S> dv(blob, s);
+ qpid::amqp_0_10::apply_visitor(dv, code);
+ }
+
+
+ private:
+ static const size_t SIZE=128 < sizeof(Vbin32) ? sizeof(Vbin32) : 128;
+ typedef framing::Blob<SIZE> Blob;
+
+ template <class V> struct VisitVisitor;
+ template <class T> struct GetVisitor;
+ template <class D> struct DecodeVisitor;
+
+ uint8_t code;
+ Blob blob;
+};
+
+class Map : public std::map<Str8, MapValue> {
+ public:
+ template <class S> void serialize(S& s) { s.split(*this); }
+ template <class S> void encode(S& s) const;
+
+ // FIXME aconway 2008-04-02: better separation for size calcultion
+ // support for static size, optimized iterator size calc.
+ void encode(Codec::Size& s) const { s.raw(0, contentSize() + 4/*size*/); }
+
+ template <class S> void decode(S& s);
+
+ private:
+ uint32_t contentSize() const;
+};
+
+std::ostream& operator<<(std::ostream&, const MapValue&);
+std::ostream& operator<<(std::ostream&, const Map::value_type&);
+std::ostream& operator<<(std::ostream&, const Map&);
+
+using framing::in_place;
+
+template <class T> MapValue::MapValue(const T& t) : code(codeFor(t)), blob(in_place<t>()) {}
+
+template <class T> MapValue& MapValue::operator=(const T& t) {
+ code=codeFor(t);
+ blob=t;
+ return *this;
+}
+
+template <class V> struct MapValue::VisitVisitor {
+ typedef typename V::result_type result_type;
+ V& visitor;
+ Blob& blob;
+ VisitVisitor(V& v, Blob& b) : visitor(v), blob(b) {}
+
+ template <class T> result_type operator()(T*) {
+ return visitor(*reinterpret_cast<T*>(blob.get()));
+ }
+};
+
+template <class V> typename V::result_type MapValue::apply_visitor(V& v) {
+ VisitVisitor<V> visitor(v, blob);
+ return qpid::amqp_0_10::apply_visitor(visitor, code);
+}
+
+template <class R> struct MapValue::GetVisitor {
+ typedef R* result_type;
+ const MapValue::Blob& blob;
+
+ GetVisitor(const MapValue::Blob& b) : blob(b) {}
+
+ R* operator()(R& r) { return &r; }
+ template <class T> R* operator()(T&) { return 0; }
+};
+
+template <class D> struct MapValue::DecodeVisitor {
+ typedef void result_type;
+ MapValue::Blob& blob;
+ D& decoder;
+ DecodeVisitor(Blob& b, D& d) : blob(b), decoder(d) {}
+
+ template <class T> void operator()(T*) {
+ T t;
+ decoder(t);
+ blob = t;
+ }
+};
+
+template <class T> T* MapValue::get() { return apply_visitor(GetVisitor<T>(blob)); }
+template <class T> const T* MapValue::get() const { return apply_visitor(GetVisitor<const T>()); }
+
+template <class V> typename V::result_type MapValue::apply_visitor(const V& v) {
+ return apply_visitor(const_cast<V&>(v));
+}
+
+template <class S> void Map::encode(S& s) const {
+ s(contentSize())(size()); // size, count
+ for (const_iterator i = begin(); i != end(); ++i)
+ s(i->first)(i->second); // key (type value)
+}
+
+template <class S> void Map::decode(S& s) {
+ uint32_t cSize, count;
+ // FIXME aconway 2008-04-02: runtime check that we consume exactly cSize.
+ s(cSize)(count);
+ for ( ; count > 0; --count) {
+ key_type k; MapValue v;
+ s(k)(v);
+ insert(value_type(k,v));
+ }
+}
+
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_MAP_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/SerializableString.h b/qpid/cpp/src/qpid/amqp_0_10/SerializableString.h
new file mode 100644
index 0000000000..485b7ca6a8
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/SerializableString.h
@@ -0,0 +1,62 @@
+#ifndef QPID_AMQP_0_10_SERIALIZABLESTRING_H
+#define QPID_AMQP_0_10_SERIALIZABLESTRING_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 {
+
+/** Template for length-prefixed strings/arrays.
+ * Unique parameter allows creation of distinct SerializableString
+ * types with the smae T/SizeType
+ */
+template <class T, class SizeType, int Unique=0>
+struct SerializableString : public std::basic_string<T> {
+ SerializableString() {}
+ template <class U> SerializableString(const U& u) : std::basic_string<T>(u) {}
+ template <class I> SerializableString(const I& i, const I& j) : std::basic_string<T>(i,j) {}
+
+ using std::basic_string<T>::operator=;
+
+ template <class S> void serialize(S& s) { s.split(*this); }
+
+ template <class S> void encode(S& s) const {
+ s(SizeType(this->size()))(this->begin(), this->end());
+ }
+
+ template <class S> void decode(S& s) {
+ SizeType newSize;
+ s(newSize);
+ this->resize(newSize);
+ s(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?
+}
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_SERIALIZABLESTRING_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp b/qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp
new file mode 100644
index 0000000000..844891d732
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/UnknownType.cpp
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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 "UnknownType.h"
+#include <boost/range/iterator_range.hpp>
+#include <ostream>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+UnknownType::Width UnknownType::WidthTable[16] = {
+ { 1, 0 },
+ { 2, 0 },
+ { 4, 0 },
+ { 8, 0 },
+ { 16, 0 },
+ { 32, 0 },
+ { 64, 0 },
+ { 128, 0 },
+ { 0, 1 },
+ { 0, 2 },
+ { 0, 4 },
+ { -1, -1 }, // Invalid
+ { 5, 0 },
+ { 9, 0 },
+ { -1, -1 }, // Invalid
+ { 0, 0 }
+};
+
+int UnknownType::fixed() const { return WidthTable[code>>4].fixed; }
+int UnknownType::variable() const { return WidthTable[code>>4].variable; }
+UnknownType::UnknownType(uint8_t c) : code(c) { data.resize(fixed()); }
+
+std::ostream& operator<<(std::ostream& o, const UnknownType& u) {
+ return o << boost::make_iterator_range(u.begin(), u.end()) << std::endl;
+}
+
+}} // namespace qpid::amqp_0_10
+
diff --git a/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h b/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h
new file mode 100644
index 0000000000..0b4ec550d1
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h
@@ -0,0 +1,86 @@
+#ifndef QPID_AMQP_0_10_UNKNOWNTYPE_H
+#define QPID_AMQP_0_10_UNKNOWNTYPE_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 <vector>
+#include <iosfwd>
+#include <stdint.h>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/** Encode/decode an unknown type based on typecode. */
+class UnknownType {
+ public:
+ UnknownType(uint8_t code=0);
+ uint8_t getCode() const { return code; }
+ /** Size of fixed type or 0 if not fixed/0-length. -1 invalid */
+ int fixed() const;
+ /** Bytes in size tyep for variable width. -1 invalid */
+ int variable() const;
+
+ typedef std::vector<char>::const_iterator const_iterator;
+ const_iterator begin() const { return data.begin(); }
+ const_iterator end() const { return data.end(); }
+
+ template <class S> void serialize(S& s) { s.split(*this); }
+ template <class S> void encode(S& s) const;
+ template <class S> void decode(S& s);
+
+ private:
+ uint8_t code;
+ struct Width { int fixed; int variable; };
+ static Width WidthTable[16];
+
+ std::vector<char> data;
+};
+
+template <class S> void UnknownType::encode(S& s) const {
+ switch (variable()) {
+ case 0: break;
+ case 1: s(uint8_t(data.size())); break;
+ case 2: s(uint16_t(data.size())); break;
+ case 4: s(uint32_t(data.size())); break;
+ }
+ s(data.begin(), data.end());
+}
+
+template <class S> void UnknownType::decode(S& s) {
+ uint32_t s8;
+ uint32_t s16;
+ uint32_t s32;
+ switch (variable()) {
+ case 0: break;
+ case 1: s(s8); data.resize(s8); break;
+ case 2: s(s16); data.resize(s16); break;
+ case 4: s(s32); data.resize(s32); break;
+ }
+ s(data.begin(), data.end());
+}
+
+inline uint8_t codeFor(const UnknownType& u) { return u.getCode(); }
+
+std::ostream& operator<<(std::ostream&, const UnknownType&);
+
+}} // namespace qpid::amqp_0_10
+
+#endif /*!QPID_AMQP_0_10_UNKNOWNTYPE_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h b/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h
index 5b00e933a9..b55f9baf42 100644
--- a/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h
+++ b/qpid/cpp/src/qpid/amqp_0_10/built_in_types.h
@@ -22,14 +22,16 @@
*/
#include "Decimal.h"
+#include "SerializableString.h"
#include "qpid/framing/SequenceNumber.h"
#include "qpid/framing/Uuid.h"
#include "qpid/sys/Time.h"
#include <boost/array.hpp>
-#include <stdint.h>
+#include <boost/range/iterator_range.hpp>
#include <string>
#include <ostream>
#include <vector>
+#include <stdint.h>
/**@file Mapping from built-in AMQP types to C++ types */
@@ -37,26 +39,47 @@ namespace qpid {
namespace amqp_0_10 {
// Fixed size types
-typedef void Void;
+struct EmptyType { template <class S> void serialize(S&) {} };
+inline std::ostream& operator<<(std::ostream& o, const EmptyType&) { return o; }
+
+struct Void : public EmptyType {};
+struct Bit : public EmptyType {};
-typedef bool Bit;
typedef bool Boolean;
typedef char Char;
typedef int8_t Int8;
typedef int16_t Int16;
typedef int32_t Int32;
typedef int64_t Int64;
-typedef uint8_t Bin8;
typedef uint8_t Uint8;
typedef uint16_t Uint16;
-typedef uint32_t CharUtf32 ;
typedef uint32_t Uint32;
typedef uint64_t Uint64;
+// A struct to be distinct from the other 32 bit integrals.
+struct CharUtf32 {
+ uint32_t value;
+ CharUtf32(uint32_t n=0) : value(n) {}
+ operator uint32_t&() { return value; }
+ operator const uint32_t&() const { return value; }
+ template <class S> void serialize(S& s) { s(value); }
+};
+
template <size_t N> struct Bin : public boost::array<char, N> {
template <class S> void serialize(S& s) { s.raw(this->begin(), this->size()); }
};
-
+
+template <size_t N> std::ostream& operator<<(std::ostream& o, const Bin<N>& b) {
+ return o << boost::make_iterator_range(b.begin(), b.end());
+}
+
+template <> struct Bin<1> : public boost::array<char, 1> {
+ Bin(char c=0) { this->front() = c; }
+ operator char() { return this->front(); }
+ template <class S> void serialize(S& s) { s.raw(data(), size()); }
+};
+
+typedef Bin<1> Bin8;
typedef Bin<128> Bin1024;
typedef Bin<16> Bin128;
typedef Bin<2> Bin16;
@@ -76,58 +99,37 @@ typedef sys::AbsTime Datetime;
typedef Decimal<Uint8, Int32> Dec32;
typedef Decimal<Uint8, Int64> Dec64;
-
-/** Template for length-prefixed strings/arrays. */
-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.split(*this); }
-
- template <class S> void encode(S& s) const {
- s(SizeType(this->size()))(this->begin(), this->end());
- }
-
- template <class S> void decode(S& s) {
- SizeType newSize;
- s(newSize);
- this->resize(newSize);
- s(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 SerializableString<Uint8, Uint8> Vbin8;
-typedef SerializableString<char, Uint8> Str8Latin;
+typedef SerializableString<char, Uint8, 1> Str8Latin;
typedef SerializableString<char, Uint8> Str8;
typedef SerializableString<Uint16, Uint8> Str8Utf16;
typedef SerializableString<Uint8, Uint16> Vbin16;
-typedef SerializableString<char, Uint16> Str16Latin;
+typedef SerializableString<char, Uint16, 1> Str16Latin;
typedef SerializableString<char, Uint16> Str16;
typedef SerializableString<Uint16, Uint16> Str16Utf16;
typedef SerializableString<Uint8, Uint32> Vbin32;
+// Forward declare class types.
+class Map;
+
// FIXME aconway 2008-02-26: Unimplemented types:
-template <class T> struct Array : public std::vector<T> { template <class S> void serialize(S&) {} };
+template <class T> struct ArrayDomain : public std::vector<T> {
+ template <class S> void serialize(S&) {}
+};
+struct Array { 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&) {} };
// FIXME aconway 2008-03-10: dummy ostream operators
-template <class T> std::ostream& operator<<(std::ostream& o, const Array<T>&) { return o; }
+template <class T> std::ostream& operator<<(std::ostream& o, const ArrayDomain<T>&) { return o; }
+inline std::ostream& operator<<(std::ostream& o, const Array&) { return o; }
inline std::ostream& operator<<(std::ostream& o, const ByteRanges&) { return o; }
-inline std::ostream& operator<<(std::ostream& o, const Map&) { return o; }
inline std::ostream& operator<<(std::ostream& o, const SequenceSet&) { return o; }
inline std::ostream& operator<<(std::ostream& o, const List&) { return o; }
inline std::ostream& operator<<(std::ostream& o, const Struct32&) { return o; }
diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am
index ca25ced5e0..ae47241e67 100644
--- a/qpid/cpp/src/tests/Makefile.am
+++ b/qpid/cpp/src/tests/Makefile.am
@@ -41,7 +41,8 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \
SequenceSet.cpp \
serialize.cpp \
ProxyTemplate.cpp apply.cpp BoundedIterator.cpp \
- IncompleteMessageList.cpp
+ IncompleteMessageList.cpp \
+ amqp_0_10/Map.cpp
check_LTLIBRARIES += libshlibtest.la
libshlibtest_la_LDFLAGS = -module -rpath $(abs_builddir)
diff --git a/qpid/cpp/src/tests/amqp_0_10/Map.cpp b/qpid/cpp/src/tests/amqp_0_10/Map.cpp
new file mode 100644
index 0000000000..958470f6d7
--- /dev/null
+++ b/qpid/cpp/src/tests/amqp_0_10/Map.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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/Map.h"
+#include "qpid/amqp_0_10/Codec.h"
+#include <iostream>
+
+using namespace qpid::amqp_0_10;
+using namespace std;
+
+namespace std {
+// Dummy += for back inserters so we can use them with the decoder.
+template <class C> back_insert_iterator<C>& operator+=(back_insert_iterator<C>& bi, size_t) { return bi; }
+}
+
+QPID_AUTO_TEST_SUITE(MapTestSuite)
+
+ BOOST_AUTO_TEST_CASE(testGetSet) {
+ MapValue v;
+ v = Str8("foo");
+ BOOST_CHECK(v.get<Str8>());
+ BOOST_CHECK(!v.get<uint8_t>());
+ BOOST_CHECK_EQUAL(*v.get<Str8>(), "foo");
+
+ v = uint8_t(42);
+ BOOST_CHECK(!v.get<Str8>());
+ BOOST_CHECK(v.get<uint8_t>());
+ BOOST_CHECK_EQUAL(*v.get<uint8_t>(), 42);
+
+ v = uint16_t(12);
+ BOOST_CHECK(v.get<uint16_t>());
+ BOOST_CHECK_EQUAL(*v.get<uint16_t>(), 12);
+}
+
+template <class R> struct TestVisitor : public MapValue::Visitor<R> {
+ template <class T> R operator()(const T&) const { throw MapValue::BadTypeException(); }
+ R operator()(const R& r) const { return r; }
+};
+
+BOOST_AUTO_TEST_CASE(testVisit) {
+ MapValue v;
+ v = Str8("foo");
+ BOOST_CHECK_EQUAL(v.apply_visitor(TestVisitor<Str8>()), "foo");
+ v = Uint16(42);
+ BOOST_CHECK_EQUAL(v.apply_visitor(TestVisitor<Uint16>()), 42);
+ try {
+ v.apply_visitor(TestVisitor<bool>());
+ BOOST_FAIL("Expecting exception");
+ }
+ catch(const MapValue::BadTypeException&) {}
+}
+
+
+BOOST_AUTO_TEST_CASE(testEncodeMapValue) {
+ MapValue mv;
+ std::string data;
+ mv = Str8("hello");
+ Codec::encode(back_inserter(data))(mv);
+ BOOST_CHECK_EQUAL(data.size(), Codec::size(mv));
+ MapValue mv2;
+ Codec::decode(data.begin())(mv2);
+ BOOST_CHECK_EQUAL(mv2.getCode(), 0x85);
+ BOOST_REQUIRE(mv2.get<Str8>());
+ BOOST_CHECK_EQUAL(*mv2.get<Str8>(), "hello");
+}
+
+BOOST_AUTO_TEST_CASE(testEncode) {
+ Map map;
+ std::string data;
+ map["A"] = true;
+ map["b"] = Str8("hello");
+ Codec::encode(back_inserter(data))(map);
+ Map map2;
+ Codec::decode(data.begin())(map2);
+ BOOST_CHECK_EQUAL(map.size(), 2u);
+ BOOST_CHECK(map["A"].get<bool>());
+ BOOST_CHECK_EQUAL(*map["b"].get<Str8>(), "hello");
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/serialize.cpp b/qpid/cpp/src/tests/serialize.cpp
index 228a4b6e3a..da71917cbd 100644
--- a/qpid/cpp/src/tests/serialize.cpp
+++ b/qpid/cpp/src/tests/serialize.cpp
@@ -25,6 +25,7 @@
#include "qpid/amqp_0_10/specification.h"
#include "qpid/amqp_0_10/ControlHolder.h"
#include "qpid/amqp_0_10/Frame.h"
+#include "qpid/amqp_0_10/Map.h"
#include <boost/test/test_case_template.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
@@ -76,16 +77,13 @@ template <class A, class B> struct concat2 { typedef typename mpl::copy<B, typen
template <class A, class B, class C> struct concat3 { typedef typename concat2<A, typename concat2<B, C>::type>::type type; };
template <class A, class B, class C, class D> struct concat4 { typedef typename concat2<A, typename concat3<B, C, D>::type>::type type; };
-typedef mpl::vector<Bit, Boolean, Char, Int32, Int64, Int8, Uint16, CharUtf32, Uint32, Uint64, Bin8, Uint8>::type IntegralTypes;
+typedef mpl::vector<Boolean, Char, Int32, Int64, Int8, Uint16, CharUtf32, Uint32, Uint64, Bin8, Uint8>::type IntegralTypes;
typedef mpl::vector<Bin1024, Bin128, Bin16, Bin256, Bin32, Bin40, Bin512, Bin64, Bin72>::type BinTypes;
-// FIXME aconway 2008-03-07: float encoding
typedef mpl::vector<Double, Float>::type FloatTypes;
typedef mpl::vector<SequenceNo, Uuid, Datetime, Dec32, Dec64> FixedSizeClassTypes;
-typedef mpl::vector<Vbin8, Str8Latin, Str8, Str8Utf16, Vbin16, Str16Latin, Str16, Str16Utf16, Vbin32> VariableSizeTypes;
+typedef mpl::vector<Map, Vbin8, Str8Latin, Str8, Str8Utf16, Vbin16, Str16Latin, Str16, Str16Utf16, Vbin32> VariableSizeTypes;
-
-// FIXME aconway 2008-03-07: float encoding
-typedef concat3<IntegralTypes, BinTypes, /*FloatTypes, */ FixedSizeClassTypes>::type FixedSizeTypes;
+typedef concat4<IntegralTypes, BinTypes, FloatTypes, FixedSizeClassTypes>::type FixedSizeTypes;
typedef concat2<FixedSizeTypes, VariableSizeTypes>::type AllTypes;
// TODO aconway 2008-02-20: should test 64 bit integrals for order also.
@@ -107,19 +105,22 @@ BOOST_AUTO_TEST_CASE(testNetworkByteOrder) {
// Assign test values to the various types.
void testValue(bool& b) { b = true; }
+void testValue(Bit&) { }
template <class T> typename boost::enable_if<boost::is_arithmetic<T> >::type testValue(T& n) { n=42; }
+void testValue(CharUtf32& c) { c = 43; }
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=0x1122; }
void testValue(SequenceNo& s) { s = 42; }
template <size_t N> void testValue(Bin<N>& a) { a.assign(42); }
-template <class T, class S> void testValue(SerializableString<T, S>& s) {
+template <class T, class S, int Unique> void testValue(SerializableString<T, S, Unique>& 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"; }
+void testValue(Map& m) { m["s"] = Str8("foobar"); m["b"] = true; m["c"] = uint16_t(42); }
//typedef mpl::vector<Str8, Str16>::type TestTypes;
BOOST_AUTO_TEST_CASE_TEMPLATE(testEncodeDecode, T, AllTypes)