Author: aconway
Date: Mon Apr  7 13:12:31 2008
New Revision: 645663

URL: http://svn.apache.org/viewvc?rev=645663&view=rev
Log:

Encoding/decoding for packed structs and optional members.

Added:
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h   (with props)
Removed:
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/PackedCodec.h
Modified:
    incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h
    incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h?rev=645663&r1=645662&r2=645663&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/Serializer.h Mon Apr  7 13:12:31 2008
@@ -167,6 +167,7 @@
 
     /** Default op() for non-primitive types. */
     template <class T> Derived& operator()(T& t) {
+
         serializable(t).serialize(self()); return self();
     }
 

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h?rev=645663&r1=645662&r2=645663&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Codec.h Mon Apr  7 
13:12:31 2008
@@ -54,16 +54,14 @@
       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 @@
         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 @@
       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 @@
         }
 
         void raw(char &b) { this->addBytes(1); b=*in++; }
-            
+
         InIter pos() const { return in; }
 
       private:

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h?rev=645663&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h Mon Apr  7 
13:12:31 2008
@@ -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*/

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Packer.h
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp?rev=645663&r1=645662&r2=645663&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/serialize.cpp Mon Apr  7 
13:12:31 2008
@@ -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(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()


Reply via email to