diff options
| author | Alan Conway <aconway@apache.org> | 2008-04-08 19:53:07 +0000 |
|---|---|---|
| committer | Alan Conway <aconway@apache.org> | 2008-04-08 19:53:07 +0000 |
| commit | 7216a7c6837ff7d43b3ee6e2446d9938e864a74e (patch) | |
| tree | 5eb31f048fba698acd71c1c6615012e3c45a0d62 /qpid/cpp | |
| parent | c89fe1d8ef23cb6f3f2c60623dfdac08216baa06 (diff) | |
| download | qpid-python-7216a7c6837ff7d43b3ee6e2446d9938e864a74e.tar.gz | |
Summary: added 0-10 Array encoding and decoding.
rubygen/0-10/allsegmenttypes.rb: test header,body and each command and control type.
rubygen/0-10/specification.rb: enable packed encoding.
src/qpid/amqp_0_10/Array.h: Implemented array and array domains.
src/qpid/amqp_0_10/Codec.h: enable litte-endian encoding for pack bits
src/qpid/amqp_0_10/Packer.h: use litte-endian encoding for pack bits
src/qpid/amqp_0_10/Unit.cpp, .h: setting flags, fix op <<.
src/qpid/amqp_0_10/complex_types.cpp, .h: added op <<
src/qpid/framing/Blob.h: copy-object template constructor.
src/tests/amqp_0_10/serialize.cpp:
- test Array
Minor adjustments for new Array.h:
src/qpid/amqp_0_10/Map.cpp
src/qpid/amqp_0_10/Map.h
src/qpid/amqp_0_10/UnknownType.h
src/qpid/amqp_0_10/built_in_types.h
src/qpid/amqp_0_10/Body.h
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@646054 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/cpp')
22 files changed, 419 insertions, 84 deletions
diff --git a/qpid/cpp/rubygen/0-10/allsegmenttypes.rb b/qpid/cpp/rubygen/0-10/allsegmenttypes.rb new file mode 100755 index 0000000000..c4c4095e02 --- /dev/null +++ b/qpid/cpp/rubygen/0-10/allsegmenttypes.rb @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +$: << ".." # Include .. in load path +require 'cppgen' + +class GenAllSegmentTypes < CppGen + def initialize(outdir, amqp) + super(outdir, amqp) + end + + def generate + h_file("tests/allSegmentTypes.h") { + include "qpid/amqp_0_10/specification.h" + include "qpid/amqp_0_10/Header.h" + include "qpid/amqp_0_10/Body.h" + genl + genl "using namespace qpid::amqp_0_10;" + genl + scope("template <class Op> size_t allSegmentTypes(Op& op) {"){ + genl "op(Header());" + genl "op(Body());" + n = 2; + @amqp.classes.each { |c| + c.commands.each { |s| genl "op(CommandHolder(#{c.nsname}::#{s.classname}()));" } + c.controls.each { |s| genl "op(ControlHolder(#{c.nsname}::#{s.classname}()));" } + n += 2 + } + genl "return #{n};" + } + } + end +end + +GenAllSegmentTypes.new($outdir, $amqp).generate(); + diff --git a/qpid/cpp/rubygen/0-10/specification.rb b/qpid/cpp/rubygen/0-10/specification.rb index d8c5378538..54d39de9b4 100755 --- a/qpid/cpp/rubygen/0-10/specification.rb +++ b/qpid/cpp/rubygen/0-10/specification.rb @@ -64,11 +64,11 @@ class Specification < CppGen genl yield if block } + genl "inline Packer<#{x.classname}> serializable(#{x.classname}& x) { return Packer<#{x.classname}>(x); }" unless x.respond_to? :pack and x.pack == "0" genl "std::ostream& operator << (std::ostream&, const #{x.classname}&);" genl "bool operator==(const #{x.classname}&, const #{x.classname}&);" end - # FIXME aconway 2008-03-10: packing, coding def action_struct_cpp(x) genl genl "const char* #{x.classname}::NAME=\"#{x.fqname}\";" @@ -89,7 +89,7 @@ class Specification < CppGen scope("std::ostream& operator << (std::ostream& o, const #{x.classname}&#{"x" unless x.fields.empty?}) {") { genl "o << \"[#{x.fqname}\";"; x.fields.each{ |f| genl "o << \" #{f.name}=\" << x.#{f.cppname};" } - genl "o << \"];\";" + genl "o << \"]\";" genl "return o;" } end @@ -151,8 +151,8 @@ class Specification < CppGen def gen_specification() h_file("#{@dir}/specification") { include "#{@dir}/specification_fwd" - include "#{@dir}/complex_types" - include "#{@dir}/Map.h" + include "#{@dir}/all_built_in_types" + include "#{@dir}/Packer.h" include "<boost/call_traits.hpp>" include "<iosfwd>" genl "using boost::call_traits;" @@ -271,7 +271,7 @@ class Specification < CppGen 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 "template <class T> explicit #{name}(const T& t) : #{holder_base}(t) {}" genl "using #{holder_base}::operator=;" genl "void set(uint8_t classCode, uint8_t code);" } @@ -281,7 +281,8 @@ class Specification < CppGen } cpp_file("#{@dir}/#{name}") { - include "#{@dir}/#{name}" + include "#{name}" + include "exceptions.h" namespace(@ns) { genl "using framing::in_place;" genl @@ -291,7 +292,7 @@ class Specification < CppGen subs.each { |s| genl "case 0x#{s.full_code.to_s(16)}: *this=in_place<#{s.fqclassname}>(); break;" } - genl "default: assert(0);" + genl "default: throw CommandInvalidException(QPID_MSG(\"Invalid class-#{base.downcase} key \" << std::hex << key));" }} genl genl "std::ostream& operator<<(std::ostream& o, const #{name}& h) { return h.get() ? (o << *h.get()) : (o << \"<empty #{name}>\"); }" diff --git a/qpid/cpp/rubygen/0-10/typecode.rb b/qpid/cpp/rubygen/0-10/typecode.rb index 459516e51c..e36b92c07c 100755 --- a/qpid/cpp/rubygen/0-10/typecode.rb +++ b/qpid/cpp/rubygen/0-10/typecode.rb @@ -13,6 +13,7 @@ class TypeCode < CppGen def type_for_code_h() h_file("#{@dir}/TypeForCode") { + include "#{@dir}/built_in_types.h" include "#{@dir}/UnknownType.h" namespace(@ns) { genl @@ -61,17 +62,30 @@ class TypeCode < CppGen end def code_for_type_h() - h_file("#{@dir}/CodeForType") { + name="#{@dir}/CodeForType" + h_file(name) { + include "#{@dir}/built_in_types.h" + 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 "template <> struct CodeForType<#{t.typename}> { static const uint8_t value; };" } genl genl "template <class T> uint8_t codeFor(const T&) { return CodeForType<T>::value; }" - }} + } + } + + cpp_file(name) { + include name + namespace(@ns) { + @types.each { |t| + genl "const uint8_t CodeForType<#{t.typename}>::value=#{t.code};" + } + } + } end def generate diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am index 991d9bc4c5..eaf8119405 100644 --- a/qpid/cpp/src/Makefile.am +++ b/qpid/cpp/src/Makefile.am @@ -104,9 +104,12 @@ libqpidcommon_la_SOURCES = \ $(rgen_common_cpp) \ $(platform_src) \ qpid/amqp_0_10/apply.h \ + qpid/amqp_0_10/all_built_in_types.h \ 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/Array.h \ + qpid/amqp_0_10/Array.cpp \ qpid/amqp_0_10/Body.h \ qpid/amqp_0_10/Header.h \ qpid/amqp_0_10/FrameHeader.h \ diff --git a/qpid/cpp/src/qpid/amqp_0_10/Array.cpp b/qpid/cpp/src/qpid/amqp_0_10/Array.cpp new file mode 100644 index 0000000000..380e0f1f36 --- /dev/null +++ b/qpid/cpp/src/qpid/amqp_0_10/Array.cpp @@ -0,0 +1,34 @@ +/* + * + * 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 "Array.h" + +namespace qpid { +namespace amqp_0_10 { + +std::ostream& operator<<(std::ostream& o, const Array& a) { + std::ostream_iterator<UnknownType> i(o, " "); + o << "Array<" << typeName(a.getType()) << "["; + std::copy(a.begin(), a.end(), i); + o << "]"; + return o; +} + +}} // namespace qpid::amqp_0_10 diff --git a/qpid/cpp/src/qpid/amqp_0_10/Array.h b/qpid/cpp/src/qpid/amqp_0_10/Array.h new file mode 100644 index 0000000000..8061a99b43 --- /dev/null +++ b/qpid/cpp/src/qpid/amqp_0_10/Array.h @@ -0,0 +1,120 @@ +#ifndef QPID_AMQP_0_10_ARRAY_H +#define QPID_AMQP_0_10_ARRAY_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/amqp_0_10/TypeForCode.h" +#include "qpid/amqp_0_10/CodeForType.h" +#include "qpid/amqp_0_10/UnknownType.h" +#include "qpid/amqp_0_10/exceptions.h" +#include "qpid/amqp_0_10/Codec.h" +#include <vector> +#include <ostream> + +namespace qpid { +namespace amqp_0_10 { + +template <class T> class ArrayDomain : public std::vector<T> { + public: + template <class S> void serialize(S& s) { s.split(*this); s(this->begin(), this->end()); } + + template <class S> void encode(S& s) const { + s(contentSize())(CodeForType<T>::value)(uint32_t(this->size())); + } + + void encode(Codec::Size& s) const { s.raw(0, contentSize() + 4/*size*/); } + + template <class S> void decode(S& s) { + uint32_t size; uint8_t type; uint32_t count; + s(size); + s.setLimit(size); + s(type); + if (type != CodeForType<T>::value) + throw InvalidArgumentException(QPID_MSG("Array domain expected type " << CodeForType<T>::value << " but found " << type)); + s(count); + this->resize(count); + } + + private: + uint32_t contentSize() const { + return Codec::size(this->begin(), this->end()) + sizeof(uint32_t) /*count*/ + sizeof(uint8_t) /*type*/; + } +}; + +template <class T> +std::ostream& operator<<(std::ostream& o, const ArrayDomain<T>& ad) { + std::ostream_iterator<T> i(o, " "); + o << "Array<" << typeName(CodeForType<T>::value) << ">["; + std::copy(ad.begin(), ad.end(), i); + o << "]"; + return o; +} + +/** A non-domain array is represented as and array of UnknownType. + * Special case templat. + */ +template<> class ArrayDomain<UnknownType> : public std::vector<UnknownType> { + public: + ArrayDomain(uint8_t type_=0) : type(type_) {} + + template <class S> void serialize(S& s) { s.split(*this); s(this->begin(), this->end()); } + + template <class S> void encode(S& s) const { + s(contentSize())(type)(uint32_t(this->size())); + } + + void encode(Codec::Size& s) const { s.raw(0, contentSize() + 4/*size*/); } + + template <class S> void decode(S& s) { + uint32_t size; uint32_t count; + s(size); + s.setLimit(size); + s(type)(count); + this->clear(); + this->resize(count, UnknownType(type)); + } + + uint8_t getType() const { return type; } + + private: + uint32_t contentSize() const { + return Codec::size(this->begin(), this->end()) + sizeof(uint32_t) /*count*/ + sizeof(uint8_t) /*type*/; + } + uint8_t type; +}; + +std::ostream& operator<<(std::ostream& o, const Array& a); + +// FIXME aconway 2008-04-08: hack to supress encoding of +// command-fragments and in-doubt as there is a problem with the spec +// (command-fragments does not have a one byte type code.) +namespace session { class CommandFragment; } +namespace dtx { class Xid; } + +template <> struct ArrayDomain<session::CommandFragment> : public Void {}; +template <> struct ArrayDomain<dtx::Xid> : public Void {}; +inline std::ostream& operator<<(std::ostream& o, const ArrayDomain<session::CommandFragment>&) { return o; } +inline std::ostream& operator<<(std::ostream& o, const ArrayDomain<dtx::Xid>&) { return o; } + +}} // namespace qpid::amqp_0_10 + +#endif /*!QPID_AMQP_0_10_ARRAY_H*/ diff --git a/qpid/cpp/src/qpid/amqp_0_10/Body.h b/qpid/cpp/src/qpid/amqp_0_10/Body.h index a2192503b8..c96931551c 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Body.h +++ b/qpid/cpp/src/qpid/amqp_0_10/Body.h @@ -31,7 +31,7 @@ namespace amqp_0_10 { class Body { public: Body() {} - Body(size_t size_) : str('\0', size_) {} + Body(size_t size_) : str(size_, '\0') {} Body(const char* data_, size_t size_) : str(data_, size_) {} size_t size() const { return str.size(); }; @@ -47,7 +47,7 @@ class Body { }; inline std::ostream& operator<<(std::ostream& o, const Body& b) { - return o << b.str.substr(16) << "... (" << b.size() << ")"; + return o << b.str.substr(0, 16) << "... (" << b.size() << ")"; } }} // namespace qpid::amqp_0_10 diff --git a/qpid/cpp/src/qpid/amqp_0_10/Codec.h b/qpid/cpp/src/qpid/amqp_0_10/Codec.h index c4909e7cbd..5cad5cf4ed 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Codec.h +++ b/qpid/cpp/src/qpid/amqp_0_10/Codec.h @@ -34,13 +34,17 @@ namespace qpid { namespace amqp_0_10 { -#ifdef BOOST_LITTLE_ENDIAN -template <class T> void endianize(T& t) { +template <class T> void reverse(T& t) { char*p =reinterpret_cast<char*>(&t); std::reverse(p, p+sizeof(T)); } + +#ifdef BOOST_LITTLE_ENDIAN +template <class T> void bigEndian(T& t) { reverse(t); } +template <class T> void littleEndian(T&) {} #else -template <class T> void endianize(T&) {} +template <class T> void littleEndian(T& t) { reverse(t); } +template <class T> void bigEndian(T&) {} #endif /** @@ -66,16 +70,16 @@ struct Codec { Encoder& operator()(int8_t x) { raw(x); return *this; } Encoder& operator()(uint8_t x) { raw(x); return *this; } - Encoder& operator()(int16_t x) { return endian(x); } - Encoder& operator()(int32_t x) { return endian(x); } - Encoder& operator()(int64_t x) { return endian(x); } + Encoder& operator()(int16_t x) { return networkByteOrder(x); } + Encoder& operator()(int32_t x) { return networkByteOrder(x); } + Encoder& operator()(int64_t x) { return networkByteOrder(x); } - Encoder& operator()(uint16_t x) { return endian(x); } - Encoder& operator()(uint32_t x) { return endian(x); } - Encoder& operator()(uint64_t x) { return endian(x); } + Encoder& operator()(uint16_t x) { return networkByteOrder(x); } + Encoder& operator()(uint32_t x) { return networkByteOrder(x); } + Encoder& operator()(uint64_t x) { return networkByteOrder(x); } - Encoder& operator()(float x) { return endian(x); } - Encoder& operator()(double x) { return endian(x); } + Encoder& operator()(float x) { return networkByteOrder(x); } + Encoder& operator()(double x) { return networkByteOrder(x); } void raw(const void* p, size_t n) { this->addBytes(n); @@ -84,12 +88,16 @@ struct Codec { void raw(char b) { this->addBytes(1); *out++=b; } + template <class T> Encoder& littleEnd(T x) { + littleEndian(x); raw(&x, sizeof(x)); return *this; + } + OutIter pos() const { return out; } private: - template <class T> Encoder& endian(T x) { - endianize(x); raw(&x, sizeof(x)); return *this; + template <class T> Encoder& networkByteOrder(T x) { + bigEndian(x); raw(&x, sizeof(x)); return *this; } OutIter out; @@ -114,16 +122,16 @@ struct Codec { Decoder& operator()(int8_t& x) { raw((char&)x); return *this; } Decoder& operator()(uint8_t& x) { raw((char&)x); return *this; } - Decoder& operator()(int16_t& x) { return endian(x); } - Decoder& operator()(int32_t& x) { return endian(x); } - Decoder& operator()(int64_t& x) { return endian(x); } + Decoder& operator()(int16_t& x) { return networkByteOrder(x); } + Decoder& operator()(int32_t& x) { return networkByteOrder(x); } + Decoder& operator()(int64_t& x) { return networkByteOrder(x); } - Decoder& operator()(uint16_t& x) { return endian(x); } - Decoder& operator()(uint32_t& x) { return endian(x); } - Decoder& operator()(uint64_t& x) { return endian(x); } + Decoder& operator()(uint16_t& x) { return networkByteOrder(x); } + Decoder& operator()(uint32_t& x) { return networkByteOrder(x); } + Decoder& operator()(uint64_t& x) { return networkByteOrder(x); } - Decoder& operator()(float& x) { return endian(x); } - Decoder& operator()(double& x) { return endian(x); } + Decoder& operator()(float& x) { return networkByteOrder(x); } + Decoder& operator()(double& x) { return networkByteOrder(x); } void raw(void *p, size_t n) { this->addBytes(n); @@ -133,12 +141,16 @@ struct Codec { void raw(char &b) { this->addBytes(1); b=*in++; } + template <class T> Decoder& littleEnd(T& x) { + raw(&x, sizeof(x)); littleEndian(x); return *this; + } + InIter pos() const { return in; } private: - template <class T> Decoder& endian(T& x) { - raw(&x, sizeof(x)); endianize(x); return *this; + template <class T> Decoder& networkByteOrder(T& x) { + raw(&x, sizeof(x)); bigEndian(x); return *this; } InIter in; @@ -177,6 +189,8 @@ struct Codec { void raw(const void*, size_t n){ size += n; } + template <class T> Size& littleEnd(T) { size+= sizeof(T); return *this; } + private: size_t size; }; @@ -191,6 +205,7 @@ struct Codec { } template <class T> static size_t size(const T& x) { return Size()(x); } + template <class Iter> static size_t size(const Iter& a, const Iter& z) { return Size()(a,z); } }; }} // namespace qpid::amqp_0_10 diff --git a/qpid/cpp/src/qpid/amqp_0_10/Map.cpp b/qpid/cpp/src/qpid/amqp_0_10/Map.cpp index 308e280e45..2d32466c3f 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Map.cpp +++ b/qpid/cpp/src/qpid/amqp_0_10/Map.cpp @@ -18,7 +18,7 @@ * under the License. * */ -#include "Map.h" +#include "all_built_in_types.h" #include <ostream> namespace qpid { diff --git a/qpid/cpp/src/qpid/amqp_0_10/Map.h b/qpid/cpp/src/qpid/amqp_0_10/Map.h index c1580bf4f3..d63eb0cc4e 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Map.h +++ b/qpid/cpp/src/qpid/amqp_0_10/Map.h @@ -14,7 +14,7 @@ * 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 + * software distributed under the License is distributed on ang * "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 diff --git a/qpid/cpp/src/qpid/amqp_0_10/Packer.h b/qpid/cpp/src/qpid/amqp_0_10/Packer.h index ebb0488525..8943dc4c51 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Packer.h +++ b/qpid/cpp/src/qpid/amqp_0_10/Packer.h @@ -126,13 +126,13 @@ template <class T> class Packer template <class S> void encode(S& s) const { Bits bits = packBits(data); - s(bits); + s.littleEnd(bits); data.serialize(s); } template <class S> void decode(S& s) { Bits bits; - s(bits); + s.littleEnd(bits); PackedDecoder<S, Bits> decode(s, bits); data.serialize(decode); } diff --git a/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp b/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp index 6b0a2e542d..1fa6b2e085 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp +++ b/qpid/cpp/src/qpid/amqp_0_10/Unit.cpp @@ -24,7 +24,7 @@ namespace qpid { namespace amqp_0_10 { -void Unit::setVariant() { +void Unit::updateVariant() { switch (header.getType()) { case CONTROL: variant=ControlHolder(); break; case COMMAND: variant=CommandHolder(); @@ -40,8 +40,16 @@ struct GetTypeVisitor : public boost::static_visitor<SegmentType> { SegmentType operator()(const Body&) const { return BODY; } }; -void Unit::setHeader(uint8_t flags) { - header.setFlags(flags); +struct GetFlagsVisitor : public boost::static_visitor<uint8_t> { + uint8_t operator()(const CommandHolder& ) const { return FIRST_FRAME|LAST_FRAME|FIRST_SEGMENT; } + uint8_t operator()(const ControlHolder& ) const { return FIRST_FRAME|LAST_FRAME|FIRST_SEGMENT; } + uint8_t operator()(const Header& ) const { return FIRST_FRAME|LAST_FRAME; } + uint8_t operator()(const Body&) const { return 0; } +}; + +void Unit::updateHeader(uint8_t flags) { + GetFlagsVisitor flagger; + header.setFlags(flags | variant.apply_visitor(flagger)); GetTypeVisitor getter; header.setType(variant.apply_visitor(getter)); header.setDataSize(Codec::size(*this)); @@ -50,7 +58,7 @@ void Unit::setHeader(uint8_t flags) { } std::ostream& operator<<(std::ostream& o, const Unit& u) { - return o << u.getHeader() << " " << u.getVariant(); + return o << u.getHeader() << " " << u.variant.type().name() << "[" << u.variant << "]"; } }} // namespace qpid::amqp_0_10 diff --git a/qpid/cpp/src/qpid/amqp_0_10/Unit.h b/qpid/cpp/src/qpid/amqp_0_10/Unit.h index dad34fef01..bcba36e35a 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Unit.h +++ b/qpid/cpp/src/qpid/amqp_0_10/Unit.h @@ -43,30 +43,33 @@ class Unit { public: typedef boost::variant<ControlHolder, CommandHolder, Header, Body> Variant; - Unit(const FrameHeader& h=FrameHeader()) : header(h) { setVariant(); } + explicit Unit(const FrameHeader& h=FrameHeader()) : header(h) { updateVariant(); } + /** + *@param flags: is ORed with the required flags for type T. + */ template <class T> - Unit(const T& t, uint8_t flags) : variant(t) { setHeader(flags); } + explicit Unit(const T& t, uint8_t flags=0) : variant(t) { updateHeader(flags); } + void setHeader(FrameHeader& h) { header = h; updateVariant(); } const FrameHeader& getHeader() const { return header; } template<class T> const T* get() const { return boost::get<T>(&variant); } template<class T> T* get() { return boost::get<T>(&variant); } - template<class T> Unit& operator==(const T& t) { variant=t; return *this; } + template<class T> Unit& operator=(const T& t) { variant=t; return *this; } template <class S> void serialize(S& s) { variant.apply_visitor(s); s.split(*this); } template <class S> void encode(S&) const {} - template <class S> void decode(S&) { setHeader(header.getFlags()); } + template <class S> void decode(S&) { updateHeader(header.getFlags()); } - const Variant& getVariant() const { return variant; } - Variant& getVariant() { return variant; } - private: - void setHeader(uint8_t flags); - void setVariant(); + void updateHeader(uint8_t flags); + void updateVariant(); Variant variant; FrameHeader header; + + friend std::ostream& operator<<(std::ostream& o, const Unit& u); }; std::ostream& operator<<(std::ostream& o, const Unit& u); diff --git a/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h b/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h index 0b4ec550d1..1e4aa04bf4 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h +++ b/qpid/cpp/src/qpid/amqp_0_10/UnknownType.h @@ -35,12 +35,13 @@ class UnknownType { 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 */ + /** Bytes in size type 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(); } + size_t size() const { return data.size(); } template <class S> void serialize(S& s) { s.split(*this); } template <class S> void encode(S& s) const; diff --git a/qpid/cpp/src/qpid/amqp_0_10/all_built_in_types.h b/qpid/cpp/src/qpid/amqp_0_10/all_built_in_types.h new file mode 100644 index 0000000000..1568465004 --- /dev/null +++ b/qpid/cpp/src/qpid/amqp_0_10/all_built_in_types.h @@ -0,0 +1,31 @@ +#ifndef QPID_AMQP_0_10_ALL_BUILT_IN_TYPES_H +#define QPID_AMQP_0_10_ALL_BUILT_IN_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. + * + */ + +#include "built_in_types.h" +#include "Map.h" +#include "Array.h" +#include "UnknownType.h" +#include "complex_types.h" + +#endif /*!QPID_AMQP_0_10_ALL_BUILT_IN_TYPES_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 c9ce27bda0..5b79faef36 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 @@ -36,7 +36,6 @@ /**@file Mapping from built-in AMQP types to C++ types */ - namespace qpid { namespace amqp_0_10 { @@ -135,20 +134,17 @@ typedef SerializableString<Uint8, Uint32> Vbin32; // Forward declare class types. class Map; +class UnknownType; +template <class T> struct ArrayDomain; +typedef ArrayDomain<UnknownType> Array; -// FIXME aconway 2008-02-26: Unimplemented types: -template <class T> struct ArrayDomain : public std::vector<T> { - template <class S> void serialize(S&) {} -}; -struct Array { template <class S> void serialize(S&) {} }; +// FIXME aconway 2008-04-08: TODO struct ByteRanges { template <class S> void serialize(S&) {} }; struct SequenceSet { 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 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 SequenceSet&) { return o; } inline std::ostream& operator<<(std::ostream& o, const List&) { return o; } diff --git a/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp b/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp index 39cbb0a2cd..93550b9c20 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp +++ b/qpid/cpp/src/qpid/amqp_0_10/complex_types.cpp @@ -23,6 +23,7 @@ #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" +#include <iostream> namespace qpid { namespace amqp_0_10 { @@ -61,5 +62,17 @@ 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; } +struct PrintVisitor { + typedef std::ostream& result_type; + std::ostream& out; + PrintVisitor(std::ostream& o) : out(o) {} + template <class T> result_type operator()(const T& t) const { return out << t; } +}; + +std::ostream& operator<<(std::ostream& o, const Command& x) { return apply(PrintVisitor(o), x); } +std::ostream& operator<<(std::ostream& o, const Control& x) { return apply(PrintVisitor(o), x); } +// FIXME aconway 2008-04-07: +// std::ostream& operator<<(std::ostream& o, const Struct& x) { apply(PrintVisitor(o), x); } + }} // namespace qpid::amqp_0_10 diff --git a/qpid/cpp/src/qpid/amqp_0_10/complex_types.h b/qpid/cpp/src/qpid/amqp_0_10/complex_types.h index d69a2be957..c8080b867d 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/complex_types.h +++ b/qpid/cpp/src/qpid/amqp_0_10/complex_types.h @@ -23,6 +23,7 @@ */ #include "built_in_types.h" +#include <iosfwd> namespace qpid { namespace amqp_0_10 { @@ -71,6 +72,7 @@ struct Command const char* getName() const; const char* getClassName() const; }; +std::ostream& operator<<(std::ostream&, const Command&); struct ControlVisitor; struct ConstControlVisitor; @@ -86,6 +88,7 @@ struct Control const char* getName() const; const char* getClassName() const; }; +std::ostream& operator<<(std::ostream&, const Control&); struct StructVisitor; struct ConstStructVisitor; @@ -98,7 +101,7 @@ struct Struct uint8_t getSize() const; uint8_t getClassCode() const; }; - +std::ostream& operator<<(std::ostream&, const Struct&); template <SegmentType E> struct ActionType; template <> struct ActionType<CONTROL> { typedef Control type; }; diff --git a/qpid/cpp/src/qpid/framing/Blob.h b/qpid/cpp/src/qpid/framing/Blob.h index 344e4ac4db..cf81f693b0 100644 --- a/qpid/cpp/src/qpid/framing/Blob.h +++ b/qpid/cpp/src/qpid/framing/Blob.h @@ -85,10 +85,6 @@ template <> struct BlobHelper<void> { * In particular the user must ensure the blob is big enough for its * contents and must know the type of object in the blob to cast get(). * - * Objects can be allocated directly in place using - * construct(in_place<T>(...)) or copied using operator=. - * Constructing a new object in the blob destroys the old one. - * * If BaseType is specified then only object that can be * safely static_cast to BaseType may be stored in the Blob. */ @@ -140,12 +136,18 @@ class Blob /** Copy a blob. */ Blob(const Blob& b) { initialize(); assign(b); } - /** @see construct() */ + /** Construct from in_place constructor */ template<class InPlace> Blob(const InPlace & expr, typename EnableInPlace<InPlace>::type* =0) { initialize(); apply(expr); } + /** Construct by copying an objecct constructor */ + template<class T> + Blob(const T & t, typename DisableInPlace<T>::type* =0) { + initialize(); apply(in_place<T>(t)); + } + ~Blob() { clear(); } /** Assign from another blob. */ diff --git a/qpid/cpp/src/tests/amqp_0_10/Map.cpp b/qpid/cpp/src/tests/amqp_0_10/Map.cpp index ad6f38b5d7..dcba6e38c2 100644 --- a/qpid/cpp/src/tests/amqp_0_10/Map.cpp +++ b/qpid/cpp/src/tests/amqp_0_10/Map.cpp @@ -19,7 +19,8 @@ * */ #include "unit_test.h" -#include "qpid/amqp_0_10/Map.h" +#include "qpid/amqp_0_10/all_built_in_types.h" +//FIXME aconway 2008-04-08: #include "qpid/amqp_0_10/allSegmentTypes.h" #include "qpid/amqp_0_10/Codec.h" #include <iostream> diff --git a/qpid/cpp/src/tests/amqp_0_10/serialize.cpp b/qpid/cpp/src/tests/amqp_0_10/serialize.cpp index 16559b3516..e479151ec0 100644 --- a/qpid/cpp/src/tests/amqp_0_10/serialize.cpp +++ b/qpid/cpp/src/tests/amqp_0_10/serialize.cpp @@ -20,6 +20,10 @@ */ #include "unit_test.h" + +#include "qpid/framing/AMQFrame.h" +#include "qpid/framing/Buffer.h" + #include "qpid/amqp_0_10/Packer.h" #include "qpid/amqp_0_10/built_in_types.h" #include "qpid/amqp_0_10/Codec.h" @@ -28,6 +32,7 @@ #include "qpid/amqp_0_10/FrameHeader.h" #include "qpid/amqp_0_10/Map.h" #include "qpid/amqp_0_10/Unit.h" +#include "tests/allSegmentTypes.h" #include <boost/test/test_case_template.hpp> #include <boost/type_traits/is_arithmetic.hpp> @@ -266,21 +271,71 @@ BOOST_AUTO_TEST_CASE(testUnit) { BOOST_CHECK_EQUAL(data, data2); } -// FIXME aconway 2008-04-07: TODO -// BOOST_AUTO_TEST_CASE(testAllSegmentTypes) { -// string data; -// int n = allSegmentTypes(Codec::encode(data)); - -// string data2; -// Codec::Decoder<string::iterator> decode(data.begin(), data.size()); -// while (decode.pos() != data.end()) { -// Unit unit; -// decode(unit); -// Codec::encode(back_insert(data)); -// --n; -// } -// BOOST_CHECK_EQUAL(n, 0); -// BOOST_CHECK_EQUAL(data, data2); +BOOST_AUTO_TEST_CASE(testArray) { + ArrayDomain<char> a; + a.resize(3, 'x'); + string data; + Codec::encode(back_inserter(data))(a); + + ArrayDomain<char> b; + Codec::decode(data.begin())(b); + BOOST_CHECK_EQUAL(b.size(), 3u); + string data3; + Codec::encode(back_inserter(data3))(a); + BOOST_CHECK_EQUAL(data, data3); + + Array x; + Codec::decode(data.begin())(x); + BOOST_CHECK_EQUAL(x.size(), 3u); + BOOST_CHECK_EQUAL(x[0].size(), 1u); + BOOST_CHECK_EQUAL(*x[0].begin(), 'x'); + BOOST_CHECK_EQUAL(*x[2].begin(), 'x'); + + string data2; + Codec::encode(back_inserter(data2))(x); + BOOST_CHECK_EQUAL(data,data2); +} + +struct RecodeUnit { + template <class T> + void operator() (const T& t) { + using qpid::framing::Buffer; + using qpid::framing::AMQFrame; + + Unit u(t); + connection::Start s; + + string data; + Codec::encode(back_inserter(data))(u.getHeader())(u); + data.push_back(char(0xCE)); // Preview end-of-frame + + Buffer buf(&data[0], data.size()); + AMQFrame f; + f.decode(buf); + + string data2(f.size(), ' '); + Buffer buf2(&data2[0], data.size()); + f.encode(buf2); + + BOOST_CHECK_EQUAL(data, data2); + + Codec::Decoder<string::iterator> decode(data2.begin()); + FrameHeader h; + decode(h); + Unit u2(h); + decode(u2); + + string data3; + Codec::encode(back_inserter(data3))(u.getHeader())(u); + + BOOST_CHECK_EQUAL(data3, data2); + } +}; + +// FIXME aconway 2008-04-08: TODO +// BOOST_AUTO_TEST_CASE(testSerializeAllSegmentTypes) { +// RecodeUnit recode; +// allSegmentTypes(recode); // } QPID_AUTO_TEST_SUITE_END() diff --git a/qpid/cpp/src/tests/python_tests b/qpid/cpp/src/tests/python_tests index a3478eac1c..f35cb16480 100755 --- a/qpid/cpp/src/tests/python_tests +++ b/qpid/cpp/src/tests/python_tests @@ -3,10 +3,11 @@ QPID_PORT=${QPID_PORT:-5672} PYTHON_TESTS=${PYTHON_TESTS:-$*} + run() { SPEC=$1 FAILING=$2 - ./run-tests --skip-self-test -v -s $SPEC -I $FAILING -b localhost:$QPID_PORT $PYTHON_TESTS || exit 1 + ./run-tests --skip-self-test -v -s $SPEC -I $FAILING -b localhost:$QPID_PORT $PYTHON_TESTS || { echo "FAIL python tests for $SPEC"; exit 1; } } if test -d ../../../python ; then |
