blob: 5c84384ad7b97639a715def944bcded412da55d1 [file] [log] [blame]
#ifndef QPID_FRAMING_BLOB_H
#define QPID_FRAMING_BLOB_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/static_assert.hpp>
#include <boost/aligned_storage.hpp>
#include <boost/checked_delete.hpp>
#include <boost/utility/typed_in_place_factory.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/version.hpp>
#include <new>
#include <assert.h>
namespace qpid {
namespace framing {
using boost::in_place;
using boost::typed_in_place_factory_base;
/** 0-arg typed_in_place_factory, missing in pre-1.35 boost. */
#if (BOOST_VERSION < 103500)
template <class T>
struct typed_in_place_factory0 : public typed_in_place_factory_base {
typedef T value_type ;
void apply ( void* address ) const { new (address) T(); }
};
/** 0-arg in_place<T>() function, missing from boost. */
template<class T>
typed_in_place_factory0<T> in_place() { return typed_in_place_factory0<T>(); }
#endif
template <class T, class R=void>
struct EnableInPlace
: public boost::enable_if<boost::is_base_and_derived<
typed_in_place_factory_base, T>,
R>
{};
template <class T, class R=void>
struct DisableInPlace
: public boost::disable_if<boost::is_base_and_derived<
typed_in_place_factory_base, T>,
R>
{};
template <class T> struct BlobHelper {
static void destroy(void* ptr) { static_cast<T*>(ptr)->~T(); }
static void copy(void* dest, const void* src) {
new (dest) T(*static_cast<const T*>(src));
}
};
template <> struct BlobHelper<void> {
static void destroy(void*);
static void copy(void* to, const void* from);
};
/**
* A Blob is a chunk of memory which can contain a single object at
* a time-arbitrary type, provided sizeof(T)<=blob.size(). Using Blobs
* ensures proper construction and destruction of its contents,
* and proper copying between Blobs, but nothing else.
*
* In particular you must ensure that the Blob is big enough for its
* contents and must know the type of object in the Blob to cast get().
*
* If BaseType is specified then only an object that can be
* static_cast to BaseType may be stored in the Blob.
*/
template <size_t Size, class BaseType=void>
class Blob
{
boost::aligned_storage<Size> store;
BaseType* basePtr;
void (*destroy)(void*);
void (*copy)(void*, const void*);
template <class T>void setType() {
BOOST_STATIC_ASSERT(sizeof(T) <= Size);
destroy=&BlobHelper<T>::destroy;
copy=&BlobHelper<T>::copy;
// Base pointer may be offeset from store.address()
basePtr = reinterpret_cast<T*>(store.address());
}
void initialize() {
destroy=&BlobHelper<void>::destroy;
copy=&BlobHelper<void>::copy;
basePtr=0;
}
template<class Factory>
typename EnableInPlace<Factory>::type apply(const Factory& factory)
{
typedef typename Factory::value_type T;
assert(empty());
factory.apply(store.address());
setType<T>();
}
void assign(const Blob& b) {
assert(empty());
if (b.empty()) return;
b.copy(this->store.address(), b.store.address());
copy = b.copy;
destroy = b.destroy;
basePtr = reinterpret_cast<BaseType*>(
((char*)this)+ ((const char*)(b.basePtr) - (const char*)(&b)));
}
public:
/** Construct an empty Blob. */
Blob() { initialize(); }
/** Copy a Blob. */
Blob(const Blob& b) { initialize(); assign(b); }
/** Construct from in_place constructor. */
template<class InPlace>
Blob(const InPlace & expr, typename EnableInPlace<InPlace>::type* =0) {
initialize(); apply(expr);
}
/** Construct by copying an object constructor. */
template<class T>
Blob(const T & t, typename DisableInPlace<T>::type* =0) {
initialize(); apply(in_place<T>(t));
}
~Blob() { clear(); }
/** Assign from another Blob. */
Blob& operator=(const Blob& b) {
clear();
assign(b);
return *this;
}
/** Assign from an in_place constructor expression. */
template<class InPlace>
typename EnableInPlace<InPlace,Blob&>::type operator=(const InPlace& expr) {
clear(); apply(expr); return *this;
}
/** Assign from an object of type T. */
template <class T>
typename DisableInPlace<T, Blob&>::type operator=(const T& x) {
clear(); apply(in_place<T>(x)); return *this;
}
/** Get pointer to Blob contents, returns 0 if empty. */
BaseType* get() { return basePtr; }
/** Get pointer to Blob contents, returns 0 if empty. */
const BaseType* get() const { return basePtr; }
/** Destroy the object in the Blob making it empty. */
void clear() {
void (*oldDestroy)(void*) = destroy;
initialize();
oldDestroy(store.address());
}
bool empty() const { return destroy==BlobHelper<void>::destroy; }
static size_t size() { return Size; }
};
}} // namespace qpid::framing
#endif /*!QPID_FRAMING_BLOB_H*/