From d48dc3b025d3c0064aa2f6650609e93a5b3bfcdf Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 21 Oct 2011 02:41:20 +0200 Subject: [PATCH 01/68] fix glitch in test definition uncovered since rand() is now properly seeded prior to each testsuite run --- src/proc/mobject/test-dummy-mobject.hpp | 2 +- tests/43session.tests | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/proc/mobject/test-dummy-mobject.hpp b/src/proc/mobject/test-dummy-mobject.hpp index 14542b629..325244691 100644 --- a/src/proc/mobject/test-dummy-mobject.hpp +++ b/src/proc/mobject/test-dummy-mobject.hpp @@ -90,7 +90,7 @@ namespace test { string display(Symbol name) const { - static format fmt("%s(ID=%4d)"); + static format fmt("%s(ID=%03d)"); return boost::str(fmt % name % this->id_); } }; diff --git a/tests/43session.tests b/tests/43session.tests index dd86bcc31..0ecfa5964 100644 --- a/tests/43session.tests +++ b/tests/43session.tests @@ -96,9 +96,9 @@ out: Placement.+mobject.+test.+TestSubMO1.+. use-cnt=1 .* out: Placement.+mobject.+test.+TestSubMO2.+. use-cnt=1 .* out: Placement.+mobject.+test.+TestSubMO21.+ use-cnt=2 .* out: Placement.+mobject.+session.+Clip.+.... use-cnt=2 .* -out: TestSubMO1\(ID= [0-9]{3}\) -out: TestSubMO2\(ID= [0-9]{3}\) -out: TestSubMO21\(ID= [0-9]{3}\) +out: TestSubMO1\(ID=[0-9]{3}\) +out: TestSubMO2\(ID=[0-9]{3}\) +out: TestSubMO21\(ID=[0-9]{3}\) out: specialAPI() out: pID\(\w{6,16}\) END From 9a1987ba241c65fb3e5e90c35aae1da5122674ad Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Fri, 21 Oct 2011 02:56:10 -0500 Subject: [PATCH 02/68] Ticket #796: Switch GUI from boost::shared_ptr to std::tr1::shared_ptr. ParentTrack and TimelineLayoutHelper need to be fixed --- src/gui/model/clip-track.cpp | 6 +-- src/gui/model/clip-track.hpp | 4 +- src/gui/model/parent-track.cpp | 27 ++++++++----- src/gui/model/parent-track.hpp | 24 +++++------ src/gui/model/project.cpp | 4 +- src/gui/model/project.hpp | 4 +- src/gui/model/sequence.cpp | 2 +- src/gui/model/track.cpp | 8 ++-- src/gui/model/track.hpp | 8 ++-- src/gui/panels/timeline-panel.cpp | 4 +- src/gui/panels/timeline-panel.hpp | 16 +++----- src/gui/widgets/timeline-widget.cpp | 19 ++++----- src/gui/widgets/timeline-widget.hpp | 40 +++++++++---------- .../widgets/timeline/timeline-arrow-tool.cpp | 14 +++---- .../widgets/timeline/timeline-arrow-tool.hpp | 2 +- src/gui/widgets/timeline/timeline-body.cpp | 6 +-- src/gui/widgets/timeline/timeline-body.hpp | 6 +-- .../widgets/timeline/timeline-clip-track.cpp | 14 +++---- .../widgets/timeline/timeline-clip-track.hpp | 10 ++--- src/gui/widgets/timeline/timeline-clip.cpp | 6 +-- src/gui/widgets/timeline/timeline-clip.hpp | 6 +-- src/gui/widgets/timeline/timeline-entity.cpp | 2 +- src/gui/widgets/timeline/timeline-entity.hpp | 7 ++-- .../widgets/timeline/timeline-group-track.cpp | 2 +- .../widgets/timeline/timeline-group-track.hpp | 2 +- .../timeline/timeline-header-container.cpp | 6 +-- .../timeline/timeline-header-container.hpp | 10 ++--- .../timeline/timeline-header-widget.cpp | 3 +- .../widgets/timeline/timeline-ibeam-tool.cpp | 2 +- .../timeline/timeline-layout-helper.cpp | 16 ++++---- .../timeline/timeline-layout-helper.hpp | 22 +++++----- src/gui/widgets/timeline/timeline-ruler.cpp | 2 +- src/gui/widgets/timeline/timeline-ruler.hpp | 4 +- src/gui/widgets/timeline/timeline-state.cpp | 6 +-- src/gui/widgets/timeline/timeline-state.hpp | 6 +-- src/gui/widgets/timeline/timeline-tool.cpp | 2 +- src/gui/widgets/timeline/timeline-tool.hpp | 2 +- src/gui/widgets/timeline/timeline-track.cpp | 6 +-- src/gui/widgets/timeline/timeline-track.hpp | 8 ++-- .../widgets/timeline/timeline-zoom-scale.cpp | 6 +-- .../widgets/timeline/timeline-zoom-scale.hpp | 10 ++--- src/gui/window-manager.cpp | 3 +- src/gui/window-manager.hpp | 5 +-- 43 files changed, 179 insertions(+), 183 deletions(-) diff --git a/src/gui/model/clip-track.cpp b/src/gui/model/clip-track.cpp index 95ddd8ac0..827aec0b9 100644 --- a/src/gui/model/clip-track.cpp +++ b/src/gui/model/clip-track.cpp @@ -24,7 +24,7 @@ #include "clip.hpp" -#include +using namespace std::tr1; namespace gui { namespace model { @@ -33,7 +33,7 @@ namespace model { { // TEST CODE: add a clip to the track - boost::shared_ptr modelClip(new model::Clip()); + shared_ptr modelClip(new model::Clip()); modelClip->setName("Clip Name"); clips.push_back(modelClip); @@ -50,7 +50,7 @@ namespace model { return os.str(); } - lumiera::observable_list< boost::shared_ptr >& + lumiera::observable_list< shared_ptr >& ClipTrack::getClipList() { return clips; diff --git a/src/gui/model/clip-track.hpp b/src/gui/model/clip-track.hpp index 288b41bf4..e115ed415 100644 --- a/src/gui/model/clip-track.hpp +++ b/src/gui/model/clip-track.hpp @@ -53,12 +53,12 @@ namespace model { /** * Gets the list of clips associated with this track. */ - lumiera::observable_list< boost::shared_ptr >& + lumiera::observable_list< std::tr1::shared_ptr >& getClipList(void); private: - lumiera::observable_list< boost::shared_ptr > clips; + lumiera::observable_list< std::tr1::shared_ptr > clips; }; diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index 874c7e9d5..d20a1adc3 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -24,6 +24,7 @@ #include using namespace boost; +using std::tr1::shared_ptr; namespace gui { namespace model { @@ -32,13 +33,13 @@ ParentTrack::ParentTrack() { } -const std::list< boost::shared_ptr >& +const std::list< std::tr1::shared_ptr >& ParentTrack::get_child_tracks() const { return tracks.get_list(); } -lumiera::observable_list< boost::shared_ptr >& +lumiera::observable_list< std::tr1::shared_ptr >& ParentTrack::get_child_track_list() { return tracks; @@ -52,11 +53,11 @@ ParentTrack::can_host_children() const bool ParentTrack::remove_descendant_track( - const boost::shared_ptr track) + const std::tr1::shared_ptr track) { REQUIRE(track); - boost::shared_ptr parent = + std::tr1::shared_ptr parent = find_descendant_track_parent(track); if(parent) { @@ -67,23 +68,29 @@ ParentTrack::remove_descendant_track( return false; } -boost::shared_ptr +std::tr1::shared_ptr ParentTrack::find_descendant_track_parent( - boost::shared_ptr child) + std::tr1::shared_ptr child) { REQUIRE(child != NULL); - BOOST_FOREACH(shared_ptr track, tracks) + BOOST_FOREACH(std::tr1::shared_ptr track, tracks) { if(track == child) return shared_from_this(); - - shared_ptr result = + + std::tr1::shared_ptr result = track->find_descendant_track_parent(child); if(result) return result; } - return shared_ptr(); + return std::tr1::shared_ptr(); +} + +std::tr1::shared_ptr +ParentTrack::shared_from_this() +{ + return std::tr1::shared_ptr(this); } } // namespace model diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index 78451972e..9a087e98f 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -31,10 +31,6 @@ #include "track.hpp" #include "lib/observable-list.hpp" -#include -#include - - namespace gui { namespace model { @@ -42,9 +38,7 @@ namespace model { * ParentTrack is the abstract base class of all tracks that can parent * children. */ -class ParentTrack : - public Track, - public boost::enable_shared_from_this +class ParentTrack : public Track { protected: /** @@ -57,13 +51,13 @@ public: /** * Gets a read-only reference to the the list of child tracks. */ - const std::list< boost::shared_ptr >& + const std::list< std::tr1::shared_ptr >& get_child_tracks() const; /** * Gets read-write access to the list of child tracks. */ - lumiera::observable_list< boost::shared_ptr >& + lumiera::observable_list< std::tr1::shared_ptr >& get_child_track_list(); /** @@ -79,7 +73,7 @@ public: * @param The model track to try and remove. * @return Returns true if the track was successfully removed. */ - bool remove_descendant_track(const boost::shared_ptr track); + bool remove_descendant_track(const std::tr1::shared_ptr track); /** * A utility function that attempts to find the parent of a track by @@ -88,14 +82,18 @@ public: * @return Returns the parent track if one was found, or an empty * shared_ptr if none was found. */ - boost::shared_ptr - find_descendant_track_parent(boost::shared_ptr child); + std::tr1::shared_ptr + find_descendant_track_parent(std::tr1::shared_ptr child); + +private: + + std::tr1::shared_ptr shared_from_this(); protected: /** * The internal list of child tracks of this parent. */ - lumiera::observable_list< boost::shared_ptr > tracks; + lumiera::observable_list< std::tr1::shared_ptr > tracks; }; } // namespace model diff --git a/src/gui/model/project.cpp b/src/gui/model/project.cpp index 3b37020cd..7f8054b53 100644 --- a/src/gui/model/project.cpp +++ b/src/gui/model/project.cpp @@ -26,7 +26,7 @@ #include "sequence.hpp" using namespace std; -using namespace boost; +using namespace std::tr1; namespace gui { namespace model { @@ -43,7 +43,7 @@ Project::~Project() } -lumiera::observable_list< boost::shared_ptr >& +lumiera::observable_list< shared_ptr >& Project::get_sequences() { return sequences; diff --git a/src/gui/model/project.hpp b/src/gui/model/project.hpp index e6e6bbc9e..29e5ca2a6 100644 --- a/src/gui/model/project.hpp +++ b/src/gui/model/project.hpp @@ -40,14 +40,14 @@ public: ~Project(); - lumiera::observable_list< boost::shared_ptr >& + lumiera::observable_list< std::tr1::shared_ptr >& get_sequences(); void add_new_sequence(uString name); private: - lumiera::observable_list< boost::shared_ptr > sequences; + lumiera::observable_list< std::tr1::shared_ptr > sequences; }; } // namespace model diff --git a/src/gui/model/sequence.cpp b/src/gui/model/sequence.cpp index 318ee4a4f..107396515 100644 --- a/src/gui/model/sequence.cpp +++ b/src/gui/model/sequence.cpp @@ -27,7 +27,7 @@ #include "group-track.hpp" #include "clip-track.hpp" -using namespace boost; +using namespace std::tr1; namespace gui { namespace model { diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index b8588ed49..5e7b4dad7 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -24,7 +24,7 @@ #include "parent-track.hpp" #include -using namespace boost; +using namespace std::tr1; using namespace std; namespace gui { @@ -39,7 +39,7 @@ Track::Track() } -const std::list< boost::shared_ptr >& +const std::list< shared_ptr >& Track::get_child_tracks() const { return Track::NoChildren; @@ -96,9 +96,9 @@ Track::print_branch() return print_branch_recursive(0); } -boost::shared_ptr +shared_ptr Track::find_descendant_track_parent( - boost::shared_ptr /*child*/) + shared_ptr /*child*/) { return shared_ptr(); } diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 7e6b9085a..46f046b99 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -57,7 +57,7 @@ public: /** * Gets the list of child tracks. */ - virtual const std::list< boost::shared_ptr >& + virtual const std::list< std::tr1::shared_ptr >& get_child_tracks () const; /** @@ -106,8 +106,8 @@ public: * @return Returns the parent track if one was found, or an empty * shared_ptr if none was found. */ - virtual boost::shared_ptr - find_descendant_track_parent (boost::shared_ptr child); + virtual std::tr1::shared_ptr + find_descendant_track_parent (std::tr1::shared_ptr child); /** * A signal which fires when the enabled status changes. @@ -154,7 +154,7 @@ protected: * An object used internally as a return value for when there's no * children. */ - static const std::list< boost::shared_ptr > NoChildren; + static const std::list< std::tr1::shared_ptr > NoChildren; /** * The internal implementation of print_branch. diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index 6f755f25c..f2ae2da56 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -39,8 +39,8 @@ using namespace gui::widgets; using namespace gui::widgets::timeline; using namespace gui::model; -using boost::shared_ptr; ///////////////////////////////TICKET #796 -using boost::weak_ptr; ///////////////////////////////TICKET #796 +using std::tr1::shared_ptr; +using std::tr1::weak_ptr; using util::contains; namespace gui { diff --git a/src/gui/panels/timeline-panel.hpp b/src/gui/panels/timeline-panel.hpp index 2215c8657..87c05425c 100644 --- a/src/gui/panels/timeline-panel.hpp +++ b/src/gui/panels/timeline-panel.hpp @@ -36,12 +36,8 @@ #include "lib/time/timevalue.hpp" -#include -#include - using namespace gui::widgets; - namespace gui { namespace model { @@ -127,8 +123,8 @@ private: void show_time (Time); - boost::shared_ptr ///////////////////////////////TICKET #796 - load_state (boost::weak_ptr sequence); + std::tr1::shared_ptr + load_state (std::tr1::weak_ptr sequence); private: @@ -148,7 +144,7 @@ private: * An invisible column which will be used to identify the sequence * of a row. */ - Gtk::TreeModelColumn< boost::weak_ptr > + Gtk::TreeModelColumn< std::tr1::weak_ptr > sequenceColumn; /** @@ -172,9 +168,9 @@ private: // Body Widgets boost::scoped_ptr timelineWidget; - - std::map< boost::weak_ptr, - boost::shared_ptr > ///////////////////////////////TICKET #796 : should use std::tr1::shared_ptr + + std::map< std::tr1::weak_ptr, + std::tr1::shared_ptr > timelineStates; // Toolbar Widgets diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index eb4decffa..4af85069a 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -27,7 +27,8 @@ using namespace Gtk; using namespace std; -using namespace boost; +using namespace std::tr1; + using namespace util; using namespace gui::widgets::timeline; @@ -44,7 +45,7 @@ const double TimelineWidget::ZoomIncrement = 1.25; const int64_t TimelineWidget::MaxScale = 30000000; // 30 Million TimelineWidget::TimelineWidget( - boost::shared_ptr source_state) : + std::tr1::shared_ptr source_state) : Table(2, 2), layoutHelper(*this), headerContainer(NULL), @@ -93,7 +94,7 @@ TimelineWidget::~TimelineWidget() /* ===== Data Access ===== */ -boost::shared_ptr +shared_ptr TimelineWidget::get_state() { return state; @@ -334,8 +335,8 @@ TimelineWidget::create_timeline_track_from_modelTrack( void TimelineWidget::remove_orphaned_tracks() { - std::map, - boost::shared_ptr > + std::map, + shared_ptr > orphan_track_map(trackMap); // Remove all tracks which are still present in the sequence @@ -356,9 +357,9 @@ TimelineWidget::remove_orphaned_tracks() void TimelineWidget::search_orphaned_tracks_in_branch( - boost::shared_ptr modelTrack, - std::map, - boost::shared_ptr > &orphan_track_map) + shared_ptr modelTrack, + std::map, + shared_ptr > &orphan_track_map) { REQUIRE(modelTrack); @@ -480,7 +481,7 @@ TimelineWidget::on_motion_in_body_notify_event(GdkEventMotion *event) return true; } -boost::shared_ptr +shared_ptr TimelineWidget::sequence() const { if(!state) diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index 884598067..6bf71ef0d 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -69,7 +69,7 @@ public: * for this timeline widget. */ TimelineWidget( - boost::shared_ptr source_state); + std::tr1::shared_ptr source_state); /** * Destructor @@ -84,13 +84,13 @@ public: * @return The state object that the timeline widget is currently * working with. */ - boost::shared_ptr get_state(); + std::tr1::shared_ptr get_state(); /** * Replaces the current TimelineState object with another. * @param new_state The new state to swap in. */ - void set_state(boost::shared_ptr new_state); + void set_state(std::tr1::shared_ptr new_state); /** * Zooms the view in or out as by a number of steps while keeping a @@ -110,13 +110,13 @@ public: */ void set_tool(timeline::ToolType tool_type); - boost::shared_ptr + std::tr1::shared_ptr get_hovering_track() const; public: /* ===== Signals ===== */ - typedef sigc::signal > TimelineStateChangeSignal; - typedef sigc::signal > HoveringTrackChangedSignal; + typedef sigc::signal > TimelineStateChangeSignal; + typedef sigc::signal > HoveringTrackChangedSignal; sigc::signal mouse_hover_signal() const; @@ -170,7 +170,7 @@ private: * @param list The parent track of the branch. */ void create_timeline_tracks_from_branch( - boost::shared_ptr modelTrack); + std::tr1::shared_ptr modelTrack); /** * Creates a timeline UI track to correspond to a model track. @@ -178,9 +178,9 @@ private: * @return The timeline track created, or an empty shared_ptr if * modelTrack has an unreckognised type (this is an error condition). */ - boost::shared_ptr + std::tr1::shared_ptr create_timeline_track_from_modelTrack( - boost::shared_ptr modelTrack); + std::tr1::shared_ptr modelTrack); /** * Removes any UI tracks which no longer have corresponding model @@ -189,9 +189,9 @@ private: void remove_orphaned_tracks(); void search_orphaned_tracks_in_branch( - boost::shared_ptr modelTrack, - std::map, - boost::shared_ptr > &orphan_track_map); + std::tr1::shared_ptr modelTrack, + std::map, + std::tr1::shared_ptr > &orphan_track_map); /** * Looks up a timeline UI track in trackMap that corresponds to a @@ -201,8 +201,8 @@ private: * modelTrack has no corresponding timeline UI track (this is an * error condition). */ - boost::shared_ptr lookup_timeline_track( - boost::shared_ptr modelTrack) const; + std::tr1::shared_ptr lookup_timeline_track( + std::tr1::shared_ptr modelTrack) const; // ----- Layout Functions ----- // @@ -232,12 +232,12 @@ private: * Helper to get the sequence object from the state. * @return Returns a shared pointer to the sequence. */ - boost::shared_ptr sequence() const; + std::tr1::shared_ptr sequence() const; // ----- Other Functions ----- // void set_hovering_track( - boost::shared_ptr hovering_track); + std::tr1::shared_ptr hovering_track); protected: @@ -245,7 +245,7 @@ protected: * The state that will be used as the data source for this timeline * widget. */ - boost::shared_ptr state; + std::tr1::shared_ptr state; // Model Data @@ -256,11 +256,11 @@ protected: * widget is updated with update_tracks, timeline tracks are added and * removed from the map in correspondence with the tree. */ - std::map, - boost::shared_ptr > + std::map, + std::tr1::shared_ptr > trackMap; - boost::shared_ptr hoveringTrack; + std::tr1::shared_ptr hoveringTrack; // Helper Classes timeline::TimelineLayoutHelper layoutHelper; diff --git a/src/gui/widgets/timeline/timeline-arrow-tool.cpp b/src/gui/widgets/timeline/timeline-arrow-tool.cpp index dab5539e4..420d3a964 100644 --- a/src/gui/widgets/timeline/timeline-arrow-tool.cpp +++ b/src/gui/widgets/timeline/timeline-arrow-tool.cpp @@ -55,17 +55,17 @@ namespace timeline { Tool::on_button_press_event(event); // Convert the mouse click position to a Time - boost::shared_ptr state = timelineBody.getTimelineWidget().get_state(); + std::tr1::shared_ptr state = timelineBody.getTimelineWidget().get_state(); REQUIRE(state); TimelineViewWindow const& window = state->get_view_window(); Time tpoint = window.x_to_time(mousePoint.get_x()); // Get the clip, if any - boost::shared_ptr track = getHoveringTrack(); - boost::shared_ptr clip = track->getClipAt(tpoint); + std::tr1::shared_ptr track = getHoveringTrack(); + std::tr1::shared_ptr clip = track->getClipAt(tpoint); // Nothing to do if there is no clip - if (clip == boost::shared_ptr()) + if (clip == std::tr1::shared_ptr()) return; clip->setSelected(true); @@ -77,7 +77,7 @@ namespace timeline { REQUIRE (event != NULL); Tool::on_button_release_event(event); - boost::shared_ptr track = + std::tr1::shared_ptr track = getHoveringTrack(); } @@ -92,10 +92,10 @@ namespace timeline { return; } - boost::shared_ptr + std::tr1::shared_ptr ArrowTool::getHoveringTrack () { - boost::shared_ptr track( + std::tr1::shared_ptr track( timelineBody.getTimelineWidget().get_hovering_track()); return track; } diff --git a/src/gui/widgets/timeline/timeline-arrow-tool.hpp b/src/gui/widgets/timeline/timeline-arrow-tool.hpp index 83abd77e7..c2f0df070 100644 --- a/src/gui/widgets/timeline/timeline-arrow-tool.hpp +++ b/src/gui/widgets/timeline/timeline-arrow-tool.hpp @@ -81,7 +81,7 @@ namespace timeline { private: - boost::shared_ptr + std::tr1::shared_ptr getHoveringTrack (); bool selectionRectangleActive; diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index b64757477..d546ada65 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -34,12 +34,10 @@ using namespace Gtk; using namespace std; -using namespace boost; using namespace lumiera; using gui::util::CairoUtil; - -using boost::shared_ptr; ////////////////////TICKET #796 +using std::tr1::shared_ptr; namespace gui { namespace widgets { @@ -351,7 +349,7 @@ TimelineBody::draw_tracks(Cairo::RefPtr cr) const shared_ptr timeline_track = timelineWidget.lookup_timeline_track(*iterator); - optional rect = + boost::optional rect = layout_helper.get_track_header_rect(timeline_track); // Is this track visible? diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index aaf90cb2e..dbc6697a1 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -124,7 +124,7 @@ protected: /** * The event handler for when the TimelineWidget's state is switched. */ - void on_state_changed (boost::shared_ptr newState); + void on_state_changed (std::tr1::shared_ptr newState); /* ===== Internals ===== */ private: @@ -142,7 +142,7 @@ private: void draw_tracks(Cairo::RefPtr cr); void draw_track(Cairo::RefPtr cr, - boost::shared_ptr timeline_track, + std::tr1::shared_ptr timeline_track, const int view_width) const; /** @@ -200,7 +200,7 @@ private: Cairo::RefPtr playbackPointColour; gui::widgets::TimelineWidget &timelineWidget; - boost::shared_ptr timelineState; ////////////////////TICKET #796 : should use std::tr1::shared_ptr + std::tr1::shared_ptr timelineState; friend class Tool; diff --git a/src/gui/widgets/timeline/timeline-clip-track.cpp b/src/gui/widgets/timeline/timeline-clip-track.cpp index 39d254a48..9f5438d0a 100644 --- a/src/gui/widgets/timeline/timeline-clip-track.cpp +++ b/src/gui/widgets/timeline/timeline-clip-track.cpp @@ -27,8 +27,8 @@ #include "timeline-view-window.hpp" using namespace Gtk; -using boost::dynamic_pointer_cast; -using boost::shared_ptr; + +using std::tr1::shared_ptr; using util::contains; namespace gui { @@ -76,7 +76,7 @@ namespace timeline { } } - boost::shared_ptr + std::tr1::shared_ptr ClipTrack::getClipAt(Time position) const { std::pair, shared_ptr > @@ -88,7 +88,7 @@ namespace timeline { } // Nothing found - return boost::shared_ptr(); + return std::tr1::shared_ptr(); } //// private methods @@ -97,8 +97,8 @@ namespace timeline { ClipTrack::createTimelineClips() { // Share the draw strategy between all objects - // TODO: use factory/builder here - static boost::shared_ptr drawStrategy(new BasicDrawStrategy()); + TODO("Use factory/builder to create Timline Clips"); + static std::tr1::shared_ptr drawStrategy(new BasicDrawStrategy()); BOOST_FOREACH (shared_ptr modelClip, getModelTrack()->getClipList()) { // Is a timeline UI clip present in the map already? @@ -115,7 +115,7 @@ namespace timeline { shared_ptr ClipTrack::getModelTrack () { - return dynamic_pointer_cast(modelTrack); + return std::tr1::dynamic_pointer_cast(modelTrack); } void diff --git a/src/gui/widgets/timeline/timeline-clip-track.hpp b/src/gui/widgets/timeline/timeline-clip-track.hpp index 1265c913b..980c37480 100644 --- a/src/gui/widgets/timeline/timeline-clip-track.hpp +++ b/src/gui/widgets/timeline/timeline-clip-track.hpp @@ -52,7 +52,7 @@ namespace timeline { * Constructor. */ ClipTrack(TimelineWidget &timelineWidget, - boost::shared_ptr track); + std::tr1::shared_ptr track); /** * Draw the track in the timeline. @@ -66,7 +66,7 @@ namespace timeline { * pointer. * @param the given time */ - boost::shared_ptr + std::tr1::shared_ptr getClipAt(Time position) const; private: @@ -80,7 +80,7 @@ namespace timeline { /** * Gets the modelTrack as a ClipTrack. */ - boost::shared_ptr + std::tr1::shared_ptr getModelTrack (); /** @@ -107,8 +107,8 @@ namespace timeline { * The clipMap maps model clips to timeline widget clips which are responsible for the * UI representation of a clip. */ - std::map, - boost::shared_ptr > + std::map, + std::tr1::shared_ptr > clipMap; }; diff --git a/src/gui/widgets/timeline/timeline-clip.cpp b/src/gui/widgets/timeline/timeline-clip.cpp index f2328bdc5..c6d90be45 100644 --- a/src/gui/widgets/timeline/timeline-clip.cpp +++ b/src/gui/widgets/timeline/timeline-clip.cpp @@ -27,11 +27,11 @@ namespace gui { namespace widgets { namespace timeline { - using boost::shared_ptr; //////////////////////TICKET #796 + using std::tr1::shared_ptr; //////////////////////TICKET #796 - Clip::Clip (boost::shared_ptr clip, - boost::shared_ptr drawStrategy) + Clip::Clip (std::tr1::shared_ptr clip, + std::tr1::shared_ptr drawStrategy) : Entity(drawStrategy) , modelClip(clip) , selected(false) diff --git a/src/gui/widgets/timeline/timeline-clip.hpp b/src/gui/widgets/timeline/timeline-clip.hpp index 2d6d83139..001fb94a0 100644 --- a/src/gui/widgets/timeline/timeline-clip.hpp +++ b/src/gui/widgets/timeline/timeline-clip.hpp @@ -49,8 +49,8 @@ namespace timeline { class Clip : public Entity { public: - Clip (boost::shared_ptr clip, - boost::shared_ptr drawStrategy); + Clip (std::tr1::shared_ptr clip, + std::tr1::shared_ptr drawStrategy); Time getBegin() const; @@ -62,7 +62,7 @@ namespace timeline { private: - boost::shared_ptr modelClip; ////////////////////////TICKET #796 : should use std::tr1 + std::tr1::shared_ptr modelClip; /** * True when this clip is selected in the GUI. diff --git a/src/gui/widgets/timeline/timeline-entity.cpp b/src/gui/widgets/timeline/timeline-entity.cpp index 13dc398aa..bc499b3d4 100644 --- a/src/gui/widgets/timeline/timeline-entity.cpp +++ b/src/gui/widgets/timeline/timeline-entity.cpp @@ -29,7 +29,7 @@ namespace gui { namespace widgets { namespace timeline { - Entity::Entity(boost::shared_ptr drawStrategy) + Entity::Entity(std::tr1::shared_ptr drawStrategy) : enabled(true), drawStrategy(drawStrategy) { } diff --git a/src/gui/widgets/timeline/timeline-entity.hpp b/src/gui/widgets/timeline/timeline-entity.hpp index a6a03b5da..bfb170aee 100644 --- a/src/gui/widgets/timeline/timeline-entity.hpp +++ b/src/gui/widgets/timeline/timeline-entity.hpp @@ -31,8 +31,9 @@ #include "lib/time/timevalue.hpp" #include +#include #include -#include //////////////////////TICKET #796 + namespace gui { namespace widgets { @@ -51,7 +52,7 @@ namespace timeline { class Entity { protected: - Entity(boost::shared_ptr drawStrategy); + Entity(std::tr1::shared_ptr drawStrategy); virtual ~Entity(); @@ -81,7 +82,7 @@ namespace timeline { bool enabled; - boost::shared_ptr drawStrategy; + std::tr1::shared_ptr drawStrategy; }; } // namespace timeline diff --git a/src/gui/widgets/timeline/timeline-group-track.cpp b/src/gui/widgets/timeline/timeline-group-track.cpp index aa43e1970..4ed072453 100644 --- a/src/gui/widgets/timeline/timeline-group-track.cpp +++ b/src/gui/widgets/timeline/timeline-group-track.cpp @@ -24,7 +24,7 @@ #include "gui/widgets/timeline-widget.hpp" using namespace Gtk; -using namespace boost; +using namespace std::tr1; using namespace sigc; namespace gui { diff --git a/src/gui/widgets/timeline/timeline-group-track.hpp b/src/gui/widgets/timeline/timeline-group-track.hpp index 3cf079b47..822142b0d 100644 --- a/src/gui/widgets/timeline/timeline-group-track.hpp +++ b/src/gui/widgets/timeline/timeline-group-track.hpp @@ -37,7 +37,7 @@ class GroupTrack : public timeline::Track { public: GroupTrack(TimelineWidget &timeline_widget, - boost::shared_ptr track); + std::tr1::shared_ptr track); void draw_track(Cairo::RefPtr cairo, TimelineViewWindow* constwindow) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 3ecfba2d0..486859845 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -30,7 +30,7 @@ using namespace Gtk; using namespace std; -using namespace boost; +using namespace std::tr1; using namespace util; namespace gui { @@ -343,7 +343,7 @@ TimelineHeaderContainer::on_scroll() void TimelineHeaderContainer::on_hovering_track_changed( - boost::shared_ptr hovering_track) + std::tr1::shared_ptr hovering_track) { (void)hovering_track; @@ -392,7 +392,7 @@ TimelineHeaderContainer::layout_headers() Widget &widget = timeline_track->get_header_widget(); - optional header_rect = + boost::optional header_rect = layout_helper.get_track_header_rect(timeline_track); if(header_rect) diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 094619ecc..6d40d621e 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -140,7 +140,7 @@ private: void on_scroll(); void on_hovering_track_changed( - boost::shared_ptr hovering_track); + std::tr1::shared_ptr hovering_track); private: /* ===== Internal Event Handlers ===== */ @@ -169,7 +169,7 @@ private: * @param offset The vertical offset of the headers in pixels. */ void draw_header_decoration( - boost::shared_ptr modelTrack, + std::tr1::shared_ptr modelTrack, const Gdk::Rectangle &clip_rect); /** @@ -182,8 +182,8 @@ private: * @remarks If the return value is going to be NULL, an ENSURE will * fail. */ - boost::shared_ptr lookup_timeline_track( - boost::shared_ptr modelTrack); + std::tr1::shared_ptr lookup_timeline_track( + std::tr1::shared_ptr modelTrack); void begin_drag(); @@ -248,7 +248,7 @@ private: int scrollSlideRate; //----- User Interaction State -----// - boost::shared_ptr hoveringTrack; + std::tr1::shared_ptr hoveringTrack; Gdk::Point mousePoint; diff --git a/src/gui/widgets/timeline/timeline-header-widget.cpp b/src/gui/widgets/timeline/timeline-header-widget.cpp index 734e42dfd..e9588fa82 100644 --- a/src/gui/widgets/timeline/timeline-header-widget.cpp +++ b/src/gui/widgets/timeline/timeline-header-widget.cpp @@ -28,9 +28,10 @@ using namespace Gtk; using namespace std; -using namespace boost; using namespace util; +using std::tr1::shared_ptr; + namespace gui { namespace widgets { namespace timeline { diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp index 6a858aa18..71aeef656 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp @@ -29,7 +29,7 @@ using namespace gui::widgets; using lib::time::Mutation; -using boost::shared_ptr; /////////////////////////TICKET #796 +using std::tr1::shared_ptr; namespace gui { namespace widgets { diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 0e311cd7d..71a55d44a 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -30,7 +30,7 @@ using namespace Gtk; using namespace std; -using namespace boost; +using namespace std::tr1; using namespace lumiera; using namespace util; using namespace gui::util; @@ -80,17 +80,17 @@ TimelineLayoutHelper::add_branch( } } -optional +boost::optional TimelineLayoutHelper::get_track_header_rect( - boost::weak_ptr track) + std::tr1::weak_ptr track) { if(contains(headerBoxes, track)) { Gdk::Rectangle rect(headerBoxes[track]); rect.set_y(rect.get_y() - timelineWidget.get_y_scroll_offset()); - return optional(rect); + return boost::optional(rect); } - return optional(); + return boost::optional(); } shared_ptr @@ -112,7 +112,7 @@ TimelineLayoutHelper::header_from_point(Gdk::Point point) return shared_ptr(); } -boost::shared_ptr +std::tr1::shared_ptr TimelineLayoutHelper::track_from_y(int y) { // Apply the scroll offset @@ -300,7 +300,7 @@ TimelineLayoutHelper::is_animating() const TimelineLayoutHelper::TrackTree::pre_order_iterator TimelineLayoutHelper::iterator_from_track( - boost::shared_ptr modelTrack) + std::tr1::shared_ptr modelTrack) { REQUIRE(modelTrack); @@ -666,7 +666,7 @@ TimelineLayoutHelper::apply_drop_to_modelTree( timelineWidget.thaw_update_tracks(); } -boost::shared_ptr +std::tr1::shared_ptr TimelineLayoutHelper::get_sequence() const { REQUIRE(timelineWidget.state); diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index bc0f1c39d..07e792e9a 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -59,7 +59,7 @@ public: /** * Definition of the layout track tree type. */ - typedef lumiera::tree< boost::shared_ptr > TrackTree; + typedef lumiera::tree< std::tr1::shared_ptr > TrackTree; public: /** @@ -101,7 +101,7 @@ public: * @see update_layout() */ boost::optional get_track_header_rect( - boost::weak_ptr track); + std::tr1::weak_ptr track); /** * Searches for a header which has the specified point inside of it. @@ -114,7 +114,7 @@ public: * tracks. * @see update_layout() */ - boost::shared_ptr header_from_point( + std::tr1::shared_ptr header_from_point( Gdk::Point point); /** @@ -128,14 +128,14 @@ public: * tracks. * @see update_layout() */ - boost::shared_ptr track_from_y(int y); + std::tr1::shared_ptr track_from_y(int y); /** * Begins to drag the track under mouse_point, if there is one. * @param mouse_point The mouse point to begin dragging from, measured * in pixels from the top left of the header container widget. */ - boost::shared_ptr + std::tr1::shared_ptr begin_dragging_track(const Gdk::Point &mouse_point); /** @@ -186,7 +186,7 @@ public: * iterator was found. */ TrackTree::pre_order_iterator iterator_from_track( - boost::shared_ptr modelTrack); + std::tr1::shared_ptr modelTrack); /** * A function that recursively calculates the visible height of a @@ -262,7 +262,7 @@ protected: * @see clone_tree_from_sequence() */ void add_branch(TrackTree::iterator_base parent_iterator, - boost::shared_ptr parent); + std::tr1::shared_ptr parent); /** * Recursively calculates the boxes for a given branch in the timeline @@ -298,8 +298,8 @@ protected: * @remarks If the return value is going to be NULL, an ENSURE will * fail. */ - boost::shared_ptr lookup_timeline_track( - boost::shared_ptr modelTrack); + std::tr1::shared_ptr lookup_timeline_track( + std::tr1::shared_ptr modelTrack); /** * A helper function which kicks off the animation timer. @@ -343,7 +343,7 @@ protected: * Helper to get the sequence object from the state. * @return Returns a shared pointer to the sequence. */ - boost::shared_ptr get_sequence() const; + std::tr1::shared_ptr get_sequence() const; protected: /** @@ -363,7 +363,7 @@ protected: * the update_layout method. * @see update_layout() */ - std::map, Gdk::Rectangle> + std::map, Gdk::Rectangle> headerBoxes; /** diff --git a/src/gui/widgets/timeline/timeline-ruler.cpp b/src/gui/widgets/timeline/timeline-ruler.cpp index 03a866482..0b8d68f22 100644 --- a/src/gui/widgets/timeline/timeline-ruler.cpp +++ b/src/gui/widgets/timeline/timeline-ruler.cpp @@ -36,7 +36,7 @@ using namespace gui; using namespace gui::widgets; using namespace gui::widgets::timeline; -using boost::shared_ptr; ////////////////////TICKET #796 +using std::tr1::shared_ptr; ////////////////////TICKET #796 using gui::util::CairoUtil; using lib::time::Time; using lib::time::TimeVar; diff --git a/src/gui/widgets/timeline/timeline-ruler.hpp b/src/gui/widgets/timeline/timeline-ruler.hpp index a7266793f..842ce6bff 100644 --- a/src/gui/widgets/timeline/timeline-ruler.hpp +++ b/src/gui/widgets/timeline/timeline-ruler.hpp @@ -111,7 +111,7 @@ private: /** * The event handler for when the TimelineWidget's state is switched. */ - void on_state_changed (boost::shared_ptr newState); ////////////////////TICKET #796 : should use std::tr1::shared_ptr + void on_state_changed (std::tr1::shared_ptr newState); ////////////////////TICKET #796 : should use std::tr1::shared_ptr private: /* ===== Internal Methods ===== */ @@ -242,7 +242,7 @@ private: /** * the currently active timeline state object */ - boost::shared_ptr timelineState; ////////////////////TICKET #796 : should use std::tr1::shared_ptr + std::tr1::shared_ptr timelineState; /** * The caches image of the ruler, over which the chevrons etc. will diff --git a/src/gui/widgets/timeline/timeline-state.cpp b/src/gui/widgets/timeline/timeline-state.cpp index 62f67aa08..b55589956 100644 --- a/src/gui/widgets/timeline/timeline-state.cpp +++ b/src/gui/widgets/timeline/timeline-state.cpp @@ -36,11 +36,11 @@ using lib::time::FSecs; using lib::time::Offset; using lib::time::Duration; using lib::time::Mutation; -using boost::shared_ptr; /////////////////////////TICKET #796 +using std::tr1::shared_ptr; -TimelineState::TimelineState (boost::shared_ptr source_sequence) +TimelineState::TimelineState (std::tr1::shared_ptr source_sequence) : sequence(source_sequence) , viewWindow(Offset(Time::ZERO), 1) , selection_(Time::ZERO, Duration::NIL) @@ -60,7 +60,7 @@ TimelineState::TimelineState (boost::shared_ptr source_sequence //////////////////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all } -boost::shared_ptr +std::tr1::shared_ptr TimelineState::get_sequence() const { return sequence; diff --git a/src/gui/widgets/timeline/timeline-state.hpp b/src/gui/widgets/timeline/timeline-state.hpp index 94c072950..23e2015e7 100644 --- a/src/gui/widgets/timeline/timeline-state.hpp +++ b/src/gui/widgets/timeline/timeline-state.hpp @@ -56,7 +56,7 @@ public: * @param source_sequence The sequence on which the TimelineWidget * will operate when this TimelineState is attached. */ - TimelineState(boost::shared_ptr source_sequence); + TimelineState(std::tr1::shared_ptr source_sequence); public: @@ -64,7 +64,7 @@ public: * Gets the sequence that is attached to this timeline state object. * @return Returns a shared_ptr to the sequence object. */ - boost::shared_ptr get_sequence() const; + std::tr1::shared_ptr get_sequence() const; /** * Gets a reference to the timeline view window object. @@ -122,7 +122,7 @@ private: * @remarks This pointer is set by the constructor and is constant, so * will not change in value during the lifetime of the class. */ - boost::shared_ptr sequence; + std::tr1::shared_ptr sequence; // View State /** diff --git a/src/gui/widgets/timeline/timeline-tool.cpp b/src/gui/widgets/timeline/timeline-tool.cpp index 9e261441d..2402f22ea 100644 --- a/src/gui/widgets/timeline/timeline-tool.cpp +++ b/src/gui/widgets/timeline/timeline-tool.cpp @@ -24,7 +24,7 @@ #include "gui/widgets/timeline-widget.hpp" using namespace Gdk; -using namespace boost; +using std::tr1::shared_ptr; namespace gui { namespace widgets { diff --git a/src/gui/widgets/timeline/timeline-tool.hpp b/src/gui/widgets/timeline/timeline-tool.hpp index e63796d56..f34cb5d32 100644 --- a/src/gui/widgets/timeline/timeline-tool.hpp +++ b/src/gui/widgets/timeline/timeline-tool.hpp @@ -133,7 +133,7 @@ protected: /** * A helper function to get the state */ - boost::shared_ptr get_state() const; + std::tr1::shared_ptr get_state() const; /** * A helper function to get the view window diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index 0a86daf2d..b0267dea3 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -29,7 +29,7 @@ using namespace Gtk; using namespace sigc; -using boost::shared_ptr; //////////////////////////////TICKET #796 : should use std::tr1 +using std::tr1::shared_ptr; namespace gui { namespace widgets { @@ -125,7 +125,7 @@ shared_ptr Track::getClipAt(Time) const { // Default implementation returns empty pointer - return boost::shared_ptr(); + return std::tr1::shared_ptr(); } void @@ -272,7 +272,7 @@ void Track::on_remove_track() { REQUIRE(modelTrack); - boost::shared_ptr state = timelineWidget.get_state(); + std::tr1::shared_ptr state = timelineWidget.get_state(); REQUIRE(state); state->get_sequence()->remove_descendant_track(modelTrack); diff --git a/src/gui/widgets/timeline/timeline-track.hpp b/src/gui/widgets/timeline/timeline-track.hpp index 79b7dec98..796b1f130 100644 --- a/src/gui/widgets/timeline/timeline-track.hpp +++ b/src/gui/widgets/timeline/timeline-track.hpp @@ -76,7 +76,7 @@ public: * Constructor */ Track(TimelineWidget &timeline_widget, - boost::shared_ptr track); + std::tr1::shared_ptr track); /** * Destructor @@ -85,7 +85,7 @@ public: Gtk::Widget& get_header_widget(); - boost::shared_ptr //////////////////////////////TICKET #796 : should use std::tr1 + std::tr1::shared_ptr //////////////////////////////TICKET #796 : should use std::tr1 getModelTrack() const; /** @@ -155,7 +155,7 @@ public: * The default implementation simply returns an empty pointer. * @param the given time */ - virtual boost::shared_ptr //////////////////////////////TICKET #796 : should use std::tr1 + virtual std::tr1::shared_ptr //////////////////////////////TICKET #796 : should use std::tr1 getClipAt (Time position) const; private: @@ -209,7 +209,7 @@ private: protected: TimelineWidget &timelineWidget; - boost::shared_ptr modelTrack; + std::tr1::shared_ptr modelTrack; private: /** diff --git a/src/gui/widgets/timeline/timeline-zoom-scale.cpp b/src/gui/widgets/timeline/timeline-zoom-scale.cpp index eedaf074b..083513647 100644 --- a/src/gui/widgets/timeline/timeline-zoom-scale.cpp +++ b/src/gui/widgets/timeline/timeline-zoom-scale.cpp @@ -20,8 +20,8 @@ * *****************************************************/ -#include "gui/widgets/timeline/timeline-zoom-scale.hpp" #include "gui/widgets/timeline-widget.hpp" +#include "gui/widgets/timeline/timeline-zoom-scale.hpp" using namespace Gtk; @@ -90,7 +90,7 @@ TimelineZoomScale::TimelineZoomScale() } void -TimelineZoomScale::wireTimelineState (boost::shared_ptr currentState, +TimelineZoomScale::wireTimelineState (std::tr1::shared_ptr currentState, TimelineWidget::TimelineStateChangeSignal stateChangeSignal) { on_timeline_state_changed (currentState); @@ -98,7 +98,7 @@ TimelineZoomScale::wireTimelineState (boost::shared_ptr currentSt } void -TimelineZoomScale::on_timeline_state_changed (boost::shared_ptr newState) +TimelineZoomScale::on_timeline_state_changed (std::tr1::shared_ptr newState) { REQUIRE (newState); timelineState = newState; diff --git a/src/gui/widgets/timeline/timeline-zoom-scale.hpp b/src/gui/widgets/timeline/timeline-zoom-scale.hpp index 9bfe8139a..ec106ad94 100644 --- a/src/gui/widgets/timeline/timeline-zoom-scale.hpp +++ b/src/gui/widgets/timeline/timeline-zoom-scale.hpp @@ -29,10 +29,6 @@ #include "gui/gtk-lumiera.hpp" #include "gui/widgets/mini-button.hpp" #include "gui/widgets/timeline-widget.hpp" -#include "gui/widgets/timeline/timeline-state.hpp" -#include "gui/widgets/timeline/timeline-view-window.hpp" - -#include using namespace Gtk; using namespace gui::widgets; @@ -55,7 +51,7 @@ public: */ sigc::signal signal_zoom(); - void wireTimelineState (boost::shared_ptr currentState, + void wireTimelineState (std::tr1::shared_ptr currentState, TimelineWidget::TimelineStateChangeSignal); private: @@ -65,7 +61,7 @@ private: * Update the slider position when the timeline state * is changed. */ - void on_timeline_state_changed (boost::shared_ptr newState); ////////////////////TICKET #796 : should use std::tr1::shared_ptr + void on_timeline_state_changed (std::tr1::shared_ptr newState); ////////////////////TICKET #796 : should use std::tr1::shared_ptr /** * Event handler for when the zoomIn Button @@ -100,7 +96,7 @@ private: const double button_step_size; - boost::shared_ptr timelineState; + std::tr1::shared_ptr timelineState; }; } // namespace gui diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index ea8322deb..821cfde60 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -33,13 +33,12 @@ using util::cStr; using namespace Gtk; using namespace Glib; -using namespace boost; using namespace std; +using namespace std::tr1; using namespace gui::workspace; namespace fsys = boost::filesystem; - namespace gui { IconSize WindowManager::GiantIconSize = ICON_SIZE_INVALID; diff --git a/src/gui/window-manager.hpp b/src/gui/window-manager.hpp index 2dbd91e93..1f0eb3a46 100644 --- a/src/gui/window-manager.hpp +++ b/src/gui/window-manager.hpp @@ -39,10 +39,9 @@ #include "gui/gtk-base.hpp" #include -#include #include #include - +#include namespace gui { @@ -195,7 +194,7 @@ private: private: - std::list< boost::shared_ptr > windowList; + std::list< std::tr1::shared_ptr > windowList; public: From c9a0209a0b9b58e29fc7dec9092451f90659dbb3 Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Fri, 21 Oct 2011 09:14:32 -0500 Subject: [PATCH 03/68] Fix ParentTrack: using std::tr1::enable_shared_from_this --- src/gui/model/parent-track.cpp | 7 +------ src/gui/model/parent-track.hpp | 8 +++----- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index d20a1adc3..3384227a1 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -72,6 +72,7 @@ std::tr1::shared_ptr ParentTrack::find_descendant_track_parent( std::tr1::shared_ptr child) { + REQUIRE(child != NULL); BOOST_FOREACH(std::tr1::shared_ptr track, tracks) { @@ -87,11 +88,5 @@ ParentTrack::find_descendant_track_parent( return std::tr1::shared_ptr(); } -std::tr1::shared_ptr -ParentTrack::shared_from_this() -{ - return std::tr1::shared_ptr(this); -} - } // namespace model } // namespace gui diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index 9a087e98f..b23d2f07c 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -38,7 +38,9 @@ namespace model { * ParentTrack is the abstract base class of all tracks that can parent * children. */ -class ParentTrack : public Track +class ParentTrack : + public Track, + public std::tr1::enable_shared_from_this { protected: /** @@ -85,10 +87,6 @@ public: std::tr1::shared_ptr find_descendant_track_parent(std::tr1::shared_ptr child); -private: - - std::tr1::shared_ptr shared_from_this(); - protected: /** * The internal list of child tracks of this parent. From 2730fa8d7a24b04a829940bed29800ab0ffce99f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 22 Oct 2011 02:49:30 +0200 Subject: [PATCH 04/68] a bit of stylistic cleanup - using std::tr1::shared_ptr in namespace gui - thus removing a lot of std::tr1 qualifications - fix some includes. Should be relative to 'src' - interface classes should declare a virtual dtor! --- src/gui/gtk-lumiera.hpp | 4 ++ src/gui/model/clip-track.hpp | 6 +- src/gui/model/parent-track.cpp | 15 +++-- src/gui/model/parent-track.hpp | 14 ++--- src/gui/model/project.hpp | 6 +- src/gui/model/sequence.hpp | 2 +- src/gui/model/track.cpp | 5 +- src/gui/model/track.hpp | 9 +-- src/gui/panels/timeline-panel.cpp | 3 +- src/gui/panels/timeline-panel.hpp | 18 ++++-- src/gui/widgets/timeline-widget.cpp | 23 ++++---- src/gui/widgets/timeline-widget.hpp | 55 +++++++++---------- .../widgets/timeline/timeline-arrow-tool.cpp | 15 +++-- .../widgets/timeline/timeline-arrow-tool.hpp | 2 +- src/gui/widgets/timeline/timeline-body.hpp | 8 +-- .../widgets/timeline/timeline-clip-track.cpp | 12 ++-- .../widgets/timeline/timeline-clip-track.hpp | 10 ++-- src/gui/widgets/timeline/timeline-clip.cpp | 6 +- src/gui/widgets/timeline/timeline-clip.hpp | 6 +- src/gui/widgets/timeline/timeline-entity.cpp | 2 +- src/gui/widgets/timeline/timeline-entity.hpp | 5 +- .../widgets/timeline/timeline-group-track.hpp | 15 ++--- .../timeline/timeline-header-container.cpp | 7 +-- .../timeline/timeline-header-container.hpp | 14 ++--- .../timeline/timeline-layout-helper.cpp | 9 ++- .../timeline/timeline-layout-helper.hpp | 22 ++++---- src/gui/widgets/timeline/timeline-ruler.cpp | 2 +- src/gui/widgets/timeline/timeline-ruler.hpp | 4 +- src/gui/widgets/timeline/timeline-state.cpp | 4 +- src/gui/widgets/timeline/timeline-state.hpp | 8 +-- src/gui/widgets/timeline/timeline-tool.hpp | 2 +- src/gui/widgets/timeline/timeline-track.cpp | 4 +- src/gui/widgets/timeline/timeline-track.hpp | 18 ++---- .../widgets/timeline/timeline-zoom-scale.cpp | 4 +- .../widgets/timeline/timeline-zoom-scale.hpp | 6 +- src/gui/window-manager.hpp | 3 +- .../proc/asset/orderingofassetstest.cpp | 2 +- tests/lib/factorytest.cpp | 6 +- 38 files changed, 173 insertions(+), 183 deletions(-) diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 65ee00e9c..315ee4f2c 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -55,11 +55,15 @@ #include "gui/window-manager.hpp" #include +#include #include namespace gui { +using std::tr1::shared_ptr; + + /* ====== The Application Class ====== */ diff --git a/src/gui/model/clip-track.hpp b/src/gui/model/clip-track.hpp index e115ed415..45a067f60 100644 --- a/src/gui/model/clip-track.hpp +++ b/src/gui/model/clip-track.hpp @@ -28,7 +28,7 @@ #ifndef CLIP_TRACK_HPP #define CLIP_TRACK_HPP -#include "track.hpp" +#include "gui/model/track.hpp" #include "lib/observable-list.hpp" namespace gui { @@ -53,12 +53,12 @@ namespace model { /** * Gets the list of clips associated with this track. */ - lumiera::observable_list< std::tr1::shared_ptr >& + lumiera::observable_list >& getClipList(void); private: - lumiera::observable_list< std::tr1::shared_ptr > clips; + lumiera::observable_list > clips; }; diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index 3384227a1..45c8d13ae 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -23,7 +23,6 @@ #include "parent-track.hpp" #include -using namespace boost; using std::tr1::shared_ptr; namespace gui { @@ -33,13 +32,13 @@ ParentTrack::ParentTrack() { } -const std::list< std::tr1::shared_ptr >& +const std::list >& ParentTrack::get_child_tracks() const { return tracks.get_list(); } -lumiera::observable_list< std::tr1::shared_ptr >& +lumiera::observable_list >& ParentTrack::get_child_track_list() { return tracks; @@ -53,11 +52,11 @@ ParentTrack::can_host_children() const bool ParentTrack::remove_descendant_track( - const std::tr1::shared_ptr track) + const shared_ptr track) { REQUIRE(track); - std::tr1::shared_ptr parent = + shared_ptr parent = find_descendant_track_parent(track); if(parent) { @@ -68,10 +67,10 @@ ParentTrack::remove_descendant_track( return false; } -std::tr1::shared_ptr -ParentTrack::find_descendant_track_parent( - std::tr1::shared_ptr child) +shared_ptr +ParentTrack::find_descendant_track_parent(shared_ptr child) { + using namespace boost; REQUIRE(child != NULL); BOOST_FOREACH(std::tr1::shared_ptr track, tracks) diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index b23d2f07c..a1c709713 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -28,7 +28,7 @@ #ifndef PARENT_TRACK_HPP #define PARENT_TRACK_HPP -#include "track.hpp" +#include "gui/model/track.hpp" #include "lib/observable-list.hpp" namespace gui { @@ -53,13 +53,13 @@ public: /** * Gets a read-only reference to the the list of child tracks. */ - const std::list< std::tr1::shared_ptr >& + const std::list >& get_child_tracks() const; /** * Gets read-write access to the list of child tracks. */ - lumiera::observable_list< std::tr1::shared_ptr >& + lumiera::observable_list >& get_child_track_list(); /** @@ -75,7 +75,7 @@ public: * @param The model track to try and remove. * @return Returns true if the track was successfully removed. */ - bool remove_descendant_track(const std::tr1::shared_ptr track); + bool remove_descendant_track (const shared_ptr track); /** * A utility function that attempts to find the parent of a track by @@ -84,14 +84,14 @@ public: * @return Returns the parent track if one was found, or an empty * shared_ptr if none was found. */ - std::tr1::shared_ptr - find_descendant_track_parent(std::tr1::shared_ptr child); + shared_ptr + find_descendant_track_parent (shared_ptr child); protected: /** * The internal list of child tracks of this parent. */ - lumiera::observable_list< std::tr1::shared_ptr > tracks; + lumiera::observable_list > tracks; }; } // namespace model diff --git a/src/gui/model/project.hpp b/src/gui/model/project.hpp index 29e5ca2a6..f2806abca 100644 --- a/src/gui/model/project.hpp +++ b/src/gui/model/project.hpp @@ -27,7 +27,7 @@ #ifndef PROJECT_HPP #define PROJECT_HPP -#include "sequence.hpp" +#include "gui/model/sequence.hpp" #include "lib/observable-list.hpp" namespace gui { @@ -40,14 +40,14 @@ public: ~Project(); - lumiera::observable_list< std::tr1::shared_ptr >& + lumiera::observable_list >& get_sequences(); void add_new_sequence(uString name); private: - lumiera::observable_list< std::tr1::shared_ptr > sequences; + lumiera::observable_list > sequences; }; } // namespace model diff --git a/src/gui/model/sequence.hpp b/src/gui/model/sequence.hpp index 45b9a43bf..db856d29e 100644 --- a/src/gui/model/sequence.hpp +++ b/src/gui/model/sequence.hpp @@ -27,7 +27,7 @@ #ifndef SEQUENCE_HPP #define SEQUENCE_HPP -#include "parent-track.hpp" +#include "gui/model/parent-track.hpp" namespace gui { namespace model { diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index 5e7b4dad7..c81cc9739 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -35,9 +35,10 @@ const list< shared_ptr > Track::NoChildren; Track::Track() : enabled(true), locked(false) -{ +{ } + +Track::~Track() { } -} const std::list< shared_ptr >& Track::get_child_tracks() const diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 46f046b99..c7472b03f 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -47,6 +47,7 @@ protected: Track(); public: + virtual ~Track(); /// this is an interface /** * Returns true if this track can own any child tracks. @@ -57,7 +58,7 @@ public: /** * Gets the list of child tracks. */ - virtual const std::list< std::tr1::shared_ptr >& + virtual const std::list >& get_child_tracks () const; /** @@ -106,8 +107,8 @@ public: * @return Returns the parent track if one was found, or an empty * shared_ptr if none was found. */ - virtual std::tr1::shared_ptr - find_descendant_track_parent (std::tr1::shared_ptr child); + virtual shared_ptr + find_descendant_track_parent (shared_ptr child); /** * A signal which fires when the enabled status changes. @@ -154,7 +155,7 @@ protected: * An object used internally as a return value for when there's no * children. */ - static const std::list< std::tr1::shared_ptr > NoChildren; + static const std::list< shared_ptr > NoChildren; /** * The internal implementation of print_branch. diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index f2ae2da56..7d5b4fa6c 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -130,8 +130,7 @@ TimelinePanel::TimelinePanel (workspace::PanelManager &panel_manager, zoomScale .set_tooltip_text(_("Adjust timeline zoom scale")); // Setup the timeline widget - shared_ptr sequence ///////////////////////////////TICKET #796 : should use std::tr1::shared_ptr instead of boost - = *get_project().get_sequences().begin(); + shared_ptr sequence = *(get_project().get_sequences().begin()); timelineWidget.reset(new TimelineWidget(load_state(sequence))); pack_start(*timelineWidget, PACK_EXPAND_WIDGET); diff --git a/src/gui/panels/timeline-panel.hpp b/src/gui/panels/timeline-panel.hpp index 87c05425c..febcb857c 100644 --- a/src/gui/panels/timeline-panel.hpp +++ b/src/gui/panels/timeline-panel.hpp @@ -36,9 +36,15 @@ #include "lib/time/timevalue.hpp" +#include + using namespace gui::widgets; namespace gui { + +using std::tr1::shared_ptr; +using std::tr1::weak_ptr; + namespace model { class Sequence; @@ -49,6 +55,7 @@ namespace panels { using lib::time::Time; + /** * The definition of the timeline panel class, which holds timeline * widgets. @@ -123,8 +130,8 @@ private: void show_time (Time); - std::tr1::shared_ptr - load_state (std::tr1::weak_ptr sequence); + shared_ptr + load_state (weak_ptr sequence); private: @@ -144,7 +151,7 @@ private: * An invisible column which will be used to identify the sequence * of a row. */ - Gtk::TreeModelColumn< std::tr1::weak_ptr > + Gtk::TreeModelColumn< weak_ptr > sequenceColumn; /** @@ -169,8 +176,9 @@ private: // Body Widgets boost::scoped_ptr timelineWidget; - std::map< std::tr1::weak_ptr, - std::tr1::shared_ptr > + std::map< weak_ptr + , shared_ptr + > timelineStates; // Toolbar Widgets diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 4af85069a..c3442902f 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -44,18 +44,17 @@ const int TimelineWidget::HeaderIndentWidth = 10; const double TimelineWidget::ZoomIncrement = 1.25; const int64_t TimelineWidget::MaxScale = 30000000; // 30 Million -TimelineWidget::TimelineWidget( - std::tr1::shared_ptr source_state) : - Table(2, 2), - layoutHelper(*this), - headerContainer(NULL), - body(NULL), - ruler(NULL), - horizontalAdjustment(0, 0, 0), - verticalAdjustment(0, 0, 0), - horizontalScroll(horizontalAdjustment), - verticalScroll(verticalAdjustment), - update_tracks_frozen(false) +TimelineWidget::TimelineWidget(shared_ptr source_state) + : Table(2, 2) + , layoutHelper(*this) + , headerContainer(NULL) + , body(NULL) + , ruler(NULL) + , horizontalAdjustment(0, 0, 0) + , verticalAdjustment(0, 0, 0) + , horizontalScroll(horizontalAdjustment) + , verticalScroll(verticalAdjustment) + , update_tracks_frozen(false) { body = manage(new TimelineBody(*this)); ENSURE(body != NULL); diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index 6bf71ef0d..39901305a 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -64,17 +64,13 @@ class TimelineWidget : public Gtk::Table { public: /** - * Constructor * @param source_state The state that will be used as the data source * for this timeline widget. */ - TimelineWidget( - std::tr1::shared_ptr source_state); + TimelineWidget (shared_ptr source_state); - /** - * Destructor - */ - ~TimelineWidget(); + virtual ~TimelineWidget(); + /* ===== Data Access ===== */ public: @@ -84,13 +80,13 @@ public: * @return The state object that the timeline widget is currently * working with. */ - std::tr1::shared_ptr get_state(); + shared_ptr get_state(); /** * Replaces the current TimelineState object with another. * @param new_state The new state to swap in. */ - void set_state(std::tr1::shared_ptr new_state); + void set_state(shared_ptr new_state); /** * Zooms the view in or out as by a number of steps while keeping a @@ -110,13 +106,13 @@ public: */ void set_tool(timeline::ToolType tool_type); - std::tr1::shared_ptr + shared_ptr get_hovering_track() const; public: /* ===== Signals ===== */ - typedef sigc::signal > TimelineStateChangeSignal; - typedef sigc::signal > HoveringTrackChangedSignal; + typedef sigc::signal > TimelineStateChangeSignal; + typedef sigc::signal > HoveringTrackChangedSignal; sigc::signal mouse_hover_signal() const; @@ -169,8 +165,8 @@ private: * already exist in trackMap. * @param list The parent track of the branch. */ - void create_timeline_tracks_from_branch( - std::tr1::shared_ptr modelTrack); + void + create_timeline_tracks_from_branch (shared_ptr modelTrack); /** * Creates a timeline UI track to correspond to a model track. @@ -178,9 +174,8 @@ private: * @return The timeline track created, or an empty shared_ptr if * modelTrack has an unreckognised type (this is an error condition). */ - std::tr1::shared_ptr - create_timeline_track_from_modelTrack( - std::tr1::shared_ptr modelTrack); + shared_ptr + create_timeline_track_from_modelTrack(shared_ptr modelTrack); /** * Removes any UI tracks which no longer have corresponding model @@ -188,10 +183,10 @@ private: */ void remove_orphaned_tracks(); - void search_orphaned_tracks_in_branch( - std::tr1::shared_ptr modelTrack, - std::map, - std::tr1::shared_ptr > &orphan_track_map); + void + search_orphaned_tracks_in_branch (shared_ptr modelTrack, + std::map, + shared_ptr > &orphan_track_map); /** * Looks up a timeline UI track in trackMap that corresponds to a @@ -201,8 +196,8 @@ private: * modelTrack has no corresponding timeline UI track (this is an * error condition). */ - std::tr1::shared_ptr lookup_timeline_track( - std::tr1::shared_ptr modelTrack) const; + shared_ptr + lookup_timeline_track (shared_ptr modelTrack) const; // ----- Layout Functions ----- // @@ -232,12 +227,12 @@ private: * Helper to get the sequence object from the state. * @return Returns a shared pointer to the sequence. */ - std::tr1::shared_ptr sequence() const; + shared_ptr sequence() const; // ----- Other Functions ----- // - void set_hovering_track( - std::tr1::shared_ptr hovering_track); + void + set_hovering_track (shared_ptr hovering_track); protected: @@ -245,7 +240,7 @@ protected: * The state that will be used as the data source for this timeline * widget. */ - std::tr1::shared_ptr state; + shared_ptr state; // Model Data @@ -256,11 +251,11 @@ protected: * widget is updated with update_tracks, timeline tracks are added and * removed from the map in correspondence with the tree. */ - std::map, - std::tr1::shared_ptr > + std::map + ,shared_ptr > trackMap; - std::tr1::shared_ptr hoveringTrack; + shared_ptr hoveringTrack; // Helper Classes timeline::TimelineLayoutHelper layoutHelper; diff --git a/src/gui/widgets/timeline/timeline-arrow-tool.cpp b/src/gui/widgets/timeline/timeline-arrow-tool.cpp index 420d3a964..8b2e0ad37 100644 --- a/src/gui/widgets/timeline/timeline-arrow-tool.cpp +++ b/src/gui/widgets/timeline/timeline-arrow-tool.cpp @@ -55,17 +55,17 @@ namespace timeline { Tool::on_button_press_event(event); // Convert the mouse click position to a Time - std::tr1::shared_ptr state = timelineBody.getTimelineWidget().get_state(); + shared_ptr state = timelineBody.getTimelineWidget().get_state(); REQUIRE(state); TimelineViewWindow const& window = state->get_view_window(); Time tpoint = window.x_to_time(mousePoint.get_x()); // Get the clip, if any - std::tr1::shared_ptr track = getHoveringTrack(); - std::tr1::shared_ptr clip = track->getClipAt(tpoint); + shared_ptr track = getHoveringTrack(); + shared_ptr clip = track->getClipAt(tpoint); // Nothing to do if there is no clip - if (clip == std::tr1::shared_ptr()) + if (!clip) return; clip->setSelected(true); @@ -77,8 +77,7 @@ namespace timeline { REQUIRE (event != NULL); Tool::on_button_release_event(event); - std::tr1::shared_ptr track = - getHoveringTrack(); + shared_ptr track = getHoveringTrack(); } void @@ -92,10 +91,10 @@ namespace timeline { return; } - std::tr1::shared_ptr + shared_ptr ArrowTool::getHoveringTrack () { - std::tr1::shared_ptr track( + shared_ptr track( timelineBody.getTimelineWidget().get_hovering_track()); return track; } diff --git a/src/gui/widgets/timeline/timeline-arrow-tool.hpp b/src/gui/widgets/timeline/timeline-arrow-tool.hpp index c2f0df070..b390a25d5 100644 --- a/src/gui/widgets/timeline/timeline-arrow-tool.hpp +++ b/src/gui/widgets/timeline/timeline-arrow-tool.hpp @@ -81,7 +81,7 @@ namespace timeline { private: - std::tr1::shared_ptr + shared_ptr getHoveringTrack (); bool selectionRectangleActive; diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index dbc6697a1..25125f2cc 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -124,7 +124,7 @@ protected: /** * The event handler for when the TimelineWidget's state is switched. */ - void on_state_changed (std::tr1::shared_ptr newState); + void on_state_changed (shared_ptr newState); /* ===== Internals ===== */ private: @@ -142,8 +142,8 @@ private: void draw_tracks(Cairo::RefPtr cr); void draw_track(Cairo::RefPtr cr, - std::tr1::shared_ptr timeline_track, - const int view_width) const; + shared_ptr timeline_track, + const int view_width) const; /** * Draws the selected timeline period. @@ -200,7 +200,7 @@ private: Cairo::RefPtr playbackPointColour; gui::widgets::TimelineWidget &timelineWidget; - std::tr1::shared_ptr timelineState; + shared_ptr timelineState; friend class Tool; diff --git a/src/gui/widgets/timeline/timeline-clip-track.cpp b/src/gui/widgets/timeline/timeline-clip-track.cpp index 9f5438d0a..f659aa1f8 100644 --- a/src/gui/widgets/timeline/timeline-clip-track.cpp +++ b/src/gui/widgets/timeline/timeline-clip-track.cpp @@ -22,9 +22,9 @@ #include -#include "timeline-clip.hpp" -#include "timeline-clip-track.hpp" -#include "timeline-view-window.hpp" +#include "gui/widgets/timeline/timeline-clip.hpp" +#include "gui/widgets/timeline/timeline-clip-track.hpp" +#include "gui/widgets/timeline/timeline-view-window.hpp" using namespace Gtk; @@ -76,7 +76,7 @@ namespace timeline { } } - std::tr1::shared_ptr + shared_ptr ClipTrack::getClipAt(Time position) const { std::pair, shared_ptr > @@ -88,7 +88,7 @@ namespace timeline { } // Nothing found - return std::tr1::shared_ptr(); + return shared_ptr(); } //// private methods @@ -98,7 +98,7 @@ namespace timeline { { // Share the draw strategy between all objects TODO("Use factory/builder to create Timline Clips"); - static std::tr1::shared_ptr drawStrategy(new BasicDrawStrategy()); + static shared_ptr drawStrategy(new BasicDrawStrategy()); BOOST_FOREACH (shared_ptr modelClip, getModelTrack()->getClipList()) { // Is a timeline UI clip present in the map already? diff --git a/src/gui/widgets/timeline/timeline-clip-track.hpp b/src/gui/widgets/timeline/timeline-clip-track.hpp index 980c37480..32b93b321 100644 --- a/src/gui/widgets/timeline/timeline-clip-track.hpp +++ b/src/gui/widgets/timeline/timeline-clip-track.hpp @@ -52,7 +52,7 @@ namespace timeline { * Constructor. */ ClipTrack(TimelineWidget &timelineWidget, - std::tr1::shared_ptr track); + shared_ptr track); /** * Draw the track in the timeline. @@ -66,7 +66,7 @@ namespace timeline { * pointer. * @param the given time */ - std::tr1::shared_ptr + shared_ptr getClipAt(Time position) const; private: @@ -80,7 +80,7 @@ namespace timeline { /** * Gets the modelTrack as a ClipTrack. */ - std::tr1::shared_ptr + shared_ptr getModelTrack (); /** @@ -107,8 +107,8 @@ namespace timeline { * The clipMap maps model clips to timeline widget clips which are responsible for the * UI representation of a clip. */ - std::map, - std::tr1::shared_ptr > + std::map, + shared_ptr > clipMap; }; diff --git a/src/gui/widgets/timeline/timeline-clip.cpp b/src/gui/widgets/timeline/timeline-clip.cpp index c6d90be45..1b4e04d72 100644 --- a/src/gui/widgets/timeline/timeline-clip.cpp +++ b/src/gui/widgets/timeline/timeline-clip.cpp @@ -27,11 +27,11 @@ namespace gui { namespace widgets { namespace timeline { - using std::tr1::shared_ptr; //////////////////////TICKET #796 + using std::tr1::shared_ptr; - Clip::Clip (std::tr1::shared_ptr clip, - std::tr1::shared_ptr drawStrategy) + Clip::Clip (shared_ptr clip, + shared_ptr drawStrategy) : Entity(drawStrategy) , modelClip(clip) , selected(false) diff --git a/src/gui/widgets/timeline/timeline-clip.hpp b/src/gui/widgets/timeline/timeline-clip.hpp index 001fb94a0..c7e6bd64b 100644 --- a/src/gui/widgets/timeline/timeline-clip.hpp +++ b/src/gui/widgets/timeline/timeline-clip.hpp @@ -49,8 +49,8 @@ namespace timeline { class Clip : public Entity { public: - Clip (std::tr1::shared_ptr clip, - std::tr1::shared_ptr drawStrategy); + Clip (shared_ptr clip, + shared_ptr drawStrategy); Time getBegin() const; @@ -62,7 +62,7 @@ namespace timeline { private: - std::tr1::shared_ptr modelClip; + shared_ptr modelClip; /** * True when this clip is selected in the GUI. diff --git a/src/gui/widgets/timeline/timeline-entity.cpp b/src/gui/widgets/timeline/timeline-entity.cpp index bc499b3d4..3f7582375 100644 --- a/src/gui/widgets/timeline/timeline-entity.cpp +++ b/src/gui/widgets/timeline/timeline-entity.cpp @@ -29,7 +29,7 @@ namespace gui { namespace widgets { namespace timeline { - Entity::Entity(std::tr1::shared_ptr drawStrategy) + Entity::Entity (shared_ptr drawStrategy) : enabled(true), drawStrategy(drawStrategy) { } diff --git a/src/gui/widgets/timeline/timeline-entity.hpp b/src/gui/widgets/timeline/timeline-entity.hpp index bfb170aee..f30a804a1 100644 --- a/src/gui/widgets/timeline/timeline-entity.hpp +++ b/src/gui/widgets/timeline/timeline-entity.hpp @@ -40,6 +40,7 @@ namespace widgets { namespace timeline { using lib::time::Time; + using std::tr1::shared_ptr; class DrawStrategy; @@ -52,7 +53,7 @@ namespace timeline { class Entity { protected: - Entity(std::tr1::shared_ptr drawStrategy); + Entity (shared_ptr drawStrategy); virtual ~Entity(); @@ -82,7 +83,7 @@ namespace timeline { bool enabled; - std::tr1::shared_ptr drawStrategy; + shared_ptr drawStrategy; }; } // namespace timeline diff --git a/src/gui/widgets/timeline/timeline-group-track.hpp b/src/gui/widgets/timeline/timeline-group-track.hpp index 822142b0d..6787c4184 100644 --- a/src/gui/widgets/timeline/timeline-group-track.hpp +++ b/src/gui/widgets/timeline/timeline-group-track.hpp @@ -26,7 +26,7 @@ #ifndef TIMELINE_GROUP_TRACK_HPP #define TIMELINE_GROUP_TRACK_HPP -#include "timeline-track.hpp" +#include "gui/widgets/timeline/timeline-track.hpp" #include "gui/model/group-track.hpp" namespace gui { @@ -36,19 +36,16 @@ namespace timeline { class GroupTrack : public timeline::Track { public: - GroupTrack(TimelineWidget &timeline_widget, - std::tr1::shared_ptr track); + GroupTrack (TimelineWidget &timeline_widget, + shared_ptr track); - void draw_track(Cairo::RefPtr cairo, - TimelineViewWindow* constwindow) - const; + void draw_track (Cairo::RefPtr cairo, + TimelineViewWindow* constwindow) const; protected: void on_child_list_changed(); }; -} // namespace timeline -} // namespace widgets -} // namespace gui +}}} // namespace gui::widgets::timeline #endif // TIMELINE_GROUP_TRACK_HPP diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 486859845..1d1af9537 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -342,12 +342,9 @@ TimelineHeaderContainer::on_scroll() } void -TimelineHeaderContainer::on_hovering_track_changed( - std::tr1::shared_ptr hovering_track) +TimelineHeaderContainer::on_hovering_track_changed( shared_ptr) { - (void)hovering_track; - - + /* do nothing */ } bool diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 6d40d621e..6c32d6ce4 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -139,8 +139,7 @@ private: */ void on_scroll(); - void on_hovering_track_changed( - std::tr1::shared_ptr hovering_track); + void on_hovering_track_changed(shared_ptr hovering_track); private: /* ===== Internal Event Handlers ===== */ @@ -168,9 +167,8 @@ private: * to control the amount of indention. * @param offset The vertical offset of the headers in pixels. */ - void draw_header_decoration( - std::tr1::shared_ptr modelTrack, - const Gdk::Rectangle &clip_rect); + void draw_header_decoration(shared_ptr modelTrack, + const Gdk::Rectangle &clip_rect); /** * A helper function which calls lookup_timeline_track within the @@ -182,8 +180,8 @@ private: * @remarks If the return value is going to be NULL, an ENSURE will * fail. */ - std::tr1::shared_ptr lookup_timeline_track( - std::tr1::shared_ptr modelTrack); + shared_ptr + lookup_timeline_track (shared_ptr modelTrack); void begin_drag(); @@ -248,7 +246,7 @@ private: int scrollSlideRate; //----- User Interaction State -----// - std::tr1::shared_ptr hoveringTrack; + shared_ptr hoveringTrack; Gdk::Point mousePoint; diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 71a55d44a..df00dd131 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -112,8 +112,8 @@ TimelineLayoutHelper::header_from_point(Gdk::Point point) return shared_ptr(); } -std::tr1::shared_ptr -TimelineLayoutHelper::track_from_y(int y) +shared_ptr +TimelineLayoutHelper::track_from_y (int y) { // Apply the scroll offset y += timelineWidget.get_y_scroll_offset(); @@ -299,8 +299,7 @@ TimelineLayoutHelper::is_animating() const } TimelineLayoutHelper::TrackTree::pre_order_iterator -TimelineLayoutHelper::iterator_from_track( - std::tr1::shared_ptr modelTrack) +TimelineLayoutHelper::iterator_from_track(shared_ptr modelTrack) { REQUIRE(modelTrack); @@ -666,7 +665,7 @@ TimelineLayoutHelper::apply_drop_to_modelTree( timelineWidget.thaw_update_tracks(); } -std::tr1::shared_ptr +shared_ptr TimelineLayoutHelper::get_sequence() const { REQUIRE(timelineWidget.state); diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 07e792e9a..2c2cca44a 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -114,8 +114,7 @@ public: * tracks. * @see update_layout() */ - std::tr1::shared_ptr header_from_point( - Gdk::Point point); + shared_ptr header_from_point (Gdk::Point point); /** * Searches for a tack which has the specified y-offset inside of it. @@ -128,15 +127,15 @@ public: * tracks. * @see update_layout() */ - std::tr1::shared_ptr track_from_y(int y); + shared_ptr track_from_y (int y); /** * Begins to drag the track under mouse_point, if there is one. * @param mouse_point The mouse point to begin dragging from, measured * in pixels from the top left of the header container widget. */ - std::tr1::shared_ptr - begin_dragging_track(const Gdk::Point &mouse_point); + shared_ptr + begin_dragging_track (Gdk::Point const& mouse_point); /** * Drops the dragging track. @@ -185,8 +184,8 @@ public: * @return Returns the model iterator of layoutTree.end() if no * iterator was found. */ - TrackTree::pre_order_iterator iterator_from_track( - std::tr1::shared_ptr modelTrack); + TrackTree::pre_order_iterator + iterator_from_track (shared_ptr modelTrack); /** * A function that recursively calculates the visible height of a @@ -262,7 +261,7 @@ protected: * @see clone_tree_from_sequence() */ void add_branch(TrackTree::iterator_base parent_iterator, - std::tr1::shared_ptr parent); + shared_ptr parent); /** * Recursively calculates the boxes for a given branch in the timeline @@ -298,8 +297,8 @@ protected: * @remarks If the return value is going to be NULL, an ENSURE will * fail. */ - std::tr1::shared_ptr lookup_timeline_track( - std::tr1::shared_ptr modelTrack); + shared_ptr + lookup_timeline_track(shared_ptr modelTrack); /** * A helper function which kicks off the animation timer. @@ -343,7 +342,8 @@ protected: * Helper to get the sequence object from the state. * @return Returns a shared pointer to the sequence. */ - std::tr1::shared_ptr get_sequence() const; + shared_ptr + get_sequence() const; protected: /** diff --git a/src/gui/widgets/timeline/timeline-ruler.cpp b/src/gui/widgets/timeline/timeline-ruler.cpp index 0b8d68f22..b8725aedf 100644 --- a/src/gui/widgets/timeline/timeline-ruler.cpp +++ b/src/gui/widgets/timeline/timeline-ruler.cpp @@ -36,7 +36,7 @@ using namespace gui; using namespace gui::widgets; using namespace gui::widgets::timeline; -using std::tr1::shared_ptr; ////////////////////TICKET #796 +using std::tr1::shared_ptr; using gui::util::CairoUtil; using lib::time::Time; using lib::time::TimeVar; diff --git a/src/gui/widgets/timeline/timeline-ruler.hpp b/src/gui/widgets/timeline/timeline-ruler.hpp index 842ce6bff..3d903aaf5 100644 --- a/src/gui/widgets/timeline/timeline-ruler.hpp +++ b/src/gui/widgets/timeline/timeline-ruler.hpp @@ -111,7 +111,7 @@ private: /** * The event handler for when the TimelineWidget's state is switched. */ - void on_state_changed (std::tr1::shared_ptr newState); ////////////////////TICKET #796 : should use std::tr1::shared_ptr + void on_state_changed (shared_ptr newState); private: /* ===== Internal Methods ===== */ @@ -242,7 +242,7 @@ private: /** * the currently active timeline state object */ - std::tr1::shared_ptr timelineState; + shared_ptr timelineState; /** * The caches image of the ruler, over which the chevrons etc. will diff --git a/src/gui/widgets/timeline/timeline-state.cpp b/src/gui/widgets/timeline/timeline-state.cpp index b55589956..74042ef39 100644 --- a/src/gui/widgets/timeline/timeline-state.cpp +++ b/src/gui/widgets/timeline/timeline-state.cpp @@ -40,7 +40,7 @@ using std::tr1::shared_ptr; -TimelineState::TimelineState (std::tr1::shared_ptr source_sequence) +TimelineState::TimelineState (shared_ptr source_sequence) : sequence(source_sequence) , viewWindow(Offset(Time::ZERO), 1) , selection_(Time::ZERO, Duration::NIL) @@ -60,7 +60,7 @@ TimelineState::TimelineState (std::tr1::shared_ptr source_seque //////////////////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all } -std::tr1::shared_ptr +shared_ptr TimelineState::get_sequence() const { return sequence; diff --git a/src/gui/widgets/timeline/timeline-state.hpp b/src/gui/widgets/timeline/timeline-state.hpp index 23e2015e7..5542b1520 100644 --- a/src/gui/widgets/timeline/timeline-state.hpp +++ b/src/gui/widgets/timeline/timeline-state.hpp @@ -29,7 +29,6 @@ #include "gui/widgets/timeline/timeline-view-window.hpp" #include "lib/time/mutation.hpp" -#include /////////////////////////TICKET #796 namespace gui { @@ -52,11 +51,10 @@ class TimelineState public: /** - * Constructor * @param source_sequence The sequence on which the TimelineWidget * will operate when this TimelineState is attached. */ - TimelineState(std::tr1::shared_ptr source_sequence); + TimelineState (shared_ptr source_sequence); public: @@ -64,7 +62,7 @@ public: * Gets the sequence that is attached to this timeline state object. * @return Returns a shared_ptr to the sequence object. */ - std::tr1::shared_ptr get_sequence() const; + shared_ptr get_sequence() const; /** * Gets a reference to the timeline view window object. @@ -122,7 +120,7 @@ private: * @remarks This pointer is set by the constructor and is constant, so * will not change in value during the lifetime of the class. */ - std::tr1::shared_ptr sequence; + shared_ptr sequence; // View State /** diff --git a/src/gui/widgets/timeline/timeline-tool.hpp b/src/gui/widgets/timeline/timeline-tool.hpp index f34cb5d32..7c54a36a5 100644 --- a/src/gui/widgets/timeline/timeline-tool.hpp +++ b/src/gui/widgets/timeline/timeline-tool.hpp @@ -133,7 +133,7 @@ protected: /** * A helper function to get the state */ - std::tr1::shared_ptr get_state() const; + shared_ptr get_state() const; /** * A helper function to get the view window diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index b0267dea3..ac1c6e4d1 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -125,7 +125,7 @@ shared_ptr Track::getClipAt(Time) const { // Default implementation returns empty pointer - return std::tr1::shared_ptr(); + return shared_ptr(); } void @@ -272,7 +272,7 @@ void Track::on_remove_track() { REQUIRE(modelTrack); - std::tr1::shared_ptr state = timelineWidget.get_state(); + shared_ptr state = timelineWidget.get_state(); REQUIRE(state); state->get_sequence()->remove_descendant_track(modelTrack); diff --git a/src/gui/widgets/timeline/timeline-track.hpp b/src/gui/widgets/timeline/timeline-track.hpp index 796b1f130..dc7b18129 100644 --- a/src/gui/widgets/timeline/timeline-track.hpp +++ b/src/gui/widgets/timeline/timeline-track.hpp @@ -72,20 +72,14 @@ public: Collapse }; - /** - * Constructor - */ Track(TimelineWidget &timeline_widget, - std::tr1::shared_ptr track); - - /** - * Destructor - */ - ~Track(); + shared_ptr track); + + virtual ~Track(); Gtk::Widget& get_header_widget(); - std::tr1::shared_ptr //////////////////////////////TICKET #796 : should use std::tr1 + shared_ptr getModelTrack() const; /** @@ -155,7 +149,7 @@ public: * The default implementation simply returns an empty pointer. * @param the given time */ - virtual std::tr1::shared_ptr //////////////////////////////TICKET #796 : should use std::tr1 + virtual shared_ptr getClipAt (Time position) const; private: @@ -209,7 +203,7 @@ private: protected: TimelineWidget &timelineWidget; - std::tr1::shared_ptr modelTrack; + shared_ptr modelTrack; private: /** diff --git a/src/gui/widgets/timeline/timeline-zoom-scale.cpp b/src/gui/widgets/timeline/timeline-zoom-scale.cpp index 083513647..7452d20cd 100644 --- a/src/gui/widgets/timeline/timeline-zoom-scale.cpp +++ b/src/gui/widgets/timeline/timeline-zoom-scale.cpp @@ -90,7 +90,7 @@ TimelineZoomScale::TimelineZoomScale() } void -TimelineZoomScale::wireTimelineState (std::tr1::shared_ptr currentState, +TimelineZoomScale::wireTimelineState (shared_ptr currentState, TimelineWidget::TimelineStateChangeSignal stateChangeSignal) { on_timeline_state_changed (currentState); @@ -98,7 +98,7 @@ TimelineZoomScale::wireTimelineState (std::tr1::shared_ptr curren } void -TimelineZoomScale::on_timeline_state_changed (std::tr1::shared_ptr newState) +TimelineZoomScale::on_timeline_state_changed (shared_ptr newState) { REQUIRE (newState); timelineState = newState; diff --git a/src/gui/widgets/timeline/timeline-zoom-scale.hpp b/src/gui/widgets/timeline/timeline-zoom-scale.hpp index ec106ad94..a57fdd6df 100644 --- a/src/gui/widgets/timeline/timeline-zoom-scale.hpp +++ b/src/gui/widgets/timeline/timeline-zoom-scale.hpp @@ -51,7 +51,7 @@ public: */ sigc::signal signal_zoom(); - void wireTimelineState (std::tr1::shared_ptr currentState, + void wireTimelineState (shared_ptr currentState, TimelineWidget::TimelineStateChangeSignal); private: @@ -61,7 +61,7 @@ private: * Update the slider position when the timeline state * is changed. */ - void on_timeline_state_changed (std::tr1::shared_ptr newState); ////////////////////TICKET #796 : should use std::tr1::shared_ptr + void on_timeline_state_changed (shared_ptr newState); /** * Event handler for when the zoomIn Button @@ -96,7 +96,7 @@ private: const double button_step_size; - std::tr1::shared_ptr timelineState; + shared_ptr timelineState; }; } // namespace gui diff --git a/src/gui/window-manager.hpp b/src/gui/window-manager.hpp index 1f0eb3a46..e06b0f4ee 100644 --- a/src/gui/window-manager.hpp +++ b/src/gui/window-manager.hpp @@ -46,6 +46,7 @@ namespace gui { using std::string; +using std::tr1::shared_ptr; namespace model { class Project; } @@ -194,7 +195,7 @@ private: private: - std::list< std::tr1::shared_ptr > windowList; + std::list > windowList; public: diff --git a/tests/components/proc/asset/orderingofassetstest.cpp b/tests/components/proc/asset/orderingofassetstest.cpp index cff898acd..130b55bfe 100644 --- a/tests/components/proc/asset/orderingofassetstest.cpp +++ b/tests/components/proc/asset/orderingofassetstest.cpp @@ -52,7 +52,7 @@ namespace asset { * or resort to template metaprogramming tricks. * Just providing templated comparison operators * would generally override the behaviour of - * boost::shared_ptr, which is not desirable. + * std::shared_ptr, which is not desirable. * @see Asset::Ident#compare */ class OrderingOfAssets_test : public Test diff --git a/tests/lib/factorytest.cpp b/tests/lib/factorytest.cpp index 8e46771c2..dbf6dddb4 100644 --- a/tests/lib/factorytest.cpp +++ b/tests/lib/factorytest.cpp @@ -61,7 +61,7 @@ namespace test{ /** Test-Factory specialised to create TargetObj instances * using the 1-argument constructor TargetObj::TargetObj(int). - * It will create boost::shared_ptr instances, because + * It will create std::shared_ptr instances, because * factory::RefcountFac was parametrised with this smart pointer type. */ class ObjFactory : public factory::RefcountFac @@ -79,7 +79,7 @@ namespace test{ /** shorthand for the created smart-pointer class, - * here it's a (refcounting) boost::shared_ptr + * here it's a (refcounting) std::shared_ptr */ typedef ObjFactory::PType pTarget; @@ -93,7 +93,7 @@ namespace test{ /******************************************************************* * @test the basic object creation Factory behaviour: We declared * a static field TargetObj::create to be a ObjFactory. So, - * by invoking this functor, we get a boost::shared_ptr + * by invoking this functor, we get a std::shared_ptr * wrapping a new TargetObj instance. From this we copy * further shared-ptrs, invoke a member function and * finally, when leaving the scope, our TargetObj From 606251749e943d49e96df39124a0e0054be8e643 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 22 Oct 2011 21:20:44 +0200 Subject: [PATCH 05/68] fix time::Control should properly include --- src/lib/time/control-impl.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/time/control-impl.hpp b/src/lib/time/control-impl.hpp index 1d2ab6d94..c950724d7 100644 --- a/src/lib/time/control-impl.hpp +++ b/src/lib/time/control-impl.hpp @@ -57,6 +57,7 @@ #include "lib/time/mutation.hpp" #include "lib/time/timevalue.hpp" +#include #include @@ -64,6 +65,8 @@ namespace lib { namespace time { namespace mutation { + using std::tr1::function; + From 4f1d7e1d3fb84e43bed9de4b298c95fbb3390bb9 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 22 Oct 2011 21:21:40 +0200 Subject: [PATCH 06/68] clean-up GUI includes. Solving problems with tr1::ref vs. boost::ref --- src/gui/panels/panel.hpp | 3 ++- src/gui/panels/viewer-panel.cpp | 4 ++-- src/gui/panels/viewer-panel.hpp | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/gui/panels/panel.hpp b/src/gui/panels/panel.hpp index 1a9801250..a6f508403 100644 --- a/src/gui/panels/panel.hpp +++ b/src/gui/panels/panel.hpp @@ -27,11 +27,12 @@ #ifndef PANEL_HPP #define PANEL_HPP -#include #include "gui/gtk-lumiera.hpp" #include "gui/widgets/panel-bar.hpp" +#include + namespace gui { namespace workspace { diff --git a/src/gui/panels/viewer-panel.cpp b/src/gui/panels/viewer-panel.cpp index 692f82308..955b92e3e 100644 --- a/src/gui/panels/viewer-panel.cpp +++ b/src/gui/panels/viewer-panel.cpp @@ -21,13 +21,13 @@ * *****************************************************/ #include "gui/gtk-lumiera.hpp" +#include "gui/panels/viewer-panel.hpp" +#include "gui/workspace/workspace-window.hpp" #include "gui/controller/controller.hpp" #include "gui/controller/playback-controller.hpp" #include "gui/display-service.hpp" -#include "gui/workspace/workspace-window.hpp" -#include "viewer-panel.hpp" using namespace Gtk; using namespace gui::widgets; diff --git a/src/gui/panels/viewer-panel.hpp b/src/gui/panels/viewer-panel.hpp index ae41516c1..7fe5cace3 100644 --- a/src/gui/panels/viewer-panel.hpp +++ b/src/gui/panels/viewer-panel.hpp @@ -26,11 +26,12 @@ #ifndef VIEWER_PANEL_HPP #define VIEWER_PANEL_HPP -#include -#include "panel.hpp" +#include "gui/panels/panel.hpp" #include "gui/widgets/video-display-widget.hpp" +#include + namespace gui { namespace panels { From b39edad306c3f5fe35d712ed5595200813c89a66 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 22 Oct 2011 21:19:57 +0200 Subject: [PATCH 07/68] clean-up some additional mentions of boost::ref --- src/lib/wrapper.hpp | 4 ++-- tests/components/proc/control/command-use2-test.cpp | 2 +- .../proc/mobject/session/session-modify-parts-test.cpp | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib/wrapper.hpp b/src/lib/wrapper.hpp index 8a7761263..d1065612f 100644 --- a/src/lib/wrapper.hpp +++ b/src/lib/wrapper.hpp @@ -64,7 +64,7 @@ namespace wrapper { /** - * Extension to boost::reference_wrapper: + * Extension to std::reference_wrapper: * Allows additionally to re-bind to another reference, * almost like a pointer. Helpful for building templates. * @warning potentially dangerous @@ -128,7 +128,7 @@ namespace wrapper { * A copyable, assignable value object, not managing ownership. * It can be default constructed and \c bool evaluated to detect * an empty holder. The value is retrieved pointer-like, by - * explicit dereferentiation. (Contrast this to boost::ref, + * explicit dereferentiation. (Contrast this to std::ref, * where the original reference is retrieved by conversion) * * The purpose of this template is to be able to remember diff --git a/tests/components/proc/control/command-use2-test.cpp b/tests/components/proc/control/command-use2-test.cpp index 29d5c6c90..8fec714fa 100644 --- a/tests/components/proc/control/command-use2-test.cpp +++ b/tests/components/proc/control/command-use2-test.cpp @@ -46,7 +46,7 @@ namespace test { using boost::str; using std::tr1::function; using std::tr1::bind; - using boost::ref; + using std::tr1::ref; using boost::lexical_cast; using util::contains; diff --git a/tests/components/proc/mobject/session/session-modify-parts-test.cpp b/tests/components/proc/mobject/session/session-modify-parts-test.cpp index 481e6f136..6d04accdd 100644 --- a/tests/components/proc/mobject/session/session-modify-parts-test.cpp +++ b/tests/components/proc/mobject/session/session-modify-parts-test.cpp @@ -34,11 +34,10 @@ #include "lib/query.hpp" #include -#include #include #include -using boost::ref; +using std::tr1::ref; using std::tr1::placeholders::_1; using util::isSameObject; using util::and_all; From 6046749f190ef07e9bab77e3b4349a04c6a1c38a Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Sat, 22 Oct 2011 04:29:55 -0500 Subject: [PATCH 08/68] Integrating time::Control into ibeam tool. --- src/gui/widgets/timeline-widget.cpp | 4 ++-- src/gui/widgets/timeline/timeline-body.cpp | 6 ++++++ src/gui/widgets/timeline/timeline-body.hpp | 4 ++++ src/gui/widgets/timeline/timeline-ibeam-tool.cpp | 7 ++----- src/gui/widgets/timeline/timeline-ibeam-tool.hpp | 7 ++++++- src/gui/widgets/timeline/timeline-state.hpp | 2 +- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index c3442902f..52008f0cc 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -62,7 +62,7 @@ TimelineWidget::TimelineWidget(shared_ptr source_state) ENSURE(headerContainer != NULL); ruler = manage(new TimelineRuler(*this)); ENSURE(ruler != NULL); - + horizontalAdjustment.signal_value_changed().connect( sigc::mem_fun( this, &TimelineWidget::on_scroll) ); verticalAdjustment.signal_value_changed().connect( sigc::mem_fun( @@ -71,7 +71,7 @@ TimelineWidget::TimelineWidget(shared_ptr source_state) this, &TimelineWidget::on_motion_in_body_notify_event) ); update_tracks(); - + attach(*body, 1, 2, 1, 2, FILL|EXPAND, FILL|EXPAND); attach(*ruler, 1, 2, 0, 1, FILL|EXPAND, SHRINK); attach(*headerContainer, 0, 1, 1, 2, SHRINK, FILL|EXPAND); diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index d546ada65..369b894ed 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -82,6 +82,12 @@ TimelineBody::getTimelineWidget () const return timelineWidget; } +TimeSpan +TimelineBody::get_selection() +{ + return timelineWidget.get_state()->get_selection(); +} + ToolType TimelineBody::get_tool() const { diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index 25125f2cc..16b3b13e7 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -46,6 +46,7 @@ class TimelineWidget; namespace timeline { using lib::time::TimeVar; +using lib::time::TimeSpan; class Track; @@ -73,6 +74,9 @@ public: TimelineWidget& getTimelineWidget () const; + TimeSpan + get_selection(); + /** * Returns the type of the currently selected timeline tool. */ diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp index 71aeef656..c8becb870 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp @@ -24,8 +24,6 @@ #include "gui/widgets/timeline-widget.hpp" #include "lib/time/mutation.hpp" -#include - using namespace gui::widgets; using lib::time::Mutation; @@ -45,12 +43,11 @@ const int IBeamTool::ScrollSlideEventInterval = 40; IBeamTool::IBeamTool(TimelineBody &timeline_body) : Tool(timeline_body), + selectionControl(), dragType(None), pinnedDragTime(), scrollSlideRate(0) -{ - -} +{ } IBeamTool::~IBeamTool() { diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.hpp b/src/gui/widgets/timeline/timeline-ibeam-tool.hpp index 291305cde..22cf6862f 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.hpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.hpp @@ -30,14 +30,17 @@ #include "gui/widgets/timeline/timeline-tool.hpp" #include "lib/time/timevalue.hpp" +#include "lib/time/timequant.hpp" +#include "lib/time/control.hpp" -#include namespace gui { namespace widgets { namespace timeline { using lib::time::TimeVar; +using lib::time::TimeSpan; +using lib::time::Control; /** * A helper class to implement the timeline i-beam tool @@ -159,6 +162,8 @@ private: }; /* ==== Internals ===== */ + Control selectionControl; + /** * Specifies the type of drag currently taking place. */ diff --git a/src/gui/widgets/timeline/timeline-state.hpp b/src/gui/widgets/timeline/timeline-state.hpp index 5542b1520..6446e7790 100644 --- a/src/gui/widgets/timeline/timeline-state.hpp +++ b/src/gui/widgets/timeline/timeline-state.hpp @@ -70,7 +70,7 @@ public: */ timeline::TimelineViewWindow& get_view_window(); - + TimeSpan get_selection() const { return selection_; } Time getSelectionStart() const { return selection_.start();} Time getSelectionEnd() const { return selection_.end(); } Time getPlaybackPeriodStart() const { return selection_.start();} From ca634bdd9ca34b2db54e3789432d7019f63f5af6 Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Thu, 13 Oct 2011 14:55:43 -0500 Subject: [PATCH 09/68] House Cleaning --- src/gui/model/clip.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/model/clip.cpp b/src/gui/model/clip.cpp index 2b7dc6cd6..f78e2c2af 100644 --- a/src/gui/model/clip.cpp +++ b/src/gui/model/clip.cpp @@ -32,7 +32,7 @@ namespace gui { namespace model { Clip::Clip() - : timeCoord_(Time(FSecs(1)), FSecs(2)) + : timeCoord_(Time(FSecs(1)), FSecs(3)) { } @@ -40,14 +40,14 @@ namespace model { Clip::setBegin (Time newStartTime) { timeCoord_.accept (Mutation::changeTime (newStartTime)); - // TODO: emit signal + TODO("Emit A Signal"); } void Clip::setDuration (Duration newLength) { timeCoord_.accept (Mutation::changeDuration(newLength)); - // TODO: emit signal + TODO("Emit A Signal"); } void From c9671b654e8b19ac9fc2d49afb17836eff05d50e Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Sat, 22 Oct 2011 19:03:17 -0500 Subject: [PATCH 10/68] time::Control Integration First Commit --- .../widgets/timeline/timeline-ibeam-tool.cpp | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp index c8becb870..7672bcf01 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp @@ -47,7 +47,10 @@ IBeamTool::IBeamTool(TimelineBody &timeline_body) : dragType(None), pinnedDragTime(), scrollSlideRate(0) -{ } +{ + // Connect the timlinebody selection to the selectionControl + this->get_state()->get_selection().accept(selectionControl); +} IBeamTool::~IBeamTool() { @@ -117,9 +120,14 @@ IBeamTool::on_button_press_event(GdkEventButton* event) // User began the drag in clear space, begin a Select drag dragType = Selection; pinnedDragTime = time; - state->setSelection (Mutation::changeTime(time)); - state->setSelection (Mutation::changeDuration(Duration::NIL)); - //////////////////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all + selectionControl (TimeSpan(time, Duration::NIL)); + state->selection_changed_signal().emit(); + std::cout << "\n" << std::string(time) << "\n"; + std::cout << std::string(state->get_selection().start()) << "\n\n"; + + //state->setSelection (Mutation::changeTime (time)); + //state->setSelection (Mutation::changeDuration (Duration::NIL)); + ////////////"//////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all } } } @@ -193,12 +201,14 @@ IBeamTool::set_leading_x(const int x) const bool set_playback_period = dragType == Selection; TimeVar newStartPoint (state->get_view_window().x_to_time(x)); Offset selectionLength (pinnedDragTime, newStartPoint); - + if (newStartPoint > pinnedDragTime) newStartPoint=pinnedDragTime; // use the smaller one as selection start - - state->setSelection (Mutation::changeTime(newStartPoint) , set_playback_period); - state->setSelection (Mutation::changeDuration(selectionLength), set_playback_period); + + // selectionControl (TimeSpan(newStartPoint, Duration(selectionLength))); + + //state->setSelection (Mutation::changeTime(newStartPoint) , set_playback_period); + // state->setSelection (Mutation::changeDuration(selectionLength), set_playback_period); //////////////////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all at once } From 4acc9d247a6fec161fdcd6c8e4d6db9550c43d20 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 23 Oct 2011 02:41:57 +0200 Subject: [PATCH 11/68] maybe fix: try to connect the selection control the other way round --- src/gui/widgets/timeline/timeline-ibeam-tool.cpp | 3 ++- src/gui/widgets/timeline/timeline-state.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp index 7672bcf01..59d5345be 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp @@ -49,11 +49,12 @@ IBeamTool::IBeamTool(TimelineBody &timeline_body) : scrollSlideRate(0) { // Connect the timlinebody selection to the selectionControl - this->get_state()->get_selection().accept(selectionControl); + this->get_state()->setSelection (selectionControl, false); } IBeamTool::~IBeamTool() { + selectionControl.disconnect(); end_scroll_slide(); } diff --git a/src/gui/widgets/timeline/timeline-state.hpp b/src/gui/widgets/timeline/timeline-state.hpp index 6446e7790..0d0b02a32 100644 --- a/src/gui/widgets/timeline/timeline-state.hpp +++ b/src/gui/widgets/timeline/timeline-state.hpp @@ -78,6 +78,7 @@ public: Time getPlaybackPoint() const { return playbackPoint_; } + /** is there currently any ongoing playback process? * Otherwise the #getPlaybackPoint is meaningless */ bool isPlaying() const { return isPlayback_; } From 0378f9266e5e910aefdd81d5330973222d6d7734 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 23 Oct 2011 02:42:25 +0200 Subject: [PATCH 12/68] fix misspelling in library --- src/lib/time/control-impl.hpp | 2 +- src/lib/time/control.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/time/control-impl.hpp b/src/lib/time/control-impl.hpp index c950724d7..25e96dc07 100644 --- a/src/lib/time/control-impl.hpp +++ b/src/lib/time/control-impl.hpp @@ -151,7 +151,7 @@ namespace mutation { /** disconnect any observers */ void - disconnnect() + disconnect() { listeners_.clear(); } diff --git a/src/lib/time/control.hpp b/src/lib/time/control.hpp index 486097934..f7f78e4d1 100644 --- a/src/lib/time/control.hpp +++ b/src/lib/time/control.hpp @@ -151,7 +151,7 @@ namespace time { /** disconnect from observed entity and * cease any change notification */ - void disconnnect(); + void disconnect(); }; @@ -209,7 +209,7 @@ namespace time { template void - Control::disconnnect() + Control::disconnect() { notifyListeners_.disconnect(); this->unbind(); From 9c04637aea97eea6cf3cee6ed117d9ba8c24d5ef Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 23 Oct 2011 02:42:25 +0200 Subject: [PATCH 13/68] fix misspelling in library --- src/lib/time/control-impl.hpp | 2 +- src/lib/time/control.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/time/control-impl.hpp b/src/lib/time/control-impl.hpp index c950724d7..25e96dc07 100644 --- a/src/lib/time/control-impl.hpp +++ b/src/lib/time/control-impl.hpp @@ -151,7 +151,7 @@ namespace mutation { /** disconnect any observers */ void - disconnnect() + disconnect() { listeners_.clear(); } diff --git a/src/lib/time/control.hpp b/src/lib/time/control.hpp index 486097934..f7f78e4d1 100644 --- a/src/lib/time/control.hpp +++ b/src/lib/time/control.hpp @@ -151,7 +151,7 @@ namespace time { /** disconnect from observed entity and * cease any change notification */ - void disconnnect(); + void disconnect(); }; @@ -209,7 +209,7 @@ namespace time { template void - Control::disconnnect() + Control::disconnect() { notifyListeners_.disconnect(); this->unbind(); From 8ff36fc209b3aa6db539c22494ea2c5d64751278 Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Sat, 22 Oct 2011 20:27:29 -0500 Subject: [PATCH 14/68] Timeline selection is now controlled by lib::time::Control --- src/gui/widgets/timeline/timeline-ibeam-tool.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp index 59d5345be..02d6cbd74 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp @@ -121,14 +121,8 @@ IBeamTool::on_button_press_event(GdkEventButton* event) // User began the drag in clear space, begin a Select drag dragType = Selection; pinnedDragTime = time; - selectionControl (TimeSpan(time, Duration::NIL)); + selectionControl (TimeSpan(time, Duration::NIL)); //TODO: TimelineState Needs a listener for selection changes state->selection_changed_signal().emit(); - std::cout << "\n" << std::string(time) << "\n"; - std::cout << std::string(state->get_selection().start()) << "\n\n"; - - //state->setSelection (Mutation::changeTime (time)); - //state->setSelection (Mutation::changeDuration (Duration::NIL)); - ////////////"//////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all } } } @@ -206,11 +200,9 @@ IBeamTool::set_leading_x(const int x) if (newStartPoint > pinnedDragTime) newStartPoint=pinnedDragTime; // use the smaller one as selection start - // selectionControl (TimeSpan(newStartPoint, Duration(selectionLength))); - - //state->setSelection (Mutation::changeTime(newStartPoint) , set_playback_period); - // state->setSelection (Mutation::changeDuration(selectionLength), set_playback_period); - //////////////////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all at once + //TODO: TimelineState Needs a listener for selection changes + selectionControl (TimeSpan (newStartPoint, Duration(selectionLength))); + state->selection_changed_signal().emit(); } void From 38111835466ba428a5a25a54536d1f698f6fe741 Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Sat, 22 Oct 2011 21:53:23 -0500 Subject: [PATCH 15/68] Added SelectionListener handling selection changing events --- .../widgets/timeline/timeline-ibeam-tool.cpp | 3 +- src/gui/widgets/timeline/timeline-state.cpp | 21 ++++++- src/gui/widgets/timeline/timeline-state.hpp | 55 ++++++++++++++++++- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp index 02d6cbd74..cd397bf3f 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp @@ -49,7 +49,8 @@ IBeamTool::IBeamTool(TimelineBody &timeline_body) : scrollSlideRate(0) { // Connect the timlinebody selection to the selectionControl - this->get_state()->setSelection (selectionControl, false); + // TODO: Create a virtual initialize function in the base class + get_state()->set_selection_control(selectionControl); } IBeamTool::~IBeamTool() diff --git a/src/gui/widgets/timeline/timeline-state.cpp b/src/gui/widgets/timeline/timeline-state.cpp index 74042ef39..70a8521cc 100644 --- a/src/gui/widgets/timeline/timeline-state.cpp +++ b/src/gui/widgets/timeline/timeline-state.cpp @@ -24,6 +24,7 @@ #include "gui/widgets/timeline/timeline-state.hpp" #include "lib/time/timevalue.hpp" #include "lib/time/mutation.hpp" +#include "lib/time/control.hpp" using namespace Gtk; using namespace sigc; @@ -36,14 +37,15 @@ using lib::time::FSecs; using lib::time::Offset; using lib::time::Duration; using lib::time::Mutation; +using lib::time::Control; using std::tr1::shared_ptr; - TimelineState::TimelineState (shared_ptr source_sequence) : sequence(source_sequence) , viewWindow(Offset(Time::ZERO), 1) , selection_(Time::ZERO, Duration::NIL) + , selectionListener() , playbackPeriod_(Time::ZERO, Duration::NIL) , playbackPoint_(Time::ZERO) , isPlayback_(false) @@ -55,6 +57,9 @@ TimelineState::TimelineState (shared_ptr source_sequence) viewWindow.set_time_scale(DEFAULT_TIMELINE_SCALE); + selectionListener.connect( + mem_fun(*this, &TimelineState::on_selection_changed)); + setSelection (Mutation::changeTime (Time(FSecs(2)))); setSelection (Mutation::changeDuration(Duration(FSecs(2)))); //////////////////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all @@ -97,6 +102,14 @@ TimelineState::setPlaybackPoint (Time newPosition) playbackChangedSignal.emit(); } +void +TimelineState::set_selection_control (SelectionControl &control) +{ + control.disconnect(); + selection_.accept (control); + control.connectChangeNotification (selectionListener); +} + sigc::signal TimelineState::selection_changed_signal() const { @@ -109,6 +122,12 @@ TimelineState::playback_changed_signal() const return playbackChangedSignal; } +void +TimelineState::on_selection_changed() +{ + selectionChangedSignal.emit(); +} + } // namespace timeline } // namespace widgets } // namespace gui diff --git a/src/gui/widgets/timeline/timeline-state.hpp b/src/gui/widgets/timeline/timeline-state.hpp index 0d0b02a32..2033665db 100644 --- a/src/gui/widgets/timeline/timeline-state.hpp +++ b/src/gui/widgets/timeline/timeline-state.hpp @@ -28,6 +28,7 @@ #include "gui/widgets/timeline/timeline-view-window.hpp" #include "lib/time/mutation.hpp" +#include "lib/time/control.hpp" namespace gui { @@ -38,9 +39,42 @@ class Sequence; namespace widgets { namespace timeline { - + +using lib::time::Control; using lib::time::Mutation; +typedef Control SelectionControl; + +/** + * SelectionListener is a template class which emits a signal when + * the value is changed by it's associated time::Control object. + */ +template +class SelectionListener + : boost::noncopyable + { + sigc::signal valueChangedSignal; + public: + SelectionListener() + { + + } + + + void + operator() (TI const& changeValue) const + { + valueChangedSignal.emit(); + } + + + void connect (const sigc::slot &connection) + { + valueChangedSignal.connect (connection); + } + + }; + /** * TimelineState is a container for the state data for TimelineWidget. * @remarks TimelineState s can be swapped out so that TimelineWidget @@ -70,7 +104,11 @@ public: */ timeline::TimelineViewWindow& get_view_window(); - TimeSpan get_selection() const { return selection_; } + TimeSpan& get_selection() { return selection_; } + + SelectionListener& + get_selection_listener() { return selectionListener; } + Time getSelectionStart() const { return selection_.start();} Time getSelectionEnd() const { return selection_.end(); } Time getPlaybackPeriodStart() const { return selection_.start();} @@ -83,6 +121,7 @@ public: * Otherwise the #getPlaybackPoint is meaningless */ bool isPlaying() const { return isPlayback_; } + void set_selection_control (SelectionControl &control); /** * Sets the period of the selection. @@ -113,6 +152,15 @@ public: * changed. */ sigc::signal playback_changed_signal() const; + +private: + + /* ========= Event Handlers ========== */ + + /** + * Event handler for when the selection is changed + */ + void on_selection_changed(); private: @@ -134,6 +182,9 @@ private: /** currently selected time period. */ TimeSpan selection_; + /** listens for a selection change */ + SelectionListener selectionListener; + /** current playback period. */ TimeSpan playbackPeriod_; From b87b6078ada0773a333ff269b68902052cb64463 Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Sun, 23 Oct 2011 00:20:48 -0500 Subject: [PATCH 16/68] Adding TimeSpan param to SelectionListener's signal --- src/gui/widgets/timeline/timeline-ibeam-tool.cpp | 13 ++++++------- src/gui/widgets/timeline/timeline-state.cpp | 7 +++++-- src/gui/widgets/timeline/timeline-state.hpp | 12 +++++++----- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp index cd397bf3f..6f20997e7 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp @@ -49,8 +49,7 @@ IBeamTool::IBeamTool(TimelineBody &timeline_body) : scrollSlideRate(0) { // Connect the timlinebody selection to the selectionControl - // TODO: Create a virtual initialize function in the base class - get_state()->set_selection_control(selectionControl); + get_state()->set_selection_control (selectionControl); } IBeamTool::~IBeamTool() @@ -122,8 +121,7 @@ IBeamTool::on_button_press_event(GdkEventButton* event) // User began the drag in clear space, begin a Select drag dragType = Selection; pinnedDragTime = time; - selectionControl (TimeSpan(time, Duration::NIL)); //TODO: TimelineState Needs a listener for selection changes - state->selection_changed_signal().emit(); + selectionControl (TimeSpan(time, Duration::NIL)); } } } @@ -194,16 +192,17 @@ IBeamTool::set_leading_x(const int x) { shared_ptr state = get_state(); - const bool set_playback_period = dragType == Selection; + // The line below needs handled differently now; + // + //const bool set_playback_period = dragType == Selection; + TimeVar newStartPoint (state->get_view_window().x_to_time(x)); Offset selectionLength (pinnedDragTime, newStartPoint); if (newStartPoint > pinnedDragTime) newStartPoint=pinnedDragTime; // use the smaller one as selection start - //TODO: TimelineState Needs a listener for selection changes selectionControl (TimeSpan (newStartPoint, Duration(selectionLength))); - state->selection_changed_signal().emit(); } void diff --git a/src/gui/widgets/timeline/timeline-state.cpp b/src/gui/widgets/timeline/timeline-state.cpp index 70a8521cc..3e512cc1e 100644 --- a/src/gui/widgets/timeline/timeline-state.cpp +++ b/src/gui/widgets/timeline/timeline-state.cpp @@ -51,7 +51,10 @@ TimelineState::TimelineState (shared_ptr source_sequence) , isPlayback_(false) { REQUIRE(sequence); - + + // Initialize the listener + selectionListener (TimeSpan (Time::ZERO, Duration::NIL)); + ////////////////////////////////////////////////////////////TICKET #798: how to handle GUI default state const int64_t DEFAULT_TIMELINE_SCALE =21000000; @@ -123,7 +126,7 @@ TimelineState::playback_changed_signal() const } void -TimelineState::on_selection_changed() +TimelineState::on_selection_changed (TimeSpan selection) { selectionChangedSignal.emit(); } diff --git a/src/gui/widgets/timeline/timeline-state.hpp b/src/gui/widgets/timeline/timeline-state.hpp index 2033665db..f4bc57e75 100644 --- a/src/gui/widgets/timeline/timeline-state.hpp +++ b/src/gui/widgets/timeline/timeline-state.hpp @@ -48,27 +48,29 @@ typedef Control SelectionControl; /** * SelectionListener is a template class which emits a signal when * the value is changed by it's associated time::Control object. + * SelectionListener wraps a sigc::signal that emits every time + * the selection is changed */ + template class SelectionListener : boost::noncopyable { - sigc::signal valueChangedSignal; + sigc::signal valueChangedSignal; public: SelectionListener() { } - void operator() (TI const& changeValue) const { - valueChangedSignal.emit(); + valueChangedSignal.emit(changeValue); } - void connect (const sigc::slot &connection) + void connect (const sigc::slot &connection) { valueChangedSignal.connect (connection); } @@ -160,7 +162,7 @@ private: /** * Event handler for when the selection is changed */ - void on_selection_changed(); + void on_selection_changed (TimeSpan selection); private: From 6c17d06e66fef79796c2d99dd98d0c680dc3186f Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Sun, 23 Oct 2011 04:20:39 -0500 Subject: [PATCH 17/68] Timeline is no longer zoomed in to far on startup. See timline-view-window.hpp int64_t timeScale for explanation --- src/gui/panels/timeline-panel.cpp | 25 +++++++------- .../widgets/timeline/timeline-ibeam-tool.cpp | 4 +-- src/gui/widgets/timeline/timeline-state.cpp | 15 ++++----- src/gui/widgets/timeline/timeline-state.hpp | 6 ++-- .../widgets/timeline/timeline-view-window.hpp | 7 ++++ .../widgets/timeline/timeline-zoom-scale.cpp | 33 ++++++++++--------- .../widgets/timeline/timeline-zoom-scale.hpp | 2 ++ 7 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index 7d5b4fa6c..0036be478 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -138,12 +138,13 @@ TimelinePanel::TimelinePanel (workspace::PanelManager &panel_manager, // wire the zoom slider to react on timeline state changes zoomScale.wireTimelineState (timelineWidget->get_state(), timelineWidget->state_changed_signal()); - + // Set the initial UI state update_sequence_chooser(); update_tool_buttons(); update_zoom_buttons(); show_time (Time::ZERO); + std::cout << timelineWidget->get_state()->get_view_window().get_time_scale() << "\n"; } const char* @@ -335,17 +336,17 @@ TimelinePanel::update_zoom_buttons() { REQUIRE(timelineWidget); - const shared_ptr state = - timelineWidget->get_state(); - if(state) - { - timeline::TimelineViewWindow &viewWindow = - state->get_view_window(); - - zoomIn.set_sensitive(viewWindow.get_time_scale() != 1); - zoomOut.set_sensitive(viewWindow.get_time_scale() - != TimelineWidget::MaxScale); - } + int64_t current_scale = + timelineWidget->get_state()->get_view_window().get_time_scale(); + + double linear_scale = + (double) current_scale / (double) TimelineWidget::MaxScale; + + /* We have to Revese the Smoothing */ + double new_relative_scale = + pow(linear_scale,(1.0/9.0)); + + timelineWidget->zoom_view (new_relative_scale); } void diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp index 6f20997e7..67da78ecd 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp @@ -180,8 +180,8 @@ IBeamTool::on_motion_notify_event(GdkEventMotion *event) bool IBeamTool::on_scroll_slide_timer() { - const Gdk::Rectangle body_rect(get_body_rectangle()); - view_window().shift_view(body_rect.get_width(), scrollSlideRate); + const Gdk::Rectangle body_rect (get_body_rectangle()); + view_window().shift_view (body_rect.get_width(), scrollSlideRate); // Return true to keep the timer going return true; diff --git a/src/gui/widgets/timeline/timeline-state.cpp b/src/gui/widgets/timeline/timeline-state.cpp index 3e512cc1e..a38911ff5 100644 --- a/src/gui/widgets/timeline/timeline-state.cpp +++ b/src/gui/widgets/timeline/timeline-state.cpp @@ -52,19 +52,18 @@ TimelineState::TimelineState (shared_ptr source_sequence) { REQUIRE(sequence); - // Initialize the listener + // Initialize the selection listener selectionListener (TimeSpan (Time::ZERO, Duration::NIL)); - - ////////////////////////////////////////////////////////////TICKET #798: how to handle GUI default state - const int64_t DEFAULT_TIMELINE_SCALE =21000000; - - viewWindow.set_time_scale(DEFAULT_TIMELINE_SCALE); - selectionListener.connect( mem_fun(*this, &TimelineState::on_selection_changed)); + ////////////////////////////////////////////////////////////TICKET #798: how to handle GUI default state + const int64_t DEFAULT_TIMELINE_SCALE =6400; + + viewWindow.set_time_scale(DEFAULT_TIMELINE_SCALE); + setSelection (Mutation::changeTime (Time(FSecs(2)))); - setSelection (Mutation::changeDuration(Duration(FSecs(2)))); + setSelection (Mutation::changeDuration (Duration(FSecs(2)))); //////////////////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all } diff --git a/src/gui/widgets/timeline/timeline-state.hpp b/src/gui/widgets/timeline/timeline-state.hpp index f4bc57e75..45ef48d13 100644 --- a/src/gui/widgets/timeline/timeline-state.hpp +++ b/src/gui/widgets/timeline/timeline-state.hpp @@ -49,7 +49,9 @@ typedef Control SelectionControl; * SelectionListener is a template class which emits a signal when * the value is changed by it's associated time::Control object. * SelectionListener wraps a sigc::signal that emits every time - * the selection is changed + * the selection is changed by the time::Control object. + * SelectionListener does NOT emit the signal if a change to the + * selection is made outside of the Control/Listener partnership. */ template @@ -66,7 +68,7 @@ class SelectionListener void operator() (TI const& changeValue) const { - valueChangedSignal.emit(changeValue); + valueChangedSignal.emit (changeValue); } diff --git a/src/gui/widgets/timeline/timeline-view-window.hpp b/src/gui/widgets/timeline/timeline-view-window.hpp index b9536deac..d52f84406 100644 --- a/src/gui/widgets/timeline/timeline-view-window.hpp +++ b/src/gui/widgets/timeline/timeline-view-window.hpp @@ -138,6 +138,13 @@ public: private: TimeVar timeOffset; + + /** + * The scale of the Timline Body. + * @remarks This value represents the time span that is visible in + * the TimelineBodyWidget. Smaller numbers here will "zoom in" + * while larger numbers will "zoom out" + */ int64_t timeScale; sigc::signal changedSignal; diff --git a/src/gui/widgets/timeline/timeline-zoom-scale.cpp b/src/gui/widgets/timeline/timeline-zoom-scale.cpp index 7452d20cd..2ee413c71 100644 --- a/src/gui/widgets/timeline/timeline-zoom-scale.cpp +++ b/src/gui/widgets/timeline/timeline-zoom-scale.cpp @@ -65,26 +65,27 @@ TimelineZoomScale::TimelineZoomScale() , button_step_size(0.03) { /* Setup the Slider Control */ - slider.set_adjustment(adjustment); - slider.set_size_request(123,10); - slider.set_digits(6); - slider.set_inverted(true); - slider.set_draw_value(false); + slider.set_adjustment (adjustment); + slider.set_size_request (123,10); + slider.set_digits (6); + + /* Inverted because smaller values "zoom in" */ + slider.set_inverted (true); + + slider.set_draw_value (false); /* Make our connections */ zoomIn.signal_clicked(). - connect(sigc::mem_fun(this, &TimelineZoomScale::on_zoom_in_clicked)); - + connect (sigc::mem_fun(this, &TimelineZoomScale::on_zoom_in_clicked)); zoomOut.signal_clicked(). - connect(sigc::mem_fun(this, &TimelineZoomScale::on_zoom_out_clicked)); - + connect (sigc::mem_fun(this, &TimelineZoomScale::on_zoom_out_clicked)); adjustment.signal_value_changed(). - connect(sigc::mem_fun(this, &TimelineZoomScale::on_zoom)); + connect (sigc::mem_fun(this, &TimelineZoomScale::on_zoom)); /* Add Our Widgets and show them */ - pack_start(zoomOut,PACK_SHRINK); - pack_start(slider,PACK_SHRINK); - pack_start(zoomIn,PACK_SHRINK); + pack_start (zoomOut,PACK_SHRINK); + pack_start (slider,PACK_SHRINK); + pack_start (zoomIn,PACK_SHRINK); show_all(); } @@ -94,7 +95,8 @@ TimelineZoomScale::wireTimelineState (shared_ptr currentState, TimelineWidget::TimelineStateChangeSignal stateChangeSignal) { on_timeline_state_changed (currentState); - stateChangeSignal.connect (sigc::mem_fun(this, &TimelineZoomScale::on_timeline_state_changed)); + stateChangeSignal.connect ( + sigc::mem_fun(this, &TimelineZoomScale::on_timeline_state_changed)); } void @@ -110,7 +112,6 @@ TimelineZoomScale::on_timeline_state_changed (shared_ptr newState (double) current_scale / (double) TimelineWidget::MaxScale; /* We have to Revese the Smoothing */ - TODO("Find a central place for ZoomSmoothingFactor Variable. right now it is 9.0"); double new_relative_scale = pow(linear_scale,(1.0/9.0)); @@ -134,7 +135,7 @@ TimelineZoomScale::on_zoom_out_clicked() void TimelineZoomScale::on_zoom() { - zoomSignal.emit(adjustment.get_value()) ; + zoomSignal.emit (adjustment.get_value()) ; } sigc::signal diff --git a/src/gui/widgets/timeline/timeline-zoom-scale.hpp b/src/gui/widgets/timeline/timeline-zoom-scale.hpp index a57fdd6df..694252319 100644 --- a/src/gui/widgets/timeline/timeline-zoom-scale.hpp +++ b/src/gui/widgets/timeline/timeline-zoom-scale.hpp @@ -51,6 +51,8 @@ public: */ sigc::signal signal_zoom(); + void set_value(double val) { adjustment.set_value(val); } + void wireTimelineState (shared_ptr currentState, TimelineWidget::TimelineStateChangeSignal); From 0aa3ca76d1d8a2af6e06616869e02143d8e66eb8 Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Sun, 23 Oct 2011 04:45:10 -0500 Subject: [PATCH 18/68] Created and Applied TimelineWidget::ZoomSmoothing --- src/gui/panels/timeline-panel.cpp | 16 +++------------- src/gui/widgets/timeline-widget.cpp | 3 ++- src/gui/widgets/timeline-widget.hpp | 1 + .../widgets/timeline/timeline-view-window.cpp | 5 +++-- src/gui/widgets/timeline/timeline-zoom-scale.cpp | 2 +- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index 0036be478..0366504c6 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -334,19 +334,9 @@ TimelinePanel::update_tool_buttons() void TimelinePanel::update_zoom_buttons() { - REQUIRE(timelineWidget); - - int64_t current_scale = - timelineWidget->get_state()->get_view_window().get_time_scale(); - - double linear_scale = - (double) current_scale / (double) TimelineWidget::MaxScale; - - /* We have to Revese the Smoothing */ - double new_relative_scale = - pow(linear_scale,(1.0/9.0)); - - timelineWidget->zoom_view (new_relative_scale); +/* This function is no longer needed + * TODO: Let the ZoomScaleWidget perform + * the update on its own */ } void diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 52008f0cc..b971477c6 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -41,7 +41,8 @@ namespace widgets { const int TimelineWidget::TrackPadding = 1; const int TimelineWidget::HeaderWidth = 150; const int TimelineWidget::HeaderIndentWidth = 10; -const double TimelineWidget::ZoomIncrement = 1.25; +const double TimelineWidget::ZoomIncrement = 1.25; // Not currently used +const double TimelineWidget::ZoomSmoothing = 9.0; const int64_t TimelineWidget::MaxScale = 30000000; // 30 Million TimelineWidget::TimelineWidget(shared_ptr source_state) diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index 39901305a..b5d57c667 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -285,6 +285,7 @@ public: * to 30000000 lumiera::Time increments. */ static const int64_t MaxScale; + static const double ZoomSmoothing; protected: static const int TrackPadding; diff --git a/src/gui/widgets/timeline/timeline-view-window.cpp b/src/gui/widgets/timeline/timeline-view-window.cpp index 07e017e07..9e80d2f9c 100644 --- a/src/gui/widgets/timeline/timeline-view-window.cpp +++ b/src/gui/widgets/timeline/timeline-view-window.cpp @@ -88,9 +88,10 @@ TimelineViewWindow::set_time_scale(double ratio) void TimelineViewWindow::zoom_view(int point, double time_scale_ratio) { - TODO("Find a Central place for a Zoom Smoothing Factor Variable. Right now it is hard coded at 9.0"); + // Apply the smoothing factor int64_t new_time_scale = - (int64_t)( pow(time_scale_ratio, 9.0) * (double)TimelineWidget::MaxScale); + (int64_t)( pow(time_scale_ratio, TimelineWidget::ZoomSmoothing) * + (double)TimelineWidget::MaxScale); /* Prevent Zooming in To Close and Far */ if(new_time_scale < 1) diff --git a/src/gui/widgets/timeline/timeline-zoom-scale.cpp b/src/gui/widgets/timeline/timeline-zoom-scale.cpp index 2ee413c71..dfa71f858 100644 --- a/src/gui/widgets/timeline/timeline-zoom-scale.cpp +++ b/src/gui/widgets/timeline/timeline-zoom-scale.cpp @@ -113,7 +113,7 @@ TimelineZoomScale::on_timeline_state_changed (shared_ptr newState /* We have to Revese the Smoothing */ double new_relative_scale = - pow(linear_scale,(1.0/9.0)); + pow(linear_scale,(1.0 / TimelineWidget::ZoomSmoothing)); adjustment.set_value(new_relative_scale); } From 1bb584f895a544fb5075ecd0de344f771e84a331 Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Sun, 23 Oct 2011 04:52:30 -0500 Subject: [PATCH 19/68] Removed some TODO's --- src/gui/widgets/timeline/timeline-view-window.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-view-window.cpp b/src/gui/widgets/timeline/timeline-view-window.cpp index 9e80d2f9c..8b6528f11 100644 --- a/src/gui/widgets/timeline/timeline-view-window.cpp +++ b/src/gui/widgets/timeline/timeline-view-window.cpp @@ -35,8 +35,7 @@ TimelineViewWindow::TimelineViewWindow (Offset offset, int64_t scale) : timeOffset(offset) , timeScale(scale) { - TODO("Create a function to limit timescale between 1 and MaxScale"); - TODO("TICKET #795 Some functions need to be private"); + } Offset @@ -90,7 +89,7 @@ TimelineViewWindow::zoom_view(int point, double time_scale_ratio) { // Apply the smoothing factor int64_t new_time_scale = - (int64_t)( pow(time_scale_ratio, TimelineWidget::ZoomSmoothing) * + (int64_t)(pow(time_scale_ratio, TimelineWidget::ZoomSmoothing) * (double)TimelineWidget::MaxScale); /* Prevent Zooming in To Close and Far */ @@ -102,8 +101,8 @@ TimelineViewWindow::zoom_view(int point, double time_scale_ratio) // The view must be shifted so that the zoom is centred on the cursor TimeVar newStartPoint = get_time_offset(); - newStartPoint += TimeValue(point * (timeScale - new_time_scale)); - set_time_offset(newStartPoint); + newStartPoint += TimeValue (point * (timeScale - new_time_scale)); + set_time_offset (newStartPoint); // Apply the new scale set_time_scale(new_time_scale); @@ -112,13 +111,13 @@ TimelineViewWindow::zoom_view(int point, double time_scale_ratio) void TimelineViewWindow::shift_view(int view_width, int shift_size) { - set_time_offset(timeOffset + TimeValue(timeScale * shift_size * view_width / 256)); + set_time_offset (timeOffset + TimeValue(timeScale * shift_size * view_width / 256)); } int TimelineViewWindow::time_to_x(TimeValue const& time) const { - return int(_raw(time - timeOffset) / timeScale); //////TODO protect against values out-of range + return int (_raw(time - timeOffset) / timeScale); //////TODO protect against values out-of range } Time From 65a29244af010519668eee5940182d136dac4f8d Mon Sep 17 00:00:00 2001 From: "Michael R. Fisher" Date: Sun, 23 Oct 2011 09:52:12 -0500 Subject: [PATCH 20/68] The tool also needs updated on TimelineState Change --- src/gui/widgets/timeline/timeline-body.cpp | 14 ++++++++++---- src/gui/widgets/timeline/timeline-body.hpp | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index 369b894ed..e64110997 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -57,9 +57,12 @@ TimelineBody::TimelineBody (TimelineWidget &timelineWidget) timelineWidget.state_changed_signal().connect( sigc::mem_fun(this, &TimelineBody::on_state_changed) ); + // Set a default Tool + this->set_tool(Arrow); + // Install style properties register_styles(); - + // Reset the state propagateStateChange(); } @@ -96,10 +99,10 @@ TimelineBody::get_tool() const } void -TimelineBody::set_tool(timeline::ToolType tool_type) +TimelineBody::set_tool(timeline::ToolType tool_type, bool force) { // Tidy up old tool - if(tool) + if(tool && !force) { // Do we need to change tools? if(tool->get_type() == tool_type) @@ -322,7 +325,10 @@ TimelineBody::propagateStateChange() viewWindow().changed_signal().connect( sigc::mem_fun(this, &TimelineBody::on_update_view) ); } - + + // Need to reload the current tool... + set_tool (get_tool(), true); + // Redraw queue_draw(); } diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index 16b3b13e7..8abf01a3f 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -88,7 +88,7 @@ public: * @param tool_type The type of tool to set. */ void - set_tool(ToolType tool_type); + set_tool(ToolType tool_type, bool force=false); /* ===== Events ===== */ protected: From f7a3fdb7a5abf3829320c8edca863c9d7eb4f5a7 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 23 Oct 2011 22:06:32 +0200 Subject: [PATCH 21/68] fix further test glitches (due to using real random numbers now) --- tests/lib/polymorphic-value-test.cpp | 2 +- tests/lib/time/digxel-test.cpp | 13 +++++++++++-- tests/lib/util-floordiv-test.cpp | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/lib/polymorphic-value-test.cpp b/tests/lib/polymorphic-value-test.cpp index 8ee1ef356..eacf30933 100644 --- a/tests/lib/polymorphic-value-test.cpp +++ b/tests/lib/polymorphic-value-test.cpp @@ -117,7 +117,7 @@ namespace test{ virtual long apiFunc() { - long rr = ii * (rand() % MAX_RAND); + long rr = ii * (1 + rand() % MAX_RAND); mark (rr); _callSum += rr; return rr; diff --git a/tests/lib/time/digxel-test.cpp b/tests/lib/time/digxel-test.cpp index b99656233..809558352 100644 --- a/tests/lib/time/digxel-test.cpp +++ b/tests/lib/time/digxel-test.cpp @@ -27,6 +27,7 @@ #include "lib/time/digxel.hpp" #include "lib/util.hpp" +#include #include #include #include @@ -55,7 +56,15 @@ namespace test{ { double arbitrary = (rand() % RAND_RANGE); arbitrary /= (1 + rand() % RAND_DENOM); - return arbitrary; + + static double prevVal; + if (arbitrary != prevVal) + { + prevVal = arbitrary; + return arbitrary; + } + else + return randomFrac(); } inline uint @@ -267,7 +276,7 @@ namespace test{ CHECK (d1 == d2); - double someValue = randomFrac(); + double someValue = d1 + randomFrac(); d1 = someValue; CHECK (d1 == someValue); diff --git a/tests/lib/util-floordiv-test.cpp b/tests/lib/util-floordiv-test.cpp index dad2a40b7..63c14a1a6 100644 --- a/tests/lib/util-floordiv-test.cpp +++ b/tests/lib/util-floordiv-test.cpp @@ -25,6 +25,7 @@ #include "lib/util.hpp" #include +#include #include #include #include From 76a6407a5ef32945e5f7d561a9b2966b120d6f54 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 23 Oct 2011 04:09:51 +0200 Subject: [PATCH 22/68] better formulation for the buffer metadata state machine --- src/proc/engine/buffer-metadata.hpp | 32 +++++++++++------------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index 6addaf574..03b04c4d9 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -374,28 +374,20 @@ namespace engine { virtual Entry& mark (BufferState newState) { - switch (this->state_) + __must_not_be_NIL(); + __must_not_be_FREE(); + + if ( (state_ == LOCKED && newState == EMITTED) + ||(state_ == EMITTED && newState == BLOCKED) + ||(state_ == BLOCKED && newState == FREE)) { - case NIL: __must_not_be_NIL(); - case FREE: __must_not_be_FREE(); - - case LOCKED: - if (newState == EMITTED) break; // allow transition - - case EMITTED: - if (newState == BLOCKED) break; // allow transition - - case BLOCKED: - if (newState == FREE) // note fall through for LOCKED and EMITTED too - { - buffer_ = 0; - break; // allow transition - } - default: - throw error::Fatal ("Invalid buffer state encountered."); + // allowed transition + if (newState == FREE) buffer_ = 0; + state_ = newState; + return *this; } - state_ = newState; - return *this; + + throw error::Fatal ("Invalid buffer state encountered."); } From c4ff87c3a8ed8e6d0626c677def6f2d28d5183af Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 24 Oct 2011 01:03:56 +0200 Subject: [PATCH 23/68] decide about the basic way to implement concrete buffer metadata --- src/proc/engine/buffer-metadata.hpp | 57 ++++++++++++++----- .../proc/engine/buffer-metadata-test.cpp | 4 +- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index 03b04c4d9..eb97a8833 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -77,6 +77,7 @@ namespace engine { class Key; class Entry; } + class Metadata; @@ -275,6 +276,12 @@ namespace engine { } } + /** + * Description of a Buffer-"type". + * Key elements will be used to generate hash IDs, + * to be embedded into a BufferDescriptor. + * Keys are chained hierarchically. + */ class Key { HashVal parent_; @@ -347,21 +354,46 @@ namespace engine { }; + /** + * A complete metadata Entry, based on a Key. + * This special Key element usually describes an actual Buffer. + * Entries are to be managed in a hashtable, which is "the metadata table". + * As a special case, an entry without a concrete buffer storage pointer + * can be created. This corresponds to a (plain) key and describes just + * a buffer type. Such type-only entries are fixed to the NIL state. + * All other entries allow for state transitions. + * + * The "metadata table" with its entries is maintained by an engine::Metadata + * instance. For the latter, Entry serves as representation and access point + * to the individual metadata; this includes using the TypeHandler for + * building and destroying buffer structures. + */ class Entry : public Key { BufferState state_; const void* buffer_; + protected: + Entry (Key const& parent, const void* bufferPtr =0) + : Key(parent) + , state_(bufferPtr? LOCKED:NIL) + , buffer_(bufferPtr) + { } + + /// Metadata is allowed to create + friend class engine::Metadata; + + // standard copy operations permitted + public: - virtual BufferState + BufferState state() const { - __must_not_be_NIL(); return state_; } - virtual const void* + const void* access() const { __must_not_be_NIL(); @@ -371,7 +403,7 @@ namespace engine { return buffer_; } - virtual Entry& + Entry& mark (BufferState newState) { __must_not_be_NIL(); @@ -391,6 +423,7 @@ namespace engine { } + private: void __must_not_be_NIL() const { @@ -409,7 +442,7 @@ namespace engine { , LUMIERA_ERROR_LIFECYCLE ); } }; - } + }//namespace metadata @@ -451,7 +484,7 @@ namespace engine { Key key ( size_t storageSize , TypeHandler instanceFunc =RAW_BUFFER - , LocalKey specifics =UNSPECIFIC) + , LocalKey specifics =UNSPECIFIC) { REQUIRE (storageSize); Key typeKey = trackKey (family_, storageSize); @@ -489,16 +522,14 @@ namespace engine { UNIMPLEMENTED ("create sub-object key for concrete buffer"); } - Key const& + Entry& get (HashVal hashID) - { - UNIMPLEMENTED ("access the plain key entry"); - } - - Entry& - get (Key key) { UNIMPLEMENTED ("access, possibly create metadata records"); + ////////////////////////////////////////////////////////////////TODO: how can we 'possibly create' without knowing the buffer pointer?? + + ////////////////////////////////////////////////////////////////TODO: thus, this should only access existing buffer (not type) entries + ////////////////////////////////////////////////////////////////TODO: ==> contradiction: Entry is subclass of Key. What's the point of this lookup? } bool diff --git a/tests/components/proc/engine/buffer-metadata-test.cpp b/tests/components/proc/engine/buffer-metadata-test.cpp index f76c4fb44..b109b9fa0 100644 --- a/tests/components/proc/engine/buffer-metadata-test.cpp +++ b/tests/components/proc/engine/buffer-metadata-test.cpp @@ -133,7 +133,7 @@ namespace test { CHECK ( isSameObject (meta_->get(key), meta_->get(key1))); CHECK (!isSameObject (meta_->get(key), meta_->get(key2))); - // entries retrieved this far are inactive (type only) entries + // entries retrieved thus far were inactive (type only) entries Metadata::Entry& m1 = meta_->get(key); CHECK (NIL == m1.state()); CHECK (!meta_->isLocked(key)); @@ -234,7 +234,7 @@ namespace test { // for the TestFrame buffers, additionally we'd have to create/attach an object attachTestFrame.createAttached (frames+0); ////////////////////////////////////////TODO: shouldn't this happen automatically?? - attachTestFrame.createAttached (frames+1); + attachTestFrame.createAttached (frames+1); //////////////////////////TODO: answer: yes. Metadata is exactly the entity which has all necessary information attachTestFrame.createAttached (frames+2); CHECK (f0.access() == frames+0); From 9af0fb096f357bd367059f8de3e4c05be8ea9eea Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 24 Oct 2011 02:14:08 +0200 Subject: [PATCH 24/68] WIP draft implementation of buffer metadata creation/storage --- src/proc/engine/buffer-metadata.hpp | 80 ++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index eb97a8833..23a4ed125 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -516,32 +516,77 @@ namespace engine { return trackKey (parentKey, specifics); } - Key + /** shortcut to access the Key part of a (probably new) Entry + * describing a concrete buffer at the given address + * @note might create/register a new Entry as a side-effect + */ + Key const& key (Key const& parentKey, const void* concreteBuffer) { - UNIMPLEMENTED ("create sub-object key for concrete buffer"); + return get (parentKey,concreteBuffer); } + /** core operation to access or create a concrete buffer metadata entry. + * The hashID of the entry in question is built, based on the parentKey, + * which denotes a buffer type, and the concrete buffer address. If yet + * unknown, a new concrete buffer metadata Entry is created and initialised + * to LOCKED state. Otherwise just the existing Entry is fetched. + * @param parentKey a key describing the \em type of the buffer + * @param concreteBuffer storage pointer, must not be NULL + * @param onlyNew disallows fetching an existing entry + * @throw error::Logic when #onlyNew is set, but an equivalent entry + * was registered previously. This indicates a serious error + * in buffer lifecycle management. + * @return reference to the entry stored in the metadata table. + * @warning the exposed reference might become invalid when the + * buffer is released or re-used later. + */ + Entry& + get (Key const& parentKey, const void* concreteBuffer, bool onlyNew =false) + { + Entry newEntry(parentKey, concreteBuffer); + Entry* existing = table_.fetch (newEntry); + if (existing && onlyNew) + throw error::Logic ("Attempt to lock a slot for a new buffer, " + "while actually the old buffer is still locked." + , error::LUMIERA_ERROR_LIFECYCLE ); + + if (!existing) + return table_.store (newEntry); + else + return *existing; + } + + /** access the metadata record registered with the given hash key. + * This might be a pseudo entry in case of a Key describing a buffer type. + * Otherwise, the entry associated with a concrete buffer pointer is returned + * by reference, an can be modified (e.g. state change) + * @param hashID which can be calculated from the Key + * @throw error::Invalid when there is no such entry + * @note use #isKnown to check existence + */ Entry& get (HashVal hashID) { - UNIMPLEMENTED ("access, possibly create metadata records"); - ////////////////////////////////////////////////////////////////TODO: how can we 'possibly create' without knowing the buffer pointer?? + Entry* entry = table_.fetch (hashID); + if (!entry) + throw error::Invalid ("Attempt to access an unknown buffer metadata entry"); - ////////////////////////////////////////////////////////////////TODO: thus, this should only access existing buffer (not type) entries - ////////////////////////////////////////////////////////////////TODO: ==> contradiction: Entry is subclass of Key. What's the point of this lookup? + return *entry; } bool isKnown (HashVal key) const { - UNIMPLEMENTED ("diagnostics: known record?"); + return bool(table_.fetch (key)); } bool isLocked (HashVal key) const { - UNIMPLEMENTED ("diagnostics: actually locked buffer instance record?"); + Entry* entry = table_.fetch (key); + return entry + && entry->isLocked(); } @@ -565,7 +610,7 @@ namespace engine { maybeStore (Key const& key) { if (isKnown (key)) return; - UNIMPLEMENTED ("registry for type keys"); + table_.store (Entry (key, NULL)); } }; @@ -581,24 +626,23 @@ namespace engine { inline Metadata::Entry& Metadata::markLocked (Key const& parentKey, const void* buffer) { - UNIMPLEMENTED ("transition to locked state"); if (!buffer) throw error::Fatal ("Attempt to lock for a NULL buffer. Allocation floundered?" , error::LUMIERA_ERROR_BOTTOM_VALUE); - Key newKey = this->key (parentKey, buffer); - if (isLocked(newKey)) - throw error::Logic ("Attempt to lock a slot for a new buffer, " - "while actually the old buffer is still locked." - , error::LUMIERA_ERROR_LIFECYCLE ); - - return this->get(newKey); + return this->get (parentKey, buffer, true); // force creation of a new entry } inline void Metadata::release (HashVal key) { - UNIMPLEMENTED ("metadata memory management"); + Entry* entry = table_.fetch (key); + if (!entry) return; + if (entry && (FREE != entry->state())) + throw error::Logic ("Attempt to release a buffer still in use" + , error::LUMIERA_ERROR_LIFECYCLE); + + table_.remove (key); } From c8cdf914eb6ac347eb30055b8506008d0ac19cad Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 28 Oct 2011 01:11:39 +0200 Subject: [PATCH 25/68] review metadata storage, stub the actual access operations --- src/proc/engine/buffer-metadata.hpp | 69 ++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index 23a4ed125..333256759 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -387,6 +387,39 @@ namespace engine { // standard copy operations permitted public: + /** is this Entry currently associated to a + * concrete buffer? Is this buffer in use? */ + bool + isLocked() const + { + ASSERT (NIL != state_ && FREE != state_); + return bool(buffer_); + } + + /** is this Entry just an (abstract) placeholder for a type? + * @return false if it's a real entry corresponding to a concrete buffer + */ + bool + isTypeKey() const + { + return !bool(buffer_); + } + + /** @note hiding the base implementation to support storing + * and lookup of individual entries in a hashtable */ + operator HashVal() const + { + return isTypeKey()? Key::operator HashVal() + : chainedHash (parentKey(), buffer_); + } + + HashVal + parentKey() const + { + return isTypeKey()? Key::parentKey() + : Key::operator HashVal(); + } + BufferState state() const { @@ -442,6 +475,32 @@ namespace engine { , LUMIERA_ERROR_LIFECYCLE ); } }; + + + /** + * (Hash)Table to store and manage buffer metadata + */ + class Table + { + public: + Entry* + fetch (HashVal hashID) const + { + UNIMPLEMENTED ("fetch metadata record by ID"); + } + + Entry& + store (Entry const& newEntry) + { + UNIMPLEMENTED ("store new metadata record"); + } + + void + remove (HashVal hashID) + { + UNIMPLEMENTED ("delete metadata record"); + } + }; }//namespace metadata @@ -454,6 +513,8 @@ namespace engine { Literal id_; HashVal family_; + metadata::Table table_; + public: typedef metadata::Key Key; @@ -533,10 +594,12 @@ namespace engine { * to LOCKED state. Otherwise just the existing Entry is fetched. * @param parentKey a key describing the \em type of the buffer * @param concreteBuffer storage pointer, must not be NULL - * @param onlyNew disallows fetching an existing entry + * @param onlyNew disallow fetching an existing entry * @throw error::Logic when #onlyNew is set, but an equivalent entry * was registered previously. This indicates a serious error * in buffer lifecycle management. + * @throw error::Invalid when invoked with NULL buffer. Use the #key + * functions instead to register and track type keys. * @return reference to the entry stored in the metadata table. * @warning the exposed reference might become invalid when the * buffer is released or re-used later. @@ -544,6 +607,10 @@ namespace engine { Entry& get (Key const& parentKey, const void* concreteBuffer, bool onlyNew =false) { + if (!concreteBuffer) + throw error::Invalid ("Attempt to lock a slot for a NULL buffer" + , error::LUMIERA_ERROR_BOTTOM_VALUE); + Entry newEntry(parentKey, concreteBuffer); Entry* existing = table_.fetch (newEntry); if (existing && onlyNew) From c91e703682a2058867dd0ec8686fd3120b395471 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 28 Oct 2011 01:18:22 +0200 Subject: [PATCH 26/68] rename the core type BufferMetadata makes the purpose more clear, and moreover it matches the header filename --- src/proc/engine/buffer-metadata.hpp | 18 ++++++------ src/proc/engine/buffer-provider.cpp | 2 +- src/proc/engine/buffer-provider.hpp | 4 +-- .../proc/engine/buffer-metadata-test.cpp | 28 +++++++++---------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index 333256759..9fa6d2e71 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -77,7 +77,7 @@ namespace engine { class Key; class Entry; } - class Metadata; + class BufferMetadata; @@ -363,7 +363,7 @@ namespace engine { * a buffer type. Such type-only entries are fixed to the NIL state. * All other entries allow for state transitions. * - * The "metadata table" with its entries is maintained by an engine::Metadata + * The "metadata table" with its entries is maintained by an engine::BufferMetadata * instance. For the latter, Entry serves as representation and access point * to the individual metadata; this includes using the TypeHandler for * building and destroying buffer structures. @@ -381,8 +381,8 @@ namespace engine { , buffer_(bufferPtr) { } - /// Metadata is allowed to create - friend class engine::Metadata; + /// BufferMetadata is allowed to create + friend class engine::BufferMetadata; // standard copy operations permitted @@ -507,7 +507,7 @@ namespace engine { - class Metadata + class BufferMetadata : boost::noncopyable { Literal id_; @@ -527,7 +527,7 @@ namespace engine { * @param implementationID to distinguish families * of type keys belonging to different registries. */ - Metadata (Literal implementationID) + BufferMetadata (Literal implementationID) : id_(implementationID) , family_(hash_value(id_)) { } @@ -690,8 +690,8 @@ namespace engine { /** */ - inline Metadata::Entry& - Metadata::markLocked (Key const& parentKey, const void* buffer) + inline BufferMetadata::Entry& + BufferMetadata::markLocked (Key const& parentKey, const void* buffer) { if (!buffer) throw error::Fatal ("Attempt to lock for a NULL buffer. Allocation floundered?" @@ -701,7 +701,7 @@ namespace engine { } inline void - Metadata::release (HashVal key) + BufferMetadata::release (HashVal key) { Entry* entry = table_.fetch (key); if (!entry) return; diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp index e0670cd73..f0d1b337f 100644 --- a/src/proc/engine/buffer-provider.cpp +++ b/src/proc/engine/buffer-provider.cpp @@ -36,7 +36,7 @@ namespace engine { BufferProvider::BufferProvider (Literal implementationID) - : meta_(new Metadata (implementationID)) + : meta_(new BufferMetadata (implementationID)) { } BufferProvider::~BufferProvider() { } diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp index ca6382d66..97712c712 100644 --- a/src/proc/engine/buffer-provider.hpp +++ b/src/proc/engine/buffer-provider.hpp @@ -56,7 +56,7 @@ namespace engine { using lib::Literal; - class Metadata; + class BufferMetadata; /** @@ -71,7 +71,7 @@ namespace engine { class BufferProvider : boost::noncopyable { - scoped_ptr meta_; + scoped_ptr meta_; protected: BufferProvider (Literal implementationID); diff --git a/tests/components/proc/engine/buffer-metadata-test.cpp b/tests/components/proc/engine/buffer-metadata-test.cpp index b109b9fa0..dd55542e2 100644 --- a/tests/components/proc/engine/buffer-metadata-test.cpp +++ b/tests/components/proc/engine/buffer-metadata-test.cpp @@ -83,7 +83,7 @@ namespace test { class BufferMetadata_test : public Test { /** common Metadata table to be tested */ - scoped_ptr meta_; + scoped_ptr meta_; virtual void run (Arg) @@ -99,7 +99,7 @@ namespace test { ensure_proper_fixture() { if (!meta_) - meta_.reset(new Metadata("BufferMetadata_test")); + meta_.reset(new BufferMetadata("BufferMetadata_test")); return (SIZE_A != SIZE_B) && (JUST_SOMETHING != meta_->key(SIZE_A)) @@ -112,11 +112,11 @@ namespace test { verifyBasicProperties() { // retrieve some type keys - Metadata::Key key = meta_->key(SIZE_A); + metadata::Key key = meta_->key(SIZE_A); CHECK (key); - Metadata::Key key1 = meta_->key(SIZE_A); - Metadata::Key key2 = meta_->key(SIZE_B); + metadata::Key key1 = meta_->key(SIZE_A); + metadata::Key key2 = meta_->key(SIZE_B); CHECK (key1); CHECK (key2); CHECK (key == key1); @@ -134,7 +134,7 @@ namespace test { CHECK (!isSameObject (meta_->get(key), meta_->get(key2))); // entries retrieved thus far were inactive (type only) entries - Metadata::Entry& m1 = meta_->get(key); + metadata::Entry& m1 = meta_->get(key); CHECK (NIL == m1.state()); CHECK (!meta_->isLocked(key)); @@ -142,7 +142,7 @@ namespace test { VERIFY_ERROR (LIFECYCLE, m1.mark(LOCKED) ); // now create an active (buffer) entry - Metadata::Entry& m2 = meta_->markLocked (key, SOME_POINTER); + metadata::Entry& m2 = meta_->markLocked (key, SOME_POINTER); CHECK (!isSameObject (m1,m2)); CHECK (NIL == m1.state()); CHECK (LOCKED == m2.state()); @@ -197,10 +197,10 @@ namespace test { { // to build a descriptor for a buffer holding a TestFrame TypeHandler attachTestFrame = TypeHandler::create(); - Metadata::Key bufferType1 = meta_->key(sizeof(TestFrame), attachTestFrame); + metadata::Key bufferType1 = meta_->key(sizeof(TestFrame), attachTestFrame); // to build a descriptor for a raw buffer of size SIZE_B - Metadata::Key rawBuffType = meta_->key(SIZE_B); + metadata::Key rawBuffType = meta_->key(SIZE_B); // to announce using a number of buffers of this type LocalKey transaction1(1); @@ -219,12 +219,12 @@ namespace test { // a real-world BufferProvider would use some kind of allocator // track individual buffers by metadata entries - Metadata::Entry f0 = meta_->markLocked(bufferType1, &frames[0]); - Metadata::Entry f1 = meta_->markLocked(bufferType1, &frames[1]); - Metadata::Entry f2 = meta_->markLocked(bufferType1, &frames[2]); + metadata::Entry f0 = meta_->markLocked(bufferType1, &frames[0]); + metadata::Entry f1 = meta_->markLocked(bufferType1, &frames[1]); + metadata::Entry f2 = meta_->markLocked(bufferType1, &frames[2]); - Metadata::Entry r0 = meta_->markLocked(bufferType1, &rawbuf[0]); - Metadata::Entry r1 = meta_->markLocked(bufferType1, &rawbuf[1]); + metadata::Entry r0 = meta_->markLocked(bufferType1, &rawbuf[0]); + metadata::Entry r1 = meta_->markLocked(bufferType1, &rawbuf[1]); CHECK (LOCKED == f0.state()); CHECK (LOCKED == f1.state()); From f849ca62d99f07fbd968c1ad5d4980434dd1f9cf Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 29 Oct 2011 02:41:56 +0200 Subject: [PATCH 27/68] implement metadata storage (hash)table not passing all tests yet --- src/proc/engine/buffer-metadata.hpp | 97 ++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 9 deletions(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index 9fa6d2e71..19c18eecb 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -57,8 +57,11 @@ #include "lib/error.hpp" #include "lib/symbol.hpp" #include "lib/functor-util.hpp" +#include "lib/util-foreach.hpp" +#include "include/logging.h" #include +#include #include #include @@ -67,6 +70,7 @@ namespace engine { using lib::HashVal; using lib::Literal; + using util::for_each; using std::tr1::bind; using std::tr1::function; using std::tr1::placeholders::_1; @@ -392,7 +396,7 @@ namespace engine { bool isLocked() const { - ASSERT (NIL != state_ && FREE != state_); + ASSERT (!buffer_ || (NIL != state_ && FREE != state_)); return bool(buffer_); } @@ -461,8 +465,9 @@ namespace engine { __must_not_be_NIL() const { if (NIL == state_) - throw error::Fatal ("Concrete buffer entry with state==NIL encountered." - "State transition logic broken (programming error)"); + throw error::Fatal ("Buffer metadata entry with state==NIL encountered." + "State transition logic broken (programming error)" + , LUMIERA_ERROR_LIFECYCLE); } void @@ -478,29 +483,103 @@ namespace engine { /** - * (Hash)Table to store and manage buffer metadata + * (Hash)Table to store and manage buffer metadata. + * Buffer metadata entries are comprised of a Key part and an extended + * Entry, holding the actual management and housekeeping metadata. The + * Keys are organised hierarchically and denote the "kind" of buffer. + * The hash values for lookup are based on the key part, chained with + * the actual memory location of the concrete buffer corresponding + * to the metadata entry to be retrieved. */ class Table { + typedef std::tr1::unordered_map MetadataStore; + + MetadataStore entries_; + public: + ~Table() { verify_all_buffers_freed(); } + + /** fetch metadata record, if any + * @param hashID for the Key part of the metadata entry + * @return pointer to the entry in the table or NULL + */ Entry* + fetch (HashVal hashID) + { + MetadataStore::iterator pos = entries_.find (hashID); + if (pos != entries_.end()) + return &(pos->second); + else + return NULL; + } + + const Entry* fetch (HashVal hashID) const { - UNIMPLEMENTED ("fetch metadata record by ID"); + MetadataStore::const_iterator pos = entries_.find (hashID); + if (pos != entries_.end()) + return &(pos->second); + else + return NULL; } - + + /** store a copy of the given new metadata entry. + * The hash key for lookup is retrieved from the given Entry, by conversion to HashVal. + * Consequently, this will be the hashID of the parent Key (type), when the entry holds + * a NULL buffer (i.e a "pseudo entry"). Otherwise, it will be this parent Key hash, + * extended by hashing the actual buffer address. + * @return reference to relevant entry for this Key. This might be a copy + * of the new entry, or an already existing entry with the same Key + */ Entry& store (Entry const& newEntry) { - UNIMPLEMENTED ("store new metadata record"); + using std::make_pair; + REQUIRE (!fetch (newEntry), "duplicate buffer metadata entry"); + MetadataStore::iterator pos = entries_.insert (make_pair (HashVal(newEntry), newEntry)) + .first; + + ENSURE (pos != entries_.end()); + return pos->second; } void remove (HashVal hashID) { - UNIMPLEMENTED ("delete metadata record"); + uint cnt = entries_.erase (hashID); + ENSURE (cnt, "entry to remove didn't exist"); + } + + private: + void + verify_all_buffers_freed() + try + { + for_each (entries_, verify_is_free); + } + catch (std::exception& problem) + { + const char* errID = lumiera_error(); + const char* operation = "Shutdown of BufferProvider metadata store"; + WARN (engine, "%s failed: %s", operation, problem.what()); + TRACE (debugging, "Error flag was: %s", errID); + } + catch (...) + { + const char* errID = lumiera_error(); + const char* operation = "Shutdown of BufferProvider metadata store"; + ERROR (engine, "%s failed with unknown exception; error flag is: %s", operation, errID); + } + + static void + verify_is_free (std::pair const& e) + { + WARN_IF (e.second.isLocked(), engine, + "Buffer still in use while shutting down BufferProvider? "); } }; + }//namespace metadata @@ -651,7 +730,7 @@ namespace engine { bool isLocked (HashVal key) const { - Entry* entry = table_.fetch (key); + const Entry* entry = table_.fetch (key); return entry && entry->isLocked(); } From e7f0211711583257abdc85037939be75138a8a45 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 30 Oct 2011 01:17:31 +0200 Subject: [PATCH 28/68] better solution for calculating the Key for a concrete Entry --- src/proc/engine/buffer-metadata.hpp | 35 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index 19c18eecb..21ed1c50a 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -353,6 +353,25 @@ namespace engine { { } + /** build derived Key for a concrete buffer Entry + * @param parent type key to subsume this buffer + * @param bufferAddr pointer to the concrete buffer + * @return Child key with hashID based on the buffer address. + * For NULL buffer a copy of the parent is returned. + */ + static Key + forEntry (Key const& parent, const void* bufferAddr) + { + Key newKey(parent); + if (bufferAddr) + { + newKey.parent_ = HashVal(parent); + newKey.hashID_ = chainedHash(parent, bufferAddr); + } + return newKey; + } + + HashVal parentKey() const { return parent_;} operator HashVal() const { return hashID_;} }; @@ -380,7 +399,7 @@ namespace engine { protected: Entry (Key const& parent, const void* bufferPtr =0) - : Key(parent) + : Key (Key::forEntry (parent, bufferPtr)) , state_(bufferPtr? LOCKED:NIL) , buffer_(bufferPtr) { } @@ -409,20 +428,6 @@ namespace engine { return !bool(buffer_); } - /** @note hiding the base implementation to support storing - * and lookup of individual entries in a hashtable */ - operator HashVal() const - { - return isTypeKey()? Key::operator HashVal() - : chainedHash (parentKey(), buffer_); - } - - HashVal - parentKey() const - { - return isTypeKey()? Key::parentKey() - : Key::operator HashVal(); - } BufferState state() const From ccd130966beb44bf4d4a840a72cf01641aed38fa Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 30 Oct 2011 02:19:10 +0200 Subject: [PATCH 29/68] finish and pass the first round of tests still missing: - implementation of a Mock frame - automatical invocation of the TypeHandler --- src/proc/engine/buffer-metadata.hpp | 2 ++ .../proc/engine/buffer-metadata-test.cpp | 20 +++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index 21ed1c50a..500d1994b 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -452,7 +452,9 @@ namespace engine { __must_not_be_FREE(); if ( (state_ == LOCKED && newState == EMITTED) + ||(state_ == LOCKED && newState == FREE) ||(state_ == EMITTED && newState == BLOCKED) + ||(state_ == EMITTED && newState == FREE) ||(state_ == BLOCKED && newState == FREE)) { // allowed transition diff --git a/tests/components/proc/engine/buffer-metadata-test.cpp b/tests/components/proc/engine/buffer-metadata-test.cpp index dd55542e2..b32da07ab 100644 --- a/tests/components/proc/engine/buffer-metadata-test.cpp +++ b/tests/components/proc/engine/buffer-metadata-test.cpp @@ -91,7 +91,6 @@ namespace test { CHECK (ensure_proper_fixture()); verifyBasicProperties(); verifyStandardCase(); - UNIMPLEMENTED ("cover all metadata properties"); } @@ -219,12 +218,12 @@ namespace test { // a real-world BufferProvider would use some kind of allocator // track individual buffers by metadata entries - metadata::Entry f0 = meta_->markLocked(bufferType1, &frames[0]); - metadata::Entry f1 = meta_->markLocked(bufferType1, &frames[1]); - metadata::Entry f2 = meta_->markLocked(bufferType1, &frames[2]); + metadata::Entry& f0 = meta_->markLocked(bufferType1, &frames[0]); + metadata::Entry& f1 = meta_->markLocked(bufferType1, &frames[1]); + metadata::Entry& f2 = meta_->markLocked(bufferType1, &frames[2]); - metadata::Entry r0 = meta_->markLocked(bufferType1, &rawbuf[0]); - metadata::Entry r1 = meta_->markLocked(bufferType1, &rawbuf[1]); + metadata::Entry& r0 = meta_->markLocked(rawBuffType, &rawbuf[0]); + metadata::Entry& r1 = meta_->markLocked(rawBuffType, &rawbuf[1]); CHECK (LOCKED == f0.state()); CHECK (LOCKED == f1.state()); @@ -254,6 +253,11 @@ namespace test { //////////////////TODO: access the storage through the metadata-key //////////////////TODO: to a state transition on the metadata + f0.mark(FREE); + f1.mark(FREE); + f2.mark(FREE); + r0.mark(FREE); + r1.mark(FREE); attachTestFrame.destroyAttached (frames+0); ////////////////////////////////////////TODO: shouldn't this happen automatically?? attachTestFrame.destroyAttached (frames+1); @@ -265,6 +269,10 @@ namespace test { meta_->release(handle_r0); meta_->release(handle_r1); + // manual cleanup of test allocations + delete[] frames; + delete[] rawbuf; + CHECK (!meta_->isLocked(handle_f0)); CHECK (!meta_->isLocked(handle_f1)); CHECK (!meta_->isLocked(handle_f2)); From 931dc3f8839094aceb293f90149fdc81841f6587 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 30 Oct 2011 05:35:36 +0100 Subject: [PATCH 30/68] draft: automatically invoke an attached ctor/dtor functor --- src/proc/engine/buffer-metadata.hpp | 132 ++++++++++++------ .../proc/engine/buffer-metadata-test.cpp | 61 ++++++-- tests/components/proc/engine/testframe.hpp | 19 +++ 3 files changed, 157 insertions(+), 55 deletions(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index 500d1994b..f86d1cdaf 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -395,10 +395,10 @@ namespace engine { : public Key { BufferState state_; - const void* buffer_; + void* buffer_; protected: - Entry (Key const& parent, const void* bufferPtr =0) + Entry (Key const& parent, void* bufferPtr =0) : Key (Key::forEntry (parent, bufferPtr)) , state_(bufferPtr? LOCKED:NIL) , buffer_(bufferPtr) @@ -435,8 +435,8 @@ namespace engine { return state_; } - const void* - access() const + void* + access() { __must_not_be_NIL(); __must_not_be_FREE(); @@ -458,7 +458,8 @@ namespace engine { ||(state_ == BLOCKED && newState == FREE)) { // allowed transition - if (newState == FREE) buffer_ = 0; + if (newState == FREE) + invokeEmbeddedDtor_and_clear(); state_ = newState; return *this; } @@ -466,6 +467,29 @@ namespace engine { throw error::Fatal ("Invalid buffer state encountered."); } + protected: + /** @internal maybe invoke a registered TypeHandler's + * constructor function, which typically builds some + * content object into the buffer by placement new. */ + void + invokeEmbeddedCtor() + { + REQUIRE (buffer_); + if (nontrivial (instanceFunc_)) + instanceFunc_.createAttached (buffer_); + } + + /** @internal maybe invoke a registered TypeHandler's + * destructor function, which typically clears up some + * content object living within the buffer */ + void + invokeEmbeddedDtor_and_clear() + { + REQUIRE (buffer_); + if (nontrivial (instanceFunc_)) + instanceFunc_.destroyAttached (buffer_); + buffer_ = 0; + } private: void @@ -668,9 +692,9 @@ namespace engine { * @note might create/register a new Entry as a side-effect */ Key const& - key (Key const& parentKey, const void* concreteBuffer) + key (Key const& parentKey, void* concreteBuffer) { - return get (parentKey,concreteBuffer); + return lock (parentKey,concreteBuffer); } /** core operation to access or create a concrete buffer metadata entry. @@ -678,6 +702,11 @@ namespace engine { * which denotes a buffer type, and the concrete buffer address. If yet * unknown, a new concrete buffer metadata Entry is created and initialised * to LOCKED state. Otherwise just the existing Entry is fetched. + * @note this function really \em activates the buffer. + * In case the type (Key) involves a TypeHandler (functor), + * its constructor function will be invoked, if actually a new + * entry gets created. Typically this mechanism will be used + * to placement-create an object into the buffer. * @param parentKey a key describing the \em type of the buffer * @param concreteBuffer storage pointer, must not be NULL * @param onlyNew disallow fetching an existing entry @@ -691,7 +720,7 @@ namespace engine { * buffer is released or re-used later. */ Entry& - get (Key const& parentKey, const void* concreteBuffer, bool onlyNew =false) + lock (Key const& parentKey, void* concreteBuffer, bool onlyNew =false) { if (!concreteBuffer) throw error::Invalid ("Attempt to lock a slot for a NULL buffer" @@ -705,7 +734,7 @@ namespace engine { , error::LUMIERA_ERROR_LIFECYCLE ); if (!existing) - return table_.store (newEntry); + return store_and_lock (newEntry); // actual creation else return *existing; } @@ -743,10 +772,45 @@ namespace engine { } - /* == memory management == */ - Entry& markLocked (Key const& parentKey, const void* buffer); - void release (HashVal key); + /* == memory management operations == */ + + /** combine the type (Key) with a concrete buffer, + * thereby marking this buffer as locked. Store a concrete + * metadata Entry to account for this fact. This might include + * invoking a constructor function, in case the type (Key) + * defines a (nontrivial) TypeHandler. + * @throw error::Fatal when locking a NULL buffer + * @throw exceptions which might be raised by a TypeHandler's + * constructor function. In this case, the Entry remains + * created, but is marked as FREE + */ + Entry& + markLocked (Key const& parentKey, void* buffer) + { + if (!buffer) + throw error::Fatal ("Attempt to lock for a NULL buffer. Allocation floundered?" + , error::LUMIERA_ERROR_BOTTOM_VALUE); + + return this->lock(parentKey, buffer, true); // force creation of a new entry + } + + /** purge the bare metadata Entry from the metadata tables. + * @throw error::Logic if the entry isn't marked FREE already + */ + void + release (HashVal key) + { + Entry* entry = table_.fetch (key); + if (!entry) return; + if (entry && (FREE != entry->state())) + throw error::Logic ("Attempt to release a buffer still in use" + , error::LUMIERA_ERROR_LIFECYCLE); + + table_.remove (key); + } + + private: @@ -765,40 +829,28 @@ namespace engine { if (isKnown (key)) return; table_.store (Entry (key, NULL)); } + + Entry& + store_and_lock (Entry const& metadata) + { + Entry& newEntry = table_.store (metadata); + try + { + newEntry.invokeEmbeddedCtor(); + } + catch(...) + { + newEntry.mark(FREE); + throw; + } + return newEntry; + } }; - - - - - /** */ - inline BufferMetadata::Entry& - BufferMetadata::markLocked (Key const& parentKey, const void* buffer) - { - if (!buffer) - throw error::Fatal ("Attempt to lock for a NULL buffer. Allocation floundered?" - , error::LUMIERA_ERROR_BOTTOM_VALUE); - - return this->get (parentKey, buffer, true); // force creation of a new entry - } - - inline void - BufferMetadata::release (HashVal key) - { - Entry* entry = table_.fetch (key); - if (!entry) return; - if (entry && (FREE != entry->state())) - throw error::Logic ("Attempt to release a buffer still in use" - , error::LUMIERA_ERROR_LIFECYCLE); - - table_.remove (key); - } - - } // namespace engine #endif diff --git a/tests/components/proc/engine/buffer-metadata-test.cpp b/tests/components/proc/engine/buffer-metadata-test.cpp index b32da07ab..85818ba6f 100644 --- a/tests/components/proc/engine/buffer-metadata-test.cpp +++ b/tests/components/proc/engine/buffer-metadata-test.cpp @@ -37,13 +37,16 @@ //#include #include #include +#include //#include //using boost::format; //using std::string; //using std::cout; //using util::for_each; +using std::strncpy; using boost::scoped_ptr; +using lib::test::randStr; using util::isnil; using util::isSameObject; @@ -66,13 +69,24 @@ namespace test { const size_t SIZE_A = 1 + rand() % TEST_MAX_SIZE; const size_t SIZE_B = 1 + rand() % TEST_MAX_SIZE; - const HashVal JUST_SOMETHING = 123; - const void* const SOME_POINTER = &JUST_SOMETHING; + HashVal JUST_SOMETHING = 123; + void* const SOME_POINTER = &JUST_SOMETHING; // const uint TEST_SIZE = 1024*1024; // const uint TEST_ELMS = 20; - - } + + template + TY& + accessAs (metadata::Entry& entry) + { + TY* ptr = reinterpret_cast (entry.access()); + ASSERT (ptr); + return *ptr; + } + }//(End) Test fixture and helpers + + + /******************************************************************* @@ -231,10 +245,6 @@ namespace test { CHECK (LOCKED == r0.state()); CHECK (LOCKED == r1.state()); - // for the TestFrame buffers, additionally we'd have to create/attach an object - attachTestFrame.createAttached (frames+0); ////////////////////////////////////////TODO: shouldn't this happen automatically?? - attachTestFrame.createAttached (frames+1); //////////////////////////TODO: answer: yes. Metadata is exactly the entity which has all necessary information - attachTestFrame.createAttached (frames+2); CHECK (f0.access() == frames+0); CHECK (f1.access() == frames+1); @@ -242,6 +252,11 @@ namespace test { CHECK (r0.access() == rawbuf+0); CHECK (r1.access() == rawbuf+1); + TestFrame defaultFrame; + CHECK (defaultFrame == f0.access()); + CHECK (defaultFrame == f1.access()); + CHECK (defaultFrame == f2.access()); + // at that point, we'd return BuffHandles to the client HashVal handle_f0(f0); HashVal handle_f1(f1); @@ -249,19 +264,31 @@ namespace test { HashVal handle_r0(r0); HashVal handle_r1(r1); - // client uses the buffers + // client uses the buffers---------------------(Start) + accessAs (f0) = testData(1); + accessAs (f1) = testData(2); + accessAs (f2) = testData(3); - //////////////////TODO: access the storage through the metadata-key - //////////////////TODO: to a state transition on the metadata - f0.mark(FREE); + CHECK (TestFrame::isAlive (f0.access())); + CHECK (TestFrame::isAlive (f1.access())); + CHECK (TestFrame::isAlive (f2.access())); + + strncpy (& accessAs (r0), randStr(SIZE_B - 1).c_str(), SIZE_B); + strncpy (& accessAs (r1), randStr(SIZE_B - 1).c_str(), SIZE_B); + + // client might trigger some state transitions + f0.mark(EMITTED); + f1.mark(EMITTED); + f1.mark(BLOCKED); + // client uses the buffers---------------------(End) + + + f0.mark(FREE); // note: this implicitly invoked the embedded dtor f1.mark(FREE); f2.mark(FREE); r0.mark(FREE); r1.mark(FREE); - attachTestFrame.destroyAttached (frames+0); ////////////////////////////////////////TODO: shouldn't this happen automatically?? - attachTestFrame.destroyAttached (frames+1); - attachTestFrame.destroyAttached (frames+2); meta_->release(handle_f0); meta_->release(handle_f1); @@ -269,6 +296,10 @@ namespace test { meta_->release(handle_r0); meta_->release(handle_r1); + CHECK (TestFrame::isDead (&frames[0])); + CHECK (TestFrame::isDead (&frames[1])); + CHECK (TestFrame::isDead (&frames[2])); + // manual cleanup of test allocations delete[] frames; delete[] rawbuf; diff --git a/tests/components/proc/engine/testframe.hpp b/tests/components/proc/engine/testframe.hpp index ba71d6646..d9e7b7b20 100644 --- a/tests/components/proc/engine/testframe.hpp +++ b/tests/components/proc/engine/testframe.hpp @@ -56,6 +56,25 @@ namespace test { public: + /** Helper to verify a given memory location holds + * an active TestFrame instance (created, not yet destroyed) + * @return true if the TestFrame datastructure is intact and + * marked as still alive. + */ + static bool + isAlive (void* memLocation) + { + UNIMPLEMENTED ("access memory as TestFrame and check internal accounting"); + } + + /** Helper to verify a given memory location holds + * an already destroyed TestFrame instance */ + static bool + isDead (void* memLocation) + { + UNIMPLEMENTED ("access memory as TestFrame and verify dtor invocation"); + } + bool operator== (void* memLocation) { From a14e4f7ccd9233d1a0148cba7e9920c3751feb8e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 31 Oct 2011 00:13:35 +0100 Subject: [PATCH 31/68] define a facility to generate test frames --- tests/46engine.tests | 8 +- .../components/proc/engine/testframe-test.cpp | 178 ++++++++++++++++++ tests/components/proc/engine/testframe.cpp | 141 ++++++++++++++ tests/components/proc/engine/testframe.hpp | 64 +++---- 4 files changed, 355 insertions(+), 36 deletions(-) create mode 100644 tests/components/proc/engine/testframe-test.cpp create mode 100644 tests/components/proc/engine/testframe.cpp diff --git a/tests/46engine.tests b/tests/46engine.tests index e2f704018..aca5be526 100644 --- a/tests/46engine.tests +++ b/tests/46engine.tests @@ -2,12 +2,18 @@ TESTING "Component Test Suite: Render Engine parts" ./test-components --group=en +PLANNED "Test support: dummy frames" TestFrame_test < + + 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. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "proc/engine/testframe.hpp" + +//#include +#include +#include +#include + +using test::Test; +//using std::cout; +using std::rand; +using boost::scoped_ptr; +//using std::memset; + + +namespace engine{ +namespace test { + + namespace { // used internally + + const uint CHAN_COUNT = 30; // independent families of test frames to generate + const uint NUM_FRAMES = 1000; // number of test frames in each of these families + + + void + corruptMemory(void* base, uint offset, uint count) + { + char* accessor = reinterpret_cast (base); + while (count--) + accessor[offset+count] = rand() % CHAR_MAX; + } + + } // (End) internal defs + + + + /******************************************************************* + * @test verify test helper for engine tests: a dummy data frame. + * TestFrame instances can be created right away, without any + * external library dependencies. A test frame is automatically + * filled with random data; multiple frames are arranged in + * sequences and channels, causing the random data to be + * reproducible yet different in each frame. + * + * To ease writing unit tests, TestFrame provides comparison + * and assignment and tracks lifecycle automatically. As tests + * regarding the engine typically have to deal with buffer + * management, an arbitrary memory location can be interpreted + * as TestFrame and checked for corruption. + */ + class TestFrame_test : public Test + { + + virtual void + run (Arg) + { + verifyBasicProperties(); + verifyFrameLifecycle(); + verifyFrameSeries(); + } + + + void + verifyBasicProperties() + { + CHECK (1024 < sizeof(TestFrame)); + + TestFrame frameA; + TestFrame frameB; + TestFrame frameC(5); + + CHECK (frameA == frameB); + CHECK (frameA != frameC); + CHECK (frameB != frameC); + + CHECK (frameA.isAlive()); + CHECK (frameB.isAlive()); + CHECK (frameC.isAlive()); + + CHECK (frameA.isSane()); + CHECK (frameB.isSane()); + CHECK (frameC.isSane()); + + void * frameMem = &frameB; + + CHECK (frameA == frameMem); + corruptMemory(frameMem,20,5); + CHECK (!frameB.isSane()); + + frameB = frameC; + + CHECK (frameB.isSane()); + CHECK (frameA != frameB); + CHECK (frameA != frameC); + CHECK (frameB == frameC); + } + + + void + verifyFrameLifecycle() + { + CHECK (!TestFrame::isDead (this)); + CHECK (!TestFrame::isAlive (this)); + + TestFrame* onHeap = new TestFrame(23); + CHECK ( TestFrame::isAlive (onHeap)); + CHECK (!onHeap->isDead()); + CHECK (onHeap->isAlive()); + CHECK (onHeap->isSane()); + + delete onHeap; + CHECK ( TestFrame::isDead (onHeap)); + CHECK (!TestFrame::isAlive (onHeap)); + } + + + /** @test build sequences of test frames, + * organised into multiple families (channels). + * Verify that adjacent frames hold differing data + */ + void + verifyFrameSeries() + { + scoped_ptr thisFrames[CHAN_COUNT]; + scoped_ptr prevFrames[CHAN_COUNT]; + + for (uint i=0; iisSane()); + CHECK (prevFrames[i]->isSane()); + CHECK (prevFrames[i]->isAlive()); + + CHECK (*thisFrames[i] != *prevFrames[i]); // differs from predecessor in the same channel + + for (uint j=0; j + + 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. + +* *****************************************************/ + + +#include "proc/engine/testframe.hpp" +#include "lib/error.hpp" + +#include + +using std::memcpy; + +namespace engine { +namespace test { + + + namespace error = lumiera::error; + + namespace { // hidden local support facilities.... + + } // (End) hidden impl details + + + TestFrame::~TestFrame() { } // emit VTables here.... + + + TestFrame::TestFrame(uint seq, uint family) + : discriminator_() + , stage_(CREATED) + { } + + + TestFrame::TestFrame (TestFrame const& o) + : discriminator_(o.discriminator_) + , stage_(CREATED) + { + memcpy (data_, o.data_, BUFFSIZ); + } + + TestFrame& + TestFrame::operator= (TestFrame const& o) + { + if (DISCARDED == stage_) + throw new error::Logic ("target TestFrame is already dead"); + if (this != &o) + { + discriminator_ = o.discriminator_; + stage_ = CREATED; + memcpy (data_, o.data_, BUFFSIZ); + } + return *this; + } + + + + /** whether this output slot is occupied + * @return true if currently unconnected and + * able to connect and handle output data + */ + bool + TestFrame::isAlive (void* memLocation) + { + UNIMPLEMENTED ("access memory as TestFrame and check internal accounting"); + } + + /** Helper to verify a given memory location holds + * an already destroyed TestFrame instance */ + bool + TestFrame::isDead (void* memLocation) + { + UNIMPLEMENTED ("access memory as TestFrame and verify dtor invocation"); + } + + bool + TestFrame::operator== (void* memLocation) const + { + UNIMPLEMENTED ("verify contents of an arbitrary memory location"); + } + + bool + TestFrame::contentEquals (TestFrame const& o) const + { + UNIMPLEMENTED ("equality of test data frames"); + } + + bool + TestFrame::isAlive() const + { + UNIMPLEMENTED ("sanity & lifecycle"); + } + + bool + TestFrame::isDead() const + { + UNIMPLEMENTED ("sanity & lifecycle"); + } + + bool + TestFrame::isSane() const + { + UNIMPLEMENTED ("sanity & lifecycle"); + } + + + + + + TestFrame + testData (uint seqNr) + { + UNIMPLEMENTED ("build, memorise and expose test data frames on demand"); + } + + TestFrame + testData (uint chanNr, uint seqNr) + { + UNIMPLEMENTED ("build, memorise and expose test data frames on demand (multi-channel)"); + } + + + + +}} // namespace engine::test diff --git a/tests/components/proc/engine/testframe.hpp b/tests/components/proc/engine/testframe.hpp index d9e7b7b20..f1b780e16 100644 --- a/tests/components/proc/engine/testframe.hpp +++ b/tests/components/proc/engine/testframe.hpp @@ -28,6 +28,8 @@ //#include "lib/time/timevalue.hpp" //#include +#include +#include //using std::tr1::shared_ptr; @@ -53,60 +55,52 @@ namespace test { */ class TestFrame { + enum StageOfLife { + CREATED, EMITTED, DISCARDED + }; + + static const size_t BUFFSIZ = 1024; + + uint64_t discriminator_; + StageOfLife stage_; + + char data_[BUFFSIZ]; public: + ~TestFrame(); + TestFrame (uint seq=0, uint family=0); + TestFrame (TestFrame const&); + TestFrame& operator= (TestFrame const&); /** Helper to verify a given memory location holds * an active TestFrame instance (created, not yet destroyed) * @return true if the TestFrame datastructure is intact and * marked as still alive. */ - static bool - isAlive (void* memLocation) - { - UNIMPLEMENTED ("access memory as TestFrame and check internal accounting"); - } + static bool isAlive (void* memLocation); /** Helper to verify a given memory location holds * an already destroyed TestFrame instance */ - static bool - isDead (void* memLocation) - { - UNIMPLEMENTED ("access memory as TestFrame and verify dtor invocation"); - } + static bool isDead (void* memLocation); - bool - operator== (void* memLocation) - { - UNIMPLEMENTED ("verify contents of an arbitrary memory location"); - } + bool isAlive() const; + bool isDead() const; + bool isSane() const; - friend bool - operator== (TestFrame const& f1, TestFrame const& f2) - { - UNIMPLEMENTED ("equality of test data frames"); - } + bool operator== (void* memLocation) const; - friend bool - operator!= (TestFrame const& f1, TestFrame const& f2) - { - return !(f1 == f2); - } + friend bool operator== (TestFrame const& f1, TestFrame const& f2) { return f1.contentEquals(f2); } + friend bool operator!= (TestFrame const& f1, TestFrame const& f2) { return !f1.contentEquals(f2); } + + private: + bool contentEquals (TestFrame const& o) const; }; - inline TestFrame - testData (uint seqNr) - { - UNIMPLEMENTED ("build, memorise and expose test data frames on demand"); - } + TestFrame testData (uint seqNr); - inline TestFrame - testData (uint chanNr, uint seqNr) - { - UNIMPLEMENTED ("build, memorise and expose test data frames on demand (multi-channel)"); - } + TestFrame testData (uint chanNr, uint seqNr); From 20777cca8a9c0e549421dda8e669a8b4839e1991 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 31 Oct 2011 02:20:32 +0100 Subject: [PATCH 32/68] implemented testframe, not passing all tests yet --- .../components/proc/engine/testframe-test.cpp | 20 +- tests/components/proc/engine/testframe.cpp | 214 +++++++++++++++--- tests/components/proc/engine/testframe.hpp | 29 ++- 3 files changed, 216 insertions(+), 47 deletions(-) diff --git a/tests/components/proc/engine/testframe-test.cpp b/tests/components/proc/engine/testframe-test.cpp index efac01b44..29e96b9c5 100644 --- a/tests/components/proc/engine/testframe-test.cpp +++ b/tests/components/proc/engine/testframe-test.cpp @@ -24,16 +24,13 @@ #include "lib/test/run.hpp" #include "proc/engine/testframe.hpp" -//#include -#include #include #include +#include using test::Test; -//using std::cout; using std::rand; using boost::scoped_ptr; -//using std::memset; namespace engine{ @@ -52,7 +49,6 @@ namespace test { while (count--) accessor[offset+count] = rand() % CHAR_MAX; } - } // (End) internal defs @@ -153,7 +149,7 @@ namespace test { for (uint nr=1; nrisSane()); CHECK (prevFrames[i]->isSane()); @@ -161,12 +157,12 @@ namespace test { CHECK (*thisFrames[i] != *prevFrames[i]); // differs from predecessor in the same channel - for (uint j=0; j + +#include #include +#include using std::memcpy; +using std::vector; namespace engine { namespace test { @@ -36,16 +41,141 @@ namespace test { namespace { // hidden local support facilities.... + /** @internal helper for generating unique test frames. + * The "discriminator" is used as a stepping size when + * filling the test frame data buffers. It is generated + * to be different on adjacent frames of the same series, + * as well as to differ to all near by neighbouring channels. + * @param seq the sequence number of the frame within the channel + * @param family the channel this frame belongs to + */ + uint64_t + generateDiscriminator(uint seq, uint family) + { + // random offset, but fixed per executable run + static uint base(10 + rand() % 90); + + // use the family as stepping + return (seq+1) * (base+family); + } + + + TestFrame& + accessAsTestFrame (void* memoryLocation) + { + REQUIRE (memoryLocation); + return *reinterpret_cast (memoryLocation); + } + + + /** + * @internal table to hold test data frames. + * These frames are built on demand, but retained thereafter. + * Some tests might rely on the actual memory locations, using the + * test frames to simulate a real input frame data stream. + * @param CHA the maximum number of channels to expect + * @param FRA the maximum number of frames to expect per channel + * @warning choose the maximum number parameters wisely. + * We're allocating memory to hold a table of test frames + * e.g. sizeof(TestFrame) * 20channels * 100frames ≈ 2 MiB + * The table uses vectors, and thus will grow on demand, + * but this might cause existing frames to be relocated in memory; + * some tests might rely on fixed memory locations. Just be cautious! + */ + template + struct TestFrameTable + : vector > + { + typedef vector > VECT; + + TestFrameTable() + : VECT(CHA) + { + for (uint i=0; i= this->size()) + { + WARN (test, "Growing table of test frames to %d channels, " + "which is > the default (%d)", chanNr, CHA); + resize(chanNr+1); + } + ENSURE (chanNr < this->size()); + vector& channel = at(chanNr); + + if (seqNr >= channel.size()) + { + WARN_IF (seqNr >= FRA, test, + "Growing channel #%d of test frames to %d elements, " + "which is > the default (%d)", chanNr, seqNr, FRA); + for (uint i=channel.size(); i<=seqNr; ++i) + channel.push_back (TestFrame (seqNr,chanNr)); + } + ENSURE (seqNr < channel.size()); + + return channel[seqNr]; + } + }; + + const uint INITIAL_CHAN = 20; + const uint INITIAL_FRAMES = 100; + + typedef TestFrameTable TestFrames; + + boost::scoped_ptr testFrames; + + TestFrame& + accessTestFrame (uint seqNr, uint chanNr) + { + if (!testFrames) testFrames.reset (new TestFrames); + + return testFrames->getFrame(seqNr,chanNr); + } + } // (End) hidden impl details - TestFrame::~TestFrame() { } // emit VTables here.... + + + TestFrame& + testData (uint seqNr) + { + return accessTestFrame (seqNr, 0); + } + + TestFrame& + testData (uint chanNr, uint seqNr) + { + return accessTestFrame (seqNr,chanNr); + } + + void + resetTestFrames() + { + testFrames.reset(0); + } + + + + + + TestFrame::~TestFrame() + { + stage_ = DISCARDED; + } TestFrame::TestFrame(uint seq, uint family) - : discriminator_() + : discriminator_(generateDiscriminator(seq,family)) , stage_(CREATED) - { } + { + ASSERT (0 < discriminator_); + buildData(); + } TestFrame::TestFrame (TestFrame const& o) @@ -71,71 +201,91 @@ namespace test { - /** whether this output slot is occupied - * @return true if currently unconnected and - * able to connect and handle output data + /** @note performing an unchecked conversion of the given + * memory location to be accessed as TestFrame. + * The sanity of the data found at that location + * is checked as well, not only the lifecycle flag. */ bool TestFrame::isAlive (void* memLocation) { - UNIMPLEMENTED ("access memory as TestFrame and check internal accounting"); + TestFrame& candidate (accessAsTestFrame (memLocation)); + return candidate.isSane() + && candidate.isAlive(); } - /** Helper to verify a given memory location holds - * an already destroyed TestFrame instance */ bool TestFrame::isDead (void* memLocation) { - UNIMPLEMENTED ("access memory as TestFrame and verify dtor invocation"); + TestFrame& candidate (accessAsTestFrame (memLocation)); + return candidate.isSane() + && candidate.isDead(); } bool TestFrame::operator== (void* memLocation) const { - UNIMPLEMENTED ("verify contents of an arbitrary memory location"); + TestFrame& candidate (accessAsTestFrame (memLocation)); + return candidate.isSane() + && candidate == *this; } bool TestFrame::contentEquals (TestFrame const& o) const { - UNIMPLEMENTED ("equality of test data frames"); + for (uint i=0; i Date: Tue, 1 Nov 2011 03:11:43 +0100 Subject: [PATCH 33/68] use boost::random to ensure distinct test frame contents --- src/tool/try.cpp | 52 +++++++--------------- tests/46engine.tests | 2 +- tests/components/proc/engine/testframe.cpp | 39 ++++++++-------- tests/components/proc/engine/testframe.hpp | 31 ++++--------- 4 files changed, 44 insertions(+), 80 deletions(-) diff --git a/src/tool/try.cpp b/src/tool/try.cpp index 9e68a90a5..7b73f4c1f 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -20,53 +20,31 @@ // 1/11 - integer floor and wrap operation(s) // 1/11 - how to fetch the path of the own executable -- at least under Linux? // 10/11 - simple demo using a pointer and a struct +// 11/11 - using the boost random number generator(s) #include +#include +#include + +using boost::lexical_cast; using std::cout; - - - -/** - * custom datastructure - * holding a constant char array with "hey" - */ -struct MyStruct - { - char data_[3]; - const int length_; - - MyStruct() - : length_(3) - { - const char *tmp = "hey"; - for (int i=0; ilength_; ++i) - cout << myPointer->data_[i]; - - cout << "\n"; - } +using std::endl; int -main (int, char**) //(int argc, char* argv[]) +main (int cnt, char* argv[]) { - printMyStruct (&theStruct); + + int32_t seed = (2 == cnt)? lexical_cast (argv[1]) : 42; + + boost::rand48 ranGen(seed); + + cout << "seed = "<< seed << endl; + for (uint i=0; i< 100; ++i) + cout << ranGen() % CHAR_MAX <<"__"; cout << "\n.gulp.\n"; diff --git a/tests/46engine.tests b/tests/46engine.tests index aca5be526..293dc00c7 100644 --- a/tests/46engine.tests +++ b/tests/46engine.tests @@ -2,7 +2,7 @@ TESTING "Component Test Suite: Render Engine parts" ./test-components --group=en -PLANNED "Test support: dummy frames" TestFrame_test < #include #include #include #include -using std::memcpy; -using std::vector; + namespace engine { namespace test { + using std::vector; + using std::memcpy; + + typedef boost::rand48 PseudoRandom; + namespace error = lumiera::error; namespace { // hidden local support facilities.... /** @internal helper for generating unique test frames. - * The "discriminator" is used as a stepping size when + * This "discriminator" is used as a random seed when * filling the test frame data buffers. It is generated * to be different on adjacent frames of the same series, * as well as to differ to all near by neighbouring channels. @@ -50,10 +55,10 @@ namespace test { * @param family the channel this frame belongs to */ uint64_t - generateDiscriminator(uint seq, uint family) + generateDistinction(uint seq, uint family) { // random offset, but fixed per executable run - static uint base(10 + rand() % 90); + static uint base(10 + rand() % 990); // use the family as stepping return (seq+1) * (base+family); @@ -128,6 +133,7 @@ namespace test { boost::scoped_ptr testFrames; + TestFrame& accessTestFrame (uint seqNr, uint chanNr) { @@ -162,6 +168,7 @@ namespace test { + /* ===== TestFrame class ===== */ TestFrame::~TestFrame() { @@ -170,16 +177,16 @@ namespace test { TestFrame::TestFrame(uint seq, uint family) - : discriminator_(generateDiscriminator(seq,family)) + : distinction_(generateDistinction (seq,family)) , stage_(CREATED) { - ASSERT (0 < discriminator_); + ASSERT (0 < distinction_); buildData(); } TestFrame::TestFrame (TestFrame const& o) - : discriminator_(o.discriminator_) + : distinction_(o.distinction_) , stage_(CREATED) { memcpy (data_, o.data_, BUFFSIZ); @@ -192,7 +199,7 @@ namespace test { throw new error::Logic ("target TestFrame is already dead"); if (this != &o) { - discriminator_ = o.discriminator_; + distinction_ = o.distinction_; stage_ = CREATED; memcpy (data_, o.data_, BUFFSIZ); } @@ -242,9 +249,9 @@ namespace test { bool TestFrame::verifyData() const { - char c(0); + PseudoRandom gen(distinction_); for (uint i=0; i #include #include -//using std::tr1::shared_ptr; -//using std::string; - - namespace engine { namespace test { -//class TestPlacement; - /** * Mock data frame for simulated rendering. * A test frame can be created and placed instead of a real data frame. @@ -52,12 +43,13 @@ namespace test { * * Each TestFrame is automatically filled with pseudo random data; * multiple frames are arranged in sequences and channels, causing the random data - * to be reproducible yet different in each frame. The lifecycle of each TestFrame - * is tracked and marked in an embedded state field. Moreover, the contents of - * the data block can be verified, because the sequence of bytes is reproducible, + * to be reproducible yet different within each frame. TestFrame's lifecycle is + * tracked and marked in an embedded state field. Moreover, the contents of the + * data block can be verified, because the sequence of bytes is reproducible, * based on the channel and sequence number of the test frame. * - * @todo WIP-WIP-WIP 9/11 + * @see TestFrame_test + * @see OutputSlotProtocol_test * */ class TestFrame @@ -68,7 +60,7 @@ namespace test { static const size_t BUFFSIZ = 1024; - uint64_t discriminator_; + uint64_t distinction_; StageOfLife stage_; char data_[BUFFSIZ]; @@ -79,7 +71,7 @@ namespace test { TestFrame (TestFrame const&); TestFrame& operator= (TestFrame const&); - /** Helper to verify a given memory location holds + /** Helper to verify that a given memory location holds * an active TestFrame instance (created, not yet destroyed) * @return true if the TestFrame datastructure is intact and * marked as still alive. @@ -101,9 +93,7 @@ namespace test { private: bool contentEquals (TestFrame const& o) const; - bool verifyData() const; - char generate (char) const; - + bool verifyData() const; void buildData (); }; @@ -126,10 +116,5 @@ namespace test { - - /* == some test data to check == */ - // extern const lib::time::Duration LENGTH_TestClip; - - }} // namespace engine::test #endif From 0cd7bd2b4c29bc8cbdc32a4635df04675cd35912 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 1 Nov 2011 03:36:35 +0100 Subject: [PATCH 34/68] add test coverage for the test frame table --- .../components/proc/engine/testframe-test.cpp | 40 +++++++++++++++++-- tests/components/proc/engine/testframe.cpp | 2 +- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/tests/components/proc/engine/testframe-test.cpp b/tests/components/proc/engine/testframe-test.cpp index 29e96b9c5..a7e086fa9 100644 --- a/tests/components/proc/engine/testframe-test.cpp +++ b/tests/components/proc/engine/testframe-test.cpp @@ -23,6 +23,7 @@ #include "lib/test/run.hpp" #include "proc/engine/testframe.hpp" +#include "lib/util.hpp" #include #include @@ -30,12 +31,13 @@ using test::Test; using std::rand; +using util::isSameObject; using boost::scoped_ptr; namespace engine{ namespace test { - + namespace { // used internally const uint CHAN_COUNT = 30; // independent families of test frames to generate @@ -76,6 +78,7 @@ namespace test { verifyBasicProperties(); verifyFrameLifecycle(); verifyFrameSeries(); + useFrameTable(); } @@ -155,14 +158,45 @@ namespace test { CHECK (prevFrames[i]->isSane()); CHECK (prevFrames[i]->isAlive()); - CHECK (*thisFrames[i] != *prevFrames[i]); // differs from predecessor in the same channel + CHECK (*thisFrames[i] != *prevFrames[i]); // differs from predecessor within the same channel for (uint j=0; j the default (%d)", chanNr, seqNr, FRA); for (uint i=channel.size(); i<=seqNr; ++i) - channel.push_back (TestFrame (seqNr,chanNr)); + channel.push_back (TestFrame (i,chanNr)); } ENSURE (seqNr < channel.size()); From d6e88c85e01c02453e4c207afccc355b5544e64a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 2 Nov 2011 01:34:05 +0100 Subject: [PATCH 35/68] finish buffer metadata; cover state transitions BufferMetadata complete and working for now --- src/proc/engine/buffer-metadata.hpp | 123 ++++++++++++---- tests/46engine.tests | 2 +- .../proc/engine/buffer-metadata-test.cpp | 137 ++++++++++++++---- 3 files changed, 204 insertions(+), 58 deletions(-) diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp index f86d1cdaf..9a73ba20a 100644 --- a/src/proc/engine/buffer-metadata.hpp +++ b/src/proc/engine/buffer-metadata.hpp @@ -31,7 +31,7 @@ ** - that overall storage size available within the buffer ** - a pair of custom \em creator and \em destructor functions to use together with this buffer ** - an additional client key to distinguish otherwise otherwise identical client requests - ** These three distinctions are applied in sequence, thus forming a tree with 3 levels. + ** These three distinctions are applied in sequence, thus forming a type tree with 3 levels. ** Only the first distinguishing level (the size) is mandatory. The others are provided, ** because some of the foreseeable buffer providers allow to re-access the data placed ** into the buffer, by assigning an internally managed ID to the buffer. The most @@ -85,15 +85,22 @@ namespace engine { + + /** + * Buffer states + * usable within BufferProvider + * and stored within the metadata + */ enum BufferState - { NIL, - FREE, - LOCKED, - EMITTED, - BLOCKED + { NIL, ///< abstract entry, not yet allocated + FREE, ///< allocated buffer, no longer in use + LOCKED, ///< allocated buffer actively in use + EMITTED, ///< allocated buffer, returned from client + BLOCKED ///< allocated buffer blocked by protocol failure }; + /** * an opaque ID to be used by the BufferProvider implementation. * Typically this will be used, to set apart some pre-registered @@ -131,7 +138,7 @@ namespace engine { }; - namespace { // Helpers for construction within the buffer... + namespace { // (optional) helpers to build an object embedded within the buffer... template inline void @@ -157,6 +164,7 @@ namespace engine { }//(End)placement-new helpers + /** * A pair of functors to maintain a datastructure within the buffer. * TypeHandler describes how to outfit the buffer in a specific way. @@ -263,7 +271,7 @@ namespace engine { - /* === Implementation === */ + /* === Metadata Implementation === */ namespace metadata { @@ -280,6 +288,7 @@ namespace engine { } } + /** * Description of a Buffer-"type". * Key elements will be used to generate hash IDs, @@ -372,6 +381,12 @@ namespace engine { } + LocalKey const& + localKey() const + { + return specifics_; + } + HashVal parentKey() const { return parent_;} operator HashVal() const { return hashID_;} }; @@ -425,7 +440,7 @@ namespace engine { bool isTypeKey() const { - return !bool(buffer_); + return NIL == state_ && !buffer_; } @@ -445,13 +460,15 @@ namespace engine { return buffer_; } + /** Buffer state machine */ Entry& mark (BufferState newState) { __must_not_be_NIL(); - __must_not_be_FREE(); - if ( (state_ == LOCKED && newState == EMITTED) + if ( (state_ == FREE && newState == LOCKED) + ||(state_ == LOCKED && newState == EMITTED) + ||(state_ == LOCKED && newState == BLOCKED) ||(state_ == LOCKED && newState == FREE) ||(state_ == EMITTED && newState == BLOCKED) ||(state_ == EMITTED && newState == FREE) @@ -460,13 +477,24 @@ namespace engine { // allowed transition if (newState == FREE) invokeEmbeddedDtor_and_clear(); + if (newState == LOCKED) + invokeEmbeddedCtor(); state_ = newState; return *this; } - throw error::Fatal ("Invalid buffer state encountered."); + throw error::Fatal ("Invalid buffer state transition."); } + Entry& + lock (void* newBuffer) + { + __must_be_FREE(); + buffer_ = newBuffer; + return mark (LOCKED); + } + + protected: /** @internal maybe invoke a registered TypeHandler's * constructor function, which typically builds some @@ -474,7 +502,7 @@ namespace engine { void invokeEmbeddedCtor() { - REQUIRE (buffer_); + __buffer_required(); if (nontrivial (instanceFunc_)) instanceFunc_.createAttached (buffer_); } @@ -485,7 +513,7 @@ namespace engine { void invokeEmbeddedDtor_and_clear() { - REQUIRE (buffer_); + __buffer_required(); if (nontrivial (instanceFunc_)) instanceFunc_.destroyAttached (buffer_); buffer_ = 0; @@ -510,9 +538,27 @@ namespace engine { "You should invoke markLocked(buffer) prior to access." , LUMIERA_ERROR_LIFECYCLE ); } + + void + __must_be_FREE() const + { + if (FREE != state_) + throw error::Logic ("Buffer already in use" + , LUMIERA_ERROR_LIFECYCLE ); + REQUIRE (!buffer_, "Buffer marked as free, " + "but buffer pointer is set."); + } + + void + __buffer_required() const + { + if (!buffer_) + throw error::Fatal ("Need concrete buffer for any further operations"); + } }; + /** * (Hash)Table to store and manage buffer metadata. * Buffer metadata entries are comprised of a Key part and an extended @@ -617,6 +663,21 @@ namespace engine { + /* ===== Buffer Metadata Frontend ===== */ + + /** + * Registry for managing buffer metadata. + * This is an implementation level service, + * used by the standard BufferProvider implementation. + * Each metadata registry (instance) defines and maintains + * a family of "buffer types"; beyond the buffer storage size, + * the concrete meaning of those types is tied to the corresponding + * BufferProvider implementation and remains opaque. These types are + * represented as hierarchically linked hash keys. The implementation + * may bind a TypeHandler to a specific type, allowing automatic invocation + * of a "constructor" and "destructor" function on each buffer of this type, + * when \em locking or \em freeing the corresponding buffer. + */ class BufferMetadata : boost::noncopyable { @@ -625,8 +686,8 @@ namespace engine { metadata::Table table_; - public: + public: typedef metadata::Key Key; typedef metadata::Entry Entry; @@ -634,8 +695,8 @@ namespace engine { * Such will maintain a family of buffer type entries * and provide a service for storing and retrieving metadata * for concrete buffer entries associated with these types. - * @param implementationID to distinguish families - * of type keys belonging to different registries. + * @param implementationID to distinguish families of + * type keys belonging to different registries. */ BufferMetadata (Literal implementationID) : id_(implementationID) @@ -661,14 +722,10 @@ namespace engine { Key typeKey = trackKey (family_, storageSize); if (nontrivial(instanceFunc)) - { typeKey = trackKey (typeKey, instanceFunc); - } if (nontrivial(specifics)) - { typeKey = trackKey (typeKey, specifics); - } return typeKey; } @@ -680,7 +737,8 @@ namespace engine { return trackKey (parentKey, instanceFunc); } - /** create a sub-type, using a different private-ID (implementation defined) */ + /** create a sub-type, + * using a different private-ID (implementation defined) */ Key key (Key const& parentKey, LocalKey specifics) { @@ -694,7 +752,11 @@ namespace engine { Key const& key (Key const& parentKey, void* concreteBuffer) { - return lock (parentKey,concreteBuffer); + Key derivedKey = Key::forEntry (parentKey, concreteBuffer); + Entry* existing = table_.fetch (derivedKey); + + return existing? *existing + : markLocked (parentKey,concreteBuffer); } /** core operation to access or create a concrete buffer metadata entry. @@ -728,15 +790,19 @@ namespace engine { Entry newEntry(parentKey, concreteBuffer); Entry* existing = table_.fetch (newEntry); + if (existing && onlyNew) throw error::Logic ("Attempt to lock a slot for a new buffer, " - "while actually the old buffer is still locked." + "while actually the old buffer is still locked" + , error::LUMIERA_ERROR_LIFECYCLE ); + if (existing && existing->isLocked()) + throw error::Logic ("Attempt to re-lock a buffer still in use" , error::LUMIERA_ERROR_LIFECYCLE ); if (!existing) return store_and_lock (newEntry); // actual creation else - return *existing; + return existing->lock (concreteBuffer); } /** access the metadata record registered with the given hash key. @@ -812,7 +878,7 @@ namespace engine { - private: + private: template Key @@ -836,7 +902,9 @@ namespace engine { Entry& newEntry = table_.store (metadata); try { - newEntry.invokeEmbeddedCtor(); + newEntry.invokeEmbeddedCtor(); + ENSURE (LOCKED == newEntry.state()); + ENSURE (newEntry.access()); } catch(...) { @@ -845,7 +913,6 @@ namespace engine { } return newEntry; } - }; diff --git a/tests/46engine.tests b/tests/46engine.tests index 293dc00c7..46c1806db 100644 --- a/tests/46engine.tests +++ b/tests/46engine.tests @@ -17,7 +17,7 @@ return: 0 END -PLANNED "buffer metadata and state transitions" BufferMetadata_test < #include #include #include -//#include -//using boost::format; -//using std::string; -//using std::cout; -//using util::for_each; using std::strncpy; using boost::scoped_ptr; using lib::test::randStr; -using util::isnil; using util::isSameObject; +using util::isnil; namespace engine{ namespace test { - -// using lib::AllocationCluster; -// using mobject::session::PEffect; -// using ::engine::BuffHandle; + using lumiera::error::LUMIERA_ERROR_FATAL; using lumiera::error::LUMIERA_ERROR_INVALID; using lumiera::error::LUMIERA_ERROR_LIFECYCLE; @@ -71,8 +56,6 @@ namespace test { HashVal JUST_SOMETHING = 123; void* const SOME_POINTER = &JUST_SOMETHING; -// const uint TEST_SIZE = 1024*1024; -// const uint TEST_ELMS = 20; template @@ -89,6 +72,7 @@ namespace test { + /******************************************************************* * @test verify the properties of the BufferMetadata records used * internally within BufferProvider to attach additional @@ -105,6 +89,7 @@ namespace test { CHECK (ensure_proper_fixture()); verifyBasicProperties(); verifyStandardCase(); + verifyStateMachine(); } @@ -151,8 +136,8 @@ namespace test { CHECK (NIL == m1.state()); CHECK (!meta_->isLocked(key)); - VERIFY_ERROR (LIFECYCLE, m1.mark(EMITTED) ); - VERIFY_ERROR (LIFECYCLE, m1.mark(LOCKED) ); + VERIFY_ERROR (LIFECYCLE, m1.mark(EMITTED)); + VERIFY_ERROR (LIFECYCLE, m1.mark(FREE) ); // now create an active (buffer) entry metadata::Entry& m2 = meta_->markLocked (key, SOME_POINTER); @@ -186,7 +171,7 @@ namespace test { CHECK ( meta_->isKnown(keyX)); CHECK ( meta_->isKnown(key1)); VERIFY_ERROR (LIFECYCLE, m2.access()); - VERIFY_ERROR (LIFECYCLE, m2.mark(LOCKED)); + VERIFY_ERROR (FATAL, m2.mark(LOCKED)); // buffer missing CHECK ( isSameObject (m2, meta_->get(keyX))); // still accessible // release buffer... @@ -202,8 +187,8 @@ namespace test { * @note to get the big picture, please refer to * BufferProviderProtocol_test#verifyStandardCase() * This testcase here performs precisely the metadata related - * operations necessary to carry out the standard case outlined - * in that more high level test. + * operations necessary to carry out the standard case + * outlined on a higher level in the mentioned test. */ void verifyStandardCase() @@ -238,13 +223,19 @@ namespace test { metadata::Entry& r0 = meta_->markLocked(rawBuffType, &rawbuf[0]); metadata::Entry& r1 = meta_->markLocked(rawBuffType, &rawbuf[1]); - + CHECK (LOCKED == f0.state()); CHECK (LOCKED == f1.state()); CHECK (LOCKED == f2.state()); CHECK (LOCKED == r0.state()); CHECK (LOCKED == r1.state()); + CHECK (transaction1 == f0.localKey()); + CHECK (transaction1 == f1.localKey()); + CHECK (transaction1 == f2.localKey()); + CHECK (transaction2 == r0.localKey()); + CHECK (transaction2 == r1.localKey()); + CHECK (f0.access() == frames+0); CHECK (f1.access() == frames+1); @@ -269,6 +260,10 @@ namespace test { accessAs (f1) = testData(2); accessAs (f2) = testData(3); + CHECK (testData(1) == frames[0]); + CHECK (testData(2) == frames[1]); + CHECK (testData(3) == frames[2]); + CHECK (TestFrame::isAlive (f0.access())); CHECK (TestFrame::isAlive (f1.access())); CHECK (TestFrame::isAlive (f2.access())); @@ -283,7 +278,7 @@ namespace test { // client uses the buffers---------------------(End) - f0.mark(FREE); // note: this implicitly invoked the embedded dtor + f0.mark(FREE); // note: implicitly invoking the embedded dtor f1.mark(FREE); f2.mark(FREE); r0.mark(FREE); @@ -296,7 +291,7 @@ namespace test { meta_->release(handle_r0); meta_->release(handle_r1); - CHECK (TestFrame::isDead (&frames[0])); + CHECK (TestFrame::isDead (&frames[0])); // was destroyed implicitly CHECK (TestFrame::isDead (&frames[1])); CHECK (TestFrame::isDead (&frames[2])); @@ -309,9 +304,93 @@ namespace test { CHECK (!meta_->isLocked(handle_f2)); CHECK (!meta_->isLocked(handle_r0)); CHECK (!meta_->isLocked(handle_r1)); + } + + + void + verifyStateMachine() + { + // start with building a type key.... + metadata::Key key = meta_->key(SIZE_A); + CHECK (NIL == meta_->get(key).state()); + CHECK (meta_->get(key).isTypeKey()); + CHECK (!meta_->isLocked(key)); -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #834 -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #834 + VERIFY_ERROR (LIFECYCLE, meta_->get(key).mark(LOCKED) ); + VERIFY_ERROR (LIFECYCLE, meta_->get(key).mark(EMITTED)); + VERIFY_ERROR (LIFECYCLE, meta_->get(key).mark(BLOCKED)); + VERIFY_ERROR (LIFECYCLE, meta_->get(key).mark(FREE) ); + VERIFY_ERROR (LIFECYCLE, meta_->get(key).mark(NIL) ); + + // now build a concrete buffer entry + metadata::Entry& entry = meta_->markLocked(key, SOME_POINTER); + CHECK (LOCKED == entry.state()); + CHECK (!entry.isTypeKey()); + + CHECK (SOME_POINTER == entry.access()); + + VERIFY_ERROR (FATAL, entry.mark(LOCKED) ); // invalid state transition + VERIFY_ERROR (FATAL, entry.mark(NIL) ); + + entry.mark (EMITTED); // valid transition + CHECK (EMITTED == entry.state()); + CHECK (entry.isLocked()); + + VERIFY_ERROR (FATAL, entry.mark(LOCKED) ); + VERIFY_ERROR (FATAL, entry.mark(EMITTED)); + VERIFY_ERROR (FATAL, entry.mark(NIL) ); + CHECK (EMITTED == entry.state()); + + entry.mark (FREE); + CHECK (FREE == entry.state()); + CHECK (!entry.isLocked()); + CHECK (!entry.isTypeKey()); + + VERIFY_ERROR (LIFECYCLE, entry.access() ); + VERIFY_ERROR (FATAL, entry.mark(LOCKED) ); + VERIFY_ERROR (FATAL, entry.mark(EMITTED)); + VERIFY_ERROR (FATAL, entry.mark(BLOCKED)); + VERIFY_ERROR (FATAL, entry.mark(FREE) ); + VERIFY_ERROR (FATAL, entry.mark(NIL) ); + + // re-use buffer slot, start new lifecycle + void* OTHER_LOCATION = this; + entry.lock (OTHER_LOCATION); + CHECK (LOCKED == entry.state()); + CHECK (entry.isLocked()); + + VERIFY_ERROR (LIFECYCLE, entry.lock(SOME_POINTER)); + + entry.mark (BLOCKED); // go directly to the blocked state + CHECK (BLOCKED == entry.state()); + VERIFY_ERROR (FATAL, entry.mark(LOCKED) ); + VERIFY_ERROR (FATAL, entry.mark(EMITTED) ); + VERIFY_ERROR (FATAL, entry.mark(BLOCKED) ); + VERIFY_ERROR (FATAL, entry.mark(NIL) ); + + CHECK (OTHER_LOCATION == entry.access()); + + entry.mark (FREE); + CHECK (!entry.isLocked()); + VERIFY_ERROR (LIFECYCLE, entry.access() ); + + meta_->lock(key, SOME_POINTER); + CHECK (entry.isLocked()); + + entry.mark (EMITTED); + entry.mark (BLOCKED); + CHECK (BLOCKED == entry.state()); + CHECK (SOME_POINTER == entry.access()); + + // can't discard metadata, need to free first + VERIFY_ERROR (LIFECYCLE, meta_->release(entry) ); + CHECK (meta_->isKnown(entry)); + CHECK (entry.isLocked()); + + entry.mark (FREE); + meta_->release(entry); + CHECK (!meta_->isKnown(entry)); + CHECK ( meta_->isKnown(key)); } }; From 63dbc89b6f4ae263b6c98ae86905c7dbc7def77d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 5 Nov 2011 16:51:24 +0100 Subject: [PATCH 36/68] draft implementation setup for OutputSlot baseclass --- src/proc/engine/engine-service.cpp | 2 +- src/proc/engine/engine-service.hpp | 2 +- src/proc/play/output-slot.cpp | 71 ++++++++++++++++++- src/proc/play/output-slot.hpp | 24 ++++--- .../proc/engine/engine-interface-test.cpp | 2 +- .../proc/play/output-slot-protocol-test.cpp | 4 +- wiki/renderengine.html | 33 ++++----- 7 files changed, 107 insertions(+), 31 deletions(-) diff --git a/src/proc/engine/engine-service.cpp b/src/proc/engine/engine-service.cpp index e9d188a78..a4e989a19 100644 --- a/src/proc/engine/engine-service.cpp +++ b/src/proc/engine/engine-service.cpp @@ -61,7 +61,7 @@ namespace engine{ CalcStream EngineService::calculate(ModelPort mPort, Timings nominalTimings, - OutputConnection output, + OutputConnection& output, Quality serviceQuality) { UNIMPLEMENTED ("build a standard calculation stream"); diff --git a/src/proc/engine/engine-service.hpp b/src/proc/engine/engine-service.hpp index 6b0d84e5f..7e5c1339b 100644 --- a/src/proc/engine/engine-service.hpp +++ b/src/proc/engine/engine-service.hpp @@ -141,7 +141,7 @@ namespace engine{ CalcStream calculate(ModelPort mPort, Timings nominalTimings, - OutputConnection output, + OutputConnection& output, Quality serviceQuality =QoS_DEFAULT); CalcStream diff --git a/src/proc/play/output-slot.cpp b/src/proc/play/output-slot.cpp index ee04ed818..5f4ae9f7b 100644 --- a/src/proc/play/output-slot.cpp +++ b/src/proc/play/output-slot.cpp @@ -21,13 +21,20 @@ * *****************************************************/ +#include "lib/error.hpp" #include "proc/play/output-slot.hpp" +#include +#include namespace proc { namespace play { + using std::vector; + + namespace error = lumiera::error; + namespace { // hidden local details of the service implementation.... @@ -35,9 +42,56 @@ namespace play { } // (End) hidden service impl details + class Connection + { + public: + }; + + + class ConnectionState + : public OutputSlot::Allocation + , public vector + , boost::noncopyable + { + + typedef OutputSlot::OpenedSinks OpenedSinks; + + + private: /* == Allocation Interface == */ + OpenedSinks + getOpenedSinks() + { + UNIMPLEMENTED ("yield all opened channels"); + } + + bool + isActive() + { + return 0 < size(); + } + + + public: + ConnectionState() + { + UNIMPLEMENTED ("immediately build up the necessary number of connections"); + } + + virtual + ~ConnectionState() + { + UNIMPLEMENTED ("shut down all connections"); + } + }; + + OutputSlot::~OutputSlot() { } // emit VTables here.... + OutputSlot::Allocation::~Allocation() { } + + + /** whether this output slot is occupied @@ -47,9 +101,22 @@ namespace play { bool OutputSlot::isFree() const { - UNIMPLEMENTED ("connection state"); + return ! this->state_; + } + + + /** */ + OutputSlot::Allocation& + OutputSlot::allocate() + { + if (!isFree()) + throw error::Logic ("Attempt to open/allocate an OutputSlot already in use."); + + UNIMPLEMENTED ("internal interface to determine the number of channel-connections"); + + this->state_.reset(new ConnectionState()); + return *state_; } - diff --git a/src/proc/play/output-slot.hpp b/src/proc/play/output-slot.hpp index ece7c4627..70e0c7bf4 100644 --- a/src/proc/play/output-slot.hpp +++ b/src/proc/play/output-slot.hpp @@ -45,10 +45,10 @@ //#include "lib/sync.hpp" #include +#include //#include //#include //#include -//#include namespace proc { @@ -61,12 +61,16 @@ namespace play { //using std::vector; //using std::tr1::shared_ptr; -//using boost::scoped_ptr; + using boost::scoped_ptr; /** established output channel */ class Connection; + /** Table to maintain connection state */ + class ConnectionState; + + typedef int64_t FrameNr; @@ -90,25 +94,29 @@ namespace play { class OutputSlot : boost::noncopyable { + scoped_ptr state_; + + public: virtual ~OutputSlot(); typedef lib::IterSource::iterator OpenedSinks; - struct Allocation + class Allocation { - OpenedSinks getOpenedSinks(); - - bool isActive(); + public: + virtual OpenedSinks getOpenedSinks() =0; + virtual bool isActive() =0; /////TODO add here the getters for timing constraints + protected: + ~Allocation(); }; bool isFree() const; - Allocation - allocate(); + Allocation& allocate(); protected: friend class DataSink; diff --git a/tests/components/proc/engine/engine-interface-test.cpp b/tests/components/proc/engine/engine-interface-test.cpp index fd55ee76f..3b0e96bd8 100644 --- a/tests/components/proc/engine/engine-interface-test.cpp +++ b/tests/components/proc/engine/engine-interface-test.cpp @@ -93,7 +93,7 @@ namespace test { ModelPort port(pipe); OutputSlot& oSlot = DiagnosticOutputSlot::build(); - Allocation output = oSlot.allocate(); + Allocation& output = oSlot.allocate(); Timings timings; /////////TODO // Invoke test subject... diff --git a/tests/components/proc/play/output-slot-protocol-test.cpp b/tests/components/proc/play/output-slot-protocol-test.cpp index ae3ec2ae5..29b1db615 100644 --- a/tests/components/proc/play/output-slot-protocol-test.cpp +++ b/tests/components/proc/play/output-slot-protocol-test.cpp @@ -71,7 +71,6 @@ namespace test { void verifyStandardCase() { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #819 // Create Test fixture. // In real usage, the OutputSlot will be preconfigured // (Media format, number of channels, physical connections) @@ -80,7 +79,7 @@ namespace test { // Client claims the OutputSlot // and opens it for exclusive use. - OutputSlot::Allocation alloc = oSlot.allocate(); + OutputSlot::Allocation& alloc = oSlot.allocate(); // Now the client is able to prepare // "calculation streams" for the individual @@ -139,6 +138,7 @@ namespace test { CHECK (*stream1++ == testData(1,0)); CHECK (*stream1++ == testData(1,1)); CHECK (!stream1); +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #819 #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #819 } }; diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 42a7cb353..6abd6656c 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -1133,8 +1133,8 @@ Beyond that, it can be necessary to associate at least a state flag with //indiv __Note__: while the API to access this service is uniform, conceptually there is a difference between just using the (shared) type information and associating individual metadata, like the buffer state. Type-~IDs, once allocated, will never be discarded (within the lifetime of an Lumiera application instance -- buffer associations aren't persistent). To the contrary, individual metadata //will be discarded,// when releasing the corresponding buffer. According to the ''prototype pattern'', individual metadata is treated as a one-way-off specialisation. -
-
It turns out that --  throughout the render engine implementation -- we never need direct access to the buffers holding media data. Buffers are just some entity to be //managed,// i.e. "allocated", "locked" and "released"; the //actual meaning of these operations can be left to the implementation.// The code within the render engine just pushes around ''smart-prt like handles''. These [[buffer handles|BuffHandle]] act as a front-end, being created by and linked to a buffer provider implementation. There is no need to manage the lifecycle of buffers automatically, because the use of buffers is embedded into the render calculation cycle, which follows a rather strict protocol anyway. Relying on the [[capabilities of the scheduler|SchedulerRequirements]], the sequence of individual jobs in the engine ensures...
+
+
It turns out that --  throughout the render engine implementation -- we never need direct access to the buffers holding actual media data. Buffers are just some entity to be //managed,// i.e. "allocated", "locked" and "released"; the //actual meaning of these operations can be left to the implementation.// The code within the render engine just pushes around ''smart-prt like handles''. These [[buffer handles|BuffHandle]] act as a front-end, being created by and linked to a buffer provider implementation. There is no need to manage the lifecycle of buffers automatically, because the use of buffers is embedded into the render calculation cycle, which follows a rather strict protocol anyway. Relying on the [[capabilities of the scheduler|SchedulerRequirements]], the sequence of individual jobs in the engine ensures...
 * that the availability of a buffer was ensured prior to planning a job ("buffer allocation")
 * that a buffer handle was obtained ("locked") prior to any operation requiring a buffer
 * that buffers are marked as free ("released") after doing the actual calculations.
@@ -3337,7 +3337,7 @@ While actually data frames are //pulled,// on a conceptual level data is assumed
 As both of these specifications are given by [[Pipe]]-~IDs, the actual designation information may be reduced. Much can be infered from the circumstances, because any pipe includes a StreamType, and an output designation for an incompatible stream type is irrelevant. (e.g. and audio output when the pipe currently in question deals with video)
 
-
+
//writing down some thoughts//
 
 * ruled out the system outputs as OutputDesignation.
@@ -3366,12 +3366,12 @@ Any external output sink is managed as a [[slot|DisplayerSlot]] in the ~OutputMa
 &rarr; see also the PlayService
 
 !the global output manager
-While within the model routing is done mostly just by referring to an OutputDesignation, at some point we need to map these abstract designations to real output capabilities. This OutputManager interface exposes these mappings and allows to control and manage them. Several elements within the application, most notably the [[viewers|ViewerAsset]], provide an implementation of this interface -- yet there is one primary implementation, the ''global output manager'', known as OutputDirector. It can be accessed through the {{{Output}}} façade interface and is the final authority when it comes to allocating an mapping of real output possibilities. The OutputDirector tracks all the OutputSlot elements currently installed and available for output.
+Within the model routing is done mostly just by referring to an OutputDesignation -- but at some point finally we need to map these abstract designations to real output capabilities. This happens at the //output managing elements.// This interface, OutputManager, exposes these mappings of logical to real outputs and allows to  manage and control them. Several elements within the application, most notably the [[viewers|ViewerAsset]], provide an implementation of this interface -- yet there is one primary implementation, the ''global output manager'', known as OutputDirector. It can be accessed through the {{{Output}}} façade interface and is the final authority when it comes to allocating and mapping of real output possibilities. The OutputDirector tracks all the OutputSlot elements currently installed and available for output.
 
-The relation between the central OutputDirector and the peripheral OutputManager implementations is hierarchical. Because output slots are usually registered rather at some peripheral output manager implementation, a direct mapping from OutputDesignation (i.e. global pipe) to these slots is created foremost at that peripheral level. Resolving a global pipe into an output slot is the core concern of any OutputManager implementation. Thus, when there is a locally preconfigured mapping, like e.g. for a viewer's video master pipe to the output slot installed by the corresponding GUI viewer element, then this mapping will picked up foremost to resolve the video master output.
+The relation between the central OutputDirector and the peripheral OutputManager implementations is hierarchical. Because output slots are usually registered rather at some peripheral output manager implementation, a direct mapping from OutputDesignation (i.e. global pipe) to these slots is created foremost at that peripheral level. Resolving a global pipe into an output slot is the core concern of any OutputManager implementation. Thus, when there is a locally preconfigured mapping, like e.g. for a viewer's video master pipe to the output slot installed by the corresponding GUI viewer element, then this mapping will be picked up foremost to resolve the video master output.
 
 For a viewer widget in the GUI this yields exactly the expeted behaviour, but in other cases, e.g. for sound output, we need more general, more globally scoped output slots. In these cases, when a local mapping is absent, the query for output resolution is passed on up to the  OutputDirector, drawing on the collection of globally available output slots for that specific kind of media.
-{{red{Question: is it possible to retrieve a slot from another peripheral node?}}}
+{{red{open question 11/11: is it possible to retrieve a slot from another peripheral node?}}}
 
@@ -3423,33 +3423,34 @@ Thus the mapping is a copyable value object, based on a associative array. It ma First and foremost, mapping can be seen as a //functional abstraction.// As it's used at implementation level, encapsulation of detail types in't the primary concern, so it's a candidate for generic programming: For each of those use cases outlined above, a distinct mapping type is created by instantiating the {{{OutputMapping<DEF>}}} template with a specifically tailored definition context ({{{DEF}}}), which takes on the role of a strategy. Individual instances of this concrete mapping type may be default created and copied freely. This instantiation process includes picking up the concrete result type and building a functor object for resolving on the fly. Thus, in the way typical for generic programming, the more involved special details are moved out of sight, while being still in scope for the purpose of inlining. But there //is// a concern better to be encapsulated and concealed at the usage site, namely accessing the rules system. Thus mapping leads itself to the frequently used implementation pattern where there is a generic frontend as header, calling into opaque functions embedded within a separate compilation unit.
-
+
Within the Lumiera player and output subsystem, actually sending data to an external output requires to allocate an ''output slot''
-This is the central metaphor for the organisation of actual (system level) outputs; using this concept allows to separate and abstract the data calculation and the organisation of playback and rendering from the specifics of the actual output sink. Actual output possibilities can be added and removed dynamically from various components (backend, GUI), all using the same resolution and mapping mechanisms (&rarr; OutputManagement)
+This is the central metaphor for the organisation of actual (system level) outputs; using this concept allows to separate and abstract the data calculation and the organisation of playback and rendering from the specifics of the actual output sink. Actual output possibilities (video in GUI window, video fullscreen, sound, Jack, rendering to file) can be added and removed dynamically from various components (backend, GUI), all using the same resolution and mapping mechanisms (&rarr; OutputManagement)
 
 !Properties of an output slot
 Each OutputSlot is an unique and distinguishable entity. It corresponds explicitly to an external output, or a group of such outputs (e.g. left and right soundcard output channels), or an output file or similar capability accepting media content. First off, an output slot needs to be provided, configured and registered, using an implementation for the kind of media data to be output (sound, video) and the special circumstances of the output capability (render a file, display video in a GUI widget, send video to a full screen display, establish a Jack port, just use some kind of "sound out"). An output slot is always limited to a single kind of media, and to a single connection unit, but this connection may still be comprised of multiple channels (stereoscopic video, multichannel sound).
 
-In order to be usable as //output sink,// an output slot needs to be //allocated,// i.e. tied to and locked for a specific client. At any time, there may be only a single client using a given output slot this way. To stress this point: output slots don't provide any kind of inherent mixing capability; any adaptation, mixing, overlaying and sharing needs to be done within the nodes network producing the output data fed to the slot. (yet some special kinds of external output capabilities -- e.g. the Jack audio connection system -- may still provide additional mixing capabilities, but that's beyond the scope of the Lumiera application)
+In order to be usable as //output sink,// an output slot needs to be //allocated,// i.e. tied to and locked for a specific client. At any time, there may be only a single client using a given output slot this way. To stress this point: output slots don't provide any kind of inherent mixing capability; any adaptation, mixing, overlaying and sharing needs to be done within the nodes network producing the output data fed to the slot. (in special cases, some external output capabilities -- e.g. the Jack audio connection system -- may still provide additional mixing capabilities, but that's beyond the scope of the Lumiera application)
 
-Once allocated, the output slot returns a set of concrete ''sink handles'' (one for each physical channel expecting data). The calculating process feeds its results into those handles. Size and other characteristics of the data frames is assumed to be suitable, which typically won't be verified at that level anymore (but the sink handle provides a hook for assertions). Besides that, the allocation of an output slot reveals detailed ''timing expectations''. The client is required to comply to these timings when ''emitting'' data -- he's even required to provide a //current time specification,// alongside with the data. Yet the output slot has the ability to handle timing failures gracefully; the concrete output slot implementation is expected to provide some kind of de-click or de-flicker facility, which kicks in automatically when a timing failure is detected.
+Once allocated, the output slot returns a set of concrete ''sink handles'' (one for each physical channel expecting data). The calculating process feeds its results into those handles. Size and other characteristics of the data frames are assumed to be suitable, which typically won't be verified at that level anymore (but the sink handle provides a hook for assertions). Besides that, the allocation of an output slot reveals detailed ''timing expectations''. The client is required to comply to these timings when ''emitting'' data -- he's even required to provide a //current time specification,// alongside with the data. Yet the output slot has the ability to handle timing failures gracefully; the concrete output slot implementation is expected to provide some kind of de-click or de-flicker facility, which kicks in automatically when a timing failure is detected.
 
 !!!data exchange models
 Data is handed over by the client invoking an {{{emit(time,...)}}} function on the sink handle. Theoretically there are two different models how this data hand-over might be performed. This corresponds to the fact, that in some cases our own code manages the output and the buffers, while in other situations we intend to use existing library solutions or even external server applications to handle output
 ;buffer handover model
 :the client owns the data buffer and cares for allocation and de-allocation. The {{{emit()}}}-call just propagates a pointer to the buffer holding the data ready for output. The output slot implementation in turn has the liability to copy or otherwise use this data within a given time limit.
 ;shared buffer model
-:here the output mechanism owns the buffer. Within a certain time window prior to the expected time of the {{{emit()}}}-call, the client may obtain this buffer (pointer) to fill in the data. The slot implementation won't touch this buffer until the {{{emit()}}} handover, which in this case just provides the time and states that the client is done with that buffer. If the data emitting handshake doesn't happen at all, it counts as late and superseded by the next handshake.
+:here the output mechanism owns the buffer. Within a certain time window prior to the expected time of the {{{emit()}}}-call, the client may obtain this buffer (pointer) to fill in the data. The slot implementation won't touch this buffer until the {{{emit()}}} handover, which in this case just provides the time and signalles the client is done with that buffer. If the data emitting handshake doesn't happen at all, it counts as late and superseded by the next handshake.
 
 !!!timing expectations
 Besides the sink handles, allocation of an output slot defines some timing constraints, which are binding for the client. These timings are detailed and explicit, including a grid of deadlines for each frame to deliver, plus a fixed //latency.// Within this context, &raquo;latency&laquo; means the requirement to be ahead of the nominal time by a certain amount, to compensate for the processing time necessary to propagate the media to the physical output pin. The output slot implementation itself is bound by external constraints to deliver data at a fixed framerate and aligned to an externally defined timing grid, plus the data needs to be handed over ahead of these time points by an time amount given by the latency. Depending on the data exchange model, there is an additional time window limiting the buffer management.
 
-The assumption is for the client to have elaborate timing capabilities at his disposal. More specifically, the client is a job running within the engine scheduler and thus can be configured to run //after// another job has finished, and to run within certain time limits. Thus the client is able to provide a //current nominal time// -- which is suitably close to the actual wall clock time. The output slot implementation can be written such as to work out from this time specification if the call is timely or overdue -- and react accordingly.
+The assumption is for the client to have elaborate timing capabilities at his disposal. More specifically, the client is assumed to be a job running within the engine scheduler and thus can be configured to run //after// another job has finished, and to run within certain time limits. Thus the client is able to provide a //current nominal time// -- which is suitably close to the actual wall clock time. The output slot implementation can be written such as to work out from this time specification if the call is timely or overdue -- and react accordingly.
 
 {{red{TODO 6/11}}}in this spec, both data exchange models exhibit a weakness regarding the releasing of buffers. At which time is it safe to release a buffer, when the handover didn't happen? Do we need an explicit callback, and how could this callback be triggered? This is similar to the problem of closing a network connection, i.e. the problem is generally unsolvable, but can be handled pragmatically within certain limits.
+{{red{WIP 11/11}}}meanwhile I've worked out the BufferProvider interface in deail. There's now a deatiled buffer handover protocol defined, which is supported by a little state engine tracking BufferMetadata. This mechanism provides a transition to {{{BLOCKED}}} state when order or timing constraints are being violated, which practically solves this problem. How to detect and resolve such a floundered state from the engine point of view still remains to be addressed.
 
 !!!Lifecycle and storage
-The concrete OutputSlot implementation is owned and managed by the facility actually providing this output possibility. For example, the GUI provides viewer widgets, while some sound output backend provides sound ports. This implementation object is required to stay alive as long as it's registered with some OutputManager. It needs to be deregistered explicitly prior to destruction -- and this deregistration may block until all clients using this slot are terminated. Beyond that, an output slot implementation is expected to handle all kinds of failures gracefully -- preferrably just emitting a signal (callback functor).
+The concrete OutputSlot implementation is owned and managed by the facility actually providing the output possibility in question. For example, the GUI provides viewer widgets, while some sound output backend provides sound ports. The associated OutputSlot implementation object is required to stay alive as long as it's registered with some OutputManager. It needs to be de-registered explicitly prior to destruction -- and this deregistration may block until all clients using this slot did terminate. Beyond that, an output slot implementation is expected to handle all kinds of failures gracefully -- preferably just emitting a signal (callback functor).
 {{red{TODO 7/11: Deregistration is an unsolved problem....}}}
 
 -----
@@ -3466,9 +3467,9 @@ Solving this problem through //generic programming// -- i.e coding both cases ef
 ;unified
 :extend and adapt the protocol such to make both models similar; concentrate all differences //within a separate buffer provider.//
 !!!discussion
-the generic approach looks as it's becoming rather convoluted in practice. We'd need to hand over additional parameters to the factory, which passes them through to the actual job implementation created. And there would be a coupling between slot and job (the slot is aware it's going to be used by a job, and even provides the implementation). Obviously, a benefit is that the actual code path executed within the job is without indirections, and all written down in a single location. Another benefit is the possibility to extend this approach to cover further buffer handling models -- it doesn't pose any requirements on the structure of the buffer handling.
-If we accept to retrieve the buffer(s) via an indirection, which we kind of do anyway //within the render node implementation// -- the unified model looks more like a clean solution. It's more like doing away with some local optimisations possible if we handle the models explicitly, so it's not much of a loss, given that the majority of the processing time will be spent within the inner pixel calculation loops for frame processing anyway. When following this approach, the BufferProvider becomes a third, independent partner, and the slot cooperates tightly with this buffer provider, while the client (processing node) still just talks to the slot. Basically, this unified solution is like extending the shared buffer model to both cases.
-&rArr; conclusion: go for the unified approach!
+the generic approach looks as it's becoming rather convoluted in practice. We'd need to hand over additional parameters to the factory, which passes them through to the actual job implementation created. And there would be a coupling between slot and job (the slot is aware it's going to be used by a job, and even provides the implementation). Obviously, a benefit is that the actual code path executed within the job is without indirections, and all written down in a single location. Another benefit is the possibility to extend this approach to cover further buffer handling models -- it doesn't pose any requirements on the structure of the buffer handling --
+On the other hand, if we accept to retrieve the buffer(s) via an indirection, which we kind of do anyway //within the render node implementation// -- the unified model looks more like a clean solution. It's more like doing away with some local optimisations possible if we handle the models explicitly, so it's not much of a loss, given that the majority of the processing time will be spent within the inner pixel calculation loops for frame processing anyway. When following this approach, the BufferProvider becomes a third, independent partner, and the slot cooperates tightly with this buffer provider, while the client (processing node) still just talks to the slot. Basically, this unified solution works like extending the shared buffer model to both cases.
+&rArr; __conclusion__: go for the unified approach!
 
 !!!unified data exchange cycle
 The planned delivery time of a frame is used as an ID throughout that cycle

From 7ab7c8073dc3bcc7b6aafdc6706253e0b7fa7ca5 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 6 Nov 2011 02:37:22 +0100
Subject: [PATCH 37/68] remold OutputSlot implementation structure

Better solution where to place the extension points
to be implemented by concrete output systems
---
 src/proc/play/output-slot-connection.hpp      | 162 ++++++++++++++++++
 src/proc/play/output-slot.cpp                 |  52 ++----
 src/proc/play/output-slot.hpp                 |  58 ++++---
 .../proc/play/diagnostic-output-slot.hpp      |   8 +-
 4 files changed, 210 insertions(+), 70 deletions(-)
 create mode 100644 src/proc/play/output-slot-connection.hpp

diff --git a/src/proc/play/output-slot-connection.hpp b/src/proc/play/output-slot-connection.hpp
new file mode 100644
index 000000000..c19080ed4
--- /dev/null
+++ b/src/proc/play/output-slot-connection.hpp
@@ -0,0 +1,162 @@
+/*
+  OUTPUT-SLOT-CONNECTION.hpp  -  implementation API for concrete output slots
+
+  Copyright (C)         Lumiera.org
+    2011,               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 output-slot-connection.hpp
+ ** Interface for concrete output implementations to talk to the OutputSlot frontend.
+ ** The OutputSlot concept helps to decouple the render engine implementation from the details
+ ** of handling external output connections. For this to work, a concrete implementation of such
+ ** an external output needs to integrate with the generic OutputSlot frontend, as used by the
+ ** engine. This generic frontend uses a PImpl, pointing to a ConnectionState object, which embodies
+ ** the actual implementation. Moreover, this actual implementation is free to use specifically crafted
+ ** OutputSlot::Connection elements to handle the ongoing output for individual channels. The latter
+ ** thus becomes the central implementation side API for providing actual output capabilities.
+ **
+ ** @see OutputSlotProtocol_test
+ ** @see diagnostic-output-slot.hpp  ////TODO
+ */
+
+
+#ifndef PROC_PLAY_OUTPUT_SLOT_CONNECTION_H
+#define PROC_PLAY_OUTPUT_SLOT_CONNECTION_H
+
+
+#include "lib/error.hpp"
+#include "proc/play/output-slot.hpp"
+#include "lib/handle.hpp"
+//#include "lib/time/timevalue.hpp"
+//#include "proc/engine/buffer-provider.hpp"
+//#include "proc/play/timings.hpp"
+#include "lib/iter-source.hpp"
+#include "lib/iter-adapter-stl.hpp"
+//#include "lib/sync.hpp"
+
+#include 
+#include 
+//#include 
+//#include 
+//#include 
+
+
+namespace proc {
+namespace play {
+
+//using ::engine::BuffHandle;
+//using ::engine::BufferProvider;
+//using lib::time::Time;
+//using std::string;
+  using lib::transform;
+  using lib::iter_stl::eachElm;
+
+//using std::vector;
+//using std::tr1::shared_ptr;
+  using boost::scoped_ptr;
+  
+  
+  
+  
+  /** established output channel */
+  class OutputSlot::Connection
+    {
+    public:
+      virtual ~Connection();
+      
+      virtual void lock     (FrameID)   =0;
+      virtual void transfer (FrameID)   =0;
+      virtual void pushout  (FrameID)   =0;
+    };
+      
+      
+  
+  
+  class OutputSlot::ConnectionState
+    : public OutputSlot::Allocation
+    , boost::noncopyable
+    {
+    public:
+      virtual ~ConnectionState() { }
+    };
+  
+  
+  template
+  class ConnectionStateManager
+    : public OutputSlot::ConnectionState
+    , public vector
+    {
+
+      typedef OutputSlot::OpenedSinks OpenedSinks;
+      
+      
+      /* == Allocation Interface == */
+      
+      OpenedSinks
+      getOpenedSinks()
+        {
+          REQUIRE (this->isActive());
+          return transform (eachElm(*this), connectOutputSink);
+        }
+      
+      bool
+      isActive()
+        {
+          return 0 < vector::size();
+        }
+      
+      
+    public:
+      ConnectionStateManager()
+        {
+          UNIMPLEMENTED ("immediately build up the necessary number of connections");
+        }
+
+     virtual
+    ~ConnectionStateManager()
+        {
+          UNIMPLEMENTED ("shut down all connections");
+        }
+      
+      virtual
+      CON
+      buildConnection()  =0;
+      
+      
+    private: // Implementation details
+      
+      DataSink
+      connectOutputSink (CON& connection)
+        {
+          DataSink newSink;
+          newSink.activate(&connection, shutdownConnection);
+          return newSink;
+        }
+      
+      void
+      shutdownConnection (CON* toClose)
+        {
+          UNIMPLEMENTED ("how to mark a connection as closed");
+        }
+    };
+  
+  
+  
+  
+}} // namespace proc::play
+#endif
diff --git a/src/proc/play/output-slot.cpp b/src/proc/play/output-slot.cpp
index 5f4ae9f7b..6cd3c5aa4 100644
--- a/src/proc/play/output-slot.cpp
+++ b/src/proc/play/output-slot.cpp
@@ -23,6 +23,7 @@
 
 #include "lib/error.hpp"
 #include "proc/play/output-slot.hpp"
+#include "proc/play/output-slot-connection.hpp"
 
 #include 
 #include 
@@ -42,48 +43,8 @@ namespace play {
   } // (End) hidden service impl details
   
   
-  class Connection
-    {
-    public:
-    };
   
   
-  class ConnectionState
-    : public OutputSlot::Allocation
-    , public vector
-    , boost::noncopyable
-    {
-
-      typedef OutputSlot::OpenedSinks OpenedSinks;
-      
-      
-    private: /* == Allocation Interface == */
-      OpenedSinks
-      getOpenedSinks()
-        {
-          UNIMPLEMENTED ("yield all opened channels");
-        }
-      
-      bool
-      isActive()
-        {
-          return 0 < size();
-        }
-      
-      
-    public:
-      ConnectionState()
-        {
-          UNIMPLEMENTED ("immediately build up the necessary number of connections");
-        }
-
-     virtual
-    ~ConnectionState()
-        {
-          UNIMPLEMENTED ("shut down all connections");
-        }
-    };
-  
   
   
   OutputSlot::~OutputSlot() { }  // emit VTables here....
@@ -114,10 +75,19 @@ namespace play {
     
     UNIMPLEMENTED ("internal interface to determine the number of channel-connections");
     
-    this->state_.reset(new ConnectionState());
+    state_.reset (this->buildState());
     return *state_;
   }
   
   
+  void
+  OutputSlot::disconnect()
+  {
+    if (!isFree())
+      state_.reset(0);    
+  }
+
+  
+  
   
 }} // namespace proc::play
diff --git a/src/proc/play/output-slot.hpp b/src/proc/play/output-slot.hpp
index 70e0c7bf4..04754e4bd 100644
--- a/src/proc/play/output-slot.hpp
+++ b/src/proc/play/output-slot.hpp
@@ -38,7 +38,7 @@
 
 #include "lib/error.hpp"
 #include "lib/handle.hpp"
-#include "lib/time/timevalue.hpp"
+//#include "lib/time/timevalue.hpp"
 #include "proc/engine/buffer-provider.hpp"
 #include "proc/play/timings.hpp"
 #include "lib/iter-source.hpp"
@@ -56,7 +56,7 @@ namespace play {
 
   using ::engine::BuffHandle;
   using ::engine::BufferProvider;
-  using lib::time::Time;
+//using lib::time::Time;
 //using std::string;
 
 //using std::vector;
@@ -64,25 +64,10 @@ namespace play {
   using boost::scoped_ptr;
   
   
-  /** established output channel */
-  class Connection;
   
-  /** Table to maintain connection state */
-  class ConnectionState;
-  
-  
-  typedef int64_t FrameNr;
-  
-  
-  class DataSink
-    : public lib::Handle
-    {
-      
-    public:
-      BuffHandle lockBufferFor(FrameNr);
-      void emit(FrameNr);
-    };
+  class DataSink;
   
+  typedef int64_t FrameID;
   
   
   
@@ -94,8 +79,16 @@ namespace play {
   class OutputSlot
     : boost::noncopyable
     {
+      
+    protected:
+      
+      /** Table to maintain connection state */
+      class ConnectionState;
+      
       scoped_ptr state_;
       
+      virtual ConnectionState* buildState() =0;
+      
       
     public:
       virtual ~OutputSlot();
@@ -113,17 +106,19 @@ namespace play {
          ~Allocation();
         };
       
+      /** established output channel */
+      class Connection;
       
+      
+      /** can this OutputSlot be allocated? */
       bool isFree()  const;
       
+      /** claim this slot for exclusive use */
       Allocation& allocate();
       
-    protected:
-      friend class DataSink;
-      
-      virtual void lock     (FrameNr, uint channel)   =0;
-      virtual void transfer (FrameNr, uint channel)   =0;
-      virtual void pushout  (FrameNr, uint channel)   =0;
+      /** disconnect from this OutputSlot
+       * @warning may block until DataSinks are gone */
+      void disconnect();
       
     private:
       
@@ -131,5 +126,18 @@ namespace play {
   
   
   
+  class DataSink
+    : public lib::Handle
+    {
+      
+    public:
+      BuffHandle lockBufferFor(FrameID);
+      void emit(FrameID);
+    };
+  
+  
+  
+  
+  
 }} // namespace proc::play
 #endif
diff --git a/tests/components/proc/play/diagnostic-output-slot.hpp b/tests/components/proc/play/diagnostic-output-slot.hpp
index 18a13c6b3..ffd1ce829 100644
--- a/tests/components/proc/play/diagnostic-output-slot.hpp
+++ b/tests/components/proc/play/diagnostic-output-slot.hpp
@@ -105,28 +105,28 @@ namespace play {
       
       
       bool
-      buffer_was_used (uint channel, FrameNr frame)
+      buffer_was_used (uint channel, FrameID frame)
         {
           UNIMPLEMENTED ("determine if the denoted buffer was indeed used");
         }
       
       
       bool
-      buffer_unused   (uint channel, FrameNr frame)
+      buffer_unused   (uint channel, FrameID frame)
         {
           UNIMPLEMENTED ("determine if the specified buffer was never touched/locked for use");
         }
       
       
       bool
-      buffer_was_closed (uint channel, FrameNr frame)
+      buffer_was_closed (uint channel, FrameID frame)
         {
           UNIMPLEMENTED ("determine if the specified buffer was indeed closed properly");
         }
       
       
       bool
-      emitted (uint channel, FrameNr frame)
+      emitted (uint channel, FrameID frame)
         {
           UNIMPLEMENTED ("determine if the specivied buffer was indeed handed over for emitting output");
         }

From a88ccd219d3d2b3e9c158771a6e7195435563286 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Mon, 7 Nov 2011 00:07:53 +0100
Subject: [PATCH 38/68] extract the diagnostic BufferProvider into separate
 header

---
 .../engine/diagnostic-buffer-provider.cpp     | 108 +-------------
 .../engine/diagnostic-buffer-provider.hpp     |  20 +--
 .../engine/tracking-heap-block-provider.cpp   | 113 +++++++++++++++
 .../engine/tracking-heap-block-provider.hpp   | 137 ++++++++++++++++++
 src/proc/play/output-slot-connection.hpp      |  49 ++++++-
 5 files changed, 311 insertions(+), 116 deletions(-)
 create mode 100644 src/proc/engine/tracking-heap-block-provider.cpp
 create mode 100644 src/proc/engine/tracking-heap-block-provider.hpp

diff --git a/src/proc/engine/diagnostic-buffer-provider.cpp b/src/proc/engine/diagnostic-buffer-provider.cpp
index 8a5efdfbe..d8933733c 100644
--- a/src/proc/engine/diagnostic-buffer-provider.cpp
+++ b/src/proc/engine/diagnostic-buffer-provider.cpp
@@ -22,17 +22,16 @@
 
 
 #include "lib/error.hpp"
-#include "include/logging.h"
 #include "lib/meta/function.hpp"
-#include "lib/scoped-ptrvect.hpp"
 
 #include "proc/engine/diagnostic-buffer-provider.hpp"
+#include "proc/engine/tracking-heap-block-provider.hpp"
 
-#include 
+//#include 
 //#include 
 
-using lib::ScopedPtrVect;
-using boost::scoped_array;
+//using lib::ScopedPtrVect;
+//using boost::scoped_array;
 
 
 
@@ -43,110 +42,15 @@ namespace engine {
   lib::Singleton DiagnosticBufferProvider::diagnostics;
   
   
-  class Block
-    : boost::noncopyable
-    {
-      size_t size_;
-      scoped_array storage_;
-      
-      bool was_locked_;
-      
-    public:
-      Block()
-        : size_(0)
-        , storage_()
-        , was_locked_(false)
-        { }
-      
-      bool
-      was_used()  const
-        {
-          return was_locked_;
-        }
-      
-      bool
-      was_closed()  const
-        {
-          return was_locked_;
-        }
-      
-      void*
-      accessMemory()  const
-        {
-          return storage_.get();
-        }
-    };
-  
     
     
   namespace { // Details of allocation and accounting
     
-    const uint MAX_BUFFERS = 50;
   
   } // (END) Details of allocation and accounting
   
   
   
-  /**
-   * @internal DiagnosticBufferProvider's PImpl.
-   * Uses a linearly growing table of heap allocated buffer blocks,
-   * which will never be discarded, unless the PImpl is discarded as a whole.
-   * This way, the tracked usage information remains available after the fact.
-   */
-  class DiagnosticBufferProvider::HeapMemProvider
-    : public BufferProvider
-    , public ScopedPtrVect
-    {
-      
-      virtual uint
-      announce (uint count, BufferDescriptor const& type)
-        {
-          UNIMPLEMENTED ("pre-register storage for buffers of a specific kind");   
-        }
-
-      
-      virtual BuffHandle
-      lockBufferFor (BufferDescriptor const& descriptor)
-        {
-          UNIMPLEMENTED ("lock buffer for exclusive use");
-        }
-      
-      virtual void
-      releaseBuffer (BuffHandle const& handle)
-        {
-          UNIMPLEMENTED ("release a buffer and invalidate the handle");
-        }
-      
-    public:
-      HeapMemProvider()
-        : BufferProvider ("Diagnostic_HeapAllocated")
-        { }
-      
-      virtual ~HeapMemProvider()
-        {
-          INFO (proc_mem, "discarding %zu diagnostic buffer entries", HeapMemProvider::size());
-        }
-      
-      Block&
-      access_or_create (uint bufferID)
-        {
-          while (!withinStorageSize (bufferID))
-            manage (new Block);
-          
-          ENSURE (withinStorageSize (bufferID));
-          return (*this)[bufferID];
-        }
-      
-    private:
-      bool
-      withinStorageSize (uint bufferID)  const
-        {
-          if (bufferID >= MAX_BUFFERS)
-            throw error::Fatal ("hardwired internal limit for test buffers exceeded");
-          
-          return bufferID < size();
-        }
-    };
   
   
 
@@ -177,10 +81,10 @@ namespace engine {
 
     
     
-  DiagnosticBufferProvider::HeapMemProvider&
+  TrackingHeapBlockProvider&
   DiagnosticBufferProvider::reset()
   {
-    pImpl_.reset(new HeapMemProvider());
+    pImpl_.reset(new TrackingHeapBlockProvider());
     return *pImpl_;
   }
   
diff --git a/src/proc/engine/diagnostic-buffer-provider.hpp b/src/proc/engine/diagnostic-buffer-provider.hpp
index 0f80fea6e..83bb589ca 100644
--- a/src/proc/engine/diagnostic-buffer-provider.hpp
+++ b/src/proc/engine/diagnostic-buffer-provider.hpp
@@ -21,7 +21,7 @@
 */
 
 /** @file diagnostic-buffer-provider.hpp
- ** An facility for writing unit-tests targetting the BufferProvider interface.
+ ** An facility for writing unit-tests targeting the BufferProvider interface.
  **
  ** @see buffer-provider-protocol-test.cpp
  */
@@ -44,6 +44,13 @@ namespace engine {
   namespace error = lumiera::error;
   
   
+  /**
+   * simple BufferProvider implementation
+   * with additional allocation tracking
+   */
+  class TrackingHeapBlockProvider;
+  
+  
   /********************************************************************
    * Helper for unit tests: Buffer provider reference implementation.
    * 
@@ -53,18 +60,11 @@ namespace engine {
     : boost::noncopyable
     {
       
-      /**
-       * simple BufferProvider implementation
-       * with additional allocation tracking
-       */
-      class HeapMemProvider;
-      
-      
-      boost::scoped_ptr              pImpl_;
+      boost::scoped_ptr    pImpl_;
       static lib::Singleton diagnostics;
       
       
-      HeapMemProvider& reset();
+      TrackingHeapBlockProvider& reset();
       bool isCurrent (BufferProvider const&);
       
       
diff --git a/src/proc/engine/tracking-heap-block-provider.cpp b/src/proc/engine/tracking-heap-block-provider.cpp
new file mode 100644
index 000000000..947acc614
--- /dev/null
+++ b/src/proc/engine/tracking-heap-block-provider.cpp
@@ -0,0 +1,113 @@
+/*
+  TrackingHeapBlockProvider  -  plain heap allocating BufferProvider implementation for tests
+
+  Copyright (C)         Lumiera.org
+    2011,               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.
+
+* *****************************************************/
+
+
+#include "lib/error.hpp"
+#include "include/logging.h"
+//#include "lib/meta/function.hpp"
+#include "lib/scoped-ptrvect.hpp"
+
+#include "proc/engine/tracking-heap-block-provider.hpp"
+
+#include 
+//#include 
+
+using lib::ScopedPtrVect;
+
+
+
+namespace engine {
+  
+  
+  
+    
+    
+  namespace { // Details of allocation and accounting
+    
+    const uint MAX_BUFFERS = 50;
+  
+  } // (END) Details of allocation and accounting
+  
+  
+  
+  /**
+   * @internal create a memory tracking BufferProvider,
+   */
+  TrackingHeapBlockProvider::TrackingHeapBlockProvider()
+    : BufferProvider ("Diagnostic_HeapAllocated")
+    { }
+  
+  TrackingHeapBlockProvider::~TrackingHeapBlockProvider()
+    {
+      INFO (proc_mem, "discarding %zu diagnostic buffer entries", TrackingHeapBlockProvider::size());
+    }
+  
+  
+  /* ==== Implementation of the BufferProvider interface ==== */
+  
+  uint
+  TrackingHeapBlockProvider::announce (uint count, BufferDescriptor const& type)
+  {
+    UNIMPLEMENTED ("pre-register storage for buffers of a specific kind");   
+  }
+
+  
+  BuffHandle
+  TrackingHeapBlockProvider::lockBufferFor (BufferDescriptor const& descriptor)
+  {
+    UNIMPLEMENTED ("lock buffer for exclusive use");
+  }
+  
+  
+  void
+  TrackingHeapBlockProvider::releaseBuffer (BuffHandle const& handle)
+  {
+    UNIMPLEMENTED ("release a buffer and invalidate the handle");
+  }
+  
+  
+  
+  /* ==== Implementation details ==== */
+  
+  diagn::Block&
+  TrackingHeapBlockProvider::access_or_create (uint bufferID)
+  {
+    while (!withinStorageSize (bufferID))
+      this->manage (new diagn::Block);
+    
+    ENSURE (withinStorageSize (bufferID));
+    return (*this)[bufferID];
+  }
+  
+  bool
+  TrackingHeapBlockProvider::withinStorageSize (uint bufferID)  const
+  {
+    if (bufferID >= MAX_BUFFERS)
+      throw error::Fatal ("hardwired internal limit for test buffers exceeded");
+    
+    return bufferID < this->size();
+  }
+  
+  
+  
+  
+} // namespace engine
diff --git a/src/proc/engine/tracking-heap-block-provider.hpp b/src/proc/engine/tracking-heap-block-provider.hpp
new file mode 100644
index 000000000..af4f5d662
--- /dev/null
+++ b/src/proc/engine/tracking-heap-block-provider.hpp
@@ -0,0 +1,137 @@
+/*
+  TRACKING-HEAP-BLOCK-PROVIDER.hpp  -  plain heap allocating BufferProvider implementation for tests
+
+  Copyright (C)         Lumiera.org
+    2011,               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 tracking-heap-block-provider.hpp
+ ** Dummy implementation of the BufferProvider interface to support writing unit tests.
+ ** This BufferProvider is especially straight forward and brain dead: it just claims
+ ** more and more heap blocks and never releases any memory dynamically. This allows
+ ** to investigate additional tracking status flags for each allocated block after
+ ** the fact.
+ ** 
+ ** The allocated buffers are numbered with a simple ascending sequence of integers,
+ ** used as LocalKey (see BufferMetadata). Clients can just request a Buffer with the
+ ** given number, causing that block to be allocated. There is a "backdoor", allowing
+ ** to access any allocated block, even if it is considered "released" by the terms
+ ** of the usual lifecycle. Only when the provider object itself gets destroyed,
+ ** all allocated blocks will be discarded.
+ ** 
+ ** @see DiagnosticOutputSlot
+ ** @see DiagnosticBufferProvider
+ ** @see buffer-provider-protocol-test.cpp
+ */
+
+#ifndef PROC_ENGINE_TRACKING_HEAP_BLOCK_PROVIDER_H
+#define PROC_ENGINE_TRACKING_HEAP_BLOCK_PROVIDER_H
+
+
+#include "lib/error.hpp"
+#include "proc/engine/buffer-provider.hpp"
+#include "lib/scoped-ptrvect.hpp"
+
+#include 
+#include 
+
+
+namespace engine {
+  
+  namespace error = lumiera::error;
+  
+  
+  namespace diagn {
+    
+    using boost::scoped_array;
+
+    
+    /**
+     * Helper for a diagnostic BufferProvider:
+     * A block of heap allocated storage, with the capability
+     * to store some additional tracking information.
+     */
+    class Block
+      : boost::noncopyable
+      {
+        size_t size_;
+        scoped_array storage_;
+        
+        bool was_locked_;
+        
+      public:
+        Block()
+          : size_(0)
+          , storage_()
+          , was_locked_(false)
+          { }
+        
+        bool
+        was_used()  const
+          {
+            return was_locked_;
+          }
+        
+        bool
+        was_closed()  const
+          {
+            return was_locked_;
+          }
+        
+        void*
+        accessMemory()  const
+          {
+            return storage_.get();
+          }
+      };
+  }
+  
+  /**
+   * simple BufferProvider implementation with additional allocation tracking.
+   * @internal used as PImpl by DiagnosticBufferProvider and DiagnosticOutputSlot.
+   * 
+   * This dummy implementation of the BufferProvider interface uses a linearly growing
+   * table of heap allocated buffer blocks, which will never be discarded, unless the object
+   * is discarded as a whole. There is an additional testing/diagnostics API to access the
+   * tracked usage information, even when blocks are already marked as "released".
+   */
+  class TrackingHeapBlockProvider
+    : public BufferProvider
+    , public lib::ScopedPtrVect
+    {
+      
+      virtual uint announce (uint count, BufferDescriptor const& type);
+      virtual BuffHandle lockBufferFor (BufferDescriptor const& descriptor);
+      virtual void releaseBuffer (BuffHandle const& handle);
+      
+    public:
+      TrackingHeapBlockProvider();
+      virtual ~TrackingHeapBlockProvider();
+      
+      diagn::Block& access_or_create (uint bufferID);
+      
+    private:
+      bool withinStorageSize (uint bufferID)  const;
+    };
+  
+  
+  
+  
+  
+} // namespace engine
+#endif
diff --git a/src/proc/play/output-slot-connection.hpp b/src/proc/play/output-slot-connection.hpp
index c19080ed4..570ca3ebf 100644
--- a/src/proc/play/output-slot-connection.hpp
+++ b/src/proc/play/output-slot-connection.hpp
@@ -73,7 +73,26 @@ namespace play {
   
   
   
-  /** established output channel */
+  /** @internal represents the \em active
+   *   point in each of the per-channel connections
+   *   used when this OutputSlot is operational.
+   *   
+   * \par OutputSlot Core API
+   *   
+   * Actually, this extension point towards the implementation
+   * of the actual output handling carries the core API of OutputSlot.
+   * Thus, the task of actually implementing an OutputSlot boils down
+   * to implementing this interface and providing a ConnectionState.
+   * - \c lock() announces this FrameID and the corresponding buffer
+   *   to be in exclusive use by the client from now on
+   * - \c transfer() ends the client sided processing and initiates
+   *   the outputting of the data found in the corresponding buffer.
+   * - \c pushout() actually pushes the denoted buffer to the output.
+   *   Typically, \c pushout() is called from the \c transfer()
+   *   implementation; yet it may as well be called from a separate
+   *   service thread or some kind of callback.
+   * @note the meaning of FrameID is implementation defined.
+   */
   class OutputSlot::Connection
     {
     public:
@@ -86,7 +105,13 @@ namespace play {
       
       
   
-  
+  /** 
+   * Extension point for Implementation.
+   * The ConnectionState is where the concrete output
+   * handling implementation is expected to reside.
+   * OutputSlot is a frontend and accesses
+   * ConnectionState in the way of a PImpl.
+   */
   class OutputSlot::ConnectionState
     : public OutputSlot::Allocation
     , boost::noncopyable
@@ -96,12 +121,28 @@ namespace play {
     };
   
   
+  /** 
+   * Base class for the typical implementation approach.
+   * Using this class is \em not mandatory. But obviously,
+   * we'd get to manage a selection of Connection objects
+   * representing the "active points" in several media channels
+   * connected through this OutputSlot. These Connection subclasses
+   * are what is referenced by the DataSink smart-ptrs handed out
+   * to the client code. As ConnectionState implements the Allocation
+   * API, it has the liability to create these DataSink smart-ptrs,
+   * which means to wire them appropriately and also provide an
+   * deleter function (here #shutdownConnection) to be invoked
+   * when the last copy of the smart-handle goes out of scope.
+   * 
+   * The typical standard/base implementation provided here
+   * manages a collection of active Connection subclass objects.
+   */
   template
   class ConnectionStateManager
     : public OutputSlot::ConnectionState
     , public vector
     {
-
+      
       typedef OutputSlot::OpenedSinks OpenedSinks;
       
       
@@ -126,7 +167,7 @@ namespace play {
         {
           UNIMPLEMENTED ("immediately build up the necessary number of connections");
         }
-
+     
      virtual
     ~ConnectionStateManager()
         {

From c8458ab39728eda235086cb35f3e0ba4281ee084 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Mon, 7 Nov 2011 00:50:03 +0100
Subject: [PATCH 39/68] improved diagnostics

---
 src/include/logging.h               |  3 +++
 src/lib/error.hpp                   | 21 +++++++++++++++++++++
 src/proc/engine/buffer-metadata.hpp | 14 +-------------
 3 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/src/include/logging.h b/src/include/logging.h
index e2b9455ea..6fd024b97 100644
--- a/src/include/logging.h
+++ b/src/include/logging.h
@@ -90,6 +90,9 @@ NOBUG_CPP_DEFINE_FLAG_PARENT    (   fileheader_dbg,             backend_dbg);
 /** base of debug logging for the proc layer */
 NOBUG_CPP_DEFINE_FLAG_PARENT    (  proc_dbg,                    debugging);
 NOBUG_CPP_DEFINE_FLAG_PARENT    (   command_dbg,                proc_dbg);
+NOBUG_CPP_DEFINE_FLAG_PARENT    (   session_dbg,                proc_dbg);
+NOBUG_CPP_DEFINE_FLAG_PARENT    (   player_dbg,                 proc_dbg);
+NOBUG_CPP_DEFINE_FLAG_PARENT    (   engine_dbg,                 proc_dbg);
 /** base of debug logging for the gui */
 NOBUG_CPP_DEFINE_FLAG_PARENT    (  gui_dbg,                     debugging);
 /** base if debug logging for the support library */
diff --git a/src/lib/error.hpp b/src/lib/error.hpp
index 5e2427e0a..110ffe61b 100644
--- a/src/lib/error.hpp
+++ b/src/lib/error.hpp
@@ -215,6 +215,27 @@ namespace lumiera {
   
 } // namespace lumiera
 
+/******************************************************
+ * convenience shortcut for a sequence of catch blocks
+ * just logging and consuming an error. Typically
+ * this sequence will be used within destructors,
+ * which, by convention, must not throw
+ */
+#define ERROR_LOG_AND_IGNORE(_FLAG_,_OP_DESCR_) \
+  catch (std::exception& problem)                \
+    {                                             \
+      const char* errID = lumiera_error();         \
+      WARN (_FLAG_, "%s failed: %s", _OP_DESCR_, problem.what()); \
+      TRACE (debugging, "Error flag was: %s", errID);\
+    }                                                 \
+  catch (...)                                          \
+    {                                                   \
+      const char* errID = lumiera_error();               \
+      ERROR (_FLAG_, "%s failed with unknown exception; " \
+                     "error flag is: %s"                   \
+                   , _OP_DESCR_, errID);                    \
+    }
+
 
 
 /******************************************************
diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp
index 9a73ba20a..57420fe7f 100644
--- a/src/proc/engine/buffer-metadata.hpp
+++ b/src/proc/engine/buffer-metadata.hpp
@@ -635,19 +635,7 @@ namespace engine {
             {
               for_each (entries_, verify_is_free);
             }
-          catch (std::exception& problem)
-            {
-              const char* errID = lumiera_error();
-              const char* operation = "Shutdown of BufferProvider metadata store";
-              WARN (engine, "%s failed: %s", operation, problem.what());
-              TRACE (debugging, "Error flag was: %s", errID);
-            }
-          catch (...)
-            {
-              const char* errID = lumiera_error();
-              const char* operation = "Shutdown of BufferProvider metadata store";
-              ERROR (engine, "%s failed with unknown exception; error flag is: %s", operation, errID);
-            }
+          ERROR_LOG_AND_IGNORE (engine,"Shutdown of BufferProvider metadata store")
           
         static void
         verify_is_free (std::pair const& e)

From 59dfb7c660d693b78a20dd025f1b83af28f8f70d Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Mon, 7 Nov 2011 01:57:33 +0100
Subject: [PATCH 40/68] start drafting a (dummy) output slot implementation

this implicates a first attempt to build a
dummy buffer provider implementation.
Mostly just defining stubs here....
---
 src/proc/play/output-slot-connection.hpp      |  7 +-
 .../proc/play/diagnostic-output-slot.hpp      | 81 ++++++++++++++++++-
 2 files changed, 82 insertions(+), 6 deletions(-)

diff --git a/src/proc/play/output-slot-connection.hpp b/src/proc/play/output-slot-connection.hpp
index 570ca3ebf..93efd8ca9 100644
--- a/src/proc/play/output-slot-connection.hpp
+++ b/src/proc/play/output-slot-connection.hpp
@@ -181,7 +181,7 @@ namespace play {
       
     private: // Implementation details
       
-      DataSink
+      static DataSink
       connectOutputSink (CON& connection)
         {
           DataSink newSink;
@@ -189,9 +189,10 @@ namespace play {
           return newSink;
         }
       
-      void
-      shutdownConnection (CON* toClose)
+      static void
+      shutdownConnection (void* toClose)
         {
+          ///////////////////////////////////////////////////////////TODO problem: is it possible to pass the concrete type????
           UNIMPLEMENTED ("how to mark a connection as closed");
         }
     };
diff --git a/tests/components/proc/play/diagnostic-output-slot.hpp b/tests/components/proc/play/diagnostic-output-slot.hpp
index ffd1ce829..39105874c 100644
--- a/tests/components/proc/play/diagnostic-output-slot.hpp
+++ b/tests/components/proc/play/diagnostic-output-slot.hpp
@@ -32,15 +32,19 @@
 
 
 #include "lib/error.hpp"
+#include "include/logging.h"
 #include "proc/play/output-slot.hpp"
+#include "proc/play/output-slot-connection.hpp"
+#include "proc/engine/buffhandle.hpp"
+#include "proc/engine/tracking-heap-block-provider.hpp"
 #include "lib/iter-source.hpp"  ////////////TODO really going down that path...?
 #include "proc/engine/testframe.hpp"
 //#include "lib/sync.hpp"
 
-//#include 
+#include 
 //#include 
 //#include 
-//#include 
+#include 
 //#include 
 
 
@@ -48,14 +52,77 @@ namespace proc {
 namespace play {
 
 //using std::string;
+  using ::engine::BufferDescriptor;
   using ::engine::test::TestFrame;
+  using ::engine::TrackingHeapBlockProvider;
 
 //using std::vector;
-//using std::tr1::shared_ptr;
+  using std::tr1::shared_ptr;
 //using boost::scoped_ptr;
   
   
   
+  class TrackingInMemoryBlockSequence
+    : public OutputSlot::Connection
+    {
+      
+      shared_ptr buffProvider_;
+      BufferDescriptor bufferType_;
+      
+      
+      /* === Connection API === */
+      
+      void
+      lock (FrameID)
+        {
+          buffProvider_->lockBufferFor (bufferType_);
+          /////////////////////////////////////////////////TODO: should return that
+        }
+      
+      void
+      transfer (FrameID frameNr)
+        {
+          pushout (frameNr);
+        }
+      
+      void
+      pushout (FrameID)
+        {
+          UNIMPLEMENTED ("simulate output");
+        }
+      
+      
+    public:
+      TrackingInMemoryBlockSequence()
+        : buffProvider_(new TrackingHeapBlockProvider())
+        , bufferType_(buffProvider_->getDescriptor())
+        {
+          INFO (engine_dbg, "building in-memory diagnostic output sequence");
+        }
+      
+      virtual
+     ~TrackingInMemoryBlockSequence()
+        {
+          INFO (engine_dbg, "releasing diagnostic output sequence");
+        }
+    };
+  
+  
+  class SimulatedOutputSequences
+    : public ConnectionStateManager
+    , boost::noncopyable
+    {
+      TrackingInMemoryBlockSequence
+      buildConnection()
+        {
+          return TrackingInMemoryBlockSequence();
+        }
+    };
+  
+    
+    
+    
+  
   /********************************************************************
    * Helper for unit tests: Mock output sink.
    * 
@@ -64,6 +131,14 @@ namespace play {
   class DiagnosticOutputSlot
     : public OutputSlot
     {
+      /* === hook into the OutputSlot frontend === */
+      ConnectionState*
+      buildState()
+        {
+          return new SimulatedOutputSequences();
+        }
+        
+      
     public:
       /** build a new Diagnostic Output Slot instance,
        *  discard the existing one. Use the static query API

From f75e55a0607b342e146c6a47b57b5fde4505ce13 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Tue, 8 Nov 2011 02:59:56 +0100
Subject: [PATCH 41/68] nail down a lot of OutputSlot implementation details

---
 src/proc/engine/buffer-provider.hpp           |  1 +
 .../engine/tracking-heap-block-provider.cpp   |  9 +++-
 .../engine/tracking-heap-block-provider.hpp   |  1 +
 src/proc/play/output-slot-connection.hpp      | 44 ++++++++++-------
 src/proc/play/output-slot.cpp                 | 24 ++++++++++
 src/proc/play/output-slot.hpp                 |  6 +--
 .../proc/play/diagnostic-output-slot.hpp      | 47 +++++++++++++++----
 .../proc/play/output-slot-protocol-test.cpp   |  6 +--
 8 files changed, 105 insertions(+), 33 deletions(-)

diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp
index 97712c712..ba4a4dd7f 100644
--- a/src/proc/engine/buffer-provider.hpp
+++ b/src/proc/engine/buffer-provider.hpp
@@ -83,6 +83,7 @@ namespace engine {
       virtual uint announce (uint count, BufferDescriptor const&) =0;
       
       virtual BuffHandle lockBufferFor (BufferDescriptor const&)  =0;
+      virtual void mark_emitted  (BuffHandle const&)              =0;
       virtual void releaseBuffer (BuffHandle const&)              =0;
       
       template
diff --git a/src/proc/engine/tracking-heap-block-provider.cpp b/src/proc/engine/tracking-heap-block-provider.cpp
index 947acc614..7fcd6ade4 100644
--- a/src/proc/engine/tracking-heap-block-provider.cpp
+++ b/src/proc/engine/tracking-heap-block-provider.cpp
@@ -78,10 +78,17 @@ namespace engine {
   }
   
   
+  void
+  TrackingHeapBlockProvider::mark_emitted (BuffHandle const& handle)
+  {
+    UNIMPLEMENTED ("commit a buffer to the protocol section");
+  }
+  
+  
   void
   TrackingHeapBlockProvider::releaseBuffer (BuffHandle const& handle)
   {
-    UNIMPLEMENTED ("release a buffer and invalidate the handle");
+    UNIMPLEMENTED ("mark a buffer as officially discarded");
   }
   
   
diff --git a/src/proc/engine/tracking-heap-block-provider.hpp b/src/proc/engine/tracking-heap-block-provider.hpp
index af4f5d662..decdc5915 100644
--- a/src/proc/engine/tracking-heap-block-provider.hpp
+++ b/src/proc/engine/tracking-heap-block-provider.hpp
@@ -117,6 +117,7 @@ namespace engine {
       
       virtual uint announce (uint count, BufferDescriptor const& type);
       virtual BuffHandle lockBufferFor (BufferDescriptor const& descriptor);
+      virtual void mark_emitted  (BuffHandle const& handle);
       virtual void releaseBuffer (BuffHandle const& handle);
       
     public:
diff --git a/src/proc/play/output-slot-connection.hpp b/src/proc/play/output-slot-connection.hpp
index 93efd8ca9..34a574d9d 100644
--- a/src/proc/play/output-slot-connection.hpp
+++ b/src/proc/play/output-slot-connection.hpp
@@ -59,7 +59,7 @@
 namespace proc {
 namespace play {
 
-//using ::engine::BuffHandle;
+  using ::engine::BuffHandle;
 //using ::engine::BufferProvider;
 //using lib::time::Time;
 //using std::string;
@@ -98,9 +98,12 @@ namespace play {
     public:
       virtual ~Connection();
       
-      virtual void lock     (FrameID)   =0;
-      virtual void transfer (FrameID)   =0;
-      virtual void pushout  (FrameID)   =0;
+      virtual BuffHandle claimBufferFor(FrameID)  =0;
+      virtual bool isTimely (FrameID, TimeValue)  =0;
+      virtual void transfer (BuffHandle const&)   =0;
+      virtual void pushout  (BuffHandle const&)   =0;
+      virtual void discard  (BuffHandle const&)   =0;
+      virtual void shutDown ()                    =0;
     };
       
       
@@ -164,19 +167,24 @@ namespace play {
       
     public:
       ConnectionStateManager()
-        {
-          UNIMPLEMENTED ("immediately build up the necessary number of connections");
-        }
-     
-     virtual
-    ~ConnectionStateManager()
-        {
-          UNIMPLEMENTED ("shut down all connections");
-        }
+        { }
       
       virtual
-      CON
-      buildConnection()  =0;
+     ~ConnectionStateManager()
+        { }
+      
+      
+      void
+      init (uint numChannels)
+        {
+          for (uint i=0; ishutDown();
         }
     };
   
diff --git a/src/proc/play/output-slot.cpp b/src/proc/play/output-slot.cpp
index 6cd3c5aa4..e93acb278 100644
--- a/src/proc/play/output-slot.cpp
+++ b/src/proc/play/output-slot.cpp
@@ -51,6 +51,8 @@ namespace play {
   
   OutputSlot::Allocation::~Allocation() { }
   
+  OutputSlot::Connection::~Connection() { }
+  
   
   
   
@@ -86,6 +88,28 @@ namespace play {
     if (!isFree())
       state_.reset(0);    
   }
+  
+  
+  
+  /* === DataSink frontend === */
+  
+  BuffHandle
+  DataSink::lockBufferFor(FrameID frameNr)
+  {
+    return impl().claimBufferFor(frameNr);
+  }
+  
+  
+  void
+  DataSink::emit (FrameID frameNr, BuffHandle const& data2emit, TimeValue currentTime)
+  {
+    OutputSlot::Connection& connection = impl();
+    if (connection.isTimely(frameNr,currentTime))
+      connection.transfer(data2emit);
+    else
+      connection.discard(data2emit);
+  }
+  
 
   
   
diff --git a/src/proc/play/output-slot.hpp b/src/proc/play/output-slot.hpp
index 04754e4bd..bd51a03b9 100644
--- a/src/proc/play/output-slot.hpp
+++ b/src/proc/play/output-slot.hpp
@@ -38,7 +38,7 @@
 
 #include "lib/error.hpp"
 #include "lib/handle.hpp"
-//#include "lib/time/timevalue.hpp"
+#include "lib/time/timevalue.hpp"
 #include "proc/engine/buffer-provider.hpp"
 #include "proc/play/timings.hpp"
 #include "lib/iter-source.hpp"
@@ -56,7 +56,7 @@ namespace play {
 
   using ::engine::BuffHandle;
   using ::engine::BufferProvider;
-//using lib::time::Time;
+  using lib::time::TimeValue;
 //using std::string;
 
 //using std::vector;
@@ -132,7 +132,7 @@ namespace play {
       
     public:
       BuffHandle lockBufferFor(FrameID);
-      void emit(FrameID);
+      void emit(FrameID, BuffHandle const&, TimeValue currentTime = Time::MAX);    ///////////////TICKET #855 
     };
   
   
diff --git a/tests/components/proc/play/diagnostic-output-slot.hpp b/tests/components/proc/play/diagnostic-output-slot.hpp
index 39105874c..ff0c96486 100644
--- a/tests/components/proc/play/diagnostic-output-slot.hpp
+++ b/tests/components/proc/play/diagnostic-output-slot.hpp
@@ -72,25 +72,47 @@ namespace play {
       
       /* === Connection API === */
       
-      void
-      lock (FrameID)
+      BuffHandle
+      claimBufferFor(FrameID frameNr) 
         {
           buffProvider_->lockBufferFor (bufferType_);
-          /////////////////////////////////////////////////TODO: should return that
+        }
+      
+      
+      bool
+      isTimely (FrameID frameNr, TimeValue currentTime)
+        {
+          if (Time::MAX == currentTime)
+            return true;
+          
+          UNIMPLEMENTED ("find out about timings");
+          return false;
         }
       
       void
-      transfer (FrameID frameNr)
+      transfer (BuffHandle const& filledBuffer)
         {
-          pushout (frameNr);
+          pushout (filledBuffer);
         }
       
       void
-      pushout (FrameID)
+      pushout (BuffHandle const& data4output)
         {
-          UNIMPLEMENTED ("simulate output");
+          buffProvider_->mark_emitted  (data4output);
+          buffProvider_->releaseBuffer (data4output);
         }
       
+      void
+      discard (BuffHandle const& superseededData)
+        {
+          buffProvider_->releaseBuffer (superseededData);
+        }
+      
+      void
+      shutDown ()
+        {
+          buffProvider_.reset();
+        }
       
     public:
       TrackingInMemoryBlockSequence()
@@ -117,6 +139,12 @@ namespace play {
         {
           return TrackingInMemoryBlockSequence();
         }
+      
+    public:
+      SimulatedOutputSequences (uint numChannels)
+        {
+          init (numChannels);
+        }
     };
   
     
@@ -131,11 +159,14 @@ namespace play {
   class DiagnosticOutputSlot
     : public OutputSlot
     {
+      
+      static const uint MAX_CHANNELS = 5;
+        
       /* === hook into the OutputSlot frontend === */
       ConnectionState*
       buildState()
         {
-          return new SimulatedOutputSequences();
+          return new SimulatedOutputSequences(MAX_CHANNELS);
         }
         
       
diff --git a/tests/components/proc/play/output-slot-protocol-test.cpp b/tests/components/proc/play/output-slot-protocol-test.cpp
index 29b1db615..ae0319b6d 100644
--- a/tests/components/proc/play/output-slot-protocol-test.cpp
+++ b/tests/components/proc/play/output-slot-protocol-test.cpp
@@ -106,9 +106,9 @@ namespace test  {
           buff10.accessAs() = testData(1,0);
           
           // Now it's time to emit the output
-          sink2.emit (frameNr-1);
-          sink2.emit (frameNr  );
-          sink1.emit (frameNr-1);
+          sink2.emit (frameNr-1, buff10);
+          sink2.emit (frameNr  , buff11);
+          sink1.emit (frameNr-1, buff00);
           // that's all for the client
           
           // Verify sane operation....

From fe1ae51b494caf81c4673fb7c32940185037e32d Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 11 Nov 2011 01:44:01 +0100
Subject: [PATCH 42/68] WIP draft test for internal test buffer provider

a test to cover a helper for writing tests ;-)
---
 src/proc/engine/buffer-provider.hpp           |   2 +-
 tests/46engine.tests                          |   5 +
 .../tracking-heap-block-provider-test.cpp     | 202 ++++++++++++++++++
 3 files changed, 208 insertions(+), 1 deletion(-)
 create mode 100644 tests/components/proc/engine/tracking-heap-block-provider-test.cpp

diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp
index ba4a4dd7f..368d54a4c 100644
--- a/src/proc/engine/buffer-provider.hpp
+++ b/src/proc/engine/buffer-provider.hpp
@@ -95,7 +95,7 @@ namespace engine {
       
       template
       BufferDescriptor getDescriptor();
-
+      
       
       
       /* === API for BuffHandle internal access === */
diff --git a/tests/46engine.tests b/tests/46engine.tests
index 46c1806db..07fac0119 100644
--- a/tests/46engine.tests
+++ b/tests/46engine.tests
@@ -7,6 +7,11 @@ return: 0
 END
 
 
+TEST "Test support: dummy buffer provider" TrackingHeapBlockProvider_test <
+
+  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.
+
+* *****************************************************/
+
+
+#include "lib/error.hpp"
+#include "lib/test/run.hpp"
+//#include "lib/test/test-helper.hpp"
+//#include "lib/util-foreach.hpp"
+//#include "proc/play/diagnostic-output-slot.hpp"
+#include "proc/engine/tracking-heap-block-provider.hpp"
+#include "proc/engine/testframe.hpp"
+//#include "proc/engine/diagnostic-buffer-provider.hpp"
+#include "proc/engine/buffhandle.hpp"
+//#include "proc/engine/bufftable.hpp"
+
+//#include 
+//#include 
+#include 
+#include 
+
+//using boost::format;
+//using std::string;
+//using std::cout;
+using std::rand;
+//using util::for_each;
+
+
+namespace engine{
+namespace test  {
+  
+//  using lib::AllocationCluster;
+//  using mobject::session::PEffect;
+//  using ::engine::BuffHandle;
+//  using lumiera::error::LUMIERA_ERROR_LIFECYCLE;
+  
+  
+  namespace { // Test fixture
+    
+    const size_t TEST_ELM_SIZE = sizeof(uint);
+    const uint   MAX_ELMS = 50;
+    
+    std::vector testNumbers(MAX_ELMS);
+    
+    
+    bool 
+    has_expectedContent (uint nr, diagn::Block& memoryBlock) 
+    {
+      void* mem = memoryBlock.accessMemory();
+      uint data = *static_cast (mem);
+      
+      return data == testNumbers[nr];
+    }
+    
+    bool
+    verifyUsedBlock (uint nr, diagn::Block& memoryBlock) 
+    {
+      return memoryBlock.was_closed()
+          && has_expectedContent (nr, memoryBlock);
+    }
+  }
+  
+  
+  /**********************************************************************
+   * @test verify a test support facility, used to write mock components
+   *       to test the lumiera engine. The TrackingHeapBlockProvider is a
+   *       braindead implementation of the BufferProvider interface: it just
+   *       claims new heap blocks and never de-allocates them, allowing other
+   *       test and mock objects to verify allocated buffers after the fact.
+   */
+  class TrackingHeapBlockProvider_test : public Test
+    {
+      virtual void
+      run (Arg) 
+        {
+          UNIMPLEMENTED ("verify test helper");
+          simpleExample();
+          verifyStandardCase();
+          verifyTestProtocol();
+        }
+      
+      
+      void
+      simpleExample()
+        {
+          TrackingHeapBlockProvider provider;
+          
+          BuffHandle testBuff = provider.lockBufferFor();
+          CHECK (testBuff);
+          CHECK (testBuff.accessAs().isSane());
+          
+          uint dataID = 1 + rand() % 29;
+          testBuff.accessAs() = testData(dataID);
+          
+          provider.mark_emitted (testBuff);
+          provider.releaseBuffer(testBuff);
+          
+          diagn::Block& block0 = provider.access_or_create(0);
+          CHECK (block0.was_used());
+          CHECK (block0.was_closed());
+          
+          CHECK (testData(dataID) == block0.accessMemory());
+        }
+      
+      
+      void
+      verifyStandardCase()
+        {
+          TrackingHeapBlockProvider provider;
+          
+          BufferDescriptor buffType = provider.getDescriptorFor(TEST_ELM_SIZE);
+          uint numElms = provider.announce(MAX_ELMS, buffType);
+          CHECK (0 < numElms);
+          CHECK (numElms <= MAX_ELMS);
+          
+          for (uint i=0; i() = testNumbers[i] = rand() % 100000;
+              provider.mark_emitted (buff);
+              provider.releaseBuffer(buff);
+            }
+          
+          for (uint nr=0; nr(0) = 20;
+          provider.access(1) = 21;
+          provider.access(2) = 22;
+          provider.access(3) = 23;
+          provider.access(4) = 24;
+          
+          bu1.accessAs() = 1;
+          bu2.accessAs() = 2;
+          bu3.accessAs() = 3;
+          bu4.accessAs() = 4;
+          bu5.accessAs() = 5;
+          
+          CHECK (20 == provider.access(0));
+          CHECK (21 == provider.access(1));
+          CHECK (22 == provider.access(2));
+          CHECK (23 == provider.access(3));
+          CHECK (24 == provider.access(4));
+          
+          provider.mark_emitted (bu3);
+          provider.mark_emitted (bu1);
+          provider.mark_emitted (bu5);
+          provider.mark_emitted (bu4);
+          provider.mark_emitted (bu2);
+          
+          CHECK (3 == provider.access(0));
+          CHECK (1 == provider.access(1));
+          CHECK (5 == provider.access(2));
+          CHECK (4 == provider.access(3));
+          CHECK (2 == provider.access(4));
+        }
+    };
+  
+  
+  /** Register this test class... */
+  LAUNCHER (TrackingHeapBlockProvider_test, "unit player");
+  
+  
+  
+}} // namespace engine::test

From fd94367b9e6a1751972d50412e2c10684aa0260d Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 11 Nov 2011 23:33:59 +0100
Subject: [PATCH 43/68] stubs and changes to make the test compile

---
 .../engine/tracking-heap-block-provider.hpp   | 33 +++++++++++++++++
 .../tracking-heap-block-provider-test.cpp     | 37 +++++++++----------
 .../proc/play/diagnostic-output-slot.hpp      |  2 +-
 3 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/src/proc/engine/tracking-heap-block-provider.hpp b/src/proc/engine/tracking-heap-block-provider.hpp
index decdc5915..a7065252a 100644
--- a/src/proc/engine/tracking-heap-block-provider.hpp
+++ b/src/proc/engine/tracking-heap-block-provider.hpp
@@ -46,6 +46,7 @@
 #include "lib/error.hpp"
 #include "proc/engine/buffer-provider.hpp"
 #include "lib/scoped-ptrvect.hpp"
+#include "lib/access-casted.hpp"
 
 #include 
 #include 
@@ -115,6 +116,10 @@ namespace engine {
     , public lib::ScopedPtrVect
     {
       
+    public:
+      /* === BufferProvider interface === */
+      
+      using BufferProvider::lockBufferFor;
       virtual uint announce (uint count, BufferDescriptor const& type);
       virtual BuffHandle lockBufferFor (BufferDescriptor const& descriptor);
       virtual void mark_emitted  (BuffHandle const& handle);
@@ -126,12 +131,40 @@ namespace engine {
       
       diagn::Block& access_or_create (uint bufferID);
       
+      template
+      TY&  accessAs (uint bufferID);
+      
     private:
       bool withinStorageSize (uint bufferID)  const;
     };
   
   
   
+  /** convenience shortcut: access the buffer with the given number,
+   *  then try to convert the raw memory to the templated type.
+   * @throw error::Invalid if the required fame number is beyond
+   *        the number of buffers marked as "emitted"
+   * @throw error::Fatal if conversion is not possible or the
+   *        conversion path chosen doesn't work (which might
+   *        be due to RTTI indicating an incompatible type).
+   */
+  template
+  TY&
+  TrackingHeapBlockProvider::accessAs (uint bufferID)
+  {
+    if (!withinStorageSize (bufferID))
+      throw error::Invalid ("Buffer with the given ID not yet emitted");
+    
+    diagn::Block& memoryBlock = access_or_create (bufferID);
+    TY* converted = util::AccessCasted::access (memoryBlock.accessMemory());
+    
+    if (!converted)
+      throw error::Fatal ("unable to access the target location with the required conversion");
+    else
+      return *converted;
+  }
+  
+  
   
   
 } // namespace engine
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 48b385085..47fd1bcd4 100644
--- a/tests/components/proc/engine/tracking-heap-block-provider-test.cpp
+++ b/tests/components/proc/engine/tracking-heap-block-provider-test.cpp
@@ -73,7 +73,8 @@ namespace test  {
     bool
     verifyUsedBlock (uint nr, diagn::Block& memoryBlock) 
     {
-      return memoryBlock.was_closed()
+      return memoryBlock.was_used()
+          && memoryBlock.was_closed()
           && has_expectedContent (nr, memoryBlock);
     }
   }
@@ -91,7 +92,6 @@ namespace test  {
       virtual void
       run (Arg) 
         {
-          UNIMPLEMENTED ("verify test helper");
           simpleExample();
           verifyStandardCase();
           verifyTestProtocol();
@@ -114,9 +114,6 @@ namespace test  {
           provider.releaseBuffer(testBuff);
           
           diagn::Block& block0 = provider.access_or_create(0);
-          CHECK (block0.was_used());
-          CHECK (block0.was_closed());
-          
           CHECK (testData(dataID) == block0.accessMemory());
         }
       
@@ -161,11 +158,11 @@ namespace test  {
           
           CHECK (5 == provider.size());
           
-          provider.access(0) = 20;
-          provider.access(1) = 21;
-          provider.access(2) = 22;
-          provider.access(3) = 23;
-          provider.access(4) = 24;
+          provider.accessAs(0) = 20;
+          provider.accessAs(1) = 21;
+          provider.accessAs(2) = 22;
+          provider.accessAs(3) = 23;
+          provider.accessAs(4) = 24;
           
           bu1.accessAs() = 1;
           bu2.accessAs() = 2;
@@ -173,11 +170,11 @@ namespace test  {
           bu4.accessAs() = 4;
           bu5.accessAs() = 5;
           
-          CHECK (20 == provider.access(0));
-          CHECK (21 == provider.access(1));
-          CHECK (22 == provider.access(2));
-          CHECK (23 == provider.access(3));
-          CHECK (24 == provider.access(4));
+          CHECK (20 == provider.accessAs(0));
+          CHECK (21 == provider.accessAs(1));
+          CHECK (22 == provider.accessAs(2));
+          CHECK (23 == provider.accessAs(3));
+          CHECK (24 == provider.accessAs(4));
           
           provider.mark_emitted (bu3);
           provider.mark_emitted (bu1);
@@ -185,11 +182,11 @@ namespace test  {
           provider.mark_emitted (bu4);
           provider.mark_emitted (bu2);
           
-          CHECK (3 == provider.access(0));
-          CHECK (1 == provider.access(1));
-          CHECK (5 == provider.access(2));
-          CHECK (4 == provider.access(3));
-          CHECK (2 == provider.access(4));
+          CHECK (3 == provider.accessAs(0));
+          CHECK (1 == provider.accessAs(1));
+          CHECK (5 == provider.accessAs(2));
+          CHECK (4 == provider.accessAs(3));
+          CHECK (2 == provider.accessAs(4));
         }
     };
   
diff --git a/tests/components/proc/play/diagnostic-output-slot.hpp b/tests/components/proc/play/diagnostic-output-slot.hpp
index ff0c96486..571c1dad0 100644
--- a/tests/components/proc/play/diagnostic-output-slot.hpp
+++ b/tests/components/proc/play/diagnostic-output-slot.hpp
@@ -66,7 +66,7 @@ namespace play {
     : public OutputSlot::Connection
     {
       
-      shared_ptr buffProvider_;
+      shared_ptr buffProvider_;
       BufferDescriptor bufferType_;
       
       

From ca0aa234799940edceaa90ddfdb91b98a528c6cd Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 12 Nov 2011 00:36:53 +0100
Subject: [PATCH 44/68] BufferProvider default impl: attaching a type

---
 src/proc/engine/buffer-metadata.hpp | 118 +-----------------
 src/proc/engine/buffer-provider.cpp |  11 +-
 src/proc/engine/buffer-provider.hpp |  11 +-
 src/proc/engine/type-handler.hpp    | 182 ++++++++++++++++++++++++++++
 4 files changed, 201 insertions(+), 121 deletions(-)
 create mode 100644 src/proc/engine/type-handler.hpp

diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp
index 57420fe7f..b06f01035 100644
--- a/src/proc/engine/buffer-metadata.hpp
+++ b/src/proc/engine/buffer-metadata.hpp
@@ -56,13 +56,11 @@
 
 #include "lib/error.hpp"
 #include "lib/symbol.hpp"
-#include "lib/functor-util.hpp"
 #include "lib/util-foreach.hpp"
 #include "include/logging.h"
+#include "proc/engine/type-handler.hpp"
 
-#include 
 #include 
-#include 
 #include 
 
 
@@ -71,9 +69,6 @@ namespace engine {
   using lib::HashVal;
   using lib::Literal;
   using util::for_each; 
-  using std::tr1::bind;
-  using std::tr1::function;
-  using std::tr1::placeholders::_1;
   
   namespace error = lumiera::error;
   
@@ -138,117 +133,6 @@ namespace engine {
     };
   
   
-  namespace { // (optional) helpers to build an object embedded within the buffer...
-    
-    template
-    inline void
-    buildIntoBuffer (void* storageBuffer)
-    {
-      new(storageBuffer) X();
-    }
-    
-    template
-    inline void
-    buildIntoBuffer_A1 (void* storageBuffer, A1 arg1)
-    {
-      new(storageBuffer) X(arg1);
-    }
-    
-    template
-    inline void
-    destroyInBuffer (void* storageBuffer)
-    {
-      X* embedded = static_cast (storageBuffer);
-      embedded->~X();
-    }
-  }//(End)placement-new helpers
-  
-  
-  
-  /**
-   * A pair of functors to maintain a datastructure within the buffer.
-   * TypeHandler describes how to outfit the buffer in a specific way.
-   * When defined, the buffer will be prepared when locking and cleanup
-   * will be invoked automatically when releasing. Especially, this
-   * can be used to \em attach an object to the buffer (placement-new) 
-   */
-  struct TypeHandler
-    {
-      typedef function DoInBuffer;
-      
-      DoInBuffer createAttached;
-      DoInBuffer destroyAttached;
-      
-      /** build an invalid NIL TypeHandler */
-      TypeHandler()
-        : createAttached()
-        , destroyAttached()
-        { }
-      
-      /** build a TypeHandler
-       *  binding to arbitrary constructor and destructor functions.
-       *  On invocation, these functions get a void* to the buffer.
-       * @note the functor objects created from these operations
-       *       might be shared for handling multiple buffers.
-       *       Be careful with any state or arguments.
-       */
-      template
-      TypeHandler(CTOR ctor, DTOR dtor)
-        : createAttached (ctor)
-        , destroyAttached (dtor)
-        { }
-      
-      /** builder function defining a TypeHandler
-       *  to place a default-constructed object
-       *  into the buffer. */
-      template
-      static TypeHandler
-      create ()
-        {
-          return TypeHandler (buildIntoBuffer, destroyInBuffer);
-        }
-      
-      template
-      static TypeHandler
-      create (A1 a1)
-        {
-          return TypeHandler ( bind (buildIntoBuffer_A1, _1, a1)
-                             , destroyInBuffer);
-        }
-      
-      bool
-      isValid()  const
-        {
-          return bool(createAttached)
-              && bool(destroyAttached);
-        }
-      
-      friend HashVal
-      hash_value (TypeHandler const& handler)
-      {
-        HashVal hash(0);
-        if (handler.isValid())
-          {
-            boost::hash_combine(hash, handler.createAttached);
-            boost::hash_combine(hash, handler.destroyAttached);
-          }
-        return hash;
-      }
-      
-      friend bool
-      operator== (TypeHandler const& left, TypeHandler const& right)
-      {
-        return (!left.isValid() && !right.isValid())
-            || (  util::rawComparison(left.createAttached, right.createAttached)
-               && util::rawComparison(left.destroyAttached, right.destroyAttached)
-               );
-      }
-      friend bool
-      operator!= (TypeHandler const& left, TypeHandler const& right)
-      {
-        return !(left == right);       
-      }
-    };
   
   
   namespace { // internal constants to mark the default case
diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp
index f0d1b337f..ea5e4f5f0 100644
--- a/src/proc/engine/buffer-provider.cpp
+++ b/src/proc/engine/buffer-provider.cpp
@@ -58,8 +58,15 @@ namespace engine {
   {
     return BufferDescriptor (*this, meta_->key (storageSize));
   }
-      
-      
+  
+  
+  BufferDescriptor
+  BufferProvider::getDescriptorFor(size_t storageSize, TypeHandler specialTreatment)
+  {
+    return BufferDescriptor (*this, meta_->key (storageSize, specialTreatment));
+  }
+  
+  
   
   
   /* === BufferDescriptor and BuffHandle === */
diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp
index 368d54a4c..174555acf 100644
--- a/src/proc/engine/buffer-provider.hpp
+++ b/src/proc/engine/buffer-provider.hpp
@@ -45,6 +45,7 @@
 #include "lib/error.hpp"
 #include "lib/symbol.hpp"
 #include "proc/engine/buffhandle.hpp"
+#include "proc/engine/type-handler.hpp"
 
 #include 
 #include 
@@ -92,6 +93,7 @@ namespace engine {
       
       /** describe the kind of buffer managed by this provider */
       BufferDescriptor getDescriptorFor(size_t storageSize=0);
+      BufferDescriptor getDescriptorFor(size_t storageSize, TypeHandler specialTreatment);
       
       template
       BufferDescriptor getDescriptor();
@@ -120,15 +122,20 @@ namespace engine {
   BuffHandle
   BufferProvider::lockBufferFor()
   {
-    UNIMPLEMENTED ("convenience shortcut to announce and lock for a specific object type");
+    BufferDescriptor buffer_to_attach_object = getDescriptor();
+    return lockBufferFor (buffer_to_attach_object);
   }
   
   
+  /** define a "buffer type" for automatically creating
+   *  an instance of the template type embedded into the buffer
+   *  and destroying that embedded object when releasing the buffer.
+   */
   template
   BufferDescriptor
   BufferProvider::getDescriptor()
   {
-    UNIMPLEMENTED ("build descriptor for automatically placing an object instance into the buffer");
+    return getDescriptorFor (sizeof(BU), TypeHandler::create());
   }
   
   
diff --git a/src/proc/engine/type-handler.hpp b/src/proc/engine/type-handler.hpp
new file mode 100644
index 000000000..d7130d308
--- /dev/null
+++ b/src/proc/engine/type-handler.hpp
@@ -0,0 +1,182 @@
+/*
+  TYPE-HANDLER.hpp  -  a functor pair for setup and destruction
+
+  Copyright (C)         Lumiera.org
+    2011,               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 type-handler.hpp
+ ** Helper holding a pair of type-build-up and destruction functors.
+ ** Basically these two functors embody all type specific knowledge required
+ ** to place an object into some buffer space and to clean up later. They may even
+ ** be used in a more unspecific way, e.g. just to "prepare" a buffer or frame and to
+ ** "clean up" after usage.
+ ** 
+ ** Within the Lumiera Engine, the BufferProvider default implementation utilises instances
+ ** of TypeHandler to \em describe specific buffer types capable of managing an attached object,
+ ** or requiring some other kind of special treatment of the memory area used for the buffer.
+ ** This BufferDescriptor is embodied into the BufferMetadata::Key and used later on to invoke
+ ** the contained ctor / dtor functors, passing a concrete buffer (memory area).
+ ** 
+ ** @see buffer-metadata.hpp
+ ** @see buffer-provider.hpp
+ ** @see BufferMetadataKey_test#verifyTypeHandler unit-test
+ */
+
+#ifndef PROC_ENGINE_TYPE_HANDLER_H
+#define PROC_ENGINE_TYPE_HANDLER_H
+
+
+#include "lib/error.hpp"
+#include "lib/functor-util.hpp"
+
+#include 
+#include 
+
+
+namespace engine {
+  
+  using lib::HashVal;
+  using std::tr1::bind;
+  using std::tr1::function;
+  using std::tr1::placeholders::_1;
+  
+  namespace error = lumiera::error;
+  
+  
+  namespace { // (optional) helpers to build an object embedded into a buffer...
+    
+    template
+    inline void
+    buildIntoBuffer (void* storageBuffer)
+    {
+      new(storageBuffer) X();
+    }
+    
+    template
+    inline void
+    buildIntoBuffer_A1 (void* storageBuffer, A1 arg1)
+    {
+      new(storageBuffer) X(arg1);
+    }
+    
+    template
+    inline void
+    destroyInBuffer (void* storageBuffer)
+    {
+      X* embedded = static_cast (storageBuffer);
+      embedded->~X();
+    }
+  }//(End)placement-new helpers
+  
+  
+  
+  /**
+   * A pair of functors to maintain a datastructure within a buffer.
+   * TypeHandler describes how to outfit the buffer in a specific way.
+   * Special convenience builder function(s) are provided to create a
+   * TypeHandler performing placement-new into a buffer given on invocation.
+   * @note engine::BufferMetadata uses a TypeHandler to represent any
+   *       special treatment of a buffer space. When defined, the buffer
+   *       will be prepared on locking and cleanup will be invoked
+   *       automatically when releasing. 
+   * @warning comparison and hash values rely on internals of the
+   *       tr1::function implementation and might not be 100% accurate
+   */
+  struct TypeHandler
+    {
+      typedef function DoInBuffer;
+      
+      DoInBuffer createAttached;
+      DoInBuffer destroyAttached;
+      
+      /** build an invalid NIL TypeHandler */
+      TypeHandler()
+        : createAttached()
+        , destroyAttached()
+        { }
+      
+      /** build a TypeHandler
+       *  binding to arbitrary constructor and destructor functions.
+       *  On invocation, these functions get a void* to the buffer.
+       * @note the functor objects created from these operations
+       *       might be shared for handling multiple buffers.
+       *       Be careful with any state or arguments.
+       */
+      template
+      TypeHandler(CTOR ctor, DTOR dtor)
+        : createAttached (ctor)
+        , destroyAttached (dtor)
+        { }
+      
+      /** builder function defining a TypeHandler
+       *  to place a default-constructed object
+       *  into the buffer. */
+      template
+      static TypeHandler
+      create ()
+        {
+          return TypeHandler (buildIntoBuffer, destroyInBuffer);
+        }
+      
+      template
+      static TypeHandler
+      create (A1 a1)
+        {
+          return TypeHandler ( bind (buildIntoBuffer_A1, _1, a1)
+                             , destroyInBuffer);
+        }
+      
+      bool
+      isValid()  const
+        {
+          return bool(createAttached)
+              && bool(destroyAttached);
+        }
+      
+      friend HashVal
+      hash_value (TypeHandler const& handler)
+      {
+        HashVal hash(0);
+        if (handler.isValid())
+          {
+            boost::hash_combine(hash, handler.createAttached);
+            boost::hash_combine(hash, handler.destroyAttached);
+          }
+        return hash;
+      }
+      
+      friend bool
+      operator== (TypeHandler const& left, TypeHandler const& right)
+      {
+        return (!left.isValid() && !right.isValid())
+            || (  util::rawComparison(left.createAttached, right.createAttached)
+               && util::rawComparison(left.destroyAttached, right.destroyAttached)
+               );
+      }
+      friend bool
+      operator!= (TypeHandler const& left, TypeHandler const& right)
+      {
+        return !(left == right);
+      }
+    };
+  
+  
+  
+} // namespace engine
+#endif

From 890b6e8366a252e24ce9735ad5b64f12f073568e Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 13 Nov 2011 04:20:14 +0100
Subject: [PATCH 45/68] WIP implementation details of diagnostic BufferProvider

---
 src/proc/engine/buffer-provider.cpp           |  23 ++++
 src/proc/engine/buffer-provider.hpp           |   4 +
 .../engine/tracking-heap-block-provider.cpp   | 118 +++++++++++++++++-
 .../engine/tracking-heap-block-provider.hpp   |   9 +-
 4 files changed, 148 insertions(+), 6 deletions(-)

diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp
index ea5e4f5f0..2e8ace5bd 100644
--- a/src/proc/engine/buffer-provider.cpp
+++ b/src/proc/engine/buffer-provider.cpp
@@ -23,7 +23,9 @@
 
 #include "proc/engine/buffer-provider.hpp"
 #include "proc/engine/buffer-metadata.hpp"
+#include "lib/util.hpp"
 
+using util::isSameObject;
 
 namespace engine {
   
@@ -67,6 +69,27 @@ namespace engine {
   }
   
   
+  BuffHandle
+  BufferProvider::buildHandle (BufferDescriptor const& type, void* storage)
+  {
+    REQUIRE (was_created_by_this_provider (type));
+    
+    HashVal typeID (type.subClassification_);
+    metadata::Key& typeKey = meta_->get (typeID);
+    metadata::Entry& entry = meta_->markLocked(typeKey, newBlock);
+    
+    return BuffHandle (BufferDescriptor(*this, entry), newBlock);
+  }
+  
+  
+  bool
+  was_created_by_this_provider (BufferDescriptor const& descr)  const
+  {
+    return isSameObject (this, descr.provider_);
+  }
+    
+  
+  
   
   
   /* === BufferDescriptor and BuffHandle === */
diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp
index 174555acf..2e7709d6f 100644
--- a/src/proc/engine/buffer-provider.hpp
+++ b/src/proc/engine/buffer-provider.hpp
@@ -104,6 +104,10 @@ namespace engine {
       
       bool verifyValidity (BufferDescriptor const&);
       
+    protected:
+      BuffHandle buildHandle (BufferDescriptor const& type, void* storage);
+      
+      bool was_created_by_this_provider (BufferDescriptor const&)  const;
     };
     
     
diff --git a/src/proc/engine/tracking-heap-block-provider.cpp b/src/proc/engine/tracking-heap-block-provider.cpp
index 7fcd6ade4..43d6cda23 100644
--- a/src/proc/engine/tracking-heap-block-provider.cpp
+++ b/src/proc/engine/tracking-heap-block-provider.cpp
@@ -24,20 +24,124 @@
 #include "lib/error.hpp"
 #include "include/logging.h"
 //#include "lib/meta/function.hpp"
-#include "lib/scoped-ptrvect.hpp"
+//#include "lib/scoped-ptrvect.hpp"
+#include "lib/scoped-holder.hpp"
+#include "lib/util-foreach.hpp"
 
 #include "proc/engine/tracking-heap-block-provider.hpp"
 
 #include 
-//#include 
+#include 
 
-using lib::ScopedPtrVect;
+using util::for_each;
+using std::vector;
+using std::auto_ptr;
+using lib::ScopedHolder;
 
 
 
 namespace engine {
   
-  
+  namespace diagn {
+    
+    typedef vector PoolVec;
+    typedef ScopedHolder PoolHolder;
+    
+    /**
+     * @internal Pool of allocated buffer Blocks of a specific size.
+     * Helper for implementing a Diagnostic BufferProvider; actually does
+     * just heap allocations for the Blocks, but keeps a collection of
+     * allocated Blocks around. Individual entries can be retrieved
+     * and thus removed from the responsibility of BlockPool.
+     * 
+     * The idea is that each buffer starts its lifecycle within some pool
+     * and later gets "emitted" to an output sequence, where it remains for
+     * later investigation and diagnostics.
+     */
+    class BlockPool
+      {
+        size_t memBlockSize_;
+        PoolHolder blockList_;
+        
+      public:
+        BlockPool()
+          : memBlockSize_(0)
+          , blockList_()
+          { }
+        
+        void
+        initialise (size_t blockSize)
+          {
+            blockList_.create();
+            memBlockSize_(blockSize);
+          }
+         // standard copy operations are valid, but will
+        //  raise an runtime error, once BlockPool is initialised.
+        
+       ~BlockPool()
+          try {
+            if (blockList_)
+              for_each (*blockList_, discardBuffer);
+            }
+          ERROR_LOG_AND_IGNORE (test, "Shutdown of diagnostic BufferProvider allocation pool");
+        
+          
+        Block&
+        createBlock()
+          {
+            Block* newBlock(0);
+            try
+              {
+                newBlock = new Block();  ////////////////////////////TODO pass size as ctor param  
+                blockList_->push_back (newBlock);
+              }
+            catch(...)
+              {
+                if (newBlock)
+                  delete newBlock;
+                throw;
+              }
+            ENSURE (newBlock);
+            return *newBlock;
+          }
+        
+        
+        auto_ptr
+        transferResponsibility (Block* allocatedBlock)
+          {
+            auto_ptr extracted;
+            PoolVec& vec = *blockList_;
+            PoolVec::iterator pos = find (vec.begin(),vec.end(), allocatedBlock);
+            if (pos != vec.end())
+              {
+                extracted.reset (allocatedBlock);
+                vec.erase(pos);
+              }
+            return extracted;
+          }
+        
+        
+        size_t
+        size()  const
+          {
+            return blockList_->size();
+          }
+        
+      private:
+          static void
+          discardBuffer (Block* block)
+            {
+              if (!block) return;
+              
+              if (block->was_used() && !block->was_closed())
+                ERROR (test, "Block actively in use while shutting down BufferProvider "
+                             "allocation pool. This might lead to Segfault and memory leaks.");
+              
+              delete block;
+            }
+      };
+
+  }
   
     
     
@@ -54,6 +158,7 @@ namespace engine {
    */
   TrackingHeapBlockProvider::TrackingHeapBlockProvider()
     : BufferProvider ("Diagnostic_HeapAllocated")
+    , pool_()
     { }
   
   TrackingHeapBlockProvider::~TrackingHeapBlockProvider()
@@ -72,9 +177,12 @@ namespace engine {
 
   
   BuffHandle
-  TrackingHeapBlockProvider::lockBufferFor (BufferDescriptor const& descriptor)
+  TrackingHeapBlockProvider::lockBufferFor (BufferDescriptor const& type)
   {
     UNIMPLEMENTED ("lock buffer for exclusive use");
+    diagn::BlockPool& blocks = getBlockPoolFor (type);
+    diagn::Block* newBlock = blocks.createBlock();
+    return buildHandle (type, newBlock);
   }
   
   
diff --git a/src/proc/engine/tracking-heap-block-provider.hpp b/src/proc/engine/tracking-heap-block-provider.hpp
index a7065252a..157aeeb5c 100644
--- a/src/proc/engine/tracking-heap-block-provider.hpp
+++ b/src/proc/engine/tracking-heap-block-provider.hpp
@@ -48,6 +48,7 @@
 #include "lib/scoped-ptrvect.hpp"
 #include "lib/access-casted.hpp"
 
+#include 
 #include 
 #include 
 
@@ -100,8 +101,13 @@ namespace engine {
             return storage_.get();
           }
       };
+      
+    class BlockPool;
+    
+    typedef std::tr1::unordered_map PoolTable;
   }
   
+  
   /**
    * simple BufferProvider implementation with additional allocation tracking.
    * @internal used as PImpl by DiagnosticBufferProvider and DiagnosticOutputSlot.
@@ -115,13 +121,14 @@ namespace engine {
     : public BufferProvider
     , public lib::ScopedPtrVect
     {
+      diagn::PoolTable pool_;
       
     public:
       /* === BufferProvider interface === */
       
       using BufferProvider::lockBufferFor;
       virtual uint announce (uint count, BufferDescriptor const& type);
-      virtual BuffHandle lockBufferFor (BufferDescriptor const& descriptor);
+      virtual BuffHandle lockBufferFor (BufferDescriptor const& type);
       virtual void mark_emitted  (BuffHandle const& handle);
       virtual void releaseBuffer (BuffHandle const& handle);
       

From 6bc94cccb5886bef40a884472c54e37e5f531020 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Mon, 14 Nov 2011 01:43:29 +0100
Subject: [PATCH 46/68] WIP refactor BufferProvider public and protected API

---
 src/proc/engine/buffer-local-key.hpp          | 89 +++++++++++++++++
 src/proc/engine/buffer-metadata.hpp           | 60 ++++--------
 src/proc/engine/buffer-provider.cpp           | 97 +++++++++++++++++--
 src/proc/engine/buffer-provider.hpp           | 31 ++++--
 src/proc/engine/buffhandle.hpp                |  7 +-
 .../engine/tracking-heap-block-provider.cpp   | 26 +++--
 .../engine/tracking-heap-block-provider.hpp   |  1 +
 7 files changed, 244 insertions(+), 67 deletions(-)
 create mode 100644 src/proc/engine/buffer-local-key.hpp

diff --git a/src/proc/engine/buffer-local-key.hpp b/src/proc/engine/buffer-local-key.hpp
new file mode 100644
index 000000000..aa620aa68
--- /dev/null
+++ b/src/proc/engine/buffer-local-key.hpp
@@ -0,0 +1,89 @@
+/*
+  BUFFER-LOCAL-KEY.hpp  -  opaque data for BufferProvider implementation
+
+  Copyright (C)         Lumiera.org
+    2011,               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.
+
+*/
+
+
+#ifndef PROC_ENGINE_BUFFR_LOCAL_KEY_H
+#define PROC_ENGINE_BUFFR_LOCAL_KEY_H
+
+
+#include "lib/error.hpp"
+
+#include 
+
+
+namespace lib {
+  typedef size_t HashVal;
+}
+
+namespace engine {
+  
+  namespace metadata {
+    class Key;
+    class Entry;
+  }
+  class BufferMetadata;
+  
+  using lib::HashVal;
+  
+  
+  
+  /**
+   * an opaque ID to be used by the BufferProvider implementation.
+   * Typically this will be used, to set apart some pre-registered
+   * kinds of buffers. It is treated as being part of the buffer type.
+   * LocalKey objects may be copied but not re-assigned or changed.
+   */
+  class LocalKey
+    {
+      uint64_t privateID_;
+      
+    public:
+      LocalKey (uint64_t opaqueValue=0)
+        : privateID_(opaqueValue)
+        { }
+      
+      operator uint64_t()  const { return privateID_; }
+      
+      bool isDefined()     const { return bool(privateID_); }
+      
+      friend size_t
+      hash_value (LocalKey const& lkey)
+      {
+        boost::hash hashFunction;
+        return hashFunction(lkey.privateID_);
+      }
+      
+    private:
+      /** assignment usually prohibited */
+      LocalKey& operator= (LocalKey const& o)
+        {
+          privateID_ = o.privateID_;
+          return *this;
+        }
+      
+      /** but Key assignments are acceptable */
+      friend class metadata::Key;
+    };
+  
+  
+} // namespace engine
+#endif
diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp
index b06f01035..87ce5e59c 100644
--- a/src/proc/engine/buffer-metadata.hpp
+++ b/src/proc/engine/buffer-metadata.hpp
@@ -59,6 +59,7 @@
 #include "lib/util-foreach.hpp"
 #include "include/logging.h"
 #include "proc/engine/type-handler.hpp"
+#include "proc/engine/buffer-local-key.hpp"
 
 #include 
 #include 
@@ -96,42 +97,6 @@ namespace engine {
   
   
   
-  /**
-   * an opaque ID to be used by the BufferProvider implementation.
-   * Typically this will be used, to set apart some pre-registered
-   * kinds of buffers. It is treated as being part of the buffer type.
-   * LocalKey objects may be copied but not re-assigned or changed.
-   */
-  class LocalKey
-    {
-      uint64_t privateID_;
-      
-    public:
-      LocalKey (uint64_t opaqueValue=0)
-        : privateID_(opaqueValue)
-        { }
-      
-      operator uint64_t()  const { return privateID_; }
-      
-      friend size_t
-      hash_value (LocalKey const& lkey)
-      {
-        boost::hash hashFunction;
-        return hashFunction(lkey.privateID_);
-      }
-      
-    private:
-      /** assignment usually prohibited */
-      LocalKey& operator= (LocalKey const& o)
-        {
-          privateID_ = o.privateID_;
-          return *this;
-        }
-      
-      /** but Key assignments are acceptable */
-      friend class metadata::Key;
-    };
-  
   
   
   
@@ -253,14 +218,20 @@ namespace engine {
          *         For NULL buffer a copy of the parent is returned.
          */
         static Key
-        forEntry (Key const& parent, const void* bufferAddr)
+        forEntry (Key const& parent, const void* bufferAddr, LocalKey const& implID =UNSPECIFIC)
           {
             Key newKey(parent);
             if (bufferAddr)
               {
                 newKey.parent_ = HashVal(parent);
                 newKey.hashID_ = chainedHash(parent, bufferAddr);
-              }
+                if (nontrivial(implID))
+                  {
+                    REQUIRE (!newKey.specifics_.isDefined(),
+                             "Implementation defined local key should not be overridden. "
+                             "Underlying buffer type already defines a nontrivial LocalKey");
+                    newKey.specifics_ = implID;
+              }   }
             return newKey; 
           }
         
@@ -297,8 +268,8 @@ namespace engine {
         void*       buffer_;
         
       protected:
-        Entry (Key const& parent, void* bufferPtr =0)
-          : Key (Key::forEntry (parent, bufferPtr))
+        Entry (Key const& parent, void* bufferPtr =0, LocalKey const& implID =UNSPECIFIC)
+          : Key (Key::forEntry (parent, bufferPtr, implID))
           , state_(bufferPtr? LOCKED:NIL)
           , buffer_(bufferPtr)
           { }
@@ -654,7 +625,10 @@ namespace engine {
        *        buffer is released or re-used later.
        */
       Entry&
-      lock (Key const& parentKey, void* concreteBuffer, bool onlyNew =false)
+      lock (Key const& parentKey
+           ,void* concreteBuffer
+           ,LocalKey const& implID
+           ,bool onlyNew =false)
         {
           if (!concreteBuffer)
             throw error::Invalid ("Attempt to lock a slot for a NULL buffer"
@@ -724,13 +698,13 @@ namespace engine {
        *        created, but is marked as FREE
        */
       Entry&
-      markLocked (Key const& parentKey, void* buffer)
+      markLocked (Key const& parentKey, void* buffer, LocalKey const& implID)
         {
           if (!buffer)
             throw error::Fatal ("Attempt to lock for a NULL buffer. Allocation floundered?"
                                , error::LUMIERA_ERROR_BOTTOM_VALUE);
           
-          return this->lock(parentKey, buffer, true); // force creation of a new entry
+          return this->lock(parentKey, buffer, implID, true); // force creation of a new entry
         }
       
       /** purge the bare metadata Entry from the metadata tables.
diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp
index 2e8ace5bd..ddb4ade3a 100644
--- a/src/proc/engine/buffer-provider.cpp
+++ b/src/proc/engine/buffer-provider.cpp
@@ -35,6 +35,9 @@ namespace engine {
     const uint DEFAULT_DESCRIPTOR = 0;
     
   }
+  
+  LUMIERA_ERROR_DEFINE (BUFFER_MANAGEMENT, "Problem providing working buffers");
+  
 
   
   BufferProvider::BufferProvider (Literal implementationID)
@@ -70,20 +73,95 @@ namespace engine {
   
   
   BuffHandle
-  BufferProvider::buildHandle (BufferDescriptor const& type, void* storage)
+  BufferProvider::buildHandle (HashVal typeID, void* storage, LocalKey const& implID)
   {
-    REQUIRE (was_created_by_this_provider (type));
-    
-    HashVal typeID (type.subClassification_);
     metadata::Key& typeKey = meta_->get (typeID);
-    metadata::Entry& entry = meta_->markLocked(typeKey, newBlock);
+    metadata::Entry& entry = meta_->markLocked(typeKey, newBlock, implID);
     
     return BuffHandle (BufferDescriptor(*this, entry), newBlock);
   }
   
   
+  /** BufferProvider API: declare in advance the need for working buffers.
+   *  This optional call allows client code to ensure the availability of the
+   *  necessary working space, prior to starting the actual operations. The
+   *  client may reasonably assume to get the actual number of buffers, as
+   *  indicated by the return value. A provider may be able to handle
+   *  various kinds of buffers (e.g. of differing size), which are
+   *  distinguished by the \em type embodied into the BufferDescriptor.
+   * @return maximum number of simultaneously usable buffers of this type,
+   *         to be retrieved later through calls to #lockBuffer.
+   * @throw error::State when no buffer of this kind can be provided
+   * @note the returned count may differ from the requested count.
+   */
+  uint
+  BufferProvider::announce (uint count, BufferDescriptor const& type)
+  {
+    uint actually_possible = prepareBuffers (count, type);
+    if (!actually_possible)
+      throw error::State ("unable to fulfil request for buffers"
+                         ,LUMIERA_ERROR_BUFFER_MANAGEMENT);
+    return actually_possible;
+  }
+  
+  
+  /** BufferProvider API: retrieve a single buffer for exclusive use.
+   *  This call actually claims a buffer of this type and marks it for
+   *  use by client code. The returned handle allows for convenient access,
+   *  but provides no automatic tracking or memory management. The client is
+   *  explicitly responsible to invoke #releaseBuffer (which can be done directly
+   *  on the BuffHandle).
+   * @return a copyable handle, representing this buffer and this usage transaction.
+   * @throw error::State when unable to provide this buffer
+   * @note this function may be used right away, without prior announcing, but then
+   *       the client should be prepared for exceptions. The #announce operation allows
+   *       to establish a reliably available baseline.
+   */
+  BuffHandle
+  BufferProvider::lockBuffer (BufferDescriptor const& type)
+  {
+    REQUIRE (was_created_by_this_provider (type));
+    
+    return provideLockedBuffer (type);
+  }     // is expected to call buildHandle() --> state transition
+  
+  
+  /** BufferProvider API: state transition to \em emitted state.
+   *  Client code may signal a state transition through this optional operation.
+   *  The actual meaning of an "emitted" buffer is implementation defined; similarly,
+   *  some back-ends may actually do something when emitting a buffer (e.g. commit data
+   *  to cache), while others just set a flag or do nothing at all. This state transition
+   *  may be invoked at most once per locked buffer.
+   * @throw error::Fatal in case of invalid state transition sequence. Only a locked buffer
+   *        may be emitted, and at most once.
+   * @warning by convention, emitting a buffer implies that the contained data is ready and
+   *        might be used by other parts of the application.
+   *        An emitted buffer should not be modified anymore. 
+   */
+  void
+  BufferProvider::emitBuffer (BuffHandle const&)
+  {
+    
+  }
+  
+  
+  /** BufferProvider API: declare done and detach.
+   *  Client code is required to release \em each previously locked buffer eventually.
+   * @warning invalidates the BuffHandle, clients mustn't access the buffer anymore.
+   *          Right after releasing, an access through the handle will throw;
+   *          yet the buffer might be re-used and the handle become valid
+   *          later on accidentally. 
+   * @note EX_FREE
+   */
+  void
+  BufferProvider::releaseBuffer (BuffHandle const&)
+  {
+    
+  }
+  
+  
   bool
-  was_created_by_this_provider (BufferDescriptor const& descr)  const
+  BufferProvider::was_created_by_this_provider (BufferDescriptor const& descr)  const
   {
     return isSameObject (this, descr.provider_);
   }
@@ -101,6 +179,13 @@ namespace engine {
   }
   
   
+  void
+  BuffHandle::emit()
+  {
+    UNIMPLEMENTED ("forward buffer emit call to buffer provider");
+  }
+  
+  
   void
   BuffHandle::release()
   {
diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp
index 2e7709d6f..a18b6cc30 100644
--- a/src/proc/engine/buffer-provider.hpp
+++ b/src/proc/engine/buffer-provider.hpp
@@ -46,6 +46,7 @@
 #include "lib/symbol.hpp"
 #include "proc/engine/buffhandle.hpp"
 #include "proc/engine/type-handler.hpp"
+#include "proc/engine/buffer-local-key.hpp"
 
 #include 
 #include 
@@ -60,6 +61,9 @@ namespace engine {
   class BufferMetadata;
   
   
+  LUMIERA_ERROR_DECLARE (BUFFER_MANAGEMENT); ///< Problem providing working buffers
+  
+  
   /**
    * Interface: a facility providing and managing working buffers for media calculations.
    * The pointer to actual buffer storage can be retrieved by
@@ -74,18 +78,27 @@ namespace engine {
     {
       scoped_ptr meta_;
       
-    protected:
+      
+    protected: /* === for Implementation by concrete providers === */
+      
       BufferProvider (Literal implementationID);
       
+      virtual uint prepareBuffers (uint count, HashVal typeID)    =0;
+      
+      virtual BuffHandle provideLockedBuffer  (HashVal typeID)    =0;
+      virtual void mark_emitted (HashVal typeID, LocalKey const&) =0;
+      virtual void detachBuffer (HashVal typeID, LocalKey const&) =0;
+      
+      
     public:
-      virtual ~BufferProvider();  ///< this is an interface
+      virtual ~BufferProvider();  ///< this is an ABC
       
       
-      virtual uint announce (uint count, BufferDescriptor const&) =0;
+      uint announce (uint count, BufferDescriptor const&);
       
-      virtual BuffHandle lockBufferFor (BufferDescriptor const&)  =0;
-      virtual void mark_emitted  (BuffHandle const&)              =0;
-      virtual void releaseBuffer (BuffHandle const&)              =0;
+      BuffHandle lockBuffer (BufferDescriptor const&);
+      void       emitBuffer (BuffHandle const&);
+      void    releaseBuffer (BuffHandle const&);
       
       template
       BuffHandle lockBufferFor ();
@@ -105,7 +118,7 @@ namespace engine {
       bool verifyValidity (BufferDescriptor const&);
       
     protected:
-      BuffHandle buildHandle (BufferDescriptor const& type, void* storage);
+      BuffHandle buildHandle (HashVal typeID, void* storage, LocalKey const&);
       
       bool was_created_by_this_provider (BufferDescriptor const&)  const;
     };
@@ -126,8 +139,8 @@ namespace engine {
   BuffHandle
   BufferProvider::lockBufferFor()
   {
-    BufferDescriptor buffer_to_attach_object = getDescriptor();
-    return lockBufferFor (buffer_to_attach_object);
+    BufferDescriptor attach_object_automatically = getDescriptor();
+    return lockBuffer (attach_object_automatically);
   }
   
   
diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp
index 14845a849..e1bd025ac 100644
--- a/src/proc/engine/buffhandle.hpp
+++ b/src/proc/engine/buffhandle.hpp
@@ -52,6 +52,8 @@
 
 namespace engine {
   
+  typedef size_t HashVal;           ////////////TICKET #722
+  
   class BufferProvider;
   
   
@@ -70,7 +72,7 @@ namespace engine {
   class BufferDescriptor
     {
       BufferProvider* provider_;
-      uint64_t subClassification_;
+      HashVal subClassification_;
       
       BufferDescriptor(BufferProvider& manager, uint64_t detail)
         : provider_(&manager)
@@ -83,6 +85,8 @@ namespace engine {
       // using standard copy operations
       
       bool verifyValidity()  const;
+      
+      operator HashVal()  const { return subClassification_; }
     };
   
   
@@ -136,6 +140,7 @@ namespace engine {
       
       
       
+      void emit();
       void release();
       
       
diff --git a/src/proc/engine/tracking-heap-block-provider.cpp b/src/proc/engine/tracking-heap-block-provider.cpp
index 43d6cda23..c40a2a56d 100644
--- a/src/proc/engine/tracking-heap-block-provider.cpp
+++ b/src/proc/engine/tracking-heap-block-provider.cpp
@@ -35,7 +35,6 @@
 
 using util::for_each;
 using std::vector;
-using std::auto_ptr;
 using lib::ScopedHolder;
 
 
@@ -106,15 +105,15 @@ namespace engine {
           }
         
         
-        auto_ptr
+        Block*
         transferResponsibility (Block* allocatedBlock)
           {
-            auto_ptr extracted;
+            Block* extracted;
             PoolVec& vec = *blockList_;
             PoolVec::iterator pos = find (vec.begin(),vec.end(), allocatedBlock);
             if (pos != vec.end())
               {
-                extracted.reset (allocatedBlock);
+                extracted = *pos;
                 vec.erase(pos);
               }
             return extracted;
@@ -179,24 +178,29 @@ namespace engine {
   BuffHandle
   TrackingHeapBlockProvider::lockBufferFor (BufferDescriptor const& type)
   {
-    UNIMPLEMENTED ("lock buffer for exclusive use");
     diagn::BlockPool& blocks = getBlockPoolFor (type);
     diagn::Block* newBlock = blocks.createBlock();
-    return buildHandle (type, newBlock);
+    return buildHandle (type, newBlock->accessMemory(), newBlock);
   }
   
   
   void
   TrackingHeapBlockProvider::mark_emitted (BuffHandle const& handle)
   {
-    UNIMPLEMENTED ("commit a buffer to the protocol section");
+    //TODO mark metadata
+    diagn::Block* block4buffer = locateBlock (handle);
+    diagn::BlockPool& pool = getBlockPoolFor (handle);
+    this->manage (pool.transferResponsibility (block4buffer));
   }
   
   
+  /** mark a buffer as officially discarded */
   void
   TrackingHeapBlockProvider::releaseBuffer (BuffHandle const& handle)
   {
-    UNIMPLEMENTED ("mark a buffer as officially discarded");
+    //TODO mark metadata
+    diagn::Block* block4buffer = locateBlock (handle);
+    block4buffer->markReleased();
   }
   
   
@@ -222,6 +226,12 @@ namespace engine {
     return bufferID < this->size();
   }
   
+  diagn::BlockPool&
+  TrackingHeapBlockProvider::getBlockPoolFor (BufferDescriptor const& type)
+  {
+    UNIMPLEMENTED ("access correct block pool, based on metadata");
+  }
+  
   
   
   
diff --git a/src/proc/engine/tracking-heap-block-provider.hpp b/src/proc/engine/tracking-heap-block-provider.hpp
index 157aeeb5c..25f89fada 100644
--- a/src/proc/engine/tracking-heap-block-provider.hpp
+++ b/src/proc/engine/tracking-heap-block-provider.hpp
@@ -143,6 +143,7 @@ namespace engine {
       
     private:
       bool withinStorageSize (uint bufferID)  const;
+      diagn::BlockPool& getBlockPoolFor (BufferDescriptor const&);      
     };
   
   

From d1d0f66fa8f1916154c72c224fef232820149ae2 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Tue, 15 Nov 2011 04:46:00 +0100
Subject: [PATCH 47/68] allow LocalKey to carry arbitrary pointers or hashes as
 payload

...used to piggyback opaque implementation data,
deliberately no typecheck here
---
 src/proc/engine/buffer-local-key.hpp | 51 ++++++++++++++++++++++++----
 1 file changed, 45 insertions(+), 6 deletions(-)

diff --git a/src/proc/engine/buffer-local-key.hpp b/src/proc/engine/buffer-local-key.hpp
index aa620aa68..15bfe07ef 100644
--- a/src/proc/engine/buffer-local-key.hpp
+++ b/src/proc/engine/buffer-local-key.hpp
@@ -54,24 +54,63 @@ namespace engine {
    */
   class LocalKey
     {
-      uint64_t privateID_;
+      union OpaqueData
+        {
+          uint64_t _as_number;
+          void*    _as_pointer;
+        };
+      
+      OpaqueData privateID_;
       
     public:
+      explicit
       LocalKey (uint64_t opaqueValue=0)
-        : privateID_(opaqueValue)
-        { }
+        { 
+          privateID_._as_number = opaqueValue;
+        }
       
-      operator uint64_t()  const { return privateID_; }
+      LocalKey (void* impl_related_ptr)
+        { 
+          privateID_._as_number  = 0;          
+          privateID_._as_pointer = impl_related_ptr;
+        }
       
-      bool isDefined()     const { return bool(privateID_); }
+      
+      operator uint64_t()  const
+        {
+          return privateID_._as_number;
+        }
+      
+      operator void*()  const
+        {
+          return privateID_._as_pointer;
+        }
+      
+      bool
+      isDefined()  const
+        {
+          return bool(privateID_._as_number); 
+        }
       
       friend size_t
       hash_value (LocalKey const& lkey)
       {
         boost::hash hashFunction;
-        return hashFunction(lkey.privateID_);
+        return hashFunction(lkey.privateID_._as_number);
       }
       
+      friend bool
+      operator== (LocalKey const& left, LocalKey const& right)
+      {
+        return uint64_t(left) == uint64_t(right);
+      }
+      friend bool
+      operator!= (LocalKey const& left, LocalKey const& right)
+      {
+        return uint64_t(left) != uint64_t(right);
+      }
+      
+      
     private:
       /** assignment usually prohibited */
       LocalKey& operator= (LocalKey const& o)

From 623bb401af168d3c16d3f6fc51d0635889cd2a27 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Tue, 15 Nov 2011 04:47:31 +0100
Subject: [PATCH 48/68] clarify implementation extension points of
 BufferProvider

decide especially how to pass on the implementation
defined data like e.g. pointers to storage extents
---
 src/proc/engine/buffer-metadata.hpp           | 10 ++---
 src/proc/engine/buffer-provider.cpp           | 20 ++++++---
 src/proc/engine/buffhandle.hpp                | 14 ++++--
 .../engine/tracking-heap-block-provider.cpp   | 43 ++++++++++++-------
 .../engine/tracking-heap-block-provider.hpp   | 21 ++++++---
 .../tracking-heap-block-provider-test.cpp     | 26 +++++------
 .../proc/play/diagnostic-output-slot.hpp      |  6 +--
 7 files changed, 87 insertions(+), 53 deletions(-)

diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp
index 87ce5e59c..47da8060b 100644
--- a/src/proc/engine/buffer-metadata.hpp
+++ b/src/proc/engine/buffer-metadata.hpp
@@ -593,13 +593,13 @@ namespace engine {
        * @note might create/register a new Entry as a side-effect 
        */ 
       Key const&
-      key (Key const& parentKey, void* concreteBuffer)
+      key (Key const& parentKey, void* concreteBuffer, LocalKey const& implID =UNSPECIFIC)
         {
           Key derivedKey = Key::forEntry (parentKey, concreteBuffer);
           Entry* existing = table_.fetch (derivedKey);
           
           return existing? *existing
-                         : markLocked (parentKey,concreteBuffer);
+                         : markLocked (parentKey,concreteBuffer,implID);
         }
       
       /** core operation to access or create a concrete buffer metadata entry.
@@ -627,14 +627,14 @@ namespace engine {
       Entry&
       lock (Key const& parentKey
            ,void* concreteBuffer
-           ,LocalKey const& implID
+           ,LocalKey const& implID =UNSPECIFIC
            ,bool onlyNew =false)
         {
           if (!concreteBuffer)
             throw error::Invalid ("Attempt to lock a slot for a NULL buffer"
                                  , error::LUMIERA_ERROR_BOTTOM_VALUE);
           
-          Entry newEntry(parentKey, concreteBuffer);
+          Entry newEntry(parentKey, concreteBuffer, implID);
           Entry* existing = table_.fetch (newEntry);
           
           if (existing && onlyNew)
@@ -698,7 +698,7 @@ namespace engine {
        *        created, but is marked as FREE
        */
       Entry&
-      markLocked (Key const& parentKey, void* buffer, LocalKey const& implID)
+      markLocked (Key const& parentKey, void* buffer, LocalKey const& implID =UNSPECIFIC)
         {
           if (!buffer)
             throw error::Fatal ("Attempt to lock for a NULL buffer. Allocation floundered?"
diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp
index ddb4ade3a..af2fe02af 100644
--- a/src/proc/engine/buffer-provider.cpp
+++ b/src/proc/engine/buffer-provider.cpp
@@ -21,6 +21,7 @@
 * *****************************************************/
 
 
+#include "lib/error.hpp"
 #include "proc/engine/buffer-provider.hpp"
 #include "proc/engine/buffer-metadata.hpp"
 #include "lib/util.hpp"
@@ -76,9 +77,9 @@ namespace engine {
   BufferProvider::buildHandle (HashVal typeID, void* storage, LocalKey const& implID)
   {
     metadata::Key& typeKey = meta_->get (typeID);
-    metadata::Entry& entry = meta_->markLocked(typeKey, newBlock, implID);
+    metadata::Entry& entry = meta_->markLocked(typeKey, storage, implID);
     
-    return BuffHandle (BufferDescriptor(*this, entry), newBlock);
+    return BuffHandle (BufferDescriptor(*this, entry), storage);
   }
   
   
@@ -139,9 +140,11 @@ namespace engine {
    *        An emitted buffer should not be modified anymore. 
    */
   void
-  BufferProvider::emitBuffer (BuffHandle const&)
+  BufferProvider::emitBuffer (BuffHandle const& handle)
   {
-    
+    metadata::Entry& metaEntry = meta_->get (handle.entryID());
+    mark_emitted (metaEntry.parentKey(), metaEntry.localKey());
+    metaEntry.mark(EMITTED);
   }
   
   
@@ -154,10 +157,13 @@ namespace engine {
    * @note EX_FREE
    */
   void
-  BufferProvider::releaseBuffer (BuffHandle const&)
-  {
-    
+  BufferProvider::releaseBuffer (BuffHandle const& handle)
+  try {
+    metadata::Entry& metaEntry = meta_->get (handle.entryID());
+    detachBuffer (metaEntry.parentKey(), metaEntry.localKey());
+    metaEntry.mark(FREE);
   }
+  ERROR_LOG_AND_IGNORE (engine, "releasing a buffer from BufferProvider")
   
   
   bool
diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp
index e1bd025ac..a12d26df8 100644
--- a/src/proc/engine/buffhandle.hpp
+++ b/src/proc/engine/buffhandle.hpp
@@ -74,7 +74,7 @@ namespace engine {
       BufferProvider* provider_;
       HashVal subClassification_;
       
-      BufferDescriptor(BufferProvider& manager, uint64_t detail)
+      BufferDescriptor(BufferProvider& manager, HashVal detail)
         : provider_(&manager)
         , subClassification_(detail)
       { }
@@ -131,9 +131,9 @@ namespace engine {
       
       /** @internal a buffer handle may be obtained by "locking"
        *  a buffer from the corresponding BufferProvider */
-      BuffHandle(BufferDescriptor const& typeInfo, PBuff storage = 0)
+      BuffHandle(BufferDescriptor const& typeInfo, void* storage = 0)
         : descriptor_(typeInfo)
-        , pBuffer_(storage)
+        , pBuffer_(static_cast(storage))
         { }
       
       // using standard copy operations
@@ -151,6 +151,8 @@ namespace engine {
       BU& accessAs();
       
       
+      //////////////////////////////////////////TICKET #249 this operator looks obsolete. The Buff type is a placeholder type,
+      //////////////////////////////////////////TODO         it should never be accessed directly from within Lumiera engine code
       Buff&
       operator* ()  const
         {
@@ -165,6 +167,12 @@ namespace engine {
               && descriptor_.verifyValidity();
         }
       
+      HashVal
+      entryID()  const
+        {
+          return descriptor_;
+        }
+      
       size_t
       size()  const
         {
diff --git a/src/proc/engine/tracking-heap-block-provider.cpp b/src/proc/engine/tracking-heap-block-provider.cpp
index c40a2a56d..1ba17d181 100644
--- a/src/proc/engine/tracking-heap-block-provider.cpp
+++ b/src/proc/engine/tracking-heap-block-provider.cpp
@@ -41,6 +41,8 @@ using lib::ScopedHolder;
 
 namespace engine {
   
+  namespace error = lumiera::error;
+  
   namespace diagn {
     
     typedef vector PoolVec;
@@ -72,7 +74,7 @@ namespace engine {
         initialise (size_t blockSize)
           {
             blockList_.create();
-            memBlockSize_(blockSize);
+            memBlockSize_ = blockSize;
           }
          // standard copy operations are valid, but will
         //  raise an runtime error, once BlockPool is initialised.
@@ -157,7 +159,7 @@ namespace engine {
    */
   TrackingHeapBlockProvider::TrackingHeapBlockProvider()
     : BufferProvider ("Diagnostic_HeapAllocated")
-    , pool_()
+    , pool_(new diagn::PoolTable)
     { }
   
   TrackingHeapBlockProvider::~TrackingHeapBlockProvider()
@@ -169,37 +171,39 @@ namespace engine {
   /* ==== Implementation of the BufferProvider interface ==== */
   
   uint
-  TrackingHeapBlockProvider::announce (uint count, BufferDescriptor const& type)
+  TrackingHeapBlockProvider::prepareBuffers(uint, lib::HashVal)
   {
     UNIMPLEMENTED ("pre-register storage for buffers of a specific kind");   
   }
 
   
   BuffHandle
-  TrackingHeapBlockProvider::lockBufferFor (BufferDescriptor const& type)
+  TrackingHeapBlockProvider::provideLockedBuffer(HashVal typeID)
   {
-    diagn::BlockPool& blocks = getBlockPoolFor (type);
-    diagn::Block* newBlock = blocks.createBlock();
-    return buildHandle (type, newBlock->accessMemory(), newBlock);
+    diagn::BlockPool& blocks = getBlockPoolFor (typeID);
+    diagn::Block& newBlock = blocks.createBlock();
+    return buildHandle (typeID, newBlock.accessMemory(), &newBlock);
   }
   
   
   void
-  TrackingHeapBlockProvider::mark_emitted (BuffHandle const& handle)
+  TrackingHeapBlockProvider::mark_emitted (HashVal typeID, LocalKey const& implID)
   {
-    //TODO mark metadata
-    diagn::Block* block4buffer = locateBlock (handle);
-    diagn::BlockPool& pool = getBlockPoolFor (handle);
+    diagn::Block* block4buffer = locateBlock (typeID, implID);
+    if (!block4buffer)
+      throw error::Logic ("Attempt to emit a buffer not known to this BufferProvider"
+                         , LUMIERA_ERROR_BUFFER_MANAGEMENT);
+    diagn::BlockPool& pool = getBlockPoolFor (typeID);
     this->manage (pool.transferResponsibility (block4buffer));
   }
   
   
   /** mark a buffer as officially discarded */
   void
-  TrackingHeapBlockProvider::releaseBuffer (BuffHandle const& handle)
+  TrackingHeapBlockProvider::detachBuffer (HashVal typeID, LocalKey const& implID)
   {
-    //TODO mark metadata
-    diagn::Block* block4buffer = locateBlock (handle);
+    diagn::Block* block4buffer = locateBlock (typeID, implID);
+    REQUIRE (block4buffer, "releasing a buffer not allocated through this provider");
     block4buffer->markReleased();
   }
   
@@ -227,11 +231,20 @@ namespace engine {
   }
   
   diagn::BlockPool&
-  TrackingHeapBlockProvider::getBlockPoolFor (BufferDescriptor const& type)
+  TrackingHeapBlockProvider::getBlockPoolFor (HashVal typeID)
   {
     UNIMPLEMENTED ("access correct block pool, based on metadata");
   }
   
+  diagn::Block*
+  TrackingHeapBlockProvider::locateBlock (HashVal typeID, void* storage)
+  {
+    diagn::BlockPool& pool = getBlockPoolFor (typeID);
+    ////TODO: step 1: try to access from pool
+    ////TODO: step 2: otherwise search already emitted blocks
+    UNIMPLEMENTED ("access correct block pool, based on metadata");
+  }
+  
   
   
   
diff --git a/src/proc/engine/tracking-heap-block-provider.hpp b/src/proc/engine/tracking-heap-block-provider.hpp
index 25f89fada..53fffa17d 100644
--- a/src/proc/engine/tracking-heap-block-provider.hpp
+++ b/src/proc/engine/tracking-heap-block-provider.hpp
@@ -60,6 +60,7 @@ namespace engine {
   
   namespace diagn {
     
+    using boost::scoped_ptr;
     using boost::scoped_array;
 
     
@@ -100,6 +101,12 @@ namespace engine {
           {
             return storage_.get();
           }
+        
+        void
+        markReleased()
+          {
+            UNIMPLEMENTED ("diagn::Block accounting functionality");
+          }
       };
       
     class BlockPool;
@@ -121,16 +128,15 @@ namespace engine {
     : public BufferProvider
     , public lib::ScopedPtrVect
     {
-      diagn::PoolTable pool_;
+      scoped_ptr pool_;
       
     public:
       /* === BufferProvider interface === */
       
-      using BufferProvider::lockBufferFor;
-      virtual uint announce (uint count, BufferDescriptor const& type);
-      virtual BuffHandle lockBufferFor (BufferDescriptor const& type);
-      virtual void mark_emitted  (BuffHandle const& handle);
-      virtual void releaseBuffer (BuffHandle const& handle);
+      virtual uint prepareBuffers (uint count, HashVal typeID);
+      virtual BuffHandle provideLockedBuffer  (HashVal typeID);
+      virtual void mark_emitted (HashVal entryID, LocalKey const&);
+      virtual void detachBuffer (HashVal entryID, LocalKey const&);
       
     public:
       TrackingHeapBlockProvider();
@@ -143,7 +149,8 @@ namespace engine {
       
     private:
       bool withinStorageSize (uint bufferID)  const;
-      diagn::BlockPool& getBlockPoolFor (BufferDescriptor const&);      
+      diagn::BlockPool& getBlockPoolFor (HashVal typeID);
+      diagn::Block* locateBlock (HashVal typeID, void*);
     };
   
   
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 47fd1bcd4..cd31351ef 100644
--- a/tests/components/proc/engine/tracking-heap-block-provider-test.cpp
+++ b/tests/components/proc/engine/tracking-heap-block-provider-test.cpp
@@ -110,7 +110,7 @@ namespace test  {
           uint dataID = 1 + rand() % 29;
           testBuff.accessAs() = testData(dataID);
           
-          provider.mark_emitted (testBuff);
+          provider.emitBuffer   (testBuff);
           provider.releaseBuffer(testBuff);
           
           diagn::Block& block0 = provider.access_or_create(0);
@@ -130,9 +130,9 @@ namespace test  {
           
           for (uint i=0; i() = testNumbers[i] = rand() % 100000;
-              provider.mark_emitted (buff);
+              provider.emitBuffer   (buff);
               provider.releaseBuffer(buff);
             }
           
@@ -150,11 +150,11 @@ namespace test  {
           
           BufferDescriptor buffType = provider.getDescriptorFor(TEST_ELM_SIZE);
           
-          BuffHandle bu1 = provider.lockBufferFor(buffType);
-          BuffHandle bu2 = provider.lockBufferFor(buffType);
-          BuffHandle bu3 = provider.lockBufferFor(buffType);
-          BuffHandle bu4 = provider.lockBufferFor(buffType);
-          BuffHandle bu5 = provider.lockBufferFor(buffType);
+          BuffHandle bu1 = provider.lockBuffer (buffType);
+          BuffHandle bu2 = provider.lockBuffer (buffType);
+          BuffHandle bu3 = provider.lockBuffer (buffType);
+          BuffHandle bu4 = provider.lockBuffer (buffType);
+          BuffHandle bu5 = provider.lockBuffer (buffType);
           
           CHECK (5 == provider.size());
           
@@ -176,11 +176,11 @@ namespace test  {
           CHECK (23 == provider.accessAs(3));
           CHECK (24 == provider.accessAs(4));
           
-          provider.mark_emitted (bu3);
-          provider.mark_emitted (bu1);
-          provider.mark_emitted (bu5);
-          provider.mark_emitted (bu4);
-          provider.mark_emitted (bu2);
+          provider.emitBuffer (bu3);
+          provider.emitBuffer (bu1);
+          provider.emitBuffer (bu5);
+          provider.emitBuffer (bu4);
+          provider.emitBuffer (bu2);
           
           CHECK (3 == provider.accessAs(0));
           CHECK (1 == provider.accessAs(1));
diff --git a/tests/components/proc/play/diagnostic-output-slot.hpp b/tests/components/proc/play/diagnostic-output-slot.hpp
index 571c1dad0..1c566d198 100644
--- a/tests/components/proc/play/diagnostic-output-slot.hpp
+++ b/tests/components/proc/play/diagnostic-output-slot.hpp
@@ -75,7 +75,7 @@ namespace play {
       BuffHandle
       claimBufferFor(FrameID frameNr) 
         {
-          buffProvider_->lockBufferFor (bufferType_);
+          return buffProvider_->lockBuffer (bufferType_);
         }
       
       
@@ -98,8 +98,8 @@ namespace play {
       void
       pushout (BuffHandle const& data4output)
         {
-          buffProvider_->mark_emitted  (data4output);
-          buffProvider_->releaseBuffer (data4output);
+          buffProvider_->emitBuffer   (data4output);
+          buffProvider_->releaseBuffer(data4output);
         }
       
       void

From 27449c143875b72055625a6089b568fda404c785 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 18 Nov 2011 01:23:50 +0100
Subject: [PATCH 49/68] implementation details of a test/dummy provider

---
 src/proc/engine/buffer-metadata.hpp           |  7 +--
 src/proc/engine/buffer-provider.cpp           |  8 +++
 src/proc/engine/buffer-provider.hpp           |  1 +
 .../engine/tracking-heap-block-provider.cpp   | 60 ++++++++++++++-----
 .../engine/tracking-heap-block-provider.hpp   | 17 +++---
 .../tracking-heap-block-provider-test.cpp     |  2 +-
 6 files changed, 68 insertions(+), 27 deletions(-)

diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp
index 47da8060b..484450a10 100644
--- a/src/proc/engine/buffer-metadata.hpp
+++ b/src/proc/engine/buffer-metadata.hpp
@@ -236,11 +236,8 @@ namespace engine {
           }
         
         
-        LocalKey const&
-        localKey()  const
-          {
-            return specifics_;
-          }
+        LocalKey const& localKey() const { return specifics_;}
+        size_t storageSize() const { return storageSize_; }
         
         HashVal parentKey()  const { return parent_;}
         operator HashVal()   const { return hashID_;}
diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp
index af2fe02af..a32639550 100644
--- a/src/proc/engine/buffer-provider.cpp
+++ b/src/proc/engine/buffer-provider.cpp
@@ -73,6 +73,14 @@ namespace engine {
   }
   
   
+  size_t
+  BufferProvider::getBufferSize (HashVal typeID)  const
+  {
+    metadata::Key& typeKey = meta_->get (typeID);
+    return typeKey.storageSize();
+  }
+  
+  
   BuffHandle
   BufferProvider::buildHandle (HashVal typeID, void* storage, LocalKey const& implID)
   {
diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp
index a18b6cc30..ce67928bb 100644
--- a/src/proc/engine/buffer-provider.hpp
+++ b/src/proc/engine/buffer-provider.hpp
@@ -118,6 +118,7 @@ namespace engine {
       bool verifyValidity (BufferDescriptor const&);
       
     protected:
+      size_t getBufferSize (HashVal typeID)  const;
       BuffHandle buildHandle (HashVal typeID, void* storage, LocalKey const&);
       
       bool was_created_by_this_provider (BufferDescriptor const&)  const;
diff --git a/src/proc/engine/tracking-heap-block-provider.cpp b/src/proc/engine/tracking-heap-block-provider.cpp
index 1ba17d181..559a6c2c3 100644
--- a/src/proc/engine/tracking-heap-block-provider.cpp
+++ b/src/proc/engine/tracking-heap-block-provider.cpp
@@ -24,6 +24,7 @@
 #include "lib/error.hpp"
 #include "include/logging.h"
 //#include "lib/meta/function.hpp"
+#include "lib/bool-checkable.hpp"
 //#include "lib/scoped-ptrvect.hpp"
 #include "lib/scoped-holder.hpp"
 #include "lib/util-foreach.hpp"
@@ -31,6 +32,7 @@
 #include "proc/engine/tracking-heap-block-provider.hpp"
 
 #include 
+#include 
 #include 
 
 using util::for_each;
@@ -60,6 +62,7 @@ namespace engine {
      * later investigation and diagnostics.
      */
     class BlockPool
+      : public lib::BoolCheckable
       {
         size_t memBlockSize_;
         PoolHolder blockList_;
@@ -93,7 +96,7 @@ namespace engine {
             Block* newBlock(0);
             try
               {
-                newBlock = new Block();  ////////////////////////////TODO pass size as ctor param  
+                newBlock = new Block(memBlockSize_);  
                 blockList_->push_back (newBlock);
               }
             catch(...)
@@ -107,12 +110,19 @@ namespace engine {
           }
         
         
+        Block*
+        find (void* bufferStorage)
+          {
+            UNIMPLEMENTED ("find a block based on storage location");
+          }
+        
+        
         Block*
         transferResponsibility (Block* allocatedBlock)
           {
             Block* extracted;
             PoolVec& vec = *blockList_;
-            PoolVec::iterator pos = find (vec.begin(),vec.end(), allocatedBlock);
+            PoolVec::iterator pos = std::find (vec.begin(),vec.end(), allocatedBlock);
             if (pos != vec.end())
               {
                 extracted = *pos;
@@ -128,6 +138,12 @@ namespace engine {
             return blockList_->size();
           }
         
+        bool
+        isValid()  const
+          {
+            return blockList_;
+          }
+        
       private:
           static void
           discardBuffer (Block* block)
@@ -160,11 +176,12 @@ namespace engine {
   TrackingHeapBlockProvider::TrackingHeapBlockProvider()
     : BufferProvider ("Diagnostic_HeapAllocated")
     , pool_(new diagn::PoolTable)
+    , outSeq_()
     { }
   
   TrackingHeapBlockProvider::~TrackingHeapBlockProvider()
     {
-      INFO (proc_mem, "discarding %zu diagnostic buffer entries", TrackingHeapBlockProvider::size());
+      INFO (proc_mem, "discarding %zu diagnostic buffer entries", outSeq_.size());
     }
   
   
@@ -194,7 +211,7 @@ namespace engine {
       throw error::Logic ("Attempt to emit a buffer not known to this BufferProvider"
                          , LUMIERA_ERROR_BUFFER_MANAGEMENT);
     diagn::BlockPool& pool = getBlockPoolFor (typeID);
-    this->manage (pool.transferResponsibility (block4buffer));
+    outSeq_.manage (pool.transferResponsibility (block4buffer));
   }
   
   
@@ -211,38 +228,53 @@ namespace engine {
   
   /* ==== Implementation details ==== */
   
+  size_t
+  TrackingHeapBlockProvider::emittedCnt()  const
+  {
+    return outSeq_.size();
+  }
+
   diagn::Block&
   TrackingHeapBlockProvider::access_or_create (uint bufferID)
   {
-    while (!withinStorageSize (bufferID))
-      this->manage (new diagn::Block);
+    while (!withinOutputSequence (bufferID))
+      outSeq_.manage (new diagn::Block(0));   /////////TICKET #856 really need a better way of returning a fallback
     
-    ENSURE (withinStorageSize (bufferID));
-    return (*this)[bufferID];
+    ENSURE (withinOutputSequence (bufferID));
+    return outSeq_[bufferID];
   }
   
   bool
-  TrackingHeapBlockProvider::withinStorageSize (uint bufferID)  const
+  TrackingHeapBlockProvider::withinOutputSequence (uint bufferID)  const
   {
     if (bufferID >= MAX_BUFFERS)
       throw error::Fatal ("hardwired internal limit for test buffers exceeded");
     
-    return bufferID < this->size();
+    return bufferID < outSeq_.size();
   }
   
   diagn::BlockPool&
   TrackingHeapBlockProvider::getBlockPoolFor (HashVal typeID)
   {
-    UNIMPLEMENTED ("access correct block pool, based on metadata");
+    diagn::BlockPool& pool = (*pool_)[typeID];
+    if (!pool)
+        pool.initialise(getBufferSize(typeID));
+    return pool;
   }
   
   diagn::Block*
   TrackingHeapBlockProvider::locateBlock (HashVal typeID, void* storage)
   {
     diagn::BlockPool& pool = getBlockPoolFor (typeID);
-    ////TODO: step 1: try to access from pool
-    ////TODO: step 2: otherwise search already emitted blocks
-    UNIMPLEMENTED ("access correct block pool, based on metadata");
+    diagn::Block* block4buffer = pool.find (storage);
+    return block4buffer? block4buffer
+                       : searchInOutSeqeuence (storage);
+  }
+  
+  diagn::Block*
+  TrackingHeapBlockProvider::searchInOutSeqeuence (void* storage)
+  {
+    UNIMPLEMENTED ("find block by storage location");
   }
   
   
diff --git a/src/proc/engine/tracking-heap-block-provider.hpp b/src/proc/engine/tracking-heap-block-provider.hpp
index 53fffa17d..bdda28c4a 100644
--- a/src/proc/engine/tracking-heap-block-provider.hpp
+++ b/src/proc/engine/tracking-heap-block-provider.hpp
@@ -57,6 +57,7 @@ namespace engine {
   
   namespace error = lumiera::error;
   
+  using lib::ScopedPtrVect;
   
   namespace diagn {
     
@@ -72,15 +73,14 @@ namespace engine {
     class Block
       : boost::noncopyable
       {
-        size_t size_;
         scoped_array storage_;
         
         bool was_locked_;
         
       public:
-        Block()
-          : size_(0)
-          , storage_()
+        explicit
+        Block(size_t bufferSize)
+          : storage_(new char[bufferSize])
           , was_locked_(false)
           { }
         
@@ -126,9 +126,9 @@ namespace engine {
    */
   class TrackingHeapBlockProvider
     : public BufferProvider
-    , public lib::ScopedPtrVect
     {
       scoped_ptr pool_;
+      ScopedPtrVect outSeq_; 
       
     public:
       /* === BufferProvider interface === */
@@ -142,15 +142,18 @@ namespace engine {
       TrackingHeapBlockProvider();
       virtual ~TrackingHeapBlockProvider();
       
+      size_t emittedCnt()  const;
+      
       diagn::Block& access_or_create (uint bufferID);
       
       template
       TY&  accessAs (uint bufferID);
       
     private:
-      bool withinStorageSize (uint bufferID)  const;
+      bool withinOutputSequence (uint bufferID)  const;
       diagn::BlockPool& getBlockPoolFor (HashVal typeID);
       diagn::Block* locateBlock (HashVal typeID, void*);
+      diagn::Block* searchInOutSeqeuence (void* storage);      
     };
   
   
@@ -167,7 +170,7 @@ namespace engine {
   TY&
   TrackingHeapBlockProvider::accessAs (uint bufferID)
   {
-    if (!withinStorageSize (bufferID))
+    if (!withinOutputSequence (bufferID))
       throw error::Invalid ("Buffer with the given ID not yet emitted");
     
     diagn::Block& memoryBlock = access_or_create (bufferID);
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 cd31351ef..405c4ceb9 100644
--- a/tests/components/proc/engine/tracking-heap-block-provider-test.cpp
+++ b/tests/components/proc/engine/tracking-heap-block-provider-test.cpp
@@ -156,7 +156,7 @@ namespace test  {
           BuffHandle bu4 = provider.lockBuffer (buffType);
           BuffHandle bu5 = provider.lockBuffer (buffType);
           
-          CHECK (5 == provider.size());
+          CHECK (5 == provider.emittedCnt());
           
           provider.accessAs(0) = 20;
           provider.accessAs(1) = 21;

From ca689ae5e056292390d2f463f932ec7677adaeec Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 18 Nov 2011 01:24:43 +0100
Subject: [PATCH 50/68] WIP some musing about building an option monad

---
 src/lib/maybe.hpp              | 122 +++++++++++++++++++++++
 tests/lib/maybe-value-test.cpp | 176 +++++++++++++++++++++++++++++++++
 2 files changed, 298 insertions(+)
 create mode 100644 src/lib/maybe.hpp
 create mode 100644 tests/lib/maybe-value-test.cpp

diff --git a/src/lib/maybe.hpp b/src/lib/maybe.hpp
new file mode 100644
index 000000000..085160a92
--- /dev/null
+++ b/src/lib/maybe.hpp
@@ -0,0 +1,122 @@
+/*
+  MAYBE.hpp  -  dealing with optional values
+
+  Copyright (C)         Lumiera.org
+    2011,               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 maybe.hpp
+ ** Support for representation of optional values.
+ ** This implements a concept ("option monad") known from functional programming,
+ ** allowing to express the fact of some value possibly be unavailable. Using this
+ ** approach allows to avoid the dangerous technique of (ab)using NULL pointers to
+ ** represent missing values. 
+ ** 
+ ** While a NULL pointer carries this special meaning just by convention, marking a
+ ** parameter or return value as optional states this fact first class, and enforces
+ ** the necessary "is available" check through the type system. Surprisingly, this
+ ** leads not only to more secure, but also much more compact code, as we're now
+ ** able to substitute a fallback just by a "or else use this" clause.
+ ** Basically, there are different ways to access the actual value
+ ** - access through implicit conversion raises an exception for missing values
+ ** - evaluation as boolean allows to check, if the value is available
+ ** - an alternative or fallback value may be attached.
+ ** 
+ ** @todo WIP and rather brainstorming as of 2/10
+ ** 
+ ** @see backend::ThreadJob usage example
+ */
+
+
+
+#ifndef LIB_MAYBE_H
+#define LIB_MAYBE_H
+
+//#include "pre.hpp"
+#include "lib/error.hpp"
+//#include "lib/wrapper.hpp"
+#include "lib/util.hpp"
+
+#include 
+
+
+
+namespace lib {
+  
+  using util::isnil;
+  using std::string;
+  namespace error = lumiera::error;
+  
+  
+  namespace maybe {
+    
+  }
+  
+  
+  /**
+   * A value, which might be unavailable
+   * @throw error::State on any attempt to access a missing value
+   *        without prior checking the availability
+   */
+  template
+  class Maybe
+    {
+      VAL value_;
+      
+    public:
+      /** mark an invalid/failed result */
+      Maybe ()
+        { }
+      
+      /** standard case: valid result */
+      Maybe (VAL const& value)
+       : value_(value)
+       { }
+      
+      
+      
+      bool
+      isValid()  const
+        {
+          UNIMPLEMENTED ("check if optional value is available");
+        }
+      
+      void
+      maybeThrow(Literal explanation =0)  const
+        {
+          if (!isValid())
+            throw error::State (explanation.empty()? "optional value not available" : string(explanation),
+                                error::LUMIERA_ERROR_BOTTOM_VALUE);
+        }
+      
+      
+      VAL
+      get()  const
+        {
+          maybeThrow();
+          return value_;
+        }
+    };
+  
+  
+  
+  
+  
+} // namespace lib
+#endif
diff --git a/tests/lib/maybe-value-test.cpp b/tests/lib/maybe-value-test.cpp
new file mode 100644
index 000000000..28e778269
--- /dev/null
+++ b/tests/lib/maybe-value-test.cpp
@@ -0,0 +1,176 @@
+/*
+  MaybeValue(Test)  -  considerations for dealing with optional values
+
+  Copyright (C)         Lumiera.org
+    2011,               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.
+
+* *****************************************************/
+
+
+
+
+#include "lib/test/run.hpp"
+#include "lib/test/test-helper.hpp"
+#include "lib/maybe.hpp"
+#include "lib/util.hpp"
+
+//#include 
+//#include 
+
+
+namespace lib {
+namespace test{
+  
+  namespace error = lumiera::error;
+  
+//  using util::isSameObject;
+//  using std::rand;
+  using util::isnil;
+  using error::LUMIERA_ERROR_BOTTOM_VALUE;
+  
+  
+  namespace { // test data and helpers...
+    
+    
+    uint INVOCATION_CNT(0);
+    
+    /** helper for testing delayed evaluation */
+    template
+    class Delayed
+      {
+        VAL v_;
+        
+      public:
+        Delayed (VAL val) : v_(val) { }
+        
+        VAL
+        operator() () const
+          {
+            ++INVOCATION_CNT;
+            return v_;
+          }
+      };
+    
+    template
+    inline Delayed
+    yield (VAL val)
+    {
+      
+    }
+  }
+  
+  
+  
+  /***************************************************************************************
+   * @test Investigate various situations of using a Maybe value or option monad.
+   * @note this is a testbed for experiments for the time being 11/2011
+   * 
+   * @see lib::Maybe 
+   * @see null-value-test.cpp
+   * @see util::AccessCasted
+   */
+  class MaybeValue_test : public Test
+    {
+      
+      void
+      run (Arg) 
+        {
+          show_basicOperations();
+          show_delayedAccess();
+        }
+      
+      
+      void
+      show_basicOperations()
+        {
+#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #856
+          Maybe one(1);
+          Maybe opt(5);
+          Maybe nil;
+          
+          CHECK (opt);    CHECK (!isnil(opt));
+          CHECK (!nil);   CHECK ( isnil(nil));
+          
+          // access the optional value
+          CHECK (1 == *one);
+          CHECK (5 == *opt);
+          
+          // can't access an bottom value
+          VERIFY_ERROR (BOTTOM_VALUE, *nil);
+          
+          // flatMap operation (apply a function)
+          CHECK (7 == *(opt >>= inc2));
+          CHECK (9 == *(opt >>= inc2 >>= inc2));
+          
+          // alternatives
+          CHECK (1 == *(one || opt));
+          CHECK (5 == *(nil || opt));
+          CHECK (1 == *(nil || one || opt));
+          
+          CHECK (1 == one.get());
+          CHECK (1 == one.getOrElse(9));
+          CHECK (9 == nil.getOrElse(9));
+#endif    /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #856
+        }
+      
+      
+      void
+      show_delayedAccess()
+        {
+          INVOCATION_CNT = 0;
+          
+          Maybe nil;
+          Maybe two(2);
+#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #856
+          Maybe later(yield(5));
+          CHECK (0 == INVOCATION_CNT);
+          
+          CHECK (2 == *(two || later));
+          CHECK (0 == INVOCATION_CNT);
+          
+          CHECK (5 == *(nil || later));
+          CHECK (1 == INVOCATION_CNT);
+          
+          later.get();
+          CHECK (2 == INVOCATION_CNT);
+          
+          CHECK (2 == two.getOrElse(later));
+          CHECK (2 == INVOCATION_CNT);
+          
+          CHECK (5 == nil.getOrElse(later));
+          CHECK (3 == INVOCATION_CNT);
+          
+          // obviously, this also works just with a function
+          CHECK (7 == nil.getOrElse(yield(7)));
+          CHECK (4 == INVOCATION_CNT);
+          
+          // stripping the delayed evaluation
+          Maybe some = later;
+          CHECK (5 == INVOCATION_CNT);
+          CHECK (5 == some);
+          
+          CHECK (5 == INVOCATION_CNT);
+#endif    /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #856
+        }
+    };
+  
+  
+  /** Register this test class... */
+  LAUNCHER (MaybeValue_test, "unit common");
+  
+  
+}} // namespace lib::test

From 1f966a02ecd612788a439a63bb658eb330891458 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 19 Nov 2011 17:46:24 +0100
Subject: [PATCH 51/68] some rather tricky adjustments to PtrDerefIter

...allowing to use that custom iterator together
with STL algorithms
---
 src/lib/iter-adapter.hpp   | 32 ++++++++++++++++++++++++++++++--
 src/lib/scoped-ptrvect.hpp | 12 ++++++++++--
 2 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp
index a8306a774..b573ec7e7 100644
--- a/src/lib/iter-adapter.hpp
+++ b/src/lib/iter-adapter.hpp
@@ -408,7 +408,7 @@ namespace lib {
       typedef typename RemovePtr::Type ValueType;
       
       template
-      struct SimilarIter
+      struct SimilarIter  ///< rebind to a similarly structured Iterator with value type T2
         {
           typedef Iter Type;
         };
@@ -445,7 +445,12 @@ namespace lib {
     public:
       typedef typename IT::value_type           pointer;
       typedef typename RemovePtr::Type value_type;
-      typedef value_type&                       reference; 
+      typedef value_type&                       reference;
+      
+      // for use with STL algorithms
+      typedef void difference_type;
+      typedef std::forward_iterator_tag iterator_category;
+      
       
       // the purpose of the following typedefs is to ease building a correct "const iterator"
       
@@ -462,6 +467,7 @@ namespace lib {
       /** PtrDerefIter is always created 
        *  by wrapping an existing iterator.
        */
+      explicit
       PtrDerefIter (IT srcIter)
         : i_(srcIter)
         { }
@@ -485,9 +491,31 @@ namespace lib {
       operator= (PtrDerefIter const& ref)
         {
           i_ = reinterpret_cast (ref.getBase());
+          return *this;
         }
       
       
+      /** explicit builder to allow creating a const variant from the basic srcIter type. 
+       *  Again, the reason necessitating this "backdoor" is that we want to swallow one level
+       *  of indirection. Generally speaking \code const T ** \endcode is not the same as
+       *  \code T * const * \endcode, but in our specific case the API ensures that a
+       *  PtrDerefIter only exposes const elements. 
+       */
+      static PtrDerefIter
+      build_by_cast (WrappedIterType const& srcIter)
+        {
+          return PtrDerefIter (reinterpret_cast (srcIter));
+        }
+      
+      static PtrDerefIter
+      nil()
+        {
+          return PtrDerefIter (IT());
+        }
+      
+      
+      
+      
       
       
       /* === lumiera forward iterator concept === */
diff --git a/src/lib/scoped-ptrvect.hpp b/src/lib/scoped-ptrvect.hpp
index 8bb713082..389456ae1 100644
--- a/src/lib/scoped-ptrvect.hpp
+++ b/src/lib/scoped-ptrvect.hpp
@@ -48,8 +48,10 @@
 #include "include/logging.h"
 #include "lib/iter-adapter.hpp"
 #include "lib/error.hpp"
+#include "lib/util.hpp"
 
 #include 
+#include 
 #include 
 
 
@@ -155,9 +157,9 @@ namespace lib {
       typedef ConstIterType const_iterator;
       
       iterator       begin()        { return       iterator (allPtrs()); }
-      const_iterator begin()  const { return const_iterator (allPtrs()); }
+      const_iterator begin()  const { return const_iterator::build_by_cast (allPtrs()); }
       iterator       end()          { return       iterator ( RIter() ); }
-      const_iterator end()    const { return const_iterator (RcIter() ); }
+      const_iterator end()    const { return const_iterator::nil();      }
       
       
       
@@ -188,6 +190,12 @@ namespace lib {
         {
           return RIter (_Vec::begin(), _Vec::end());
         }
+      RIter
+      allPtrs ()  const
+        {
+          _Vec& elements = util::unConst(*this);
+          return RIter (elements.begin(), elements.end());
+        }
     };
   
   

From 5947e0e3e150e8efde908673d98ec00b689fce43 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 19 Nov 2011 17:48:04 +0100
Subject: [PATCH 52/68] allow to detach an object managed by ScopedPtrVect

---
 src/lib/scoped-ptrvect.hpp | 42 ++++++++++++++++++++++++++++----------
 1 file changed, 31 insertions(+), 11 deletions(-)

diff --git a/src/lib/scoped-ptrvect.hpp b/src/lib/scoped-ptrvect.hpp
index 389456ae1..8ed96b0db 100644
--- a/src/lib/scoped-ptrvect.hpp
+++ b/src/lib/scoped-ptrvect.hpp
@@ -125,22 +125,42 @@ namespace lib {
         }   }
       
       
+      /** withdraw responsibility for a specific object.
+       *  This object will be removed form this collection
+       *  and returned as-is; it won't be deleted when the
+       *  ScopedPtrVect goes out of scope.
+       * @param obj address of the object in question.
+       * @return pointer to the object, if found.
+       *         Otherwise, NULL will be returned and the
+       *         collection of managed objects remains unaltered
+       * @note EX_STRONG
+       */
+      T*
+      detach (void* objAddress)
+        {
+          T* extracted = static_cast (objAddress);
+          VIter pos = std::find (_Vec::begin(),_Vec::end(), extracted);
+          if (pos != _Vec::end() && bool(*pos))
+            {
+              extracted = *pos;
+              _Vec::erase(pos);  // EX_STRONG
+              return extracted;
+            }
+          return NULL;
+        }
+      
+      
       void
       clear()
         { 
           VIter e = _Vec::end();
           for (VIter i = _Vec::begin(); i!=e; ++i)
-            {
-              if (*i)
-                try
-                  {
-                    delete *i;
-                    *i = 0;
-                  }
-                catch(std::exception& ex)
-                  {
-                    WARN (library, "Problem while deallocating ScopedPtrVect: %s", ex.what());
-            }     }
+            if (*i)
+              try {
+                  delete *i;
+                  *i = 0;
+                }
+              ERROR_LOG_AND_IGNORE (library, "Clean-up of ScopedPtrVect");
           _Vec::clear();
         }
       

From 3830ff7ce1f9e9d17bcca4969590a9f13b4d4438 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 19 Nov 2011 17:51:08 +0100
Subject: [PATCH 53/68] refactor the test/dummy provider, based on
 ScopedPtrVect solely

instead of using a vector directy, move the
additionally required functinoality in the
utility class. This forced me to adjust
the IterAdapter, to allow working with
STL algorithms
---
 .../engine/tracking-heap-block-provider.cpp   | 119 +++++++++++-------
 1 file changed, 74 insertions(+), 45 deletions(-)

diff --git a/src/proc/engine/tracking-heap-block-provider.cpp b/src/proc/engine/tracking-heap-block-provider.cpp
index 559a6c2c3..88769ff1a 100644
--- a/src/proc/engine/tracking-heap-block-provider.cpp
+++ b/src/proc/engine/tracking-heap-block-provider.cpp
@@ -25,19 +25,25 @@
 #include "include/logging.h"
 //#include "lib/meta/function.hpp"
 #include "lib/bool-checkable.hpp"
-//#include "lib/scoped-ptrvect.hpp"
+#include "lib/scoped-ptrvect.hpp"
 #include "lib/scoped-holder.hpp"
 #include "lib/util-foreach.hpp"
 
 #include "proc/engine/tracking-heap-block-provider.hpp"
 
 #include 
+#include 
 #include 
 #include 
 
-using util::for_each;
+//using util::for_each;
+using util::and_all;
 using std::vector;
 using lib::ScopedHolder;
+using lib::ScopedPtrVect;
+using std::tr1::function;
+using std::tr1::bind;
+using std::tr1::placeholders::_1;
 
 
 
@@ -45,9 +51,46 @@ namespace engine {
   
   namespace error = lumiera::error;
   
+  
+  namespace { // implementation helpers... 
+    
+    using diagn::Block;
+    
+    /** helper to find Block entries
+     *  based on the storage used by the buffer,
+     *  which is maintained by this Block entry */
+    inline bool
+    identifyBlock (Block const& inQuestion, void* storage)
+    {
+      return inQuestion.accessMemory() == storage;
+    }
+    
+    /** build a searching predicate */
+    inline function
+    search_for_block_using_this_storage (void* storage)
+    {
+      return bind (identifyBlock, _1, storage);
+    }
+    
+    template
+    inline Block*
+    pick_Block_by_storage (VEC& vec, void* bufferLocation)
+    {
+      typename VEC::iterator pos
+        = std::find_if (vec.begin(),vec.end()
+                       ,search_for_block_using_this_storage(bufferLocation));
+      if (pos!=vec.end())
+        return &(*pos);
+      else
+        return NULL;
+    }
+  }
+  
+  
+  
   namespace diagn {
     
-    typedef vector PoolVec;
+    typedef ScopedPtrVect  PoolVec;
     typedef ScopedHolder PoolHolder;
     
     /**
@@ -83,52 +126,31 @@ namespace engine {
         //  raise an runtime error, once BlockPool is initialised.
         
        ~BlockPool()
-          try {
-            if (blockList_)
-              for_each (*blockList_, discardBuffer);
-            }
-          ERROR_LOG_AND_IGNORE (test, "Shutdown of diagnostic BufferProvider allocation pool");
+         {
+           if (!verify_all_children_closed())
+             ERROR (test, "Block actively in use while shutting down BufferProvider "
+               "allocation pool. This might lead to Segfault and memory leaks.");
+         }
+        
         
-          
         Block&
         createBlock()
           {
-            Block* newBlock(0);
-            try
-              {
-                newBlock = new Block(memBlockSize_);  
-                blockList_->push_back (newBlock);
-              }
-            catch(...)
-              {
-                if (newBlock)
-                  delete newBlock;
-                throw;
-              }
-            ENSURE (newBlock);
-            return *newBlock;
+            return blockList_->manage (new Block(memBlockSize_));
           }
         
         
         Block*
-        find (void* bufferStorage)
+        find (void* bufferLocation)
           {
-            UNIMPLEMENTED ("find a block based on storage location");
+            return pick_Block_by_storage (*blockList_, bufferLocation);            
           }
         
         
         Block*
         transferResponsibility (Block* allocatedBlock)
           {
-            Block* extracted;
-            PoolVec& vec = *blockList_;
-            PoolVec::iterator pos = std::find (vec.begin(),vec.end(), allocatedBlock);
-            if (pos != vec.end())
-              {
-                extracted = *pos;
-                vec.erase(pos);
-              }
-            return extracted;
+            return blockList_->detach (allocatedBlock);
           }
         
         
@@ -145,16 +167,23 @@ namespace engine {
           }
         
       private:
-          static void
-          discardBuffer (Block* block)
+          bool
+          verify_all_children_closed()
             {
-              if (!block) return;
-              
-              if (block->was_used() && !block->was_closed())
-                ERROR (test, "Block actively in use while shutting down BufferProvider "
-                             "allocation pool. This might lead to Segfault and memory leaks.");
-              
-              delete block;
+            try {
+                if (blockList_)
+                  return and_all (*blockList_, is_in_sane_state);
+                }
+              ERROR_LOG_AND_IGNORE (test, "State verification of diagnostic BufferProvider allocation pool");
+              return true;
+            }
+          
+          
+          static bool
+          is_in_sane_state (Block const& block)
+            {
+              return !block.was_used()
+                  ||  block.was_closed();
             }
       };
 
@@ -272,9 +301,9 @@ namespace engine {
   }
   
   diagn::Block*
-  TrackingHeapBlockProvider::searchInOutSeqeuence (void* storage)
+  TrackingHeapBlockProvider::searchInOutSeqeuence (void* bufferLocation)
   {
-    UNIMPLEMENTED ("find block by storage location");
+    return pick_Block_by_storage (outSeq_, bufferLocation);            
   }
   
   

From 13b795016b4b3809604de933e26cb0ce69689417 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 19 Nov 2011 18:01:48 +0100
Subject: [PATCH 54/68] comment rewording

---
 src/lib/iter-adapter.hpp | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp
index b573ec7e7..1b92fd8ac 100644
--- a/src/lib/iter-adapter.hpp
+++ b/src/lib/iter-adapter.hpp
@@ -22,13 +22,14 @@
 
 /** @file iter-adapter.hpp
  ** Helper template(s) for creating lumiera forward iterators.
+ ** These are the foundation to build up iterator like types from scratch.
  ** Usually, these templates will be created and provided by a custom
  ** container type and accessed by the client through a typedef name
  ** "iterator" (similar to the usage within the STL). For more advanced
  ** usage, the providing container might want to subclass these iterators,
  ** e.g. to provide an additional, specialised API.
  ** 
- ** Depending on the concrete situation, there are several flavours
+ ** Depending on the concrete situation, several flavours are provided:
  ** - the IterAdapter retains an active callback connection to the
  **   controlling container, thus allowing arbitrary complex behaviour.
  ** - the RangeIter allows just to expose a range of elements defined
@@ -36,21 +37,32 @@
  ** - often, objects are managed internally by pointers, while allowing
  **   the clients to use direct references; to support this usage scenario,
  **   PtrDerefIter wraps an existing iterator, while dereferencing any value
- **   automatically on access.  
+ **   automatically on access.
+ ** 
+ ** There are many further ways of yielding a Lumiera forward iterator.
+ ** For example, lib::IterSource builds a "iterable" source of data elements,
+ ** while hiding the actual container or generator implementation behind a
+ ** vtable call. Besides, there are adapters for the most common usages
+ ** with STL containers, and such iterators can also be combined and
+ ** extended with the help of itertools.hpp
+ ** 
+ ** Basically every class in compliance with our specific iterator concept
+ ** can be used as a building block in this framework.
  ** 
  ** 
  ** \par Lumiera forward iterator concept
  ** 
  ** Similar to the STL, instead of using a common "Iterator" base class,
- ** instead we define a common set of functions and behaviour which can
+ ** we rather define a common set of functions and behaviour which can
  ** be expected from any such iterator. These rules are similar to STL's
  ** "forward iterator", with the addition of an bool check to detect
- ** iteration end. The latter s inspired by the \c hasNext() function
+ ** iteration end. The latter is inspired by the \c hasNext() function
  ** found in many current languages supporting iterators. In a similar
  ** vein (inspired from functional programming), we deliberately don't
  ** support the various extended iterator concepts from STL and boost
- ** (random access iterators, output iterators and the like). According
- ** to this concept, an iterator is a promise for pulling values,
+ ** (random access iterators, output iterators, arithmetics, difference
+ ** between iterators and the like). According to this concept,
+ ** an iterator is a promise for pulling values,
  ** and nothing beyond that.
  ** 
  ** - Any Lumiera forward iterator can be in a "exhausted" (invalid) state,
@@ -58,7 +70,7 @@
  **   created by the default ctor is always fixed to that state. This
  **   state is final and can't be reset, meaning that any iterator is
  **   a disposable one-way-off object.
- ** - iterators are copyable and comparable
+ ** - iterators are copyable and equality comparable
  ** - when an iterator is \em not in the exhausted state, it may be
  **   \em dereferenced to yield the "current" value.
  ** - moreover, iterators may be incremented until exhaustion.

From 0a1256f4e31e1881245f02a0ab26021cd753505c Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 19 Nov 2011 21:41:50 +0100
Subject: [PATCH 55/68] cover and verify detaching from ScopedPtrVect

---
 src/lib/scoped-ptrvect.hpp        |  3 +-
 tests/lib/scoped-ptrvect-test.cpp | 46 +++++++++++++++++++++++++++++--
 2 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/src/lib/scoped-ptrvect.hpp b/src/lib/scoped-ptrvect.hpp
index 8ed96b0db..dd04492a6 100644
--- a/src/lib/scoped-ptrvect.hpp
+++ b/src/lib/scoped-ptrvect.hpp
@@ -134,6 +134,7 @@ namespace lib {
        *         Otherwise, NULL will be returned and the
        *         collection of managed objects remains unaltered
        * @note EX_STRONG
+       * @todo TICKET #856 better return a Maybe instead of a pointer?
        */
       T*
       detach (void* objAddress)
@@ -177,8 +178,8 @@ namespace lib {
       typedef ConstIterType const_iterator;
       
       iterator       begin()        { return       iterator (allPtrs()); }
-      const_iterator begin()  const { return const_iterator::build_by_cast (allPtrs()); }
       iterator       end()          { return       iterator ( RIter() ); }
+      const_iterator begin()  const { return const_iterator::build_by_cast (allPtrs()); }
       const_iterator end()    const { return const_iterator::nil();      }
       
       
diff --git a/tests/lib/scoped-ptrvect-test.cpp b/tests/lib/scoped-ptrvect-test.cpp
index 48461e56b..63772334b 100644
--- a/tests/lib/scoped-ptrvect-test.cpp
+++ b/tests/lib/scoped-ptrvect-test.cpp
@@ -43,7 +43,9 @@ namespace test{
   
   /********************************************************************
    *  @test ScopedPtrVect manages the lifecycle of a number of objects.
-   *  @todo implement detaching of objects
+   *        The API is similar to a vector and allows for element access
+   *        and iteration. Individual elements can be detached and thus
+   *        removed from the responsibility of the container.
    */
   class ScopedPtrVect_test : public Test
     {
@@ -53,7 +55,7 @@ namespace test{
         {
           simpleUsage();
           iterating();
-//        detaching();
+          detaching();
         }
       
       
@@ -91,7 +93,7 @@ namespace test{
             holder.manage (new Dummy);
             holder.manage (new Dummy);
             CHECK (9 == holder.size());
-            CHECK (0!=checksum);
+            CHECK (0 < checksum);
           }
           CHECK (0==checksum);
         }
@@ -143,8 +145,46 @@ namespace test{
           CHECK (0==checksum);
         }
       
+      
+      void
+      detaching()
+        {
+          int id2, id3;
+          Dummy* extracted(0);
+          CHECK (0==checksum);
+          {
+            VectD holder;
+            CHECK (0 == checksum);
+            CHECK (isnil (holder));
+            
+            holder.manage (new Dummy);
+            holder.manage (new Dummy);
+            holder.manage (new Dummy);
+            holder.manage (new Dummy);
+            holder.manage (new Dummy);
+            CHECK (5 == holder.size());
+            CHECK (0 < checksum);
+            
+            id2 = holder[2].getVal();
+            id3 = holder[3].getVal();
+            
+            extracted = holder.detach(& holder[2]);
+            CHECK (id2 == extracted->getVal());
+            CHECK (id3 == holder[2].getVal());
+            CHECK (4 == holder.size());
+          }
+          CHECK (0 < checksum);     // not all dummies are dead
+          CHECK (id2 == checksum); //  #2 is alive!
+          
+          extracted->setVal(id2+id3);
+          CHECK (id2+id3 == checksum);
+          
+          delete extracted;
+          CHECK (0 == checksum);
+        }
     };
   
+  
   LAUNCHER (ScopedPtrVect_test, "unit common");
   
   

From 91b74ad7bdbcb73da66cd9850cd8b48c7df897b9 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 20 Nov 2011 01:35:52 +0100
Subject: [PATCH 56/68] implement missing parts of test/dummy buffer provider

---
 src/proc/engine/buffer-provider.cpp           | 32 +++++++++++++------
 src/proc/engine/buffer-provider.hpp           |  5 ++-
 src/proc/engine/buffhandle.hpp                | 18 +++++++++--
 .../engine/tracking-heap-block-provider.cpp   | 27 +++++++++++++---
 wiki/renderengine.html                        |  4 +--
 5 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp
index a32639550..b4eb794ca 100644
--- a/src/proc/engine/buffer-provider.cpp
+++ b/src/proc/engine/buffer-provider.cpp
@@ -39,8 +39,12 @@ namespace engine {
   
   LUMIERA_ERROR_DEFINE (BUFFER_MANAGEMENT, "Problem providing working buffers");
   
-
   
+  /** build a new provider instance, managing a family of buffers.
+   *  The metadata of these buffers is organised hierarchically based on
+   *  chained hash values, using the #implementationID as a seed.
+   * @param implementationID symbolic ID setting these family of buffers apart.
+   */
   BufferProvider::BufferProvider (Literal implementationID)
     : meta_(new BufferMetadata (implementationID))
     { }
@@ -53,9 +57,9 @@ namespace engine {
    *          currently locked and usable by client code
    */
   bool
-  BufferProvider::verifyValidity (BufferDescriptor const&)
+  BufferProvider::verifyValidity (BufferDescriptor const& bufferID)
   {
-    UNIMPLEMENTED ("BufferProvider basic and default implementation");
+    return meta_->isLocked (bufferID);
   }
   
   
@@ -81,6 +85,12 @@ namespace engine {
   }
   
   
+  /** callback from implementation to build and enrol a BufferHandle,
+   * to be returned to the client as result of the #lockBuffer call.
+   * Performs the necessary metadata state transition leading from an
+   * abstract buffer type to a metadata::Entry corresponding to an
+   * actual buffer, which is locked for exclusive use by one client. 
+   */ 
   BuffHandle
   BufferProvider::buildHandle (HashVal typeID, void* storage, LocalKey const& implID)
   {
@@ -177,7 +187,7 @@ namespace engine {
   bool
   BufferProvider::was_created_by_this_provider (BufferDescriptor const& descr)  const
   {
-    return isSameObject (this, descr.provider_);
+    return isSameObject (*this, *descr.provider_);
   }
     
   
@@ -194,18 +204,20 @@ namespace engine {
   
   
   void
-  BuffHandle::emit()
+  BufferDescriptor::emit (BuffHandle const& handle)  const
   {
-    UNIMPLEMENTED ("forward buffer emit call to buffer provider");
+    REQUIRE (verifyValidity());
+    provider_->emitBuffer(handle);
   }
   
   
   void
-  BuffHandle::release()
+  BufferDescriptor::release (BuffHandle const& handle)  const
   {
-    UNIMPLEMENTED ("forward buffer release call to buffer provider");
+    REQUIRE (verifyValidity());
+    provider_->releaseBuffer(handle);
   }
   
-
-
+  
+  
 } // namespace engine
diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp
index ce67928bb..933841423 100644
--- a/src/proc/engine/buffer-provider.hpp
+++ b/src/proc/engine/buffer-provider.hpp
@@ -22,7 +22,7 @@
 
 /** @file buffer-provider.hpp
  ** Abstraction to represent buffer management and lifecycle within the render engine.
- ** It turns out that --  throughout the render engine implementation -- we never need
+ ** It turns out that -- throughout the render engine implementation -- we never need
  ** direct access to the buffers holding media data. Buffers are just some entity to be \em managed,
  ** i.e. "allocated", "locked" and "released"; the actual meaning of these operations is an implementation detail.
  ** The code within the render engine just pushes around BufferHandle objects, which act as a front-end,
@@ -71,7 +71,10 @@ namespace engine {
    * - "locking" a buffer to yield a buffer handle
    * - dereferencing this smart-handle class
    * 
+   * @warning all of BufferProvider is assumed to run within a threadsafe environment.
+   * 
    * @todo as of 6/2011 buffer management within the engine is still a bit vague
+   * @todo as of 11/11 thread safety within the engine remains to be clarified
    */
   class BufferProvider
     : boost::noncopyable
diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp
index a12d26df8..a1c64ac17 100644
--- a/src/proc/engine/buffhandle.hpp
+++ b/src/proc/engine/buffhandle.hpp
@@ -54,6 +54,7 @@ namespace engine {
   
   typedef size_t HashVal;           ////////////TICKET #722
   
+  class BuffHandle;
   class BufferProvider;
   
   
@@ -86,6 +87,9 @@ namespace engine {
       
       bool verifyValidity()  const;
       
+      void emit   (BuffHandle const&)  const;
+      void release (BuffHandle const&)  const;
+      
       operator HashVal()  const { return subClassification_; }
     };
   
@@ -140,8 +144,18 @@ namespace engine {
       
       
       
-      void emit();
-      void release();
+      void
+      emit()
+        {
+          REQUIRE (pBuffer_);
+          descriptor_.emit (*this);
+        }
+      
+      void release()
+        {
+          REQUIRE (pBuffer_);
+          descriptor_.release (*this);
+        }
       
       
       template
diff --git a/src/proc/engine/tracking-heap-block-provider.cpp b/src/proc/engine/tracking-heap-block-provider.cpp
index 88769ff1a..15c1e24d1 100644
--- a/src/proc/engine/tracking-heap-block-provider.cpp
+++ b/src/proc/engine/tracking-heap-block-provider.cpp
@@ -107,12 +107,14 @@ namespace engine {
     class BlockPool
       : public lib::BoolCheckable
       {
+        uint maxAllocCount_;
         size_t memBlockSize_;
         PoolHolder blockList_;
         
       public:
         BlockPool()
-          : memBlockSize_(0)
+          : maxAllocCount_(0) // unlimited by default
+          , memBlockSize_(0)
           , blockList_()
           { }
         
@@ -127,12 +129,26 @@ namespace engine {
         
        ~BlockPool()
          {
-           if (!verify_all_children_closed())
+           if (!verify_all_children_idle())
              ERROR (test, "Block actively in use while shutting down BufferProvider "
                "allocation pool. This might lead to Segfault and memory leaks.");
          }
         
         
+        uint 
+        prepare_for (uint number_of_expected_buffers)
+          {
+            if (maxAllocCount_ && 
+                maxAllocCount_ < blockList_->size() + number_of_expected_buffers)
+              {
+                ASSERT (maxAllocCount_ >= blockList_->size());
+                return maxAllocCount_ - blockList_->size();
+              }
+            // currently no hard limit imposed
+            return number_of_expected_buffers;
+          }
+        
+        
         Block&
         createBlock()
           {
@@ -168,7 +184,7 @@ namespace engine {
         
       private:
           bool
-          verify_all_children_closed()
+          verify_all_children_idle()
             {
             try {
                 if (blockList_)
@@ -217,9 +233,10 @@ namespace engine {
   /* ==== Implementation of the BufferProvider interface ==== */
   
   uint
-  TrackingHeapBlockProvider::prepareBuffers(uint, lib::HashVal)
+  TrackingHeapBlockProvider::prepareBuffers(uint requestedAmount, HashVal typeID)
   {
-    UNIMPLEMENTED ("pre-register storage for buffers of a specific kind");   
+    diagn::BlockPool& responsiblePool = getBlockPoolFor (typeID);
+    return responsiblePool.prepare_for (requestedAmount);
   }
 
   
diff --git a/wiki/renderengine.html b/wiki/renderengine.html
index 6abd6656c..a1a95a954 100644
--- a/wiki/renderengine.html
+++ b/wiki/renderengine.html
@@ -1133,7 +1133,7 @@ Beyond that, it can be necessary to associate at least a state flag with //indiv
 __Note__: while the API to access this service is uniform, conceptually there is a difference between just using the (shared) type information and associating individual metadata, like the buffer state. Type-~IDs, once allocated, will never be discarded (within the lifetime of an Lumiera application instance -- buffer associations aren't persistent). To the contrary, individual metadata //will be discarded,// when releasing the corresponding buffer. According to the ''prototype pattern'', individual metadata is treated as a one-way-off specialisation.
 
-
+
It turns out that --  throughout the render engine implementation -- we never need direct access to the buffers holding actual media data. Buffers are just some entity to be //managed,// i.e. "allocated", "locked" and "released"; the //actual meaning of these operations can be left to the implementation.// The code within the render engine just pushes around ''smart-prt like handles''. These [[buffer handles|BuffHandle]] act as a front-end, being created by and linked to a buffer provider implementation. There is no need to manage the lifecycle of buffers automatically, because the use of buffers is embedded into the render calculation cycle, which follows a rather strict protocol anyway. Relying on the [[capabilities of the scheduler|SchedulerRequirements]], the sequence of individual jobs in the engine ensures...
 * that the availability of a buffer was ensured prior to planning a job ("buffer allocation")
 * that a buffer handle was obtained ("locked") prior to any operation requiring a buffer
@@ -1142,7 +1142,7 @@ __Note__: while the API to access this service is uniform, conceptually there is
 !operations
 While BufferProvider is an interface meant to be backed by various different kinds of buffer and memory management approaches, there is a common set of operations to be supported by any of them
 ;announcing
-:client code may announce beforehand that it expects to get a certain amount of buffers. Usually this causes some allocations to happen right away, or it might trigger similar mechanisms to ensure availability; the BufferProvider will then return the actual number of buffers guaranteed to be available. This announcing step is optional an can happen any time before or even after using the buffers and it can be repeated with different values to adjust to changing requirements. (Currently 9/2011 this is meant to be global for the whole BufferProvider, but it might happen that we need to break that down to individual clients)
+:client code may announce beforehand that it expects to get a certain amount of buffers. Usually this causes some allocations to happen right away, or it might trigger similar mechanisms to ensure availability; the BufferProvider will then return the actual number of buffers guaranteed to be available. This announcing step is optional an can happen any time before or even after using the buffers and it can be repeated with different values to adjust to changing requirements. Thus the announced amount of buffers always denotes //additional buffers,// on top of what is actively used at the moment. This safety margin of available buffers usually is accounted separately for each distinct kind of buffer (buffer type). There is no tracking as to which specific client requested buffers, beyond the buffer type.
 ;locking
 :this operation actually makes a buffer available for a specific client and returns a [[buffer handle|BuffHandle]]. The corresponding buffer is marked as used and can't be locked again unless released. If necessary, at that point the BufferProvider might allocate memory to accommodate (especially when the buffers weren't announced beforehand). The locking may fail and raise an exception. You may expect failure to be unlikely when buffers have been //announced beforehand.// To support additional sanity checks, the client may provide a token-ID with the lock-operation. This token may be retrieved later and it may be used to ensure the buffer is actually locked for //this token.//
 ;attaching

From d6de8c8d1a42b6a4a8230dc13d4359a8f1d42169 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Mon, 21 Nov 2011 02:28:44 +0100
Subject: [PATCH 57/68] implement some missing nits and bits

---
 src/proc/engine/buffer-provider.cpp           |  7 ++++++
 src/proc/engine/buffer-provider.hpp           |  2 +-
 src/proc/engine/buffhandle.hpp                | 13 ++++++-----
 .../engine/tracking-heap-block-provider.hpp   | 22 +++++++++----------
 4 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp
index b4eb794ca..e7f7f9cb2 100644
--- a/src/proc/engine/buffer-provider.cpp
+++ b/src/proc/engine/buffer-provider.cpp
@@ -203,6 +203,13 @@ namespace engine {
   }
   
   
+  size_t
+  BufferDescriptor::determineBufferSize() const
+  {
+    return provider_->getBufferSize (*this);
+  }
+  
+  
   void
   BufferDescriptor::emit (BuffHandle const& handle)  const
   {
diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp
index 933841423..b52948911 100644
--- a/src/proc/engine/buffer-provider.hpp
+++ b/src/proc/engine/buffer-provider.hpp
@@ -119,9 +119,9 @@ namespace engine {
       /* === API for BuffHandle internal access === */
       
       bool verifyValidity (BufferDescriptor const&);
+      size_t getBufferSize (HashVal typeID)  const;
       
     protected:
-      size_t getBufferSize (HashVal typeID)  const;
       BuffHandle buildHandle (HashVal typeID, void* storage, LocalKey const&);
       
       bool was_created_by_this_provider (BufferDescriptor const&)  const;
diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp
index a1c64ac17..2e33b54d6 100644
--- a/src/proc/engine/buffhandle.hpp
+++ b/src/proc/engine/buffhandle.hpp
@@ -86,6 +86,7 @@ namespace engine {
       // using standard copy operations
       
       bool verifyValidity()  const;
+      size_t determineBufferSize() const;
       
       void emit   (BuffHandle const&)  const;
       void release (BuffHandle const&)  const;
@@ -190,7 +191,7 @@ namespace engine {
       size_t
       size()  const
         {
-          UNIMPLEMENTED ("forward to the buffer provider for storage size diagnostics");
+          return descriptor_.determineBufferSize();
         }
       
     };
@@ -212,15 +213,17 @@ namespace engine {
   }
   
   
-  /** convenience shortcut: access the buffer contents in a typesafe fashion.
-   *  This is equivalent to a plain dereferentiation with additional metadata check
-   * @throw error::Logic in case of type mismatch \c LUMIERA_ERROR_WRONG_TYPE
+  /** 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()
   {
-    UNIMPLEMENTED ("convenience shortcut to access buffer contents typesafe");
+    REQUIRE (pBuffer_);
+    return *reinterpret_cast (pBuffer_);
   }
   
   
diff --git a/src/proc/engine/tracking-heap-block-provider.hpp b/src/proc/engine/tracking-heap-block-provider.hpp
index bdda28c4a..70dec474d 100644
--- a/src/proc/engine/tracking-heap-block-provider.hpp
+++ b/src/proc/engine/tracking-heap-block-provider.hpp
@@ -46,7 +46,6 @@
 #include "lib/error.hpp"
 #include "proc/engine/buffer-provider.hpp"
 #include "lib/scoped-ptrvect.hpp"
-#include "lib/access-casted.hpp"
 
 #include 
 #include 
@@ -75,37 +74,38 @@ namespace engine {
       {
         scoped_array storage_;
         
-        bool was_locked_;
+        bool was_released_;
         
       public:
         explicit
         Block(size_t bufferSize)
-          : storage_(new char[bufferSize])
-          , was_locked_(false)
+          : storage_(bufferSize? new char[bufferSize] : NULL)
+          , was_released_(false)
           { }
         
         bool
         was_used()  const
           {
-            return was_locked_;
+            return bool(storage_);
           }
         
         bool
         was_closed()  const
           {
-            return was_locked_;
+            return was_released_;
           }
         
         void*
         accessMemory()  const
           {
+            REQUIRE (storage_, "Block was never prepared for use");
             return storage_.get();
           }
         
         void
         markReleased()
           {
-            UNIMPLEMENTED ("diagn::Block accounting functionality");
+            was_released_ = true;
           }
       };
       
@@ -174,12 +174,10 @@ namespace engine {
       throw error::Invalid ("Buffer with the given ID not yet emitted");
     
     diagn::Block& memoryBlock = access_or_create (bufferID);
-    TY* converted = util::AccessCasted::access (memoryBlock.accessMemory());
+    TY* converted = reinterpret_cast (memoryBlock.accessMemory());
     
-    if (!converted)
-      throw error::Fatal ("unable to access the target location with the required conversion");
-    else
-      return *converted;
+    REQUIRE (converted);
+    return *converted;
   }
   
   

From 2ae1e3c8f937d1d1cc5fe51a21f7db2dcfb303dc Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Mon, 21 Nov 2011 03:26:08 +0100
Subject: [PATCH 58/68] test/dummy buffer provider finished and passes test

---
 src/proc/engine/buffhandle.hpp                |  9 +-
 .../engine/diagnostic-buffer-provider.cpp     |  6 +-
 .../engine/tracking-heap-block-provider.cpp   | 34 ++++----
 .../engine/tracking-heap-block-provider.hpp   |  4 +-
 .../tracking-heap-block-provider-test.cpp     | 87 ++++++++++++-------
 5 files changed, 82 insertions(+), 58 deletions(-)

diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp
index 2e33b54d6..affbf8dd6 100644
--- a/src/proc/engine/buffhandle.hpp
+++ b/src/proc/engine/buffhandle.hpp
@@ -154,8 +154,13 @@ namespace engine {
       
       void release()
         {
-          REQUIRE (pBuffer_);
-          descriptor_.release (*this);
+          if (pBuffer_)
+            {
+              REQUIRE (isValid());
+              descriptor_.release (*this);
+              pBuffer_ = 0;
+            }
+          ENSURE (!isValid());
         }
       
       
diff --git a/src/proc/engine/diagnostic-buffer-provider.cpp b/src/proc/engine/diagnostic-buffer-provider.cpp
index d8933733c..f00dcb8a3 100644
--- a/src/proc/engine/diagnostic-buffer-provider.cpp
+++ b/src/proc/engine/diagnostic-buffer-provider.cpp
@@ -103,21 +103,21 @@ namespace engine {
   bool
   DiagnosticBufferProvider::buffer_was_used (uint bufferID)  const
     {
-      return pImpl_->access_or_create(bufferID).was_used();
+      return pImpl_->access_emitted(bufferID).was_used();
     }
   
   
   bool
   DiagnosticBufferProvider::buffer_was_closed (uint bufferID)  const
     {
-      return pImpl_->access_or_create(bufferID).was_closed();
+      return pImpl_->access_emitted(bufferID).was_closed();
     }
   
   
   void*
   DiagnosticBufferProvider::accessMemory (uint bufferID)  const
     {
-      return pImpl_->access_or_create(bufferID).accessMemory();
+      return pImpl_->access_emitted(bufferID).accessMemory();
     }
   
 
diff --git a/src/proc/engine/tracking-heap-block-provider.cpp b/src/proc/engine/tracking-heap-block-provider.cpp
index 15c1e24d1..f9e951889 100644
--- a/src/proc/engine/tracking-heap-block-provider.cpp
+++ b/src/proc/engine/tracking-heap-block-provider.cpp
@@ -32,7 +32,6 @@
 #include "proc/engine/tracking-heap-block-provider.hpp"
 
 #include 
-#include 
 #include 
 #include 
 
@@ -41,9 +40,6 @@ using util::and_all;
 using std::vector;
 using lib::ScopedHolder;
 using lib::ScopedPtrVect;
-using std::tr1::function;
-using std::tr1::bind;
-using std::tr1::placeholders::_1;
 
 
 
@@ -57,12 +53,11 @@ namespace engine {
     using diagn::Block;
     
     /** helper to find Block entries
-     *  based on the storage used by the buffer,
-     *  which is maintained by this Block entry */
+     *  based on their raw memory address */
     inline bool
     identifyBlock (Block const& inQuestion, void* storage)
     {
-      return inQuestion.accessMemory() == storage;
+      return storage == &inQuestion;
     }
     
     /** build a searching predicate */
@@ -74,11 +69,11 @@ namespace engine {
     
     template
     inline Block*
-    pick_Block_by_storage (VEC& vec, void* bufferLocation)
+    pick_Block_by_storage (VEC& vec, void* blockLocation)
     {
       typename VEC::iterator pos
         = std::find_if (vec.begin(),vec.end()
-                       ,search_for_block_using_this_storage(bufferLocation));
+                       ,search_for_block_using_this_storage(blockLocation));
       if (pos!=vec.end())
         return &(*pos);
       else
@@ -157,9 +152,9 @@ namespace engine {
         
         
         Block*
-        find (void* bufferLocation)
+        find (void* blockLocation)
           {
-            return pick_Block_by_storage (*blockList_, bufferLocation);            
+            return pick_Block_by_storage (*blockList_, blockLocation);            
           }
         
         
@@ -210,6 +205,8 @@ namespace engine {
   namespace { // Details of allocation and accounting
     
     const uint MAX_BUFFERS = 50;
+    
+    diagn::Block emptyPlaceholder(0);
   
   } // (END) Details of allocation and accounting
   
@@ -281,13 +278,12 @@ namespace engine {
   }
 
   diagn::Block&
-  TrackingHeapBlockProvider::access_or_create (uint bufferID)
+  TrackingHeapBlockProvider::access_emitted (uint bufferID)
   {
-    while (!withinOutputSequence (bufferID))
-      outSeq_.manage (new diagn::Block(0));   /////////TICKET #856 really need a better way of returning a fallback
-    
-    ENSURE (withinOutputSequence (bufferID));
-    return outSeq_[bufferID];
+    if (!withinOutputSequence (bufferID))
+      return emptyPlaceholder;
+    else
+      return outSeq_[bufferID];
   }
   
   bool
@@ -318,9 +314,9 @@ namespace engine {
   }
   
   diagn::Block*
-  TrackingHeapBlockProvider::searchInOutSeqeuence (void* bufferLocation)
+  TrackingHeapBlockProvider::searchInOutSeqeuence (void* blockLocation)
   {
-    return pick_Block_by_storage (outSeq_, bufferLocation);            
+    return pick_Block_by_storage (outSeq_, blockLocation);            
   }
   
   
diff --git a/src/proc/engine/tracking-heap-block-provider.hpp b/src/proc/engine/tracking-heap-block-provider.hpp
index 70dec474d..a42fb65f8 100644
--- a/src/proc/engine/tracking-heap-block-provider.hpp
+++ b/src/proc/engine/tracking-heap-block-provider.hpp
@@ -144,7 +144,7 @@ namespace engine {
       
       size_t emittedCnt()  const;
       
-      diagn::Block& access_or_create (uint bufferID);
+      diagn::Block& access_emitted (uint bufferID);
       
       template
       TY&  accessAs (uint bufferID);
@@ -173,7 +173,7 @@ namespace engine {
     if (!withinOutputSequence (bufferID))
       throw error::Invalid ("Buffer with the given ID not yet emitted");
     
-    diagn::Block& memoryBlock = access_or_create (bufferID);
+    diagn::Block& memoryBlock = access_emitted (bufferID);
     TY* converted = reinterpret_cast (memoryBlock.accessMemory());
     
     REQUIRE (converted);
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 405c4ceb9..2d48be480 100644
--- a/tests/components/proc/engine/tracking-heap-block-provider-test.cpp
+++ b/tests/components/proc/engine/tracking-heap-block-provider-test.cpp
@@ -23,34 +23,19 @@
 
 #include "lib/error.hpp"
 #include "lib/test/run.hpp"
-//#include "lib/test/test-helper.hpp"
-//#include "lib/util-foreach.hpp"
-//#include "proc/play/diagnostic-output-slot.hpp"
 #include "proc/engine/tracking-heap-block-provider.hpp"
 #include "proc/engine/testframe.hpp"
-//#include "proc/engine/diagnostic-buffer-provider.hpp"
 #include "proc/engine/buffhandle.hpp"
-//#include "proc/engine/bufftable.hpp"
 
-//#include 
-//#include 
-#include 
 #include 
+#include 
 
-//using boost::format;
-//using std::string;
-//using std::cout;
 using std::rand;
-//using util::for_each;
 
 
 namespace engine{
 namespace test  {
   
-//  using lib::AllocationCluster;
-//  using mobject::session::PEffect;
-//  using ::engine::BuffHandle;
-//  using lumiera::error::LUMIERA_ERROR_LIFECYCLE;
   
   
   namespace { // Test fixture
@@ -62,7 +47,7 @@ namespace test  {
     
     
     bool 
-    has_expectedContent (uint nr, diagn::Block& memoryBlock) 
+    has_expectedContent (uint nr, diagn::Block& memoryBlock)
     {
       void* mem = memoryBlock.accessMemory();
       uint data = *static_cast (mem);
@@ -71,7 +56,7 @@ namespace test  {
     }
     
     bool
-    verifyUsedBlock (uint nr, diagn::Block& memoryBlock) 
+    verifyUsedBlock (uint nr, diagn::Block& memoryBlock)
     {
       return memoryBlock.was_used()
           && memoryBlock.was_closed()
@@ -113,7 +98,7 @@ namespace test  {
           provider.emitBuffer   (testBuff);
           provider.releaseBuffer(testBuff);
           
-          diagn::Block& block0 = provider.access_or_create(0);
+          diagn::Block& block0 = provider.access_emitted(0);
           CHECK (testData(dataID) == block0.accessMemory());
         }
       
@@ -138,7 +123,7 @@ namespace test  {
           
           for (uint nr=0; nr(0) = 20;
-          provider.accessAs(1) = 21;
-          provider.accessAs(2) = 22;
-          provider.accessAs(3) = 23;
-          provider.accessAs(4) = 24;
+          // buffers are locked, 
+          // but still within the per-type allocation pool
+          // while the output sequence is still empty
+          CHECK (!provider.access_emitted(0).was_used());
+          CHECK (!provider.access_emitted(1).was_used());
+          CHECK (!provider.access_emitted(2).was_used());
+          CHECK (!provider.access_emitted(3).was_used());
+          CHECK (!provider.access_emitted(4).was_used());
           
+          // can use the buffers for real
           bu1.accessAs() = 1;
           bu2.accessAs() = 2;
           bu3.accessAs() = 3;
           bu4.accessAs() = 4;
           bu5.accessAs() = 5;
           
-          CHECK (20 == provider.accessAs(0));
-          CHECK (21 == provider.accessAs(1));
-          CHECK (22 == provider.accessAs(2));
-          CHECK (23 == provider.accessAs(3));
-          CHECK (24 == provider.accessAs(4));
+          CHECK (0 == provider.emittedCnt());
           
+          // now emit buffers in shuffled order
           provider.emitBuffer (bu3);
           provider.emitBuffer (bu1);
           provider.emitBuffer (bu5);
           provider.emitBuffer (bu4);
           provider.emitBuffer (bu2);
           
+          CHECK (5 == provider.emittedCnt());
+          
           CHECK (3 == provider.accessAs(0));
           CHECK (1 == provider.accessAs(1));
           CHECK (5 == provider.accessAs(2));
           CHECK (4 == provider.accessAs(3));
           CHECK (2 == provider.accessAs(4));
+          
+          CHECK ( provider.access_emitted(0).was_used());
+          CHECK ( provider.access_emitted(1).was_used());
+          CHECK ( provider.access_emitted(2).was_used());
+          CHECK ( provider.access_emitted(3).was_used());
+          CHECK ( provider.access_emitted(4).was_used());
+          
+          CHECK (!provider.access_emitted(0).was_closed());
+          CHECK (!provider.access_emitted(1).was_closed());
+          CHECK (!provider.access_emitted(2).was_closed());
+          CHECK (!provider.access_emitted(3).was_closed());
+          CHECK (!provider.access_emitted(4).was_closed());
+          
+          bu5.release();
+          CHECK (!provider.access_emitted(0).was_closed());
+          CHECK (!provider.access_emitted(1).was_closed());
+          CHECK ( provider.access_emitted(2).was_closed());
+          CHECK (!provider.access_emitted(3).was_closed());
+          CHECK (!provider.access_emitted(4).was_closed());
+          
+          bu2.release();
+          bu2.release();
+          bu5.release();
+          CHECK (!provider.access_emitted(0).was_closed());
+          CHECK (!provider.access_emitted(1).was_closed());
+          CHECK ( provider.access_emitted(2).was_closed());
+          CHECK (!provider.access_emitted(3).was_closed());
+          CHECK ( provider.access_emitted(4).was_closed());
+          
+          CHECK (!bu2);
+          CHECK (bu3);
+          
+          bu1.release();
+          bu3.release();
+          bu4.release();
+          
+          CHECK (5 == provider.emittedCnt());
         }
     };
   

From 74702ebecdd06ba7ec081c6588e836812b2ffc0a Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Thu, 24 Nov 2011 03:33:23 +0100
Subject: [PATCH 59/68] address the next test...

---
 src/proc/engine/buffhandle.hpp                             | 7 ++++++-
 .../proc/engine/buffer-provider-protocol-test.cpp          | 7 +++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp
index affbf8dd6..eb87ffec2 100644
--- a/src/proc/engine/buffhandle.hpp
+++ b/src/proc/engine/buffhandle.hpp
@@ -52,6 +52,9 @@
 
 namespace engine {
   
+  namespace error = lumiera::error;
+  using error::LUMIERA_ERROR_LIFECYCLE;
+  
   typedef size_t HashVal;           ////////////TICKET #722
   
   class BuffHandle;
@@ -227,7 +230,9 @@ namespace engine {
   BU&
   BuffHandle::accessAs()
   {
-    REQUIRE (pBuffer_);
+    if (!pBuffer_)
+      throw error::Logic ("buffer not (yet) locked for access by clients"
+                         , LUMIERA_ERROR_LIFECYCLE);
     return *reinterpret_cast (pBuffer_);
   }
   
diff --git a/tests/components/proc/engine/buffer-provider-protocol-test.cpp b/tests/components/proc/engine/buffer-provider-protocol-test.cpp
index fdfba1e67..6732668b6 100644
--- a/tests/components/proc/engine/buffer-provider-protocol-test.cpp
+++ b/tests/components/proc/engine/buffer-provider-protocol-test.cpp
@@ -76,7 +76,6 @@ namespace test  {
       virtual void
       run (Arg) 
         {
-          UNIMPLEMENTED ("build a diagnostic buffer provider and perform a full lifecycle");
           verifySimpleUsage();
           verifyStandardCase();
         }
@@ -93,10 +92,10 @@ namespace test  {
           BuffHandle buff = provider.lockBufferFor();
           CHECK (buff.isValid());
           CHECK (sizeof(TestFrame) <= buff.size());
-          buff.create() = testData(0);
+          buff.accessAs() = testData(0);
           
-          TestFrame& storage = buff.accessAs();
-          CHECK (testData(0) == storage);
+          TestFrame& content = buff.accessAs();
+          CHECK (testData(0) == content);
           
           buff.release();
           CHECK (!buff.isValid());

From eed6d8cd1e17f6aad8377cc5acd1901423bca730 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 25 Nov 2011 17:16:33 +0100
Subject: [PATCH 60/68] split out obsolete ChannelDescriptor for later
 refactoring

Meanwhile, BuffHanle became way more concrete,
making the separation of any kind of buffer or channel
type management concievable.

Thus: extract the obsolete ChannelDescriptor
and use switch at any location where the old
(superseeded) buffer handle is still referred
---
 src/proc/engine/bufftable-obsolete.hpp        |   2 +-
 src/proc/engine/channel-descriptor.hpp        | 242 ++++++++++++++++++
 src/proc/engine/nodeinvocation.hpp            |   2 +-
 src/proc/engine/nodeoperation.hpp             |   2 +-
 .../proc/engine/node-basic-test.cpp           |   2 +-
 5 files changed, 246 insertions(+), 4 deletions(-)
 create mode 100644 src/proc/engine/channel-descriptor.hpp

diff --git a/src/proc/engine/bufftable-obsolete.hpp b/src/proc/engine/bufftable-obsolete.hpp
index bd79683ee..2b43ee6d1 100644
--- a/src/proc/engine/bufftable-obsolete.hpp
+++ b/src/proc/engine/bufftable-obsolete.hpp
@@ -26,7 +26,7 @@
 
 
 #include "lib/error.hpp"
-#include "proc/engine/buffhandle.hpp"
+#include "proc/engine/channel-descriptor.hpp"
 #include "proc/engine/procnode.hpp"
 
 #include 
diff --git a/src/proc/engine/channel-descriptor.hpp b/src/proc/engine/channel-descriptor.hpp
new file mode 100644
index 000000000..1631690dc
--- /dev/null
+++ b/src/proc/engine/channel-descriptor.hpp
@@ -0,0 +1,242 @@
+/*
+  CHANNEL-DESCRIPTOR.hpp  -  Channel / Buffer type representation for the engine
+
+  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.hpp
+ ** Various bits needed to support the buffer management within the render nodes.
+ ** When pulling data from predecessor nodes and calculating new data, each render node
+ ** needs several input and output buffers. These may be allocated and provided by several
+ ** different "buffer providers" (for example the frame cache). Typically, the real buffers
+ ** will be passed as parameters to the actual job instance when scheduled, drawing on the
+ ** results of prerequisite jobs. Yet the actual job implementation remains agnostic with
+ ** respect to the way actual buffers are provided; the invocation just pushes BuffHandle
+ ** objects around. The actual render function gets an array of C-pointers to the actual
+ ** buffers, and for accessing those buffers, the node needs to keep a table of buffer
+ ** pointers, and for releasing the buffers later on, we utilise the buffer handles.
+ ** The usage pattern of those buffer pointer tables is stack-like, thus the actual
+ ** implementation utilises a single large buffer pointer array per pull() call
+ ** sequence and dynamically claims small chunks for each node.
+ ** 
+ ** @see nodewiring-def.hpp
+ ** @see nodeoperation.hpp
+ ** @see bufftable.hpp       storage for the buffer table
+ ** @see engine::RenderInvocation
+ */
+
+#ifndef ENGINE_CHANNEL_DESCRIPTOR_H
+#define ENGINE_CHANNEL_DESCRIPTOR_H
+
+
+#include "lib/error.hpp"
+#include "lib/streamtype.hpp"
+#include "lib/bool-checkable.hpp"
+
+
+namespace engine {
+  
+  namespace error = lumiera::error;
+  using error::LUMIERA_ERROR_LIFECYCLE;
+  
+  typedef size_t HashVal;           ////////////TICKET #722
+  
+  class BuffHandle;
+  class BufferProvider;
+  
+  
+  
+  /**
+   * An opaque descriptor to identify the type and further properties of a data buffer.
+   * For each kind of buffer, there is somewhere a BufferProvider responsible for the
+   * actual storage management. This provider may "lock" a buffer for actual use,
+   * returning a BuffHandle.
+   * @note this descriptor and especially the #subClassification_ is really owned
+   *       by the BufferProvider, which may use (and even change) the opaque contents
+   *       to organise the internal buffer management.
+   * 
+   * @todo try to move that definition into buffer-provider.hpp   ////////////////////////////////////TICKET #249
+   */
+  class BufferDescriptor
+    {
+      BufferProvider* provider_;
+      HashVal subClassification_;
+      
+      BufferDescriptor(BufferProvider& manager, HashVal detail)
+        : provider_(&manager)
+        , subClassification_(detail)
+      { }
+      
+      friend class BufferProvider;
+      
+    public:
+      // using standard copy operations
+      
+      bool verifyValidity()  const;
+      size_t determineBufferSize() const;
+      
+      void emit   (BuffHandle const&)  const;
+      void release (BuffHandle const&)  const;
+      
+      operator HashVal()  const { return subClassification_; }
+    };
+  
+  
+  
+  class ProcNode;
+  typedef ProcNode* PNode;
+  
+  
+  struct ChannelDescriptor  ///////TODO really need to define that here? it is needed for node wiring only
+    {
+      const lumiera::StreamType * bufferType;                /////////////////////////////////////////TICKET #828
+    };
+  
+  struct InChanDescriptor : ChannelDescriptor
+    {
+      PNode dataSrc;    ///< the ProcNode to pull this input from
+      uint srcChannel; ///<  output channel to use on the predecessor node
+    };
+  
+  
+  
+  
+  
+  /**
+   * Handle for a buffer for processing data, abstracting away the actual implementation.
+   * The real buffer pointer can be retrieved by dereferencing this smart-handle class.
+   * 
+   * @todo as of 6/2011 it isn't clear how buffer handles are actually created
+   *       and how the lifecycle (and memory) management works                  //////////////////////TICKET #249 rework BuffHandle creation and usage
+   */
+  class BuffHandle
+    : public lib::BoolCheckable
+    {
+      typedef lumiera::StreamType::ImplFacade::DataBuffer Buff;
+      
+      BufferDescriptor descriptor_;
+      Buff* pBuffer_; 
+      
+      
+    public:
+      typedef Buff* PBuff;
+      
+      /** @internal a buffer handle may be obtained by "locking"
+       *  a buffer from the corresponding BufferProvider */
+      BuffHandle(BufferDescriptor const& typeInfo, void* storage = 0)
+        : descriptor_(typeInfo)
+        , pBuffer_(static_cast(storage))
+        { }
+      
+      // using standard copy operations
+      
+      
+      
+      void
+      emit()
+        {
+          REQUIRE (pBuffer_);
+          descriptor_.emit (*this);
+        }
+      
+      void release()
+        {
+          if (pBuffer_)
+            {
+              REQUIRE (isValid());
+              descriptor_.release (*this);
+              pBuffer_ = 0;
+            }
+          ENSURE (!isValid());
+        }
+      
+      
+      template
+      BU& create();
+      
+      template
+      BU& accessAs();
+      
+      
+      //////////////////////////////////////////TICKET #249 this operator looks obsolete. The Buff type is a placeholder type,
+      //////////////////////////////////////////TODO         it should never be accessed directly from within Lumiera engine code
+      Buff&
+      operator* ()  const
+        {
+          ENSURE (pBuffer_);
+          return *pBuffer_;
+        }
+      
+      bool
+      isValid()  const
+        {
+          return bool(pBuffer_)
+              && descriptor_.verifyValidity();
+        }
+      
+      HashVal
+      entryID()  const
+        {
+          return descriptor_;
+        }
+      
+      size_t
+      size()  const
+        {
+          return descriptor_.determineBufferSize();
+        }
+      
+    };
+  
+  
+  /* === 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
+#endif
diff --git a/src/proc/engine/nodeinvocation.hpp b/src/proc/engine/nodeinvocation.hpp
index a67696850..7bb92f1e2 100644
--- a/src/proc/engine/nodeinvocation.hpp
+++ b/src/proc/engine/nodeinvocation.hpp
@@ -55,7 +55,7 @@
 
 #include "proc/state.hpp"
 #include "proc/engine/procnode.hpp"
-#include "proc/engine/buffhandle.hpp"
+#include "proc/engine/channel-descriptor.hpp"
 #include "proc/engine/bufftable-obsolete.hpp"
 
 
diff --git a/src/proc/engine/nodeoperation.hpp b/src/proc/engine/nodeoperation.hpp
index 947fa645f..34e8b684f 100644
--- a/src/proc/engine/nodeoperation.hpp
+++ b/src/proc/engine/nodeoperation.hpp
@@ -59,7 +59,7 @@
 
 #include "proc/state.hpp"
 #include "proc/engine/procnode.hpp"
-#include "proc/engine/buffhandle.hpp"
+#include "proc/engine/channel-descriptor.hpp"
 #include "proc/engine/bufftable-obsolete.hpp"
 #include "proc/engine/nodeinvocation.hpp"
 
diff --git a/tests/components/proc/engine/node-basic-test.cpp b/tests/components/proc/engine/node-basic-test.cpp
index 8e973cc1a..810edf8a7 100644
--- a/tests/components/proc/engine/node-basic-test.cpp
+++ b/tests/components/proc/engine/node-basic-test.cpp
@@ -26,7 +26,7 @@
 #include "proc/engine/nodefactory.hpp"
 #include "proc/engine/nodewiring.hpp"
 #include "proc/engine/stateproxy.hpp"
-#include "proc/engine/buffhandle.hpp"
+#include "proc/engine/channel-descriptor.hpp"
 #include "proc/mobject/session/effect.hpp"
 #include "lib/allocation-cluster.hpp"
 

From d6b069fbbd6e225edcd4961f8f14b62945c0ead4 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 25 Nov 2011 17:29:06 +0100
Subject: [PATCH 61/68] clean-up after refactoring

---
 src/proc/engine/buffhandle.hpp         |  38 ++----
 src/proc/engine/channel-descriptor.hpp | 181 +------------------------
 src/proc/engine/procnode.hpp           |   1 +
 3 files changed, 21 insertions(+), 199 deletions(-)

diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp
index eb87ffec2..185914fa5 100644
--- a/src/proc/engine/buffhandle.hpp
+++ b/src/proc/engine/buffhandle.hpp
@@ -21,9 +21,9 @@
 */
 
 /** @file buffhandle.hpp
- ** Various bits needed to support the buffer management within the render nodes.
+ ** A front-end to support the buffer management within the render nodes.
  ** When pulling data from predecessor nodes and calculating new data, each render node
- ** needs several input and output buffers. These may be allocated and provided by several
+ ** needs several input and output buffers. These may be allocated and provided by various
  ** different "buffer providers" (for example the frame cache). Typically, the real buffers
  ** will be passed as parameters to the actual job instance when scheduled, drawing on the
  ** results of prerequisite jobs. Yet the actual job implementation remains agnostic with
@@ -31,12 +31,18 @@
  ** objects around. The actual render function gets an array of C-pointers to the actual
  ** buffers, and for accessing those buffers, the node needs to keep a table of buffer
  ** pointers, and for releasing the buffers later on, we utilise the buffer handles.
- ** The usage pattern of those buffer pointer tables is stack-like, thus the actual
- ** implementation utilises a single large buffer pointer array per pull() call
- ** sequence and dynamically claims small chunks for each node.
  ** 
- ** @see nodewiring-def.hpp
- ** @see nodeoperation.hpp
+ ** These buffer handles are based on a buffer descriptor record, which is opaque as far
+ ** as the client is concerned. BufferDescriptor acts as a representation of the type or
+ ** kind of buffer. The only way to obtain such a BufferDescriptor is from a concrete
+ ** BufferProvider implementation. A back-link to this owning and managing provider is
+ ** embedded into the BufferDescriptor, allowing to retrieve an buffer handle, corresponding
+ ** to an actual buffer provided and managed behind the scenes. There is no automatic
+ ** resource management; clients are responsible to invoke BuffHandle#release when done.
+ ** 
+ ** @see BufferProvider
+ ** @see BufferProviderProtocol_test usage demonstration
+ ** @see OutputSlot
  ** @see bufftable.hpp       storage for the buffer table
  ** @see engine::RenderInvocation
  */
@@ -99,24 +105,6 @@ namespace engine {
   
   
   
-  class ProcNode;
-  typedef ProcNode* PNode;
-  
-  
-  struct ChannelDescriptor  ///////TODO really need to define that here? it is needed for node wiring only
-    {
-      const lumiera::StreamType * bufferType;                /////////////////////////////////////////TICKET #828
-    };
-  
-  struct InChanDescriptor : ChannelDescriptor
-    {
-      PNode dataSrc;    ///< the ProcNode to pull this input from
-      uint srcChannel; ///<  output channel to use on the predecessor node
-    };
-  
-  
-  
-  
   
   /**
    * Handle for a buffer for processing data, abstracting away the actual implementation.
diff --git a/src/proc/engine/channel-descriptor.hpp b/src/proc/engine/channel-descriptor.hpp
index 1631690dc..0a8e9887a 100644
--- a/src/proc/engine/channel-descriptor.hpp
+++ b/src/proc/engine/channel-descriptor.hpp
@@ -20,24 +20,15 @@
 
 */
 
-/** @file buffhandle.hpp
- ** Various bits needed to support the buffer management within the render nodes.
- ** When pulling data from predecessor nodes and calculating new data, each render node
- ** needs several input and output buffers. These may be allocated and provided by several
- ** different "buffer providers" (for example the frame cache). Typically, the real buffers
- ** will be passed as parameters to the actual job instance when scheduled, drawing on the
- ** results of prerequisite jobs. Yet the actual job implementation remains agnostic with
- ** respect to the way actual buffers are provided; the invocation just pushes BuffHandle
- ** objects around. The actual render function gets an array of C-pointers to the actual
- ** buffers, and for accessing those buffers, the node needs to keep a table of buffer
- ** pointers, and for releasing the buffers later on, we utilise the buffer handles.
- ** The usage pattern of those buffer pointer tables is stack-like, thus the actual
- ** implementation utilises a single large buffer pointer array per pull() call
- ** sequence and dynamically claims small chunks for each node.
+/** @file channel-descriptor.hpp
+ ** Representation of the Media type of a data channel used within the engine.
+ ** 
+ ** @todo as it stands (11/2011) this file is obsoleted and needs to be refactored,
+ **       alongside with adapting the node invocation to the new BufferProvider interface.
  ** 
  ** @see nodewiring-def.hpp
  ** @see nodeoperation.hpp
- ** @see bufftable.hpp       storage for the buffer table
+ ** @see bufftable-obsolete.hpp       storage for the buffer table
  ** @see engine::RenderInvocation
  */
 
@@ -59,43 +50,7 @@ namespace engine {
   
   class BuffHandle;
   class BufferProvider;
-  
-  
-  
-  /**
-   * An opaque descriptor to identify the type and further properties of a data buffer.
-   * For each kind of buffer, there is somewhere a BufferProvider responsible for the
-   * actual storage management. This provider may "lock" a buffer for actual use,
-   * returning a BuffHandle.
-   * @note this descriptor and especially the #subClassification_ is really owned
-   *       by the BufferProvider, which may use (and even change) the opaque contents
-   *       to organise the internal buffer management.
-   * 
-   * @todo try to move that definition into buffer-provider.hpp   ////////////////////////////////////TICKET #249
-   */
-  class BufferDescriptor
-    {
-      BufferProvider* provider_;
-      HashVal subClassification_;
-      
-      BufferDescriptor(BufferProvider& manager, HashVal detail)
-        : provider_(&manager)
-        , subClassification_(detail)
-      { }
-      
-      friend class BufferProvider;
-      
-    public:
-      // using standard copy operations
-      
-      bool verifyValidity()  const;
-      size_t determineBufferSize() const;
-      
-      void emit   (BuffHandle const&)  const;
-      void release (BuffHandle const&)  const;
-      
-      operator HashVal()  const { return subClassification_; }
-    };
+  class BufferDescriptor;
   
   
   
@@ -116,127 +71,5 @@ namespace engine {
   
   
   
-  
-  
-  /**
-   * Handle for a buffer for processing data, abstracting away the actual implementation.
-   * The real buffer pointer can be retrieved by dereferencing this smart-handle class.
-   * 
-   * @todo as of 6/2011 it isn't clear how buffer handles are actually created
-   *       and how the lifecycle (and memory) management works                  //////////////////////TICKET #249 rework BuffHandle creation and usage
-   */
-  class BuffHandle
-    : public lib::BoolCheckable
-    {
-      typedef lumiera::StreamType::ImplFacade::DataBuffer Buff;
-      
-      BufferDescriptor descriptor_;
-      Buff* pBuffer_; 
-      
-      
-    public:
-      typedef Buff* PBuff;
-      
-      /** @internal a buffer handle may be obtained by "locking"
-       *  a buffer from the corresponding BufferProvider */
-      BuffHandle(BufferDescriptor const& typeInfo, void* storage = 0)
-        : descriptor_(typeInfo)
-        , pBuffer_(static_cast(storage))
-        { }
-      
-      // using standard copy operations
-      
-      
-      
-      void
-      emit()
-        {
-          REQUIRE (pBuffer_);
-          descriptor_.emit (*this);
-        }
-      
-      void release()
-        {
-          if (pBuffer_)
-            {
-              REQUIRE (isValid());
-              descriptor_.release (*this);
-              pBuffer_ = 0;
-            }
-          ENSURE (!isValid());
-        }
-      
-      
-      template
-      BU& create();
-      
-      template
-      BU& accessAs();
-      
-      
-      //////////////////////////////////////////TICKET #249 this operator looks obsolete. The Buff type is a placeholder type,
-      //////////////////////////////////////////TODO         it should never be accessed directly from within Lumiera engine code
-      Buff&
-      operator* ()  const
-        {
-          ENSURE (pBuffer_);
-          return *pBuffer_;
-        }
-      
-      bool
-      isValid()  const
-        {
-          return bool(pBuffer_)
-              && descriptor_.verifyValidity();
-        }
-      
-      HashVal
-      entryID()  const
-        {
-          return descriptor_;
-        }
-      
-      size_t
-      size()  const
-        {
-          return descriptor_.determineBufferSize();
-        }
-      
-    };
-  
-  
-  /* === 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
 #endif
diff --git a/src/proc/engine/procnode.hpp b/src/proc/engine/procnode.hpp
index 757524914..4017140c6 100644
--- a/src/proc/engine/procnode.hpp
+++ b/src/proc/engine/procnode.hpp
@@ -46,6 +46,7 @@
 #include "proc/state.hpp"
 #include "proc/asset/proc.hpp"
 #include "proc/mobject/parameter.hpp"
+#include "proc/engine/channel-descriptor.hpp"
 #include "lib/frameid.hpp"
 #include "lib/ref-array.hpp"
 

From ce25be6fa3b7b099eaa46a119fb21e5cf87294c6 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 25 Nov 2011 18:20:01 +0100
Subject: [PATCH 62/68] refactor relation of BuffHandle and BufferDescriptor

they are now tightly coupled and assumed to
work together; there is no need to relay half
of BuffHandle's interface through BufferDescriptor
---
 src/proc/engine/buffer-provider.cpp    | 17 +++++++++++------
 src/proc/engine/buffhandle.hpp         | 26 +++++---------------------
 src/proc/engine/bufftable-obsolete.hpp |  1 +
 3 files changed, 17 insertions(+), 27 deletions(-)

diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp
index e7f7f9cb2..6c33104b0 100644
--- a/src/proc/engine/buffer-provider.cpp
+++ b/src/proc/engine/buffer-provider.cpp
@@ -211,18 +211,23 @@ namespace engine {
   
   
   void
-  BufferDescriptor::emit (BuffHandle const& handle)  const
+  BuffHandle::emit()
   {
-    REQUIRE (verifyValidity());
-    provider_->emitBuffer(handle);
+    REQUIRE (isValid());
+    descriptor_.provider_->emitBuffer(*this);
   }
   
   
   void
-  BufferDescriptor::release (BuffHandle const& handle)  const
+  BuffHandle::release()
   {
-    REQUIRE (verifyValidity());
-    provider_->releaseBuffer(handle);
+    if (pBuffer_)
+      {
+        REQUIRE (isValid());
+        descriptor_.provider_->releaseBuffer(*this);
+        pBuffer_ = 0;
+      }
+    ENSURE (!isValid());
   }
   
   
diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp
index 185914fa5..32a47fc2c 100644
--- a/src/proc/engine/buffhandle.hpp
+++ b/src/proc/engine/buffhandle.hpp
@@ -81,6 +81,7 @@ namespace engine {
    */
   class BufferDescriptor
     {
+    protected:
       BufferProvider* provider_;
       HashVal subClassification_;
       
@@ -90,6 +91,7 @@ namespace engine {
       { }
       
       friend class BufferProvider;
+      friend class BuffHandle;
       
     public:
       // using standard copy operations
@@ -97,9 +99,6 @@ namespace engine {
       bool verifyValidity()  const;
       size_t determineBufferSize() const;
       
-      void emit   (BuffHandle const&)  const;
-      void release (BuffHandle const&)  const;
-      
       operator HashVal()  const { return subClassification_; }
     };
   
@@ -136,23 +135,8 @@ namespace engine {
       
       
       
-      void
-      emit()
-        {
-          REQUIRE (pBuffer_);
-          descriptor_.emit (*this);
-        }
-      
-      void release()
-        {
-          if (pBuffer_)
-            {
-              REQUIRE (isValid());
-              descriptor_.release (*this);
-              pBuffer_ = 0;
-            }
-          ENSURE (!isValid());
-        }
+      void emit();
+      void release();
       
       
       template
@@ -181,7 +165,7 @@ namespace engine {
       HashVal
       entryID()  const
         {
-          return descriptor_;
+          return HashVal(descriptor_);
         }
       
       size_t
diff --git a/src/proc/engine/bufftable-obsolete.hpp b/src/proc/engine/bufftable-obsolete.hpp
index 2b43ee6d1..391808f65 100644
--- a/src/proc/engine/bufftable-obsolete.hpp
+++ b/src/proc/engine/bufftable-obsolete.hpp
@@ -70,6 +70,7 @@ namespace engine {
       PBu inBuff;
     };
   
+  class BufferDescriptor;
   
     /** Obsolete, to be rewritten  /////TICKET #826 */
   class BuffTableStorage

From 55a77bdd73e304d79efdcfdcf55127e50ed8c728 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 25 Nov 2011 20:23:31 +0100
Subject: [PATCH 63/68] 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 

From 2fce2b1c8d4488fbb4403955ae36475c09bffec3 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 25 Nov 2011 22:05:12 +0100
Subject: [PATCH 64/68] make ctor-tracking test::Dummy more widely usable

---
 src/lib/test/test-helper.cpp              |  6 ++
 src/lib/test/testdummy.hpp                | 99 +++++++++++++++++++++++
 tests/lib/scoped-holder-test.cpp          | 58 ++++++-------
 tests/lib/scoped-holder-transfer-test.cpp | 48 +++++------
 tests/lib/scoped-ptrvect-test.cpp         | 32 ++++----
 tests/lib/testdummy.hpp                   | 87 --------------------
 tests/lib/vector-transfer-test.cpp        | 16 ++--
 7 files changed, 182 insertions(+), 164 deletions(-)
 create mode 100644 src/lib/test/testdummy.hpp
 delete mode 100644 tests/lib/testdummy.hpp

diff --git a/src/lib/test/test-helper.cpp b/src/lib/test/test-helper.cpp
index 8c8a7dda0..1d031b3b0 100644
--- a/src/lib/test/test-helper.cpp
+++ b/src/lib/test/test-helper.cpp
@@ -22,6 +22,7 @@
 
 
 #include "lib/test/test-helper.hpp"
+#include "lib/test/testdummy.hpp"
 
 #include 
 
@@ -55,7 +56,12 @@ namespace test{
       garbage[--p] = alpha[rand() % MAXAL];
     return garbage;
   }
+
   
+  /** storage for testdummy flags */
+    
+  long Dummy::_local_checksum = 0;
+  bool Dummy::_throw_in_ctor = false;
   
   
 }} // namespace lib::test
diff --git a/src/lib/test/testdummy.hpp b/src/lib/test/testdummy.hpp
new file mode 100644
index 000000000..24d467c1f
--- /dev/null
+++ b/src/lib/test/testdummy.hpp
@@ -0,0 +1,99 @@
+/*
+  TESTDUMMY.hpp  -  yet another test dummy for tracking ctor/dtor calls
+
+  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.
+
+* *****************************************************/
+
+
+
+#include 
+#include 
+
+
+namespace lib {
+namespace test{
+    
+  
+  class Dummy 
+    : boost::noncopyable
+    {
+      int val_;
+      
+      /** to verify ctor/dtor calls */
+      static long _local_checksum;
+      static bool _throw_in_ctor;
+      
+    public:
+      Dummy ()
+        : val_(1 + (rand() % 100000000))
+        { init(); }
+      
+      Dummy (int v)
+        : val_(v)
+        { init(); }
+      
+      ~Dummy()
+        {
+          checksum() -= val_;
+        }
+      
+      long add (int i)    { return val_+i; }
+      
+      int getVal()  const { return val_; }
+      
+      void
+      setVal (int newVal)
+        {
+          checksum() += newVal - val_;
+          val_ = newVal;
+        }
+      
+      friend void
+      swap (Dummy& dum1, Dummy& dum2)  ///< checksum neutral
+      {
+        std::swap(dum1.val_, dum2.val_);
+      }
+      
+      static long&
+      checksum()
+        {
+          return _local_checksum;
+        }
+      
+      static void
+      activateCtorFailure(bool indeed =true)
+        {
+          _throw_in_ctor = indeed;
+        }
+      
+      
+    private:
+      void
+      init()
+        {
+          checksum() += val_;
+          if (_throw_in_ctor)
+            throw val_;
+        }
+
+    };
+  
+  
+}} // namespace lib::test
+
diff --git a/tests/lib/scoped-holder-test.cpp b/tests/lib/scoped-holder-test.cpp
index b424ec685..dd0734bb7 100644
--- a/tests/lib/scoped-holder-test.cpp
+++ b/tests/lib/scoped-holder-test.cpp
@@ -28,7 +28,7 @@
 #include "lib/error.hpp"
 
 #include "lib/scoped-holder.hpp"
-#include "testdummy.hpp"
+#include "lib/test/testdummy.hpp"
 
 #include 
 #include 
@@ -85,20 +85,20 @@ namespace test{
       void
       checkAllocation()
         {
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             HO holder;
             CHECK (!holder);
-            CHECK (0==checksum);
+            CHECK (0 == Dummy::checksum());
             
             create_contained_object (holder);
             CHECK (holder);
             CHECK (false!=holder);
             CHECK (holder!=false);
             
-            CHECK (0!=checksum);
+            CHECK (0 != Dummy::checksum());
             CHECK ( &(*holder));
-            CHECK (holder->add(2) == checksum+2);
+            CHECK (holder->add(2) == 2 + Dummy::checksum());
             
             Dummy *rawP = holder.get();
             CHECK (rawP);
@@ -111,7 +111,7 @@ namespace test{
             TRACE (test, "size(object) = %lu", sizeof(*holder));
             TRACE (test, "size(holder) = %lu", sizeof(holder));
           }
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
       
@@ -119,11 +119,11 @@ namespace test{
       void
       checkErrorHandling()
         {
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             HO holder;
             
-            throw_in_ctor = true;
+            Dummy::activateCtorFailure();
             try
               {
                 create_contained_object (holder);
@@ -131,15 +131,15 @@ namespace test{
               }
             catch (int val)
               {
-                CHECK (0!=checksum);
-                checksum -= val;
-                CHECK (0==checksum);
+                CHECK (0 != Dummy::checksum());
+                Dummy::checksum() -= val;
+                CHECK (0 == Dummy::checksum());
               }
             CHECK (!holder);  /* because the exception happens in ctor
                                  object doesn't count as "created" */
-            throw_in_ctor = false;
+            Dummy::activateCtorFailure(false);
           }
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
       
@@ -147,7 +147,7 @@ namespace test{
       void
       checkCopyProtocol()
         {
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             HO holder;
             HO holder2 (holder);
@@ -158,38 +158,38 @@ namespace test{
             CHECK (!holder);
             create_contained_object (holder);
             CHECK (holder);
-            long currSum = checksum;
+            long currSum = Dummy::checksum();
             void* adr = holder.get();
             
             VERIFY_ERROR(LOGIC, holder2 = holder );
             CHECK (holder);
             CHECK (!holder2);
             CHECK (holder.get()==adr);
-            CHECK (checksum==currSum);
+            CHECK (Dummy::checksum()==currSum);
             
             VERIFY_ERROR(LOGIC, holder = holder2 );
             CHECK (holder);
             CHECK (!holder2);
             CHECK (holder.get()==adr);
-            CHECK (checksum==currSum);
+            CHECK (Dummy::checksum()==currSum);
             
             create_contained_object (holder2);
             CHECK (holder2);
-            CHECK (checksum != currSum);
-            currSum = checksum;
+            CHECK (Dummy::checksum() != currSum);
+            currSum = Dummy::checksum();
             
             VERIFY_ERROR(LOGIC, holder = holder2 );
             CHECK (holder);
             CHECK (holder2);
             CHECK (holder.get()==adr);
-            CHECK (checksum==currSum);
+            CHECK (Dummy::checksum()==currSum);
             
             VERIFY_ERROR(LOGIC, HO holder3 (holder2) );
             CHECK (holder);
             CHECK (holder2);
-            CHECK (checksum==currSum);
+            CHECK (Dummy::checksum()==currSum);
           }
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
       
@@ -202,7 +202,7 @@ namespace test{
         {
           typedef std::map MapHO;
           
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             MapHO maph;
             CHECK (isnil (maph));
@@ -212,8 +212,8 @@ namespace test{
                 HO & contained = maph[i];
                 CHECK (!contained);
               }                      // 100 holder objects created by sideeffect
-                                    
-            CHECK (0==checksum);   // ..... without creating any contained object!
+                                    // ..... without creating any contained object!  
+            CHECK (0 == Dummy::checksum());
             CHECK (!isnil (maph));
             CHECK (100==maph.size());
             
@@ -224,14 +224,14 @@ namespace test{
                 CHECK (0 < maph[i]->add(12));
               }
             CHECK (100==maph.size());
-            CHECK (0!=checksum);
+            CHECK (0 != Dummy::checksum());
             
             
             long value55 = maph[55]->add(0); 
-            long currSum = checksum;
+            long currSum = Dummy::checksum();
             
             CHECK (1 == maph.erase(55));
-            CHECK (checksum == currSum - value55); // proves object#55's dtor has been invoked
+            CHECK (Dummy::checksum() == currSum - value55); // proves object#55's dtor has been invoked
             CHECK (maph.size() == 99);
             
             maph[55];                              // create new empty holder by sideeffect...
@@ -239,7 +239,7 @@ namespace test{
             CHECK (!maph[55]);
             CHECK (maph.size() == 100);
           }
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
       
diff --git a/tests/lib/scoped-holder-transfer-test.cpp b/tests/lib/scoped-holder-transfer-test.cpp
index 0c3773095..36b1bdd2c 100644
--- a/tests/lib/scoped-holder-transfer-test.cpp
+++ b/tests/lib/scoped-holder-transfer-test.cpp
@@ -27,7 +27,7 @@
 
 #include "lib/scoped-holder.hpp"
 #include "lib/scoped-holder-transfer.hpp"
-#include "testdummy.hpp"
+#include "lib/test/testdummy.hpp"
 
 #include 
 #include 
@@ -125,17 +125,17 @@ namespace test {
       void
       buildVector()
         {
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             typedef typename Table::Type Vect;
             
             Vect table(50);
-            CHECK (0==checksum);
+            CHECK (0 == Dummy::checksum());
             
             for (uint i=0; i<10; ++i)
               create_contained_object (table[i]);
             
-            CHECK (0 < checksum);
+            CHECK (0 < Dummy::checksum());
             CHECK ( table[9]);
             CHECK (!table[10]);
             
@@ -145,7 +145,7 @@ namespace test {
             CHECK (rawP == &(*table[5]));
             CHECK (rawP->add(-555) == table[5]->add(-555));
           }
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
       
@@ -153,29 +153,29 @@ namespace test {
       void
       growVector()
         {
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             typedef typename Table::Type Vect;
             
             Vect table;
             table.reserve(2);
-            CHECK (0==checksum);
+            CHECK (0 == Dummy::checksum());
             
             cout << ".\n..install one element at index[0]\n";
             table.push_back(HO());
-            CHECK (0==checksum);
+            CHECK (0 == Dummy::checksum());
             
             create_contained_object (table[0]); // switches into "managed" state
-            CHECK (0 < checksum);
-            int theSum = checksum;
+            CHECK (0 < Dummy::checksum());
+            int theSum = Dummy::checksum();
             
             cout << ".\n..*** resize table to 16 elements\n";
             for (uint i=0; i<15; ++i)
               table.push_back(HO());
             
-            CHECK (theSum==checksum);
+            CHECK (theSum == Dummy::checksum());
           }
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
       
@@ -183,37 +183,37 @@ namespace test {
       void
       checkErrorHandling()
         {
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             typedef typename Table::Type Vect;
             
             Vect table(5);
             table.reserve(5);
-            CHECK (0==checksum);
+            CHECK (0 == Dummy::checksum());
             
             create_contained_object (table[2]);
             create_contained_object (table[4]);
-            CHECK (0 < checksum);
-            int theSum = checksum;
+            CHECK (0 < Dummy::checksum());
+            int theSum = Dummy::checksum();
             
             cout << ".\n.throw some exceptions...\n";
-            throw_in_ctor = true;
+            Dummy::activateCtorFailure();
             try
               {
                 create_contained_object (table[3]);
-                NOTREACHED ();
+                NOTREACHED ("ctor should throw");
               }
             catch (int val)
               {
-                CHECK (theSum < checksum);
-                checksum -= val;
-                CHECK (theSum==checksum);
+                CHECK (theSum < Dummy::checksum());
+                Dummy::checksum() -= val;
+                CHECK (theSum == Dummy::checksum());
               }
             CHECK ( table[2]);
             CHECK (!table[3]); // not created because of exception
             CHECK ( table[4]);
             
-            throw_in_ctor = false;
+            Dummy::activateCtorFailure(false);
             throw_in_transfer=true;  // can do this only when using ScopedHolder
             try
               {
@@ -223,10 +223,10 @@ namespace test {
               {
                 CHECK ( table.size() < 10);
               }
-            CHECK (theSum == checksum);
+            CHECK (theSum == Dummy::checksum());
             throw_in_transfer=false;
           }
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
     };
diff --git a/tests/lib/scoped-ptrvect-test.cpp b/tests/lib/scoped-ptrvect-test.cpp
index 63772334b..b1d7fe62f 100644
--- a/tests/lib/scoped-ptrvect-test.cpp
+++ b/tests/lib/scoped-ptrvect-test.cpp
@@ -27,7 +27,7 @@
 #include "lib/util.hpp"
 
 #include "lib/scoped-ptrvect.hpp"
-#include "testdummy.hpp"
+#include "lib/test/testdummy.hpp"
 
 
 namespace lib {
@@ -63,16 +63,16 @@ namespace test{
       void
       simpleUsage()
         {
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             VectD holder;
             CHECK (isnil (holder));
-            CHECK (0==checksum);
+            CHECK (0 == Dummy::checksum());
             
             Dummy* ptr = new Dummy();
             Dummy& ref = holder.manage (ptr);
             CHECK (!isnil (holder));
-            CHECK (0!=checksum);
+            CHECK (0 != Dummy::checksum());
             CHECK (&ref==ptr);
             
             holder.manage (new Dummy);
@@ -80,7 +80,7 @@ namespace test{
             CHECK (3 == holder.size());
             
             holder.clear();
-            CHECK (0==checksum);
+            CHECK (0 == Dummy::checksum());
             CHECK (isnil (holder));
             
             holder.manage (new Dummy);
@@ -93,16 +93,16 @@ namespace test{
             holder.manage (new Dummy);
             holder.manage (new Dummy);
             CHECK (9 == holder.size());
-            CHECK (0 < checksum);
+            CHECK (0 < Dummy::checksum());
           }
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
       
       void
       iterating()
         {
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             VectD holder;
             for (int i=0; i<16; ++i)
@@ -142,7 +142,7 @@ namespace test{
             VERIFY_ERROR (ITER_EXHAUST, ++cii );
             
           }
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
       
@@ -151,10 +151,10 @@ namespace test{
         {
           int id2, id3;
           Dummy* extracted(0);
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           {
             VectD holder;
-            CHECK (0 == checksum);
+            CHECK (0 == Dummy::checksum());
             CHECK (isnil (holder));
             
             holder.manage (new Dummy);
@@ -163,7 +163,7 @@ namespace test{
             holder.manage (new Dummy);
             holder.manage (new Dummy);
             CHECK (5 == holder.size());
-            CHECK (0 < checksum);
+            CHECK (0 < Dummy::checksum());
             
             id2 = holder[2].getVal();
             id3 = holder[3].getVal();
@@ -173,14 +173,14 @@ namespace test{
             CHECK (id3 == holder[2].getVal());
             CHECK (4 == holder.size());
           }
-          CHECK (0 < checksum);     // not all dummies are dead
-          CHECK (id2 == checksum); //  #2 is alive!
+          CHECK (0 < Dummy::checksum());     // not all dummies are dead
+          CHECK (id2 == Dummy::checksum()); //  #2 is alive!
           
           extracted->setVal(id2+id3);
-          CHECK (id2+id3 == checksum);
+          CHECK (id2+id3 == Dummy::checksum());
           
           delete extracted;
-          CHECK (0 == checksum);
+          CHECK (0 == Dummy::checksum());
         }
     };
   
diff --git a/tests/lib/testdummy.hpp b/tests/lib/testdummy.hpp
deleted file mode 100644
index 76dcac652..000000000
--- a/tests/lib/testdummy.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-  TESTDUMMY.hpp  -  yet another test dummy for tracking ctor/dtor calls
-
-  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.
-
-* *****************************************************/
-
-
-
-#include 
-#include 
-
-
-namespace lib {
-namespace test{
-    
-  namespace { // yet another test dummy
-    
-    long checksum = 0;
-    bool throw_in_ctor = false;
-    
-    class Dummy 
-      : boost::noncopyable
-      {
-        int val_;
-        
-      public:
-        Dummy ()
-          : val_(1 + (rand() % 100000000))
-          { init(); }
-        
-        Dummy (int v)
-          : val_(v)
-          { init(); }
-        
-        ~Dummy()
-          {
-            checksum -= val_;
-          }
-        
-        long add (int i)    { return val_+i; }
-        
-        int getVal()  const { return val_; }
-        
-        void
-        setVal (int newVal)
-          {
-            checksum += newVal - val_;
-            val_ = newVal;
-          }
-        
-        friend void
-        swap (Dummy& dum1, Dummy& dum2)  ///< checksum neutral
-        {
-          std::swap(dum1.val_, dum2.val_);
-        }
-        
-      private:
-        void
-        init()
-          {
-            checksum += val_;
-            if (throw_in_ctor)
-              throw val_;
-          }
-
-      };
-      
-  }  // anonymous test dummy
-  
-}} // namespace lib::test
-
diff --git a/tests/lib/vector-transfer-test.cpp b/tests/lib/vector-transfer-test.cpp
index 98f8f4021..6a4e8974d 100644
--- a/tests/lib/vector-transfer-test.cpp
+++ b/tests/lib/vector-transfer-test.cpp
@@ -25,7 +25,7 @@
 #include "lib/test/run.hpp"
 
 #include "lib/scoped-holder-transfer.hpp"
-#include "testdummy.hpp"
+#include "lib/test/testdummy.hpp"
 
 #include 
 #include 
@@ -130,27 +130,27 @@ namespace test {
           cout << "\n..setup table space for 2 elements\n";
           TransDummyVector table;
           table.reserve(2);
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           
           cout << "\n..install one element at index[0]\n";
           table.push_back(TransDummy());
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
           
           table[0].setup(); // switches into "managed" state
-          CHECK (0 < checksum);
-          int theSum = checksum;
+          CHECK (0 < Dummy::checksum());
+          int theSum = Dummy::checksum();
           
           cout << "\n..*** resize table to 5 elements\n";
           table.resize(5);
-          CHECK (theSum==checksum);
+          CHECK (theSum==Dummy::checksum());
           
           cout << "\n..install another element\n";
           table[3].setup(375);
-          CHECK (theSum+375==checksum);
+          CHECK (theSum+375==Dummy::checksum());
           
           cout << "\n..kill all elements....\n";
           table.clear();
-          CHECK (0==checksum);
+          CHECK (0 == Dummy::checksum());
         }
       
     };

From 7ba8ff432f5557295d0527ae71fc781b4ecc52b0 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 26 Nov 2011 00:09:59 +0100
Subject: [PATCH 65/68] BufferProvider interface finished thus far.

simulated lifecycle passes unit test
---
 src/proc/engine/buffer-metadata.hpp           |  31 ++++-
 src/proc/engine/buffer-provider.cpp           |  48 ++++++--
 src/proc/engine/buffer-provider.hpp           |   8 +-
 src/proc/engine/buffhandle-attach.hpp         |   1 +
 src/proc/engine/buffhandle.hpp                |   7 +-
 .../engine/diagnostic-buffer-provider.cpp     |  29 +----
 .../engine/diagnostic-buffer-provider.hpp     |  17 +--
 tests/46engine.tests                          |   2 +-
 .../proc/control/command-argument-test.cpp    |   2 +-
 .../engine/buffer-provider-protocol-test.cpp  | 114 +++++++++++++++---
 10 files changed, 178 insertions(+), 81 deletions(-)

diff --git a/src/proc/engine/buffer-metadata.hpp b/src/proc/engine/buffer-metadata.hpp
index 484450a10..c33c59ea7 100644
--- a/src/proc/engine/buffer-metadata.hpp
+++ b/src/proc/engine/buffer-metadata.hpp
@@ -235,6 +235,15 @@ namespace engine {
             return newKey; 
           }
         
+        void
+        useTypeHandlerFrom (Key const& ref)
+          {
+            if (nontrivial(this->instanceFunc_))
+              throw error::Logic ("unable to supersede an already attached TypeHandler"
+                                 , LUMIERA_ERROR_LIFECYCLE);
+            instanceFunc_ = ref.instanceFunc_;
+          }
+        
         
         LocalKey const& localKey() const { return specifics_;}
         size_t storageSize() const { return storageSize_; }
@@ -346,6 +355,16 @@ namespace engine {
             return mark (LOCKED);
           }
         
+        Entry&
+        invalidate (bool invokeDtor =true)
+          {
+            if (buffer_ && invokeDtor)
+              invokeEmbeddedDtor_and_clear();
+            buffer_ = 0;
+            state_ = FREE;
+            return *this;
+          }
+        
         
       protected:
         /** @internal maybe invoke a registered TypeHandler's
@@ -712,11 +731,19 @@ namespace engine {
         {
           Entry* entry = table_.fetch (key);
           if (!entry) return;
-          if (entry && (FREE != entry->state()))
+          
+          ASSERT (entry && (key == HashVal(*entry)));
+          release (*entry);
+        }
+      
+      void
+      release (Entry const& entry)
+        {
+          if (FREE != entry.state())
             throw error::Logic ("Attempt to release a buffer still in use"
                                , error::LUMIERA_ERROR_LIFECYCLE);
           
-          table_.remove (key);
+          table_.remove (HashVal(entry));
         }
       
       
diff --git a/src/proc/engine/buffer-provider.cpp b/src/proc/engine/buffer-provider.cpp
index 449b41370..1303d1458 100644
--- a/src/proc/engine/buffer-provider.cpp
+++ b/src/proc/engine/buffer-provider.cpp
@@ -89,7 +89,7 @@ namespace engine {
    * to be returned to the client as result of the #lockBuffer call.
    * Performs the necessary metadata state transition leading from an
    * abstract buffer type to a metadata::Entry corresponding to an
-   * actual buffer, which is locked for exclusive use by one client. 
+   * actual buffer, which is locked for exclusive use by one client.
    */ 
   BuffHandle
   BufferProvider::buildHandle (HashVal typeID, void* storage, LocalKey const& implID)
@@ -178,8 +178,9 @@ namespace engine {
   BufferProvider::releaseBuffer (BuffHandle const& handle)
   try {
     metadata::Entry& metaEntry = meta_->get (handle.entryID());
+    metaEntry.mark(FREE);   // might invoke embedded dtor function
     detachBuffer (metaEntry.parentKey(), metaEntry.localKey());
-    metaEntry.mark(FREE);
+    meta_->release (metaEntry);
   }
   ERROR_LOG_AND_IGNORE (engine, "releasing a buffer from BufferProvider")
   
@@ -198,7 +199,15 @@ namespace engine {
   void
   BufferProvider::attachTypeHandler (BuffHandle const& target, BufferDescriptor const& reference)
   {
-    UNIMPLEMENTED ("convenience shortcut to attach/place an object in one sway");
+    metadata::Entry& metaEntry = meta_->get (target.entryID());
+    metadata::Entry& refEntry = meta_->get (reference);
+    REQUIRE (refEntry.isTypeKey());
+    REQUIRE (!metaEntry.isTypeKey());
+    if (!metaEntry.isLocked())
+      throw error::Logic ("unable to attach an object because buffer isn't locked for use"
+                         , LUMIERA_ERROR_LIFECYCLE);
+    
+    metaEntry.useTypeHandlerFrom (refEntry); // EX_STRONG
   }
   
   
@@ -211,10 +220,14 @@ namespace engine {
    */
   void
   BufferProvider::emergencyCleanup (BuffHandle const& target, bool invokeDtor)
-  {
-    UNIMPLEMENTED ("emergency cleanup");
+  try {
+    metadata::Entry& metaEntry = meta_->get (target.entryID());
+    metaEntry.invalidate (invokeDtor);
+    detachBuffer (metaEntry.parentKey(), metaEntry.localKey());
+    meta_->release (metaEntry);
   }
-
+  ERROR_LOG_AND_IGNORE (engine, "cleanup of buffer metadata while handling an error")
+  
   
   
   bool
@@ -222,7 +235,7 @@ namespace engine {
   {
     return isSameObject (*this, *descr.provider_);
   }
-    
+  
   
   
   
@@ -267,20 +280,35 @@ namespace engine {
   void
   BuffHandle::emergencyCleanup()
   {
-    descriptor_.provider_->emergencyCleanup(*this); // EX_FREE 
-    pBuffer_ = 0;       
+    descriptor_.provider_->emergencyCleanup(*this); // EX_FREE
+    pBuffer_ = 0;
   }
   
   
+  /** Install a standard TypeHandler for an already locked buffer.
+   *  This causes the dtor function to be invoked when releasing this buffer.
+   *  The assumption is that client code will placement-construct an object
+   *  into this buffer right away, and thus we're taking ownership on that object.
+   * @param type a reference BufferDescriptor defining an embedded TypeHandler to use
+   *        A copy of this TypeHandler will be stored into the local metadata for
+   *        this buffer only, not altering the basic buffer type in any way
+   * @throw lifecycle error when attempting to treat an buffer not in locked state
+   * @throw error::Logic in case of insufficient buffer space to hold the
+   *        intended target object
+   * @note EX_STRONG
+   */
   void
   BuffHandle::takeOwnershipFor(BufferDescriptor const& type)
   {
+    if (!this->isValid())
+      throw error::Logic ("attaching an object requires an buffer in locked state"
+                         , LUMIERA_ERROR_LIFECYCLE);
     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
   }
-
+  
   
   
   
diff --git a/src/proc/engine/buffer-provider.hpp b/src/proc/engine/buffer-provider.hpp
index 4fff36efe..37add12f1 100644
--- a/src/proc/engine/buffer-provider.hpp
+++ b/src/proc/engine/buffer-provider.hpp
@@ -131,10 +131,10 @@ namespace engine {
       
       bool was_created_by_this_provider (BufferDescriptor const&)  const;
     };
-    
-    
-    
-    
+  
+  
+  
+  
   /* === Implementation === */
   
   /** convenience shortcut:
diff --git a/src/proc/engine/buffhandle-attach.hpp b/src/proc/engine/buffhandle-attach.hpp
index 4f5b94b55..0b2d3a0ae 100644
--- a/src/proc/engine/buffhandle-attach.hpp
+++ b/src/proc/engine/buffhandle-attach.hpp
@@ -67,6 +67,7 @@ namespace engine {
       {                                   \
         emergencyCleanup(); /* EX_FREE */ \
         pBuffer_ = 0;                     \
+        throw;                            \
       }
   
   /** convenience shortcut: place and maintain an object within the buffer.
diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp
index a035f3a69..9ed842cb4 100644
--- a/src/proc/engine/buffhandle.hpp
+++ b/src/proc/engine/buffhandle.hpp
@@ -43,7 +43,7 @@
  ** @see BufferProvider
  ** @see BufferProviderProtocol_test usage demonstration
  ** @see OutputSlot
- ** @see bufftable.hpp       storage for the buffer table
+ ** @see bufftable.hpp      storage for the buffer table
  ** @see engine::RenderInvocation
  */
 
@@ -76,8 +76,6 @@ namespace engine {
    * @note this descriptor and especially the #subClassification_ is really owned
    *       by the BufferProvider, which may use (and even change) the opaque contents
    *       to organise the internal buffer management.
-   * 
-   * @todo try to move that definition into buffer-provider.hpp   ////////////////////////////////////TICKET #249
    */
   class BufferDescriptor
     {
@@ -108,9 +106,6 @@ namespace engine {
   /**
    * Handle for a buffer for processing data, abstracting away the actual implementation.
    * The real buffer pointer can be retrieved by dereferencing this smart-handle class.
-   * 
-   * @todo as of 6/2011 it isn't clear how buffer handles are actually created
-   *       and how the lifecycle (and memory) management works                  //////////////////////TICKET #249 rework BuffHandle creation and usage
    */
   class BuffHandle
     : public lib::BoolCheckable
diff --git a/src/proc/engine/diagnostic-buffer-provider.cpp b/src/proc/engine/diagnostic-buffer-provider.cpp
index f00dcb8a3..98f65cf94 100644
--- a/src/proc/engine/diagnostic-buffer-provider.cpp
+++ b/src/proc/engine/diagnostic-buffer-provider.cpp
@@ -27,13 +27,6 @@
 #include "proc/engine/diagnostic-buffer-provider.hpp"
 #include "proc/engine/tracking-heap-block-provider.hpp"
 
-//#include 
-//#include 
-
-//using lib::ScopedPtrVect;
-//using boost::scoped_array;
-
-
 
 namespace engine {
   
@@ -42,20 +35,10 @@ namespace engine {
   lib::Singleton DiagnosticBufferProvider::diagnostics;
   
   
-    
-    
-  namespace { // Details of allocation and accounting
-    
-  
-  } // (END) Details of allocation and accounting
   
   
-  
-  
-  
-
   DiagnosticBufferProvider::DiagnosticBufferProvider()
-    : pImpl_() //////////TODO create PImpl here
+    : pImpl_()
     { }
   
   DiagnosticBufferProvider::~DiagnosticBufferProvider() { }
@@ -78,9 +61,9 @@ namespace engine {
     return diagnostics();
   }
   
-
-    
-    
+  
+  
+  
   TrackingHeapBlockProvider&
   DiagnosticBufferProvider::reset()
   {
@@ -93,9 +76,9 @@ namespace engine {
   {
     return &implInstance == pImpl_.get();
   }
-
   
-
+  
+  
   
   
   /* === diagnostic API === */
diff --git a/src/proc/engine/diagnostic-buffer-provider.hpp b/src/proc/engine/diagnostic-buffer-provider.hpp
index 83bb589ca..cef2c1e0d 100644
--- a/src/proc/engine/diagnostic-buffer-provider.hpp
+++ b/src/proc/engine/diagnostic-buffer-provider.hpp
@@ -33,6 +33,7 @@
 #include "lib/error.hpp"
 #include "lib/singleton.hpp"
 #include "lib/util.hpp"
+#include "proc/engine/type-handler.hpp"
 #include "proc/engine/buffer-provider.hpp"
 
 #include 
@@ -98,22 +99,6 @@ namespace engine {
       bool all_buffers_released()          const;
       
       
-      template
-      bool
-      object_was_attached (uint bufferID)  const
-        {
-          UNIMPLEMENTED ("verify object attachment status of a specific buffer");
-        }
-      
-      
-      template
-      bool
-      object_was_destroyed (uint bufferID)  const
-        {
-          UNIMPLEMENTED ("verify object attachment status of a specific buffer");
-        }
-      
-      
       
     private:
       
diff --git a/tests/46engine.tests b/tests/46engine.tests
index 07fac0119..b0de4f200 100644
--- a/tests/46engine.tests
+++ b/tests/46engine.tests
@@ -12,7 +12,7 @@ return: 0
 END
 
 
-PLANNED "Buffer provider diagnostics" BufferProviderProtocol_test <
-//#include 
-
-//using boost::format;
-//using std::string;
-//using std::cout;
+using util::isSameObject;
 using util::for_each;
 
 
 namespace engine{
 namespace test  {
   
-//  using lib::AllocationCluster;
-//  using mobject::session::PEffect;
+  using lib::test::Dummy;
+  
   using ::engine::BuffHandle;
-  using lumiera::error::LUMIERA_ERROR_LIFECYCLE;
+  using error::LUMIERA_ERROR_LOGIC;
+  using error::LUMIERA_ERROR_LIFECYCLE;
   
   
   namespace { // Test fixture
@@ -64,12 +60,16 @@ namespace test  {
   }
   
   
-  /*******************************************************************
-   * @test verify the OutputSlot interface and base implementation
-   *       by performing full data exchange cycle. This is a
-   *       kind of "dry run" for documentation purposes,
-   *       both the actual OutputSlot implementation
-   *       as the client using this slot are Mocks.
+  /******************************************************************************
+   * @test verify and demonstrate the usage cycle of data buffers for the engine
+   *       based on the BufferProvider interface. This is kind of a "dry run"
+   *       for documentation purposes, because the BufferProvider implementation
+   *       used here is just a diagnostics facility, allowing to investigate
+   *       the state of individual buffers even after "releasing" them.
+   *       
+   *       This test should help understanding the sequence of buffer management
+   *       operations performed at various stages while passing an calculation job
+   *       through the render engine.
    */
   class BufferProviderProtocol_test : public Test
     {
@@ -78,6 +78,8 @@ namespace test  {
         {
           verifySimpleUsage();
           verifyStandardCase();
+          verifyObjectAttachment();
+          verifyObjectAttachmentFailure();
         }
       
       
@@ -97,6 +99,7 @@ namespace test  {
           TestFrame& content = buff.accessAs();
           CHECK (testData(0) == content);
           
+          buff.emit();
           buff.release();
           CHECK (!buff.isValid());
           VERIFY_ERROR (LIFECYCLE, buff.accessAs() );
@@ -104,8 +107,6 @@ namespace test  {
           DiagnosticBufferProvider& checker = DiagnosticBufferProvider::access(provider);
           CHECK (checker.buffer_was_used (0));
           CHECK (checker.buffer_was_closed (0));
-          CHECK (checker.object_was_attached (0));
-          CHECK (checker.object_was_destroyed (0));
           
           CHECK (testData(0) == checker.accessMemory (0));
         }
@@ -146,6 +147,83 @@ namespace test  {
           CHECK (checker.all_buffers_released());
 #endif    /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #829
         }
+      
+      
+      void
+      verifyObjectAttachment()
+        {
+          BufferProvider& provider = DiagnosticBufferProvider::build();
+          BufferDescriptor type_A = provider.getDescriptorFor(sizeof(TestFrame));
+          BufferDescriptor type_B = provider.getDescriptorFor(sizeof(int));
+          BufferDescriptor type_C = provider.getDescriptor();
+          
+          BuffHandle handle_A = provider.lockBuffer(type_A);
+          BuffHandle handle_B = provider.lockBuffer(type_B);
+          BuffHandle handle_C = provider.lockBuffer(type_C);
+          
+          CHECK (handle_A);
+          CHECK (handle_B);
+          CHECK (handle_C);
+          
+          CHECK (sizeof(TestFrame) == handle_A.size());
+          CHECK (sizeof( int )     == handle_B.size());
+          CHECK (sizeof( int )     == handle_C.size());
+          
+          TestFrame& embeddedFrame = handle_A.create();
+          CHECK (isSameObject (*handle_A, embeddedFrame));
+          CHECK (embeddedFrame.isAlive());
+          CHECK (embeddedFrame.isSane());
+          
+          VERIFY_ERROR (LOGIC,     handle_B.create());   // too small to hold a TestFrame
+          VERIFY_ERROR (LIFECYCLE, handle_C.create());         // has already an attached TypeHandler (creating an int)
+          
+          handle_A.release();
+          handle_B.release();
+          handle_C.release();
+          
+          CHECK (embeddedFrame.isDead());
+          CHECK (embeddedFrame.isSane());
+        }
+      
+      
+      void
+      verifyObjectAttachmentFailure()
+        {
+          BufferProvider& provider = DiagnosticBufferProvider::build();
+          BufferDescriptor type_D = provider.getDescriptorFor(sizeof(Dummy));
+          
+          Dummy::checksum() = 0;
+          BuffHandle handle_D = provider.lockBuffer(type_D);
+          CHECK (0 == Dummy::checksum());  // nothing created thus far
+          
+          handle_D.create();
+          CHECK (0 < Dummy::checksum());
+          
+          handle_D.release();
+          CHECK (0 == Dummy::checksum());
+          
+          BuffHandle handle_DD = provider.lockBuffer(type_D);
+          
+          CHECK (0 == Dummy::checksum());
+          Dummy::activateCtorFailure();
+          
+          CHECK (handle_DD.isValid());
+          try
+            {
+              handle_DD.create();
+              NOTREACHED ("Dummy ctor should fail");
+            }
+          catch (int val)
+            {
+              CHECK (!handle_DD.isValid());
+              
+              CHECK (0 < Dummy::checksum());
+              CHECK (val == Dummy::checksum());
+            }
+          
+          VERIFY_ERROR (LIFECYCLE, handle_DD.accessAs() );
+          VERIFY_ERROR (LIFECYCLE, handle_DD.create() );
+        }
     };
   
   

From d58fa9129c33b259db111976b7350f58e6224b75 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 26 Nov 2011 23:32:56 +0100
Subject: [PATCH 66/68] clean-up: remove direct access to the selection value

---
 src/gui/widgets/timeline/timeline-body.cpp       | 6 ------
 src/gui/widgets/timeline/timeline-body.hpp       | 3 ---
 src/gui/widgets/timeline/timeline-ibeam-tool.hpp | 4 ++--
 src/gui/widgets/timeline/timeline-state.hpp      | 2 --
 4 files changed, 2 insertions(+), 13 deletions(-)

diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp
index e64110997..650feeb6b 100644
--- a/src/gui/widgets/timeline/timeline-body.cpp
+++ b/src/gui/widgets/timeline/timeline-body.cpp
@@ -85,12 +85,6 @@ TimelineBody::getTimelineWidget () const
   return timelineWidget;
 }
 
-TimeSpan
-TimelineBody::get_selection()
-{
-  return timelineWidget.get_state()->get_selection();
-}
-
 ToolType
 TimelineBody::get_tool() const
 {
diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp
index 8abf01a3f..c248ca061 100644
--- a/src/gui/widgets/timeline/timeline-body.hpp
+++ b/src/gui/widgets/timeline/timeline-body.hpp
@@ -74,9 +74,6 @@ public:
   TimelineWidget&
   getTimelineWidget () const;
 
-  TimeSpan
-  get_selection();
-
   /**
    * Returns the type of the currently selected timeline tool.
    */
diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.hpp b/src/gui/widgets/timeline/timeline-ibeam-tool.hpp
index 22cf6862f..ecf5b517d 100644
--- a/src/gui/widgets/timeline/timeline-ibeam-tool.hpp
+++ b/src/gui/widgets/timeline/timeline-ibeam-tool.hpp
@@ -138,12 +138,12 @@ private:
   enum DragType
     {
       /**
-       * No drag is occuring
+       * No drag is occurring
        */
       None,
       
       /**
-       * A selection drag is occuring.
+       * A selection drag is occurring.
        * @remarks The position of one end of the selection was set at
        * mouse-down of the drag, and the other end is set by
        * drag-release.
diff --git a/src/gui/widgets/timeline/timeline-state.hpp b/src/gui/widgets/timeline/timeline-state.hpp
index 36ba996f3..7b5221aa1 100644
--- a/src/gui/widgets/timeline/timeline-state.hpp
+++ b/src/gui/widgets/timeline/timeline-state.hpp
@@ -106,8 +106,6 @@ public:
    */
   timeline::TimelineViewWindow& get_view_window();
   
-  TimeSpan& get_selection()           { return selection_; }
-
   SelectionListener&
   get_selection_listener()            { return selectionListener; }
 

From a6392f5d14adca9bdcedf6217195cf6d4824b6d9 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 27 Nov 2011 00:52:10 +0100
Subject: [PATCH 67/68] review and annotate design aspects regarding zoom
 handling

---
 src/gui/panels/timeline-panel.cpp                 |  1 -
 src/gui/widgets/timeline-widget.cpp               |  3 ++-
 src/gui/widgets/timeline/timeline-body.cpp        |  3 ++-
 src/gui/widgets/timeline/timeline-ruler.cpp       |  2 ++
 src/gui/widgets/timeline/timeline-view-window.cpp | 12 ++++--------
 src/gui/widgets/timeline/timeline-zoom-scale.cpp  |  1 +
 6 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp
index 0366504c6..827a2bee9 100644
--- a/src/gui/panels/timeline-panel.cpp
+++ b/src/gui/panels/timeline-panel.cpp
@@ -144,7 +144,6 @@ TimelinePanel::TimelinePanel (workspace::PanelManager &panel_manager,
   update_tool_buttons();
   update_zoom_buttons();
   show_time (Time::ZERO);
-  std::cout << timelineWidget->get_state()->get_view_window().get_time_scale() << "\n";
 }
 
 const char*
diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp
index b971477c6..81d93e5ba 100644
--- a/src/gui/widgets/timeline-widget.cpp
+++ b/src/gui/widgets/timeline-widget.cpp
@@ -415,12 +415,13 @@ TimelineWidget::update_scroll()
   
   if(state)
     {
+                                            ///////////////////////////////////////////////TICKET #861 shoudln't that be performed by TimelineViewWindow, instead of manipulating values from the outside?
       timeline::TimelineViewWindow &window = state->get_view_window();
       
       //----- Horizontal Scroll ------//
       
       // TEST CODE
-      horizontalAdjustment.set_upper(1000 * GAVL_TIME_SCALE / 200);
+      horizontalAdjustment.set_upper( 1000 * GAVL_TIME_SCALE / 200);
       horizontalAdjustment.set_lower(-1000 * GAVL_TIME_SCALE / 200);
       
       // Set the page size
diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp
index 650feeb6b..1b580c262 100644
--- a/src/gui/widgets/timeline/timeline-body.cpp
+++ b/src/gui/widgets/timeline/timeline-body.cpp
@@ -267,7 +267,8 @@ TimelineBody::on_motion_notify_event(GdkEventMotion *event)
   
   if (timelineState)
     {
-      // Handle a middle-mouse drag if one is occuring
+      // Handle a middle-mouse drag if one is occurring
+                                   /////////////////////////////TICKET #861 : shoudln't all of that be performed by TimelineViewWindow, instead of manipulating values from the outside?
       switch(dragType)
         {
         case Shift:
diff --git a/src/gui/widgets/timeline/timeline-ruler.cpp b/src/gui/widgets/timeline/timeline-ruler.cpp
index b8725aedf..532e461f7 100644
--- a/src/gui/widgets/timeline/timeline-ruler.cpp
+++ b/src/gui/widgets/timeline/timeline-ruler.cpp
@@ -274,6 +274,7 @@ TimelineRuler::draw_ruler(Cairo::RefPtr cr,
   REQUIRE(ruler_rect.get_width() > 0);
   REQUIRE(ruler_rect.get_height() > 0);
   
+                                   /////////////////////////////TICKET #861 : what part of these calculation could be centralised within TimelineViewWindow?
   const TimelineViewWindow &window = viewWindow();
   const gavl_time_t left_offset = _raw(window.get_time_offset());
   const int64_t time_scale = window.get_time_scale();
@@ -504,6 +505,7 @@ TimelineRuler::calculate_major_spacing() const
 {
   unsigned int i;
   
+                                   /////////////////////////////TICKET #861 : couldn't that be a library function in TimelineViewWindow?
   const gavl_time_t major_spacings[] = {
       GAVL_TIME_SCALE / 1000,    
       GAVL_TIME_SCALE / 400,
diff --git a/src/gui/widgets/timeline/timeline-view-window.cpp b/src/gui/widgets/timeline/timeline-view-window.cpp
index 8b6528f11..c53722e89 100644
--- a/src/gui/widgets/timeline/timeline-view-window.cpp
+++ b/src/gui/widgets/timeline/timeline-view-window.cpp
@@ -88,9 +88,8 @@ void
 TimelineViewWindow::zoom_view(int point, double time_scale_ratio)
 {
   // Apply the smoothing factor
-  int64_t new_time_scale =
-      (int64_t)(pow(time_scale_ratio, TimelineWidget::ZoomSmoothing) *
-          (double)TimelineWidget::MaxScale);
+  int64_t new_time_scale(pow (time_scale_ratio, TimelineWidget::ZoomSmoothing)
+                         * double(TimelineWidget::MaxScale));
 
   /* Prevent Zooming in To Close and Far */
   if(new_time_scale < 1)
@@ -100,8 +99,7 @@ TimelineViewWindow::zoom_view(int point, double time_scale_ratio)
     new_time_scale = TimelineWidget::MaxScale;
 
   // The view must be shifted so that the zoom is centred on the cursor
-  TimeVar newStartPoint = get_time_offset();
-  newStartPoint += TimeValue (point * (timeScale - new_time_scale));
+  TimeVar newStartPoint = timeOffset + TimeValue(point * (timeScale - new_time_scale));
   set_time_offset (newStartPoint);
     
   // Apply the new scale
@@ -133,7 +131,5 @@ TimelineViewWindow::changed_signal() const
   return changedSignal;
 }
 
-}   // namespace timeline
-}   // namespace widgets
-}   // namespace gui
+}}} // namespace gui::widgets::timeline
 
diff --git a/src/gui/widgets/timeline/timeline-zoom-scale.cpp b/src/gui/widgets/timeline/timeline-zoom-scale.cpp
index dfa71f858..02169dfdd 100644
--- a/src/gui/widgets/timeline/timeline-zoom-scale.cpp
+++ b/src/gui/widgets/timeline/timeline-zoom-scale.cpp
@@ -102,6 +102,7 @@ TimelineZoomScale::wireTimelineState (shared_ptr currentState,
 void
 TimelineZoomScale::on_timeline_state_changed (shared_ptr newState)
 {
+                                     /////////////////////////////TICKET #861 : part of that could be a library routine!
   REQUIRE (newState);
   timelineState = newState;
   

From d6fa67f2b8f9073737cd3c305ace3664395eb1d0 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 27 Nov 2011 01:28:48 +0100
Subject: [PATCH 68/68] refactor zoom smothing into TimelineViewWindow

---
 src/gui/widgets/timeline-widget.cpp           |  4 +--
 src/gui/widgets/timeline-widget.hpp           | 10 -------
 .../widgets/timeline/timeline-view-window.cpp | 27 +++++++++++++++----
 .../widgets/timeline/timeline-view-window.hpp | 14 ++++++++++
 .../widgets/timeline/timeline-zoom-scale.cpp  | 13 +--------
 5 files changed, 38 insertions(+), 30 deletions(-)

diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp
index 81d93e5ba..fac09a6f5 100644
--- a/src/gui/widgets/timeline-widget.cpp
+++ b/src/gui/widgets/timeline-widget.cpp
@@ -41,9 +41,7 @@ namespace widgets {
 const int TimelineWidget::TrackPadding = 1;
 const int TimelineWidget::HeaderWidth = 150;
 const int TimelineWidget::HeaderIndentWidth = 10;
-const double TimelineWidget::ZoomIncrement = 1.25; // Not currently used
-const double TimelineWidget::ZoomSmoothing = 9.0;
-const int64_t TimelineWidget::MaxScale = 30000000; // 30 Million
+
 
 TimelineWidget::TimelineWidget(shared_ptr source_state)
   : Table(2, 2)
diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp
index b5d57c667..ffff15dda 100644
--- a/src/gui/widgets/timeline-widget.hpp
+++ b/src/gui/widgets/timeline-widget.hpp
@@ -278,20 +278,10 @@ protected:
   bool update_tracks_frozen;
    
   /* ===== Constants ===== */
-public:
-  /**
-   * The maximum scale for timeline display.
-   * @remarks At MaxScale, every pixel on the timeline is equivalent
-   * to 30000000 lumiera::Time increments.
-   */ 
-  static const int64_t MaxScale;
-  static const double ZoomSmoothing;
-  
 protected:
   static const int TrackPadding;
   static const int HeaderWidth;
   static const int HeaderIndentWidth;
-  static const double ZoomIncrement;
 
   friend class timeline::TimelineBody;
   friend class timeline::TimelineHeaderContainer;
diff --git a/src/gui/widgets/timeline/timeline-view-window.cpp b/src/gui/widgets/timeline/timeline-view-window.cpp
index c53722e89..357e4db97 100644
--- a/src/gui/widgets/timeline/timeline-view-window.cpp
+++ b/src/gui/widgets/timeline/timeline-view-window.cpp
@@ -31,6 +31,14 @@ namespace gui {
 namespace widgets {
 namespace timeline {
 
+/* == public constants == */
+  
+const int64_t TimelineViewWindow::MaxScale = 30000000; // 30 Million
+const double TimelineViewWindow::ZoomIncrement = 1.25; // Not currently used
+const double TimelineViewWindow::ZoomSmoothing = 9.0;
+
+
+
 TimelineViewWindow::TimelineViewWindow (Offset offset, int64_t scale)
   : timeOffset(offset)
   , timeScale(scale)
@@ -67,7 +75,7 @@ TimelineViewWindow::set_time_scale(int64_t scale)
 void
 TimelineViewWindow::set_time_scale(double ratio)
 {
-  int64_t max = TimelineWidget::MaxScale;
+  int64_t max = MaxScale;
   int64_t min = 1;
 
   if(ratio <= 0.0)
@@ -84,19 +92,28 @@ TimelineViewWindow::set_time_scale(double ratio)
    set_time_scale((int64_t)(ratio * max));
 }
 
+double
+TimelineViewWindow::get_smoothed_time_scale()  const
+{
+  double linear_scale ( 1.0 / MaxScale * timeScale);
+
+  // reverse the effect of zoom scale smoothing
+  return pow (linear_scale, (1.0 / ZoomSmoothing));
+}
+
 void
 TimelineViewWindow::zoom_view(int point, double time_scale_ratio)
 {
   // Apply the smoothing factor
-  int64_t new_time_scale(pow (time_scale_ratio, TimelineWidget::ZoomSmoothing)
-                         * double(TimelineWidget::MaxScale));
+  int64_t new_time_scale(pow (time_scale_ratio, ZoomSmoothing)
+                         * double(MaxScale));
 
   /* Prevent Zooming in To Close and Far */
   if(new_time_scale < 1)
     new_time_scale = 1;
 
-  if(new_time_scale > TimelineWidget::MaxScale)
-    new_time_scale = TimelineWidget::MaxScale;
+  if(new_time_scale > MaxScale)
+    new_time_scale = MaxScale;
 
   // The view must be shifted so that the zoom is centred on the cursor
   TimeVar newStartPoint = timeOffset + TimeValue(point * (timeScale - new_time_scale));
diff --git a/src/gui/widgets/timeline/timeline-view-window.hpp b/src/gui/widgets/timeline/timeline-view-window.hpp
index d52f84406..f4c6fa558 100644
--- a/src/gui/widgets/timeline/timeline-view-window.hpp
+++ b/src/gui/widgets/timeline/timeline-view-window.hpp
@@ -54,6 +54,16 @@ using lib::time::Offset;
 class TimelineViewWindow
 {
 public:
+    
+  /**
+   * The maximum scale for timeline display.
+   * @remarks At MaxScale, every pixel on the timeline is equivalent
+   * to 30000000 lumiera::Time increments.
+   */ 
+  static const int64_t MaxScale;
+  static const double ZoomSmoothing;
+  static const double ZoomIncrement;
+  
  
   /**
    * @param offset The initial view offset.
@@ -95,6 +105,10 @@ public:
    */
   void set_time_scale(int64_t time_scale);
   void set_time_scale(double ratio);
+  
+  /** get the current time scale with zoom smoothing applied */
+  double get_smoothed_time_scale()  const;
+  
   /**
    * Zooms the view in or out as by a number of steps while keeping a 
    * given point on the timeline still.
diff --git a/src/gui/widgets/timeline/timeline-zoom-scale.cpp b/src/gui/widgets/timeline/timeline-zoom-scale.cpp
index 02169dfdd..99299608a 100644
--- a/src/gui/widgets/timeline/timeline-zoom-scale.cpp
+++ b/src/gui/widgets/timeline/timeline-zoom-scale.cpp
@@ -102,21 +102,10 @@ TimelineZoomScale::wireTimelineState (shared_ptr currentState,
 void
 TimelineZoomScale::on_timeline_state_changed (shared_ptr newState)
 {
-                                     /////////////////////////////TICKET #861 : part of that could be a library routine!
   REQUIRE (newState);
   timelineState = newState;
   
-  int64_t current_scale =
-      getViewWindow().get_time_scale();
-
-  double linear_scale =
-      (double) current_scale / (double) TimelineWidget::MaxScale;
-
-  /* We have to Revese the Smoothing */
-  double new_relative_scale =
-      pow(linear_scale,(1.0 / TimelineWidget::ZoomSmoothing));
-
-  adjustment.set_value(new_relative_scale);
+  adjustment.set_value (getViewWindow().get_smoothed_time_scale());
 }
 
 void