summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qpid/cpp/src/qpid/Serializer.h1
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Codec.h9
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/PackedCodec.h79
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Packer.h148
-rw-r--r--qpid/cpp/src/tests/amqp_0_10/serialize.cpp62
5 files changed, 204 insertions, 95 deletions
diff --git a/qpid/cpp/src/qpid/Serializer.h b/qpid/cpp/src/qpid/Serializer.h
index 6b67a4ccf8..2660fb2b3e 100644
--- a/qpid/cpp/src/qpid/Serializer.h
+++ b/qpid/cpp/src/qpid/Serializer.h
@@ -167,6 +167,7 @@ template <class Derived> class DecoderBase : public Serializer<Derived> {
/** Default op() for non-primitive types. */
template <class T> Derived& operator()(T& t) {
+
serializable(t).serialize(self()); return self();
}
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Codec.h b/qpid/cpp/src/qpid/amqp_0_10/Codec.h
index 622032fddc..c4909e7cbd 100644
--- a/qpid/cpp/src/qpid/amqp_0_10/Codec.h
+++ b/qpid/cpp/src/qpid/amqp_0_10/Codec.h
@@ -54,16 +54,14 @@ struct Codec {
public:
typedef EncoderBase<Encoder<OutIter> > Base;
typedef OutIter Iterator;
-
+
Encoder(OutIter o, size_t limit=Base::maxLimit()) : out(o) {
this->setLimit(limit);
}
using EncoderBase<Encoder<OutIter> >::operator();
- // FIXME aconway 2008-03-10: wrong encoding, need packing support
Encoder& operator()(bool x) { raw(x); return *this;}
-
Encoder& operator()(char x) { raw(x); return *this; }
Encoder& operator()(int8_t x) { raw(x); return *this; }
Encoder& operator()(uint8_t x) { raw(x); return *this; }
@@ -79,7 +77,6 @@ struct Codec {
Encoder& operator()(float x) { return endian(x); }
Encoder& operator()(double x) { return endian(x); }
-
void raw(const void* p, size_t n) {
this->addBytes(n);
out = std::copy((const char*)p, (const char*)p+n, out);
@@ -103,7 +100,7 @@ struct Codec {
public:
typedef DecoderBase<Decoder<InIter> > Base;
typedef InIter Iterator;
-
+
Decoder(InIter i, size_t limit=Base::maxLimit()) : in(i) {
this->setLimit(limit);
}
@@ -135,7 +132,7 @@ struct Codec {
}
void raw(char &b) { this->addBytes(1); b=*in++; }
-
+
InIter pos() const { return in; }
private:
diff --git a/qpid/cpp/src/qpid/amqp_0_10/PackedCodec.h b/qpid/cpp/src/qpid/amqp_0_10/PackedCodec.h
deleted file mode 100644
index 408c20cb0b..0000000000
--- a/qpid/cpp/src/qpid/amqp_0_10/PackedCodec.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef QPID_AMQP_0_10_PACKEDCODEC_H
-#define QPID_AMQP_0_10_PACKEDCODEC_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 "Codec.h"
-
-namespace qpid {
-namespace amqp_0_10 {
-
-/**
- * Packed encoding/decoding. Process or ignore fields based on
- * packing bits.
- */
-struct PackedCodec {
- template <class Bits, class InnerDecoder>
- class Decoder :
- public DecoderBase<PackedCodec::Decoder<Bits, InnerDecoder> >
- {
- public:
- Decoder(Bits b, const InnerDecoder& d)
- : bits(b), decode(const_cast<InnerDecoder&>(d)) {}
-
- // Decode if pack bit is set.
- template<class T> Decoder& operator()(T& t) {
- if (bits & 1)
- decode(t);
- else
- t = T(); // FIXME aconway 2008-04-02: see below
- bits >>= 1;
- return *this;
- }
- Bits bits;
- InnerDecoder& decode;
- };
-
- template <class Bits, class InnerDecoder>
- static Decoder<Bits, InnerDecoder> decode(Bits b, const InnerDecoder& d) {
- return Decoder<Bits, InnerDecoder>(b,d);
- }
-
- // FIXME aconway 2008-04-02: Incorrect packed semantics.
- // Current implementation is:
- // - decode value if packed bit set, else default initialize value.
- // - encode always encode values
- // - size count all values.
- // Correct implementation:
- // - optional value of type T is mapped to boost::optional<T>
- // - decode value if packed bit set, else value=boost::none
- // - PackedCodec::Encoder collect packing bits (1 unless == boost::none)
- // Codec::Encoder optional skip if none
- // - size: count only non-none values.
- // Note we don't encode/decodde the pack bits themselves here, that
- // happens in the Holder. Holders handle size, count & pack attributes.
-};
-
-
-}} // namespace qpid::amqp_0_10
-
-#endif /*!QPID_AMQP_0_10_PACKEDCODEC_H*/
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Packer.h b/qpid/cpp/src/qpid/amqp_0_10/Packer.h
new file mode 100644
index 0000000000..1005ef34aa
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp_0_10/Packer.h
@@ -0,0 +1,148 @@
+#ifndef QPID_PACKER_H
+#define QPID_PACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/optional.hpp>
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/** Serialization for optional values */
+template <class T> struct SerializableOptional {
+ boost::optional<T>& optional;
+ SerializableOptional(boost::optional<T>& x) : optional(x) {}
+ template <class S> void serialize(S& s) {
+ if (optional)
+ s(*optional);
+ }
+};
+
+}}
+
+
+namespace boost { // For argument dependent lookup.
+
+template <class T>
+qpid::amqp_0_10::SerializableOptional<T> serializable(boost::optional<T>& x) {
+ return qpid::amqp_0_10::SerializableOptional<T>(x);
+}
+
+} // namespace boost
+
+namespace qpid {
+namespace amqp_0_10 {
+
+/** "Encoder" that encodes a struct as a set of bit flags
+ * for all non-empty members.
+ */
+class PackBits {
+ public:
+ PackBits() : bit(1), bits(0) {}
+
+ void setBit() { bits |= bit; bit <<= 1; }
+ void skipBit() { bit <<= 1; }
+
+ uint32_t getBits() { return bits; }
+
+ template <class T> PackBits& operator()(const T&) { setBit(); return *this; }
+
+ template <class T> PackBits& operator()(const boost::optional<T>& opt) {
+ opt ? setBit() : skipBit(); return *this;
+ }
+
+ private:
+ uint32_t bit;
+ uint32_t bits;
+};
+
+/** Bit mask to encode a packable struct */
+template<class T> uint32_t packBits(const T& t) {
+ PackBits pack;
+ const_cast<T&>(t).serialize(pack);
+ return pack.getBits();
+}
+
+template <class Decoder, class Bits>
+class PackedDecoder {
+ public:
+ PackedDecoder(Decoder& d, Bits b) : decode(d), bits(b) {}
+
+ template <class T> PackedDecoder& operator()(T& t) { decode(t); return *this; }
+
+ template <class T> PackedDecoder& operator()(boost::optional<T>& opt) {
+ if (bits & 1) {
+ opt = T();
+ decode(*opt);
+ }
+ else
+ opt = boost::none;
+ bits >>= 1;
+ return *this;
+ }
+
+ private:
+ Decoder& decode;
+ Bits bits;
+};
+
+/** Metafunction to compute type to contain pack bits. */
+template <int PackBytes> struct PackBitsType;
+template <> struct PackBitsType<1> { typedef uint8_t type; };
+template <> struct PackBitsType<2> { typedef uint16_t type; };
+template <> struct PackBitsType<4> { typedef uint32_t type; };
+
+/**
+ * Helper to serialize packed structs.
+ */
+template <class T> class Packer
+{
+ public:
+ typedef typename PackBitsType<T::PACK>::type Bits;
+
+ Packer(T& t) : data(t) {}
+
+ template <class S> void serialize(S& s) { s.split(*this); }
+
+ template <class S> void encode(S& s) const {
+ Bits bits = packBits(data);
+ s(bits);
+ data.serialize(s);
+ }
+
+ template <class S> void decode(S& s) {
+ Bits bits;
+ s(bits);
+ PackedDecoder<S, Bits> decode(s, bits);
+ data.serialize(decode);
+ }
+
+
+ private:
+ T& data;
+};
+
+}} // namespace qpid::amqp_0_10
+
+
+
+#endif /*!QPID_PACKER_H*/
diff --git a/qpid/cpp/src/tests/amqp_0_10/serialize.cpp b/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
index a6cb28caee..dcf27e457a 100644
--- a/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
+++ b/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
@@ -20,9 +20,9 @@
*/
#include "unit_test.h"
+#include "qpid/amqp_0_10/Packer.h"
#include "qpid/amqp_0_10/built_in_types.h"
#include "qpid/amqp_0_10/Codec.h"
-#include "qpid/amqp_0_10/PackedCodec.h"
#include "qpid/amqp_0_10/specification.h"
#include "qpid/amqp_0_10/ControlHolder.h"
#include "qpid/amqp_0_10/Frame.h"
@@ -31,12 +31,14 @@
#include <boost/test/test_case_template.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/utility/enable_if.hpp>
+#include <boost/optional.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/back_inserter.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/empty_sequence.hpp>
#include <iterator>
#include <string>
+#include <sstream>
#include <iostream>
#include <netinet/in.h>
@@ -254,15 +256,55 @@ BOOST_AUTO_TEST_CASE(testFrameEncodeDecode) {
}
-BOOST_AUTO_TEST_CASE(testPackedCodec) {
- int i=-1, j=-1, k=-1, l=-1;
- std::string data;
- Codec::encode(std::back_inserter(data))(1)(3);
- PackedCodec::decode(0x5, Codec::decode(data.begin()))(i)(j)(k)(l);
- BOOST_CHECK_EQUAL(i, 1);
- BOOST_CHECK_EQUAL(j, 0);
- BOOST_CHECK_EQUAL(k, 3);
- BOOST_CHECK_EQUAL(l, 0);
+struct DummyPacked {
+ static const uint8_t PACK=1;
+ boost::optional<char> i, j;
+ char k;
+ DummyPacked(char a=0, char b=0, char c=0) : i(a), j(b), k(c) {}
+ template <class S> void serialize(S& s) { s(i)(j)(k); }
+
+ string str() const {
+ ostringstream os;
+ os << i << j << k;
+ return os.str();
+ }
+};
+
+Packer<DummyPacked> serializable(DummyPacked& d) { return Packer<DummyPacked>(d); }
+
+BOOST_AUTO_TEST_CASE(testPackBits) {
+ DummyPacked d('a','b','c');
+ BOOST_CHECK_EQUAL(packBits(d), 7u);
+ d.j = boost::none;
+ BOOST_CHECK_EQUAL(packBits(d), 5u);
+}
+
+
+BOOST_AUTO_TEST_CASE(testPacked) {
+ string data;
+
+ Codec::encode(back_inserter(data))('a')(boost::optional<char>('b'))(boost::optional<char>())('c');
+ BOOST_CHECK_EQUAL(data, "abc");
+ data.clear();
+
+ DummyPacked dummy('a','b','c');
+
+ Codec::encode(back_inserter(data))(dummy);
+ BOOST_CHECK_EQUAL(data.size(), 4u);
+ BOOST_CHECK_EQUAL(data, string("\007abc"));
+ data.clear();
+
+ dummy.i = boost::none;
+ Codec::encode(back_inserter(data))(dummy);
+ BOOST_CHECK_EQUAL(data, string("\6bc"));
+ data.clear();
+
+ const char* missing = "\5xy";
+ Codec::decode(missing)(dummy);
+ BOOST_CHECK(dummy.i);
+ BOOST_CHECK_EQUAL(dummy.i, 'x');
+ BOOST_CHECK(!dummy.j);
+ BOOST_CHECK_EQUAL(dummy.k, 'y');
}
QPID_AUTO_TEST_SUITE_END()