From 55a77bdd73e304d79efdcfdcf55127e50ed8c728 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 25 Nov 2011 20:23:31 +0100 Subject: [PATCH] factor out and treat the attaching of objects separately this is an advanced feature not required in the standard buffer usage cycle --- src/proc/engine/buffer-provider.cpp | 54 +++++++- src/proc/engine/buffer-provider.hpp | 9 +- src/proc/engine/buffhandle-attach.hpp | 128 ++++++++++++++++++ src/proc/engine/buffhandle.hpp | 37 +---- .../engine/buffer-provider-protocol-test.cpp | 2 +- .../tracking-heap-block-provider-test.cpp | 2 +- 6 files changed, 196 insertions(+), 36 deletions(-) create mode 100644 src/proc/engine/buffhandle-attach.hpp diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp index 6c33104b0..449b41370 100644 --- a/src/proc/engine/buffer-provider.cpp +++ b/src/proc/engine/buffer-provider.cpp @@ -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 diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp index b52948911..4fff36efe 100644 --- a/src/proc/engine/buffer-provider.hpp +++ b/src/proc/engine/buffer-provider.hpp @@ -106,6 +106,11 @@ namespace engine { template 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&); diff --git a/src/proc/engine/buffhandle-attach.hpp b/src/proc/engine/buffhandle-attach.hpp new file mode 100644 index 000000000..4f5b94b55 --- /dev/null +++ b/src/proc/engine/buffhandle-attach.hpp @@ -0,0 +1,128 @@ +/* + BUFFHANDLE-ATTACH.hpp - Buffer handle extension to attach objects into the buffer + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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 + inline BU& + BuffHandle::create() + { + takeOwnershipFor(); + _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 + inline void + BuffHandle::takeOwnershipFor() + { + BufferDescriptor howto_attach_object_automatically + = descriptor_.provider_->getDescriptor(); + 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 + inline BU& + BuffHandle::accessAs() + { + if (!pBuffer_) + throw error::Logic ("buffer not (yet) locked for access by clients" + , LUMIERA_ERROR_LIFECYCLE); + return *reinterpret_cast (pBuffer_); + } + + + +} // namespace engine +#endif diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp index 32a47fc2c..a035f3a69 100644 --- a/src/proc/engine/buffhandle.hpp +++ b/src/proc/engine/buffhandle.hpp @@ -174,40 +174,15 @@ namespace engine { return descriptor_.determineBufferSize(); } + private: + template + 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 - 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 - BU& - BuffHandle::accessAs() - { - if (!pBuffer_) - throw error::Logic ("buffer not (yet) locked for access by clients" - , LUMIERA_ERROR_LIFECYCLE); - return *reinterpret_cast (pBuffer_); - } - } // namespace engine diff --git a/tests/components/proc/engine/buffer-provider-protocol-test.cpp b/tests/components/proc/engine/buffer-provider-protocol-test.cpp index 6732668b6..b7cfd338b 100644 --- a/tests/components/proc/engine/buffer-provider-protocol-test.cpp +++ b/tests/components/proc/engine/buffer-provider-protocol-test.cpp @@ -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 diff --git a/tests/components/proc/engine/tracking-heap-block-provider-test.cpp b/tests/components/proc/engine/tracking-heap-block-provider-test.cpp index 2d48be480..62ff32412 100644 --- a/tests/components/proc/engine/tracking-heap-block-provider-test.cpp +++ b/tests/components/proc/engine/tracking-heap-block-provider-test.cpp @@ -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 #include