diff options
Diffstat (limited to 'qpid/cpp/src/qpid/Serializer.h')
-rw-r--r-- | qpid/cpp/src/qpid/Serializer.h | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/qpid/cpp/src/qpid/Serializer.h b/qpid/cpp/src/qpid/Serializer.h new file mode 100644 index 0000000000..a8ded9f5e0 --- /dev/null +++ b/qpid/cpp/src/qpid/Serializer.h @@ -0,0 +1,197 @@ +#ifndef QPID_SERIALIZER_H +#define QPID_SERIALIZER_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 <limits> +#include <algorithm> +#include "qpid/Exception.h" // FIXME aconway 2008-04-03: proper exception class. + +namespace qpid { + +/** + * Overload for types that do not provide a serialize() member. + * It should retrun a wrapper holding a reference to t that implements + * serialize() + */ +template <class T> T& serializable(T& t) { return t; } + +/** Serialize std::pair */ +template <class T, class U> struct SerializablePair { + std::pair<T,U>& value; + SerializablePair(std::pair<T,U>& x) : value(x) {} + template <class S> void serialize(S& s) { s(value.first)(value.second); } +}; + +template <class T, class U> +SerializablePair<T,U> serializable(std::pair<T,U>& p) { + return SerializablePair<T,U>(p); +} + +/** + * Base class for all serializers. + * Derived serializers inherit from either Encoder or Decoder. + * Serializers can be used as functors or static_visitors. + */ +template <class Derived> class Serializer { + public: + /** Temporarily set a lower relative limit on the serializer */ + class ScopedLimit { + public: + ScopedLimit(Serializer& s, size_t l) + : serializer(s), save(serializer.setLimit(l)) {} + + ~ScopedLimit() { serializer.setAbsLimit(save); } + + private: + Serializer& serializer; + size_t save; + }; + + static size_t maxLimit() { return std::numeric_limits<size_t>::max(); } + + Serializer() : bytes(0), limit(maxLimit()) {} + + typedef Derived& result_type; // unary functor requirement. + + /** Wrapper functor to pass serializer functors by reference. */ + template <class S> struct Ref { + typedef typename S::result_type result_type; + S& s; + Ref(S& ss) : s(ss) {} + template <class T> result_type operator()(T& x) { return s(x); } + template <class T> result_type operator()(const T& x) { return s(x); } + }; + + /** Reference wrapper to pass serializers by reference, + * e.g. to std:: functions that take functors. + */ + template <class S> static Ref<S> ref(S& s) { return Ref<S>(s); } + + /** Generic rule to serialize an iterator range */ + template <class Iter> Derived& operator()(Iter begin, Iter end) { + std::for_each(begin, end, ref(this->self())); + return self(); + } + + /** Set limit relative to current position. + * @return old absolute limit. + */ + size_t setLimit(size_t n) { + size_t l=limit; + limit = bytes+n; + return l; + } + + /** Get the max number of bytes that can be processed under the + * current limit. + */ + size_t bytesRemaining() const { + return limit - bytes; + } + /** Set absolute limit. */ + void setAbsLimit(size_t n) { + limit = n; + if (bytes > limit) + throw Exception("Framing error: data overrun"); // FIXME aconway 2008-04-03: proper exception. + } + + protected: + Derived& self() { return *static_cast<Derived*>(this); } + void addBytes(size_t n) { + size_t newBytes=bytes+n; + if (newBytes > limit) + throw Exception("Framing error: data overrun"); // FIXME aconway 2008-04-03: proper exception. + bytes = newBytes; + } + + private: + void checkLimit() { + } + + size_t bytes; // how many bytes serialized. + size_t limit; // bytes may not exceed this limit. +}; + +/** + * Base class for encoders, provides generic encode functions. + * + * A derived encoder must provide operator(const T&) to encode all + * primitive types T. + */ +template <class Derived> class EncoderBase : public Serializer<Derived> { + public: + using Serializer<Derived>::operator(); + using Serializer<Derived>::self; + + /** Default op() for non-primitive types. */ + template <class T> Derived& operator()(const T& t) { + serializable(const_cast<T&>(t)).serialize(self()); return self(); + } + + /** Split serialize() into encode()/decode() */ + template <class T> Derived& split(const T& t) { + t.encode(self()); return self(); + } +}; + +/** + * Base class for decoders, provides generic decode functions. + * + * A derived encoder must provide operator(T&) to encode all + * primitive types T. + */ +template <class Derived> class DecoderBase : public Serializer<Derived> { + public: + using Serializer<Derived>::operator(); + using Serializer<Derived>::self; + + /** Default op() for non-primitive types. */ + 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(); + } +}; + +/** Serialize a type by converting it to/from another type. + * To serialize type Foo by converting to/from type Bar create + * a serializable() overload like this: + * + * SerializeAs<Foo,Bar> serializable(Foo& t) { return SerializeAs<Foo,Bar>(t); } + */ +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=Type(x); } +}; + +} // namespace qpid + +#endif /*!QPID_SERIALIZER_H*/ |