#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 #include #include "qpid/amqp_0_10/built_in_types.h" namespace qpid { namespace amqp_0_10 { /** Serialization for optional values */ template struct SerializableOptional { boost::optional& optional; SerializableOptional(boost::optional& x) : optional(x) {} template void serialize(S& s) { if (optional) s(*optional); } }; }} namespace boost { // For argument dependent lookup. template qpid::amqp_0_10::SerializableOptional serializable(boost::optional& x) { return qpid::amqp_0_10::SerializableOptional(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(bool b) { if (b) bits |= bit; bit <<= 1; } uint32_t getBits() { return bits; } /** The bit is always set for non-optional values. */ template PackBits& operator()(const T&) { setBit(1); return *this; } /** For optional values the bit is set if the value is present. */ template PackBits& operator()(const boost::optional& opt) { setBit(opt); return *this; } /** Bits are special optional values */ PackBits& operator()(Bit b) { setBit(b); return *this; } private: uint32_t bit; uint32_t bits; }; /** Bit mask to encode a packable struct */ template uint32_t packBits(const T& t) { PackBits pack; const_cast(t).serialize(pack); return pack.getBits(); } /** Decode members enabled by Bits */ template class PackedDecoder { public: PackedDecoder(Decoder& d, Bits b) : decode(d), bits(b) {} template PackedDecoder& operator()(T& t) { if (bits & 1) decode(t); else t = T(); // FIXME aconway 2008-04-10: When we have all optionals // represented by boost::optional the line above should be: // throw CommandInvalidException("A required value was omitted."); bits >>= 1; return *this; } template PackedDecoder& operator()(boost::optional& 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 struct UintOfSize; template <> struct UintOfSize<1> { typedef uint8_t type; }; template <> struct UintOfSize<2> { typedef uint16_t type; }; template <> struct UintOfSize<4> { typedef uint32_t type; }; /** * Helper to serialize packed structs. */ template class Packer { public: typedef typename UintOfSize::type Bits; Packer(T& t) : data(t) {} template void serialize(S& s) { s.split(*this); } template void encode(S& s) const { Bits bits = packBits(data); s.littleEnd(bits); data.serialize(s); } template void decode(S& s) { Bits bits; s.littleEnd(bits); PackedDecoder decode(s, bits); data.serialize(decode); } protected: T& data; }; template struct SizedPacker : public Packer { typedef typename UintOfSize::type Size; SizedPacker(T& t) : Packer(t) {} template void serialize(S& s) { s.split(*this); } template void encode(S& s) const { Codec::Size sizer; this->data.serialize(sizer); Size size=size_t(sizer)+T::PACK; // Size with pack bits. s(size); Packer::encode(s); } template void decode(S& s) { Size size; s(size); typename S::ScopedLimit l(s, size); Packer::decode(s); } }; template struct SizedPacker : public Packer { SizedPacker(T& t) : Packer(t) {} }; }} // namespace qpid::amqp_0_10 #endif /*!QPID_PACKER_H*/