diff options
author | Alan Conway <aconway@apache.org> | 2008-03-11 22:13:10 +0000 |
---|---|---|
committer | Alan Conway <aconway@apache.org> | 2008-03-11 22:13:10 +0000 |
commit | eadb91781ab0d6e786500a3798f1bf2a83293a05 (patch) | |
tree | e582626920f3583e27deda835a2e2389c9c5e8c7 /cpp | |
parent | 2250ec787ae5fb84fbebfee35bd9925ebd1dd679 (diff) | |
download | qpid-python-eadb91781ab0d6e786500a3798f1bf2a83293a05.tar.gz |
rubygen/0-10/specification.rb:
- Simplified enum mapping/encoding.
- struct encoding
- ostream << operators
src/qpid/Serializer.h
- free funciton serialization
- separate Encoder/Decoder for const correctness
- split() to allow separate encode/decode for complex cases.
src/qpid/amqp_0_10/Assembly.cpp, Assembly.h: AMQP 0-10 final Assembly
src/qpid/amqp_0_10/Codec.h
- Replaced enable_if with overloads, simpler & more flexible.
src/qpid/amqp_0_10/Frame.cpp, .h: AMQP 0-10 final frame.
src/qpid/amqp_0_10/Holder.h:
- provide const and non-const apply
src/qpid/amqp_0_10/Segment.cpp, .h: AMQP 0-10 final Segment.
src/qpid/amqp_0_10/apply.h
- ConstApplyFunctor for const apply.
src/qpid/amqp_0_10/built_in_types.h
- SerializableString encoding
src/qpid/amqp_0_10/complex_types.cpp, .h
- const application
- Action base class for command/control.
src/qpid/framing/AMQBody.h
- removed 0-10 final changes, moving integration point down the stack.
src/qpid/sys/Shlib.h
- removed unused and uncompilable (on some compilers) function.
src/qpid/sys/Time.h, .cpp
- ostream << for AbsTime and Duration.
src/tests/Assembly.cpp, Segment.cpp, apply.cpp, serialize.cpp: testing new code.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@636126 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp')
-rwxr-xr-x | cpp/rubygen/0-10/specification.rb | 30 | ||||
-rw-r--r-- | cpp/src/Makefile.am | 4 | ||||
-rw-r--r-- | cpp/src/qpid/Serializer.h | 84 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Assembly.cpp | 82 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Assembly.h | 71 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Codec.h | 158 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Frame.cpp | 28 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Frame.h | 171 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Holder.h | 17 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Segment.cpp | 81 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/Segment.h | 127 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/apply.h | 6 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/built_in_types.h | 52 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/complex_types.cpp | 2 | ||||
-rw-r--r-- | cpp/src/qpid/amqp_0_10/complex_types.h | 32 | ||||
-rw-r--r-- | cpp/src/qpid/framing/AMQBody.h | 12 | ||||
-rw-r--r-- | cpp/src/qpid/sys/Shlib.h | 6 | ||||
-rw-r--r-- | cpp/src/qpid/sys/Time.h | 4 | ||||
-rw-r--r-- | cpp/src/qpid/sys/posix/Time.cpp | 28 | ||||
-rw-r--r-- | cpp/src/tests/apply.cpp | 2 | ||||
-rw-r--r-- | cpp/src/tests/serialize.cpp | 55 |
21 files changed, 891 insertions, 161 deletions
diff --git a/cpp/rubygen/0-10/specification.rb b/cpp/rubygen/0-10/specification.rb index c159d9f08b..a11abdb877 100755 --- a/cpp/rubygen/0-10/specification.rb +++ b/cpp/rubygen/0-10/specification.rb @@ -15,11 +15,13 @@ class Specification < CppGen genl typename=d.name.typename if d.enum - scope("enum #{typename}Enum {", "};") { + scope("enum #{typename} {", "};") { genl d.enum.choices.map { |c| "#{c.name.constname} = #{c.value}" }.join(",\n") } - genl "typedef Enum<#{typename}Enum, uint8_t> #{typename};" + scope("inline SerializableEnum<#{typename}, uint8_t> serializable(#{typename}& e) {") { + genl "return SerializableEnum<#{typename}>(e);" + } else genl "typedef #{d.amqp2cpp} #{typename};" end @@ -52,11 +54,20 @@ class Specification < CppGen ctor_decl(x.classname, x.parameters) unless x.fields.empty? genl "void accept(Visitor&);" genl "void accept(ConstVisitor&) const;" + if (x.fields.empty?) + genl "template <class S> void serialize(S&) {}" + else + scope("template <class S> void serialize(S& s) {") { + gen "s"; x.fields.each { |f| gen "(#{f.cppname})"}; genl ";" + } + end genl yield if block } + genl "std::ostream& operator << (std::ostream&, 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}\";" @@ -73,6 +84,12 @@ class Specification < CppGen genl "void #{x.classname}::accept(Visitor& v) { v.visit(*this); }" genl "void #{x.classname}::accept(ConstVisitor& v) const { v.visit(*this); }" end + genl + scope("std::ostream& operator << (std::ostream& o, const #{x.classname}&#{"x" unless x.fields.empty?}) {") { + genl "return o << \"[#{x.fqname}\";"; + x.fields.each{ |f| genl "o << \" #{f.name}=\" << x.#{f.cppname};" } + genl "o << \"];\";" + } end # structs @@ -87,13 +104,6 @@ class Specification < CppGen function_defn("template <class T> void invoke", ["T& target"]) { genl "target.#{a.funcname}(#{a.values.join(', ')});" } - if (a.fields.empty?) - genl "template <class S> void serialize(S&) {}" - else - scope("template <class S> void serialize(S& s) {") { - gen "s"; a.fields.each { |f| gen "(#{f.cppname})"}; genl ";" - } - end } end @@ -108,6 +118,7 @@ class Specification < CppGen include "#{@dir}/built_in_types" include "#{@dir}/complex_types" include "<boost/call_traits.hpp>" + include "<iosfwd>" genl "using boost::call_traits;" namespace(@ns) { # Top level @@ -133,6 +144,7 @@ class Specification < CppGen cpp_file("#{@dir}/specification") { include "#{@dir}/specification" + include "<iostream>" # FIXME aconway 2008-03-04: add Struct visitors. ["Command","Control"].each { |x| include "#{@dir}/Apply#{x}" } namespace(@ns) { diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am index 8ec15619c1..da3a86787a 100644 --- a/cpp/src/Makefile.am +++ b/cpp/src/Makefile.am @@ -109,6 +109,10 @@ libqpidcommon_la_SOURCES = \ qpid/amqp_0_10/Holder.h \ qpid/amqp_0_10/Codec.h \ qpid/amqp_0_10/Decimal.h \ + qpid/amqp_0_10/Segment.h \ + qpid/amqp_0_10/Segment.cpp \ + qpid/amqp_0_10/Assembly.h \ + qpid/amqp_0_10/Assembly.cpp \ qpid/Serializer.h \ qpid/framing/AccumulatedAck.cpp \ qpid/framing/AMQBody.cpp \ diff --git a/cpp/src/qpid/Serializer.h b/cpp/src/qpid/Serializer.h index 34b95d3ffd..e0e29e24fd 100644 --- a/cpp/src/qpid/Serializer.h +++ b/cpp/src/qpid/Serializer.h @@ -23,59 +23,71 @@ */ #include <boost/utility/enable_if.hpp> -#include <boost/static_assert.hpp> -#include <boost/type_traits/is_class.hpp> -#include <algorithm> +#include <boost/type_traits/is_base_and_derived.hpp> namespace qpid { +namespace serialize { -// FIXME aconway 2008-03-03: Doc - esp decoding -template <class Derived> class Serializer { - public: - typedef Serializer result_type; // unary functor requirement. +// FIXME aconway 2008-03-03: Document. +// Encoder/Decoder concept: add op() for primitive types, raw(), +// op()(Iter, Iter). Note split, encode, decode. +// - static const bool IS_DECODER=false; +// FIXME aconway 2008-03-09: document - non-intrusive serialzation. +// Default rule calls member. Enums must provide an override rule. - /** Generic handler for class objects, call serialize() */ - template <class T> - typename boost::enable_if<boost::is_class<T>, Derived&>::type - operator()(T& t) { - t.serialize(self()); - return self(); - } +/** Overload for types that do not provide a serialize() member.*/ +template <class T> T& serializable(T& t) { return t; } + +template <class Derived> class Encoder { + public: + typedef Derived& result_type; // unary functor requirement. - /** Generic handler for const class objects, call serialize() */ + /** Default op() calls serializable() free function */ template <class T> - typename boost::enable_if<boost::is_class<T>, Derived&>::type - operator()(const T& t) { - assert(!Derived::IS_DECODER); // We won't modify the value. - // const_cast so we don't need 2 serialize() members for every class. - const_cast<T&>(t).serialize(self()); - return self(); + Derived& operator()(const T& t) { + serializable(const_cast<T&>(t)).serialize(self()); return self(); } - template <class T, bool=false> struct Split { - Split(Derived& s, T& t) { t.encode(s); } - }; - - template <class T> struct Split<T,true> { - Split(Derived& s, T& t) { t.decode(s); } - }; - /** - * Called by classes that want to receive separate - * encode()/decode() calls. - */ + /** Split serialize() into encode()/decode() */ template <class T> - void split(T& t) { Split<T, Derived::IS_DECODER>(self(),t); } - + Derived& split(const T& t) { t.encode(self()); return self(); } + private: Derived& self() { return *static_cast<Derived*>(this); } }; +template <class Derived> class Decoder { + public: + typedef Derived& result_type; // unary functor requirement. + + /** Default op() calls serializable() free function */ + template <class T> + Derived& operator()(T& t) { + serializable(t).serialize(self()); return self(); + } + /** Split serialize() into encode()/decode() */ + template <class T> + Derived& split(T& t) { t.decode(self()); return self(); } + + private: + Derived& self() { return *static_cast<Derived*>(this); } +}; +/** Serialize a type by converting it to/from another type */ +template <class Type, class AsType> +struct SerializeAs { + Type& value; + SerializeAs(Type & t) : value(t) {} + template <class S> void serialize(S& s) { s.split(*this); } + template <class S> void encode(S& s) const { s(AsType(value)); } + template <class S> void decode(S& s) { AsType x; s(x); value=x; } +}; -} // namespace qpid +}} // namespace qpid::serialize +// FIXME aconway 2008-03-09: rename to serialize.h +// #endif /*!QPID_SERIALIZER_H*/ diff --git a/cpp/src/qpid/amqp_0_10/Assembly.cpp b/cpp/src/qpid/amqp_0_10/Assembly.cpp new file mode 100644 index 0000000000..ad753e2d08 --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/Assembly.cpp @@ -0,0 +1,82 @@ +/* + * + * 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 "Assembly.h" +#include "qpid/Exception.h" +#include "Codec.h" +#include "qpid/framing/Blob.h" + +namespace qpid { +namespace amqp_0_10 { + +using framing::in_place; + +Assembly::Assembly(const Command& c) : command(in_place<Command::Holder>(c)) {} +Assembly::Assembly(const Control& c) : control(in_place<Control::Holder>(c)) {} + +void Assembly::add(const Frame& f) { + switch (f.getType()) { + case COMMAND: { + Segment& s = segments[ACTION_SEG]; + s.add(f); + if (s.isComplete()) { + command = in_place<Command::Holder>(); + Codec::decode(s.begin())(*command); + if (f.testFlags(Frame::LAST_SEGMENT)) { + segments[HEADER_SEG].setMissing(); + segments[BODY_SEG].setMissing(); + } + } + break; + } + case CONTROL: { + Segment& s = segments[ACTION_SEG]; + s.add(f); + if (s.isComplete()) { + control = in_place<Control::Holder>(); + Codec::decode(s.begin())(*control); + if (f.testFlags(Frame::LAST_SEGMENT)) { + segments[HEADER_SEG].setMissing(); + segments[BODY_SEG].setMissing(); + } + } + break; + } + case HEADER: { + Segment& s = segments[HEADER_SEG]; + s.add(f); + if (s.isComplete()) { + header = in_place<Header>(); + Codec::decode(*header); + if (f.testFlags(Frame::LAST_SEGMENT)) { + segments[BODY_SEG].setMissing(); + } + } + break; + } + case BODY: { + Segment& s = segments[BODY_SEG]; + s.add(f); + break; + } + } +} + +}} // namespace qpid::amqp_0_10 diff --git a/cpp/src/qpid/amqp_0_10/Assembly.h b/cpp/src/qpid/amqp_0_10/Assembly.h new file mode 100644 index 0000000000..6205032ef9 --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/Assembly.h @@ -0,0 +1,71 @@ +#ifndef QPID_AMQP_0_10_ASSEMBLY_H +#define QPID_AMQP_0_10_ASSEMBLY_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/CommandHolder.h" +#include "qpid/amqp_0_10/ControlHolder.h" +#include "Segment.h" +#include <boost/optional.hpp> + +namespace qpid { +namespace amqp_0_10 { + +// FIXME aconway 2008-03-06: TODO +struct Header { + template <class S> void serialize(S&) {} +}; + +class Assembly +{ + public: + enum SegmentIndex { ACTION_SEG, HEADER_SEG, BODY_SEG }; + + Assembly() {} + Assembly(const Command& c); + Assembly(const Control& c); + + Segment& getSegment(int i) { return segments[i]; } + const Segment& getSegment(int i) const { return segments[i]; } + + const Command* getCommand() const { return command ? command->get() : 0; } + const Control* getControl() const { return control ? control->get() : 0; } + const Header* getHeader() const { return header.get_ptr(); } + + void setCommand(const Command& c) { *command = c; } + void setControl(const Control& c) { *control = c; } + void setHeader(const Header& h) { header = h; } + + void add(const Frame& f); + + bool isComplete() const { return segments[BODY_SEG].isComplete(); } + + private: + Segment segments[3]; + boost::optional<Command::Holder> command; + boost::optional<Control::Holder> control; + boost::optional<Header> header; +}; + +}} // namespace qpid::amqp_0_10 + +#endif /*!QPID_AMQP_0_10_ASSEMBLY_H*/ diff --git a/cpp/src/qpid/amqp_0_10/Codec.h b/cpp/src/qpid/amqp_0_10/Codec.h index a36004753a..04112cc4d1 100644 --- a/cpp/src/qpid/amqp_0_10/Codec.h +++ b/cpp/src/qpid/amqp_0_10/Codec.h @@ -28,34 +28,55 @@ #include <boost/type_traits/is_float.hpp> #include <boost/type_traits/is_arithmetic.hpp> #include <boost/detail/endian.hpp> +#include <boost/static_assert.hpp> namespace qpid { namespace amqp_0_10 { + +#ifdef BOOST_LITTLE_ENDIAN +template <class T> void endianize(T& t) { + char*p =reinterpret_cast<char*>(&t); + std::reverse(p, p+sizeof(T)); +} +#else +template <class T> void endianize(T&) {} +#endif + /** * AMQP 0-10 encoding and decoding. */ -struct Codec { // FIXME aconway 2008-02-29: drop this wrapper? +struct Codec { + + // FIXME aconway 2008-02-29: drop this wrapper, rename to + // IteratorEncoder, IteratorDecoder? /** Encode to an output byte iterator */ template <class OutIter> - class Encode : public Serializer<Encode<OutIter> > { + class Encode : public serialize::Encoder<Encode<OutIter> > + { public: Encode(OutIter o) : out(o) {} - using Serializer<Encode<OutIter> >::operator(); + using serialize::Encoder<Encode<OutIter> >::operator(); - template <class T> - typename boost::enable_if<boost::is_integral<T>, Encode&>::type - operator()(T x) { - endianize(x); - raw(&x, sizeof(x)); - return *this; - } + // FIXME aconway 2008-03-10: wrong encoding, need packing support + Encode& operator()(bool x) { *out++=x; return *this;} + + Encode& operator()(char x) { *out++=x; return *this; } + Encode& operator()(int8_t x) { *out++=x; return *this; } + Encode& operator()(uint8_t x) { *out++=x; return *this; } + + Encode& operator()(int16_t x) { return endian(x); } + Encode& operator()(int32_t x) { return endian(x); } + Encode& operator()(int64_t x) { return endian(x); } + + Encode& operator()(uint16_t x) { return endian(x); } + Encode& operator()(uint32_t x) { return endian(x); } + Encode& operator()(uint64_t x) { return endian(x); } + + Encode& operator()(float x) { return endian(x); } + Encode& operator()(double x) { return endian(x); } - // 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) { raw(&x, sizeof(x)); return *this; } template <class Iter> Encode& operator()(Iter begin, Iter end) { std::for_each(begin, end, *this); @@ -63,42 +84,45 @@ struct Codec { // FIXME aconway 2008-02-29: drop this wrapper? } void raw(const void* p, size_t n) { - std::copy((const char*)p, (const char*)p+n, out); + std::copy((const char*)p, (const char*)p+n, out); + out += n; } - + + OutIter pos() const { return out; } + private: + + template <class T> Encode& endian(T x) { + endianize(x); raw(&x, sizeof(x)); return *this; + } + OutIter out; }; template <class InIter> - class Decode : public Serializer<Decode<InIter> > { + class Decode : public serialize::Decoder<Decode<InIter> > { public: Decode(InIter i) : in(i) {} - static const bool IS_DECODER=true; + using serialize::Decoder<Decode<InIter> >::operator(); - using Serializer<Decode<InIter> >::operator(); - - template <class T> - typename boost::enable_if<boost::is_integral<T>, Decode&>::type - operator()(T& x) { - raw(&x, sizeof(x)); - endianize(x); - return *this; - } + // FIXME aconway 2008-03-10: wrong encoding, need packing support + Decode& operator()(bool& x) { x=*in++; return *this; } - template <class T> - typename boost::enable_if<boost::is_float<T>, Decode&>::type - operator()(T& x) { raw(&x, sizeof(x)); return *this; } + Decode& operator()(char& x) { x=*in++; return *this; } + Decode& operator()(int8_t& x) { x=*in++; return *this; } + Decode& operator()(uint8_t& x) { x=*in++; return *this; } - template<class T, class SizeType> - Decode& operator()(SerializableString<T,SizeType>& str) { - SizeType n; - (*this)(n); - str.resize(n); - std::for_each(str.begin(), str.end(), *this); - return *this; - } + Decode& operator()(int16_t& x) { return endian(x); } + Decode& operator()(int32_t& x) { return endian(x); } + Decode& operator()(int64_t& x) { return endian(x); } + + Decode& operator()(uint16_t& x) { return endian(x); } + Decode& operator()(uint32_t& x) { return endian(x); } + Decode& operator()(uint64_t& x) { return endian(x); } + + Decode& operator()(float& x) { return endian(x); } + Decode& operator()(double& x) { return endian(x); } template <class Iter> Decode& operator()(Iter begin, Iter end) { std::for_each(begin, end, *this); @@ -106,34 +130,47 @@ struct Codec { // FIXME aconway 2008-02-29: drop this wrapper? } 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; } + InIter pos() const { return in; } + private: + + template <class T> Decode& endian(T& x) { + raw(&x, sizeof(x)); endianize(x); return *this; + } + InIter in; }; - class Size : public Serializer<Size> { + class Size : public serialize::Encoder<Size> { public: Size() : size(0) {} operator size_t() const { return size; } - using Serializer<Size>::operator(); + using serialize::Encoder<Size>::operator(); + + // FIXME aconway 2008-03-10: wrong encoding, need packing support + Size& operator()(bool x) { size += sizeof(x); return *this; } - template <class T> - typename boost::enable_if<boost::is_arithmetic<T>, Size&>::type - operator()(const T&) { size += sizeof(T); return *this; } + Size& operator()(char x) { size += sizeof(x); return *this; } + Size& operator()(int8_t x) { size += sizeof(x); return *this; } + Size& operator()(uint8_t x) { size += sizeof(x); return *this; } - template<class T, class SizeType> - Size& operator()(const SerializableString<T,SizeType>& str) { - size += sizeof(SizeType) + str.size()*sizeof(T); - return *this; - } + Size& operator()(int16_t x) { size += sizeof(x); return *this; } + Size& operator()(int32_t x) { size += sizeof(x); return *this; } + Size& operator()(int64_t x) { size += sizeof(x); return *this; } + + Size& operator()(uint16_t x) { size += sizeof(x); return *this; } + Size& operator()(uint32_t x) { size += sizeof(x); return *this; } + Size& operator()(uint64_t x) { size += sizeof(x); return *this; } + + 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) { @@ -147,27 +184,16 @@ struct Codec { // FIXME aconway 2008-02-29: drop this wrapper? size_t size; }; - template <class OutIter> static Decode<OutIter> decode(const OutIter &i) { - return Decode<OutIter>(i); + // FIXME aconway 2008-03-11: rename to encoder(), decoder() + template <class InIter> static Decode<InIter> decode(const InIter &i) { + return Decode<InIter>(i); } - template <class InIter> static Encode<InIter> encode(InIter i) { - return Encode<InIter>(i); + template <class OutIter> static Encode<OutIter> encode(OutIter i) { + return Encode<OutIter>(i); } template <class T> static size_t size(const T& x) { return Size()(x); } - - 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/Frame.cpp b/cpp/src/qpid/amqp_0_10/Frame.cpp new file mode 100644 index 0000000000..1140b6058d --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/Frame.cpp @@ -0,0 +1,28 @@ +/* + * + * 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 "Frame.h" + +namespace qpid { +namespace amqp_0_10 { + +bool Frame::match(const Frame& x) { +} +}} // namespace qpid::amqp_0_10 diff --git a/cpp/src/qpid/amqp_0_10/Frame.h b/cpp/src/qpid/amqp_0_10/Frame.h new file mode 100644 index 0000000000..2ae0c75073 --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/Frame.h @@ -0,0 +1,171 @@ +#ifndef QPID_AMQP_0_10_FRAME_H +#define QPID_AMQP_0_10_FRAME_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/built_in_types.h" +#include <boost/shared_array.hpp> + +namespace qpid { +namespace amqp_0_10 { + +class FrameHeader { + public: + enum Flags { FIRST_SEGMENT=8, LAST_SEGMENT=4, FIRST_FRAME=2, LAST_FRAME=1 }; + enum ShortFlags { FS=8, LS=4, FF=2, LF=1 }; + + + FrameHeader(uint8_t flags_=0, SegmentType type_=SegmentType(), uint8_t track_=0, uint16_t channel_=0) + : flags(flags_), type(type_), size_(), track(track_), channel(channel_) + {} + + uint8_t getFlags() const { return flags; } + SegmentType getType() const { return type; } + uint16_t getSize() const { return size_; } + uint8_t getTrack() const { return track; } + uint16_t getChannel() const { return channel; } + + void setFlags(uint8_t flags_) { flags=flags_; } + void setType(SegmentType type_) { type=type_; } + void setTrack(uint8_t track_) { track=track_; } + void setChannel(uint8_t channel_) { channel=channel_; } + + Flags testFlags(uint8_t f) const { return Flags(flags & f); } + void raiseFlags(uint8_t f) { flags |= f; } + void clearFlags(uint8_t f) { flags &= ~f; } + + uint16_t size() const { return size_; } + bool empty() const { return size()==0; } + + bool operator==(const FrameHeader& x) + { return memcmp(this, &x, sizeof(this)); } + + template <class S> void serialize(S& s); + + protected: + uint8_t flags; + SegmentType type; + uint16_t size_; + uint8_t track; + uint16_t channel; + + private: +}; + +class Frame : public FrameHeader { + public: + Frame(uint8_t flags_=0, SegmentType type_=SegmentType(), uint8_t track_=0, + uint16_t channel_=0) + : FrameHeader(flags_, type_, track_, channel_), ref() {} + + Frame(const FrameHeader& header) : FrameHeader(header), ref() {} + + Frame(const FrameHeader& header, size_t s) + : FrameHeader(header), ref() { resize(s); } + + Frame(const FrameHeader& header, const char* a, const char* b, + bool copyFlag=true) : FrameHeader(header), ref() { + if (copyFlag) copy(a,b); else refer(a,b); + } + + Frame(const FrameHeader& header, const char* p, std::size_t s, + bool copyFlag=true) : FrameHeader(header), ref() { + if (copyFlag) copy(p,p+s); else refer(p,p+s); + } + + + /** Allocate a buffer of at least size bytes */ + void resize(uint16_t size); + + /** Make the frame refer to byte range [begin,end) + * Range is NOT COPIED, it must be valid for lifetime of Frame. + */ + void refer(const char* begin, const char* end); + + /** Allocate a buffer and copy range begin/end */ + void copy(const char* begin, const char* end); + + char* begin() { assert(!ref); return data.get(); } + const char* begin() const { return ref ? ref : data.get(); } + char* end() { return begin() + size(); } + const char* end() const { return begin() + size(); } + + void clear() { data.reset(); ref = 0; size_= 0; } + + template <class S> void serialize(S& s); + template <class S> void encode(S& s) const; + template <class S> void decode(S& s); + + private: + boost::shared_array<char> data; + const char* ref; +}; + +inline void Frame::refer(const char* a, const char* b) { + data.reset(); + ref = a; + size_ = b-a; +} + +inline void Frame::copy(const char* a, const char* b) { + resize(b-a); + std::copy(a, b, begin()); +} + +inline void Frame::resize(uint16_t s) { + if (s > size() || ref) { + ref = 0; + data.reset(new char[s]); + } + size_=s; +} + +template <class S> void FrameHeader::serialize(S& s) { + uint8_t pad8=0; + uint32_t pad32=0; + s(flags)(type)(size_)(pad8)(track)(channel)(pad32); +} + +template <class S> void Frame::serialize(S& s) { s.split(*this); } + +template <class S> void Frame::encode(S& s) const { + s(static_cast<const FrameHeader&>(*this)); + s.raw(begin(), size()); +} + +template <class S> void Frame::decode(S& s) { + try { + uint16_t oldSize = size_; + s(static_cast<FrameHeader&>(*this)); + std::swap(oldSize, size_); + resize(oldSize); + s.raw(begin(), size()); + } catch (...) { + clear(); + throw; + } +} + +}} // namespace qpid::amqp_0_10 + +#endif /*!QPID_AMQP_0_10_FRAME_H*/ + diff --git a/cpp/src/qpid/amqp_0_10/Holder.h b/cpp/src/qpid/amqp_0_10/Holder.h index 76f8aa52de..4c1fccd44f 100644 --- a/cpp/src/qpid/amqp_0_10/Holder.h +++ b/cpp/src/qpid/amqp_0_10/Holder.h @@ -29,18 +29,29 @@ namespace amqp_0_10 { template <class DerivedHolder, class BaseHeld, size_t Size> struct Holder : public framing::Blob<Size, BaseHeld> { - typedef framing::Blob<Size, BaseHeld> Base; + struct Assign : public ApplyFunctor<void> { + Holder& holder; + Assign(Holder& x) : holder(x) {} + template <class T> void operator()(const T& rhs) { holder=rhs; } + }; + Holder() {} + Holder(const BaseHeld& x) { *this=x; } template <class T> Holder(const T& value) : Base(value) {} using Base::operator=; - + Holder& operator=(const BaseHeld& rhs) { + Assign assign(*this); + apply(assign, rhs); + return *this; + } + uint8_t getCode() const { return this->get()->getCode(); } uint8_t getClassCode() const { return this->get()->getClassCode(); } - template <class S> void encode(S& s) { + template <class S> void encode(S& s) const { s(getClassCode())(getCode()); } diff --git a/cpp/src/qpid/amqp_0_10/Segment.cpp b/cpp/src/qpid/amqp_0_10/Segment.cpp new file mode 100644 index 0000000000..0d7c9c55f1 --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/Segment.cpp @@ -0,0 +1,81 @@ +/* + * + * 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 "Segment.h" +#include "qpid/Exception.h" +#include <boost/ref.hpp> +#include <numeric> + +namespace qpid { +namespace amqp_0_10 { + +Segment::Segment() : missing() {} + +bool Segment::isComplete() const { + return missing || !frames.empty() && (frames.back().testFlags(Frame::LAST_FRAME)); +} + +Segment::const_iterator Segment::begin() const { + return Segment::const_iterator(frames, frames.begin(), frames.begin()->begin()); +} + +Segment::const_iterator Segment::end() const { + return const_iterator(frames, frames.end(), frames.end()->end()); +} + +namespace { +Frame::Flags segFlags(const Frame& f) { + return f.testFlags(Frame::FIRST_SEGMENT | Frame::LAST_SEGMENT); +} +} // namespace + +void Segment::add(const Frame& frame) { + // FIXME aconway 2008-03-07: ex types & messages. + if (isComplete()) throw Exception("cannot add frame to complete segment"); + if (!frames.empty()) { + if (frame.testFlags(Frame::FIRST_FRAME) || + frame.getType() != frames.front().getType() || + segFlags(frames.front()) != segFlags(frame)) + throw Exception("invalid frame"); + } + frames.push_back(frame); +} + +bool Segment::isFirst() const { + return !frames.empty() && frames.front().testFlags(Frame::FIRST_SEGMENT); +} + +bool Segment::isLast() const { + return !frames.empty() && frames.front().testFlags(Frame::LAST_SEGMENT); +} + +namespace { +size_t accumulate_size(size_t total, const Frame& f) { + return total+f.size(); +} +} + +size_t Segment::size() const { + return std::accumulate(frames.begin(), frames.end(), 0, &accumulate_size); +} + +}} // namespace qpid::amqp_0_10 + + diff --git a/cpp/src/qpid/amqp_0_10/Segment.h b/cpp/src/qpid/amqp_0_10/Segment.h new file mode 100644 index 0000000000..219517811a --- /dev/null +++ b/cpp/src/qpid/amqp_0_10/Segment.h @@ -0,0 +1,127 @@ +#ifndef QPID_AMQP_0_10_SEGMENT_H +#define QPID_AMQP_0_10_SEGMENT_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 "Frame.h" +#include "qpid/InlineVector.h" +#include "qpid/amqp_0_10/built_in_types.h" +#include <boost/iterator/iterator_facade.hpp> +#include <boost/range/iterator_range.hpp> +#include <vector> + +namespace qpid { +namespace amqp_0_10 { + +/** + * Represents a (possibly incomplete) header or body segment. + */ +class Segment { + public: + // TODO aconway 2008-03-07: optimize - use ISlist instead of vector. + typedef std::vector<Frame> Frames; + struct const_iterator; + + Segment(); + + bool isComplete() const; + bool isFirst() const; + bool isLast() const; + + const Frames& getFrames() const { return frames; } + + void add(const Frame& frame); + + /** Mark an empty segment as complete. + *@pre frames.empty(). + */ + void setMissing() { assert(frames.empty()); missing = true; } + + size_t size() const; ///< Content size. + + /** Iterate over content as a continuous range of bytes. */ + const_iterator begin() const; + const_iterator end() const; + + // TODO aconway 2008-03-07: Provide output iterator + // that extends the segment as basis for ostream (XML exchange) + private: + bool missing; + Frames frames; +}; + +class Segment::const_iterator : public boost::iterator_facade< + Segment::const_iterator, const char, boost::forward_traversal_tag> +{ + public: + const_iterator() : frames(), p() {} + + private: +#ifndef NDEBUG + void invariant() const { + assert(frames); + assert(frames->begin() <= i); + assert(i <= frames->end()); + assert(i->begin() <= p); + assert(p <= i->end()); + } + void valid() const { + invariant(); + assert(p < i->end()); + } +#endif + const_iterator(const Frames& f, Frames::const_iterator pos, const char* ptr) + : frames(&f), i(pos), p(ptr) { skip_empty(); } + + const char& dereference() const { valid(); return *p; } + bool equal(const const_iterator& x) const { return p == x.p; } + void increment() { valid(); ++p; skip_empty(); } + void advance(ptrdiff_t n) { + ptrdiff_t r = i->end() - p; + while (n > r) { + assert(i != frames->end()); + n -= r; + p = (++i)->begin(); + r = i->size(); + } + p += n; + skip_empty(); + } + void skip_empty() { + invariant(); + while (p == i->end() && i != frames->end()) + p = (++i)->begin(); + invariant(); + } + + const Frames* frames; + Frames::const_iterator i; + const char* p; + + friend class Segment; + friend class boost::iterator_core_access; +}; + + +}} // namespace qpid::amqp_0_10 + +#endif /*!QPID_AMQP_0_10_SEGMENT_H*/ diff --git a/cpp/src/qpid/amqp_0_10/apply.h b/cpp/src/qpid/amqp_0_10/apply.h index 05b7669322..f32b3482ef 100644 --- a/cpp/src/qpid/amqp_0_10/apply.h +++ b/cpp/src/qpid/amqp_0_10/apply.h @@ -79,11 +79,7 @@ typename F::result_type apply(const F& functor, Visitable& visitable) { return visitor.getResult(); } -template <class R, bool Const=false> struct ApplyFunctor { - typedef R result_type; - static const bool IS_CONST=Const; -}; -template <class R> struct ConstApplyFunctor : public ApplyFunctor<R, true> {}; +template <class R> struct ApplyFunctor { typedef R result_type; }; }} // namespace qpid::amqp_0_10 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 6188e259f0..5b00e933a9 100644 --- a/cpp/src/qpid/amqp_0_10/built_in_types.h +++ b/cpp/src/qpid/amqp_0_10/built_in_types.h @@ -42,16 +42,16 @@ typedef void Void; 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 int8_t Int8; +typedef uint8_t Bin8; +typedef uint8_t Uint8; typedef uint16_t Uint16; typedef uint32_t CharUtf32 ; typedef uint32_t Uint32; typedef uint64_t Uint64; -typedef uint8_t Bin8; -typedef uint8_t Uint8; template <size_t N> struct Bin : public boost::array<char, N> { template <class S> void serialize(S& s) { s.raw(this->begin(), this->size()); } @@ -81,9 +81,19 @@ typedef Decimal<Uint8, Int64> Dec64; 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) { + + 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 @@ -114,21 +124,29 @@ struct Map { template <class S> void serialize(S&) {} }; struct List { template <class S> void serialize(S&) {} }; struct Struct32 { template <class S> void serialize(S&) {} }; -// Serializable enum support -template <class E, class Store> struct Enum { - Store value; - Enum() {} - Enum(E v) : value(v) {} - Enum(Store v) : value(v) {} - Enum& operator=(E v) { value=v; return *this; } - Enum& operator=(Store v) { value=v; return *this; } - operator E() const { return value; } - operator Store() const { return value; } - template <class S> void serialize(S& s) { s(value); } +// FIXME aconway 2008-03-10: dummy ostream operators +template <class T> std::ostream& operator<<(std::ostream& o, const Array<T>&) { 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; } + +/** Serialization helper for enums */ +template <class Enum, class Int=uint8_t> +struct SerializableEnum { + Enum& value; + SerializableEnum(Enum & e) : value(e) {} + template <class S> void serialize(S& s) { s.split(*this); } + template <class S> void encode(S& s) const { s(Int(value)); } + template <class S> void decode(S& s) { Int i; s(i); value=Enum(i); } }; -enum SegmentTypeEnum { CONTROL, COMMAND, HEADER, BODY }; -typedef Enum<SegmentTypeEnum, uint8_t> SegmentType; +enum SegmentType { CONTROL, COMMAND, HEADER, BODY }; + +inline SerializableEnum<SegmentType> serializable(SegmentType& st) { + return SerializableEnum<SegmentType>(st); +} }} // namespace qpid::amqp_0_10 diff --git a/cpp/src/qpid/amqp_0_10/complex_types.cpp b/cpp/src/qpid/amqp_0_10/complex_types.cpp index 0960db469d..39cbb0a2cd 100644 --- a/cpp/src/qpid/amqp_0_10/complex_types.cpp +++ b/cpp/src/qpid/amqp_0_10/complex_types.cpp @@ -29,7 +29,7 @@ namespace amqp_0_10 { // Functors for getting static values from a visitable base type. #define QPID_STATIC_VALUE_GETTER(NAME, TYPE, VALUE) \ - struct NAME : public ConstApplyFunctor<TYPE> { \ + struct NAME : public ApplyFunctor<TYPE> { \ template <class T> TYPE operator()(const T&) const { return T::VALUE; }\ } diff --git a/cpp/src/qpid/amqp_0_10/complex_types.h b/cpp/src/qpid/amqp_0_10/complex_types.h index f4810ba2d7..864fed5ae8 100644 --- a/cpp/src/qpid/amqp_0_10/complex_types.h +++ b/cpp/src/qpid/amqp_0_10/complex_types.h @@ -22,6 +22,8 @@ * */ +#include "built_in_types.h" + namespace qpid { namespace amqp_0_10 { @@ -37,12 +39,31 @@ template <class V, class CV, class H> struct Visitable { virtual void accept(ConstVisitor&) const = 0; }; +struct Command; +struct Control; + +struct Action { // Marker for commands & controls + virtual ~Action() {} + virtual Command* getCommand() { return 0; } + virtual Control* getControl() { return 0; } + + virtual const Command* getCommand() const { + return const_cast<Action*>(this)->getCommand(); + } + virtual const Control* getControl() const { + return const_cast<Action*>(this)->getControl(); + } +}; + struct CommandVisitor; struct ConstCommandVisitor; struct CommandHolder; struct Command - : public Visitable<CommandVisitor, ConstCommandVisitor, CommandHolder> + : public Action, + public Visitable<CommandVisitor, ConstCommandVisitor, CommandHolder> { + using Action::getCommand; + Command* getCommand() { return this; } uint8_t getCode() const; uint8_t getClassCode() const; const char* getName() const; @@ -53,8 +74,11 @@ struct ControlVisitor; struct ConstControlVisitor; struct ControlHolder; struct Control - : public Visitable<ControlVisitor, ConstControlVisitor, ControlHolder> + : public Action, + public Visitable<ControlVisitor, ConstControlVisitor, ControlHolder> { + using Action::getControl; + Control* getControl() { return this; } uint8_t getCode() const; uint8_t getClassCode() const; const char* getName() const; @@ -74,6 +98,10 @@ struct Struct }; +template <SegmentType E> struct ActionType; +template <> struct ActionType<CONTROL> { typedef Control type; }; +template <> struct ActionType<COMMAND> { typedef Command type; }; + }} // namespace qpid::amqp_0_10 #endif /*!QPID_AMQP_0_10_COMPLEX_TYPES_H*/ diff --git a/cpp/src/qpid/framing/AMQBody.h b/cpp/src/qpid/framing/AMQBody.h index 925f4c46ac..f3bf65470c 100644 --- a/cpp/src/qpid/framing/AMQBody.h +++ b/cpp/src/qpid/framing/AMQBody.h @@ -22,8 +22,6 @@ * */ #include "qpid/framing/amqp_types.h" -#include "qpid/amqp_0_10/built_in_types.h" -#include "qpid/amqp_0_10/complex_types.h" #include <ostream> @@ -62,12 +60,6 @@ class AMQBody virtual AMQMethodBody* getMethod() { return 0; } virtual const AMQMethodBody* getMethod() const { return 0; } - virtual amqp_0_10::Command* getCommand() { return 0; } - virtual const amqp_0_10::Command* getCommand() const { return 0; } - - virtual amqp_0_10::Control* getControl() { return 0; } - virtual const amqp_0_10::Control* getControl() const { return 0; } - /** Match if same type and same class/method ID for methods */ static bool match(const AMQBody& , const AMQBody& ); }; @@ -78,9 +70,7 @@ enum BodyTypes { METHOD_BODY = 1, HEADER_BODY = 2, CONTENT_BODY = 3, - HEARTBEAT_BODY = 8, - COMMAND_BODY = 100+amqp_0_10::COMMAND, - CONTROL_BODY = 100+amqp_0_10::CONTROL + HEARTBEAT_BODY = 8 }; }} // namespace qpid::framing diff --git a/cpp/src/qpid/sys/Shlib.h b/cpp/src/qpid/sys/Shlib.h index debf231125..e2752dc7d6 100644 --- a/cpp/src/qpid/sys/Shlib.h +++ b/cpp/src/qpid/sys/Shlib.h @@ -56,12 +56,6 @@ class Shlib { this->getSymbol(symbol))); } - /** Look up symbol in shared library. */ - template <class T*> - void* getSymbol(const std::string& symbol) { - return getSymbol<T>(symbol.c_str()); - } - private: void* handle; void load(const char* libname); diff --git a/cpp/src/qpid/sys/Time.h b/cpp/src/qpid/sys/Time.h index c87bd6f05b..860fc49097 100644 --- a/cpp/src/qpid/sys/Time.h +++ b/cpp/src/qpid/sys/Time.h @@ -24,6 +24,7 @@ #include <stdint.h> #include <limits> +#include <iosfwd> namespace qpid { namespace sys { @@ -54,6 +55,8 @@ class AbsTime { friend bool operator>(const AbsTime& a, const AbsTime& b); }; +std::ostream& operator << (std::ostream&, const AbsTime&); + class Duration { static int64_t max() { return std::numeric_limits<int64_t>::max(); } int64_t nanosecs; @@ -67,6 +70,7 @@ class Duration { inline operator int64_t() const; }; +std::ostream& operator << (std::ostream&, const Duration&); AbsTime::AbsTime(const AbsTime& t, const Duration& d) : time_ns(d == Duration::max() ? max() : t.time_ns+d.nanosecs) diff --git a/cpp/src/qpid/sys/posix/Time.cpp b/cpp/src/qpid/sys/posix/Time.cpp index ac63a3d038..b2b7a81130 100644 --- a/cpp/src/qpid/sys/posix/Time.cpp +++ b/cpp/src/qpid/sys/posix/Time.cpp @@ -22,7 +22,7 @@ #include "PrivatePosix.h" #include "qpid/sys/Time.h" - +#include <ostream> #include <time.h> #include <sys/time.h> @@ -40,7 +40,7 @@ AbsTime AbsTime::now() { struct timespec& toTimespec(struct timespec& ts, const Duration& t) { ts.tv_sec = t / TIME_SEC; ts.tv_nsec = t % TIME_SEC; - return ts; + return ts; } struct timeval& toTimeval(struct timeval& tv, const Duration& t) { @@ -53,5 +53,29 @@ Duration toTime(const struct timespec& ts) { return ts.tv_sec*TIME_SEC + ts.tv_nsec; } +std::ostream& operator<<(std::ostream& o, const Duration& d) { + return o << int64_t(d) << "ns"; +} + +std::ostream& operator<<(std::ostream& o, const AbsTime& t) { + static const char * month_abbrevs[] = { + "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" + }; + struct tm * timeinfo; + time_t rawtime(t.timeValue()/TIME_SEC); + timeinfo = localtime (&rawtime); + char time_string[100]; + sprintf ( time_string, + "%d-%s-%02d %02d:%02d:%02d", + 1900 + timeinfo->tm_year, + month_abbrevs[timeinfo->tm_mon], + timeinfo->tm_mday, + timeinfo->tm_hour, + timeinfo->tm_min, + timeinfo->tm_sec + ); + return o << time_string; +} + }} diff --git a/cpp/src/tests/apply.cpp b/cpp/src/tests/apply.cpp index 1b66d8e3b4..450aeac356 100644 --- a/cpp/src/tests/apply.cpp +++ b/cpp/src/tests/apply.cpp @@ -26,7 +26,7 @@ QPID_AUTO_TEST_SUITE(VisitorTestSuite) using namespace qpid::amqp_0_10; -struct GetCode : public ConstApplyFunctor<uint8_t> { +struct GetCode : public ApplyFunctor<uint8_t> { template <class T> uint8_t operator()(const T&) const { return T::CODE; } }; diff --git a/cpp/src/tests/serialize.cpp b/cpp/src/tests/serialize.cpp index 9eaf78ab78..228a4b6e3a 100644 --- a/cpp/src/tests/serialize.cpp +++ b/cpp/src/tests/serialize.cpp @@ -24,6 +24,7 @@ #include "qpid/amqp_0_10/Codec.h" #include "qpid/amqp_0_10/specification.h" #include "qpid/amqp_0_10/ControlHolder.h" +#include "qpid/amqp_0_10/Frame.h" #include <boost/test/test_case_template.hpp> #include <boost/type_traits/is_arithmetic.hpp> @@ -57,6 +58,10 @@ std::ostream& operator<<(std::ostream& out, const AbsTime& t) { } // qpid +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(SerializeTestSuite) @@ -73,12 +78,14 @@ template <class A, class B, class C, class D> struct concat4 { typedef typename typedef mpl::vector<Bit, 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 concat4<IntegralTypes, BinTypes, FloatTypes, FixedSizeClassTypes>::type FixedSizeTypes; +// FIXME aconway 2008-03-07: float encoding +typedef concat3<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. @@ -133,7 +140,9 @@ struct TestMe { bool encoded, decoded; char value; TestMe(char v) : encoded(), decoded(), value(v) {} - template <class S> void encode(S& s) { encoded=true; s(value); } + template <class S> void encode(S& s) const { + const_cast<TestMe*>(this)->encoded=true; s(value); + } template <class S> void decode(S& s) { decoded=true; s(value); } template <class S> void serialize(S& s) { s.split(*this); } }; @@ -174,4 +183,46 @@ BOOST_AUTO_TEST_CASE(testControlEncodeDecode) { BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u); } +BOOST_AUTO_TEST_CASE(testFrameEncodeDecode) { + static const int overhead=12; + string data; + Frame r, c; + char d1[]="abcdefg"; + r.refer(d1, d1+sizeof(d1)); + r.setFlags(Frame::FIRST_FRAME); + r.setType(CONTROL); + r.setChannel(32); + r.setTrack(1); + char d2[]="01234567"; + c.copy(d2, d2+sizeof(d2)); + + BOOST_CHECK_EQUAL(overhead+sizeof(d1), Codec::size(r)); + BOOST_CHECK_EQUAL(overhead+sizeof(d2), Codec::size(c)); + Codec::encode(std::back_inserter(data))(r)(c); + BOOST_CHECK_EQUAL(data.size(), Codec::size(r)+Codec::size(c)); + + FrameHeader fh; + std::string::iterator i = Codec::decode(data.begin())(fh).pos(); + size_t s = fh.size(); + BOOST_CHECK_EQUAL(s, sizeof(d1)); + BOOST_CHECK_EQUAL(std::string(i, i+s), std::string(d1, d1+s)); + + + Frame f1, f2; + Codec::decode(data.begin())(f1)(f2); + BOOST_CHECK_EQUAL(f1.size(), sizeof(d1)); + BOOST_CHECK_EQUAL(std::string(f1.begin(), f1.size()), + std::string(d1, sizeof(d1))); + BOOST_CHECK_EQUAL(f1.size(), r.size()); + BOOST_CHECK_EQUAL(f1.getFlags(), Frame::FIRST_FRAME); + BOOST_CHECK_EQUAL(f1.getType(), CONTROL); + BOOST_CHECK_EQUAL(f1.getChannel(), 32); + BOOST_CHECK_EQUAL(f1.getTrack(), 1); + + BOOST_CHECK_EQUAL(f2.size(), c.size()); + BOOST_CHECK_EQUAL(std::string(f2.begin(), f2.end()), + std::string(d2, d2+sizeof(d2))); + +} + QPID_AUTO_TEST_SUITE_END() |