factor out and treat the attaching of objects separately

this is an advanced feature not required
in the standard buffer usage cycle
This commit is contained in:
Fischlurch 2011-11-25 20:23:31 +01:00
parent ce25be6fa3
commit 55a77bdd73
6 changed files with 196 additions and 36 deletions

View file

@ -57,7 +57,7 @@ namespace engine {
* currently locked and usable by client code
*/
bool
BufferProvider::verifyValidity (BufferDescriptor const& bufferID)
BufferProvider::verifyValidity (BufferDescriptor const& bufferID) const
{
return meta_->isLocked (bufferID);
}
@ -184,6 +184,39 @@ namespace engine {
ERROR_LOG_AND_IGNORE (engine, "releasing a buffer from BufferProvider")
/** @warning this operation locally modifies the metadata entry of a single buffer
* to attach a TypeHandler taking ownership of an object embedded within the buffer.
* The client is responsible for actually placement-constructing the object; moreover
* the client is responsible for any damage done to already existing buffer content.
* @note the buffer must be in locked state and the underlying buffer type must not define
* an non-trivial TypeDescriptor, because there is no clean way of superseding an
* existing TypeDescriptor, which basically is just a functor and possibly
* could perform any operation on buffer clean-up.
* @note EX_STRONG
*/
void
BufferProvider::attachTypeHandler (BuffHandle const& target, BufferDescriptor const& reference)
{
UNIMPLEMENTED ("convenience shortcut to attach/place an object in one sway");
}
/** @internal abort normal lifecycle, reset the underlying buffer and detach from it.
* This allows to break out of normal usage and reset the handle to \em invalid state
* @param invokeDtor if possibly the clean-up function of an TypeHandler registered with
* the buffer metadata should be invoked prior to resetting the metadata state.
* Default is \em not to invoke anything
* @note EX_FREE
*/
void
BufferProvider::emergencyCleanup (BuffHandle const& target, bool invokeDtor)
{
UNIMPLEMENTED ("emergency cleanup");
}
bool
BufferProvider::was_created_by_this_provider (BufferDescriptor const& descr) const
{
@ -231,5 +264,24 @@ namespace engine {
}
void
BuffHandle::emergencyCleanup()
{
descriptor_.provider_->emergencyCleanup(*this); // EX_FREE
pBuffer_ = 0;
}
void
BuffHandle::takeOwnershipFor(BufferDescriptor const& type)
{
if (this->size() < type.determineBufferSize())
throw error::Logic ("insufficient buffer size to hold an instance of that type");
descriptor_.provider_->attachTypeHandler(*this, type); // EX_STRONG
}
} // namespace engine

View file

@ -106,6 +106,11 @@ namespace engine {
template<typename BU>
BuffHandle lockBufferFor ();
/** allow for attaching and owing an object within an already created buffer */
void attachTypeHandler (BuffHandle const& target, BufferDescriptor const& reference);
void emergencyCleanup (BuffHandle const& target, bool invokeDtor =false);
/** describe the kind of buffer managed by this provider */
BufferDescriptor getDescriptorFor(size_t storageSize=0);
@ -118,8 +123,8 @@ namespace engine {
/* === API for BuffHandle internal access === */
bool verifyValidity (BufferDescriptor const&);
size_t getBufferSize (HashVal typeID) const;
bool verifyValidity (BufferDescriptor const&) const;
size_t getBufferSize (HashVal typeID) const;
protected:
BuffHandle buildHandle (HashVal typeID, void* storage, LocalKey const&);

View file

@ -0,0 +1,128 @@
/*
BUFFHANDLE-ATTACH.hpp - Buffer handle extension to attach objects into the buffer
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file buffhandle-attach.hpp
** Extension to allow placing objects right into the buffers, taking ownership.
** This extension is mostly helpful for writing unit-tests, and beyond that for the
** rather unusual case where we need to place an full-blown object into the buffer,
** instead of just plain data. A possible use case for this mechanism is to allow for
** state pre calculation stream, feeding this local state to the individual render node
** embedded into a "state frame". Some effect processors indeed need to maintain state
** beyond the single frame (e.g. averaging, integrating, sound compression), which usually
** is handled by applying an "instance" of that processor to the frames to be calculated
** in a straight sequence.
**
** BuffHandle and the underlying BufferProvider standard implementation support that case
** by attaching an object managing functor to the metadata. This way, the state can live
** directly embedded into the frame and still be accessed like an object. To keep the
** header and compilation footprint low, the implementation of the functions supporting
** this special case was split out of the basic buffhandle.hpp
**
** @see BuffHandle
** @see BufferProviderProtocol_test usage demonstration
*/
#ifndef ENGINE_BUFFHANDLE_ATTACH_H
#define ENGINE_BUFFHANDLE_ATTACH_H
#include "lib/error.hpp"
#include "proc/engine/buffer-provider.hpp"
#include "proc/engine/buffhandle.hpp"
namespace engine {
/* === BuffHandle Implementation === */
#define _EXCEPTION_SAFE_INVOKE(_CTOR_) \
try \
{ \
return *new(pBuffer_) _CTOR_; \
} \
catch(...) \
{ \
emergencyCleanup(); /* EX_FREE */ \
pBuffer_ = 0; \
}
/** convenience shortcut: place and maintain an object within the buffer.
* This operation performs the necessary steps to attach an object;
* if the buffer isn't locked yet, it will do so. Moreover, the created
* object will be owned by the buffer management facilities, i.e. the
* destructor is registered as cleanup function.
* @throw error::Logic in case there is already another TypeHandler registered
* in charge of managing the buffer contents, or when the object to create
* would not fit into this buffer.
*/
template<typename BU>
inline BU&
BuffHandle::create()
{
takeOwnershipFor<BU>();
_EXCEPTION_SAFE_INVOKE (BU());
}
#undef _EXCEPTION_SAFE_INVOKE
/** @internal helper to attach an TypeHandler after-the fact.
* @note this prepares the buffer for placement-creating an embedded object.
* It doesn't actually create an object
* @throw error::Logic in case there is already another TypeHandler registered
* in charge of managing the buffer contents, or when the object to create
* would not fit into this buffer.
*/
template<typename BU>
inline void
BuffHandle::takeOwnershipFor()
{
BufferDescriptor howto_attach_object_automatically
= descriptor_.provider_->getDescriptor<BU>();
takeOwnershipFor (howto_attach_object_automatically); // EX_STRONG
}
/** convenience shortcut: access the buffer contents casted to a specific type.
* @warning this is a \em blind cast, there is no type safety.
* @note clients can utilise the metadata::LocalKey to keep track of some
* specific property of the buffer, like e.g. the type of object.
*/
template<typename BU>
inline BU&
BuffHandle::accessAs()
{
if (!pBuffer_)
throw error::Logic ("buffer not (yet) locked for access by clients"
, LUMIERA_ERROR_LIFECYCLE);
return *reinterpret_cast<BU*> (pBuffer_);
}
} // namespace engine
#endif

View file

@ -174,40 +174,15 @@ namespace engine {
return descriptor_.determineBufferSize();
}
private:
template<typename BU>
void takeOwnershipFor();
void takeOwnershipFor(BufferDescriptor const& type);
void emergencyCleanup();
};
/* === Implementation details === */
/** convenience shortcut: place and maintain an object within the buffer.
* This operation performs the necessary steps to attach an object;
* if the buffer isn't locked yet, it will do so. Moreover, the created
* object will be owned by the buffer management facilities, i.e. the
* destructor is registered as cleanup function.
*/
template<typename BU>
BU&
BuffHandle::create()
{
UNIMPLEMENTED ("convenience shortcut to attach/place an object in one sway");
}
/** convenience shortcut: access the buffer contents casted to a specific type.
* @warning this is a \em blind cast, there is no type safety.
* @note clients can utilise the metadata::LocalKey to keep track of some
* specific property of the buffer, like e.g. the type of object.
*/
template<typename BU>
BU&
BuffHandle::accessAs()
{
if (!pBuffer_)
throw error::Logic ("buffer not (yet) locked for access by clients"
, LUMIERA_ERROR_LIFECYCLE);
return *reinterpret_cast<BU*> (pBuffer_);
}
} // namespace engine

View file

@ -28,7 +28,7 @@
//#include "proc/play/diagnostic-output-slot.hpp"
#include "proc/engine/testframe.hpp"
#include "proc/engine/diagnostic-buffer-provider.hpp"
#include "proc/engine/buffhandle.hpp"
#include "proc/engine/buffhandle-attach.hpp"
#include "proc/engine/bufftable.hpp"
//#include <boost/format.hpp>

View file

@ -24,8 +24,8 @@
#include "lib/error.hpp"
#include "lib/test/run.hpp"
#include "proc/engine/tracking-heap-block-provider.hpp"
#include "proc/engine/buffhandle-attach.hpp"
#include "proc/engine/testframe.hpp"
#include "proc/engine/buffhandle.hpp"
#include <cstdlib>
#include <vector>