diff --git a/SConstruct b/SConstruct index c2e703031..1f1673f6c 100644 --- a/SConstruct +++ b/SConstruct @@ -60,6 +60,8 @@ def setupBasicEnvironment(): EnsurePythonVersion(2,3) EnsureSConsVersion(0,96,90) + Decider('MD5-timestamp') # detect changed files by timestamp, then do a MD5 + opts = defineCmdlineOptions() env = LumieraEnvironment(options=opts ,toolpath = [TOOLDIR] diff --git a/configure.ac b/configure.ac index cc7eee8b6..297b9c2cc 100644 --- a/configure.ac +++ b/configure.ac @@ -188,9 +188,9 @@ AC_CHECK_HEADER([execinfo.h], AC_DEFINE(HAVE_EXECINFO_H)) PKG_CHECK_MODULES(VALGRIND, [valgrind], AC_DEFINE(HAVE_VALGRIND_H), AC_MSG_NOTICE([valgrind not found (optional)])) -PKG_CHECK_MODULES(NOBUGMT_LUMIERA, [nobugmt >= 200909.1], +PKG_CHECK_MODULES(NOBUGMT_LUMIERA, [nobugmt >= 201001.1], AC_DEFINE(HAVE_NOBUGMT_H), - AC_MSG_ERROR([NoBug pkg-config metadata missing (http://www.pipapo.org/pipawiki/NoBug)]) + AC_MSG_ERROR([Missing required nobug version (http://www.lumiera.org/nobug_manual.html)]) ) # END Nobug Dependancies diff --git a/doc/devel/draw/Session.ScopeStructure-1.svg b/doc/devel/draw/Session.ScopeStructure-1.svg new file mode 100644 index 000000000..98e693597 --- /dev/null +++ b/doc/devel/draw/Session.ScopeStructure-1.svg @@ -0,0 +1,1621 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + Structure of Placement Scopes + + + Ichthyostega + + + design sketch: Relation of the nested Placement Scopes within the Lumiera session + 2009 + + + + + + + + + + + + + + + + + + + + + + + + Clip2 + + Sequence + Timeline-1 + + + Timeline-2 + + + + Clip1 + + Effect + + Effect + + Effect + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + root : global rules + + + + + + + + + + + + + + + + + + + + Binding + global Pipes + global Pipes + + + + + Binding + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + diff --git a/doc/devel/uml/class128645.html b/doc/devel/uml/class128645.html index 27413648f..5f94489fb 100644 --- a/doc/devel/uml/class128645.html +++ b/doc/devel/uml/class128645.html @@ -23,7 +23,9 @@
Operation resolve

create an actual (explicit) placement while trying to satisfy the network of adjacent objects and placements.

Declaration :

Relation subject (<unidirectional association>)

Placement acts as smart pointer

Declaration :

Operation chain

create and add another Placement for this media object, thus increasingly constraining the (possible) position of this object.

Declaration :

-
Relation chain (<unidirectional association>)

Chain of additional Placements further constraining the position of this MObject

Declaration :

+
Relation chain (<unidirectional association>)

Chain of additional Placements further constraining the position of this MObject

Declaration :

+
Relation <unidirectional association>

Declaration :

Stereotype: has_a

+

All public operations : chain , resolve

diff --git a/doc/devel/uml/class152069.html b/doc/devel/uml/class152069.html new file mode 100644 index 000000000..899872f11 --- /dev/null +++ b/doc/devel/uml/class152069.html @@ -0,0 +1,23 @@ + + + + + + +Class PlacementIndex + + + + + +
Class PlacementIndex
+

+ + + + +

Declaration :

+
+

All public operations : issue

+ + diff --git a/doc/devel/uml/class152197.html b/doc/devel/uml/class152197.html new file mode 100644 index 000000000..3bc899ed8 --- /dev/null +++ b/doc/devel/uml/class152197.html @@ -0,0 +1,20 @@ + + + + + + +Class Sequence + + + + + +
Class Sequence
+

+ + + + +

Declaration :

+ diff --git a/doc/devel/uml/class152325.html b/doc/devel/uml/class152325.html new file mode 100644 index 000000000..b800ba25b --- /dev/null +++ b/doc/devel/uml/class152325.html @@ -0,0 +1,20 @@ + + + + + + +Class Binding + + + + + +
Class Binding
+

+ + + + +

Declaration :

+ diff --git a/doc/devel/uml/class152453.html b/doc/devel/uml/class152453.html new file mode 100644 index 000000000..be3d68aa4 --- /dev/null +++ b/doc/devel/uml/class152453.html @@ -0,0 +1,24 @@ + + + + + + +Class PlacementRef + + + + + +
Class PlacementRef
+

+ + + + +

Declaration :

+ +
Relation id_ (<unidirectional association>)

Declaration :

Stereotype: holds

+
+ + diff --git a/doc/devel/uml/class152581.html b/doc/devel/uml/class152581.html new file mode 100644 index 000000000..6b8ffdfb5 --- /dev/null +++ b/doc/devel/uml/class152581.html @@ -0,0 +1,22 @@ + + + + + + +Class Id + + + + + +
Class Id
+

+ + + + +

Declaration :

+
+ + diff --git a/doc/devel/uml/class152709.html b/doc/devel/uml/class152709.html new file mode 100644 index 000000000..331b63679 --- /dev/null +++ b/doc/devel/uml/class152709.html @@ -0,0 +1,21 @@ + + + + + + +Class LuidH + + + + + +
Class LuidH
+

+ + + + +

Declaration :

Directly inherited by : Id

+ + diff --git a/doc/devel/uml/class152837.html b/doc/devel/uml/class152837.html new file mode 100644 index 000000000..05dbec817 --- /dev/null +++ b/doc/devel/uml/class152837.html @@ -0,0 +1,24 @@ + + + + + + +Class MObjectRef + + + + + +
Class MObjectRef
+

+ + + + +

Declaration :

+ +
Relation pRef_ (<unidirectional association>)

Declaration :

Stereotype: holds

+
+ + diff --git a/doc/devel/uml/class152965.html b/doc/devel/uml/class152965.html new file mode 100644 index 000000000..a297d3f85 --- /dev/null +++ b/doc/devel/uml/class152965.html @@ -0,0 +1,21 @@ + + + + + + +Class Handle + + + + + +
Class Handle
+

+ + + + +

Declaration :

Directly inherited by : MObjectRef

+ + diff --git a/doc/devel/uml/class153093.html b/doc/devel/uml/class153093.html new file mode 100644 index 000000000..b5b237ee8 --- /dev/null +++ b/doc/devel/uml/class153093.html @@ -0,0 +1,20 @@ + + + + + + +Class shared_ptr + + + + + +
Class shared_ptr
+

+ + + + +

Declaration :

+ diff --git a/doc/devel/uml/class153221.html b/doc/devel/uml/class153221.html new file mode 100644 index 000000000..9ead038a7 --- /dev/null +++ b/doc/devel/uml/class153221.html @@ -0,0 +1,20 @@ + + + + + + +Class P + + + + + +
Class P
+

+ + + + +

Declaration :

+ diff --git a/doc/devel/uml/class153349.html b/doc/devel/uml/class153349.html new file mode 100644 index 000000000..845e35a8d --- /dev/null +++ b/doc/devel/uml/class153349.html @@ -0,0 +1,26 @@ + + + + + + +Class Scope + + + + + +
Class Scope
+

+ + + + +

Declaration :

+ +
Relation <unidirectional association>

Declaration :

Stereotype: holds

+ +
Operation getParent

Declaration :

+

All public operations : getParent

+ + diff --git a/doc/devel/uml/class153477.html b/doc/devel/uml/class153477.html new file mode 100644 index 000000000..25eca07ee --- /dev/null +++ b/doc/devel/uml/class153477.html @@ -0,0 +1,24 @@ + + + + + + +Class ScopePath + + + + + +
Class ScopePath
+

+ + + + +

Declaration :

+ +
Relation path_ (<directional composition>)

Declaration :

Stereotype: vector

+
+ + diff --git a/doc/devel/uml/class153605.html b/doc/devel/uml/class153605.html new file mode 100644 index 000000000..e4b3f0a0f --- /dev/null +++ b/doc/devel/uml/class153605.html @@ -0,0 +1,23 @@ + + + + + + +Class QueryFocus + + + + + +
Class QueryFocus
+

+ + + + +

Declaration :

+ +
Relation <unidirectional association>

Declaration :

+ + diff --git a/doc/devel/uml/class153733.html b/doc/devel/uml/class153733.html new file mode 100644 index 000000000..1b5d0de72 --- /dev/null +++ b/doc/devel/uml/class153733.html @@ -0,0 +1,23 @@ + + + + + + +Class QueryFocusStack + + + + + +
Class QueryFocusStack
+

+ + + + +

Declaration :

+ +
Relation <directional composition>

Declaration :

+ + diff --git a/doc/devel/uml/class153861.html b/doc/devel/uml/class153861.html new file mode 100644 index 000000000..70c14570f --- /dev/null +++ b/doc/devel/uml/class153861.html @@ -0,0 +1,26 @@ + + + + + + +Class ScopeLocator + + + + + +
Class ScopeLocator
+

+ + + + +

Declaration :

Stereotype: singleton

+
+ +
Relation <unidirectional association>

Declaration :

+
Relation <unidirectional association>

Declaration :

Stereotype: uses

+
+ + diff --git a/doc/devel/uml/class153989.html b/doc/devel/uml/class153989.html new file mode 100644 index 000000000..f41ba6162 --- /dev/null +++ b/doc/devel/uml/class153989.html @@ -0,0 +1,28 @@ + + + + + + +Class QueryResolver + + + + + +
Class QueryResolver
+

+ + + + +

Declaration :

Directly inherited by : PlacementIndex ResolvingFacility

+

Stereotype: interface

+
+ +
Operation issue

Declaration :

+ +
Relation <unidirectional association>

Declaration :

+

All public operations : issue

+ + diff --git a/doc/devel/uml/class155141.html b/doc/devel/uml/class155141.html new file mode 100644 index 000000000..21e3e2ab4 --- /dev/null +++ b/doc/devel/uml/class155141.html @@ -0,0 +1,25 @@ + + + + + + +Class Query + + + + + +
Class Query
+

+ + + + +

Declaration :

+
Class Cursor
+ +
Relation <unidirectional association>

Declaration :

Stereotype: type-def

+
+ + diff --git a/doc/devel/uml/class155269.html b/doc/devel/uml/class155269.html new file mode 100644 index 000000000..0465cbbe2 --- /dev/null +++ b/doc/devel/uml/class155269.html @@ -0,0 +1,23 @@ + + + + + + +Class Cursor + + + + + +
Class Cursor
+

+ + + + +

Declaration :

nested in Query

+
+
+ + diff --git a/doc/devel/uml/class155397.html b/doc/devel/uml/class155397.html new file mode 100644 index 000000000..79a851cef --- /dev/null +++ b/doc/devel/uml/class155397.html @@ -0,0 +1,24 @@ + + + + + + +Class IterAdapter + + + + + +
Class IterAdapter
+

+ + + + +

Declaration :

+ +
Relation source_ (<unidirectional association>)

Declaration :

+
Relation pos_ (<unidirectional association>)

Declaration :

+ + diff --git a/doc/devel/uml/class155525.html b/doc/devel/uml/class155525.html new file mode 100644 index 000000000..9549695c5 --- /dev/null +++ b/doc/devel/uml/class155525.html @@ -0,0 +1,25 @@ + + + + + + +Class ResolvingFacility + + + + + +
Class ResolvingFacility
+

+ + + + +

Declaration :

+ +
Relation <unidirectional association>

Declaration :

Stereotype: produce

+
+

All public operations : issue

+ + diff --git a/doc/devel/uml/class156805.html b/doc/devel/uml/class156805.html new file mode 100644 index 000000000..ac99bb5c1 --- /dev/null +++ b/doc/devel/uml/class156805.html @@ -0,0 +1,26 @@ + + + + + + +Class Goal + + + + + +
Class Goal
+

+ + + + +

Declaration :

Directly inherited by : Query

+

Stereotype: interface

+
+
Class Result
+ +
Relation <unidirectional association>

Declaration :

+ + diff --git a/doc/devel/uml/class156933.html b/doc/devel/uml/class156933.html new file mode 100644 index 000000000..124edc599 --- /dev/null +++ b/doc/devel/uml/class156933.html @@ -0,0 +1,22 @@ + + + + + + +Class Result + + + + + +
Class Result
+

+ + + + +

Declaration :

Directly inherited by : Cursor

+

nested in Goal

+ + diff --git a/doc/devel/uml/class158085.html b/doc/devel/uml/class158085.html new file mode 100644 index 000000000..3c9c4d92a --- /dev/null +++ b/doc/devel/uml/class158085.html @@ -0,0 +1,23 @@ + + + + + + +Class ResultSet + + + + + +
Class ResultSet
+

+ + + + +

Declaration :

+
+

All public operations : isValid , nextResult

+ + diff --git a/doc/devel/uml/class159237.html b/doc/devel/uml/class159237.html new file mode 100644 index 000000000..b390ac9d6 --- /dev/null +++ b/doc/devel/uml/class159237.html @@ -0,0 +1,28 @@ + + + + + + +Class Resolution + + + + + +
Class Resolution
+

+ + + + +

Declaration :

Directly inherited by : ResultSet

+

nested in QueryResolver

+
+ +
Operation isValid

Declaration :

+
Operation nextResult

Declaration :

+
Relation <unidirectional association>

Declaration :

+

All public operations : isValid , nextResult

+ + diff --git a/doc/devel/uml/classdiagrams.html b/doc/devel/uml/classdiagrams.html index bfd20dbab..73a9e7f73 100644 --- a/doc/devel/uml/classdiagrams.html +++ b/doc/devel/uml/classdiagrams.html @@ -23,15 +23,19 @@ Command structure Controller Entities File MappingShows whats used to access Frames +Focus of Query HierarchyLumiera Exception hierarchy In Memory Database interface components Layer Separation Interface Media-Asset Relations +MObjectRef Proc-Asset Relations +Query Interface Render Entities Render Mechanics Rules access +Session backbone Session structure StateAdapter composition Stream Type Framework diff --git a/doc/devel/uml/classes.html b/doc/devel/uml/classes.html index ebec4c117..7254ced2b 100644 --- a/doc/devel/uml/classes.html +++ b/doc/devel/uml/classes.html @@ -27,6 +27,7 @@ AssetManagerboundaryFacade for the Asset subsystem AutoAutomation data for some parameter (i.e. a time varying function) BackendCache +Binding BuffHandle BuffTable Buildableinterface @@ -52,6 +53,7 @@ ConManagerConnection Manager, used to build the connections between render engine nodes, if these nodes need to cooperate besides the normal "data pull" operation. Esp., the Connection Manager knows how to wire up the effect's parameters with the corresponding ParamProviders (autmation) in the Session Constraint ControllerFacadeboundaryProvides unified access to the Proc-Subsystem Controller. Especially, this Facade class provides the functions to get a render engine to carry out actual renderings. +Cursor Datasetmeta asset describing a collection of control data DBImplementation of the registry holding all Asset instances known to the Asset Manager subsystem. As of 8/2007 implemented by a hashtable. DefaultsManager @@ -83,18 +85,23 @@ FrameDescriptorinterfaceA FrameDescriptor implements the higher level interfaces for frames. Further refinements are made by subclassing and policy classes FrameReference GLBuf +Goalinterface +Handle HandlingPatterninterface +Id ImplFacade InstanceHandle InterpolatorProvides the implementation for getting the acutal value of a time varying or automated effect/plugin parameter Invalid Invocation +IterAdapter Label Link LocatingPinAn element with value semantics, which actually implements the placement of some MObject by positioning it in some way. Lock Lock Logic +LuidH Mask Mediakey abstraction: media-like assets MediaAccessFacadeboundaryprovides functions for querying (opening) a media file, detecting the channels or streams found within this file, etc. Delegating to the actual backend functions @@ -103,18 +110,22 @@ Metakey abstraction: metadata and organisational asset Meta MObjectinterface +MObjectRef Monitor Mutationfunc MutexI provided a reworked Mutex class in my Cinelerra2 repository NodeCreatorToolThis Tool implementation plays the central role in the buld process: given a MObject from Session, it is able to attach ProcNodes to the render engine under construction such as to reflect the properties of the MObject in the actual render. NodeWiring OperationBase +P ParamAccessor ParameterDescriptor and access object for a plugin parameter. Parameters may be provided with values from the session, and this values may be automated. ParamProviderinterfaceA facility to get the actual value of a plugin/effect parameter PathManagerWhile building a render engine, this Strategy class decides on the actual render strategy in accordance to the current controller settings (system state) Pipestructural asset representing a basic building block within the high level model: a port for building a processing chain and generating media output Placementinterfaceused to specify the position of a MObject in the EDL. This can be done in various ways (absolute, relative).
Placement at the same time acts as (refcounting) smart pointer for accessing the MObject. +PlacementIndex +PlacementRef PlayControl PlayheadCursor Plug @@ -131,9 +142,13 @@ Prototype Proxy PullInput +Query QueryCache +QueryFocus +QueryFocusStack QueryHandlerinterface QueryHandlerImpl +QueryResolverinterface ReadSource RedoLast RelativeLocation @@ -142,18 +157,27 @@ RenderGraph RenderStateEncapsulates the logic used to get a "current render process" in accordance to the currentyl applicable controller settings. The provided StateProxy serves to hold any mutalbe state used in the render process, so the rest of the render engine can be stateless. RenderTask +Resolution ResolverBase +ResolvingFacility +Result +ResultSet Scheduler +Scope +ScopeLocatorsingleton +ScopePath Segment Segmentation SegmentationToolTool implementation for deriving a partitioning of the current timeline such, that each segement has a constant configuration. "Constant" means here, that any remaining changes over time can be represented by automation solely, without the need to change the node connections. Seq +Sequence Sequence Serializeractor ServiceImpl SessionPrimary Interface for all editing tasks.
The session contains defaults, all the assets being edited, and a set of EDL with the individual MObjects to be manipulated and rendered. SessionImplImplementation class for the Session interface SessManager +shared_ptr SimpleClipElementary clip consisting of only one media stream SmartPointerauxiliary SourceSource Node: represents a media source to pull data from. diff --git a/doc/devel/uml/classes_list.html b/doc/devel/uml/classes_list.html index 173ec52e4..ab8b6e948 100644 --- a/doc/devel/uml/classes_list.html +++ b/doc/devel/uml/classes_list.html @@ -28,6 +28,7 @@ AssetManager
Auto
BackendCache
+Binding
BuffHandle
BuffTable
Buildable
@@ -53,6 +54,7 @@ ConManager
Constraint
ControllerFacade
+Cursor
Dataset
DB
DefaultsManager
@@ -84,18 +86,23 @@ FrameDescriptor
FrameReference
GLBuf
+Goal
+Handle
HandlingPattern
+Id
ImplFacade
InstanceHandle
Interpolator
Invalid
Invocation
+IterAdapter
Label
Link
LocatingPin
Lock
Lock
Logic
+LuidH
Mask
Media
MediaAccessFacade
@@ -104,18 +111,22 @@ Meta
Meta
MObject
+MObjectRef
Monitor
Mutation
Mutex
NodeCreatorTool
NodeWiring
OperationBase
+P
ParamAccessor
Parameter
ParamProvider
PathManager
Pipe
Placement
+PlacementIndex
+PlacementRef
PlayControl
PlayheadCursor
Plug
@@ -132,9 +143,13 @@ Prototype
Proxy
PullInput
+Query
QueryCache
+QueryFocus
+QueryFocusStack
QueryHandler
QueryHandlerImpl
+QueryResolver
ReadSource
RedoLast
RelativeLocation
@@ -143,18 +158,27 @@ RenderGraph
RenderState
RenderTask
+Resolution
ResolverBase
+ResolvingFacility
+Result
+ResultSet
Scheduler
+Scope
+ScopeLocator
+ScopePath
Segment
Segmentation
SegmentationTool
Seq
+Sequence
Sequence
Serializer
ServiceImpl
Session
SessionImpl
SessManager
+shared_ptr
SimpleClip
SmartPointer
Source
diff --git a/doc/devel/uml/fig134021.png b/doc/devel/uml/fig134021.png index edd544530..5405d2010 100644 Binary files a/doc/devel/uml/fig134021.png and b/doc/devel/uml/fig134021.png differ diff --git a/doc/devel/uml/fig136325.png b/doc/devel/uml/fig136325.png new file mode 100644 index 000000000..d3247b41e Binary files /dev/null and b/doc/devel/uml/fig136325.png differ diff --git a/doc/devel/uml/fig136453.png b/doc/devel/uml/fig136453.png new file mode 100644 index 000000000..2768139df Binary files /dev/null and b/doc/devel/uml/fig136453.png differ diff --git a/doc/devel/uml/fig136581.png b/doc/devel/uml/fig136581.png new file mode 100644 index 000000000..f94911df8 Binary files /dev/null and b/doc/devel/uml/fig136581.png differ diff --git a/doc/devel/uml/fig137733.png b/doc/devel/uml/fig137733.png new file mode 100644 index 000000000..df4eb2a81 Binary files /dev/null and b/doc/devel/uml/fig137733.png differ diff --git a/doc/devel/uml/index.html b/doc/devel/uml/index.html index 4cbf83614..a7d15c3ef 100644 --- a/doc/devel/uml/index.html +++ b/doc/devel/uml/index.html @@ -147,7 +147,7 @@ Documentation
Artifact Lumiera

the main executable to be built

Depends on common

Depends on gui

Depends on proc

Depends on backend

Stereotype: executable

-

executable associated with : allocation, vframe, toolfactory, hub, buildable, abstractmo, exitnode, pathmanager, track, meta, fixedlocation, relativelocation, controllerfacade, rendergraph, pluginadapter, explicitplacement, auto, glrender, arender, renderstate, label, nodecreatertool, projector, interpolator, paramprovider, mask, mobject, source, frame, effect, buildertool, segmentationtool, link, parameter, renderengine, glbuf, procnode, stateproxy, edl, fixture, glpipe, main, conmanager, clip, vrender, placement, sessionimpl, builderfacade, aframe, assembler, trafo

+

executable associated with : aframe, assembler, trafo, allocation, vframe, toolfactory, hub, buildable, abstractmo, exitnode, pathmanager, track, meta, fixedlocation, relativelocation, controllerfacade, rendergraph, pluginadapter, explicitplacement, auto, glrender, arender, renderstate, label, nodecreatertool, projector, interpolator, paramprovider, mask, mobject, source, frame, effect, buildertool, segmentationtool, link, parameter, renderengine, glbuf, procnode, stateproxy, edl, fixture, glpipe, main, conmanager, clip, vrender, placement, sessionimpl, builderfacade

Artifact main

Stereotype: source

@@ -949,8 +949,11 @@ undo

2.3 Package MObject

+ +

2.3.1 Package Session

+
-

2.3.1 Class View Session

+

2.3.1.1 Class View Session parts

@@ -987,17 +990,55 @@ undo + +

2.3.1.2 Class View Object ref

+
+ +

+

MObjectRef



+
+
Class Id
+
Class LuidH
+
+
+ +

2.3.1.3 Class View Datastructure

+
+ +

+

Session backbone



+
+
Class Sequence
+
Class Binding
+
+
+ +

2.3.2 Package Placement

+
+ +

2.3.2.1 Class View Scopes

+
+ +

+

Focus of Query



+
Class Scope
+
Class ScopePath
+
+
+
+
+
-

2.3.2 Package Builder

+

2.3.3 Package Builder

-

2.3.2.1 Class View Builder Workings

+

2.3.3.1 Class View Builder Workings

build process



This figure shows the process of building and starting a RenderEngine

-

2.3.2.1.1 Activity building the Engine

+

2.3.3.1.1 Activity building the Engine

Pre Condition :

    Post Condition :

      @@ -1011,7 +1052,7 @@ undo

      Defined in building the Engine

      Pre Condition :

        Post Condition :

          Behavior :

            Flow <flow>

            From configure Tools To fork activity node

            Weight :

              Guard :

                Selection :

                  Transformation :

                    -

                    2.3.2.1.1.1 Expansion region establish partitioning

                    +

                    2.3.3.1.1.1 Expansion region establish partitioning

                    Opaque activity action define segment
                    @@ -1038,7 +1079,7 @@ undo

                    Defined in building the Engine

                    Flow <flow>

                    From fork activity node To segment Tool

                    Weight :

                      Guard :

                        Selection :

                          Transformation :

                            Flow <flow>

                            From fork activity node To build Tool

                            Weight :

                              Guard :

                                Selection :

                                  Transformation :

                                    -

                                    2.3.2.1.1.2 Expansion region build Processors

                                    +

                                    2.3.3.1.1.2 Expansion region build Processors

                                    Activity object build Tool
                                    @@ -1086,7 +1127,7 @@ undo
                                    -

                                    2.3.3 Use Case View config examples

                                    +

                                    2.3.4 Use Case View config examples

                                    @@ -1474,6 +1515,15 @@ undo
                                    + +

                                    +

                                    Query Interface



                                    +
                                    +
                                    Class Goal
                                    +
                                    Class Query
                                    +
                                    +
                                    +
                                    Class ResultSet

                                    5.3.3 Use Case View query use

                                    @@ -1503,8 +1553,18 @@ undo
                                    Class instance predicate impl

                                    type :TypeHandler

                                    + +

                                    5.4 Package Containers

                                    +
                                    + +

                                    5.4.1 Class View Custom holders

                                    +
                                    +
                                    Class Handle
                                    +
                                    Class P
                                    +
                                    +
                                    -

                                    5.4 Class View error

                                    +

                                    5.5 Class View error

                                    @@ -1518,7 +1578,7 @@ undo -

                                    5.5 Class View Service Components

                                    +

                                    5.6 Class View Service Components

                                    Class Tool
                                    @@ -1528,7 +1588,7 @@ undo
                                    Class Appconfig
                                    -

                                    5.6 Class View Posix Threads Abstraction

                                    +

                                    5.7 Class View Posix Threads Abstraction

                                    C++ wrapers for pthreads

                                    Class Thread
                                    @@ -1536,9 +1596,10 @@ undo
                                    Class Mutex
                                    -

                                    5.7 Class View SmartPointers

                                    +

                                    5.8 Class View SmartPointers

                                    +
                                    diff --git a/doc/devel/uml/index_60.html b/doc/devel/uml/index_60.html index ab6befaf1..5fa958d5f 100644 --- a/doc/devel/uml/index_60.html +++ b/doc/devel/uml/index_60.html @@ -17,8 +17,8 @@ - + @@ -28,10 +28,10 @@ - - + + @@ -45,20 +45,20 @@ - - - - - - - - + + + + + + + + - +
                                    NameKindDescription
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    diff --git a/doc/devel/uml/index_65.html b/doc/devel/uml/index_65.html index 38dfaced6..4afe9874b 100644 --- a/doc/devel/uml/index_65.html +++ b/doc/devel/uml/index_65.html @@ -57,8 +57,8 @@ Assetsclass view ATTACHattributeattach subject to anchor (e.g. an effect to a clip) au1class instance -aud_aclass instance aud_Aclass instance +aud_aclass instance audioclass instance audio1class instance audio1class instance diff --git a/doc/devel/uml/index_66.html b/doc/devel/uml/index_66.html index 2788567d7..bb6bceff8 100644 --- a/doc/devel/uml/index_66.html +++ b/doc/devel/uml/index_66.html @@ -23,6 +23,7 @@ backend-componentscomponent diagram BackendCacheclass BackendLayerpackage +Bindingclass BuffHandleclass BuffTableclass buildoperation @@ -37,8 +38,8 @@ buildableartifactmarker interface denoting any MObject able to be treated by Tools buildEngineoperationMain Operation of the Builder: create a render engine for a given part of the timeline Buildercomponent -builderpackagesourcecode package

                                    The Builder creating the Render Engine,
                                    located within the MObject Subsystem Builderpackage +builderpackagesourcecode package

                                    The Builder creating the Render Engine,
                                    located within the MObject Subsystem Builder Entitiesclass diagram Builder Tool (Visitor)class diagram Builder Workingsclass view diff --git a/doc/devel/uml/index_67.html b/doc/devel/uml/index_67.html index a8a98a5d6..573a61e0e 100644 --- a/doc/devel/uml/index_67.html +++ b/doc/devel/uml/index_67.html @@ -34,39 +34,39 @@ checked_inrelationchecked_in objects are subject of cache aging and must be not in use checked_outrelationthis list keeps all mappings which are in use, and thus prevents them from Cache aging choice pseudo statechoice pseudo state +class instanceclass instance +class instanceclass instance +class instanceclass instance +class instanceclass instance +class instanceclass instance +class instanceclass instance class instanceclass instance class instanceclass instance class instanceclass instance -class instanceclass instance class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance class instanceclass instance +class instanceclass instance class instanceclass instance -class instanceclass instance -class instanceclass instance +class instanceclass instance +class instanceclass instance +class instanceclass instance +class instanceclass instance class instanceclass instance -class instanceclass instance +class instanceclass instance +class instanceclass instance class instanceclass instance class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance -class instanceclass instance +class instanceclass instance class instanceclass instance +class instanceclass instance +class instanceclass instance +class instanceclass instance +class instanceclass instance clearoperationclear current session contents
                                    without resetting overall session config.
                                    Afterwards, the session will contain only one
                                    empty EDL, while all Assets are retained.
                                    client codecomponent Clipclassbookkeeping (asset) view of a media clip. -clipartifactbookkeeping (asset) view of a media clip. clipartifacta Media Clip +clipartifactbookkeeping (asset) view of a media clip. Clipclass clipsrelation closureattribute @@ -109,6 +109,7 @@ connectopaque activity action constraintartifactLocatingPin representing an directive by the user that
                                    must not be violated Constraintclass +Containerspackage controlpackagesourcecode package

                                    The Processing and Render Controller,
                                    and the Proc-Layer dispatcher ControlpackageCommand handling, Proc-Layer dispatcher, controller and administrative facilities Controllercomponent @@ -124,6 +125,8 @@ currentclass instance currentrelationStandard access path to get at the current session via the Session Manager, which acts as a "PImpl" smart pointer currFramerelation +Cursorclass +Custom holdersclass view diff --git a/doc/devel/uml/index_68.html b/doc/devel/uml/index_68.html index 580695e3a..0af5dabf9 100644 --- a/doc/devel/uml/index_68.html +++ b/doc/devel/uml/index_68.html @@ -20,6 +20,7 @@ Datasetclassmeta asset describing a collection of control data datasetartifactmeta asset describing a collection of control data datasrcrelationThe predecessor in a processing pipeline, i.e. a source to get data to be processed +Datastructureclass view DBclassImplementation of the registry holding all Asset instances known to the Asset Manager subsystem. As of 8/2007 implemented by a hashtable. dbartifactregistry holding known Asset instances. defaultsrelation @@ -32,8 +33,8 @@ designpackage designpackageAll things concering the big picture.
                                    Not a real code package, rather a container for design drafts, specifications, decisions. detect Channelsuse case -determine Render Paramsopaque activity action determine Render Paramsexpansion region +determine Render Paramsopaque activity action devnullclass instance Dispatchercomponent dispatchOpoperation diff --git a/doc/devel/uml/index_70.html b/doc/devel/uml/index_70.html index 93fe59aa1..e177ed876 100644 --- a/doc/devel/uml/index_70.html +++ b/doc/devel/uml/index_70.html @@ -39,9 +39,10 @@ fixtureartifactthe (low level) representation of the EDL with concrete placement data Fixturecomponent Fixtureclass +Focus of Queryclass diagram fork activity nodefork activity node -fork pseudo statefork pseudo state fork pseudo statefork pseudo state +fork pseudo statefork pseudo state FrameclassFrames are just a low level lump of continous memory, most parts are opaque. Frames are memory sensitive, they will be small constant sized structures which can be efficently managed in a pool. Framenode FrameclassTODO: how to relate to Cehteh's Frame entity in the Backend?
                                    The latter is the fundamental Frame entity, wheras this Object rather represents a buffer set containing frame date diff --git a/doc/devel/uml/index_71.html b/doc/devel/uml/index_71.html index a95c02ef8..93915463a 100644 --- a/doc/devel/uml/index_71.html +++ b/doc/devel/uml/index_71.html @@ -38,6 +38,7 @@ getFixtureoperationWhile the session can be comprised of several EDLs,
                                    there is only one Fixture, which represents the actual
                                    configuration of all Objects to be rendered getFrameoperationmode = READ, WRITE, ... getIDoperation +getParentoperation getParentsoperationList of entities this asset depends on or requires to be functional. May be empty. The head of this list can be considered the primary prerequisite getPlaylistForRenderoperation getStateProxyoperation @@ -49,6 +50,7 @@ globalBussesrelation glpipeartifactspecialized connection element for handling OpenGL implementation details glrenderartifactRepresentation of a OpenGL accellerated Video render process +Goalclass graphnode groupsattributeadditional classification, selections or departments this asset belongs to. Groups are optional, non-exclusive and may be overlapping. guipackagesourcecode package

                                    User Interface classes go here diff --git a/doc/devel/uml/index_72.html b/doc/devel/uml/index_72.html index 7356cb17f..2d011b5a4 100644 --- a/doc/devel/uml/index_72.html +++ b/doc/devel/uml/index_72.html @@ -17,6 +17,7 @@ + @@ -24,8 +25,8 @@ - +
                                    NameKindDescription
                                    Handleclass
                                    handlerelationweak pointer
                                    handlesrelation
                                    handles_availableattributeinitialized to the maximum number of filehandles the backend may use for mapped files. When no handles are available, the handle which is last in the handles list is closed and (re-)used.
                                    Else this number is decremented for each new filehandle used and incremented for any one explicitly freed.
                                    Hierarchyclass diagramLumiera Exception hierarchy
                                    howtoProcoperation@return descriptor how to build a render pipeline corresponding to this media
                                    hubartifactspecial ProcNode used to build data distributing connections
                                    HUEclass instance
                                    HUEclass instance
                                    HUEclass instance
                                    diff --git a/doc/devel/uml/index_73.html b/doc/devel/uml/index_73.html index 1e264158e..bc3749d4b 100644 --- a/doc/devel/uml/index_73.html +++ b/doc/devel/uml/index_73.html @@ -20,6 +20,8 @@ idattributeAsset primary key. IDattribute IDentry point pseudo state +Idclass +id_relation ImplFacadeclass In Memory Databaseclass diagram inFixtureactivity action pin @@ -40,6 +42,9 @@ iporelation isActiveoperationweather this asset is swithced on and consequently included in the fixture and participates in rendering isCalculatedoperation +issueoperation +isValidoperation +IterAdapterclass diff --git a/doc/devel/uml/index_76.html b/doc/devel/uml/index_76.html index bdd59ab29..3eaed2f2b 100644 --- a/doc/devel/uml/index_76.html +++ b/doc/devel/uml/index_76.html @@ -34,6 +34,7 @@ Lockclass Logicclass longDescattributeuser visible qualification of the thing, unit or concept represented by this asset. perferably "in one line". To be localized. +LuidHclass Lumieraartifactthe main executable to be built lumierapackage diff --git a/doc/devel/uml/index_77.html b/doc/devel/uml/index_77.html index bef78819f..c54b8ea8c 100644 --- a/doc/devel/uml/index_77.html +++ b/doc/devel/uml/index_77.html @@ -41,6 +41,8 @@ mobjectpackagesourcecode package

                                    MObject Subsystem
                                    including the Session (EDL), Builder and Processing Controller MObjectpackage MObjectclass +MObjectRefclass diagram +MObjectRefclass Monitorclass multichannel clipobject diagram Mutationclass diff --git a/doc/devel/uml/index_78.html b/doc/devel/uml/index_78.html index 2671839d3..dd4d80ba8 100644 --- a/doc/devel/uml/index_78.html +++ b/doc/devel/uml/index_78.html @@ -21,6 +21,7 @@ nameattribute need sub objectuse case nextrelationnext additional LocatingPin, if any +nextResultoperation node1class instance node2class instance node3class instance diff --git a/doc/devel/uml/index_79.html b/doc/devel/uml/index_79.html index 0f0da521d..c557cd0be 100644 --- a/doc/devel/uml/index_79.html +++ b/doc/devel/uml/index_79.html @@ -17,11 +17,12 @@ + - + diff --git a/doc/devel/uml/index_80.html b/doc/devel/uml/index_80.html index fc2fcf572..1c5804224 100644 --- a/doc/devel/uml/index_80.html +++ b/doc/devel/uml/index_80.html @@ -17,6 +17,7 @@
                                    NameKindDescription
                                    Object refclass view
                                    offsetattributeOffset the actual position by this (time) value relative to the anchor point. TODO: Representation?
                                    OperationBaseclass
                                    orgattributeorigin or authorship id. Can be a project abbreviation, a package id or just the authors nickname or UID. This allows for the compnent name to be more generic (e.g. "blur"). Default for all assets provided by the core Lumiera codebase is "lumi".
                                    ouputclass instance
                                    ouputclass instance
                                    ouputclass instance
                                    ouputclass instance
                                    outPortrelationthe Port this MObject wants to be conected to
                                    Overviewcomponent diagramThis drawing shows the top level compoents and relations
                                    + @@ -25,6 +26,7 @@ + @@ -32,7 +34,10 @@ + + + @@ -44,9 +49,11 @@ + + diff --git a/doc/devel/uml/index_81.html b/doc/devel/uml/index_81.html index 6367201fd..eb42837b2 100644 --- a/doc/devel/uml/index_81.html +++ b/doc/devel/uml/index_81.html @@ -18,11 +18,16 @@
                                    NameKindDescription
                                    Pclass
                                    paramrelation
                                    ParamAccessorclass
                                    parameterartifactrepresentation of an automatable effect/plugin parameter
                                    ParamProviderclassA facility to get the actual value of a plugin/effect parameter
                                    paramsrelation
                                    paramsrelation
                                    path_relation
                                    PathManagerclassWhile building a render engine, this Strategy class decides on the actual render strategy in accordance to the current controller settings (system state)
                                    pathmanagerartifactManager for deciding the actual render strategy
                                    Pipeclassstructural asset representing a basic building block within the high level model: a port for building a processing chain and generating media output
                                    pipesrelation
                                    pipesrelationthe global ports (busses) of the session
                                    placementartifactKey Abstraction: a way to place and locate a Media Object
                                    Placementpackage
                                    Placementclassused to specify the position of a MObject in the EDL. This can be done in various ways (absolute, relative).
                                    Placement at the same time acts as (refcounting) smart pointer for accessing the MObject.
                                    PlacementIndexclass
                                    PlacementRefclass
                                    playoperationTODO: will probably be handled differently (see Cehteh)
                                    PlayControlclass
                                    PlayheadCursorclass
                                    pluginadapterartifactAdapter for integrating various Effect processors in the render pipeline
                                    pnodenode
                                    pointattributeidentifying the point where the nodes should be attached
                                    pos_relation
                                    Posix Threads Abstractionclass viewC++ wrapers for pthreads
                                    predecessorsrelation
                                    predicate implclass instance
                                    pRef_relation
                                    Prefetchclass
                                    Previewclassalternative version of the media data, probably with lower resolution
                                    previewartifactalternative version of the media data, probably with lower resolution
                                    + + + + +
                                    NameKindDescription
                                    queryclass view
                                    Queryclass
                                    Query Interfaceclass diagram
                                    Query System overviewcomponent view
                                    query useuse case view
                                    QueryCacheclass
                                    QueryFocusclass
                                    QueryFocusStackclass
                                    QueryHandlerclass
                                    QueryHandlerImplclass
                                    QueryResolverclass
                                    diff --git a/doc/devel/uml/index_82.html b/doc/devel/uml/index_82.html index 3f9b13363..827043e15 100644 --- a/doc/devel/uml/index_82.html +++ b/doc/devel/uml/index_82.html @@ -45,11 +45,15 @@ RenderTaskclass reprattributehuman readable representation of the condition characterizing this allocaton, e.g. "t >= 10" resetoperationreset all session config and
                                    start with a pristine default session. +Resolutionclass resolveoperationcreate an actual (explicit) placement while trying to satisfy the network of adjacent objects and placements. resolveoperation resolveoperation Resolvercomponent ResolverBaseclass +ResolvingFacilityclass +Resultclass +ResultSetclass retrieveoperation rootCauseoperationIf this exception was caused by a chain of further exceptions,
                                    return the first one registered in this throw sequence.
                                    This works only, if every exceptions thrown as a consequence
                                    of another exception is propperly constructed by passing
                                    the original exception to the constructor Rule Basecomponent diff --git a/doc/devel/uml/index_83.html b/doc/devel/uml/index_83.html index fa8dc7579..f519ce594 100644 --- a/doc/devel/uml/index_83.html +++ b/doc/devel/uml/index_83.html @@ -20,6 +20,11 @@ SAMETIMEattributeplace subject at the sime time as the anchor saveoperationcreate a complete, serialized representation
                                    of the current session config and contents.
                                    @todo how to serialize, prameters, return value? Schedulerclass +Scopeclass +ScopeLocatorclass +ScopePathclass +Scopesclass view +scopesrelation scratchstate segmentartifactSegment of the Timeline.
                                    Used at the moment (7/07) for partitioning the timeline/fixture into segments
                                    to be rendered by a specialized render node network for each, without the need
                                    to change any connections within a given segment.
                                    Note this concept may be superfluos alltogether; is a draft and the real
                                    use still needs to be worked out... Segmentclass @@ -31,15 +36,18 @@ segmentsactivity object segmentsrelationthe partitioning of the Timeline to be created by this tool. Seqclass +Sequenceclass Sequenceclass Serializerclass Service Componentsclass view ServiceImplclass Sessioncomponent sessionartifactInterface: the session edited by the user -Sessionclass view sessionpackagesourcecode package

                                    Everything concerning the EDL and Session, within the MObject Subsystem +Sessionpackage SessionclassPrimary Interface for all editing tasks.
                                    The session contains defaults, all the assets being edited, and a set of EDL with the individual MObjects to be manipulated and rendered. +Session backboneclass diagram +Session partsclass view Session structureclass diagram sessionimplartifactholds the complete session data to be edited by the user SessionImplclassImplementation class for the Session interface @@ -47,6 +55,7 @@ SessManagerclass setup Build Paramsopaque activity action setup StateProxyopaque activity action +shared_ptrclass shortDescattributeuser visible Name-ID. To be localized. simpleclipartifactElementary clip (single media stream only) SimpleClipclassElementary clip consisting of only one media stream @@ -57,21 +66,22 @@ SourceclassSource Node: represents a media source to pull data from. sourceartifactRepresentation of a Media source Source Overviewdeployment diagram +source_relation startattributebegin of the timerange covered by this processor startattribute Stateclass Statenode Stateclass staterelation -state actionstate action -state actionstate action -state actionstate action -state actionstate action state actionstate actiontry to fetch existing definition -state actionstate action +state actionstate action state actionstate action state actionstate action state actionstate action +state actionstate action +state actionstate action +state actionstate action +state actionstate action StateAdapterclass StateAdapter compositionclass diagram StateProxyclass diff --git a/doc/devel/uml/index_84.html b/doc/devel/uml/index_84.html index ea6b9d69e..5ca78a2ce 100644 --- a/doc/devel/uml/index_84.html +++ b/doc/devel/uml/index_84.html @@ -34,8 +34,8 @@ Trackclassstructural asset holding the configuration of a track in the EDL trackattribute trackrelation -trackartifactA grouping device within the EDL. The corresponding Placement
                                    by which this Track object is refered defines fallback placing
                                    properties to be used by all objects placed on this track in
                                    case they don't specify more concrete placements.
                                    Typically, tracks are used do make default Port connections,
                                    define a layer or pan for sound and for for disabling groups
                                    of clips. Note tracks are grouped in a tree like fashion.
                                    trackartifactstructural asset holding the configuration of a track in the EDL +trackartifactA grouping device within the EDL. The corresponding Placement
                                    by which this Track object is refered defines fallback placing
                                    properties to be used by all objects placed on this track in
                                    case they don't specify more concrete placements.
                                    Typically, tracks are used do make default Port connections,
                                    define a layer or pan for sound and for for disabling groups
                                    of clips. Note tracks are grouped in a tree like fashion.
                                    trackrelation Trackclass tracksrelationelementary media assets comprising this compound @@ -45,9 +45,9 @@ treatoperation treatoperationThis operation is to be overloaded for the specific MObject subclasses to be treated. treatoperation +treatoperation treatoperation treatoperation -treatoperation treatoperation treatoperation treatoperation diff --git a/doc/devel/uml/index_86.html b/doc/devel/uml/index_86.html index 85cc3a896..ada782f0a 100644 --- a/doc/devel/uml/index_86.html +++ b/doc/devel/uml/index_86.html @@ -21,21 +21,21 @@ VFrameclass vframeartifacta buffer and render process holding a Video frame vid1class instance -vid_Aclass instance -vid_Aclass instance -vid_aclass instance vid_aclass instance +vid_aclass instance +vid_Aclass instance vid_Aclass instance +vid_Aclass instance +videoclass instance videoclass instance videoclass instance -videoclass instance videoclass instance -video1class instance -video1class instance -video1class instance -video1class instance -video1class instance video1class instance +video1class instance +video1class instance +video1class instance +video1class instance +video1class instance Visitableclass visitorpackagesub-namespace for visitor library implementation visitorartifactAcyclic Visitor library diff --git a/doc/devel/uml/packages.html b/doc/devel/uml/packages.html index 7b039a400..8b63a59fb 100644 --- a/doc/devel/uml/packages.html +++ b/doc/devel/uml/packages.html @@ -20,12 +20,13 @@ Asset backendsrcsourcecode package

                                    Data backend classes here... BackendLayer -Builder buildersrcsourcecode package

                                    The Builder creating the Render Engine,
                                    located within the MObject Subsystem +Builder codegenThis package is used to organize code generation by BOUML. It is considered useless after having generated the initial code skeleton. commonsrcsourcecode package

                                    Common library and helper classes CommonLib ConfigQuery +Containers controlsrcsourcecode package

                                    The Processing and Render Controller,
                                    and the Proc-Layer dispatcher ControlCommand handling, Proc-Layer dispatcher, controller and administrative facilities design @@ -37,10 +38,12 @@ lumiera mobjectsrcsourcecode package

                                    MObject Subsystem
                                    including the Session (EDL), Builder and Processing Controller MObject +Placement procsrcsourcecode package

                                    All classes belonging to the (middle) processing layer ProcessingLayer RenderEngine sessionsrcsourcecode package

                                    Everything concerning the EDL and Session, within the MObject Subsystem +Session toolsrcsourcecode package

                                    Tools and Utilities
                                    (separate from the main cinelrra binary) visitorsub-namespace for visitor library implementation diff --git a/doc/devel/uml/public_operations.html b/doc/devel/uml/public_operations.html index 717b3562d..02e32e775 100644 --- a/doc/devel/uml/public_operations.html +++ b/doc/devel/uml/public_operations.html @@ -44,6 +44,7 @@ getFixtureSessionWhile the session can be comprised of several EDLs,
                                    there is only one Fixture, which represents the actual
                                    configuration of all Objects to be rendered getFrameFilemode = READ, WRITE, ... getIDAssetManager +getParentScope getParentsAssetList of entities this asset depends on or requires to be functional. May be empty. The head of this list can be considered the primary prerequisite getPlaylistForRenderFixture getStateProxyRenderState @@ -53,9 +54,12 @@ howtoProcMedia@return descriptor how to build a render pipeline corresponding to this media isActiveAssetweather this asset is swithced on and consequently included in the fixture and participates in rendering isCalculatedState +issueQueryResolver +isValidResolution knownAssetManager@return true if the given id is registered in the internal asset DB loadSessManagerreplace the current session by a new
                                    session loaded from serialized state. makeTypeHandler +nextResultResolution playRenderEngineTODO: will probably be handled differently (see Cehteh) processProcNode pullProcNode @@ -70,13 +74,13 @@ saveSessManagercreate a complete, serialized representation
                                    of the current session config and contents.
                                    @todo how to serialize, prameters, return value? treatApplicable treatBuilderToolThis operation is to be overloaded for the specific MObject subclasses to be treated. +treatNodeCreatorTool treatNodeCreatorTool treatNodeCreatorTool -treatNodeCreatorTool treatNodeCreatorTool treatSegmentationTool -treatSegmentationTool treatSegmentationTool +treatSegmentationTool useFileFileProviderAnnounces that the application intends to use this file with mode (READ|WRITE|READWRITE) useTemporaryStorageFileProviderProvides a pool for interminate frames whatError diff --git a/src/common/subsystem-runner.hpp b/src/common/subsystem-runner.hpp index d8fa5bb6d..8e7edcffc 100644 --- a/src/common/subsystem-runner.hpp +++ b/src/common/subsystem-runner.hpp @@ -26,6 +26,7 @@ #include "lib/error.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "common/subsys.hpp" #include "lib/sync.hpp" diff --git a/src/include/logging.h b/src/include/logging.h index ad67cb300..2cbd07a82 100644 --- a/src/include/logging.h +++ b/src/include/logging.h @@ -123,6 +123,8 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( thread, backend); NOBUG_CPP_DEFINE_FLAG_PARENT ( proc, progress); /** progress log for proc-layer command dispatch */ NOBUG_CPP_DEFINE_FLAG_PARENT ( command, proc); +/** progress log for session datastructure */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( session, proc); /** progress log for the gui */ NOBUG_CPP_DEFINE_FLAG_PARENT ( gui, progress); /** progress log for the support lib */ diff --git a/src/lib/bool-checkable.hpp b/src/lib/bool-checkable.hpp index dd03610b8..8ff9ab063 100644 --- a/src/lib/bool-checkable.hpp +++ b/src/lib/bool-checkable.hpp @@ -54,6 +54,7 @@ #define LIB_BOOL_CHECKABLE_H +#include namespace lib { @@ -117,9 +118,34 @@ namespace lib { return !(obj.*isValid)(); } + + /** safety guard: when this comparison kicks in, the compiler + * is about to use an implicit bool conversion on both sides to + * perform an equality test. This is most likely not what you want. + * Define an explicit equality comparison in the class using BoolCheckable! + */ + friend bool + operator== (BoolCheckable const&, BoolCheckable const&) + { + BOOST_STATIC_ASSERT (false && sizeof(T) ); + return false; + } }; +///////////////////////////////////////TICKET #477 : consider alternative safe-bool idiom +// struct _Hidden_type +// { +// _Hidden_type* _M_bool; +// }; +// +// /// This typedef is used to implement the safe_bool idiom. +// typedef _Hidden_type* _Hidden_type::* _Safe_bool; +// +// public: +// operator _Safe_bool() const +// { +// return isValid()? &_Hidden_type::_M_bool : 0; } } // namespace lib diff --git a/src/lib/cmdline.hpp b/src/lib/cmdline.hpp index 31d49acff..1353a9d1d 100644 --- a/src/lib/cmdline.hpp +++ b/src/lib/cmdline.hpp @@ -42,7 +42,7 @@ namespace util { /** * Abstraction of the usual "int argc, int** argv"-Commandline, * to be able to treat it as a vector of strings. Inherits from - * vector, but provides convienient conversions to + * vector, but provides convenient conversions to * string (joining delimited by space)... */ class Cmdline : public VectS diff --git a/src/lib/condition.h b/src/lib/condition.h index efb3136ab..87ee2a97e 100644 --- a/src/lib/condition.h +++ b/src/lib/condition.h @@ -43,50 +43,44 @@ * @param nobugflag NoBug flag used to log actions on the condition * @param cnd Condition variable to be locked */ -#define LUMIERA_CONDITION_SECTION(nobugflag, cnd) \ - for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ - lumiera_cond_section_ = { \ - (void*)1, lumiera_condition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_cond_section_.lock;) \ - for ( \ - ({ \ - lumiera_cond_section_.lock = (cnd); \ - NOBUG_IF_ALPHA(lumiera_cond_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire condmutex", lumiera_cond_section_.rh) \ - { \ - if (pthread_mutex_lock (&(cnd)->cndmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ - } \ - }); \ - lumiera_cond_section_.lock; \ - ({ \ - LUMIERA_CONDITION_SECTION_UNLOCK; \ - })) +#define LUMIERA_CONDITION_SECTION(nobugflag, cnd) \ + for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ + lumiera_cond_section_ = { \ + cnd, lumiera_condition_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_cond_section_.lock) \ + { \ + RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire condmutex", lumiera_cond_section_.rh); \ + if (pthread_mutex_lock (&(cnd)->cndmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ + } \ + lumiera_cond_section_.lock; \ + }); \ + ({ \ + LUMIERA_CONDITION_SECTION_UNLOCK; \ + })) -#define LUMIERA_CONDITION_SECTION_CHAIN(nobugflag, cnd) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ - NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_cond_section_ = { \ - (void*)1, lumiera_condition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_cond_section_.lock;) \ - for ( \ - ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ - lumiera_cond_section_.lock = cnd; \ - NOBUG_IF_ALPHA(lumiera_cond_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condmutex", lumiera_cond_section_.rh) \ - { \ - if (pthread_mutex_lock (&(cnd)->cndmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ - } \ - }); \ - lumiera_cond_section_.lock; \ - ({ \ - LUMIERA_CONDITION_SECTION_UNLOCK; \ - })) +#define LUMIERA_CONDITION_SECTION_CHAIN(nobugflag, cnd) \ + for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_cond_section_ = { \ + cnd, lumiera_condition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_cond_section_.lock) \ + { \ + REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condmutex", lumiera_cond_section_.rh); \ + if (pthread_mutex_lock (&(cnd)->cndmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ + lumiera_cond_section_.lock; \ + }); \ + ({ \ + LUMIERA_CONDITION_SECTION_UNLOCK; \ + })) diff --git a/src/lib/error.hpp b/src/lib/error.hpp index b17d808f8..daf2cf242 100644 --- a/src/lib/error.hpp +++ b/src/lib/error.hpp @@ -124,6 +124,7 @@ namespace lumiera { /* generic error situations */ LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached + LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value /** Macro for creating derived exception classes properly diff --git a/src/lib/exception.cpp b/src/lib/exception.cpp index a86d796ea..f3013009c 100644 --- a/src/lib/exception.cpp +++ b/src/lib/exception.cpp @@ -66,7 +66,9 @@ namespace lumiera { /* some further generic error situations */ LUMIERA_ERROR_DEFINE (WRONG_TYPE, "runtime type mismatch"); - LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached"); + LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached"); + LUMIERA_ERROR_DEFINE (BOTTOM_VALUE, "invalid or NIL value"); + } // namespace error diff --git a/src/lib/format.hpp b/src/lib/format.hpp index 084a5c941..0e75f6da2 100644 --- a/src/lib/format.hpp +++ b/src/lib/format.hpp @@ -46,8 +46,8 @@ namespace util { - using lumiera::typelist::can_ToString; - using lumiera::typelist::can_lexical2string; + using lib::meta::can_ToString; + using lib::meta::can_lexical2string; using lib::Symbol; using boost::enable_if; using boost::disable_if; diff --git a/src/lib/hash-indexed.hpp b/src/lib/hash-indexed.hpp index 5a814b131..4294f69fa 100644 --- a/src/lib/hash-indexed.hpp +++ b/src/lib/hash-indexed.hpp @@ -42,6 +42,7 @@ ** for the generic ID. ** - providing a Mixin, which allows any hierarchy to use this facility without ** much code duplication, including an adapter for tr1::unordered_map + ** - equality comparison ** ** @see HashIndexed_test ** @see Placement usage example @@ -103,12 +104,12 @@ namespace lib { typedef lumiera_uid* LUID; - operator size_t () const { return lumiera_uid_hash ((LUID)&luid_); } - bool operator== (LuidH const& o) const { return lumiera_uid_eq ((LUID)&luid_, (LUID)&o.luid_); } + operator size_t () const { return lumiera_uid_hash (get()); } + bool operator== (LuidH const& o) const { return lumiera_uid_eq (get(), o.get()); } bool operator!= (LuidH const& o) const { return !operator== (o); } /** for passing to C APIs */ - LUID get() const { return (LUID)&luid_; } + LUID get() const { return const_cast (&luid_);} }; @@ -187,6 +188,11 @@ namespace lib { this->id_ = ref.getID(); } + /** equality comparison delegated to the ID implementation */ + friend bool operator== (HashIndexed const& hal, HashIndexed const& har) { return hal.id_==har.id_; } + friend bool operator!= (HashIndexed const& hal, HashIndexed const& har) { return hal.id_!=har.id_; } + + protected: HashIndexed () : id_() {} HashIndexed (IMP const& iref) : id_(iref) {} diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 6280e60f8..8e085811a 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -65,6 +65,7 @@ ** ** @todo WIP WIP WIP ** @todo see Ticket #182 + ** @todo naming of the iteration control function: TICKET #410 ** ** @see scoped-ptrvect.hpp */ @@ -113,6 +114,14 @@ namespace lib { typedef const TY* pointer; }; + + void + _throwIterExhausted() + { + throw lumiera::error::Invalid ("Can't iterate further", + lumiera::error::LUMIERA_ERROR_ITER_EXHAUST); + } + } @@ -125,9 +134,24 @@ namespace lib { * - it is not just a disguised pointer (meaning, it's more expensive) * - it checks validity on every operation and may throw * - it has a distinct back-link to the source container - * - the source container needs to implement iterStart() and iterInc() - * - we need friendship to access the callbacks on the container + * - the source container needs to provide hasNext() and iterNext() free functions. + * - we may need friendship to implement those extension points on the container * - the end-of-iteration can be detected by bool check + * @note it is possible to "hide" a smart-ptr within the CON template parameter. + * + * \par Stipulations + * - POS refers to the current position within the data source of this iterator. + * -# it should be default constructible + * -# it should be copy constructible + * -# when IterAdapter is supposed to be assignable, then POS should be + * -# it should provide embedded typedefs for pointer, reference and value_type, + * or alternatively resolve these types through a specialisation if IterTraits. + * -# it should be convertible to the pointer type it declares + * -# dereferencing it should yield type that is convertible to the reference type + * - CON points to the data source of this iterator (typically a data container type) + * We store a pointer-like backlink to invoke a special iteration control API: + * -# \c hasNext yields true iff the source has yet more result values to yield + * -# \c iterNext advances the POS to the next element * * @see scoped-ptrvect.hpp usage example * @see iter-adaptor-test.cpp @@ -136,7 +160,7 @@ namespace lib { class IterAdapter : public lib::BoolCheckable > { - const CON* source_; + CON source_; mutable POS pos_; public: @@ -144,7 +168,7 @@ namespace lib { typedef typename IterTraits::reference reference; typedef typename IterTraits::value_type value_type; - IterAdapter (const CON* src, const POS& startpos) + IterAdapter (CON src, POS const& startpos) : source_(src) , pos_(startpos) { @@ -152,8 +176,8 @@ namespace lib { } IterAdapter () - : source_(0) - , pos_(0) + : source_() + , pos_() { } @@ -213,7 +237,7 @@ namespace lib { bool checkPos() const { - return source_ && CON::hasNext (source_,pos_); + return source_ && hasNext (source_,pos_); //////////////TICKET #410 } /** ask the controlling container to yield the next position. @@ -226,7 +250,7 @@ namespace lib { { if (!checkPos()) return false; - CON::iterNext (source_,pos_); + iterNext (source_,pos_); return checkPos(); } @@ -237,8 +261,7 @@ namespace lib { _maybe_throw() const { if (!isValid()) - throw lumiera::error::Invalid ("Can't iterate further", - lumiera::error::LUMIERA_ERROR_ITER_EXHAUST); + _throwIterExhausted(); } /// comparison is allowed to access impl iterator @@ -286,8 +309,8 @@ namespace lib { { } RangeIter () - : p_(0) - , e_(0) + : p_() + , e_() { } @@ -335,7 +358,7 @@ namespace lib { bool isValid () const { - return (p_!= IT(0)) && (p_ != e_); + return (p_!= IT()) && (p_ != e_); } bool @@ -356,8 +379,7 @@ namespace lib { _maybe_throw() const { if (!isValid()) - throw lumiera::error::Invalid ("Can't iterate further", - lumiera::error::LUMIERA_ERROR_ITER_EXHAUST); + _throwIterExhausted(); } }; diff --git a/src/lib/iter-source.hpp b/src/lib/iter-source.hpp new file mode 100644 index 000000000..a18de84e0 --- /dev/null +++ b/src/lib/iter-source.hpp @@ -0,0 +1,395 @@ +/* + ITER-SOURCE.hpp - an interface to build an opaque iterator-based data source + + Copyright (C) Lumiera.org + 2010, 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 iter-source.hpp + ** Extension module to build an opaque data source, accessible as + ** Lumiera Forward Iterator. It is based on combining an IterAdapter + ** with classical polymorphism; here, the data source, which is addressed + ** by IderAdapter through the "iteration control API", is abstracted behind + ** an interface (with virtual functions). Together this allows to build + ** a simple data source type, without needing to disclose details of + ** the implementation. + ** + ** \par Standard Adapters + ** As a complement, this header contains a generic implementation + ** of the IterSource interface by wrapping an existing Lumiera Forward Iterator. + ** Using this WrappedLumieraIterator, the details of this wrapped source iterator + ** remain opaque. To ease the use of this adapter, a selection of free functions + ** is provided, allowing to build opaque "all elements" or "all keys" iterators + ** for various STL containers. + ** + ** @see iter-adapter.hpp + ** @see itertool.hpp + ** @see iter-source-test.cpp + ** + */ + + +#ifndef LIB_ITER_SOURCE_H +#define LIB_ITER_SOURCE_H + + +#include "lib/iter-adapter.hpp" +#include "lib/itertools.hpp" + +#include +#include +#include + + + + +namespace lib { + + using std::tr1::shared_ptr; + + + + /** + * Iteration source interface to abstract a data source, + * which then can be accessed through IterAdapter as a frontend, + * allowing to pull individual elements until exhaustion. + * + * This base class is empty and makes no assumptions regarding + * identity, instantiation and copying. + * + * @see PlacementIndex::Table#_eachEntry_4check usage example + * @see iter-source-test.cpp + */ + template + class IterSource + { + + protected: /* == data source API to implement == */ + + typedef TY* Pos; + typedef shared_ptr DataHandle; + + + /** iteration start: prepare the first element. + * may return NULL in case of empty data source + */ + virtual Pos firstResult () =0; + + /** iteration step: switch on to the next element. + * The pos pointer may be set to NULL to report + * iteration end + */ + virtual void nextResult(Pos& pos) =0; + + /** disconnect the data source / iteration frontend. + * Depending on the way the IterSource got created + * this \em might (or might not) be followed by + * destroying the data source. + * @note must not throw + */ + virtual void disconnect () { } + + + + public: + virtual ~IterSource() { }; ///< is ABC + + /* == Iteration control API for IterAdapter frontend == */ + + friend bool + hasNext (DataHandle const&, Pos const& pos) ////TICKET #410 + { + return bool(pos); + } + + friend void + iterNext (DataHandle& source, Pos& pos) + { + ASSERT (source); + source->nextResult(pos); + } + + + /* == public builder API to create instances == */ + + typedef IterAdapter iterator; + + /** build an iterator frontend for the given source, + * @note the source is allocated separately and + * \em not owned by the iterator frontend + */ + static iterator + build (IterSource& sourceImpl) + { + DataHandle sourceHandle (&sourceImpl, &detach_without_destroy); + return startIteration(sourceHandle); + } + + /** build an iterator frontend, thereby managing + * the given heap allocated source object instance. + * @note we take ownership and destroy the source + * when the last copy of the created iterator + * goes out of scope. + */ + static iterator + build (IterSource* sourceImplObject) + { + DataHandle sourceHandle (sourceImplObject, &destroy_managed_source); + return startIteration(sourceHandle); + } + + static iterator EMPTY_SOURCE; + + + + private: + static iterator + startIteration (DataHandle sourceHandle) + { + REQUIRE (sourceHandle); + Pos first = sourceHandle->firstResult(); + return iterator (sourceHandle, first); + } + + + static void + detach_without_destroy (IterSource * source) + { + WARN_IF (!source, library, "IterSource deleter called with NULL source pointer"); + if (source) + source->disconnect(); + } + + static void + destroy_managed_source (IterSource * source) + { + WARN_IF (!source, library, "IterSource deleter called with NULL source pointer"); + if (source) + { + source->disconnect(); + delete source; + } + } + }; + + + /** storage for the empty data-source constant */ + template + typename IterSource::iterator IterSource::EMPTY_SOURCE = iterator(); + + + + + + /** + * Standard implementation of the IterSource interface: + * a wrapped "Lumiera Forward Iterator". Usually, such a wrapper instance + * is passed to one of the IterSource's builder functions, thereby + * erasing the specific type information of the template parameter IT + */ + template + class WrappedLumieraIterator + : public IterSource + , boost::noncopyable + { + typedef IterSource _Base; + typedef typename _Base::Pos Pos; + + IT src_; + + Pos + firstResult () + { + if (!src_) + return 0; + else + return & *src_; + } + + void + nextResult (Pos& pos) + { + if (!pos) return; + if (src_) ++src_; + if (src_) + pos = & *src_; + else + pos = 0; + } + + + + public: + WrappedLumieraIterator (IT const& orig) + : src_(orig) + { } + }; + + + + + /* === pre-defined Adapters for frequently used Containers === */ + + namespace iter_impl { + namespace { // traits and helpers... + + template + struct _SeqT + { + typedef typename CON::iterator::value_type Val; + typedef typename IterSource::iterator Iter; + }; + + template + struct _MapT + { + typedef typename MAP::key_type Key; + typedef typename MAP::value_type::second_type Val; + typedef typename IterSource::iterator KeyIter; + typedef typename IterSource::iterator ValIter; + }; + + + template + struct _IterT + { + typedef typename IT::value_type Val; + typedef typename IterSource::iterator Iter; + }; + + template + struct _PairIterT + { + typedef typename IT::value_type PairType; + typedef typename PairType::second_type ValType; + typedef typename PairType::first_type ConstKeyType; + + // since we're returning the keys always by value, + // we can strip the const added by the STL map types + typedef typename boost::remove_const::type KeyType; + + typedef TransformIter KeyIter; + typedef TransformIter ValIter; + + static KeyType takeFirst (PairType const& pair) { return pair.first; } + static ValType takeSecond(PairType const& pair) { return pair.second;} + }; + + + template + typename _PairIterT::KeyIter + takePairFirst (IT const& source) + { + return transformIterator(source, _PairIterT::takeFirst ); + } + + template + typename _PairIterT::ValIter + takePairSecond (IT const& source) + { + return transformIterator(source, _PairIterT::takeSecond ); + } + + } //(END) type helpers... + + + + /** wraps a given Lumiera Forward Iterator, + * exposing just a IterSource based frontend. + */ + template + typename _IterT::Iter + wrapIter (IT const& source) + { + typedef typename _IterT::Val ValType; + + return IterSource::build (new WrappedLumieraIterator (source)); + } + + + /** @return a Lumiera Forward Iterator to yield + * all the keys of the given Map or Hashtable + */ + template + typename _MapT::KeyIter + eachMapKey (MAP& map) + { + typedef RangeIter Range; + + Range contents (map.begin(), map.end()); + return wrapIter (takePairFirst (contents)); + } + + + /** @return a Lumiera Forward Iterator to yield + * all the keys of the given Map or Hashtable + */ + template + typename _MapT::ValIter + eachMapVal (MAP& map) + { + typedef RangeIter Range; + + Range contents (map.begin(), map.end()); + return wrapIter (takePairSecond(contents)); + } + + + /** @return a Lumiera Forward Iterator to yield + * all \em distinct keys of a Multimap + * @warning we do a full table scan to find + * the distinct keys + */ + template + typename _MapT::KeyIter + eachDistinctKey (MAP& map) + { + typedef RangeIter Range; + + Range contents (map.begin(), map.end()); + return wrapIter (filterRepetitions (takePairFirst(contents))); + } + + + /** @param container a STL-like container, providing + * - a typedef \c iterator + * - functions \c begin() and \c end() + * @return a Lumiera Forward Iterator yielding all values + * starting with \c begin and excluding \c end . + */ + template + typename _SeqT::Iter + eachEntry (CON& container) + { + typedef typename _SeqT::Val ValType; + typedef RangeIter Range; + + Range contents (container.begin(), container.end()); + return IterSource::build (new WrappedLumieraIterator(contents)); + } + + } + using iter_impl::wrapIter; + using iter_impl::eachMapKey; + using iter_impl::eachDistinctKey; + using iter_impl::eachMapVal; + using iter_impl::eachEntry; + + +} // namespace lib +#endif diff --git a/src/lib/itertools.hpp b/src/lib/itertools.hpp new file mode 100644 index 000000000..80092d61b --- /dev/null +++ b/src/lib/itertools.hpp @@ -0,0 +1,558 @@ +/* + ITERTOOLS.hpp - collection of tools for building and combining iterators + + Copyright (C) Lumiera.org + 2009, 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 itertools.hpp + ** Helpers for working with iterators based on the pipeline model. + ** Iterators abstract from the underlying data container and provide + ** the contained data as a source to pull values from. Based on this + ** model, we can build pipelines, with filters, valves, junction points + ** and transforming facilities. The templates in this header enable such, + ** based on the Lumiera Forward Iterator concept. They build on generic + ** programming techniques, thus are intended to be combined at compile time + ** using definitive type information. Contrast this to an iterator model + ** as in Java's Commons-Collections, where Iterator is an Interface based + ** on virtual functions. Thus, the basic problem to overcome is the lack + ** of a single common interface, which could serve as foundation for + ** type inference. As a solution, we use a "onion" approach, where a + ** generic base gets configured with an active core, implementing + ** the filtering or processing functionality, while the base class + ** (IterTool) exposes the operations necessary to comply to the + ** Forward Iterator Concept. + ** + ** \par filtering Iterator + ** The FilterIter template can be used to build a filter into a pipeline, + ** as it forwards only those elements from its source iterator, which pass + ** the predicate evaluation. Anything acceptable as ctor parameter for a + ** tr1::function object can be passed in as predicate, but of course the + ** signature must be sensible. Please note, that -- depending on the + ** predicate -- already the ctor or even a simple \c bool test might + ** pull and exhaust the source iterator completely, in an attempt + ** to find the first element passing the predicate test. + ** + ** \par processing Iterator + ** the TransformIter template can be used as processing (or transforming) + ** step within the pipeline. It is created with a functor, which, when + ** pulling elements, is invoked for each element pulled from the + ** source iterator. The signature of the functor must match the + ** desired value (output) type. + ** + ** @todo WIP WIP WIP + ** @todo see Ticket #347 + ** + ** @see IterAdapter + ** @see itertools-test.cpp + ** @see contents-query.hpp + */ + + +#ifndef LIB_ITERTOOLS_H +#define LIB_ITERTOOLS_H + + +#include "lib/bool-checkable.hpp" +#include "lib/iter-adapter.hpp" +#include "lib/meta/function.hpp" +#include "lib/meta/trait.hpp" +#include "lib/wrapper.hpp" +#include "lib/util.hpp" + +#include + + + +namespace lib { + + using std::tr1::function; + using util::unConst; + + using lib::meta::RefTraits; + + + + /** + * A neutral \em identity-function core, + * also serving as point-of reference how any + * core is intended to work. Any core is intended + * to serve as inner part of an iterator tool template. + * - it provides the trait typedefs + * - it abstracts the "source" + * - it abstracts the local operation to be performed + * - the ctor of the core sets up the configuration. + * @note cores should be copyable without much overhead + */ + template + struct IdentityCore + { + IT source_; + + IdentityCore (IT const& orig) + : source_(orig) + { } + + IT& + pipe () + { + return source_; + } + + IT const& + pipe () const + { + return source_; + } + + void + advance () + { + ++source_; + } + + bool + evaluate () const + { + return bool(source_); + } + + typedef typename IT::pointer pointer; + typedef typename IT::reference reference; + typedef typename IT::value_type value_type; + }; + + + /** + * Standard functionality to build up any iterator tool. + * IterTool exposes the frontend functions necessary to + * comply to the Lumiera Forward Iterator concept. + * The protected part provides the building blocks + * to implement the actual processing/filter logic. + */ + template + class IterTool + : public lib::BoolCheckable > + { + + protected: /* iteration control */ + CORE core_; + + bool + hasData() const + { + return core_.evaluate() + || unConst(this)->iterate(); + } // skipping irrelevant results doesn't count as "mutation" + + bool + iterate () + { + if (!core_.pipe()) return false; + + do core_.advance(); + while (core_.pipe() && !core_.evaluate()); + return core_.pipe(); + } + + void + _maybe_throw() const + { + if (!isValid()) + _throwIterExhausted(); + } + + + + public: + typedef typename CORE::pointer pointer; + typedef typename CORE::reference reference; + typedef typename CORE::value_type value_type; + + + IterTool (CORE const& setup) + : core_(setup) + { + hasData(); + } + + + + /* === lumiera forward iterator concept === */ + + reference + operator*() const + { + _maybe_throw(); + return *core_.pipe(); + } + + pointer + operator->() const + { + _maybe_throw(); + return & *core_.pipe(); + } + + IterTool& + operator++() + { + _maybe_throw(); + iterate(); + return *this; + } + + bool + isValid () const + { + return hasData(); + } + + bool + empty () const + { + return !isValid(); + } + + }; + + + template + inline bool + operator== (IterTool const& it1, IterTool const& it2) + { + return (!it1 && !it2 ) + || ( it1 && it2 && (*it1) == (*it2) ) + ; + } + + template + inline bool + operator!= (IterTool const& ito1, IterTool const& ito2) + { + return !(ito1 == ito2); + } + + + + + + + + + /** + * Implementation of the filter logic. + * This core stores a function object instance, + * passing each pulled source element to this + * predicate function for evaluation. + * @note predicate is evaluated at most once + * for each value yielded by the source + */ + template + struct FilterCore + : IdentityCore + { + typedef IdentityCore Raw; + typedef typename IT::reference Val; + + + function predicate_; + + bool + evaluate () const + { + return Raw::pipe() + && currVal_isOK(); + } + + + mutable bool isOK_; + mutable bool cached_; + + bool + currVal_isOK () const ///< @return (maybe cached) result of filter predicate + { + return (cached_ && isOK_) + || (cached_ = true + &&(isOK_ = predicate_(*Raw::pipe()))); + } + + void + advance () + { + cached_ = false; + Raw::advance(); + } + + + template + FilterCore (IT const& source, PRED prediDef) + : Raw(source) + , predicate_(prediDef) // induces a signature check + , cached_(false) + { } + }; + + + /** + * Iterator tool filtering pulled data according to a predicate + */ + template + class FilterIter + : public IterTool > + { + typedef FilterCore _Filter; + typedef IterTool<_Filter> _Impl; + + static bool acceptAll(typename _Filter::Val) { return true; } + + + public: + FilterIter () + : _Impl(FilterCore(IT(), acceptAll)) + { } + + template + FilterIter (IT const& src, PRED filterPredicate) + : _Impl(_Filter(src,filterPredicate)) + { } + + FilterIter& + operator++ () + { + _Impl::operator++(); + return *this; + } + }; + + + /** Build a FilterIter: convenience free function shortcut, + * picking up the involved types automatically. + * @param filterPredicate to be invoked for each source element + * @return Iterator filtering contents of the source + */ + template + inline FilterIter + filterIterator (IT const& src, PRED filterPredicate) + { + return FilterIter(src,filterPredicate); + } + + + /** + * Helper: predicate returning \c true + * whenever the argument value changes + * during a sequence of invocations. + */ + template + class SkipRepetition + { + typedef wrapper::ItemWrapper Item; + + Item prev_; + + public: + bool + operator() (VAL const& elm) + { + if (prev_ && + (*prev_ == elm)) + return false; + + // element differs from predecessor + prev_ = elm; + return true; + } + + typedef bool result_type; + }; + + + + + + + + + + + + /** + * Implementation of custom processing logic. + * This core stores a function object instance + * to treat each source element pulled. + */ + template + class TransformingCore + { + typedef typename IT::reference InType; + typedef wrapper::ItemWrapper Item; + + function trafo_; + + IT source_; + Item treated_; + + void + processItem () + { + if (source_) + treated_ = trafo_(*source_); + else + treated_.reset(); + } + + + + public: + TransformingCore () ///< deactivated core + : trafo_() + , source_() + , treated_() + { } + + template + TransformingCore (IT const& orig, FUN processor) + : trafo_(processor) // induces a signature check + , source_(orig) + { + processItem(); + } + + Item const& + pipe () const + { + return treated_; + } + + void + advance () + { + ++source_; + processItem(); + } + + bool + evaluate () const + { + return bool(source_); + } + + typedef typename RefTraits::pointer pointer; + typedef typename RefTraits::reference reference; + typedef typename RefTraits::value_type value_type; + }; + + + /** + * Iterator tool treating pulled data by a custom transformation (function) + */ + template + class TransformIter + : public IterTool > + { + typedef TransformingCore _Trafo; + typedef IterTool<_Trafo> _IteratorImpl; + + public: + TransformIter () + : _IteratorImpl(_Trafo()) + { } + + template + TransformIter (IT const& src, FUN trafoFunc) + : _IteratorImpl(_Trafo(src,trafoFunc)) + { } + + TransformIter& + operator++ () + { + _IteratorImpl::operator++(); + return *this; + } + }; + + + + namespace { // Helper to pick up the produced value type automatically + + using lumiera::typelist::FunctionSignature; + + template + struct _ProducedOutput + { + typedef typename FunctionSignature >::Ret Type; + }; + + template + struct _ProducedOutput > + { + typedef typename FunctionSignature >::Ret Type; + }; + + template + struct _ProducedOutput + { + typedef typename FunctionSignature >::Ret Type; + }; + } + + + /** Build a TransformIter: convenience free function shortcut, + * picking up the involved types automatically. + * @param processingFunc to be invoked for each source element + * @return Iterator processing the source feed + */ + template + inline TransformIter::Type> + transformIterator (IT const& src, FUN processingFunc) + { + typedef typename _ProducedOutput::Type OutVal; + return TransformIter(src,processingFunc); + } + + + + + /* === utility functions === */ + + template + inline void + append_all (IT iter, CON& container) + { + for ( ; iter; ++iter ) + container.push_back (*iter); + } + + + /** filters away repeated values + * emitted by source iterator */ + template + FilterIter + filterRepetitions (IT const& source) + { + typedef typename IT::value_type Val; + return filterIterator(source, SkipRepetition() ); + } + + + + + +} // namespace lib +#endif diff --git a/src/lib/meta/duck-detector.hpp b/src/lib/meta/duck-detector.hpp new file mode 100644 index 000000000..70bec2a18 --- /dev/null +++ b/src/lib/meta/duck-detector.hpp @@ -0,0 +1,205 @@ +/* + DUCK-DETECTOR.hpp - helpers for statically detecting properties of a type + + Copyright (C) Lumiera.org + 2010, 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 duck-detector.hpp + ** Metaprogramming helpers to check for specific properties of a type in question. + ** Building upon the "SFINE" principle, it is possible to create \em metafunction templates, + ** which answer some questions about a given type at compile time. A lot of generic flavours of + ** this kind can be found in the boost-type-trait library (part of std::tr1). At times though, + ** you want to ask more specific questions, like e.g. "does this type provide an operation \c quack() "? + ** Because, if we can get a \c bool answer to such a question at compile time, we can use + ** \c boost::enable_if to pick a special implementation based on the test result. Together, these + ** techniques allow to adopt a duck-typed programming style, where an arbitrary object is allowed + ** to enter a given API function, provided this object supports some special operations. + ** + ** While C++ certainly isn't a dynamic language and doesn't provide any kind of run time introspection, + ** doing such check-and branch at compile time allows even to combine such a flexible approach with + ** static type safety, which is compelling. (The downside is the danger of code bloat, as is with all + ** template based techniques). + ** + ** \par how the implementation works + ** + ** Most of these trait templates rely on a creative use of function overloading. The C++ standard + ** requires the compiler silently to drop any candidate of overload resolution which has + ** gotten an invalid function signature as a result of instantiating a template (type). This allow + ** us to set up kind of a "trap" for the compiler: we present two overloaded candidate functions + ** with a different return type; by investigating the resulting return type we're able to figure + ** out the overload actually picked by the compiler. + ** + ** This header provides some pre-configured tests, available as macros. Each of them contains + ** a template based on the described setup, containing a \em probe type expression at some point. + ** The key is to build this probe expression in a way that it's valid only if the type in question + ** has a specific property + ** + ** - if the type should contain a nested type of typedef with a specific name, we simply use + ** this nested type in the signature of the overloaded function + ** - if the type should contain a \em member with a specific name, we initialise a member pointer + ** within a probe template with this member (if there isn't such a member, the probe template + ** initialisation fails and the other function overload gets picked) + ** - as an extension to this approach, we can even declare a member function pointer with a + ** specific function signature and then try to assign the named member. This allows even + ** to determine if a member function of a type in question has the desired signature. + ** + ** All these detection building blocks are written such as to provide a bool member \v ::value, + ** which is in accordance to the conventions of boost metaprogramming. I.e. you can immediately + ** use them within boost::enable_if + ** + ** @see util-foreach.hpp usage example + ** @see duck-detector-test.cpp + ** + */ + + +#ifndef LIB_META_DUCK_DETECTOR_H +#define LIB_META_DUCK_DETECTOR_H + + +#include "lib/meta/util.hpp" + +namespace lib { +namespace meta{ + + ///////////////TICKET #175 sort out meta namespace + using lumiera::Yes_t; + using lumiera::No_t; + +}} // namespace lib::meta + + + + + + +/** Detector for a nested type. + * Defines a metafunction (template), allowing to detect + * if a type TY in question has a nested type or typedef + * with the given name. To answer this question, instantiate + * resulting HasNested_XXX template with the type in question + * and check the static bool value field. + */ +#define META_DETECT_NESTED(_TYPE_) \ + template \ + class HasNested_##_TYPE_ \ + { \ + \ + template \ + static Yes_t check(typename X::_TYPE_ *); \ + template \ + static No_t check(...); \ + \ + public: \ + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); \ + }; + + + +/** Detector for a nested member (field or function). + * Defines a metafunction (template), allowing to detect + * the presence of a member with the given name within + * a type in question. + */ +#define META_DETECT_MEMBER(_NAME_) \ + template \ + class HasMember_##_NAME_ \ + { \ + template \ + struct Probe \ + { }; \ + \ + template \ + static Yes_t check(Probe * ); \ + template \ + static No_t check(...); \ + \ + public: \ + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); \ + }; + + + +/** Detector for a specific member function. + * Defines a metafunction (template), allowing to detect + * the presence of a member function with the specific + * signature, as defined by the parameters. Note this + * check will probably fail if there are overloads + */ +#define META_DETECT_FUNCTION(_RET_TYPE_,_FUN_NAME_,_ARGS_) \ + template \ + class HasFunSig_##_FUN_NAME_ \ + { \ + template \ + struct Probe \ + { }; \ + \ + template \ + static Yes_t check(Probe * ); \ + template \ + static No_t check(...); \ + \ + public: \ + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); \ + }; + + + +/** Detector for a dereferentiation operator. Works like member detection */ +#define META_DETECT_OPERATOR_DEREF() \ + template \ + class HasOperator_deref \ + { \ + template \ + struct Probe \ + { }; \ + \ + template \ + static Yes_t check(Probe * ); \ + template \ + static No_t check(...); \ + \ + public: \ + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); \ + }; + + + +/** Detector for a prefix increment operator. Works like function detection */ +#define META_DETECT_OPERATOR_INC() \ + template \ + class HasOperator_inc \ + { \ + template \ + struct Probe \ + { }; \ + \ + template \ + static Yes_t check(Probe * ); \ + template \ + static No_t check(...); \ + \ + public: \ + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); \ + }; + + + +#endif diff --git a/src/lib/meta/generator.hpp b/src/lib/meta/generator.hpp index 5469fbaeb..b248888d2 100644 --- a/src/lib/meta/generator.hpp +++ b/src/lib/meta/generator.hpp @@ -42,8 +42,14 @@ This code is heavily inspired by ** Helpers for working with lumiera::typelist::Types (i.e. lists-of-types). ** The main purpose is to build interfaces and polymorphic implementations ** (using virtual functions) based on templated Types or Collections of types, - ** which is not possible without Template Metaprogrmming. + ** which is not possible without Template Metaprogramming. ** + ** The facilities in this header work by instantiating another template, + ** which is passed in as (template template) parameter, for each of a + ** given sequence of types. What varies is the way how this "for each" + ** instantiation is mixed or inherited into the resulting product. + ** + ** @see generator-test.cpp ** @see lumiera::query::ConfigRules usage example ** @see typelist.hpp ** @@ -99,6 +105,13 @@ namespace typelist{ }; + /** Helper to just inherit from the given type(s) */ + template + struct InheritFrom : T + { }; + + + /** * Build a single inheritance chain of template instantiations. diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index 323ae0ac4..eb6d208ef 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -21,20 +21,208 @@ */ -#ifndef LUMIERA_META_TRAIT_H -#define LUMIERA_META_TRAIT_H +#ifndef LIB_META_TRAIT_H +#define LIB_META_TRAIT_H #include "lib/meta/util.hpp" +#include "lib/meta/duck-detector.hpp" +#include "lib/wrapper.hpp" ////////////////////////TODO only because of AssignableRefWrapper -- can we get rid of this import? #include #include +#include +#include +#include #include #include +//Forward declarations for the Unwrap helper.... +namespace boost{ + template class reference_wrapper; +} +namespace std { +namespace tr1 { + template class reference_wrapper; + template class shared_ptr; +}} +namespace lumiera{ + template class P; +} +namespace mobject{ + template class Placement; +} -namespace lumiera { -namespace typelist { + +namespace lib { +namespace meta { + + + + /** + * Helper for type analysis: + * tries to extract a base type from various wrappers. + * Additionally allows to extract/deref the wrapped element. + * @warning strips away any const + */ + template + struct Unwrap + { + typedef X Type; + + static X& + extract (X const& x) + { + return const_cast (x); + } + }; + + template + struct Unwrap + { + typedef typename boost::remove_cv::type Type; + + static Type& + extract (const X* ptr) + { + ASSERT (ptr); + return const_cast (*ptr); + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (boost::reference_wrapper wrapped) + { + return wrapped; + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (std::tr1::reference_wrapper wrapped) + { + return wrapped; + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (std::tr1::shared_ptr ptr) + { + ASSERT (ptr); + return *ptr; + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (lumiera::P ptr) + { + ASSERT (ptr); + return *ptr; + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (mobject::Placement placement) + { + ASSERT (placement.isValid()); + return *placement; + } + }; + + + /** convenience shortcut: unwrapping free function. + * @return reference to the bare element. + * @warning this function is dangerous: it strips away + * any managing smart-ptr and any const! + * You might even access and return a + * reference to an anonymous temporary. + */ + template + typename Unwrap::Type& + unwrap (X const& wrapped) + { + return Unwrap::extract(wrapped); + } + + + + + /** Helper for type analysis: tries to strip all kinds of type adornments */ + template + struct Strip + { + typedef typename boost::remove_cv ::type TypeUnconst; + typedef typename boost::remove_reference::type TypeReferred; + typedef typename boost::remove_pointer ::type TypePointee; + typedef typename boost::remove_cv ::type TypePlain; + + typedef typename Unwrap ::Type Type; + }; + + + + + /** Type definition helper for pointer and reference types. + * Allows to create a member field and to get the basic type + * irrespective if the given type is plain, pointer or reference + */ + template + struct RefTraits + { + typedef TY* pointer; + typedef TY& reference; + typedef TY value_type; + typedef value_type member_type; + }; + + template + struct RefTraits + { + typedef TY* pointer; + typedef TY& reference; + typedef TY value_type; + typedef pointer member_type; + }; + + template + struct RefTraits + { + typedef TY* pointer; + typedef TY& reference; + typedef TY value_type; + typedef lib::wrapper::AssignableRefWrapper member_type; + }; + //////////////////////////////////////////TODO: member_type not needed anymore 12/09 -- obsolete? useful? keep it? + + + + + + @@ -69,5 +257,71 @@ namespace typelist { }; -}} // namespace lumiera::typelist + + + /** Trait template to detect a type usable with the STL for-each loop. + * Basically we're looking for the functions to get the begin/end iterator + */ + template + class can_STL_ForEach + { + typedef typename Strip::Type Type; + + struct is_iterable + { + META_DETECT_NESTED(iterator); + META_DETECT_FUNCTION(typename X::iterator, begin,(void)); + META_DETECT_FUNCTION(typename X::iterator, end ,(void)); + + enum { value = HasNested_iterator::value + && HasFunSig_begin::value + && HasFunSig_end::value + }; + }; + + struct is_const_iterable + { + META_DETECT_NESTED(const_iterator); + META_DETECT_FUNCTION(typename X::const_iterator, begin,(void) const); + META_DETECT_FUNCTION(typename X::const_iterator, end ,(void) const); + + enum { value = HasNested_const_iterator::value + && HasFunSig_begin::value + && HasFunSig_end::value + }; + }; + + + public: + enum { value = is_iterable::value + || is_const_iterable::value + }; + }; + + + /** Trait template to detect a type usable immediately as + * "Lumiera Forward Iterator" in a specialised for-each loop + * This is just a heuristic, based on some common properties + * of such iterators; it is enough to distinguish it from an + * STL container, but can certainly be refined. + */ + template + class can_IterForEach + { + typedef typename Strip::Type Type; + + META_DETECT_NESTED(value_type); + META_DETECT_OPERATOR_DEREF(); + META_DETECT_OPERATOR_INC(); + + public: + enum{ value = boost::is_convertible::value + && HasNested_value_type::value + && HasOperator_deref::value + && HasOperator_inc::value + }; + }; + + +}} // namespace lib::meta #endif diff --git a/src/lib/multifact-arg.hpp b/src/lib/multifact-arg.hpp new file mode 100644 index 000000000..dfb452765 --- /dev/null +++ b/src/lib/multifact-arg.hpp @@ -0,0 +1,130 @@ +/* + MULTIFACT-ARG.hpp - variant of family-of-object factory, accepting fabrication arguments + + Copyright (C) Lumiera.org + 2009, 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 multifact.hpp + ** Extension allowing the MultiFact to pass arguments to the fabrication. + ** This extension is implemented by template specialisations and thus kicks in + ** when specifying a function \em signature as factory "product type". The resulting + ** factory class exposes a function call operator matching this signature, additionally + ** expecting the ID (to select the specific fabrication function) as first parameter. + ** + ** @note the function signature used for this variant of MultiFact should specify + ** the raw/base (interface) type of the produced objects as a return type. + ** Depending on the used wrapper, the actual fabrication functions indeed + ** should yield the product in a form suitable to be accepted by the + ** wrapper. E.g., when building smart-ptrs, the fabrication function + ** should actually deliver a raw pointer to a heap allocated object. + ** + ** @see multifact-argument-test.cpp + ** @see query-resolver.cpp usage example + ** @see multifact.hpp standard case + */ + + +#ifndef LIB_MULTIFACT_ARG_H +#define LIB_MULTIFACT_ARG_H + + +#include "lib/multifact.hpp" + +#include "lib/meta/function.hpp" + + + +namespace lib { + namespace factory { + + + using lumiera::typelist::Types; + using lumiera::typelist::FunctionSignature; + using lumiera::typelist::FunctionTypedef; + using std::tr1::function; + + + /** + * Extended MultiFact configuration for arbitrary fabrication functions. + * Contrary to the (simple) standard case, such fabrication functions + * take additional arguments on each invocation. These arguments need + * to be passed through by MultiFact. Moreover, the actual Wrapper + * used may require these fabrication functions to deliver their + * product in a specific form, e.g. as pointer or reference. + * Thus, we have to re-build the actual signature of the + * fabrication functions to be installed into MultiFact. + */ + template< typename SIG + , template class Wrapper + > + struct FabWiring, Wrapper> + : Wrapper >::Ret> + { + typedef typename FunctionSignature >::Args Args; + typedef typename FunctionSignature >::Ret Element; + typedef typename Wrapper::PType WrappedProduct; + typedef typename Wrapper::RType FabProduct; + typedef typename FunctionTypedef::Sig SIG_Fab; + }; + + + + + /** + * Variant of MultiFact, accepting an additional invocation argument. + * Similar to the (simple) standard case, this MultiFact specialisation + * allows to install suitable fabrication function(s) at runtime and + * will select the function to use on invocation based on the given ID. + * One additional argument will be passed on to this function. + * @todo with a bit more metaprogramming it would be possible to + * accept multiple arguments; maybe we'll need this later on. + */ + template< typename ELM, typename ARG + , typename ID + , template class Wrapper + > + class MultiFact + : public MultiFact,ID,Wrapper> + { + typedef MultiFact,ID,Wrapper> _Base; + typedef typename _Base::Creator Creator; + + public: + typedef typename _Base::Product Product; + + Product + operator() (ID const& id, ARG arg) + { + Creator& func = selectProducer (id); + return wrap (func(arg)); + } + + }; + + + + } // namespace factory + + + + // TODO is there some suitable standard configuration we could provide here?? + + +} // namespace lib +#endif diff --git a/src/lib/multifact.hpp b/src/lib/multifact.hpp index 557e52375..6e77b5d6e 100644 --- a/src/lib/multifact.hpp +++ b/src/lib/multifact.hpp @@ -22,9 +22,32 @@ /** @file multifact.hpp ** Building blocks of a configurable factory, generating families of related objects. + ** Serving the "classical" factory situation: obtaining objects of various kinds, which + ** are related somehow (usually through an common interface). The creation of these + ** objects is non-trivial while number and exact parametrisation aren't known beforehand + ** and need to be figured out at runtime. Thus, a number of "fabrication lines" is set up, + ** to be selected on invocation through an ID (which may be symbolic, hashed or structural). ** - ** @todo WIP-WIP-WIP ... currently collecting various bits of implementation here. TICKET #277 + ** Usually, the issue of object and storage management is closely related, while it is + ** desirable to keep the object production logic clean of these rather technical concerns. + ** The implementation built here separates the latter into a policy template invoked as a + ** \em wrapper, accepting the raw product and either registering it, taking ownership, clone + ** it or use it for more involved wiring. Obviously, the product generated by the installed + ** "fabrication lines" needs to be delivered in a form acceptable by the concrete wrapper; + ** mismatch will be spotted by the compiler on registration of the respective fabrication + ** function. ** + ** \par Singleton generation + ** For the very common situation of needing various singleton objects, accessible by ID, + ** there is a convenience shortcut: The nested MultiFact::Singleton template can be instantiated + ** within the context providing the objects (usually a static context). In itself a lib::Singleton + ** factory, it automatically registers the singleton access function as "fabrication" function + ** into a suitable MultiFact instance passed in as ctor parameter. + ** + ** @note there is an extension header, multifact-arg.hpp, which provides template specialisations + ** for the special case when the fabrication functions need additional invocation arguments. + ** + ** @see multifact-test.cpp ** @see SingletonFactory ** @see lib::factory::Factory */ @@ -39,6 +62,7 @@ #include "util.hpp" #include +#include #include @@ -46,6 +70,7 @@ namespace lib { namespace factory { + //////TODO: couldn't these wrappers be extracted into a separate header? /** * Dummy "wrapper", @@ -54,26 +79,44 @@ namespace lib { template struct PassReference { + typedef TAR& RType; typedef TAR& PType; - PType wrap (TAR& object) { return object; } + PType wrap (RType object) { return object; } }; + /** + * Wrapper taking ownership, + * by wrapping into smart-ptr + */ + template + struct BuildRefcountPtr + { + typedef TAR* RType; + typedef std::tr1::shared_ptr PType; + + PType wrap (RType ptr) { return PType (ptr); } + }; + + + + + /** * Table of registered production functions for MultiFact. * Each stored function can be accessed by ID and is able - * to fabricate a specific object, which is assignable to TY + * to fabricate a specific object, which is assignable to + * the nominal target type in the MultiFact definition. */ - template + template struct Fab { - typedef TY& RawProduct; - typedef std::tr1::function FactoryFunc; + typedef std::tr1::function FactoryFunc; FactoryFunc& - select (ID id) + select (ID const& id) { if (!contains (id)) throw lumiera::error::Invalid("unknown factory product requested."); @@ -82,7 +125,7 @@ namespace lib { } void - defineProduction (ID id, FactoryFunc fun) + defineProduction (ID const& id, FactoryFunc fun) { producerTable_[id] = fun; } @@ -99,6 +142,23 @@ namespace lib { + /** + * @internal configuration of the elements + * to be combined into a MultiFact instance + */ + template< typename TY + , template class Wrapper + > + struct FabWiring + : Wrapper + { + typedef typename Wrapper::PType WrappedProduct; + typedef typename Wrapper::RType FabProduct; + typedef FabProduct SIG_Fab(void); + }; + + + /** * Factory for creating a family of objects by ID. * The actual factory functions are to be installed @@ -114,20 +174,32 @@ namespace lib { , template class Wrapper > class MultiFact - : Wrapper + : public FabWiring { - typedef Fab _Fab; - typedef typename _Fab::FactoryFunc Creator; - typedef typename Wrapper::PType Product; + typedef FabWiring _Conf; + typedef typename _Conf::SIG_Fab SIG_Fab; + typedef Fab _Fab; _Fab funcTable_; - public: - Product - operator() (ID id) + protected: + typedef typename _Fab::FactoryFunc Creator; + + Creator& + selectProducer (ID const& id) { - Creator& func = funcTable_.select(id); + return funcTable_.select(id); + } + + + public: + typedef typename _Conf::WrappedProduct Product; + + Product + operator() (ID const& id) + { + Creator& func = selectProducer (id); return wrap (func()); } @@ -146,7 +218,7 @@ namespace lib { /** * Convenience shortcut for automatically setting up * a production line, fabricating a singleton instance - * of the given target type (TAR) + * of the given implementation target type (IMP) */ template class Singleton @@ -170,7 +242,7 @@ namespace lib { /* === diagnostics === */ - + bool empty () const { return funcTable_.empty(); } bool contains (ID id) const { return funcTable_.contains (id); } }; diff --git a/src/lib/mutex.h b/src/lib/mutex.h index 1a85d970a..c49265e6a 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -37,26 +37,23 @@ /** * Mutual exclusive section. */ -#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \ - for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ - lumiera_lock_section_ = { \ - (void*)1, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - lumiera_lock_section_.lock = (mtx); \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_WAIT (nobugflag, (mtx)->rh, "acquire mutex", lumiera_lock_section_.rh) \ - { \ - if (pthread_mutex_lock (&(mtx)->mutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ - } \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_MUTEX_SECTION_UNLOCK; \ - })) +#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \ + for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ + lumiera_lock_section_ = { \ + mtx, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + { \ + RESOURCE_WAIT (nobugflag, (mtx)->rh, "acquire mutex", lumiera_lock_section_.rh); \ + if (pthread_mutex_lock (&(mtx)->mutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ + } \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_MUTEX_SECTION_UNLOCK; \ + })) /** @@ -66,30 +63,25 @@ * This macro should only be used inside LUMIERA_MUTEX_SECTION and should be * called on the correct mutexes, period. */ - -#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ - NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ - (void*)1, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ - lumiera_lock_section_.lock = mtx; \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_WAIT (nobugflag, (mtx)->rh, "acquire mutex", lumiera_lock_section_.rh) \ - { \ - if (pthread_mutex_lock (&(mtx)->mutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ - } \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_MUTEX_SECTION_UNLOCK; \ - })) - +#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \ + for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ + mtx, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + { \ + REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + RESOURCE_WAIT (nobugflag, (mtx)->rh, "acquire mutex", lumiera_lock_section_.rh); \ + if (pthread_mutex_lock (&(mtx)->mutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_MUTEX_SECTION_UNLOCK; \ + })) #define LUMIERA_MUTEX_SECTION_UNLOCK \ LUMIERA_SECTION_UNLOCK_(&lumiera_lock_section_) diff --git a/src/lib/reccondition.h b/src/lib/reccondition.h index 51ce6ef07..77fdb8961 100644 --- a/src/lib/reccondition.h +++ b/src/lib/reccondition.h @@ -41,51 +41,45 @@ * @param nobugflag NoBug flag used to log actions on the condition * @param cnd Condition variable to be locked */ -#define LUMIERA_RECCONDITION_SECTION(nobugflag, cnd) \ - for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ - lumiera_reccond_section_ = { \ - (void*)1, lumiera_reccondition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_reccond_section_.lock;) \ - for ( \ - ({ \ - lumiera_reccond_section_.lock = (cnd); \ - NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh) \ - { \ - if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ - } \ - }); \ - lumiera_reccond_section_.lock; \ - ({ \ - LUMIERA_RECCONDITION_SECTION_UNLOCK; \ - })) +#define LUMIERA_RECCONDITION_SECTION(nobugflag, cnd) \ + for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ + lumiera_reccond_section_ = { \ + cnd, lumiera_reccondition_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_reccond_section_.lock) \ + { \ + RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh); \ + if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ + } \ + lumiera_reccond_section_.lock; \ + }); \ + ({ \ + LUMIERA_RECCONDITION_SECTION_UNLOCK; \ + })) -#define LUMIERA_RECCONDITION_SECTION_CHAIN(nobugflag, cnd) \ - for (lumiera_sectionlock *lumiera_reccond_section_old_ = &lumiera_reccond_section_, \ - NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_reccond_section_ = { \ - (void*)1, lumiera_reccondition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_reccond_section_.lock;) \ - for ( \ - ({ \ - REQUIRE (lumiera_reccond_section_old_->lock, "section prematurely unlocked"); \ - lumiera_reccond_section_.lock = (cnd); \ - NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh) \ - { \ - if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_reccond_section_old_); \ - } \ - }); \ - lumiera_reccond_section_.lock; \ - ({ \ - LUMIERA_RECCONDITION_SECTION_UNLOCK; \ - })) +#define LUMIERA_RECCONDITION_SECTION_CHAIN(nobugflag, cnd) \ + for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_reccond_section_ = { \ + cnd, lumiera_reccondition_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_reccond_section_.lock) \ + { \ + REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh); \ + if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ + lumiera_reccond_section_.lock; \ + }); \ + ({ \ + LUMIERA_RECCONDITION_SECTION_UNLOCK; \ + })) #define LUMIERA_RECCONDITION_SECTION_UNLOCK \ diff --git a/src/lib/recmutex.h b/src/lib/recmutex.h index ec0cea6e4..204b2fce0 100644 --- a/src/lib/recmutex.h +++ b/src/lib/recmutex.h @@ -36,47 +36,45 @@ /** * Recursive Mutual exclusive section. */ -#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \ - for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ - lumiera_lock_section_ = { \ - (void*)1, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - lumiera_lock_section_.lock = (mtx); \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", \ - NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \ - if (pthread_mutex_lock (&(mtx)->recmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_lock_section_.rh); \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_MUTEX_SECTION_UNLOCK; \ +#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \ + for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ + lumiera_lock_section_ = { \ + mtx, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + { \ + RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", \ + NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \ + if (pthread_mutex_lock (&(mtx)->recmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_lock_section_.rh); \ + } \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_MUTEX_SECTION_UNLOCK; \ })) -#define LUMIERA_RECMUTEX_SECTION_CHAIN(nobugflag, mtx) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ - NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ - (void*)1, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ - lumiera_lock_section_.lock = (mtx); \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", \ - NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \ - if (pthread_mutex_lock (&(mtx)->recmutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_lock_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_) \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_MUTEX_SECTION_UNLOCK; \ +#define LUMIERA_RECMUTEX_SECTION_CHAIN(nobugflag, mtx) \ + for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ + mtx, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + { \ + REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", \ + NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \ + if (pthread_mutex_lock (&(mtx)->recmutex)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_lock_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_MUTEX_SECTION_UNLOCK; \ })) diff --git a/src/lib/rwlock.h b/src/lib/rwlock.h index 2cd8d006a..57176313d 100644 --- a/src/lib/rwlock.h +++ b/src/lib/rwlock.h @@ -45,101 +45,88 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK); /** * Read locked section. */ -#define LUMIERA_RDLOCK_SECTION(nobugflag, rwlck) \ - for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ - lumiera_lock_section_ = { \ - (void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - lumiera_lock_section_.lock = (rwlck); \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire readlock", lumiera_lock_section_.rh) \ - { \ - if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); \ - } \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_RWLOCK_SECTION_UNLOCK; \ - })) +#define LUMIERA_RDLOCK_SECTION(nobugflag, rwlck) \ + for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ + lumiera_lock_section_ = { \ + rwlck, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + { \ + RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire readlock", lumiera_lock_section_.rh); \ + if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); \ + } \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_RWLOCK_SECTION_UNLOCK; \ + })) -#define LUMIERA_RDLOCK_SECTION_CHAIN(nobugflag, rwlck) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ - NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ - (void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ - lumiera_lock_section_.lock = (rwlck); \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire readlock", lumiera_lock_section_.rh) \ - { \ - if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ - } \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_MUTEX_SECTION_UNLOCK; \ - })) - +#define LUMIERA_RDLOCK_SECTION_CHAIN(nobugflag, rwlck) \ + for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ + rwlck, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + { \ + REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire readlock", lumiera_lock_section_.rh); \ + if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_MUTEX_SECTION_UNLOCK; \ + })) /** * Write locked section. */ -#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \ - for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ - lumiera_lock_section_ = { \ - (void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - lumiera_lock_section_.lock = (rwlck); \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire writelock", lumiera_lock_section_.rh) \ - { \ - if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ - } \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_RWLOCK_SECTION_UNLOCK; \ - })) +#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \ + for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ + lumiera_lock_section_ = { \ + rwlck, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + { \ + RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire writelock", lumiera_lock_section_.rh); \ + if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ + } \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_RWLOCK_SECTION_UNLOCK; \ + })) #define LUMIERA_WRLOCK_SECTION_CHAIN(nobugflag, rwlck) \ for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ - (void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ - lumiera_lock_section_.lock;) \ - for ( \ - ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ - lumiera_lock_section_.lock = (rwlck); \ - NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \ - RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire writelock", lumiera_lock_section_.rh) \ - { \ - if (pthread_rwlock_wrlock (&(twlck)->rwlock)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ - } \ - }); \ - lumiera_lock_section_.lock; \ - ({ \ - LUMIERA_MUTEX_SECTION_UNLOCK; \ - })) + rwlck, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + { \ + REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + RESOURCE_WAIT (nobugflag, (rwlck)->rh, "acquire writelock", lumiera_lock_section_.rh); \ + if (pthread_rwlock_wrlock (&(twlck)->rwlock)) \ + LUMIERA_DIE (LOCK_ACQUIRE); \ + RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_MUTEX_SECTION_UNLOCK; \ + })) #define LUMIERA_RWLOCK_SECTION_UNLOCK \ diff --git a/src/lib/scoped-holder.hpp b/src/lib/scoped-holder.hpp index 392a36d58..4e2c82627 100644 --- a/src/lib/scoped-holder.hpp +++ b/src/lib/scoped-holder.hpp @@ -145,7 +145,7 @@ namespace lib { char content_[sizeof(TY)]; char created_; - typedef ScopedHolder _ThisType; + typedef ScopedHolder _ThisType; ////TODO can get rid of this typedef, after using BoolCheckable static char must_be_empty (_ThisType const& ref) @@ -216,6 +216,7 @@ namespace lib { typedef char _ThisType::*unspecified_bool_type; + //////////////////////////////////TICKET #178 /** implicit conversion to "bool" */ operator unspecified_bool_type() const // never throws { diff --git a/src/lib/singleton-ref.hpp b/src/lib/singleton-ref.hpp index 48e74635c..8fc9c289c 100644 --- a/src/lib/singleton-ref.hpp +++ b/src/lib/singleton-ref.hpp @@ -23,7 +23,15 @@ /** @file singleton-ref.hpp ** Helper for singleton-kind access without managing object creation and lifecycle. ** A typical usage scenario is when implementing C Language Interfaces without any - ** canonical access to some "this" pointer. + ** canonical access to some "this" pointer. In this case + ** - an instance of the \c Access policy class is created "somewhere" (usually as + ** global variable). Calls from within the C code would enter through this accessor. + ** - when the actual service implementation class comes up, it creates an SingletonRef + ** instance and thereby wires the (already existing) accessor up with \c *this + ** - when the service goes down, access is closed automatically and reliably. + ** Client code (from within C) should check the accessor (by \c bool check) + ** prior to any access, because accessing a closed connection will throw + ** (that's unfortunate, but at least throwing is better than segfaulting) ** ** @see gui::NotificationService usage example */ @@ -90,7 +98,11 @@ namespace lib { /************************************************************* * Helper template providing singleton access without managing - * object creation and lifecycle. + * object creation and lifecycle. Just the access to the + * implementation instance is handled: on creation, access is + * enabled, and disabled on destruction. Client code is assumed + * to invoke through the Access (template template param), + * handed in as ctor parameter. * @param TY the actual type to be made accessible * @param B a base class to inherit from; defaults to noncopyable * @param Accessor how to implement the static instance access diff --git a/src/lib/sub-id.hpp b/src/lib/sub-id.hpp index 257dc2638..98df7c4e7 100644 --- a/src/lib/sub-id.hpp +++ b/src/lib/sub-id.hpp @@ -49,14 +49,19 @@ #include "lib/format.hpp" //#include +#include /////TODO better push the hash implementation into a cpp file (and btw, do it more seriously!) + #include #include namespace lib { - using std::string; + using boost::hash_value; + using std::ostream; + using std::string; + using std::cout; @@ -73,15 +78,32 @@ namespace lib { virtual operator string() const =0; }; - - - ostream& - operator<< (ostream& os, SubID const& sID) - { - return os << string(sID); - } - + + inline ostream& + operator<< (ostream& os, SubID const& sID) + { + return os << string(sID); + } + + inline size_t + hash_value (SubID const& sID) + { + return hash_value (string (sID)); + } + + inline bool + operator== (SubID const& id1, SubID const& id2) + { + return (string (id1) == string (id2)); + } + + ////////TODO a serious implementation should descend recursively, instead of relying on the string representation + + + + + template class SubId @@ -96,7 +118,8 @@ namespace lib { operator string() const { - return util::str (baseID_); + using util::str; + return str (baseID_); // note: extension point } }; diff --git a/src/lib/symbol-impl.cpp b/src/lib/symbol-impl.cpp index 1345ab795..3d06dcc35 100644 --- a/src/lib/symbol-impl.cpp +++ b/src/lib/symbol-impl.cpp @@ -67,10 +67,13 @@ namespace lib { size_t hash_value (Literal sym) { size_t hash=0; - const char *pos = sym; - size_t maxpos = STRING_MAX_RELEVANT; - for ( ; pos && --maxpos; ++pos) - hash_combine(hash, *pos); + if (sym) + { + const char *pos = sym; + size_t maxpos = STRING_MAX_RELEVANT; + for ( ; *pos && --maxpos; ++pos) + hash_combine(hash, *pos); + } return hash; } diff --git a/src/lib/symbol.hpp b/src/lib/symbol.hpp index 562a6bf09..fcc9041ce 100644 --- a/src/lib/symbol.hpp +++ b/src/lib/symbol.hpp @@ -51,6 +51,7 @@ namespace lib { /** inline string literal * @todo improve interaction with Symbol * @todo make it non-nullable + * @todo maybe use boost/operators Ticket #417 */ class Literal { @@ -126,6 +127,32 @@ namespace lib { return ! (sy1 == sy2); } + /// comparison with c-strings //////TICKET #417 + inline bool + operator== (Literal sy1, const char* const sy2) + { + return (sy1 == Literal(sy2)); + } + + inline bool + operator== (const char* const sy1, Literal sy2) + { + return (Literal(sy1) == sy2); + } + + inline bool + operator!= (Literal sy1, const char* const sy2) + { + return ! (sy1 == Literal(sy2)); + } + + inline bool + operator!= (const char* const sy1, Literal sy2) + { + return ! (Literal(sy1) == sy2); + } + + /// string concatenation inline std::string operator+ (std::string str, Literal const& sym) { diff --git a/src/lib/test/test-helper.cpp b/src/lib/test/test-helper.cpp index 401690788..0c67ca7fd 100644 --- a/src/lib/test/test-helper.cpp +++ b/src/lib/test/test-helper.cpp @@ -41,5 +41,21 @@ namespace test{ } + /** @todo probably this can be done in a more clever way. Anyone...? + */ + string + randStr (size_t len) + { + static const string alpha ("aaaabbccddeeeeffgghiiiijjkkllmmnnooooppqqrrssttuuuuvvwwxxyyyyzz0123456789"); + static const size_t MAXAL (alpha.size()); + + string garbage(len,'\0'); + size_t p = len; + while (p) + garbage[--p] = alpha[rand() % MAXAL]; + return garbage; + } + + }} // namespace lib::test diff --git a/src/lib/test/test-helper.hpp b/src/lib/test/test-helper.hpp index 26d3b5616..afa79c743 100644 --- a/src/lib/test/test-helper.hpp +++ b/src/lib/test/test-helper.hpp @@ -110,6 +110,11 @@ namespace test{ return Time (500 * (rand() % 2), (rand() % 600)); } + /** create garbage string of given length + * @return string containing arbitrary lower case letters and numbers + */ + string randStr (size_t len); + }} // namespace lib::test diff --git a/src/lib/util-foreach.hpp b/src/lib/util-foreach.hpp new file mode 100644 index 000000000..bfb6f9514 --- /dev/null +++ b/src/lib/util-foreach.hpp @@ -0,0 +1,347 @@ +/* + UTIL-FOREACH.hpp - helpers for doing something for each element + + Copyright (C) Lumiera.org + 2009, 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 util-foreach.hpp + ** Perform operations "for each element" of a collection. + ** This header defines various flavours of these active iteration functions, + ** which all take a functor and invoke it in some way over the collection's elements. + ** - basic constructs + ** - for_each + ** - and_all (all quantisation) + ** - has_any (existence quantisation) + ** - kinds of collection + ** - STL collections and anything which has an iterator, \c begin() and \c end() + ** - "Lumiera Forward Iterator" instance to yield all the elements of the collection + ** - support for on-the-fly binding up to 4 arguments of the functor + ** + ** @warning in the standard case (STL container) the collection to operate on is + ** taken by \c const& -- but the const is stripped silently. + ** + ** Thus, within the iteration, the function passed in can \em modify the original collection. + ** If you pass in a ref to a temporary, the compiler won't complain. Moreover, several kinds + ** of wrappers are also stripped silently, including reference_wrapper, shared_ptr and + ** lumiera::P. The rationale for this non-standard behaviour is to allow convenient writing + ** of in-line iteration, where even the collection to iterate is yielded by function call. + ** + ** @see util-foreach-test.cpp + ** + */ + + +#ifndef UTIL_FOREACH_H +#define UTIL_FOREACH_H + +#include "lib/util.hpp" +#include "lib/meta/trait.hpp" + +#include +#include + + + +namespace util { + + using boost::enable_if; + using boost::disable_if; + + using lib::meta::can_STL_ForEach; + using lib::meta::can_IterForEach; + + + + /** All quantification: check if all elements of a collection + * satisfy the given predicate. Actually a short-circuit + * evaluation is performed. + */ + template + inline bool + and_all (IT i, IT end, FUN predicate) + { + for ( ; i!=end; ++i ) + if (!predicate(*i)) + return false; + + return true; + } + + + /** Existential quantification: check if any element + * of a collection satisfies the given predicate. + * Actually, a short-circuit evaluation is performed. + */ + template + inline bool + has_any (IT i, IT end, FUN predicate) + { + for ( ; i!=end; ++i ) + if (predicate(*i)) + return true; + + return false; + } + + + /* === specialisations for STL containers and Lumiera Forward Iterators === */ + + /** operating on all elements of a STL container. + * @note the container is taken by \c const& and + * the \c const is \em stripped before iteration. + * @note this case is the default and kicks in + * \em unless we detect a Lumiera iterator. + * The handling is different for \c and_all + */ + template + inline typename disable_if< can_IterForEach, + FUN >::type + for_each (Container const& coll, FUN doIt) + { + using lib::meta::unwrap; + + return std::for_each (unwrap(coll).begin() + ,unwrap(coll).end() + , doIt); + } + + + /** operating on a Lumiera Forward Iterator until exhaustion. */ + template + inline typename enable_if< can_IterForEach, + FUN >::type + for_each (IT const& ii, FUN doIt) + { + return std::for_each (ii, IT(), doIt); + } + + + + + template + inline typename enable_if< can_STL_ForEach, + bool >::type + and_all (Container const& coll, FUN predicate) + { + using lib::meta::unwrap; + + return and_all (unwrap(coll).begin() + ,unwrap(coll).end() + , predicate); + } + + + template + inline typename enable_if< can_IterForEach, + bool >::type + and_all (IT const& ii, FUN predicate) + { + return and_all (ii, IT(), predicate); + } + + + + template + inline typename enable_if< can_STL_ForEach, + bool >::type + has_any (Container const& coll, FUN predicate) + { + using lib::meta::unwrap; + + return has_any (unwrap(coll).begin() + ,unwrap(coll).end() + , predicate); + } + + + template + inline typename enable_if< can_IterForEach, + bool >::type + has_any (IT const& ii, FUN predicate) + { + return has_any (ii, IT(), predicate); + } + + + + + /* === allow creating argument binders on-the-fly === */ + + + template < typename CON, typename FUN + , typename P1 + > + inline void //________________________________ + for_each (CON const& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument + { + for_each (elements, std::tr1::bind (function, bind1)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + > + inline void //________________________________ + for_each (CON const& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments + { + for_each (elements, std::tr1::bind (function, bind1, bind2)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + , typename P3 + > + inline void //________________________________ + for_each (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments + { + for_each (elements, std::tr1::bind (function, bind1, bind2, bind3)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + , typename P3 + , typename P4 + > + inline void //________________________________ + for_each (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments + { + for_each (elements, std::tr1::bind (function, bind1, bind2, bind3, bind4)); + } + + + + + + template < typename CON, typename FUN + , typename P1 + > + inline bool //________________________________ + and_all (CON const& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument + { + return and_all (elements, std::tr1::bind (function, bind1)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + > + inline bool //________________________________ + and_all (CON const& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments + { + return and_all (elements, std::tr1::bind (function, bind1, bind2)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + , typename P3 + > + inline bool //________________________________ + and_all (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments + { + return and_all (elements, std::tr1::bind (function, bind1, bind2, bind3)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + , typename P3 + , typename P4 + > + inline bool //________________________________ + and_all (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments + { + return and_all (elements, std::tr1::bind (function, bind1, bind2, bind3, bind4)); + } + + + + + + template < typename CON, typename FUN + , typename P1 + > + inline bool //________________________________ + has_any (CON const& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument + { + return has_any (elements, std::tr1::bind (function, bind1)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + > + inline bool //________________________________ + has_any (CON const& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments + { + return has_any (elements, std::tr1::bind (function, bind1, bind2)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + , typename P3 + > + inline bool //________________________________ + has_any (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments + { + return has_any (elements, std::tr1::bind (function, bind1, bind2, bind3)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + , typename P3 + , typename P4 + > + inline bool //________________________________ + has_any (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments + { + return has_any (elements, std::tr1::bind (function, bind1, bind2, bind3, bind4)); + } + + + + +} // namespace util +#endif /*UTIL_FOREACH_H*/ diff --git a/src/lib/util.hpp b/src/lib/util.hpp index 02a52941b..3d3abf038 100644 --- a/src/lib/util.hpp +++ b/src/lib/util.hpp @@ -191,32 +191,6 @@ namespace util { } - /** shortcut for operating on all elements of a container. - * Isn't this already defined somewhere? It's so obvious.. - */ - template - inline Oper - for_each (Container& c, Oper doIt) - { - return std::for_each (c.begin(),c.end(), doIt); - } - - - /** shortcut for testing all elements of a collection - * with the given predicate. - */ - template - inline bool - and_all (SEQ& coll, Oper predicate) - { - typename SEQ::const_iterator e = coll.end(); - typename SEQ::const_iterator i = coll.begin(); - - while (i!=e && predicate(*i)) ++i; - return i==e; - } - - /** shortcut to save some typing when having to define * const and non-const variants of member functions */ diff --git a/src/lib/wrapper.hpp b/src/lib/wrapper.hpp new file mode 100644 index 000000000..918c9834a --- /dev/null +++ b/src/lib/wrapper.hpp @@ -0,0 +1,378 @@ +/* + WRAPPER.hpp - some smart wrapping and reference managing helper templates + + Copyright (C) Lumiera.org + 2009, 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 wrapper.hpp + ** Library implementation: smart-pointer variations, wrappers and managing holders. + ** This is (intended to become) a loose collection of the various small helper templates + ** for wrapping, containing, placing or handling a somewhat \em problematic other object. + ** Mostly these are implemented to suit a specific need and then factored out later on. + ** - AssignableRefWrapper is not used anymore as of 12/09 + ** - ItemWrapper is a similar concept, but more like a smart-ptr. Moreover, + ** it can be instantiated with a value type, a pointer or a reference type, + ** yielding the same behaviour in all cases (useful for building templates) + ** - FunctionResult is the combination of ItemWrapper with a functor object + ** to cache the function result value. It is used to implement a transforming + ** iterator, especially supporting the case when the transformation function + ** is to return a reference + ** + ** @see lib::TransformIter + ** + */ + + +#ifndef LIB_WRAPPER_H +#define LIB_WRAPPER_H + +#include "lib/error.hpp" +#include "lib/bool-checkable.hpp" +#include "lib/meta/function.hpp" +#include "lib/meta/function-closure.hpp" +#include "lib/util.hpp" + +#include +#include +#include + + +namespace lib { +namespace wrapper { + + using util::unConst; + using util::isSameObject; + using lumiera::typelist::FunctionSignature; + using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE; + + using boost::remove_const; + using std::tr1::function; + + + /** + * Extension to boost::reference_wrapper: + * Allows additionally to re-bind to another reference, + * almost like a pointer. Helpful for building templates. + * @warning potentially dangerous + */ + template + class AssignableRefWrapper + : public std::tr1::reference_wrapper + { + typedef std::tr1::reference_wrapper RefWrapper; + public: + + explicit AssignableRefWrapper(TY& ref) + : RefWrapper(ref) + { } + + AssignableRefWrapper& + operator= (RefWrapper const& o) + { + RefWrapper::operator= (o); + return *this; + } + + AssignableRefWrapper& + operator= (TY& newRef) + { + (*this) = RefWrapper(newRef); + return *this; + } + }; + + + + + /** + * Universal value/ref wrapper behaving like a pointer. + * 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, + * where the original reference is retrieved by conversion) + * + * The purpose of this template is to be able to remember + * pretty much any kind of value or pointer or reference, + * and to subsume this handling within a single template. + * An example would be to remember the value yielded + * by a function, without any further assumptions + * regarding this function. + */ + template + class ItemWrapper + : public BoolCheckable > + { + + typedef typename remove_const::type TY_unconst; + + + mutable + char content_[sizeof(TY)]; + bool created_; + + void + build (TY const& ref) + { + new(&content_) TY(ref); + created_ = true; + } + + void + discard () + { + if (created_) access().~TY(); + created_ = false; + } + + TY& + access () const + { + return reinterpret_cast (content_); + } + + TY_unconst& + access_unconst() const ///< used to assign new buffer contents + { + return const_cast (access()); + } + + public: + ItemWrapper() + : created_(false) + { } + + explicit + ItemWrapper(TY const& o) + { + build (o); + } + + ~ItemWrapper() + { + discard(); + } + + + /* == copy and assignment == */ + + ItemWrapper (ItemWrapper const& ref) + : created_(false) + { + if (ref.isValid()) + build (*ref); + } + + ItemWrapper& + operator= (ItemWrapper const& ref) + { + if (!ref.isValid()) + discard(); + else + this->operator= (*ref); + + return *this; + } + + template + ItemWrapper& + operator= (X const& something) ///< accept anything assignable to TY + { + if (!isSameObject (something, access() )) + { + if (created_) + access_unconst() = something; + else + build (something); + } + + return *this; + } + + + /* == value access == */ + TY& + operator* () const + { + if (!created_) + throw lumiera::error::State ("accessing uninitialised value/ref wrapper" + , LUMIERA_ERROR_BOTTOM_VALUE); + return access(); + } + + bool + isValid () const + { + return created_; + } + + void + reset () + { + discard(); + } + }; + + + /** + * Specialisation of the ItemWrapper to deal with references, + * as if they were pointer values. Allows the reference value + * to be default constructed to \c NULL and to be re-assigned. + */ + template + class ItemWrapper + : public BoolCheckable > + { + + TY * content_; + + + public: + ItemWrapper() + : content_() + { } + + explicit + ItemWrapper(TY& o) + : content_( &o ) + { } + + + /* using default copy and assignment */ + + /** allowing to re-bind the reference */ + ItemWrapper& + operator= (TY& otherRef) + { + content_ = &otherRef; + return *this; + } + + + + /* == value access == */ + TY& + operator* () const + { + if (!content_) + throw lumiera::error::State ("accessing uninitialised reference wrapper" + , LUMIERA_ERROR_BOTTOM_VALUE); + return *content_; + } + + bool + isValid () const + { + return bool(content_); + } + + void + reset () + { + content_ = 0; + } + }; + + + + /** allow equality comparison if the wrapped types are comparable */ + template + inline bool + operator== (ItemWrapper const& w1, ItemWrapper const& w2) + { + return (!w1 && !w2) + || ( w1 && w2 && (*w1)==(*w2)); + } + template + inline bool + operator!= (ItemWrapper const& w1, ItemWrapper const& w2) + { + return !(w1 == w2); + } + + + + /** + * Extension of ItemWrapper: a function remembering + * the result of the last invocation. Initially, the "value" + * is bottom (undefined, NIL), until the function is invoked + * for the first time. After that, the result of the last + * invocation can be accessed by \c operator*() + * + * @note non-copyable. (removing this limitation would + * require a much more expensive implementation, + * by implementing operator() ourselves) + */ + template + class FunctionResult + : public function + , boost::noncopyable + { + typedef typename FunctionSignature >::Ret Res; + typedef ItemWrapper ResWrapper; + + ResWrapper lastResult_; + + + Res + captureResult (Res res) + { + lastResult_ = res; + return res; + } + + public: + /** default ctor yields an object + * locked to \em invalid state */ + FunctionResult () { } + + /** Create result-remembering functor + * by binding the given function. Explanation: + * - *this is a \em function + * - initially it is defined as invalid + * - then we build the function composition of + * the target function, and a function storing + * the result value into the ResWrapper member + * - define ourselves by assigning the resulting + * composite function + */ + template + FunctionResult (FUN targetFunction) + { + using std::tr1::bind; + using std::tr1::placeholders::_1; + using lumiera::typelist::func::chained; + // note: binding "this" mandates noncopyable + function doCaptureResult = bind (&FunctionResult::captureResult, this, _1 ); + function chainedWithResCapture = chained (targetFunction, doCaptureResult); + + function::operator= (chainedWithResCapture); // define the function (baseclass) + } + + + Res& operator*() const { return *lastResult_; } + bool isValid () const { return lastResult_.isValid(); } + + operator bool() const { return isValid(); } + // can't use lib::BoolCheckable, because tr1::function implements safe-bool too + }; + + +}} // namespace lib::wrap +#endif diff --git a/src/proc/Makefile.am b/src/proc/Makefile.am index 0f896a834..51371e560 100644 --- a/src/proc/Makefile.am +++ b/src/proc/Makefile.am @@ -94,7 +94,6 @@ liblumiprocmobject_la_SOURCES = \ $(liblumiprocmobject_la_srcdir)/mobject-ref.cpp \ $(liblumiprocmobject_la_srcdir)/parameter.cpp \ $(liblumiprocmobject_la_srcdir)/paramprovider.cpp \ - $(liblumiprocmobject_la_srcdir)/placement-index.cpp \ $(liblumiprocmobject_la_srcdir)/placement.cpp @@ -137,7 +136,6 @@ liblumiprocplay_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra liblumiprocplay_la_SOURCES = \ $(liblumiprocplay_la_srcdir)/dummy-player-service.cpp \ $(liblumiprocplay_la_srcdir)/dummy-image-generator.cpp - liblumiprocmobjectsession_la_srcdir = $(top_srcdir)/src/proc/mobject/session @@ -146,32 +144,39 @@ noinst_LTLIBRARIES += liblumiprocmobjectsession.la liblumiprocmobjectsession_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror liblumiprocmobjectsession_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra -liblumiprocmobjectsession_la_SOURCES = \ - $(liblumiprocmobjectsession_la_srcdir)/abstractmo.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/allocation.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/auto.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/binding.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/clip.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/compoundclip.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/constraint.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/defsmanager.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/effect.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/fixedlocation.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/label.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/meta.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/relativelocation.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/segment.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/segmentation.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/simpleclip.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/plug.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/session-impl.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/sess-manager-impl.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/edl.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/session.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/track.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/fixture.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/locatingpin.cpp \ - $(liblumiprocmobjectsession_la_srcdir)/mobjectfactory.cpp \ +liblumiprocmobjectsession_la_SOURCES = \ + $(liblumiprocmobjectsession_la_srcdir)/abstractmo.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/allocation.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/auto.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/binding.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/clip.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/compoundclip.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/constraint.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/defsmanager.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/effect.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/fixedlocation.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/label.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/meta.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/relativelocation.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/segment.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/segmentation.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/simpleclip.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/plug.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/session-impl.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/sess-manager-impl.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/edl.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/session.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/track.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/fixture.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/locatingpin.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/mobjectfactory.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/placement-index.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/query-resolver.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/placement-index-query-resolver.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/session-services.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/root.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/scope.cpp \ + $(liblumiprocmobjectsession_la_srcdir)/scope-path.cpp \ $(liblumiprocmobjectsession_la_srcdir)/wish.cpp @@ -240,6 +245,13 @@ noinst_HEADERS += \ $(liblumiproc_la_srcdir)/mobject/session/locatingpin.hpp \ $(liblumiproc_la_srcdir)/mobject/session/plug.hpp \ $(liblumiproc_la_srcdir)/mobject/session/defsregistry.hpp \ + $(liblumiproc_la_srcdir)/mobject/session/placement-index.hpp \ + $(liblumiproc_la_srcdir)/mobject/session/query-resolver.hpp \ + $(liblumiproc_la_srcdir)/mobject/session/placement-index-query-resolver.hpp \ + $(liblumiproc_la_srcdir)/mobject/session/session-service-fetch.hpp \ + $(liblumiproc_la_srcdir)/mobject/session/root.hpp \ + $(liblumiproc_la_srcdir)/mobject/session/scope.hpp \ + $(liblumiproc_la_srcdir)/mobject/session/scope-path.hpp \ $(liblumiproc_la_srcdir)/mobject/explicitplacement.hpp \ $(liblumiproc_la_srcdir)/mobject/mobject.hpp \ $(liblumiproc_la_srcdir)/mobject/placement.hpp \ diff --git a/src/proc/asset.cpp b/src/proc/asset.cpp index 3d4b8fc79..25f0da1d2 100644 --- a/src/proc/asset.cpp +++ b/src/proc/asset.cpp @@ -23,6 +23,7 @@ #include "proc/asset.hpp" #include "proc/assetmanager.hpp" +#include "lib/util-foreach.hpp" #include "lib/util.hpp" #include @@ -123,7 +124,7 @@ namespace asset { // can indeed to do the toggle... this->enabled = on; - for_each (dependants, bind (&propagate_down, _1 ,on)); + for_each (dependants, &propagate_down, _1 ,on); return true; } diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp index f371b5efc..1676c96da 100644 --- a/src/proc/asset/db.hpp +++ b/src/proc/asset/db.hpp @@ -162,7 +162,7 @@ namespace asset { static const PAsset NULLP; IdHashtable::const_iterator i = table.find (hash); if (i == table.end()) - return NULLP; // empty ptr signaling "not found" + return NULLP; // empty ptr signalling "not found" else return i->second; } diff --git a/src/proc/asset/pipe.hpp b/src/proc/asset/pipe.hpp index c2a9a8ff0..3fde3c44c 100644 --- a/src/proc/asset/pipe.hpp +++ b/src/proc/asset/pipe.hpp @@ -78,7 +78,7 @@ namespace asset /** use another wiring template. Triggers complete rebuild of the render engine. */ void switchProcPatt (PProcPatt& another); - /** convienience shortcut for retrieving default configured pipes */ + /** convenience shortcut for retrieving default configured pipes */ static PPipe query (string properties) ; }; diff --git a/src/proc/asset/structfactoryimpl.hpp b/src/proc/asset/structfactoryimpl.hpp index f39d41b05..a3bce4b60 100644 --- a/src/proc/asset/structfactoryimpl.hpp +++ b/src/proc/asset/structfactoryimpl.hpp @@ -149,7 +149,7 @@ namespace asset StructFactoryImpl::fabricate (const Query& caps) { TODO ("actually extract properties/capabilities from the query..."); - TODO ("make sure AssetManager detects dublicates (currently 4/08 it doesn't)"); + TODO ("make sure AssetManager detects duplicates (currently 4/08 it doesn't)"); return new Track (createIdent (caps)); } diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index c26811bed..625c189c1 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -25,7 +25,7 @@ #include "proc/asset/db.hpp" #include "lib/sync.hpp" -#include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include #include diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index 6068a86c4..6e0730b5e 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -73,11 +73,11 @@ namespace asset { /** provide the unique ID for given Asset::Ident tuple */ static ID getID (const Asset::Ident&); - /** retrieve the registerd smart-ptr for any asset */ + /** retrieve the registered smart-ptr for any asset */ template static P wrap (const KIND& asset); - /** find and return corresponging object */ + /** find and return corresponding object */ template P getAsset (const ID& id) throw(lumiera::error::Invalid); diff --git a/src/proc/control/command-registry.hpp b/src/proc/control/command-registry.hpp index 603aa5d9e..4dbd225be 100644 --- a/src/proc/control/command-registry.hpp +++ b/src/proc/control/command-registry.hpp @@ -34,10 +34,10 @@ ** \par Services during command lifecycle ** Each command starts out as command definition, accessed by client code through CommandDef. ** While collecting the necessary parts of such a definition, there is just an empty (pending) - ** Command (smart-ptr frontend), which is already registered with the intended command-ID. - ** A lookup on this ID would still fail at this point, as the \link #queryIndex search function \endlink - ** treats missing and incomplete command definitions similar. When the definition is complete, - ** a CommandImpl frame is allocated, configured and used to activate the Command (smart-ptr frontend). + ** Command (smart-ptr frontend), which is not yet usable, being held within the CommandDef. + ** When the definition is complete, a CommandImpl frame is allocated, configured and used to + ** activate the Command (smart-ptr frontend), at which point it also gets accessible + ** through the CommandRegistry. ** ** Later on, client code is assumed to re-access the command by ID. It may bind arguments, which are ** stored in the already allocated ArgumentHolder. (-->Ticket #269). As the Command frontend is a diff --git a/src/proc/control/command.cpp b/src/proc/control/command.cpp index fd6068316..55d9a1ef0 100644 --- a/src/proc/control/command.cpp +++ b/src/proc/control/command.cpp @@ -249,7 +249,7 @@ namespace control { - /** @return number distinguishable registered command \em instances */ + /** @return number of distinguishable registered command \em instances */ size_t Command::instance_count() { diff --git a/src/proc/control/memento-tie.hpp b/src/proc/control/memento-tie.hpp index bbab73313..3c78b99f7 100644 --- a/src/proc/control/memento-tie.hpp +++ b/src/proc/control/memento-tie.hpp @@ -78,6 +78,8 @@ namespace control { * which needs to be stored within the MementoTie. On UNDO, the undo-operation functor needs * to be provided with a reference to this stored memento value through an additional * parameter (which by convention is always the last argument of the undo function). + * @warning take care of the MementoTie storage location, as the bound functions + * returned by #tieCaptureFunc and #tieUndoFunc refer to \c this internally. * * @param SIG signature of the command operation * @param MEM type of the memento state to capture. Needs to be default constructible and copyable diff --git a/src/proc/engine/nodewiring-def.hpp b/src/proc/engine/nodewiring-def.hpp index 4fc4f14c2..c659d2493 100644 --- a/src/proc/engine/nodewiring-def.hpp +++ b/src/proc/engine/nodewiring-def.hpp @@ -42,6 +42,7 @@ #include "proc/engine/procnode.hpp" #include "lib/refarray.hpp" +#include "lib/util-foreach.hpp" #include //#include diff --git a/src/proc/mobject/builder/applicable-builder-target-types.hpp b/src/proc/mobject/builder/applicable-builder-target-types.hpp new file mode 100644 index 000000000..ac94da38b --- /dev/null +++ b/src/proc/mobject/builder/applicable-builder-target-types.hpp @@ -0,0 +1,94 @@ +/* + ApplicableBuilderTargetTypes - definition header specifying all types treated by builder tools + + 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 applicable-builder-target-types.hpp + ** Declaration of all kinds of MObjects to be treated by some "Builder tool". + ** This is part of Lumiera's visitation mechanism: Individual MObject subclasses + ** may declare by the \c DEFINE_PROCESSABLE_BY macro to be specifically processable + ** by a builder tool (visitor). On the other hand, any concrete builder tool (visitor) + ** is free to define a \c treat(Type) function for each of these specific subclasses. + ** If the tool doesn't define such a specific \c treat(..) function, the next suitable + ** function for a supertype will be used. + ** + ** Now there needs to be \em one location where all the specific kinds of treat-able + ** MObjects are declared together (in a typelist). Moreover, we need the full declaration + ** of these classes. This is the catch of using the visitor pattern. Thus, any class + ** to be treated \em specifically (as opposed to be just treated through a supertype + ** or super interface) has two liabilities: + ** - DEFINE_PROCESSABLE_BY + ** - declare the type here in this file, including the header. + ** + ** @note actually the ApplicableBuilderTargetTypes template, when used (as a baseclass + ** of any concrete builder tool, causes the generation of the necessary + ** dispatcher tables used by our visitor implementation. + ** + ** @see buildertool.hpp + ** @see buildertooltest.hpp + ** @see nodecreatertool.hpp + */ + + + +#ifndef MOBJECT_BUILDER_APPLICABLEBUILDERTARGETTYPES_H +#define MOBJECT_BUILDER_APPLICABLEBUILDERTARGETTYPES_H + +#include "proc/mobject/builder/buildertool.hpp" + +// NOTE:  need to include *all* classes using DEFINE_PROCESSABLE_BY(BuilderTool) +#include "proc/mobject/session/root.hpp" +#include "proc/mobject/session/clip.hpp" +#include "proc/mobject/session/effect.hpp" +#include "proc/mobject/session/auto.hpp" + + /////////////////////////////////TICKET #414 + + + +namespace mobject { +namespace builder { + + typedef Types< session::Root, + session::Clip, + session::Effect, + session::AbstractMO + > ::List + BuilderTargetTypes; + /////////////////////////////////TICKET #414 + + + /** + * Marker used to declare some visiting Tool class to be actually a + * mobject::builder::BuilderTool and to possibly accept and treat the + * common selection of types to be handled by any such builder tool. + * The actual BuilderTool impl should inherit from this template by + * feeding back its type (CRTP), this causes a dispatcher table entry + * to be generated for this concrete BuilderTool implementation. + */ + template + struct ApplicableBuilderTargetTypes + : Applicable + { }; + + + +}} // namespace mobject::builder +#endif diff --git a/src/proc/mobject/builder/applicablebuildertargettypes.hpp b/src/proc/mobject/builder/applicablebuildertargettypes.hpp deleted file mode 100644 index b02fb9d45..000000000 --- a/src/proc/mobject/builder/applicablebuildertargettypes.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - ApplicableBuilderTargetTypes - definitinon header specifying all types treated by builder tools - - 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. - -*/ - - -#ifndef MOBJECT_BUILDER_APPLICABLEBUILDERTARGETTYPES_H -#define MOBJECT_BUILDER_APPLICABLEBUILDERTARGETTYPES_H - -#include "proc/mobject/builder/buildertool.hpp" - - - -namespace mobject { - namespace session { - - class Clip; - class Effect; - class AbstractMO; - template class Auto; - // Forward declarations sufficient here... - // actual definitions necessary only in the - // implementation file (*cpp) of the builder tool. - } - - namespace builder { - - typedef Types< session::Clip, - session::Effect, - session::AbstractMO - > ::List - BuilderTargetTypes; - - - /** - * Marker used to declare some visiting Tool class to be actually a - * mobject::builder::BuilderTool and to possibly accept and treat the - * common selection of types to be handled by any such builder tool. - * The actual BuilderTool impl should inherit from this template by - * feeding back its type (CRTP), this causes a dispatcher table entry - * to be generated for this concrete BuilderTool implementation. - */ - template - struct ApplicableBuilderTargetTypes - : Applicable - { }; - - - - } // namespace mobject::builder - -} // namespace mobject -#endif diff --git a/src/proc/mobject/builder/buildertool.hpp b/src/proc/mobject/builder/buildertool.hpp index e0b90979e..9f6a06a25 100644 --- a/src/proc/mobject/builder/buildertool.hpp +++ b/src/proc/mobject/builder/buildertool.hpp @@ -28,22 +28,22 @@ ** ** As the objects to be treated are normally handled by smart-ptrs, BuilderTool provides ** a special facility for dealing with these wrapped objects. There are some liabilities. - **
                                    • each concrete Buildable subtype to be treated specifically needs to - ** declare \c DEFINE_PROCESSABLE_BY(BuilderTool)
                                    • - **
                                    • at the same time, the concrete BuilderTool subclass has to declare - ** being Applicable to this concrete Buildable subtype. The recommended way - ** of ensuring this, is to add an entry to applicablebuildertargettypes.hpp - ** and then derive the concrete BuilderTool subclass from - ** ApplicableBuilderTargetTypes
                                    • - **
                                    • when accessing the wrapper from within a \c treat() function, a suitable - ** concrete wrapper type has to be specified. If the wrapper type used for - ** invoking the BuilderTool (function \c apply(BuilderTool&l, WrappedObject&) ) - ** can not be converted to this type requested from within the call, an - ** assertion failure (or segmentation fault in a release build) will result.
                                    • + ** - each concrete Buildable subtype to be treated specifically needs to + ** declare \c DEFINE_PROCESSABLE_BY(BuilderTool) + ** - at the same time, the concrete BuilderTool subclass has to declare + ** being Applicable to this concrete Buildable subtype. The recommended way + ** of ensuring this, is to add an entry to applicable-builder-target-types.hpp + ** and then derive the concrete BuilderTool subclass from + ** ApplicableBuilderTargetTypes + ** - when accessing the wrapper from within a \c treat() function, a suitable + ** concrete wrapper type has to be specified. If the wrapper type used for + ** invoking the BuilderTool (function \c apply(BuilderTool&l, WrappedObject&) ) + ** can not be converted to this type requested from within the call, an + ** assertion failure (or segmentation fault in a release build) will result. **
                                    ** ** @see visitor.hpp - ** @see applicablebuildertargettypes.hpp + ** @see applicable-builder-target-types.hpp ** @see buildertooltest.hpp ** @see nodecreatertool.hpp */ diff --git a/src/proc/mobject/builder/nodecreatortool.cpp b/src/proc/mobject/builder/nodecreatortool.cpp index 8664a2b01..854d92dbc 100644 --- a/src/proc/mobject/builder/nodecreatortool.cpp +++ b/src/proc/mobject/builder/nodecreatortool.cpp @@ -22,9 +22,7 @@ #include "proc/mobject/builder/nodecreatortool.hpp" -#include "proc/mobject/session/clip.hpp" -#include "proc/mobject/session/effect.hpp" -#include "proc/mobject/session/auto.hpp" + using mobject::Buildable; using mobject::session::Clip; @@ -34,8 +32,12 @@ using mobject::session::Auto; namespace mobject { namespace builder { - - + /////////////////////////////////TICKET #414 + + + ////TODO: do we ever get to treat a model root element?? + + void NodeCreatorTool::treat (Buildable& something) { @@ -63,7 +65,7 @@ namespace mobject { void NodeCreatorTool::onUnknown (Buildable& target) { - UNIMPLEMENTED ("catch-all when partitioning timeline"); ////////TODO: verify why this gets enfoced here... + UNIMPLEMENTED ("catch-all when partitioning timeline"); ////////TODO: verify why this gets enforced here... } diff --git a/src/proc/mobject/builder/nodecreatortool.hpp b/src/proc/mobject/builder/nodecreatortool.hpp index 4d3d04b9c..6d2b5e9e8 100644 --- a/src/proc/mobject/builder/nodecreatortool.hpp +++ b/src/proc/mobject/builder/nodecreatortool.hpp @@ -25,7 +25,7 @@ #define MOBJECT_BUILDER_NODECREATORTOOL_H -#include "proc/mobject/builder/applicablebuildertargettypes.hpp" +#include "proc/mobject/builder/applicable-builder-target-types.hpp" #include "proc/engine/rendergraph.hpp" @@ -66,7 +66,7 @@ namespace builder { virtual void treat (mobject::session::Auto& automation) ; //TODO: the automation-type-problem virtual void treat (mobject::Buildable& something) ; - void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shaddow this?? + void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shadow this?? }; diff --git a/src/proc/mobject/builder/segmentationtool.cpp b/src/proc/mobject/builder/segmentationtool.cpp index 703f25150..d0a18595d 100644 --- a/src/proc/mobject/builder/segmentationtool.cpp +++ b/src/proc/mobject/builder/segmentationtool.cpp @@ -22,9 +22,7 @@ #include "proc/mobject/builder/segmentationtool.hpp" -#include "proc/mobject/session/clip.hpp" -#include "proc/mobject/session/effect.hpp" -#include "proc/mobject/session/segment.hpp" + using mobject::Buildable; using mobject::session::Clip; @@ -34,6 +32,7 @@ using mobject::session::Effect; namespace mobject { namespace builder { + /////////////////////////////////TICKET #414 SegmentationTool::SegmentationTool(mobject::session::Fixture&) diff --git a/src/proc/mobject/builder/segmentationtool.hpp b/src/proc/mobject/builder/segmentationtool.hpp index 7106874c5..2b88f572a 100644 --- a/src/proc/mobject/builder/segmentationtool.hpp +++ b/src/proc/mobject/builder/segmentationtool.hpp @@ -25,7 +25,7 @@ #define MOBJECT_BUILDER_SEGMENTATIONTOOL_H -#include "proc/mobject/builder/applicablebuildertargettypes.hpp" +#include "proc/mobject/builder/applicable-builder-target-types.hpp" #include "proc/mobject/session/segmentation.hpp" #include "proc/mobject/session/fixture.hpp" //////TODO really on the header?? @@ -59,7 +59,7 @@ namespace mobject { void treat (mobject::Buildable& something) ; - void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shaddow this?? + void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shadow this?? bool empty() const; diff --git a/src/proc/mobject/explicitplacement.hpp b/src/proc/mobject/explicitplacement.hpp index b9522a111..a4b947473 100644 --- a/src/proc/mobject/explicitplacement.hpp +++ b/src/proc/mobject/explicitplacement.hpp @@ -49,10 +49,11 @@ namespace mobject { const Time time; const Pipe pipe; - typedef std::pair SolutionData; //TODO (ichthyo consideres better passing of solution by subclass) + typedef std::pair SolutionData; //TODO (ichthyo considers better passing of solution by subclass) /** no need to resolve any further, as this ExplicitPlacement * already \e is the result of a resolve()-call. + * //////////////////////TICKET #439 */ virtual ExplicitPlacement resolve () const diff --git a/src/proc/mobject/mobject-ref.cpp b/src/proc/mobject/mobject-ref.cpp index 69b4362f8..e711b26a8 100644 --- a/src/proc/mobject/mobject-ref.cpp +++ b/src/proc/mobject/mobject-ref.cpp @@ -46,7 +46,8 @@ namespace mobject { /** */ - LUMIERA_ERROR_DEFINE (INVALID_PLACEMENTREF, "unresolvable placement reference, or of incompatible type"); + LUMIERA_ERROR_DEFINE (INVALID_PLACEMENTREF, "unresolvable placement reference, or of incompatible type"); + LUMIERA_ERROR_DEFINE (BOTTOM_PLACEMENTREF, "NIL placement-ID marker encountered."); diff --git a/src/proc/mobject/mobject-ref.hpp b/src/proc/mobject/mobject-ref.hpp index 2312c16db..abdd03481 100644 --- a/src/proc/mobject/mobject-ref.hpp +++ b/src/proc/mobject/mobject-ref.hpp @@ -124,6 +124,37 @@ namespace mobject { else return *this; } + + /* == equality comparisons == */ + + template + bool + operator== (MORef const& oRef) + { + return pRef_ == oRef.pRef_; + } + + template + bool + operator== (PlacementRef const& pRef) + { + return pRef_ == pRef; + } + + template + bool + operator== (typename Placement::ID const& pID) + { + return pRef_ == pID; + } + + template + bool + operator!= (XX const& xx) + { + return !((*this) == xx); + } + }; ////////////////TODO currently just fleshing out the API.... diff --git a/src/proc/mobject/mobject.hpp b/src/proc/mobject/mobject.hpp index fecb8ee81..f73fb33c8 100644 --- a/src/proc/mobject/mobject.hpp +++ b/src/proc/mobject/mobject.hpp @@ -85,7 +85,7 @@ namespace mobject { /** MObject self-test (usable for asserting) */ virtual bool isValid() const =0; - virtual Time& getLength() =0; ///< @todo how to deal with the time/length field?? + virtual Time& getLength() =0; ///< @todo how to deal with the time/length field?? ////TICKET #448 virtual bool operator== (const MObject& oo) const =0; diff --git a/src/proc/mobject/placement-index.cpp b/src/proc/mobject/placement-index.cpp deleted file mode 100644 index 7fc5d9be0..000000000 --- a/src/proc/mobject/placement-index.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - PlacementIndex - tracking individual Placements and their relations - - 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 placement-index.cpp - ** - ** simple hash based implementation. Proof-of-concept - ** and for fleshing out the API - ** - ** @todo change PlacementIndex into an interface and create a separated implementation class - ** @see PlacementRef - ** @see PlacementIndex_test - ** - */ - - -#include "proc/mobject/placement-index.hpp" -#include "proc/mobject/session/session-impl.hpp" - -//#include -//using boost::str; - -namespace mobject { - - - class PlacementIndex::Table - { - public: - Table () - { } - - size_t - size() const - { - UNIMPLEMENTED ("PlacementIndex datastructure"); - return 0; - } - - }; - - - /* some type shorthands */ - typedef shared_ptr PIdx; - typedef PlacementIndex::PlacementMO PlacementMO; - typedef PlacementIndex::PRef PRef; - typedef PlacementIndex::ID ID; - - - /** @internal Factory for creating a new placement index. - * For use by the Session and for unit tests. - */ - PlacementIndex::Factory PlacementIndex::create; - - PlacementIndex::PlacementIndex() - : pTab_() - { } - - PlacementIndex::~PlacementIndex() { } - - - PlacementMO& - PlacementIndex::getRoot() const - { - UNIMPLEMENTED ("managing the implicit root context within a scope hierarchy"); - } - - - size_t - PlacementIndex::size() const - { - return pTab_->size() - 1; - } - - - bool - PlacementIndex::contains (ID id) const - { - UNIMPLEMENTED ("containment test: is the given Placement known within this index"); - return false; - } - - - PlacementMO& - PlacementIndex::find (ID) const - { - UNIMPLEMENTED ("main operation of PlacmentIndex: lookup a Placement by ID"); - } - - - - PlacementMO& - PlacementIndex::getScope (ID) const - { - UNIMPLEMENTED ("Secondary core operation of PlacmentIndex: find the 'parent' Placement by using the Placement relation index"); - } - - - vector - PlacementIndex::getReferrers (ID) const - { - UNIMPLEMENTED ("query the Placement relation index and retrieve all other placements bound to this one by a placement-relation"); - } - - - ID - PlacementIndex::insert (PlacementMO& newObj, PlacementMO& targetScope) - { - UNIMPLEMENTED ("store a new information record into PlacmentIndex: ID -> (ref-to-Placement, parent-Placement)"); - } - - - bool - PlacementIndex::remove (ID) - { - UNIMPLEMENTED ("remove a information record from PlacementIndex, and also deregister any placement-relations bound to it"); - } - - - - - namespace { // implementation detail: default global placement index access - - PIdx globalIndex; - - PIdx const& - getGlobalIndex() - { - if (globalIndex) - return globalIndex; - else - return session::SessManagerImpl::getCurrentIndex(); - } - - } // (End) implementation detail - - - - - - void - reset_PlacementIndex (PIdx const& alternativeIndex) - { - globalIndex = alternativeIndex; - } - - /** @internal restore the implicit PlacementIndex to its default implementation (=the session) */ - void - reset_PlacementIndex() - { - globalIndex.reset(); - } - - /** by default, this reaches for the PlacementIndex maintained within - * the current session. But for the purpose of unit tests, an alternative - * PlacementIndex may have been \link #reset_PlacementIndex installed \endlink - */ - Placement & - fetch_PlacementIndex (Placement::ID const& pID) - { - return getGlobalIndex()->find (pID); - } - - /** @internal used by PlacementRef to implement a self-check */ - bool - checkContains_PlacementIndex (Placement::ID const& pID) - { - return getGlobalIndex()->contains (pID); - } - - -} // namespace mobject diff --git a/src/proc/mobject/placement-index.hpp b/src/proc/mobject/placement-index.hpp deleted file mode 100644 index bd8950ef4..000000000 --- a/src/proc/mobject/placement-index.hpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - PLACEMENT-INDEX.hpp - tracking individual Placements and their relations - - Copyright (C) Lumiera.org - 2009, 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 placement-index.hpp - ** - ** @see PlacementRef - ** @see PlacementIndex_test - ** - */ - - - -#ifndef MOBJECT_PLACEMENT_INDEX_H -#define MOBJECT_PLACEMENT_INDEX_H - -//#include "pre.hpp" -//#include "proc/mobject/session/locatingpin.hpp" -//#include "proc/asset/pipe.hpp" -#include "lib/util.hpp" -#include "lib/factory.hpp" -#include "proc/mobject/placement.hpp" -#include "proc/mobject/placement-ref.hpp" - -#include -#include -#include -#include - - -namespace mobject { - - using lib::factory::RefcountFac; - using std::tr1::shared_ptr; - using boost::scoped_ptr; - using std::vector; - - class MObject; - - - /** - */ - class PlacementIndex - : boost::noncopyable - { - class Table; - - scoped_ptr pTab_; - - public: - typedef Placement PlacementMO; - typedef PlacementRef PRef; - typedef PlacementMO::ID const& ID; - - - PlacementMO& find (ID) const; - - template - Placement& find (PlacementMO::Id) const; - template - Placement& find (PlacementRef const&) const; - - PlacementMO& getScope (PlacementMO const&) const; - PlacementMO& getScope (ID) const; - - vector getReferrers (ID) const; - - - /** retrieve the logical root scope */ - PlacementMO& getRoot() const; - - /** diagnostic: number of indexed entries */ - size_t size() const; - bool contains (PlacementMO const&) const; - bool contains (ID) const; - - - /* == mutating operations == */ - - ID insert (PlacementMO& newObj, PlacementMO& targetScope); - bool remove (PlacementMO&); - bool remove (ID); - - - typedef RefcountFac Factory; - - static Factory create; - - ~PlacementIndex(); - - protected: - PlacementIndex() ; - - friend class lib::factory::Factory > >; - }; - ////////////////TODO currently just fleshing out the API; probably have to split off an impl.class; but for now a PImpl is sufficient... - - - - /** @internal there is an implicit PlacementIndex available on a global scale, - * by default implemented within the current session. This function allows - * to re-define this implicit index temporarily, e.g. for unit tests. */ - void - reset_PlacementIndex(shared_ptr const&) ; - - /** @internal restore the implicit PlacementIndex to its default implementation (=the session) */ - void - reset_PlacementIndex() ; - - /** @internal access point for PlacementRef to the implicit global PlacementIndex */ - Placement & - fetch_PlacementIndex(Placement::ID const&) ; - - - - - /* === forwarding implementations of the templated API === */ - - template - inline Placement& - PlacementIndex::find (PlacementMO::Id id) const - { - PlacementMO& result (find (id)); - REQUIRE (INSTANCEOF (MO, &result) ); - return static_cast&> (result); - } - - - template - inline Placement& - PlacementIndex::find (PlacementRef const& pRef) const - { - PlacementMO::Id id (pRef); - return find (id); - } - - - inline Placement& - PlacementIndex::getScope (PlacementMO const& p) const - { - return getScope(p.getID()); - } - - inline bool - PlacementIndex::contains (PlacementMO const& p) const - { - return contains (p.getID()); - } - - inline bool - PlacementIndex::remove (PlacementMO& p) - { - return remove (p.getID()); - } - - - -} // namespace mobject -#endif diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp index 9b8d8843a..96372de92 100644 --- a/src/proc/mobject/placement-ref.hpp +++ b/src/proc/mobject/placement-ref.hpp @@ -31,7 +31,7 @@ ** these cases will just be a subclass or Placement ** (which in the mentioned example would mean it couldn't be ** passed to a API function expecting a Placement). - ** This is uggly, but doesn't seem to bear any danger. + ** This is ugly, but doesn't seem to bear any danger. ** ** @see Placement ** @see PlacementRef_test @@ -47,8 +47,10 @@ //#include "proc/mobject/session/locatingpin.hpp" //#include "proc/asset/pipe.hpp" #include "lib/error.hpp" +#include "lib/bool-checkable.hpp" #include "proc/mobject/placement.hpp" #include "proc/mobject/explicitplacement.hpp" /////////////TODO this is ugly! Why can't placement::resolve() return a reference?? +#include "proc/mobject/session/session-service-fetch.hpp" //#include @@ -60,24 +62,22 @@ namespace mobject { class MObject; - // see placement-index.cpp - Placement & - fetch_PlacementIndex(Placement::ID const&) ; - - bool - checkContains_PlacementIndex (Placement::ID const& pID) ; LUMIERA_ERROR_DECLARE (INVALID_PLACEMENTREF); ///< unresolvable placement reference, or of incompatible type + LUMIERA_ERROR_DECLARE (BOTTOM_PLACEMENTREF); ///< NIL placement-ID marker encountered + /** + * TODO type comment */ - template + template class PlacementRef + : public lib::BoolCheckable > { - typedef Placement PlacementMO; - typedef Placement::ID _ID; ////TODO: could we define const& here?? - typedef Placement::Id _Id; + typedef Placement PlacementMX; + typedef Placement::ID _ID; + typedef Placement::Id _Id; _Id id_; @@ -105,6 +105,13 @@ namespace mobject { validate(id_); } + /** Default is an NIL Placement ref. It throws on any access. */ + PlacementRef () + : id_( bottomID() ) + { + REQUIRE (!isValid(), "hash-ID clash with existing ID"); + } + PlacementRef (PlacementRef const& r) ///< copy ctor : id_(r.id_) { @@ -112,7 +119,7 @@ namespace mobject { } template - PlacementRef (PlacementRef const& r) ///< extended copy ctor, when type X is assignable to MO + PlacementRef (PlacementRef const& r) ///< extended copy ctor, when type X is assignable to MX : id_(recast(r)) { validate(id_); @@ -148,9 +155,9 @@ namespace mobject { /* == forwarding smart-ptr operations == */ - PlacementMO& operator*() const { return access(id_); } ///< dereferencing fetches referred Placement from Index + PlacementMX& operator*() const { return access(id_); } ///< dereferencing fetches referred Placement from Index - PlacementMO& operator->() const { return access(id_); } ///< provide access to pointee API by smart-ptr chaining + PlacementMX& operator->() const { return access(id_); } ///< provide access to pointee API by smart-ptr chaining operator string() const { return access(id_).operator string(); } size_t use_count() const { return access(id_).use_count(); } @@ -166,11 +173,6 @@ namespace mobject { bool operator!= (PlacementRef const& o) const { return id_ != o; } - typedef _Id PlacementRef::*__unspecified_bool_type; - - /** implicit conversion to "bool" */ - operator __unspecified_bool_type() const { return isValid()? &PlacementRef::id_ : 0; } // never throws - bool operator! () const { return !isValid(); } // ditto @@ -188,7 +190,11 @@ namespace mobject { return false; } - ExplicitPlacement resolve() const { return access(id_).resolve();} + ExplicitPlacement + resolve() const + { + return access(id_).resolve(); + } ////////////////TODO more operations to come.... @@ -197,14 +203,15 @@ namespace mobject { bool checkValidity () const { - return checkContains_PlacementIndex(this->id_); + return session::SessionServiceFetch::isAccessible() // session interface opened? + && session::SessionServiceFetch::isRegisteredID (this->id_); } static void validate (_Id const& rId) { - PlacementMO& pRef (access (rId)); - if (!(pRef.template isCompatible())) + PlacementMX& pRef (access (rId)); + if (!(pRef.template isCompatible())) throw lumiera::error::Invalid("actual type of the resolved placement is incompatible",LUMIERA_ERROR_INVALID_PLACEMENTREF); ////////////////////////TODO: 1. better message, including type? @@ -224,17 +231,27 @@ namespace mobject { return reinterpret_cast<_Id const&> (*luid); } - static PlacementMO& + static _Id const& + bottomID () ///< @return marker for \em invalid reference + { + static lumiera_uid invalidLUID; + return recast (&invalidLUID); + } + + static PlacementMX& access (_Id const& placementID) { - Placement & pla (fetch_PlacementIndex (placementID)); // may throw + Placement & pla (session::SessionServiceFetch::resolveID (placementID)); // may throw REQUIRE (pla.isValid()); - ASSERT (pla.isCompatible()); - return static_cast (pla); + ASSERT (pla.isCompatible()); + return static_cast (pla); } }; + /** frequently-used shorthand */ + typedef PlacementRef RefPlacement; + } // namespace mobject diff --git a/src/proc/mobject/placement.cpp b/src/proc/mobject/placement.cpp index 71a930e2d..1b6e4c14d 100644 --- a/src/proc/mobject/placement.cpp +++ b/src/proc/mobject/placement.cpp @@ -38,6 +38,7 @@ namespace mobject { * because we define the Placements of more specific * MObject kinds to be subclasses of Placement, * so they will inherit this function. + * //////////////////////TICKET #439 */ ExplicitPlacement Placement::resolve () const @@ -68,6 +69,16 @@ namespace mobject { } + bool + isSameDef (PlacementMO const& pl1, PlacementMO const& pl2) + { + return pl1.getID() == pl2.getID() + || pl1.chain == pl2.chain + ; + } + + + } // namespace mobject diff --git a/src/proc/mobject/placement.hpp b/src/proc/mobject/placement.hpp index 4f2ff9d95..1ebb966ac 100644 --- a/src/proc/mobject/placement.hpp +++ b/src/proc/mobject/placement.hpp @@ -42,18 +42,17 @@ ** absolute position (time, track). ** ** Together, this yields semantics somewhere in between value semantics and reference semantics. - ** As any smart-ptr, placements are copyable, any such copies being considered equivalent. \em But, - ** when added to the Session, a placement acts as if it was an \em instance of the object it - ** points at, with the purpose to bind this instance into the Session with specific placement + ** As any smart-ptr, placements are copyable, but each such copy takes on a distinct identity. + ** Moreover, when added to the Session, a placement acts as if it was an \em instance of the object + ** it points at, with the purpose to bind this instance into the Session with specific placement ** properties. Thus, such a placement-within-session \em is an distinguishable entity, because ** the settings on the contained LocatingPin chain \em do constitute the relation properties ** of the MObject "placed" by this placement. To support this rather ref-like semantics, any - ** placement has an embedded ID (identity), and the Session won't allow to add a clone copy - ** of an placement with the same identity. Moreover, it is possible to create a smart-ptr - ** like PlacementRef to denote a specific placement found within the current Session. + ** placement has an embedded ID (identity). Building on this ID, it is possible to create a + ** smart-ptr like PlacementRef to denote a specific placement found within the Session. ** ** Placements are templated on the type of the actual MObject they refer to, so, sometimes - ** we rather use a Placement to be able to use the more specific methods of the + ** e.g. we rather use a Placement to be able to use the more specific methods of the ** session::Clip interface. But please note the following detail: this type ** labelling and downcasting is the only difference between these subclasses, ** besides that, they can be replaced literally by one another (slicing is accepted). @@ -72,7 +71,7 @@ #include "lib/hash-indexed.hpp" #include "proc/mobject/session/locatingpin.hpp" -#include "proc/asset/pipe.hpp" /////TODO: get rid of this (Trac #109) +#include "proc/asset/pipe.hpp" //////////////TICKET #109 : get rid of this #include @@ -116,15 +115,15 @@ namespace mobject { */ template<> class Placement - : protected shared_ptr, - public HashIndexed, lib::hash::LuidH> //////TODO: really need to be inherited publicly? + : protected shared_ptr + , public HashIndexed, lib::hash::LuidH > { protected: typedef HashIndexed, lib::hash::LuidH> HashInd; typedef shared_ptr _SmartPtr; typedef void (*Deleter)(MObject*); typedef lumiera::Time Time; - typedef asset::shared_ptr Pipe; ////TODO: get rid of this + typedef asset::shared_ptr Pipe; ////TICKET #109 : get rid of this @@ -171,14 +170,29 @@ namespace mobject { * provide the resulting (explicit) placement. */ virtual ExplicitPlacement resolve () const; - //////////////////////////TODO could resolve() return a reference? Otherwise placement-ref.hpp needs to include ExplicitPlacement + //////////////////////////TODO (1) could resolve() return a reference? Otherwise placement-ref.hpp needs to include ExplicitPlacement + //////////////////////////TODO (2) does this really need to be virtual. Guess not. It's not abstract and not really polymorphic. But virtual here causes template bloat. + ////////////TICKET #439 + Placement (Placement const& ref) + : _SmartPtr (ref) + , HashInd() // creating a new ID! + , chain(ref.chain) + { } + protected: Placement (MObject & subject, Deleter killer) - : _SmartPtr (&subject, killer) {}; + : _SmartPtr (&subject, killer) { }; friend class session::MObjectFactory; + + +/////////////////////////////////////////////////////////TICKET #513 +// private: +// /** copy assignment prohibited */ +// Placement& operator= (Placement const&); +/////////////////////////////////////////////////////////TICKET #513 }; @@ -198,7 +212,7 @@ namespace mobject { { protected: typedef Placement _Parent; - typedef typename _Parent::template Id const& _ID; + typedef typename _Parent::template Id const& _Id; typedef typename _Parent::Deleter Deleter; typedef typename _Parent::_SmartPtr _SmartPtr; @@ -217,7 +231,7 @@ namespace mobject { (_SmartPtr::operator-> ()); } - _ID + _Id getID () const ///< @note overrides HashIndexed::getID to pass specific type information, { return _Parent::template recastID(); @@ -226,14 +240,26 @@ namespace mobject { }; - string - format_PlacementID (Placement const&) ; - - - /** @todo cleanup uses of ref-to-placement. See Trac #115 */ + /** @todo cleanup uses of ref-to-placement. See Ticket #115 */ typedef Placement PlacementMO; typedef Placement PMO; + + + + /* == free functions == */ - + string + format_PlacementID (PlacementMO const&) ; + + + /** compare the properties of placement + * @return \c true if all the LocatingPin entries + * in both placements are semantically equivalent. + */ + bool + isSameDef (PlacementMO const&, PlacementMO const&); + + + } // namespace mobject #endif diff --git a/src/proc/mobject/session.hpp b/src/proc/mobject/session.hpp index 0542e1da2..987d2503b 100644 --- a/src/proc/mobject/session.hpp +++ b/src/proc/mobject/session.hpp @@ -23,9 +23,22 @@ /** @file session.hpp ** Primary Interface to the current Session. + ** The session interface can be used to discover session's contents. + ** Mostly, these objects within the session are MObject subclasses, but they + ** are attached into the session by a Placement. Usually, you'd want to use + ** the discovered objects to invoke operations on them; in most cases, + ** invoking any mutating operation should be wrapped into a Command. + ** ** The Interface Session is abstract and only accessible via the ** static field Session::current, which actually refers to a SessManager - ** singleton instance. The latter acts as smart ptr-to-Impl. + ** singleton instance. The latter acts as smart ptr-to-Impl for accessing the + ** current session, but at the same time exposes a lifecycle/management API. + ** + ** @note if interested in the interplay of Session, SessManager and the + ** internal service APIs (SessionServices), you should have a look + ** at session-service-access-test.cpp, as this test creates a complete + ** but simplified mock setup of the session and session manager, without + ** any access and synchronisation and similar concerns, to read top down. ** */ @@ -80,11 +93,12 @@ namespace mobject { { protected: Session (session::DefsManager&) throw(); - virtual ~Session () = 0; + virtual ~Session (); public: static session::SessManager& current; - session::DefsManager& defaults; + static bool initFlag; ///////////////TICKET #518 yet another hack; actually need to care for session manager startup. + session::DefsManager& defaults; ///////////////TODO this is a hack... better solve it based on the new SessionServices mechanism virtual bool isValid () = 0; virtual void add (PMO& placement) = 0; @@ -101,6 +115,7 @@ namespace mobject { extern const char* ON_SESSION_START; ///< triggered before loading any content into a newly created session extern const char* ON_SESSION_INIT; ///< triggered when initialising a new session, after adding content + extern const char* ON_SESSION_READY; ///< triggered after session is completely functional and all APIs are open. extern const char* ON_SESSION_END; ///< triggered before discarding an existing session @@ -113,6 +128,9 @@ namespace mobject { class SessManager : private boost::noncopyable { public: + /** diagnostics: session interface opened? */ + virtual bool isUp () =0; + /** clear current session contents * without resetting overall session config. * Afterwards, the session will contain only one @@ -128,13 +146,13 @@ namespace mobject { /** replace the current session by a new * session loaded from serialised state. */ - virtual void load () =0; + virtual void load () =0; /** create a complete, serialised representation * of the current session config and contents. * @todo how to serialise, parameters, return value? */ - virtual void save () =0; + virtual void save () =0; /** access to the current session object instance. * This is the sole access path available for clients. @@ -142,7 +160,7 @@ namespace mobject { */ virtual Session* operator-> () throw() =0; - virtual ~SessManager() {}; + virtual ~SessManager(); }; diff --git a/src/proc/mobject/session/defsmanager.hpp b/src/proc/mobject/session/defsmanager.hpp index a223a17e8..ac4bfa673 100644 --- a/src/proc/mobject/session/defsmanager.hpp +++ b/src/proc/mobject/session/defsmanager.hpp @@ -52,17 +52,18 @@ namespace mobject { * code didn't give more specific parameters. Necessary sub-objects * will be created on demand, and any default configuration, once * found, will be remembered and stored with the current session. + * + * @note while the logic of defaults handling can be considered + * roughly final, as of 12/09 most of the actual object + * handling is placeholder code. */ class DefsManager : private boost::noncopyable { scoped_ptr defsRegistry; - protected: + public: DefsManager () throw(); - friend class SessManagerImpl; - - public: ~DefsManager (); /** common access point: retrieve the default object fulfilling @@ -111,6 +112,13 @@ namespace mobject { // template class SMP ///< smart pointer class to wrap the result // > // SMP operator() (const lumiera::Query&); + +// 12/09: according to my current knowledge of template metaprogramming, the answer is "no", +// but we could use a traits template to set up a fixed association of smart pointers +// and kinds of target object. This would allow to define a templated operator() returning +// the result wrapped into the right holder. But currently I don't see how to build a sensible +// implementation infrastructure backing such an interface. +//////////TICKET #452 }; diff --git a/src/proc/mobject/session/defsregistry.hpp b/src/proc/mobject/session/defsregistry.hpp index 3fbd4aa1f..f37f08109 100644 --- a/src/proc/mobject/session/defsregistry.hpp +++ b/src/proc/mobject/session/defsregistry.hpp @@ -43,6 +43,7 @@ #include "lib/sync-classlock.hpp" #include "lib/query.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "lib/p.hpp" #include diff --git a/src/proc/mobject/session/edl.hpp b/src/proc/mobject/session/edl.hpp index e72b91bad..f6e3db000 100644 --- a/src/proc/mobject/session/edl.hpp +++ b/src/proc/mobject/session/edl.hpp @@ -40,7 +40,9 @@ namespace mobject { namespace session { - class EDL ///////////////////////////TODO is considered to be renamed as "Sequence". Should be converted to an Inteface + class EDL ///////////////////////////TICKET #152 EDL will be renamed to "Sequence". + ///////////////////////////TODO: Should be converted to an facade interface + ///////////////////////////TODO: what follows is dummy code and will be dropped! { protected: Placement track; @@ -55,7 +57,7 @@ namespace mobject { Placement& getTracks () { return track; } ///< @todo work out the correct use of tracks! make const correct! size_t size () { - UNIMPLEMENTED ("what ist the 'size' of an EDL?"); + UNIMPLEMENTED ("what is the 'size' of an EDL?"); return 0; } diff --git a/src/proc/mobject/session/label.cpp b/src/proc/mobject/session/label.cpp index c5d85907d..6f6224fed 100644 --- a/src/proc/mobject/session/label.cpp +++ b/src/proc/mobject/session/label.cpp @@ -22,16 +22,21 @@ #include "proc/mobject/session/label.hpp" +#include "lib/util.hpp" -namespace mobject +using util::isnil; + +namespace mobject { +namespace session { + + + /** @todo real validity self-check for Label MObject */ + bool + Label::isValid() const { - namespace session - { - - /** */ - - - - } // namespace mobject::session - -} // namespace mobject + return !isnil (typeID_); + } + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/label.hpp b/src/proc/mobject/session/label.hpp index b968baa68..8d349a91e 100644 --- a/src/proc/mobject/session/label.hpp +++ b/src/proc/mobject/session/label.hpp @@ -25,28 +25,40 @@ #define MOBJECT_SESSION_LABEL_H #include "proc/mobject/session/meta.hpp" +#include "lib/symbol.hpp" -namespace mobject - { - namespace session +namespace mobject { +namespace session { + + using lib::Symbol; + + + /** + * Any sort of User visible Marker or Tag, used + * to mark time positions and ranges, or specific + * locations to attach other MObjects to. + * + * @todo Placeholder code for now. + * @todo planning to provide some kind of dynamic properties (map) + */ + class Label : public Meta { - - - /** - * Any sort of User visible Marker or Tag, used - * to mark time positions and ranges, or specific - * locations to attach other MObjects to. - */ - class Label : public Meta - { - ///////////TODO: timespan fields here or already in class Meta?? - }; - - - - } // namespace mobject::session - -} // namespace mobject + ///////////TODO: timespan fields here or already in class Meta?? + + Symbol typeID_; + + virtual bool isValid() const; + + public: + Label (Symbol type) + : typeID_(type) + { } + + }; + + + +}} // namespace mobject::session #endif diff --git a/src/proc/mobject/session/locatingpin.cpp b/src/proc/mobject/session/locatingpin.cpp index 9191c818f..f4e7ce954 100644 --- a/src/proc/mobject/session/locatingpin.cpp +++ b/src/proc/mobject/session/locatingpin.cpp @@ -146,8 +146,8 @@ namespace session { LocatingPin::Pipe LocatingPin::LocatingSolution::getPipe() { - UNIMPLEMENTED ("get effective Pipe of Solution"); - return Pipe (); + TODO ("implement Placement LocatingSolution"); + return asset::Pipe::query ("pipe(master)"); // yet another idiotic dummy } diff --git a/src/proc/mobject/session/locatingpin.hpp b/src/proc/mobject/session/locatingpin.hpp index be45a1ad2..a3b1e27f1 100644 --- a/src/proc/mobject/session/locatingpin.hpp +++ b/src/proc/mobject/session/locatingpin.hpp @@ -34,7 +34,7 @@ ** ** @todo this can be considered a preliminary sketch without being backed ** by actual functionality. Just enough to be able to drive the design of - ** other parts ahead. See esp. Trac #100, which contains an idea for a + ** other parts ahead. See esp. TICKET #100, which contains an idea for a ** refactoring. ** */ @@ -99,7 +99,7 @@ namespace mobject { typedef lumiera::Time Time; typedef Time* Track; //TODO dummy declaration; we don't use Tracks as first-class entity any longer typedef std::tr1::shared_ptr Pipe; - typedef std::pair SolutionData; //TODO (ichthyo considers better passing of solution by subclass) + typedef std::pair SolutionData; //TICKET #100 (ichthyo considers better passing of solution by subclass) struct LocatingSolution; /** next additional Pin, if any */ @@ -124,6 +124,7 @@ namespace mobject { LocatingPin (const LocatingPin&); LocatingPin& operator= (const LocatingPin&); virtual LocatingPin* clone () const; + virtual ~LocatingPin() {}; // protected: @@ -166,8 +167,20 @@ protected: bool still_to_solve (); }; + + friend bool operator== (LocatingPin const&, LocatingPin const&); + }; + + /** check for equivalent definition of a complete locating chain */ + + inline bool + operator== (LocatingPin const& pin1, LocatingPin const& pin2) + { +//////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #511 really implement equivalence relation! + return pin1.resolve().first == pin2.resolve().first; + } diff --git a/src/proc/mobject/session/meta.hpp b/src/proc/mobject/session/meta.hpp index f1a69b98d..dffd8610c 100644 --- a/src/proc/mobject/session/meta.hpp +++ b/src/proc/mobject/session/meta.hpp @@ -37,10 +37,12 @@ namespace session { * but rather all sorts of Processing Instructions * and other metadata, which can be placed and * attached within the EDL/Session. + * @todo do we need this abstract baseclass? */ class Meta : public AbstractMO { /////////// + //////////////////////////////TICKET #448 what to do with the length here?? }; diff --git a/src/proc/mobject/session/mobjectfactory.cpp b/src/proc/mobject/session/mobjectfactory.cpp index e6e158731..8b4cf5d89 100644 --- a/src/proc/mobject/session/mobjectfactory.cpp +++ b/src/proc/mobject/session/mobjectfactory.cpp @@ -22,18 +22,37 @@ #include "proc/mobject/session/mobjectfactory.hpp" +#include "proc/mobject/session/root.hpp" #include "proc/mobject/session/clip.hpp" #include "proc/mobject/session/track.hpp" #include "proc/mobject/session/effect.hpp" +#include "proc/mobject/session/label.hpp" #include "proc/asset/clip.hpp" #include "proc/asset/track.hpp" #include "proc/asset/effect.hpp" -namespace mobject - { - namespace session - { +namespace mobject { +namespace session { + ////////////////////////////////////////////////////////////////////////////////TICKET #414 + + + /** build a new session/model root element. */ + Placement + MObjectFactory::operator() (DefsManager& sessionDefaultsHandler) + { + return Placement (*new Root (sessionDefaultsHandler), &deleterFunc); + } + + + /** build a new session/model root element. */ + Placement
                                    pTab_; + + + typedef PlacementMO::ID _PID; + typedef std::tr1::unordered_multimap<_PID,_PID>::const_iterator ScopeIter; + typedef lib::RangeIter ScopeRangeIter; + + + + public: + typedef Placement PlacementMO; + typedef PlacementRef PRef; + typedef PlacementMO::ID const& ID; + + typedef lib::TransformIter iterator; + + + /* == query operations == */ + + PlacementMO& find (ID) const; + + template + Placement& find (PlacementMO::Id) const; + template + Placement& find (PlacementRef const&) const; + + PlacementMO& getScope (PlacementMO const&) const; + PlacementMO& getScope (ID) const; + + iterator getReferrers (ID) const; + + + /** retrieve the logical root scope */ + PlacementMO& getRoot() const; + + size_t size() const; + bool contains (PlacementMO const&) const; + bool contains (ID) const; + + bool isValid() const; + + + + + /* == mutating operations == */ + + ID insert (PlacementMO const& newObj, ID targetScope); + bool remove (PlacementMO&); + bool remove (ID); + + + + PlacementIndex(PlacementMO const&); + ~PlacementIndex() ; + + void clear(); + + }; + + + + + + + + + /* === forwarding implementations of the templated API === */ + + + namespace { // shortcuts... + + template + inline void + ___check_compatibleType(PlacementMO& questionable) + { + if (!questionable.isCompatible()) + throw lumiera::error::Logic ("Attempt to retrieve a Placement of specific type, " + "while the actual type of the pointee (MObject) " + "registered within the index isn't compatible with the " + "requested specific MObject subclass" + ,LUMIERA_ERROR_PLACEMENT_TYPE); + } + + inline void + __check_knownID(PlacementIndex const& idx, PlacementMO::ID id) + { + if (!id) + throw lumiera::error::Logic ("Encountered a NIL Placement-ID marker" + ,LUMIERA_ERROR_BOTTOM_PLACEMENTREF); + if (!idx.contains (id)) + throw lumiera::error::Invalid ("Accessing Placement not registered within the index" + ,LUMIERA_ERROR_NOT_IN_SESSION); ///////////////////////TICKET #197 + } + }//(End) shortcuts + + + + + template + inline Placement& + PlacementIndex::find (PlacementMO::Id id) const + { + PlacementMO& result (find (id)); + + ___check_compatibleType (result); + return static_cast&> (result); + } + + + template + inline Placement& + PlacementIndex::find (PlacementRef const& pRef) const + { + PlacementMO::Id id (pRef); + return find (id); + } + + + inline Placement& + PlacementIndex::getScope (PlacementMO const& p) const + { + return getScope(p.getID()); + } + + inline bool + PlacementIndex::contains (PlacementMO const& p) const + { + return contains (p.getID()); + } + + inline bool + PlacementIndex::remove (PlacementMO& p) + { + return remove (p.getID()); + } + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/query-focus-stack.hpp b/src/proc/mobject/session/query-focus-stack.hpp new file mode 100644 index 000000000..7bac96683 --- /dev/null +++ b/src/proc/mobject/session/query-focus-stack.hpp @@ -0,0 +1,195 @@ +/* + QUERY-FOCUS-STACK.hpp - management of current scope within the Session + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_QUERY_FOCUS_STACK_H +#define MOBJECT_SESSION_QUERY_FOCUS_STACK_H + +#include "proc/mobject/session/scope-path.hpp" + +#include +#include + +using std::list; + + +namespace mobject { +namespace session { + + + + /** + * A custom stack holding ScopePath »frames«. + * It is utilised by the ScopeLocator to establish the + * \em current query focus location. Client code should + * access this mechanism through QueryFocus instances + * used as frontend. These QueryFocus objects incorporate + * a boost::intrusive_ptr, which stores the ref-count within + * the mentioned ScopePath frames located in the stack. + * + * \par automatic cleanup of unused frames + * + * The stack is aware of this ref-counting mechanism and will -- + * on each access -- automatically clean up any unused frames starting + * from stack top, until encountering the first frame still in use. + * This frame, by definition, is the current focus location. + * The stack ensures there is always at least one ScopePath frame, + * default-creating a new one if necessary. + * + * @see query-focus-stack-test.cpp + * @see ScopeLocator + * @see QueryFocus access point for client code + */ + class QueryFocusStack + : boost::noncopyable + { + + std::list paths_; + + public: + QueryFocusStack () + : paths_() + { + openDefaultFrame(); + } + + + bool empty () const; + size_t size () const; + + ScopePath& push (Scope const&); + ScopePath& top (); + void pop_unused (); + void clear (); + + + private: + void openDefaultFrame (); + }; + + + + + + + + /* __implementation__ */ + + bool + QueryFocusStack::empty () const + { + return paths_.empty(); + } + + + size_t + QueryFocusStack::size () const + { + return paths_.size(); + } + + + void + QueryFocusStack::clear () + { + paths_.clear(); + } + + + /** Open a new path frame, pushing down the current frame. + * The new frame tries to locate the given start scope + * and navigates to this position. + * @note EXCEPTION_STRONG guarantee + * @return reference to the newly created path on top + * @throw error::Invalid if newStartPoint isn't locatable + */ + ScopePath& + QueryFocusStack::push (Scope const& newStartPoint) + { + ScopePath newPathFrame (newStartPoint); // may throw + ENSURE (newPathFrame.isValid() || newStartPoint.isRoot()); + + paths_.push_back (newPathFrame); + ENSURE (0 < size()); + return paths_.back(); + } + + + /** @return the topmost path frame actually in use + * @note may invoke #pop_unused() + * @note EXCEPTON_FREE ///////TODO prove! + */ + ScopePath& + QueryFocusStack::top () + { + if ( 0 == size() + || 0 == paths_.back().ref_count() + ) + pop_unused(); + + ENSURE (!empty()); + return paths_.back(); + } + + + /** investigate the stack top and discard any path frames + * which aren't referred anymore (as indicated by their + * ScopePath#use_count(). After executing this function + * the topmost frame is either in use, or a new default + * frame has been created at the bottom of an empty stack. + * @note EXCEPTION_FREE ///////TODO prove! + */ + void + QueryFocusStack::pop_unused () + { + if (1 == size() && !paths_.front().isValid()) + return; // unnecessary to evict a base frame repeatedly + + while (size() && (0 == paths_.back().ref_count())) + paths_.pop_back(); + + if (0 == size()) + openDefaultFrame(); + ENSURE (!empty()); + } + + + /** @internal open a default path frame at the bottom + * of an empty stack, locating to current model root + * @note EXCEPTION_FREE ///////TODO prove! + */ + void + QueryFocusStack::openDefaultFrame () + { + REQUIRE (0 == size()); + + paths_.resize(1); + + ENSURE (!paths_.front().empty()); + ENSURE (!paths_.front().isValid()); // i.e. just root scope + } + + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/query-focus.cpp b/src/proc/mobject/session/query-focus.cpp new file mode 100644 index 000000000..965d50b66 --- /dev/null +++ b/src/proc/mobject/session/query-focus.cpp @@ -0,0 +1,142 @@ +/* + QueryFocus - management of current scope within the Session + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/query-focus.hpp" + + +namespace mobject { +namespace session { + + + + /** + * create a new QueryFocus (handle) + * linked to the current focus for discovery queries. + * The existence of this QueryFocus instance keeps this + * current focus alive, but multiple instances share a + * common focus location and may change this location. + * + */ + QueryFocus::QueryFocus() + : focus_( & currPath()) + { } + + + /** + * @internal build a new QueryFocus + * as attached to an existing path. + */ + QueryFocus::QueryFocus(ScopePath& path_to_attach) + : focus_( &path_to_attach) + { } + + + /** @internal access the path designating + * the current focus location */ + ScopePath& + QueryFocus::currPath() + { + return ScopeLocator::instance().currPath(); + } + + + /** discard any state and navigate + * current focus path to model root + */ + QueryFocus& + QueryFocus::reset () + { + REQUIRE (focus_); + focus_->clear(); + return *this; + } + + + + + + namespace {// error check shortcut.... + + using lumiera::error::Invalid; + + void + ___check_validTaget (Scope const& target) + { + if (!target.isValid()) + throw Invalid ("Invalid target location for QueryFocus" + , LUMIERA_ERROR_INVALID_SCOPE); ////////////////TICKET #197 + } + }//(End) shortcut + + + + /** attach this QueryFocus to a container-like scope, + * causing it to \em navigate, changing the + * current ScopePath as a side-effect + * @throw error::Invalid if the given container is + * invalid or can't be located within the model + */ + QueryFocus& + QueryFocus::attach (Scope const& container) + { + ___check_validTaget (container); + + REQUIRE (focus_); + focus_->navigate (container); + return *this; + } + + + /** push the "current QueryFocus" aside and open a new focus frame. + * This new QueryFocus will act as "current" until going out of scope + * @throw error::Invalid in case of invalid or unlocatable target scope + */ + QueryFocus + QueryFocus::push (Scope const& otherContainer) + { + ___check_validTaget (otherContainer); + + QueryFocus newFocus (ScopeLocator::instance().pushPath()); + newFocus.attach (otherContainer); + return newFocus; + } + + + /** cease to use \em this specific reference to the current frame. + * This operation immediately tries to re-attach to what is "current" + * and readjusts the internal handle. But when the previously released + * reference was the last one, releasing it will cause the QueryFocusStack + * to pop, in which case we'll re-attach to the now uncovered previous stack top. + */ + QueryFocus& + QueryFocus::pop() + { + focus_ = 0; + focus_ = & currPath(); + + return *this; + } + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp new file mode 100644 index 000000000..4a211d8ee --- /dev/null +++ b/src/proc/mobject/session/query-focus.hpp @@ -0,0 +1,154 @@ +/* + QUERY-FOCUS.hpp - management of current scope within the Session + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_QUERY_FOCUS_H +#define MOBJECT_SESSION_QUERY_FOCUS_H + +#include "proc/mobject/session/scope-path.hpp" +#include "proc/mobject/session/scope-locator.hpp" + +#include + +namespace mobject { +namespace session { + + + + /** + * Current focus location to use as point-of reference + * for contents and location discovery queries. This is the + * frontend to be used by client code: a smart-handle, internally + * linked through the ScopeLocaor singleton to a stack of current + * focus path locations. The intention is for this current location + * to follow the ongoing query/discovery operations mostly automatically. + * + * \par usage + * + * A QueryFocus (frontend handle) can be default constructed, in which + * case it will automatically connect to what is currently the focus + * location for any further queries. Here, the current focus location + * is defined as the most recently used location which is still referred + * by some QueryFocus handle. + * + * Alternatively, through the static factory function #push(), a new + * focus location may be opened, thereby pushing the currently used + * focus location aside. This new focus location will remain the + * current focus, while any handles referring to it is still in use. + * + * Using an existing QueryFocus (handle), the current focus may be + * shifted to another scope within the current session. + * + * The templated query functions allow to issue specifically typed + * queries to retrieve all children (immediately contained in a + * given scope), or do discover depth-first any content within + * this scope. The result set of these queries will be filtered + * to yield only placements compatible to the specified kind of + * MObject. E.g, you may query all Clip objects within a given Track. + * + * The implementation of these query operations is backed by the + * PlacementIndex in the current session. The link to the session + * is established the moment these query functions are invoked. + * The returned iterator (Lumiera Forward Iterator) contains a + * smart-ptr to keep the hidden result set alive. The results + * are delivered without any defined order (implementation is + * hashtable based) + * + * @see query-focus-test.cpp + */ + class QueryFocus + { + boost::intrusive_ptr focus_; + + public: + QueryFocus(); + + ScopePath currentPath() const; + operator Scope() const; + + QueryFocus& attach (Scope const&); + static QueryFocus push (Scope const&); + QueryFocus& reset (); + QueryFocus& pop (); + + + template + typename ScopeQuery::iterator + query() const; + + template + typename ScopeQuery::iterator + explore() const; + + + private: + QueryFocus (ScopePath&); + static ScopePath& currPath(); + }; + + + + + + + /** allowing direct conversion to Scope. + * Implemented by copying the scope at + * leaf position of the current focus path + */ + QueryFocus::operator Scope() const + { + return currPath().getLeaf(); + } + + /**@note returning a copy */ + ScopePath + QueryFocus::currentPath() const + { + return currPath(); + } + + + /** discover depth-first any matching object + * within \em current focus. Resolution is + * delegate to the \em current session */ + template + typename ScopeQuery::iterator + QueryFocus::query() const + { + ScopeLocator::instance().query (*this); + } + + + /** discover any matching object contained + * as immediate Child within \em current focus. + * Resolution through \em current session */ + template + typename ScopeQuery::iterator + QueryFocus::explore() const + { + ScopeLocator::instance().explore (*this); + } + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp new file mode 100644 index 000000000..5b01ef3c5 --- /dev/null +++ b/src/proc/mobject/session/query-resolver.cpp @@ -0,0 +1,125 @@ +/* + QueryResolver - interface for discovering contents of a scope + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/query-resolver.hpp" +#include "lib/multifact-arg.hpp" + +namespace mobject { +namespace session { + + using lib::factory::MultiFact; + using lib::factory::BuildRefcountPtr; + + + /* generate vtables here... */ + + Goal::~Goal() { } + + Resolution::~Resolution() { } + + QueryResolver::~QueryResolver() { } + + + + + typedef Goal::QueryID const& QID; + + /** we're going to use QueryID as Map key... */ + inline bool + operator< (QID q1, QID q2) + { + return (q1.kind < q2.kind) + || (q1.kind == q2.kind + && q1.type < q2.type + ); + } + + + + + + /* == dispatch to resolve typed queries == */ + + /** factory used as dispatcher table + * for resolving typed queries */ + typedef MultiFact< Resolution(Goal const&) // nominal signature of fabrication + , Goal::QueryID // select resolution function by kind-of-Query + , BuildRefcountPtr // wrapper: manage result set by smart-ptr + > DispatcherTable; // + + struct QueryDispatcher + : DispatcherTable + { + + PReso + handle (Goal const& query) + { + QID qID = query.getQID(); + ENSURE (contains (qID)); + + return (*this) (qID, query); + } //qID picks the resolution function + }; + + + + QueryResolver::QueryResolver () + : dispatcher_(new QueryDispatcher) + { } + + + /** @par implementation + * For actually building a result set, the QueryResolver base implementation + * uses an embedded dispatcher table. The concrete query resolving facilities, + * when implementing the QueryResolver interface, are expected to register + * individual resolution functions into this QueryDispatcher table. + * Whenever issuing a Goal, a suitable resolution function is picked + * based on the Goal::QueryID, which contains an embedded type code. + * Thus, the individual resolution function can (re)establish a + * typed context and downcast the Goal appropriately + */ + PReso + QueryResolver::issue (Goal const& query) const + { + TODO ("ensure proper initialisation"); + + if (!canHandle (query)) + throw lumiera::error::Invalid ("unable to resolve this kind of query"); ////TICKET #197 + + return dispatcher_->handle(query); + } + + + void + QueryResolver::installResolutionCase (QID qID, function resolutionFun) + { + ENSURE (!dispatcher_->contains (qID), + "duplicate registration of query resolution function"); + + dispatcher_->defineProduction (qID, resolutionFun); + } + + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp new file mode 100644 index 000000000..7ea26ca14 --- /dev/null +++ b/src/proc/mobject/session/query-resolver.hpp @@ -0,0 +1,332 @@ +/* + QUERY-RESOLVER.hpp - interface for discovering contents of a scope + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_QUERY_RESOLVER_H +#define MOBJECT_SESSION_QUERY_RESOLVER_H + +//#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/placement.hpp" +#include "lib/bool-checkable.hpp" +#include "lib/typed-counter.hpp" +#include "lib/iter-adapter.hpp" +#include "lib/util.hpp" + +#include +#include +#include +#include +//#include +#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + using util::unConst; + using boost::noncopyable; + using boost::scoped_ptr; + using std::tr1::function; + using std::string; + + class no_copy_by_client + { + protected: + ~no_copy_by_client() {} + no_copy_by_client() {} + no_copy_by_client (no_copy_by_client const&) {} + no_copy_by_client const& + operator=(no_copy_by_client const&) { return *this; } + }; + + class Goal; + class Resolution; + class QueryResolver; + class QueryDispatcher; + + /** Allow for taking ownership of a result set */ + typedef std::tr1::shared_ptr PReso; + + + + /** + * TODO type comment + * Query ABC + */ + class Goal + : no_copy_by_client + { + public: + virtual ~Goal() ; + + enum Kind + { GENERIC = 0 + , DISCOVERY + }; + + struct QueryID + { + Kind kind; + size_t type; + }; + + QueryID const& + getQID() const + { + return id_; + } + + + /** + * Single Solution, possibly part of a result set. + * A pointer-like object, usually to be down-casted + * to a specifically typed Query::Cursor + * @see Resolution + */ + class Result + : public lib::BoolCheckable + { + void* cur_; + + protected: + void point_at(void* p) { cur_ = p; } + + template + RES& + access() + { + REQUIRE (cur_); + return *reinterpret_cast (cur_); + } + + public: + bool isValid() const { return bool(cur_); } + + Result() : cur_(0) { } ///< create an NIL result + }; + + + + protected: + QueryID id_; + + Goal (QueryID qid) + : id_(qid) + { } + + }; + + + inline bool + operator== (Goal::QueryID const& id1, Goal::QueryID const& id2) + { + return id1.kind == id2.kind + && id1.type == id2.type; + } + + inline bool + operator!= (Goal::QueryID const& id1, Goal::QueryID const& id2) + { + return ! (id1 == id2); + } + + + + /** Context used for generating type-IDs to denote + * the specific result types of issued queries */ + typedef lib::TypedContext ResultType; + + template + inline size_t + getResultTypeID() ///< @return unique ID denoting result type RES + { + return ResultType::ID::get(); + } + + + + + /** + * TODO type comment + * Concrete query to yield specifically typed result elements + */ + template + class Query + : public Goal + { + protected: + static QueryID + defineQueryTypeID (Kind queryType = Goal::GENERIC) + { + QueryID id = {queryType, getResultTypeID() }; + return id; + } + + public: + Query() + : Goal (defineQueryTypeID()) + { } + + + /* results retrieval */ + class Cursor + : public Goal::Result + { + public: + typedef RES value_type; + typedef RES& reference; + typedef RES* pointer; + + RES& operator* () { return access(); } + RES* operator->() { return & access(); } + + void point_at(RES* r){ Goal::Result::point_at(r);} + void point_at(RES& r){ Goal::Result::point_at(&r);} + }; + + + typedef lib::IterAdapter iterator; + + iterator operator() (QueryResolver const& resolver) const; + iterator resolveBy (QueryResolver const& resolver) const; + + + protected: + Query (QueryID qID) + : Goal (qID) + { } + + }; + + + + + + /** + * ABC denoting the result set + * of an individual query resolution + */ + class Resolution + : noncopyable + { + public: + typedef Goal::Result Result; + + virtual ~Resolution(); + + + friend bool + hasNext (PReso const&, Result const& pos) ////TICKET #410 + { + return bool(pos); + } + + friend void + iterNext (PReso& resultSet, Result& pos) + { + resultSet->nextResult(pos); + } + + + virtual Result prepareResolution() =0; + + protected: + + virtual void nextResult(Result& pos) =0; + }; + + + /** + * Interface: a facility for resolving (some) queries + * TODO type comment + */ + class QueryResolver + : noncopyable + { + scoped_ptr dispatcher_; + + + public: + virtual ~QueryResolver() ; + + virtual operator string () const =0; ///< short characterisation of the actual facility + + + /** issue a query to retrieve contents + * The query is handed over internally to a suitable resolver implementation. + * @return concrete Resolution of the query (ResultSet), \em managed by smart-pointer. + * @throw lumiera::Error subclass if query evaluation flounders. + * This might be broken logic, invalid input, misconfiguration + * or failure of an external facility used for resolution. + * @note a query may yield no results, in which case the iterator is empty. + */ + PReso issue (Goal const& query) const; + + bool canHandle (Goal const&) const; + + + + protected: /* ===== API for concrete query resolvers ===== */ + + virtual bool canHandleQuery (Goal::QueryID const&) const =0; + + void installResolutionCase (Goal::QueryID const&, + function); + + QueryResolver(); + }; + + + + + template + inline typename Query::iterator + Query::resolveBy (QueryResolver const& resolver) const + { + PReso resultSet = resolver.issue (*this); + Result first = resultSet->prepareResolution(); + Cursor& start = static_cast (first); // note: type RES must be compatible! + return iterator (resultSet, start); + } + + + /** notational convenience shortcut, + * synonymous to #resolveBy */ + template + inline typename Query::iterator + Query::operator() (QueryResolver const& resolver) const + { + return resolveBy (resolver); + } + + + inline bool + QueryResolver::canHandle(Goal const& query) const + { + return canHandleQuery (query.getQID()); + } + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/root.cpp b/src/proc/mobject/session/root.cpp new file mode 100644 index 000000000..88a631c78 --- /dev/null +++ b/src/proc/mobject/session/root.cpp @@ -0,0 +1,53 @@ +/* + Root - root element of the high-level model, global session scope + + 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 "proc/mobject/session/root.hpp" +#include "proc/mobject/session/defsmanager.hpp" + + +namespace mobject { +namespace session { + + /** */ + Root::Root (DefsManager& dM) + : defaults_(dM) + { } + + + + /** @todo validity self-check of the model root + * should do substantial checks; the idea is + * to perform a complete sanity check by delegating + * to the parts. + * @note beware of performance problems here! + */ + bool + Root::isValid() const + { + return true; //////////////////TICKET #447 + } + + /////////////////////////////////TODO more to come..... + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/root.hpp b/src/proc/mobject/session/root.hpp new file mode 100644 index 000000000..b6457bd77 --- /dev/null +++ b/src/proc/mobject/session/root.hpp @@ -0,0 +1,74 @@ +/* + ROOT.hpp - root element of the high-level model, global session scope + + 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. + +*/ + + +#ifndef MOBJECT_SESSION_ROOT_H +#define MOBJECT_SESSION_ROOT_H + +#include "proc/mobject/session/meta.hpp" +#include "proc/mobject/builder/buildertool.hpp" + + +namespace mobject { +namespace session { + + class DefsManager; + + + /** + * High-level model root element, corresponding to + * the global session wide scope. Serves as link to any + * definitions, rules and defaults valid throughout this + * session. Will be created automatically and inserted into + * the PlacementIndex of an empty session; causes the globals + * to be saved/loaded alongside with the model. + * + * @todo WIP-WIP.. Serialisation is postponed, the rules implementation + * is preliminary, the active link to the AssetManager is missing. + * Thus, as of 12/09 this is an empty placeholder and just serves + * as root scope. + */ + class Root : public Meta + { + DefsManager& defaults_; + + ///////////TODO: timespan fields here or already in class Meta?? + ///////////TODO: any idea about the purpose of root's "timespan"?? ///////TICKET #448 + + virtual bool isValid() const; + + public: + Root (DefsManager&); + + DEFINE_PROCESSABLE_BY (builder::BuilderTool); + + }; + + + } // namespace mobject::session + + /** Placement defined to be subclass of Placement */ + template class Placement; + typedef Placement PRoot; + +} // namespace mobject +#endif diff --git a/src/proc/mobject/session/scope-locator.hpp b/src/proc/mobject/session/scope-locator.hpp new file mode 100644 index 000000000..c6c9aba5d --- /dev/null +++ b/src/proc/mobject/session/scope-locator.hpp @@ -0,0 +1,129 @@ +/* + SCOPE-LOCATOR.hpp - management and registration point for the QueryFocus-system + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_SCOPE_LOCATOR_H +#define MOBJECT_SESSION_SCOPE_LOCATOR_H + +#include "proc/mobject/session/scope.hpp" +#include "proc/mobject/session/scope-query.hpp" +#include "proc/mobject/placement.hpp" +#include "lib/singleton.hpp" + +#include + + +namespace mobject { +namespace session { + + using boost::scoped_ptr; + + class QueryFocusStack; + class ScopePath; + + + + /** + * Singleton service establishing a link to relate + * any compound of nested placement scopes to the current session + * and the \em current focus for querying and exploring this structure. + * While it is OK to use this service directly, clients usually would + * prefer to use QueryFocus as a frontend. + * + * ScopeLocator is the access point both to the current query scope location + * (as maintained with the help of the QueryFocusStack) and allows to explore + * the current session data structures (building on a QueryResolver service + * exposed by the session). + * + * @note in its current form (11/09), ScopeLocator is deliberately not threadsafe + */ + class ScopeLocator + { + scoped_ptr focusStack_; + + public: + static lib::Singleton instance; + + ScopePath& currPath(); + ScopePath& pushPath(); + + template + typename ScopeQuery::iterator + explore (Scope); + + template + typename ScopeQuery::iterator + query (Scope); + + template + typename ScopeQuery::iterator + locate (Scope scope); + + ~ScopeLocator(); + + protected: + ScopeLocator(); + + friend class lib::singleton::StaticCreate; + + private: + QueryResolver const& theResolver(); + }; + + + + + /** use the contents-resolving facility exposed by the session + * to enumerate the contents (children) of the given scope + */ + template + inline typename ScopeQuery::iterator + ScopeLocator::explore (Scope scope) + { + return ScopeQuery (theResolver(), scope.getTop(), CHILDREN); + } + + + /** use the contents-resolving facility exposed by the session + * to discover depth-first any object within this scope + */ + template + inline typename ScopeQuery::iterator + ScopeLocator::query (Scope scope) + { + return ScopeQuery (theResolver(), scope.getTop(), CONTENTS); + } + + + /** use the contents-resolving facility exposed by the session + * to discover the path up from the given scope to model root + */ + template + inline typename ScopeQuery::iterator + ScopeLocator::locate (Scope scope) + { + return ScopeQuery (theResolver(), scope.getTop(), PATH); + } + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp new file mode 100644 index 000000000..eb7d14319 --- /dev/null +++ b/src/proc/mobject/session/scope-path.cpp @@ -0,0 +1,288 @@ +/* + ScopePath - logical access path down from Session root + + Copyright (C) Lumiera.org + 2009, 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/logging.h" +#include "proc/mobject/session/scope-path.hpp" +#include "proc/mobject/session/scope-locator.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/mobject.hpp" +#include "lib/util-foreach.hpp" +#include "lib/itertools.hpp" +#include "lib/symbol.hpp" +#include "lib/error.hpp" + +#include +#include + +namespace mobject { +namespace session { + + using std::reverse; + + using std::tr1::bind; + using std::tr1::function; + using std::tr1::placeholders::_1; + using lib::append_all; + using util::and_all; + + using namespace lumiera; + + + LUMIERA_ERROR_DEFINE (EMPTY_SCOPE_PATH, "Placement scope not locatable (empty model path)"); + + + + namespace { // Helpers and shortcuts.... + + /** issue a query to discover the path to root, + * starting with the given scope */ + inline ScopeQuery::iterator + discoverScopePath (Scope const& leaf) + { + return ScopeLocator::instance().locate (leaf); + } + + + void + ___check_notBottom (const ScopePath *path, lib::Literal operation_descr) + { + REQUIRE (path); + if (path->empty()) + throw error::Invalid (operation_descr+" an empty placement scope path" + , LUMIERA_ERROR_EMPTY_SCOPE_PATH); + } + }//(End) helpers + + + + + /** + * Create an \em empty path. + * By default, a scope path just contains + * the root scope of the current session (PlacementIndex). + * @note invoking this function accesses the session and thus + * may cause an empty default session to be created. + */ + ScopePath::ScopePath () + : refcount_(0) + , path_() + { + clear(); + } + + + /** + * When creating a path to a given (leaf) scope, + * the complete sequence of nested scopes leading to + * this special scope is discovered, using the query service + * exposed by the session (through ScopeLocator). + * @note when locating the default (invalid) scope, + * a special empty ScopePath is created + * @throw error::Invalid if the given target scope + * can't be connected to the (implicit) root + */ + ScopePath::ScopePath (Scope const& leaf) + : refcount_(0) + , path_() + { + if (!leaf.isValid()) return; // invalid leaf defines invalid path.... + + append_all (discoverScopePath(leaf), path_); + reverse (path_.begin(), path_.end()); + } + + + ScopePath::~ScopePath() + { + WARN_IF (refcount_, session, "Destroying a scope path frame with ref-count=%lu", refcount_); + } + + + /** constant \em invalid path token. Created by locating an invalid scope */ + const ScopePath ScopePath::INVALID = ScopePath(Scope()); + + + /** a \em valid path consists of more than just the root element. + * @note contrary to this, an \em empty path doesn't even contain a root element + */ + bool + ScopePath::isValid() const + { + return (0 < length()) +#ifndef NDEBUG + && hasValidRoot() +#endif + ; + } + + bool + ScopePath::hasValidRoot() const + { + REQUIRE (0 < length()); + return path_[0] == currModelRoot(); + } + + PlacementMO const& + ScopePath::currModelRoot() const + { + return SessionServiceExploreScope::getScopeRoot(); + } + + + + + + /* == Relations == */ + + Scope const& + ScopePath::getLeaf() const + { + ___check_notBottom (this, "Inspecting"); + return path_.back(); + } + + + /** verify the scope in question is equivalent + * to our leaf scope. Equivalence of scopes means + * they are defined by the same scope top placement, + * i.e. registered with the same Placement-ID. + */ + bool + ScopePath::endsAt(Scope const& aScope) const + { + return aScope == getLeaf(); + } + + + bool + ScopePath::contains (Scope const& aScope) const + { + for (iterator ii = this->begin(); ii; ++ii) + if (aScope == *ii) + return true; + + return false; + } + + + bool + ScopePath::contains (ScopePath const& otherPath) const + { + if ( empty()) return false; + if (!otherPath.isValid()) return true; + if (!isValid()) return false; + + ASSERT (1 < length()); + ASSERT (1 < otherPath.length()); + + for (iterator ii = otherPath.begin(); ii; ++ii) + if (!this->contains (*ii)) + return false; + + return true; + } + + + ScopePath + commonPrefix (ScopePath const& path1, ScopePath const& path2) + { + typedef std::vector::iterator VIter; + ScopePath prefix (ScopePath::INVALID); + uint len = std::min (path1.length(), path2.length()); + for (uint pos = 0; pos + + 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 scope-path.hpp + ** An Object representing a sequence of nested scopes within the Session. + ** MObjects are being attached to the model by Placements, and each Placement + ** is added as belonging \em into another Placement, which defines the Scope + ** of the addition. There is one (abstract) root element, containing the timelines; + ** from there a nested sequence of scopes leads down to each Placement. + ** Ascending this path yields all the scopes to search or query in proper order + ** to be used when resolving some attribute of placement. Placements use visibility + ** rules comparable to visibility of scoped definitions in common programming languages + ** or in cascading style sheets, where a local definition can shadow a global one. + ** In a similar way, properties not defined locally may be resolved by querying + ** up the sequence of nested scopes. + ** + ** A scope path is represented as sequence of scopes, where each Scope is implemented + ** by a PlacementRef pointing to the »scope top«, i.e. the placement in the session + ** constituting this scope. The leaf of this path can be considered the current scope. + ** ScopePath is intended to remember a \em current location within the model, to be + ** used for resolving queries and discovering contents. + ** + ** \par operations and behaviour + ** + ** In addition to some search and query functions, a scope path has the ability to + ** \em navigate to a given target scope, which must be reachable by ascending and + ** descending into the branches of the overall tree or DAG (in the general case). + ** Navigating changes the current path, which usually happens when the current + ** "focus" shifts while operating on the model. + ** + ** - ScopePath can be default constructed, yielding an \em invalid path. + ** - When created with a given target Scope, a connection to the current Session + ** is created behind the scenes to discover the path starting from this target + ** Scope up to model root. This is the core "locating" operation. It may fail. + ** - There is a pre defined \c ScopePath::INVALID token + ** - ScopePaths are intended to be handled by value (as are Scopes and + ** PlacementRefs). They are equality comparable and provide several specialised + ** relation predicates. + ** - all implementations are focused on clarity, not uttermost performance, as + ** the assumption is for paths to be relatively short and path operations to + ** be executed rather in a GUI action triggered context. + ** - the iteration (Lumiera Forward Iterator) yields the path elements in + ** \em ascending order, starting with the leaf element + ** - a path containing just the root element evaluates to \c bool(false) + ** (rationale is that any valid, usable path is below just root). + ** - an empty (nil) path doesn't even contain the root element and + ** may throw on many operations. + ** + ** \par relation to ScopeLocator + ** + ** ScopeLocator holds the QueryFocusStack, which contains ScopePath objects. + ** Each of these stack frames represents the current location for some evaluation + ** context; it is organised as stack to allow intermediate evaluations. Management + ** of these stack frames is automated, with the assistance of ScopePath by + ** incorporating a ref-count. + ** + ** @see scope-path-test.cpp + ** @see Scope + ** @see ScopeLocator + ** + */ + + +#ifndef MOBJECT_SESSION_SCOPE_PATH_H +#define MOBJECT_SESSION_SCOPE_PATH_H + +#include "proc/mobject/session/scope.hpp" +#include "lib/bool-checkable.hpp" +#include "lib/iter-adapter.hpp" +#include "lib/error.hpp" + +#include + + +namespace mobject { +namespace session { + + + LUMIERA_ERROR_DECLARE (EMPTY_SCOPE_PATH); ///< Placement scope not locatable (empty model path) + + + /** + * Sequence of nested scopes within the high-level model. + * Implemented as vector of Scope elements. Providing + * state and relation predicates, and the ability to + * \em navigate the current location, as represented + * by the current leaf element of the path. + * + * Incorporates a ref count to be utilised by ScopeLocator + * and QueryFocus to establish the \em current focus (path). + */ + class ScopePath + : public lib::BoolCheckable + { + size_t refcount_; + std::vector path_; + + typedef vector _VType; + typedef _VType::const_reverse_iterator _VIter; + typedef lib::RangeIter<_VIter> _IterType; + + public: + ~ScopePath (); + ScopePath (); + ScopePath (Scope const& leaf); + + static const ScopePath INVALID; + + /* == state diagnostics == */ + bool isValid() const; + bool empty() const; + size_t size() const; + size_t length() const; + size_t ref_count()const; + ////////////////////////////////////////TICKET #429 : diagnostic output to be added later + + /// Iteration is always ascending from leaf to root + typedef _IterType iterator; + iterator begin() const; + iterator end() const; + + + /* == relations == */ + Scope const& getLeaf() const; + bool endsAt (Scope const&) const; + bool contains (Scope const&) const; + bool contains (ScopePath const&) const; + + friend ScopePath commonPrefix (ScopePath const&, ScopePath const&); + friend bool disjoint (ScopePath const&, ScopePath const&); + + friend bool operator== (ScopePath const&, ScopePath const&); + + friend void intrusive_ptr_add_ref (ScopePath*); + friend void intrusive_ptr_release (ScopePath*); + + + /* == mutations == */ + void clear(); + Scope& moveUp(); + Scope& goRoot(); + void navigate (Scope const&); + + + private: + bool hasValidRoot() const; + PlacementMO const& currModelRoot() const; + void appendScope (Scope const&); + }; + + + + + + + + inline bool + operator== (ScopePath const& path1, ScopePath const& path2) + { + return path1.path_ == path2.path_; + } + + inline bool + operator!= (ScopePath const& path1, ScopePath const& path2) + { + return !(path1 == path2); + } + + + /** management function for boost::intrusive_ptr + * to be picked up by ADL + */ + inline void + intrusive_ptr_add_ref (ScopePath* pathFrame) + { + REQUIRE (pathFrame); + ++(pathFrame->refcount_); + } + + inline void + intrusive_ptr_release (ScopePath* pathFrame) + { + REQUIRE (pathFrame); + if (0 < pathFrame->refcount_) + --(pathFrame->refcount_); + } + + + + inline size_t + ScopePath::ref_count() const + { + return refcount_; + } + + + inline size_t + ScopePath::length() const + { + return path_.size(); + } + + + inline size_t + ScopePath::size() const + { + return path_.size(); + } + + /** an empty path doesn't even contain a root element. + * Many operations throw when invoked on such a path. + * Navigating up from an root path creates an empty path. + */ + inline bool + ScopePath::empty() const + { + return path_.empty(); + } + + + inline ScopePath::iterator + ScopePath::begin() const + { + return iterator (path_.rbegin(), path_.rend()); + } + + inline ScopePath::iterator + ScopePath::end() const + { + return iterator(); + } + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/scope-query.hpp b/src/proc/mobject/session/scope-query.hpp new file mode 100644 index 000000000..9e91fa9fc --- /dev/null +++ b/src/proc/mobject/session/scope-query.hpp @@ -0,0 +1,210 @@ +/* + SCOPE-QUERY.hpp - query to discover the contents of a container-like part of the model + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_SCOPE_QUERY_H +#define MOBJECT_SESSION_SCOPE_QUERY_H + + +#include "proc/mobject/placement.hpp" +#include "proc/mobject/session/query-resolver.hpp" + +#include + + +namespace mobject { +namespace session { + + using std::tr1::bind; + using std::tr1::function; + using std::tr1::placeholders::_1; + + + + /** + * Mix-in ABC, combining a Query for placement-attached objects + * with an embedded result set iterator. Thus, an concrete (derived) + * DiscoveryQuery can be created by the invoking client code, and + * then immediately explored until exhaustion of the result iterator. + */ + template + class DiscoveryQuery + : public Query > + , public Query >::iterator + { + + /// Assignment explicitly disallowed (but copy ctor is ok) + DiscoveryQuery const& operator=(DiscoveryQuery const&); + + protected: + typedef Query > _Query; + typedef typename _Query::iterator _QIter; + + DiscoveryQuery () + : _Query (_Query::defineQueryTypeID (Goal::DISCOVERY)) + , _QIter () + { } + + + typedef PlacementMO const& Pla; + typedef function ContentFilter; + + /** yield an additional filter to be applied + * on the result set. */ + virtual ContentFilter buildContentFilter() const =0; + }; + + + enum ScopeQueryKind + { CONTENTS = 0 ///< discover any contained objects depth-first + , CHILDREN ///< discover the immediate children + , PARENTS ///< discover the enclosing scopes + , PATH ///< discover the path to root + }; + + + /** + * Query a scope to discover it's contents or location. + * This is a special kind of query, wired up such as to enumerate + * the contents or parents of a scope, filtered by a subtype-check. + * For the actual resolution of the elements to discover, this query + * relies on an index like facility (usually Session's PlacementIndex), + * which is abstracted as a QueryResolver, but actually is expected to + * cooperate especially with this Query subclass to retrieve the scope + * to be enumerated and the definition of the actual filter predicate. + * Currently (11/09), there is a special, hard-wired Query-kind-ID + * \c Goal::DISCOVERY to distinguish this special kind of a Query. + * + * Contrary to the usual handling of a generic query, a ScopeQuery + * object holds it's own discovery iterator and thus is completely + * self contained. The query is issued automatically on construction, + * thus the embedded iterator immediately points at the first result. + * Moreover, as any Lumiera Forward Iterator is \c bool checkable, + * a ScopeQuery not yielding any results will evaluate to \c false + * immediately after construction, allowing convenient inline checks. + * The query can be re-issued by the function operator, and the + * embedded result iterator can of course be copied to a bare + * iterator instance, e.g. for passing it on (ScopeQuery + * itself is intended to be used polymorphically and + * thus defined to be not assignable) + */ + template + class ScopeQuery + : public DiscoveryQuery + { + typedef DiscoveryQuery _Par; + typedef typename _Par::_Query _Query; + + + QueryResolver const& index_; + PlacementMO const& startPoint_; + ScopeQueryKind to_discover_; + + public: + typedef typename _Par::ContentFilter ContentFilter; + typedef typename _Query::iterator iterator; + + + ScopeQuery (QueryResolver const& resolver, + PlacementMO const& scope, + ScopeQueryKind direction) + : index_(resolver) + , startPoint_(scope) + , to_discover_(direction) + { + resetResultIteration (_Query::resolveBy(index_)); + } + + + + iterator + operator() () const + { + return _Query::resolveBy (index_); + } + + PlacementMO const& + searchScope () const + { + return startPoint_; + } + + ScopeQueryKind + searchDirection () const + { + return to_discover_; + } + + ContentFilter + contentFilter () const + { + return buildContentFilter(); + } + + + private: + /** the default implementation of the content filtering + * builds on the downcast-function available on each + * Placement instance. By parametrising this function + * with our template parameter MO, we pick out only + * those elements of the scope being subclasses of MO + */ + virtual ContentFilter + buildContentFilter() const + { + return bind (&PlacementMO::isCompatible, _1 ); + } + + void + resetResultIteration (iterator const& newQueryResults) + { + static_cast (*this) = newQueryResults; + } + }; + + + template + struct ContentsQuery + : ScopeQuery + { + ContentsQuery (QueryResolver const& resolver, + PlacementMO const& scope) + : ScopeQuery (resolver,scope, CONTENTS) + { } + + }; + + + template + struct PathQuery + : ScopeQuery + { + PathQuery (QueryResolver const& resolver, + PlacementMO const& scope) + : ScopeQuery (resolver,scope, PARENTS) + { } + + }; + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp new file mode 100644 index 000000000..9dbf81365 --- /dev/null +++ b/src/proc/mobject/session/scope.cpp @@ -0,0 +1,193 @@ +/* + Scope - nested search scope for properties of placement + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/scope.hpp" +#include "proc/mobject/session/scope-locator.hpp" +#include "proc/mobject/session/query-focus-stack.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "proc/mobject/placement.hpp" +//#include "proc/mobject/session/mobjectfactory.hpp" +//#include "proc/asset/track.hpp" + +namespace mobject { +namespace session { + + + LUMIERA_ERROR_DEFINE (INVALID_SCOPE, "Placement scope invalid an not locatable within model"); + + + + /** conversion of a scope top (placement) into a Scope. + * only allowed if the given Placement is actually attached + * to the session, which will be checked by index access */ + Scope::Scope (PlacementMO const& constitutingPlacement) + : anchor_(constitutingPlacement) + { + + } + + + Scope::Scope () + : anchor_() + { + REQUIRE (!anchor_.isValid()); + } + + + Scope::Scope (Scope const& o) + : anchor_(o.anchor_) + { } + + + Scope& + Scope::operator= (Scope const& o) + { + anchor_ = o.anchor_; ////////////////////////////TODO verify correctness + return *this; + } + + + + ScopeLocator::ScopeLocator() + : focusStack_(new QueryFocusStack) + { + TODO ("anything in initialise here?"); + } + + ScopeLocator::~ScopeLocator() { } + + + /** Storage holding the single ScopeLocator instance */ + lib::Singleton ScopeLocator::instance; + + + /** @internal the one (and only) access point + * actually to link the system of Scope and QueryFocus + * to the current session, by delegating resolution + * of contents discovery queries to the PlacementIndex + * managed within the session + */ + QueryResolver const& + ScopeLocator::theResolver() + { + return SessionServiceExploreScope::getResolver(); + } + + + /** establishes the \em current query focus location. + * Relies on the state of the QueryFocusStack. + * If there is no current focus location, a new + * one is created, referring to the root Scope. + * @return the current path corresponding to the + * most recently used QueryFocus, which is + * actually still referred from somewhere. + * @note may cause the QueryFocusStack to pop + * path entries no longer in use. + */ + ScopePath& + ScopeLocator::currPath() + { + return focusStack_->top(); + } + + + /** push aside the current focus location + * and open a new ScopePath frame, to serve + * as \em current location until released + */ + ScopePath& + ScopeLocator::pushPath() + { + return focusStack_->push (SessionServiceExploreScope::getScopeRoot()); + } + + + + /** discover the enclosing scope of a given Placement */ + Scope const& + Scope::containing (PlacementMO const& aPlacement) + { + UNIMPLEMENTED ("scope discovery"); + } + + + Scope const& + Scope::containing (RefPlacement const& refPlacement) + { + return containing (*refPlacement); + } + + + PlacementMO& + Scope::getTop() const + { + ASSERT (anchor_); + return *anchor_; + } + + + /** retrieve the parent scope which encloses this scope. + * @throw error::Invalid if this is the root scope + */ + Scope const& + Scope::getParent() const + { + UNIMPLEMENTED ("retrieve the enclosing parent scope"); + } + + + /** @return true if this is the outmost (root) scope */ + bool + Scope::isRoot() const + { + UNIMPLEMENTED ("detection of root scope"); + } + + + /** check if this scope can be located. + * An default constructed Scope (i.e without + * defining Placement) can't be located and returns false here */ + bool + Scope::isValid() const + { + return anchor_.isValid(); + } + + + /** enumerate the path of nested scopes up to root scope. + * @return an iterator which starts with this scope and + * successively yields outer scopes, stopping at root. + */ + Scope::IterType_ + Scope::ascend() const + { + UNIMPLEMENTED ("ascend scope hierarchy up to root"); + } + + + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp new file mode 100644 index 000000000..7dbc3ee00 --- /dev/null +++ b/src/proc/mobject/session/scope.hpp @@ -0,0 +1,112 @@ +/* + SCOPE.hpp - nested search scope for properties of placement + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_SCOPE_H +#define MOBJECT_SESSION_SCOPE_H + +//#include "proc/mobject/mobject.hpp" +#include "proc/mobject/placement.hpp" +#include "proc/mobject/placement-ref.hpp" +//#include "proc/mobject/session/query-resolver.hpp" ///////////TODO: really? +#include "lib/iter-adapter.hpp" +#include "lib/error.hpp" +//#include "lib/singleton.hpp" + +//#include +//#include +//#include +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + using lib::IterAdapter; + + LUMIERA_ERROR_DECLARE (INVALID_SCOPE); ///< Placement scope invalid an not locatable within model + + + + /** + * TODO type comment + * @note Scope is a passive entity, + * basically just wrapping up a Scope-top Placement. + * Contrast this to QueryFocus, which actively + * maintains the current focus location. + */ + class Scope + { + RefPlacement anchor_; + + typedef IterAdapter IterType_; + + public: + Scope (PlacementMO const& constitutingPlacement); + Scope (); ///< unlocated NIL scope + + Scope (Scope const&); + Scope& operator= (Scope const&); + + static Scope const& containing (PlacementMO const& aPlacement); //////////////TODO really returning a const& here?? + static Scope const& containing (RefPlacement const& refPlacement); + + Scope const& getParent() const; + PlacementMO& getTop() const; + bool isValid() const; + bool isRoot() const; + + typedef IterType_ iterator; + iterator ascend() const; + + friend bool operator== (Scope const&, Scope const&); + friend bool operator!= (Scope const&, Scope const&); + }; + + +///////////////////////////TODO currently just fleshing the API + + + /** as scopes are constituted by a "scope top" element (placement) + * registered within the PlacementIndex of the current session, + * equality is defined in terms of this defining placement. + */ + inline bool + operator== (Scope const& scope1, Scope const& scope2) + { + return scope1.anchor_ == scope2.anchor_; + } + + inline bool + operator!= (Scope const& scope1, Scope const& scope2) + { + return scope1.anchor_ != scope2.anchor_; + } + + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/sequence.cpp b/src/proc/mobject/session/sequence.cpp new file mode 100644 index 000000000..8717c5bf9 --- /dev/null +++ b/src/proc/mobject/session/sequence.cpp @@ -0,0 +1,48 @@ +/* + Sequence - Compound of MObjects placed on a track tree. Building block of the Session + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/sequence.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "proc/mobject/placement.hpp" +//#include "proc/mobject/session/mobjectfactory.hpp" +//#include "proc/asset/track.hpp" + +namespace mobject { +namespace session { + + + + /** create an empty default configured Sequence */ + Sequence::Sequence () +// : track (makeDefaultTrack ()) +// , clips (0) + { + + } + + + + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/sequence.hpp b/src/proc/mobject/session/sequence.hpp new file mode 100644 index 000000000..038bbcb60 --- /dev/null +++ b/src/proc/mobject/session/sequence.hpp @@ -0,0 +1,55 @@ +/* + SEQUENCE.hpp - Compound of MObjects placed on a track tree. Building block of the Session + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_SEQUENCE_H +#define MOBJECT_SESSION_SEQUENCE_H + +//#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/placement.hpp" + +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + + + /** + * TODO type comment + */ + class Sequence + { + + public: + Sequence(); + + }; +///////////////////////////TODO currently just fleshing the API + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/sess-manager-impl.cpp b/src/proc/mobject/session/sess-manager-impl.cpp index 4428e587d..ffaedf750 100644 --- a/src/proc/mobject/session/sess-manager-impl.cpp +++ b/src/proc/mobject/session/sess-manager-impl.cpp @@ -37,7 +37,7 @@ #include "proc/mobject/session.hpp" -#include "proc/mobject/session/session-impl.hpp" +#include "proc/mobject/session/sess-manager-impl.hpp" #include "proc/mobject/session/defsmanager.hpp" //#include "proc/mobject/session/defsregistry.hpp" #include "lib/error.hpp" @@ -59,7 +59,7 @@ namespace session { * @note any exceptions arising while building the basic * session object(s) will halt the system. */ - SessionImpl* + SessionImplAPI* SessManagerImpl::operator-> () throw() { if (!pImpl_) @@ -87,11 +87,19 @@ namespace session { * \link #operator-> access \endlink to the session object. */ SessManagerImpl::SessManagerImpl () throw() - : pDefs_ (0), - pImpl_ (0) - { } + : pImpl_ (0) + { + Session::initFlag = true; //////////////////////////////////////// TICKET #518 instead of this hack, implement basic-init of the session manager for real + } + + bool + SessManagerImpl::isUp () + { + return bool(pImpl_); + } + /** @note no transactional behaviour. * may succeed partial. */ @@ -111,14 +119,12 @@ namespace session { void SessManagerImpl::reset () { - scoped_ptr tmpD (new DefsManager); - scoped_ptr tmpS (new SessionImpl (*tmpD)); + scoped_ptr tmpS (new SessionImplAPI); TODO ("reset the assets registered with AssetManager"); - // Ichthyo-intern: ticket #95 + /////////////////////////////////////////////////////////////////// TICKET #154 TODO ("thread lock"); - pDefs_.swap (tmpD); pImpl_.swap (tmpS); } @@ -145,12 +151,5 @@ namespace session { } - shared_ptr& - SessManagerImpl::getCurrentIndex () - { - return static_cast (Session::current).pImpl_->pIdx_; - } - - }} // namespace mobject::session diff --git a/src/proc/mobject/session/sess-manager-impl.hpp b/src/proc/mobject/session/sess-manager-impl.hpp new file mode 100644 index 000000000..5a07d5ec1 --- /dev/null +++ b/src/proc/mobject/session/sess-manager-impl.hpp @@ -0,0 +1,67 @@ +/* + SESS-MANAGER-IMPL.hpp - global session access and lifecycle + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_SESS_MANAGER_IMPL_H +#define MOBJECT_SESSION_SESS_MANAGER_IMPL_H + +#include "proc/mobject/session/session-impl.hpp" + + +namespace mobject { +namespace session { + + + + /** + * Session manager implementation class holding the + * actual smart pointer to the current Session impl. + */ + class SessManagerImpl : public SessManager + { + scoped_ptr pImpl_; + + SessManagerImpl() throw(); + friend class lib::singleton::StaticCreate; + + virtual ~SessManagerImpl() {} + + /* ==== SessManager API ==== */ + virtual void clear () ; + virtual void reset () ; + virtual void load () ; + virtual void save () ; + + virtual bool isUp () ; + + + public: + /* ==== proc layer internal API ==== */ + + virtual SessionImplAPI* operator-> () throw() ; + + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-impl.cpp b/src/proc/mobject/session/session-impl.cpp index d870e46a9..526698ea9 100644 --- a/src/proc/mobject/session/session-impl.cpp +++ b/src/proc/mobject/session/session-impl.cpp @@ -22,24 +22,41 @@ #include "proc/mobject/session/session-impl.hpp" +#include "proc/mobject/session/mobjectfactory.hpp" #include "proc/mobject/placement.hpp" +#include "proc/mobject/mobject.hpp" #include "lib/error.hpp" namespace mobject { namespace session { + /////////////////////////////////////////TODO temporary hack: use Meyer's singleton + namespace { + DefsManager& + getDummyDefaultsManager() + { + static scoped_ptr dummyInstance(0); + if (!dummyInstance) dummyInstance.reset (new DefsManager); + + return *dummyInstance; + } + } + /////////////////////////////////////////TODO temporary hack + + /** create a new empty session with default values. * @note any exception arising while creating this * default session will inevitably halt the * system (and this is desirable) */ - SessionImpl::SessionImpl (DefsManager& defs) throw() - : Session(defs), - focusEDL_(0), - edls(1), - fixture(new Fixture), - pIdx_(PlacementIndex::create()) + SessionImpl::SessionImpl () + : Session( getDummyDefaultsManager() ) ///////TODO temporary hack + , pIdx_( MObject::create (getDummyDefaultsManager())) ////TODO temporary hack + , focusEDL_(0) + , edls() /////////// this is dummy code. How to initialise the default session? ///////TICKET #497 + , fixture(new Fixture) { + INFO (session, "new Session created."); } @@ -53,7 +70,7 @@ namespace session { try { edls.clear(); - edls.resize(1); + edls.resize(1); //////////////////////////////////////////////////////////////////////////TICKET #513 focusEDL_ = 0; } catch (...) diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp index 0ddc63381..2c9bb572a 100644 --- a/src/proc/mobject/session/session-impl.hpp +++ b/src/proc/mobject/session/session-impl.hpp @@ -22,13 +22,23 @@ /** @file session-impl.hpp - ** Session and SessionManager Implemention classes. + ** Session and SessionServices Implementation classes. ** Session and the corresponding Manager are primary Interfaces ** to control the behaviour of the editing part of the application. - ** All all implementaion complexities are hidden behind a "PImpl". - ** - ** This file contains the implementation classes, it should never - ** be included by client code. + ** All all implementation complexities are hidden behind a "PImpl". + ** + ** This file contains the implementation level API, it should never + ** be included by client code. Besides the actual SessionImpl, a set + ** of further implementation level services is provided for use by + ** Proc-Layer's internals. These additional SessionServices are to be + ** accessed through dedicated headers and interface classes (typically + ** through static access functions), thereby abstracting from the actual + ** session implementation. Within this file, the implementation of these + ** SessionServices is wired up with the SessionImpl object. + ** + ** @see Session public API + ** @see session-services.hpp + ** @see session-service-access-test.cpp for a complete simplified mock session manager ** */ @@ -39,7 +49,15 @@ #include "proc/mobject/session.hpp" #include "proc/mobject/session/edl.hpp" #include "proc/mobject/session/fixture.hpp" -#include "proc/mobject/placement-index.hpp" +#include "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/session-services.hpp" + +#include "proc/mobject/session/session-service-fetch.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" +#include "proc/mobject/session/session-service-defaults.hpp" + +#include "proc/mobject/session/placement-index-query-resolver.hpp" #include #include @@ -53,17 +71,22 @@ namespace session { using std::vector; using boost::scoped_ptr; using std::tr1::shared_ptr; - + /** * Implementation class for the Session interface */ class SessionImpl : public mobject::Session { + PlacementIndex pIdx_; + uint focusEDL_; - vector edls; + vector edls; /////////////////////TICKET #500 #513 #514 PFix fixture; - shared_ptr pIdx_; + + + scoped_ptr defaultsManager_; ///////////TODO: later, this will be the real defaults manager. Currently this is just never initialised (11/09) + /* ==== Session API ==== */ virtual bool isValid (); @@ -76,45 +99,133 @@ namespace session { virtual void rebuildFixture (); protected: /* == management API === */ - SessionImpl (DefsManager&) throw(); - friend class SessManagerImpl; + SessionImpl (); void clear (); + friend class SessManagerImpl; + + PlacementIndex& + getPlacementIndex() + { + ENSURE (pIdx_.isValid()); + return pIdx_; + } }; - /** - * Session manager implementation class holding the - * actual smart pointer to the current Session impl. - */ - class SessManagerImpl : public SessManager + + /* ===== providing internal services for Proc ===== */ + + template + struct ServiceAccessPoint + : IMPL { - scoped_ptr pDefs_; - scoped_ptr pImpl_; - - SessManagerImpl() throw(); - friend class lib::singleton::StaticCreate; - - virtual ~SessManagerImpl() {} - - /* ==== SessManager API ==== */ - virtual void clear () ; - virtual void reset () ; - virtual void load () ; - virtual void save () ; - virtual SessionImpl* operator-> () throw() ; - - - public: - /* ==== proc layer internal API ==== */ - - /** @internal access point for PlacementIndex and PlacementRef */ - static shared_ptr& getCurrentIndex () ; + bool + isRegisteredID (PMO::ID const& placementID) + { + return IMPL::getPlacementIndex().contains (placementID); //never throws + } + PMO& + resolveID (PMO::ID const& placementID) + { + return IMPL::getPlacementIndex().find (placementID); //may throw + } }; + template + struct ServiceAccessPoint + : IMPL + { + QueryResolver& + getScopeQueryResolver() + { + return resolvingWrapper_; + } + + PlacementMO& + getScopeRoot() + { + return IMPL::getPlacementIndex().getRoot(); + } + + protected: + ServiceAccessPoint() + : resolvingWrapper_(IMPL::getPlacementIndex()) + { } + + private: + PlacementIndexQueryResolver resolvingWrapper_; + }; + + + + template + struct ServiceAccessPoint + : IMPL + { + PlacementIndex& + getPlacementIndex() + { + if (mockIndex_ && mockIndex_->isValid()) + return *mockIndex_; + else + return IMPL::getPlacementIndex(); + } + + void + reset_PlacementIndex (PlacementIndex* alternativeIndex =0) + { + mockIndex_ = alternativeIndex; + } + + protected: + ServiceAccessPoint() + : mockIndex_(0) + { } + + private: + PlacementIndex* mockIndex_; + }; + + + + template + struct ServiceAccessPoint + : IMPL +// , SessionServiceDefaults + { + ////////////////////////////TODO + }; + + + + + + + class SessManagerImpl; + + /** + * actual configuration of the session implementation compound: + * forming an inheritance chain of all internal SesssionServices + * stacked on top of the SessionImpl class. + * @note SessionImplAPI is actually an alias to the global Session PImpl + */ + typedef SessionServices< Types< SessionServiceFetch + , SessionServiceExploreScope + , SessionServiceMockIndex + , SessionServiceDefaults + > // List of the APIs to provide + , SessManagerImpl // frontend for access + , SessionImpl // implementation base class + > // + SessionImplAPI; + + + + }} // namespace mobject::session #endif diff --git a/src/proc/mobject/session/session-service-defaults.hpp b/src/proc/mobject/session/session-service-defaults.hpp new file mode 100644 index 000000000..e97a8409b --- /dev/null +++ b/src/proc/mobject/session/session-service-defaults.hpp @@ -0,0 +1,59 @@ +/* + SESSION-SERVICE-DEFAULTS.hpp - session implementation service API: manage default objects + + 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 session-service-defaults.hpp + ** Implementation level session API: manage default configured objects. + ** + ** @todo rework the existing DefsManager to fit into this scheme. TICKET #404 + ** + ** @see session-impl.hpp implementation of the service + ** @see session-services.cpp implementation of access + ** + */ + + +#ifndef MOBJECT_SESSION_SESSION_SERVICE_DEFAULTS_H +#define MOBJECT_SESSION_SESSION_SERVICE_DEFAULTS_H + +//#include "proc/mobject/session.hpp" +//#include "lib/meta/generator.hpp" + + + + +namespace mobject { +namespace session { + +// using lumiera::typelist::InstantiateChained; +// using lumiera::typelist::InheritFrom; +// using lumiera::typelist::NullType; + + + class SessionServiceDefaults + { + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-service-explore-scope.hpp b/src/proc/mobject/session/session-service-explore-scope.hpp new file mode 100644 index 000000000..a93b08ba3 --- /dev/null +++ b/src/proc/mobject/session/session-service-explore-scope.hpp @@ -0,0 +1,78 @@ +/* + SESSION-SERVICE-EXPLORE-SCOPE.hpp - session implementation service API: explore scope + + 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 session-service-explore-scope.hpp + ** Implementation level session API: query a scope. + ** This specialised service is intended to be used by the Scope and + ** QueryFocus framework for enumerating objects contained within a + ** given scope and for locating the scope's parent scope. Basically, + ** this service just exposes a QueryResolver, which is actually + ** backed by the PlacementIndex and is able to handle queries of + ** type ScopeQuery, especially ContentsQuery and PathQuery. + ** + ** By virtue of this service, QueryFocus, Scope and Placement can + ** remain completely agnostic of session's implementation details, + ** especially they aren't bound to PlacementIndex. This is important, + ** because the public session API is casted in terms of PlacementRef + ** and QueryFocus. An implementation of this service is available + ** through the SessionServices access mechanism. + ** + ** @see session-impl.hpp implementation of the service + ** @see session-services.cpp implementation of access + ** + */ + + +#ifndef MOBJECT_SESSION_SESSION_SERVICE_EXPLORE_SCOPE_H +#define MOBJECT_SESSION_SESSION_SERVICE_EXPLORE_SCOPE_H + +#include "proc/mobject/placement.hpp" +#include "proc/mobject/session/query-resolver.hpp" + + + + +namespace mobject { +namespace session { + + + + /** + * Implementation-level service for issuing contents/discovery queries. + * Actually, the implementation of this service is backed by the PlacementIndex + * within the current session, but this link isn't disclosed to client code. + * The exposed QueryResolver is able to handle typed DiscoveryQuery instances. + * Usually, on invocation, a search scope needs to be specified. The root Scope + * of the current model (session datastructure) can be obtained by #getScopeRoot + */ + struct SessionServiceExploreScope + { + static QueryResolver const& getResolver(); + + static PlacementMO& getScopeRoot(); + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-service-fetch.hpp b/src/proc/mobject/session/session-service-fetch.hpp new file mode 100644 index 000000000..50f62c7c5 --- /dev/null +++ b/src/proc/mobject/session/session-service-fetch.hpp @@ -0,0 +1,73 @@ +/* + SESSION-SERVICE-FETCH.hpp - session implementation service API: fetch PlacementRef + + 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 session-service-fetch.hpp + ** Implementation level session API: resolve a Placement by hash-ID. + ** This specialised service is intended to be used by PlacementRef, + ** in order to (re)-access the Placement instance within the session, + ** given the hash-ID of this placement. An implementation of this + ** service is available through the SessionServices access mechanism. + ** + ** @see session-impl.hpp implementation of the service + ** @see session-services.cpp implementation of access + ** + */ + + +#ifndef MOBJECT_SESSION_SESSION_SERVICE_FETCH_H +#define MOBJECT_SESSION_SESSION_SERVICE_FETCH_H + +//#include "proc/mobject/session.hpp" +//#include "lib/meta/generator.hpp" +#include "proc/mobject/placement.hpp" + + + + +namespace mobject { +namespace session { + +// using lumiera::typelist::InstantiateChained; +// using lumiera::typelist::InheritFrom; +// using lumiera::typelist::NullType; + + /** + * Implementation-level service for resolving an Placement-ID. + * Usually, this service is backed by the PlacementIndex of the + * current session -- however, for the purpose of unit testing, + * this index may be overlaid temporarily, by using the + * SessionServiceMockIndex API. + */ + class SessionServiceFetch + { + public: + static PlacementMO& resolveID (PlacementMO::ID const&) ; + static bool isRegisteredID (PlacementMO::ID const&) ; + + static bool isAccessible() ; + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-service-mock-index.hpp b/src/proc/mobject/session/session-service-mock-index.hpp new file mode 100644 index 000000000..4389a80f6 --- /dev/null +++ b/src/proc/mobject/session/session-service-mock-index.hpp @@ -0,0 +1,78 @@ +/* + SESSION-SERVICE-MOCK-INDEX.hpp - session service API: mock PlacementIndex for tests + + 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 session-service-mock-index.hpp + ** Implementation level session API: PlacementIndex mock for tests. + ** Allows (temporarily) to replace the real Placement index within + ** the session by a mock instance installed and provided through + ** this API. Unit tests may use this \em backdoor to set up a + ** specially prepared index to verify the behaviour of Placement + ** and Scope resolution operations. + ** + ** The test/mock instance of the placement index obtained by this API + ** is \em not wired with the session. Rather it is managed by smart-ptr. + ** When the last smart-ptr instance goes out of scope, the test index + ** instance will be shut down and removed, thereby uncovering the + ** original PlacementIndex living within the session. + ** + ** @see session-impl.hpp implementation of the service + ** @see session-services.cpp implementation of access + ** + */ + + +#ifndef MOBJECT_SESSION_SESSION_SERVICE_MOCK_INDEX_H +#define MOBJECT_SESSION_SESSION_SERVICE_MOCK_INDEX_H + +#include "proc/mobject/session/placement-index.hpp" + +#include + + + + +namespace mobject { +namespace session { + + typedef std::tr1::shared_ptr PPIdx; + + + /** there is an implicit PlacementIndex available on a global level, + * by default implemented within the current session. This Service + * temporarily overlays a newly created mock instance, e.g. for tests. + * @return smart-ptr managing a newly created mock index instance. + * Any implicit access to the session's placement index will + * be redirected to that instance. When the smart-ptr reaches + * use-count zero, access to the original PlacementIndex + * will be restored. + */ + class SessionServiceMockIndex + { + public: + static PPIdx install (); + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp new file mode 100644 index 000000000..ba6fc861c --- /dev/null +++ b/src/proc/mobject/session/session-services.cpp @@ -0,0 +1,125 @@ +/* + SessionServices - accessing Proc-Layer internal session implementation services + + 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 "proc/mobject/session/session-service-fetch.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" +#include "proc/mobject/session/session-service-defaults.hpp" + +#include "proc/mobject/session/session-services.hpp" +#include "proc/mobject/session/session-impl.hpp" +#include "proc/mobject/session/sess-manager-impl.hpp" + +#include "proc/mobject/session/mobjectfactory.hpp" +#include "lib/symbol.hpp" + +using lib::Symbol; + +namespace mobject { +namespace session { + + /** is the element-fetch service usable? + * Effectively this means: is the session up? + */ + bool + SessionServiceFetch::isAccessible () + { + return Session::initFlag + && Session::current.isUp(); + } + + /** verify the given placement-ID (hash) is valid, + * by checking if it refers to a Placement instance + * currently registered with the PlacementIndex of the + * active Session. */ + bool + SessionServiceFetch::isRegisteredID (PlacementMO::ID const& placementID) + { + return SessionImplAPI::current->isRegisteredID (placementID); + } + + + /** actually retrieve a Placement tracked by the index. + * @param placementID hash-ID, typically from a PlacementRef + * @throw error::Invalid if the ID isn't resolvable + * @note the returned ref is guaranteed to be valid and usable + * only \em now, which means, by virtue of the ProcDispatcher + * and command processing, during this operation. It can be + * used to invoke an operation, but should never be stored; + * rather, client code should create an MObjectRef, if + * bound to store an reference for later. + */ + PlacementMO& + SessionServiceFetch::resolveID (PlacementMO::ID const& placementID) + { + return SessionImplAPI::current->resolveID (placementID); + } + + + namespace { // deleter function to clean up test/mock PlacementIndex + void + remove_testIndex (PlacementIndex* testIdx) + { + REQUIRE (testIdx); + SessionImplAPI::current->reset_PlacementIndex(); // restore default Index from Session + + testIdx->clear(); + ASSERT (0 == testIdx->size()); + delete testIdx; + } + } + + /** Re-define the implicit PlacementIndex temporarily, e.g. for unit tests. */ + PPIdx + SessionServiceMockIndex:: install () + { + Symbol typeID ("dummyRoot"); + PMO dummyRoot (MObject::create (typeID)); + PPIdx mockIndex (new PlacementIndex(dummyRoot), &remove_testIndex); // manage instance lifecycle + ENSURE (mockIndex); + ENSURE (mockIndex->isValid()); + ENSURE (1 == mockIndex.use_count()); + + SessionImplAPI::current->reset_PlacementIndex (mockIndex.get()); + return mockIndex; + } + + + /** @return resolver for DiscoveryQuery instances, actually backed by PlacementIndex */ + QueryResolver const& + SessionServiceExploreScope::getResolver() + { + return SessionImplAPI::current->getScopeQueryResolver(); + } + + + /** @return root scope of the current model (session datastructure) */ + PlacementMO& + SessionServiceExploreScope::getScopeRoot() + { + return SessionImplAPI::current->getScopeRoot(); + } + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/session-services.hpp b/src/proc/mobject/session/session-services.hpp new file mode 100644 index 000000000..889f70cbd --- /dev/null +++ b/src/proc/mobject/session/session-services.hpp @@ -0,0 +1,140 @@ +/* + SESSION-SERVICES.hpp - accessing Proc-Layer internal session implementation services + + 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 session-services.hpp + ** A mechanism for exposing and accessing implementation level + ** services of the session. While any client code should always + ** use the public Session API, some implementation level facilities + ** within Proc-Layer need to cooperate with a wider SessionImpl API. + ** On the other hand, we don't want to create coupling between the + ** mentioned Proc internals and the session implementation. Another + ** concern addressed by this mechanism is to assure consistency + ** across all those implementation APIs. New APIs can be added + ** just by extending a template definition and will automatically + ** participate in the session management mechanisms, because any + ** access is routed through the top level Session PImpl. + ** + ** \par structure of session implementation-level services + ** + ** Assumed any part of the Proc implementation needs to cooperate + ** with the session implementation; the necessary link has to be + ** abstracted into an implementation level API. Typically, this + ** API provides an static access function, which is to be implemented + ** "somewhere else", so the Proc implementation isn't required to + ** include anything of the session implementation level + ** + ** In order to actually provide such a service, an specialisation of + ** the ServiceAccessPoint template has to be defined, which may mix in + ** the service API and implement it directly on top of SessionImpl. + ** Note, mixing in the API isn't required -- alternatively the API might + ** be completely bridged through the mentioned static access functions + ** (i.e. such would be kind of an generic API, relying on convention + ** rather than on a vtable) + ** + ** When the SessManagerImpl creates the concrete session object, + ** it doesn't use the bare SessionImpl class; rather, an inheritance + ** chain is formed, starting with SessionImpl and stacking any of the + ** configured ServiceAccessPoint instantiations on top of it. Thus, + ** the public session access gets the concrete implementation of the + ** Session API (through the vtable), while any service level access + ** can use the corresponding service API directly. Service APIs have + ** to care to avoid name clashes though. + ** + ** The implementation of all the service API access functions is + ** bundled within session-service.cpp -- where the full compound + ** of SessionImpl and the ServiceAccessPoint specialisations has + ** to be visible. + ** + ** @see session-service-access-test.cpp simplified inline demo definition of this setup + ** @see session.hpp public session API + ** @see session-impl.hpp definition of ServiceAccessPoint specialisations + ** @see session-impl.cpp session implementation internals + ** + */ + + +#ifndef MOBJECT_SESSION_SESSION_SERVICES_H +#define MOBJECT_SESSION_SESSION_SERVICES_H + +#include "proc/mobject/session.hpp" +#include "lib/meta/generator.hpp" + + + + +namespace mobject { +namespace session { + + using lumiera::typelist::InstantiateChained; + using lumiera::typelist::Types; + + + /** + * Access point to a single implementation-level API. + * For each concrete service to provide, an specialisation + * of this template is assumed to exist which inherits from + * IMPL; it will be used in an inheritance-chain on top of + * SessionImpl and thus can access the latter (= session + * implementation API) just through its parent class IMPL + */ + template + struct ServiceAccessPoint; + + + /** + * Collection of configured implementation-level services + * to provide by the Session. An instance of this template + * is created on top of SessionImpl, configured such as + * to inherit from all the concrete services to be + * exposed for use by Proc-Lyer's internals. + * + * @param APIS sequence of API types to implement + * @param FRONT type of the frontend used for access + * @param SESS the basic session implementation + */ + template< typename APIS + , class FRONT + , class SESS + > + class SessionServices + : public InstantiateChained< typename APIS::List // for each of the API types... + , ServiceAccessPoint // instantiate a service implementation + , SESS // and stack all these on top of SessionImpl + > + { + public: + static FRONT& current; ///< intended to be hard-wired to SessManagerImpl singleton + + /** access an service by explicit downcast. + * @warning this function is dangerous; never store the + * returned reference, as the referred object + * might go away due to session close/reset/load + */ + template + API& get() { return *this; } + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session.cpp b/src/proc/mobject/session/session.cpp index dec115d15..3c344a2e7 100644 --- a/src/proc/mobject/session/session.cpp +++ b/src/proc/mobject/session/session.cpp @@ -34,6 +34,7 @@ #include "proc/mobject/session.hpp" #include "proc/mobject/session/defsmanager.hpp" #include "proc/mobject/session/session-impl.hpp" +#include "proc/mobject/session/sess-manager-impl.hpp" #include "lib/symbol.hpp" #include "lib/singleton.hpp" @@ -43,9 +44,17 @@ using lib::Symbol; using lib::Singleton; using mobject::session::SessManager; using mobject::session::SessManagerImpl; +using mobject::session::SessionImplAPI; namespace mobject { + + /** temporary fix for init problems + * @todo really solve the basic init of session manager TICKET #518 + */ + bool Session::initFlag = false; + + /** the sole access point for all client code to the system-wide * "current session". Implemented as smart pointer to singleton * implementation object, where the smart pointer is actually @@ -53,11 +62,20 @@ namespace mobject { * * Consequently, if you want to talk to the session manager, * you use dot-notation, while you access the session object - * via arrow notaion (e.g. \code Session::current->getFixture() ) + * via arrow notation (e.g. \code Session::current->getFixture() ) */ SessManager& Session::current = Singleton()(); + /** special access point allowing Proc-Layer internals + * to cooperate with session implementation level APIs + */ + template<> + SessManagerImpl& SessionImplAPI::current = static_cast (Session::current); + + + + /** \par * LifecycleHook, to perform all the basic setup for a new session, * prior to adding any specific data, configuration or content. Any subsystems @@ -79,6 +97,17 @@ namespace mobject { */ const char* ON_SESSION_INIT ("ON_SESSION_INIT"); + /** \par + * LifecycleHook, to perform post loading tasks, requiring an already completely usable + * and configured session to be in place. When activated, the session is completely restored + * according to the standard or persisted definition and any access interfaces are already + * opened and enabled. Scripts and the GUI might even be accessing the session in parallel. + * Subsystems intending to perform additional processing should register here, if requiring + * fully functional client side APIs. Examples would be statistics gathering, validation + * or auto-correction of the session's contents. + */ + const char* ON_SESSION_READY ("ON_SESSION_READY"); + /** \par * LifecycleHook, to perform any state saving, deregistration or de-activation necessary * before bringing down an existing session. When invoked, the session is still fully valid @@ -92,12 +121,13 @@ namespace mobject { - Session::~Session () - { } - Session::Session (session::DefsManager& def) throw() : defaults(def) { } + + // Emit the vtables and other magic stuff here... + SessManager::~SessManager() { } + Session::~Session () { } diff --git a/src/proc/mobject/session/timeline.cpp b/src/proc/mobject/session/timeline.cpp new file mode 100644 index 000000000..458220993 --- /dev/null +++ b/src/proc/mobject/session/timeline.cpp @@ -0,0 +1,48 @@ +/* + Timeline - independent top-level element of the Session + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/timeline.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "proc/mobject/placement.hpp" +//#include "proc/mobject/session/mobjectfactory.hpp" +//#include "proc/asset/track.hpp" + +namespace mobject { +namespace session { + + + + /** TODO??? */ + Timeline::Timeline () +// : track (makeDefaultTrack ()) +// , clips (0) + { + + } + + + + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/timeline.hpp b/src/proc/mobject/session/timeline.hpp new file mode 100644 index 000000000..03f666a25 --- /dev/null +++ b/src/proc/mobject/session/timeline.hpp @@ -0,0 +1,55 @@ +/* + TIMELINE.hpp - independent top-level element of the Session + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_TIMELINE_H +#define MOBJECT_SESSION_TIMELINE_H + +//#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/placement.hpp" + +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + + + /** + * TODO type comment + */ + class Timeline + { + + public: + Timeline(); + + }; +///////////////////////////TODO currently just fleshing the API + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/track.hpp b/src/proc/mobject/session/track.hpp index 5a9166a31..7b3222bdb 100644 --- a/src/proc/mobject/session/track.hpp +++ b/src/proc/mobject/session/track.hpp @@ -72,7 +72,9 @@ namespace session { public: /** Child tracks in a tree structure */ - vector > subTracks; ////TODO: it should really work with Placements! this here is just a decoy!!!!!!! + vector > subTracks; ///////////TODO: it should really work with PlacementRefs! this here is just a decoy!!!!!!! +/////////////////////////////////////////////////////////TICKET #513 + virtual bool isValid() const; }; diff --git a/src/tool/try.cpp b/src/tool/try.cpp index de206c43e..af6b66ae1 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -13,71 +13,89 @@ // 7/08 - combining partial specialisation and subclasses // 10/8 - abusing the STL containers to hold noncopyable values // 6/09 - investigating how to build a mixin template providing an operator bool() +// 12/9 - tracking down a strange "warning: type qualifiers ignored on function return type" +// 1/10 - can we determine at compile time the presence of a certain function (for duck-typing)? -#include -#define LUMIERA_LOGGING_CXX -#include "include/logging.h" +//#include +//#define LUMIERA_LOGGING_CXX +//#include "include/logging.h" //#include "include/nobugcfg.h" -#include "lib/bool-checkable.hpp" + #include //#include -#include +#include #include #include -using std::rand; +//using std::rand; using std::string; using std::cout; -using boost::format; +using std::endl; - namespace { - boost::format fmt ("<%2i>"); - long checksum = 0; - } - - struct TestIt1 - : lib::BoolCheckable +struct A + { + int& funA (); + }; + +struct B + { + void funA(); + }; + + + typedef char Yes_t; + struct No_t { char padding[8]; }; + + + template + class Detector1 { + template + struct Probe + { }; - int val_; - - TestIt1 (int v = (rand() % 10)) - : val_(v) - { } - - bool - isValid() const - { - return val_ % 2; - } + template + static Yes_t check(Probe*); + template + static No_t check(...); + public: + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); + }; + + + template + class Detector2 + { + template + struct Probe + { }; + + template + static Yes_t check(Probe*); + template + static No_t check(...); + + public: + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); }; - int -main (int, char**) //(int argc, char* argv[]) +main (int, char**) { - NOBUG_INIT; +// NOBUG_INIT; - for (int i=0; i<10; ++i) - { - TestIt1 testrosteron (i); - - if (testrosteron) - cout << "doIt \n"; - if (!testrosteron) - cout << i << "\n"; - } - cout << "size=" << sizeof(TestIt1) <<"\n"; + cout << "Detector1 = " << Detector1::value << endl; + cout << "Detector1 = " << Detector1::value << endl; - char* horror = 0; - ERROR (all, "note: %s is a horrible thing", horror); + cout << "Detector2 = " << Detector2::value << endl; + cout << "Detector2 = " << Detector2::value << endl; cout << "\n.gulp.\n"; diff --git a/tests/40components.tests b/tests/40components.tests index 7475363bd..89a3a791c 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -182,6 +182,17 @@ return: 0 END +TEST "Duck typing support" DuckDetector_test < : Yes +out: HasNested_Core : No +out: HasMember_honk : Yes +out: HasMember_honk : Yes +out: HasFunSig_honk : Yes +out: HasFunSig_honk : No +return: 0 +END + + TEST "ExceptionError_test" ExceptionError_test < : Yes +out: can_STL_ForEach : Yes +out: can_STL_ForEach : Yes +out: can_STL_ForEach : Yes +out: can_STL_ForEach : Yes +out: can_STL_ForEach : Yes +out: can_STL_ForEach : No +out: can_STL_ForEach : No +out: can_STL_ForEach : No +out: can_STL_ForEach : No +out: can_IterForEach : No +out: can_IterForEach : No +out: can_IterForEach : No +out: can_IterForEach : No +out: can_IterForEach : No +out: can_IterForEach : No +out: can_IterForEach : Yes +out: can_IterForEach : Yes +out: can_IterForEach : Yes +out: can_IterForEach : Yes +END + + PLANNED "RefArray_test" RefArray_test < > out: ctor DoIt > out: ctor DoIt > out: ctor DoIt > -out: Block< 2>::eat\(..\) -out: Block< 5>::eat\(..\) -out: Block<13>::eat\(..\) +out: devouring__Block< 2>__ +out: devouring__Block< 5>__ +out: devouring__Block<13>__ out: gulp! out: dtor DoIt > out: dtor DoIt > @@ -863,11 +937,116 @@ return: 0 END -PLANNED "extensible symbolic identifier" SubID_test < #include diff --git a/tests/components/proc/asset/asset-diagnostics.hpp b/tests/components/proc/asset/asset-diagnostics.hpp index 2ae2a232f..856f131b3 100644 --- a/tests/components/proc/asset/asset-diagnostics.hpp +++ b/tests/components/proc/asset/asset-diagnostics.hpp @@ -34,6 +34,7 @@ #include "proc/assetmanager.hpp" +#include "lib/util-foreach.hpp" #include "lib/util.hpp" #include diff --git a/tests/components/proc/control/command-argument-test.cpp b/tests/components/proc/control/command-argument-test.cpp index 2b9368bd3..bdf7b2724 100644 --- a/tests/components/proc/control/command-argument-test.cpp +++ b/tests/components/proc/control/command-argument-test.cpp @@ -27,6 +27,7 @@ #include "lib/scoped-ptrvect.hpp" #include "lib/lumitime-fmt.hpp" #include "lib/meta/tuple.hpp" +#include "lib/util-foreach.hpp" #include "lib/util.hpp" #include diff --git a/tests/components/proc/control/handling-pattern-standard-impl-test.cpp b/tests/components/proc/control/handling-pattern-standard-impl-test.cpp index f9fdf0058..a83eed6d7 100644 --- a/tests/components/proc/control/handling-pattern-standard-impl-test.cpp +++ b/tests/components/proc/control/handling-pattern-standard-impl-test.cpp @@ -30,7 +30,7 @@ //#include "proc/mobject/test-dummy-mobject.hpp" //#include "lib/p.hpp" //#include "proc/mobject/placement.hpp" -//#include "proc/mobject/placement-index.hpp" +//#include "proc/mobject/session/placement-index.hpp" //#include "proc/mobject/explicitplacement.hpp" #include "proc/control/command.hpp" #include "proc/control/command-impl.hpp" diff --git a/tests/components/proc/mobject/mobject-ref-test.cpp b/tests/components/proc/mobject/mobject-ref-test.cpp index fad045ab4..158de4395 100644 --- a/tests/components/proc/mobject/mobject-ref-test.cpp +++ b/tests/components/proc/mobject/mobject-ref-test.cpp @@ -28,7 +28,8 @@ #include "proc/mobject/mobject-ref.hpp" #include "proc/mobject/placement.hpp" #include "proc/mobject/placement-ref.hpp" -#include "proc/mobject/placement-index.hpp" +#include "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" #include "proc/mobject/session/clip.hpp" #include "proc/mobject/explicitplacement.hpp" #include "proc/mobject/test-dummy-mobject.hpp" @@ -46,6 +47,9 @@ namespace test { using lumiera::Time; using session::Clip; + + using session::SessionServiceMockIndex; + /*************************************************************************** @@ -84,12 +88,10 @@ namespace test { ASSERT (2 == pClip2.use_count()); -#if 0 /////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! // Prepare an (test)Index - typedef shared_ptr PIdx; - PIdx index (PlacementIndex::create()); + PPIdx index = SessionServiceMockIndex::install(); PMO& root = index->getRoot(); - reset_PlacementIndex(index); // Add the Clips to "session" index->insert (pClip1, root); @@ -125,10 +127,12 @@ namespace test { index->remove (pClip1); index->remove (pClip2); ASSERT (0 == index->size()); + ASSERT (1 == index.use_count()); ASSERT (2 == pClip1.use_count()); ASSERT (2 == pClip2.use_count()); + index.reset(); #endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! - reset_PlacementIndex(); + } @@ -136,7 +140,7 @@ namespace test { void checkBuildMObjectRef (REF refObj, void* placementAdr) { -#if 0 /////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! MORef rMO; ASSERT (!rMO); // still empty (not bound) cout << rMO << endl; @@ -177,7 +181,7 @@ namespace test { void checkLifecylce (PMObj const& p1, PMObj const& p2) { -#if 0 /////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! ASSERT (2 == p1.use_count()); ASSERT (2 == p2.use_count()); @@ -215,7 +219,7 @@ namespace test { void checkTypeHandling (LumieraUid luid) { -#if 0 /////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! MObjectRef rMObj; MORef rClip; MORef rSub1; diff --git a/tests/components/proc/mobject/placement-basic-test.cpp b/tests/components/proc/mobject/placement-basic-test.cpp index 9725c4bee..21c663b74 100644 --- a/tests/components/proc/mobject/placement-basic-test.cpp +++ b/tests/components/proc/mobject/placement-basic-test.cpp @@ -79,7 +79,7 @@ namespace mobject { ExplicitPlacement expla = pc.resolve(); ASSERT (expla.time == Time(1)); ASSERT (!expla.chain.isOverdetermined()); - //ASSERT (*expla == *pc); ////////////////////////TODO: define equality on placements (Trac #119) +// ASSERT (*expla == *pc); ////////////////////////////////////////////TICKET #511 define equivalence of locating chains and solutions // now overconstraining with another Placement pc.chain(Time(2)); diff --git a/tests/components/proc/mobject/placement-hierarchy-test.cpp b/tests/components/proc/mobject/placement-hierarchy-test.cpp index 5feca7a21..4a2d8514e 100644 --- a/tests/components/proc/mobject/placement-hierarchy-test.cpp +++ b/tests/components/proc/mobject/placement-hierarchy-test.cpp @@ -132,7 +132,7 @@ namespace test { hijacked->specialAPI(); ASSERT (3 == hijacked.use_count()); - ASSERT (hijacked.getID() == pSub3.getID()); + ASSERT (hijacked.getID() == pClip.getID()); cout << format_PlacementID(pSub1) << endl; cout << format_PlacementID(pSub2) << endl; diff --git a/tests/components/proc/mobject/placement-index-test.cpp b/tests/components/proc/mobject/placement-index-test.cpp deleted file mode 100644 index b9b003ede..000000000 --- a/tests/components/proc/mobject/placement-index-test.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - PlacementIndex(Test) - facility keeping track of Placements within the Session - - Copyright (C) Lumiera.org - 2009, 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 "proc/asset/media.hpp" -//#include "proc/mobject/session.hpp" -//#include "proc/mobject/session/edl.hpp" -#include "proc/mobject/session/testclip.hpp" -#include "proc/mobject/placement.hpp" -#include "proc/mobject/placement-index.hpp" -//#include "proc/mobject/explicitplacement.hpp" -//#include "lib/util.hpp" - -//#include -//#include - -//using boost::format; -//using lumiera::Time; -//using util::contains; -using std::string; -//using std::cout; - - -namespace mobject { -namespace test { - - using asset::VIDEO; - using session::test::TestClip; - - - - /*************************************************************************** - * @test basic behaviour of the index mechanism used to keep track of - * individual Placements as added to the current Session.. - * @see mobject::Placement - * @see mobject::MObject#create - * @see mobject::Placement#addPlacement - * @see mobject::Placement#resolve - */ - class PlacementIndex_test : public Test - { - typedef shared_ptr PIdx; - - virtual void - run (Arg) - { - PIdx index (PlacementIndex::create()); - ASSERT (index); - - /////////////////////////////////TODO - checkSimpleInsert (index); - } - - void - checkSimpleInsert (PIdx index) - { - PMO clip = TestClip::create(); - PMO& root = index->getRoot(); - - ASSERT (0 == index->size()); - ASSERT (!index->contains (clip)); - -// index->insert (clip, root); - ASSERT (1 == index->size()); - ASSERT ( index->contains (clip)); - -// index->remove(clip); - ASSERT (0 == index->size()); - ASSERT (!index->contains (clip)); - ASSERT ( index->contains (root)); - } - }; - - - /** Register this test class... */ - LAUNCHER (PlacementIndex_test, "unit session"); - - -}} // namespace mobject::test diff --git a/tests/components/proc/mobject/placement-object-identity-test.cpp b/tests/components/proc/mobject/placement-object-identity-test.cpp new file mode 100644 index 000000000..dad475fb0 --- /dev/null +++ b/tests/components/proc/mobject/placement-object-identity-test.cpp @@ -0,0 +1,159 @@ +/* + PlacementObjectIdentity(Test) - object identity for placements into the session + + Copyright (C) Lumiera.org + 2010, 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/lumitime.hpp" +#include "proc/asset/media.hpp" +#include "proc/mobject/mobject.hpp" +#include "proc/mobject/mobject-ref.hpp" +#include "proc/mobject/placement.hpp" +#include "proc/mobject/placement-ref.hpp" +#include "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" +#include "proc/mobject/session/clip.hpp" +#include "proc/mobject/explicitplacement.hpp" +//#include "proc/mobject/test-dummy-mobject.hpp" +//#include "lib/test/test-helper.hpp" + +//#include +// +//using std::string; +//using std::cout; +//using std::endl; + + +namespace mobject { +namespace test { + + using lumiera::Time; + using session::Clip; + + using session::SessionServiceMockIndex; + + + + /*************************************************************************** + * @test verify correct handling of object identity. Create test objects, + * add placements to a dummy index/session, then create PlacementRef + * and MObjectRef handles. Finally do cross comparisons. + * + * @todo WIP-WIP to be written... TICKET #517 + * + * @see mobject::PlacementRef_test + * @see mobject::MObjectRef_test + */ + class PlacementObjectIdentity_test : public Test + { + + typedef Placement PMObj; + typedef Placement PClip; + + typedef PlacementMO::ID PMObjID; + typedef PlacementMO::Id PClipID; + + + virtual void + run (Arg) + { + + // create data simulating a "Session" + PMObj pClip1 = asset::Media::create("test-1", asset::VIDEO)->createClip(); + PMObj pClip2 = asset::Media::create("test-2", asset::VIDEO)->createClip(); + + // set up a tie to fixed start positions + pClip1.chain(Time(10)); + pClip2.chain(Time(20)); + + ASSERT (pClip1->isValid()); + ASSERT (pClip2->isValid()); + ASSERT (2 == pClip1.use_count()); // one by the placement and one by the clip-Asset + ASSERT (2 == pClip2.use_count()); + + ////////////////TODO direct comparisons + ////////////////TODO direct comparisons + + UNIMPLEMENTED ("verify proper handling of object identity"); + +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 517 !!!!!!!!!!!!!! + // Prepare an (test)Index + PPIdx index = SessionServiceMockIndex::install(); + PMO& root = index->getRoot(); + + // Add the Clips to "session" + PMObjID clip1ID = index->insert (pClip1, root); + PMObjID clip2ID = index->insert (pClip2, root); + + ////////////////TODO compare ids + ////////////////TODO compare ids + + + // extract various kinds of IDs and refs + PMObj & rP1 (pClip1); + PMObj const& rP2 (pClip2); + PMObj::ID id1 = pClip1.getID(); + PMObj::Id id2 = pClip2.getID(); + LumieraUid luid = id1.get(); + + PlacementRef ref1 (id1); + PlacementRef ref2 (pClip2); + + MORef rMO; + ASSERT (!rMO); // still empty (not bound) + + // activate by binding to provided ref + rMO.activate(refObj); + ASSERT (rMO); // now bound + + ///TODO access Placement, fetch ID + + // re-link to the Placement (note we get the Clip API!) + Placement & refP = rMO.getPlacement(); + ASSERT (refP); + ASSERT (3 == refP.use_count()); + ASSERT (&refP == placementAdr); // actually denotes the address of the original Placement in the "session" + + ExplicitPlacement exPla = refP.resolve(); + ASSERT (exPla.time == start); // recovered Placement resolves to the same time as provided by the proxied API + ASSERT (4 == refP.use_count()); // but now we've indeed created an additional owner (exPla) + ASSERT (4 == rMO.use_count()); + + + ////////////////TODO now do the cross comparisons + ////////////////TODO now do the cross comparisons + + + ///clean up... + index.reset(); + +#endif //////////////////////////////////////////////// ////////////////////////////////////////////////////TODO to be written........!!!!! + } + + + }; + + + /** Register this test class... */ + LAUNCHER (PlacementObjectIdentity_test, "function session"); + + +}} // namespace mobject::test diff --git a/tests/components/proc/mobject/placement-ref-test.cpp b/tests/components/proc/mobject/placement-ref-test.cpp index 9bbe17109..14272322e 100644 --- a/tests/components/proc/mobject/placement-ref-test.cpp +++ b/tests/components/proc/mobject/placement-ref-test.cpp @@ -22,12 +22,14 @@ #include "lib/test/run.hpp" -#include "lib/lumitime.hpp" +#include "lib/test/test-helper.hpp" #include "proc/mobject/placement.hpp" #include "proc/mobject/placement-ref.hpp" -#include "proc/mobject/placement-index.hpp" +#include "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" #include "proc/mobject/explicitplacement.hpp" #include "proc/mobject/test-dummy-mobject.hpp" +#include "lib/lumitime.hpp" #include "lib/util.hpp" #include @@ -67,10 +69,8 @@ namespace test { p2.chain(Time(2)); // define start time of Placement-2 to be at t=2 // Prepare an (test)Index backing the PlacementRefs - typedef shared_ptr PIdx; - PIdx index (PlacementIndex::create()); + PPIdx index = SessionServiceMockIndex::install(); PMO& root = index->getRoot(); - reset_PlacementIndex(index); index->insert (p1, root); index->insert (p2, root); @@ -151,15 +151,9 @@ namespace test { // actually, the assignment has invalidated ref1, because of the changed ID ASSERT (p1.getID() == p2.getID()); - try - { - *ref1; - NOTREACHED(); - } - catch (...) - { - ASSERT (lumiera_error () == LUMIERA_ERROR_INVALID_PLACEMENTREF); - } + + VERIFY_ERROR(INVALID_PLACEMENTREF, *ref1 ); + ASSERT (!index->contains(p1)); // index indeed detected the invalid ref ASSERT (3 == ref2.use_count()); // but ref2 is still valid @@ -167,19 +161,19 @@ namespace test { index->remove (ref2); ASSERT (!ref2); // checks invalidity without throwing ASSERT (!refX); - try - { - *ref2; - NOTREACHED(); - } - catch (...) - { - ASSERT (lumiera_error () == LUMIERA_ERROR_INVALID_PLACEMENTREF); - } + VERIFY_ERROR(INVALID_PLACEMENTREF, *ref2 ); + + // deliberately create an invalid PlacementRef + PlacementRef bottom; + ASSERT (!bottom); + VERIFY_ERROR(INVALID_PLACEMENTREF, *bottom ); + VERIFY_ERROR(INVALID_PLACEMENTREF, bottom->specialAPI() ); + VERIFY_ERROR(INVALID_PLACEMENTREF, bottom.resolve() ); //consistency check; then reset PlacementRef index to default ASSERT (0 == index->size()); - reset_PlacementIndex(); + ASSERT (1 == index.use_count()); + index.reset(); } }; diff --git a/tests/components/proc/mobject/session/addcliptest.cpp b/tests/components/proc/mobject/session/addcliptest.cpp index 7d7469448..e3b9f2b36 100644 --- a/tests/components/proc/mobject/session/addcliptest.cpp +++ b/tests/components/proc/mobject/session/addcliptest.cpp @@ -61,8 +61,9 @@ namespace mobject PSess sess = Session::current; PMO clip = TestClip::create(); sess->add (clip); - - ASSERT (sess->currEDL().contains (clip)); + +///////////////////////////////////////////////////////////////////TICKET #499 +// ASSERT (sess->currEDL().contains (clip)); // TODO: Clip-Asset and Placement magic?? } }; diff --git a/tests/components/proc/mobject/session/defsregistryimpltest.cpp b/tests/components/proc/mobject/session/defsregistryimpltest.cpp index 88c804cec..1f76282ed 100644 --- a/tests/components/proc/mobject/session/defsregistryimpltest.cpp +++ b/tests/components/proc/mobject/session/defsregistryimpltest.cpp @@ -182,7 +182,7 @@ namespace mobject { i = reg_->candidates(q3); ASSERT ( *i++ == o3); // found by direct match - ASSERT ( *i++ == o1); // followed by the ordered ennumeration + ASSERT ( *i++ == o1); // followed by the ordered enumeration ASSERT ( *i++ == o2); ASSERT ( *i++ == o3); ASSERT ( *i++ == o3); diff --git a/tests/components/proc/mobject/session/placement-index-query-test.cpp b/tests/components/proc/mobject/session/placement-index-query-test.cpp new file mode 100644 index 000000000..a0728fff2 --- /dev/null +++ b/tests/components/proc/mobject/session/placement-index-query-test.cpp @@ -0,0 +1,116 @@ +/* + PlacementIndexQuery(Test) - querying the placement index through the generic query interface + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/query-resolver.hpp" +#include "proc/mobject/session/scope-query.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/session/placement-index-query-resolver.hpp" +#include "proc/mobject/session/test-scopes.hpp" +#include "lib/util.hpp" + +#include +#include + + + +namespace mobject { +namespace session { +namespace test { + + using session::PathQuery; + using session::ContentsQuery; + using util::isSameObject; + using std::string; + using std::cout; + using std::endl; + + + /**************************************************************************** + * @test accessing the PlacementIndex through the generic query interface, + * for discovering scope contents and containing scope. + * + * @see mobject::session::PlacementIndex + * @see mobject::session::QueryResolver + * @see mobject::session::ContentsQuery + */ + class PlacementIndexQuery_test : public Test + { + + virtual void + run (Arg) + { + checkQueryResolver(); + checkQueryOperations(); + } + + void + checkQueryResolver() + { + PPIdx index = build_testScopes(); + QueryResolver const& resolver1 (SessionServiceExploreScope::getResolver()); + QueryResolver const& resolver2 (SessionServiceExploreScope::getResolver()); + + ASSERT (isSameObject (resolver1, resolver2)); + + PlacementMO& root1 = index->getRoot(); + PlacementMO& root2 = SessionServiceExploreScope::getScopeRoot(); + ASSERT (isSameObject (root1, root2)); + + PlacementMO& elm1 = *ContentsQuery(resolver1,root1); + PlacementMO& elm2 = *(index->getReferrers(root1)); + ASSERT (isSameObject (elm1, elm2)); + } + + void + checkQueryOperations() + { + // Prepare an (test)Index (dummy "session") + PPIdx index = build_testScopes(); + PlacementMO& root = index->getRoot(); + PlacementIndexQueryResolver resolver(*index); + + discover (ContentsQuery (resolver,root)); + + PlacementMO& elm = *ContentsQuery(resolver,root); + + discover (PathQuery (resolver,elm)); + } + + + template + void + discover (IT result) + { + for ( ; result; ++result) + cout << string(*result) << endl; + } + + }; + + + /** Register this test class... */ + LAUNCHER (PlacementIndexQuery_test, "unit session"); + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/placement-index-test.cpp b/tests/components/proc/mobject/session/placement-index-test.cpp new file mode 100644 index 000000000..ad117cdf8 --- /dev/null +++ b/tests/components/proc/mobject/session/placement-index-test.cpp @@ -0,0 +1,264 @@ +/* + PlacementIndex(Test) - facility keeping track of Placements within the Session + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/scope.hpp" +#include "proc/mobject/placement.hpp" +#include "lib/util.hpp" + +#include "proc/mobject/session/testclip.hpp" +#include "proc/mobject/session/testroot.hpp" + +#include +#include + +using boost::format; +using util::isSameObject; +using std::string; +using std::cout; +using std::endl; + + +namespace mobject { +namespace session { +namespace test { + + using session::test::TestClip; + + typedef PlacementIndex& Idx; + + + /*************************************************************************** + * @test basic behaviour of the index mechanism used to keep track + * of individual Placements as added to the current Session. + * @see mobject::Placement + * @see mobject::MObject#create + * @see mobject::Placement#addPlacement + * @see mobject::Placement#resolve + */ + class PlacementIndex_test : public Test + { + + virtual void + run (Arg) + { + PlacementIndex index (make_dummyRoot()); + ASSERT (index.isValid()); + + checkSimpleInsertRemove (index); + has_size (0, index); + + checkSimpleAccess (index); + has_size (2, index); + + checkScopeHandling (index); + has_size (8, index); + + checkContentsEnumeration (index); + + has_size (8, index); + ASSERT (index.isValid()); + + index.clear(); + has_size (0, index); + ASSERT (index.isValid()); + } + + void + has_size(uint siz, Idx index) + { + ASSERT (siz == index.size()); + } + + + void + checkSimpleInsertRemove (Idx index) + { + PMO clip = TestClip::create(); + PMO& root = index.getRoot(); + + ASSERT (0 == index.size()); + + PMO::ID elmID = index.insert (clip, root); + ASSERT (1 == index.size()); + ASSERT ( index.contains (elmID)); + ASSERT (!index.contains (clip)); // index stores copies + + index.remove(clip); // has no effect + ASSERT (1 == index.size()); + index.remove(elmID); + ASSERT (0 == index.size()); + ASSERT (!index.contains (elmID)); + ASSERT ( index.contains (root)); + } + + + void + checkSimpleAccess (Idx index) + { + PMO testObj = TestClip::create(); + PMO& root = index.getRoot(); + PMO::ID elmID = index.insert (testObj, root); + + PMO& elm = index.find(elmID); + ASSERT (elmID == elm.getID()); + ASSERT (!isSameObject (elm,testObj)); // note: placements are registered as copy + ASSERT (isSameDef(elm,testObj)); // they are semantically equivalent ////////TICKET #511 + ASSERT (elmID != testObj.getID()); // but have a distinct identity + + PMO::ID elmID2 = index.insert(testObj, root); + ASSERT (elmID2 != elmID); // ...and each insert creates a new instance + ASSERT (testObj != index.find (elmID)); + ASSERT (testObj != index.find (elmID2)); + ASSERT (isSameDef(testObj, index.find(elmID))); + ASSERT (isSameDef(testObj, index.find(elmID2))); + ASSERT (!isSameObject (testObj, index.find(elmID2))); + ASSERT (!isSameObject (elm, index.find(elmID2))); + + // can repeatedly retrieve a reference to the same object + ASSERT ( isSameObject (elm, index.find(elmID ))); + ASSERT ( isSameObject (elm, index.find(elmID ))); + + // can also re-access objects by previous ref + ASSERT ( isSameObject (elm, index.find(elm))); + } + + + void + checkInvalidRef (Idx index) + { + RefPlacement invalid; + PlacementMO::ID invalidID (invalid); + ASSERT (!bool(invalidID)); + ASSERT (!bool(invalid)); + + VERIFY_ERROR(BOTTOM_PLACEMENTREF, index.find(invalid) ); + VERIFY_ERROR(BOTTOM_PLACEMENTREF, index.find(invalidID) ); + VERIFY_ERROR(BOTTOM_PLACEMENTREF, index.getScope(invalidID) ); + + ASSERT (!index.contains(invalidID)); + + PMO testObj = TestClip::create(); + VERIFY_ERROR(INVALID_SCOPE, index.insert(testObj, invalidID) ); + + ASSERT (false == index.remove(invalidID)); + } + + + void + checkScopeHandling (Idx index) + { + PMO testObj = TestClip::create(); + PMO& root = index.getRoot(); + + typedef PMO::ID ID; + ID e1 = index.insert (testObj, root); + ID e11 = index.insert (testObj, e1); + ID e12 = index.insert (testObj, e1); + ID e13 = index.insert (testObj, e1); + ID e131 = index.insert (testObj, e13); + ID e132 = index.insert (testObj, e13); + ID e133 = index.insert (testObj, e13); + ID e1331 = index.insert (testObj, e133); + + ASSERT (root == index.getScope(e1)); + ASSERT (e1 == index.getScope(e11).getID()); + ASSERT (e1 == index.getScope(e12).getID()); + ASSERT (e1 == index.getScope(e13).getID()); + ASSERT (e13 == index.getScope(e131).getID()); + ASSERT (e13 == index.getScope(e132).getID()); + ASSERT (e13 == index.getScope(e133).getID()); + ASSERT (e133 == index.getScope(e1331).getID()); + ASSERT (e1 != e13); + ASSERT (e13 != e133); + + ASSERT (index.getScope(e11) == index.getScope(index.find(e11))); + ASSERT (index.getScope(e131) == index.getScope(index.find(e131))); + + VERIFY_ERROR(NONEMPTY_SCOPE, index.remove(e13) ); // can't remove a scope-constituting element + VERIFY_ERROR(NONEMPTY_SCOPE, index.remove(e133) ); + + ASSERT (index.contains(e1331)); + ASSERT (index.remove(e1331)); + ASSERT (!index.contains(e1331)); + ASSERT (!index.remove(e1331)); + + ASSERT (index.remove(e133)); // but can remove an scope, after emptying it + ASSERT (!index.contains(e133)); + } + + + + typedef PlacementIndex::iterator Iter; + + /** @test drill down into the tree-like structure + * and enumerate the contents of each element, if any + */ + void + checkContentsEnumeration (Idx index) + { + PMO& root = index.getRoot(); + + Iter rootContents = index.getReferrers (root.getID()); + ASSERT (rootContents); + + discover (index, rootContents, 0); + } + + + void + discover (Idx index, Iter iter, uint level) + { + uint count (0); + for ( ; iter; ++iter ) + { + cout << indent(level) << "::" << string(*iter) << endl; + + ++count; + Iter scopeContents = index.getReferrers (iter->getID()); + if (scopeContents) + discover (index, scopeContents, level+1); + } + + static format summary ("...%i elements at Level %i"); + cout << indent(level) << summary % count % level << endl; + + ASSERT (!iter); + ASSERT (0 < count); + } + + static string + indent (uint level) + { + return string (level, ' '); + } + }; + + + /** Register this test class... */ + LAUNCHER (PlacementIndex_test, "unit session"); + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/placement-scope-test.cpp b/tests/components/proc/mobject/session/placement-scope-test.cpp new file mode 100644 index 000000000..936eb84ca --- /dev/null +++ b/tests/components/proc/mobject/session/placement-scope-test.cpp @@ -0,0 +1,186 @@ +/* + PlacementScope(Test) - accessing and navigating placement scope + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/scope.hpp" +#include "proc/mobject/session/test-scopes.hpp" +//#include "lib/lumitime.hpp" +//#include "proc/mobject/placement-ref.hpp" +//#include "proc/mobject/session/placement-index.hpp" +//#include "proc/mobject/test-dummy-mobject.hpp" +#include "lib/util.hpp" + +#include +//#include + + + +namespace mobject { +namespace session { +namespace test { + +// using namespace mobject::test; + using lumiera::error::LUMIERA_ERROR_INVALID; + + using util::isSameObject; + //using lumiera::Time; + //using std::string; + using std::cout; + using std::endl; + + + + /*************************************************************************** + * @test basic behaviour of the nested placement search scopes. + * Using a pseudo-session (actually just a PlacementIndex), + * this test creates some nested scopes and then... + * - discovers the scope of a placement + * - finds the parent scope + * - enumerates a scope path up to root + * + * @see mobject::Placement + * @see mobject::session::ScopePath + * @see mobject::session::QueryFocus + */ + class PlacementScope_test : public Test + { + + virtual void + run (Arg) + { + // Prepare an (test)Index backing the PlacementRefs + PPIdx index = build_testScopes(); + + verifyEquality(); + UNIMPLEMENTED ("function test of placement scope interface"); +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! + verifyLookup (index); + verifyNavigation (index); + } + + + typedef Query >::iterator _Iter; + + _Iter + getContents(PPIdx index) + { + return index->query(index->getRoot()); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! + } + + /** @test for each Placement in our test "session", + * find the scope and verify it's in line with the index + */ + void + verifyLookup (PPIdx ref_index) + { +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! + for (_Iter elm = getContents(ref_index); elm; ++elm) + { + ASSERT (elm->isValid()); + cout << string(*elm) << endl; + Scope const& scope1 = Scope::containing(*elm); + + RefPlacement ref (*elm); + Scope const& scope2 = Scope::containing(ref); + + // verify this with the scope registered within the index... + PlacementMO& scopeTop = ref_index->getScope(*elm); + ASSERT (scope1 == scopeTop); + ASSERT (scope2 == scopeTop); + ASSERT (scope1 == scope2); + + ASSERT (isSameObject (scope1,scope2)); + } +#endif //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! + } + + + /** @test equality of scopes is based on the ID of the scope top (Placement) */ + void + verifyEquality () + { + PlacementMO& aPlac = retrieve_startElm(); + Scope scope1(aPlac); + Scope scope2(aPlac); + Scope nil; + + ASSERT (scope1 == scope2); ASSERT (scope2 == scope1); + ASSERT (scope1 != nil); ASSERT (nil != scope1); + ASSERT (scope2 != nil); ASSERT (nil != scope2); + + ASSERT (aPlac == scope1); ASSERT (scope1 == aPlac); + ASSERT (aPlac == scope2); ASSERT (scope2 == aPlac); + ASSERT (aPlac != nil); ASSERT (nil != aPlac); + + Scope par (scope1.getParent()); + ASSERT (scope1 != par); ASSERT (par != scope1); + ASSERT (scope2 != par); ASSERT (par != scope2); + + PlacementMO& plac2 (scope2.getTop()); + ASSERT (aPlac.getID() == plac2.getID()); + + PlacementMO& parPlac (par.getTop()); + ASSERT (aPlac.getID() != parPlac.getID()); + } + + + /** @test navigate to root, starting from each Placement */ + void + verifyNavigation (PPIdx ref_index) + { +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! + for (_Iter elm = getContents(ref_index); elm; ++elm) + { + Scope const& scope = Scope::containing(*elm); + ASSERT (scope == *scope.ascend()); + for (Scope::iterator sco = scope.ascend(); sco; ++sco) + if (sco->isRoot()) + { + VERIFY_ERROR (INVALID, sco->getParent() ); + RefPlacement top = sco->getTop(); + RefPlacement root = ref_index->getRoot(); + + ASSERT (isSameObject (top,root)); + } + else + { + Scope& parent = sco->getParent(); + RefPlacement top = sco->getTop(); + Scope& parentsScope = Scope::containing(top); + RefPlacement topsTop = ref_index->getScope(top); ///////////////////TODO impact of Binding a Sequence? see Ticket #311 + ASSERT (topsTop == parentsScope); + ASSERT (isSameObject (topsTop, parentsScope.getTop())); + } } +#endif //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! + } + + }; + + + /** Register this test class... */ + LAUNCHER (PlacementScope_test, "function session"); + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/query-focus-stack-test.cpp b/tests/components/proc/mobject/session/query-focus-stack-test.cpp new file mode 100644 index 000000000..844c08d31 --- /dev/null +++ b/tests/components/proc/mobject/session/query-focus-stack-test.cpp @@ -0,0 +1,244 @@ +/* + QueryFocusStack(Test) - verify the stack of focus path frames + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/test-scopes.hpp" +#include "proc/mobject/session/query-focus-stack.hpp" +#include "lib/util.hpp" + + + + +namespace mobject { +namespace session { +namespace test { + + using util::isnil; + using util::isSameObject; + using lumiera::error::LUMIERA_ERROR_INVALID; + + + /*************************************************************************** + * @test behaviour of the stack of focus location paths. + * Basically this is just a stack, but has a somewhat unusual behaviour + * on pop(), as it considers the (intrusive) ref-count maintained within + * the stack frames (ScopePath instances) and cleans up unused frames. + * Similar to the ScopePath_test, we use a pseudo-session to create + * some path frames to play with. + * + * @see mobject::session::QueryFocusStack + * @see mobject::session::ScopePath + */ + class QueryFocusStack_test : public Test + { + + virtual void + run (Arg) + { + // Prepare an (test)Index backing the PlacementRefs + PPIdx index = build_testScopes(); + + createStack(); + usePushedFrame(); + automaticFrameHandling(); + verify_errorHandling(); + clear(); + } + + + void + createStack () + { + QueryFocusStack stack; + + ASSERT (!isnil (stack)); + ASSERT (!isnil (stack.top())); + ASSERT (stack.top().getLeaf().isRoot()); + } + + + void + usePushedFrame () + { + QueryFocusStack stack; + PMO& startPoint = retrieve_startElm(); + + ScopePath& firstFrame = stack.top(); // remember for later + intrusive_ptr_add_ref (&firstFrame); + stack.top().navigate(startPoint); + stack.top().moveUp(); + ASSERT (Scope(startPoint).getParent() == stack.top().getLeaf()); + ASSERT (1 == stack.size()); + + // now open a second path frame, pushing aside the initial one + ScopePath& secondFrame = stack.push(startPoint); + intrusive_ptr_add_ref (&secondFrame); + ASSERT (2 == stack.size()); + ASSERT (secondFrame == stack.top()); + ASSERT (secondFrame.getLeaf() == startPoint); + ASSERT (secondFrame.getLeaf() != firstFrame.getLeaf()); + + // can still reach and manipulate the ref-count of the first frame + intrusive_ptr_add_ref (&firstFrame); + ASSERT (2 == firstFrame.ref_count()); + ASSERT (1 == secondFrame.ref_count()); + + // can use/navigate the stack top frame + stack.top().goRoot(); + ASSERT (isnil (stack.top())); // now indeed at root == empty path + ASSERT (secondFrame.getLeaf().isRoot()); + ASSERT (secondFrame == stack.top()); + + // now drop back to the first frame: + ASSERT (1 == secondFrame.ref_count()); + intrusive_ptr_release (&secondFrame); + ASSERT (0 == secondFrame.ref_count()); + stack.pop_unused(); + ASSERT (1 == stack.size()); + ASSERT (firstFrame == stack.top()); + + // ...still pointing at the previous location + ASSERT (Scope(startPoint).getParent() == stack.top().getLeaf()); + ASSERT (2 == firstFrame.ref_count()); + } + + + void + automaticFrameHandling () + { + QueryFocusStack stack; + PMO& startPoint = retrieve_startElm(); + + ScopePath& firstFrame = stack.top(); // remember for later + stack.top().navigate(startPoint); + ASSERT (1 == stack.size()); + intrusive_ptr_add_ref (&firstFrame); + + // now open two new frames, but don't add ref-counts on them + ScopePath& secondFrame = stack.push(startPoint); + ScopePath& thirdFrame = stack.push(startPoint); + ASSERT (3 == stack.size()); + ASSERT (1 == firstFrame.ref_count()); + ASSERT (0 == secondFrame.ref_count()); + ASSERT (0 == thirdFrame.ref_count()); + + // any ref to top detects the non-referred-to state (by ref count==0) + // and will automatically pop and clean up... + ScopePath& newTop = stack.top(); + ASSERT (1 == stack.size()); + ASSERT (firstFrame == stack.top()); + ASSERT (isSameObject(newTop, firstFrame)); + ASSERT (stack.top().getLeaf() == startPoint); + + // second exercise: a pop_unused may even completely empty the stack + ScopePath& anotherFrame = stack.push(startPoint); + ASSERT (0 == anotherFrame.ref_count()); + ASSERT (1 == firstFrame.ref_count()); + intrusive_ptr_release (&anotherFrame); + ASSERT (0 == firstFrame.ref_count()); + ASSERT (firstFrame.getLeaf() == startPoint); + + stack.pop_unused(); + ASSERT (1 == stack.size()); + // Note: don't use previously taken pointers + // or references anymore, after the stack + // triggered a cleanup! + ScopePath& anotherFrame2 = stack.top(); + ASSERT (0 == anotherFrame2.ref_count()); + ASSERT (anotherFrame2.getLeaf().isRoot()); + anotherFrame2.navigate(startPoint); + ASSERT (anotherFrame2.getLeaf() == startPoint); + + stack.top(); + ASSERT (1 == stack.size()); + ASSERT (stack.top().getLeaf().isRoot()); + } + + + void + verify_errorHandling () + { + QueryFocusStack stack; + PMO& startPoint = retrieve_startElm(); + + ScopePath& firstFrame = stack.top(); // remember for later + stack.top().navigate(startPoint); + ASSERT (1 == stack.size()); + intrusive_ptr_add_ref (&firstFrame); + + ScopePath beforeInvalidNavigation = firstFrame; + Scope unrelatedScope (TestPlacement<> (*new DummyMO)); + + // try to navigate to an invalid place + VERIFY_ERROR (INVALID, stack.top().navigate (unrelatedScope) ); + ASSERT (1 == stack.size()); + ASSERT (1 == firstFrame.ref_count()); + ASSERT (stack.top().getLeaf() == startPoint); + + // try to push an invalid place + VERIFY_ERROR (INVALID, stack.push (unrelatedScope) ); + ASSERT (1 == stack.size()); + ASSERT (1 == firstFrame.ref_count()); + ASSERT (stack.top().getLeaf() == startPoint); + } + + + void + clear () + { + QueryFocusStack stack; + intrusive_ptr_add_ref (&stack.top()); + stack.top().moveUp(); + ASSERT (stack.top().empty()); + + PMO& startPoint = retrieve_startElm(); + intrusive_ptr_add_ref ( & stack.push(startPoint) ); + intrusive_ptr_add_ref ( & stack.push(startPoint) ); + intrusive_ptr_add_ref ( & stack.push(startPoint) ); + intrusive_ptr_add_ref ( & stack.push(startPoint) ); + intrusive_ptr_add_ref ( & stack.push(startPoint) ); + intrusive_ptr_add_ref ( & stack.push(startPoint) ); + intrusive_ptr_add_ref ( & stack.push(startPoint) ); + intrusive_ptr_add_ref ( & stack.push(startPoint) ); + intrusive_ptr_add_ref ( & stack.push(startPoint) ); + ASSERT (10 == stack.size()); + stack.pop_unused(); + ASSERT (10 == stack.size()); + ASSERT (1 == stack.top().ref_count()); + + stack.clear(); + ASSERT (1 == stack.size()); + ASSERT (!stack.top().empty()); + ASSERT (stack.top().getLeaf().isRoot()); + ASSERT (0 == stack.top().ref_count()); + } + + }; + + + /** Register this test class... */ + LAUNCHER (QueryFocusStack_test, "unit session"); + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/query-focus-test.cpp b/tests/components/proc/mobject/session/query-focus-test.cpp new file mode 100644 index 000000000..93b3f0a04 --- /dev/null +++ b/tests/components/proc/mobject/session/query-focus-test.cpp @@ -0,0 +1,166 @@ +/* + QueryFocus(Test) - verify proper management of current scope + + Copyright (C) Lumiera.org + 2009, 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/lumitime.hpp" +//#include "proc/mobject/placement-ref.hpp" +#include "proc/mobject/session/test-scopes.hpp" +#include "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/query-focus.hpp" +#include "proc/mobject/session/scope.hpp" +//#include "lib/util.hpp" + +#include +#include + + + +namespace mobject { +namespace session { +namespace test { + + //using util::isSameObject; + //using lumiera::Time; + using std::string; + using std::cout; + using std::endl; + + + /********************************************************************************** + * @test handling of current query focus when navigating a system of nested scopes. + * Using a pseudo-session (actually just a PlacementIndex), this test + * creates some nested scopes and then checks moving the "current scope". + * + * @see mobject::PlacementIndex + * @see mobject::session::ScopePath + * @see mobject::session::QueryFocus + */ + class QueryFocus_test : public Test + { + + virtual void + run (Arg) + { + + // Prepare an (test)Index backing the PlacementRefs + PPIdx index = build_testScopes(); + PMO& root = index->getRoot(); + + QueryFocus theFocus; + theFocus.reset(); + ASSERT (Scope(root) == Scope(theFocus)); + + checkNavigation (theFocus); + + Scope scopePosition = Scope(theFocus); + manipulate_subFocus(); + + QueryFocus currentFocus; + ASSERT (scopePosition == Scope(currentFocus)); + ASSERT (currentFocus == theFocus); + } + + + /** @test move the current focus to various locations + * and discover contents there. */ + void + checkNavigation (QueryFocus& focus) + { + focus.reset(); + ASSERT (Scope(focus).isRoot()); + +#ifdef false ////////////////////////////////////////////////////////////////////////////////TICKET 384 + PMO& someObj = focus.query(); + // by construction of the test fixture, + // we know this object is root -> ps2 -> ps3 + + ASSERT (Scope(focus).isRoot()); + focus.attach (someObj); + ASSERT (!Scope(focus).isRoot()); + ScopePath path = focus.currentPath(); + ASSERT (someObj == path.getLeaf()); + ASSERT (path.getParent().getParent().isRoot()); + + focus.attach (path.getParent()); + ASSERT (Scope(focus) == path.getParent()); + ASSERT (someObj != Scope(focus)); + ASSERT (path.contains (focus.currentPath())); + ASSERT (focus.currentPath().getParent().isRoot()); +#endif + } + + + /** @test side-effect free manipulation of a sub-focus */ + void + manipulate_subFocus() + { +#ifdef false ////////////////////////////////////////////////////////////////////////////////TICKET 384 + QueryFocus original; // automatically attaches to current stack top + uint num_refs = original.ref_count(); + ASSERT (num_refs > 1); + + QueryFocus subF = QueryFocus::push(); + cout << string(subF) << endl; + ASSERT (subF == original); + + ASSERT ( 1 == subF.ref_count()); + ASSERT (num_refs == original.ref_count()); + + { // temporarily creating an independent focus attached differently + QueryFocus subF2 = QueryFocus::push(Scope(subF).getParent()); + ASSERT (subF2 != subF); + ASSERT (subF == original); + cout << string(subF2) << endl; + + Iterator ii = subF2.query(); + while (ii) + { + subF2.attach(*ii); + cout << string(subF2) << endl; + ii = subF2.query(); + } + cout << string(subF2) << "<<<--discovery exhausted" << endl; + + subF2.pop(); // releasing this focus and re-attaching to what's on stack top + cout << string(subF2) << "<<<--after pop()" << endl; + ASSERT (subF2 == subF); + ASSERT (2 == subF2.ref_count()); // both are now attached to the same path + ASSERT (2 == subF.ref_count()); + } + // subF2 went out of scope, but no auto-pop happens (because subF is still there) + cout << string(subF) << endl; + + ASSERT ( 1 == subF.ref_count()); + ASSERT (num_refs == original.ref_count()); + // when subF goes out of scope now, auto-pop will happen... +#endif + } + + }; + + + /** Register this test class... */ + LAUNCHER (QueryFocus_test, "unit session"); + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/query-resolver-test.cpp b/tests/components/proc/mobject/session/query-resolver-test.cpp new file mode 100644 index 000000000..d3a785b0f --- /dev/null +++ b/tests/components/proc/mobject/session/query-resolver-test.cpp @@ -0,0 +1,225 @@ +/* + QueryResolver(Test) - issuing typed queries over a generic interface + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/query-resolver.hpp" +#include "lib/singleton.hpp" + +#include +#include + + + +namespace mobject { +namespace session { +namespace test { + + using lib::test::showSizeof; + using std::string; + using std::cout; + using std::endl; + + + + + namespace { // providing a test query resolving facility... + + typedef Goal::QueryID const& QID; + + /** an sequence of "solutions" to be "found" */ + template + class DummySolutions; + + template<> + class DummySolutions + { + int resNr_; + + public: + DummySolutions() : resNr_(7) {} + + int* next () { --resNr_; return &resNr_; } + bool exhausted() { return !bool(resNr_); } + }; + + template<> + class DummySolutions + : public DummySolutions + { + string currentText_; + + public: + string* + next () + { + static const char* lumi ="Lumiera"; + currentText_ = string (lumi + *DummySolutions::next()); + return ¤tText_; + } + }; + + + /** + * a concrete "resolution" of the query + * is a set of "solutions", which can be + * explored by iteration. Thus, the result set + * has to implement the iteration control API + * as required by IterAdapter + */ + template + struct DummyResultSet + : Resolution + { + DummySolutions solutions_; + + typedef typename Query::Cursor Cursor; + + Result + prepareResolution() + { + Cursor cursor; + cursor.point_at (solutions_.next()); + return cursor; + } + + void + nextResult(Result& pos) + { + Cursor& cursor = static_cast (pos); + + if (solutions_.exhausted()) + cursor.point_at (0); + else + cursor.point_at (solutions_.next()); + } + }; + + + + /** + * a (dummy) concrete query resolution facility. + * It is hard-wired to accept queries on int and string, + * generating a sequence of results for both cases + */ + class DummyTypedSolutionProducer + : public QueryResolver + { + bool + canHandleQuery (QID qID) const + { + return Goal::GENERIC == qID.kind + && (wantResultType (qID) + ||wantResultType(qID)); + } + + template + bool + wantResultType (QID qID) const + { + return qID.type == getResultTypeID(); + } + + + template + static Resolution* + resolutionFunction (Goal const& goal) + { + QID qID = goal.getQID(); + REQUIRE (qID.kind == Goal::GENERIC + && qID.type == getResultTypeID()); + + return new DummyResultSet(); + } + + operator string() const { return "Test-DummyQueryResolver"; } + + public: + DummyTypedSolutionProducer() + : QueryResolver() + { + Goal::QueryID case1 = {Goal::GENERIC, getResultTypeID()}; + Goal::QueryID case2 = {Goal::GENERIC, getResultTypeID()}; + + installResolutionCase(case1, &resolutionFunction ); + installResolutionCase(case2, &resolutionFunction ); + } + }; + + + lib::Singleton testResolver; + + QueryResolver& + buildTestQueryResolver () + { + return testResolver(); + } + + } // (END) implementation of a test query resolving facility + + + + + + + /*********************************************************************************** + * @test verify the mechanism for issuing typed queries through a generic interface, + * without disclosing the facility actually answering those queries. + * Results are to be retrieved through a Lumiera Forward Iterator. + * + * @see mobject::session::QueryResolver + * @see mobject::session::ScopeLocate usage example + * @see mobject::session::ContentsQuery typed query example + * @see contents-query-test.cpp + */ + class QueryResolver_test : public Test + { + + virtual void + run (Arg) + { + QueryResolver& resolver = buildTestQueryResolver(); + Query firstQuery; + explore (firstQuery (resolver)); + + Query secondQuery; + explore (secondQuery(resolver)); + } + + template + static void + explore (ITER ii) + { + cout << "Query-Results: " << showSizeof(ii) << endl; + for ( ; ii; ++ii ) + cout << *ii << endl; + } + + }; + + + /** Register this test class... */ + LAUNCHER (QueryResolver_test, "unit session"); + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/rebuildfixturetest.cpp b/tests/components/proc/mobject/session/rebuildfixturetest.cpp index ae287786c..a0970ff8b 100644 --- a/tests/components/proc/mobject/session/rebuildfixturetest.cpp +++ b/tests/components/proc/mobject/session/rebuildfixturetest.cpp @@ -25,6 +25,7 @@ #include "proc/mobject/session.hpp" #include "proc/mobject/session/edl.hpp" #include "proc/mobject/session/testsession1.hpp" +#include "lib/util-foreach.hpp" #include "lib/util.hpp" //#include diff --git a/tests/components/proc/mobject/session/scope-path-test.cpp b/tests/components/proc/mobject/session/scope-path-test.cpp new file mode 100644 index 000000000..a2bcfb206 --- /dev/null +++ b/tests/components/proc/mobject/session/scope-path-test.cpp @@ -0,0 +1,344 @@ +/* + ScopePath(Test) - verify handling of logical access path down from Session root + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/test-scopes.hpp" +#include "proc/mobject/session/scope-path.hpp" +//#include "lib/lumitime.hpp" +//#include "proc/mobject/placement-ref.hpp" +//#include "proc/mobject/session/placement-index.hpp" +//#include "proc/mobject/test-dummy-mobject.hpp" +#include "lib/util.hpp" + +//#include +//#include + + + +namespace mobject { +namespace session { +namespace test { + + using util::isnil; + using util::isSameObject; +//using lumiera::Time; +//using std::string; +//using std::cout; +//using std::endl; +// using namespace mobject::test; + using lumiera::error::LUMIERA_ERROR_LOGIC; + using lumiera::error::LUMIERA_ERROR_INVALID; + + + /*************************************************************************** + * @test properties and behaviour of the path of nested scopes. + * Using a pseudo-session (actually just a PlacementIndex), this test + * creates some nested scopes and executes navigation moves on them. + * @see mobject::Placement + * @see mobject::session::ScopePath + * @see mobject::session::QueryFocus + */ + class ScopePath_test : public Test + { + + virtual void + run (Arg) + { + // Prepare an (test)Index backing the PlacementRefs + PPIdx index = build_testScopes(); + PMO& startPlacement = retrieve_startElm(); + ASSERT (startPlacement.isValid()); + + ScopePath testPath = buildPath (startPlacement); + checkRelations (testPath,startPlacement); + invalidPath (testPath,startPlacement); + rootPath (testPath); + check_Identity_and_Copy (startPlacement); + navigate (testPath, index); + clear (testPath, index); + ////////////////////////////////////////TICKET #429 : verify diagnostic output (to be added later) + } + + + ScopePath + buildPath (PMO& startPla) + { + Scope startScope (startPla); + ScopePath path (startScope); + ScopePath path2 (startScope); + ScopePath path3 (path2); + + ASSERT (path); + ASSERT (path.contains (startScope)); + ASSERT ( path.getLeaf() == path2.getLeaf()); + ASSERT (path2.getLeaf() == path3.getLeaf()); + + Scope unrelatedScope (TestPlacement<> (*new DummyMO)); + VERIFY_ERROR (INVALID, ScopePath(unrelatedScope) ); + + return path; + } + + + void + checkIteration (ScopePath path, PMO& refPlacement) + { + Scope refScope(refPlacement); + ScopePath::iterator ii = path.begin(); + ASSERT (ii); + while (++ii) + { + ASSERT (*ii == refScope.getParent()); + refScope = *ii; + } + } + + + void + checkRelations (ScopePath path1, PMO& refPlacement) + { + ASSERT (path1.contains (refPlacement)); + + Scope refScope (refPlacement); + ASSERT (path1.contains (refScope)); + ASSERT (path1.endsAt (refScope)); + + ScopePath path2 (refScope); + ASSERT (path2.contains (refScope)); + ASSERT (path2.endsAt (refScope)); + + ASSERT (path1 == path2); + ASSERT (!isSameObject (path1,path2)); + + Scope parent = path2.moveUp(); + ASSERT (path2.endsAt (parent)); + ASSERT (path1.endsAt (refScope)); + ASSERT (parent == refScope.getParent()); + ASSERT (path1 != path2); + ASSERT (path2 != path1); + ASSERT (path1.contains (path2)); ////////////////////TODO: not clear if we really need to implement those relations + ASSERT (!disjoint(path1,path2)); + ASSERT (path2 == commonPrefix(path1,path2)); + ASSERT (path2 == commonPrefix(path2,path1)); + ASSERT (path1 != commonPrefix(path1,path2)); + ASSERT (path1 != commonPrefix(path2,path1)); + } + + + void + rootPath (ScopePath refPath) + { + ASSERT ( refPath); + refPath.goRoot(); + ASSERT (!refPath); + ASSERT (!refPath.empty()); + ASSERT (!refPath.isValid()); + ASSERT (1 == refPath.length()); + + ScopePath defaultPath; + ASSERT (!defaultPath); + ASSERT (refPath == defaultPath); + } + + + void + invalidPath (ScopePath refPath, PMO& refPlacement) + { + ASSERT (refPath); + ASSERT (!ScopePath::INVALID); + ASSERT (isnil (ScopePath::INVALID)); + + ScopePath invalidP (ScopePath::INVALID); + ASSERT (isnil (invalidP)); + ASSERT (invalidP == ScopePath::INVALID); + ASSERT (!isSameObject (invalidP, ScopePath::INVALID)); + + ASSERT (refPath.contains (refPlacement)); + ASSERT (!invalidP.contains (refPlacement)); + + Scope refScope (refPlacement); + ASSERT (!invalidP.contains (refScope)); + ASSERT (!invalidP.endsAt (refScope)); + + ASSERT (refPath.contains (invalidP)); // If the moon consists of green cheese, I'll eat my hat! + ASSERT (!invalidP.contains (refPath)); + ASSERT (invalidP == commonPrefix(refPath,invalidP)); + ASSERT (invalidP == commonPrefix(invalidP,refPath)); + + VERIFY_ERROR (LOGIC, invalidP.moveUp()); + Scope root = refPath.goRoot(); + ASSERT (1 == refPath.length()); + + Scope nil = refPath.moveUp(); + ASSERT (refPath.empty()); + ASSERT (!nil.isValid()); + ASSERT (refPath == invalidP); + ASSERT (invalidP.contains (nil)); + + refPath.navigate(root); + ASSERT (refPath != invalidP); + ASSERT (!isnil (refPath)); + + //ScopePath::INVALID.navigate(root); // doesn't compile + } + + + void + check_Identity_and_Copy (PMO& refPlacement) + { + Scope startScope (refPlacement); + ScopePath path1 (startScope); + ScopePath path2 (startScope); + ScopePath path3 (path2); + + ASSERT (path1.contains (startScope)); + ASSERT (path2.contains (startScope)); + ASSERT (path3.contains (startScope)); + + ASSERT (path1 == path2); + ASSERT (path2 == path3); + ASSERT (path1 == path3); + ASSERT (!isSameObject (path1,path2)); + ASSERT (!isSameObject (path2,path3)); + ASSERT (!isSameObject (path1,path3)); + + Scope parent = path3.moveUp(); + ASSERT (path1 == path2); + ASSERT (path2 != path3); + ASSERT (path1 != path3); + + path2 = path3; + ASSERT (path1 != path2); + ASSERT (path2 == path3); + ASSERT (path1 != path3); + + path1 = ScopePath::INVALID; + ASSERT (path1 != path2); + ASSERT (path2 != path3); + ASSERT (path1 != path3); + } + + + /** @test modify a path by \em navigating it. + * - move one step above the current leaf + * - move up to the root element + * - move back to the parent and verify we're just above the leaf + * - attach a new sibling node and move the path down to there + * - extract the common prefix, which should again point to the parent + * - find a placement in a completely separate branch (only sharing the + * root node). Navigate to there and verify root is the common prefix. + */ + void + navigate (const ScopePath refPath, PPIdx index) + { + ScopePath path (refPath); + ASSERT (path == refPath); + + Scope leaf = path.getLeaf(); + Scope parent = path.moveUp(); + ASSERT (path != refPath); + ASSERT (refPath.contains (path)); + ASSERT (refPath.endsAt (leaf)); + ASSERT (path.endsAt (parent)); + ASSERT (parent == leaf.getParent()); + ASSERT (parent == path.getLeaf()); + + Scope root = path.goRoot(); + ASSERT (path != refPath); + ASSERT (path.endsAt (root)); + ASSERT (refPath.contains (path)); + ASSERT (!path.endsAt (parent)); + ASSERT (!path.endsAt (leaf)); + + path.navigate (parent); + ASSERT (path.endsAt (parent)); + ASSERT (!path.endsAt (root)); + ASSERT (!path.endsAt (leaf)); + + TestPlacement<> newNode (*new DummyMO); + PMO& parentRefPoint = parent.getTop(); + index->insert (newNode, parentRefPoint); // place as sibling of "leaf" + path.navigate (newNode); + Scope sibling = path.getLeaf(); + ASSERT (parent == sibling.getParent()); + ASSERT (path.endsAt (sibling)); + ASSERT (path.contains (parent)); + ASSERT (path.contains (root)); + ASSERT (!refPath.contains (path)); + ASSERT (!path.contains (refPath)); + ASSERT (!disjoint (path,refPath)); + ASSERT (!disjoint (refPath,path)); + + ScopePath prefix = commonPrefix (path,refPath); + ASSERT (prefix == commonPrefix (refPath,path)); + ASSERT (prefix.endsAt (parent)); + ASSERT (!prefix.contains (leaf)); + ASSERT (!prefix.contains (sibling)); + path.navigate (prefix.getLeaf()); + ASSERT (path == prefix); + + // try to navigate to an unconnected location... + ScopePath beforeInvalidNavigation = path; + Scope unrelatedScope (TestPlacement<> (*new DummyMO)); + VERIFY_ERROR (INVALID, path.navigate (unrelatedScope) ); + ASSERT (path == beforeInvalidNavigation); // not messed up by the incident + + // now explore a completely separate branch.... + PMO& separatePlacement = *explore_testScope ( + *explore_testScope ( + *explore_testScope ( + root.getTop()))); + path.navigate (separatePlacement); + ASSERT (path); + ASSERT (disjoint (path,refPath)); + ASSERT (path.contains(separatePlacement)); + Scope other = path.getLeaf(); + ASSERT (isSameObject (other.getTop(), separatePlacement)); + ScopePath rootPrefix = commonPrefix (path,refPath); + ASSERT (rootPrefix.endsAt (root)); + + } + + + void + clear (ScopePath& path, PPIdx index) + { + ASSERT (path); + PMO rootNode = index->getRoot(); + ASSERT (path.getLeaf() != rootNode); + + path.clear(); + ASSERT (!path); + ASSERT (!isnil (path)); + ASSERT (path.getLeaf() == rootNode); + } + + }; + + + /** Register this test class... */ + LAUNCHER (ScopePath_test, "unit session"); + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/scope-query-test.cpp b/tests/components/proc/mobject/session/scope-query-test.cpp new file mode 100644 index 000000000..e139b6452 --- /dev/null +++ b/tests/components/proc/mobject/session/scope-query-test.cpp @@ -0,0 +1,101 @@ +/* + ScopeQuery(Test) - running queries to discover container contents, filtering (sub)types + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/session/scope-query.hpp" +#include "proc/mobject/session/test-scopes.hpp" +//#include "lib/util.hpp" + +#include +#include + + + +namespace mobject { +namespace session { +namespace test { + + using std::string; + using std::cout; + using std::endl; + + + /********************************************************************************************** + * @test how to discover contents or location of a container-like part of the high-level model. + * As this container-like object is just a concept and actually implemented by the + * PlacementIndex, this means querying the index for elements registered with + * a given scope or finding the enclosing scopes. The discovered + * elements will be filtered by a runtime type check. + * + * @todo cover using an additional dynamic filter on the results + * + * @see mobject::session::PlacementIndex + * @see mobject::session::QueryResolver + * @see mobject::session::ContentsQuery + */ + class ScopeQuery_test : public Test + { + + virtual void + run (Arg) + { + // Prepare an (test)Index (dummy "session") + PPIdx testSession (build_testScopes()); + + QueryResolver const& resolver = SessionServiceExploreScope::getResolver(); + PlacementMO const& scope = SessionServiceExploreScope::getScopeRoot(); + + discover (ScopeQuery (resolver,scope, CONTENTS)); + discover (ScopeQuery (resolver,scope, CONTENTS)); + discover (ScopeQuery (resolver,scope, CONTENTS)); + discover (ScopeQuery (resolver,scope, CONTENTS)); + + ScopeQuery specialEl(resolver,scope, CONTENTS); + + discover (ScopeQuery (resolver,*specialEl, PARENTS)); + discover (ScopeQuery (resolver,*specialEl, PATH)); + discover (ScopeQuery (resolver,*specialEl, PATH)); + discover (specialEl); + } + + + template + void + discover (ScopeQuery const& query) + { + typedef typename ScopeQuery::iterator I; + + for (I elm(query); + elm; ++elm) + cout << string(*elm) << endl; + } + + }; + + + /** Register this test class... */ + LAUNCHER (ScopeQuery_test, "unit session"); + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/session-service-access-test.cpp b/tests/components/proc/mobject/session/session-service-access-test.cpp new file mode 100644 index 000000000..c1d7bc877 --- /dev/null +++ b/tests/components/proc/mobject/session/session-service-access-test.cpp @@ -0,0 +1,351 @@ +/* + SessionServiceAccess(Test) - accessing implementation level session services + + 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 "lib/test/run.hpp" +#include "proc/mobject/session.hpp" +#include "lib/meta/generator.hpp" +#include "lib/singleton.hpp" +#include +#include +#include + + +namespace mobject { +namespace session { +namespace test { + + using lib::Singleton; + using boost::lexical_cast; + using std::ostream; + using std::string; + using std::cout; + using std::endl; + + + namespace { // what follows is a simulated (simplified) version + // of the complete Session + SessionManager setup..... + + using lumiera::typelist::Types; + using lumiera::typelist::InstantiateChained; + + + + /* === Interface level === */ //----------------corresponding-to-session.hpp + + struct TSessManager; + typedef TSessManager& PSess; + + struct TSession + { + virtual ~TSession () { } + static TSessManager& current; + + virtual void externalOperation () =0; + }; + + struct TSessManager + { + /** access to the current session */ + virtual TSession* operator-> () =0; + + virtual void reset () =0; + virtual ~TSessManager() { }; + }; + + + + + /* === Service level API === */ //----------------internal-API-definition-headers + + struct InternalAPI_1 + { + virtual ~InternalAPI_1() {} + virtual uint getMagic() =0; + + static InternalAPI_1& access(); + }; + + struct InternalAPI_2 + { + static void invokeImplementationService(); + }; + + + + /* === Implementation level === */ //----------------corresponding-to-session-impl.hpp + + struct TSessionImpl : TSession + { + static uint magic_; + + /* ==== Session API ==== */ + void externalOperation() ; + + /* ==== Implementation level API ==== */ + void implementationService() ; + + /* ==== internals ==== */ + + TSessionImpl(); + operator string() const; + }; + + + + template + struct TServiceAccessPoint; + + template + struct TServiceAccessPoint + : IMPL + , InternalAPI_1 + { + uint + getMagic () + { + return IMPL::magic_; + } + }; + + template + struct TServiceAccessPoint + : IMPL + { + void + forwardServiceInvocation() + { + IMPL::implementationService(); + } + }; + + template< typename IMPS + , class FRONT + , class SESS + > + class TSessionServices + : public InstantiateChained + { + public: + + static FRONT& current; + + template + API& + get() + { + return *this; + } + }; + + + + + + /* === storage and basic session manager configuration === */ + + struct TSessManagerImpl; + + typedef TSessionServices< Types + , TSessManagerImpl + , TSessionImpl + > SessionImplAPI; + + + + struct TSessManagerImpl : TSessManager + { + scoped_ptr pImpl_; + + TSessManagerImpl() + : pImpl_(0) + { } + + SessionImplAPI* + operator-> () + { + if (!pImpl_) + this->reset(); + return pImpl_.get(); + } + + + /* ==== Manager API ==== */ + void + reset () + { + scoped_ptr tmpS (new SessionImplAPI); + pImpl_.swap (tmpS); + } + }; + + + uint TSessionImpl::magic_; + + TSessManager& TSession::current = Singleton()(); + //note: already during static initialisation + + template<> + TSessManagerImpl& SessionImplAPI::current = static_cast (TSession::current); + + + + + + + + + /* === Implementation of service access === */ //----------------corresponding-to-session-services.cpp + + InternalAPI_1& + InternalAPI_1::access() + { + return SessionImplAPI::current->get(); + } + + void + InternalAPI_2::invokeImplementationService() + { + SessionImplAPI::current->forwardServiceInvocation(); + } + + + + + + /* === Implementation of Session internals === */ //----------------corresponding-to-session-impl.cpp + + inline ostream& + operator<< (ostream& os, TSessionImpl const& simpl) + { + return os << string(simpl); + } + + TSessionImpl::operator string() const + { + return string("Session-Impl(") + + lexical_cast(magic_) + + ")"; + } + + TSessionImpl::TSessionImpl() + { + ++magic_; + cout << "creating new Session " << magic_ << endl; + } + + void + TSessionImpl::externalOperation() + { + cout << *this << "::externalOperation()" << endl; + } + + /* ==== Implementation level API ==== */ + inline void + TSessionImpl::implementationService() + { + cout << *this << "::implementationService()" << endl; + } + + + } // (END) simulated session management + + + + + + + + + + + /******************************************************************************* + * Verify the access mechanism both to the pubic session API and + * to implementation level APIs used by Proc-Layer internals. + * + * Actually, this test uses a simulated setup of the real session, + * complete with interfaces, implementation and session manager frontend. + * + * @see session-impl.hpp the real thing + * @see SessionServices; + */ + class SessionServiceAccess_test : public Test + { + virtual void + run (Arg) + { + access_defaultSession(); + make_newSession(); + invoke_implServices(); + } + + + /** @test accessing an non-existing session + * causes creation of a new TSessionImpl instance. + * After that, the public API function gets invoked. + */ + void + access_defaultSession () + { + cout << "Session not yet used...." << endl; + TSession::current->externalOperation(); + } + + + /** @test invoking the management API to close the session. + * The next public API invocation will create + * a new TSessionImpl instance. + */ + void + make_newSession () + { + TSession::current.reset(); + TSession::current->externalOperation(); + } + + + /** example of an one-liner, as it might be used + * internally by implementation code within Proc-Layer */ + uint magic() { return InternalAPI_1::access().getMagic(); } + + /** @test accessing implementation-level APIs */ + void + invoke_implServices () + { + cout << "current Session-Impl-ID = " << magic() << endl; + InternalAPI_2::invokeImplementationService(); + + cout << "now resetting this session." << endl; + TSession::current.reset(); + + InternalAPI_2::invokeImplementationService(); // invocation creates new session as side effect + cout << "current Session-Impl-ID = " << magic() << endl; + } + }; + + + /** Register this test class... */ + LAUNCHER (SessionServiceAccess_test, "function session"); + + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/sessionstructuretest.cpp b/tests/components/proc/mobject/session/sessionstructuretest.cpp index 198505657..173127dd6 100644 --- a/tests/components/proc/mobject/session/sessionstructuretest.cpp +++ b/tests/components/proc/mobject/session/sessionstructuretest.cpp @@ -59,6 +59,9 @@ namespace mobject run (Arg arg) { PSess sess = Session::current; + + UNIMPLEMENTED("the real standard structure of the session"); //////////////////////////TICKET #499 + ASSERT (0 <= sess->currEDL().size()); // TODO implement ASSERT (0 <= sess->getFixture()->size()); // TODO implement ASSERT (sess->currEDL().getTracks()->isValid()); diff --git a/tests/components/proc/mobject/session/test-scopes.cpp b/tests/components/proc/mobject/session/test-scopes.cpp new file mode 100644 index 000000000..578c7e638 --- /dev/null +++ b/tests/components/proc/mobject/session/test-scopes.cpp @@ -0,0 +1,94 @@ +/* + TEST-SCOPES.cpp - builds a test PlacementIndex containing dummy Placements as nested scopes + + Copyright (C) Lumiera.org + 2009, 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 "proc/mobject/session/test-scopes.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/session/scope-query.hpp" + + +namespace mobject { +namespace session { +namespace test { + + + /** @note this dummy index isn't actively connected to the session; + * the unit tests rely on this dummy index containing + * a specific tree structure of test-dummy MObjects. + */ + PPIdx + build_testScopes() + { + PDum p1(*new TestSubMO21); + PDum p2(*new TestSubMO21); + PDum p3(*new TestSubMO21); + PDum p4(*new TestSubMO21); + PDum p5(*new TestSubMO21); + + PDum ps1(*new DummyMO); + PDum ps2(*new TestSubMO2); + PDum ps3(*new TestSubMO1); + + // Prepare an (test)Index backing the PlacementRefs + PPIdx index (SessionServiceMockIndex::install()); + + PMO& root = index->getRoot(); + + typedef PMO::ID ID; + ID i1 = index->insert (p1, root); + ID i2 = index->insert (p2, i1 ); + ID i3 = index->insert (p3, i2 ); + ID i4 = index->insert (p4, i3 ); + ID i5 = index->insert (p5, i4 ); + + ID is1 = index->insert (ps1,root); + ID is2 = index->insert (ps2,root); + ID is3 = index->insert (ps3, is2); + + return index; + } + + + /** @note this test helper only works if build_testScopes is invoked + * beforehand, and the returned smart-ptr to the created test/dummy index + * is retained. Moreover, this function makes assumptions about the actual + * objects created by the former test function. + * @throw lumiera::error::Invalid if the intended start element doesn't exist (anymore) + */ + PlacementMO& + retrieve_startElm() + { + return *ContentsQuery(SessionServiceExploreScope::getResolver() + ,SessionServiceExploreScope::getScopeRoot()); + } + + + ScopeQuery::iterator + explore_testScope (PlacementMO const& scopeTop) + { + return ScopeQuery(SessionServiceExploreScope::getResolver(), + scopeTop, CHILDREN); + } + + +}}} // namespace mobject::session::test diff --git a/tests/components/proc/mobject/session/test-scopes.hpp b/tests/components/proc/mobject/session/test-scopes.hpp new file mode 100644 index 000000000..29da6ba88 --- /dev/null +++ b/tests/components/proc/mobject/session/test-scopes.hpp @@ -0,0 +1,75 @@ +/* + TEST-SCOPES.hpp - builds a test PlacementIndex containing dummy Placements as nested scopes + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_TEST_TEST_SCOPES_H +#define MOBJECT_SESSION_TEST_TEST_SCOPES_H + + +#include "proc/mobject/test-dummy-mobject.hpp" +#include "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/scope-query.hpp" +#include "proc/mobject/placement.hpp" + +#include + + +namespace mobject { +namespace session { +namespace test { + + using namespace mobject::test; + typedef TestPlacement PDum; + + typedef std::tr1::shared_ptr PPIdx; + + + + /** helper for tests: create a pseudo-session (actually just a PlacementIndex), + * which contains some nested placement scopes. + * @return new PlacementIndex, which has already been activated to be used + * by all Placements from now on. This activation will be cleared + * automatically, when this object goes out of scope. + * + * @see mobject::PlacementIndex + * @see session::SessManagerImpl::getCurrentIndex() + * @see mobject::session::SessionServiceMockIndex::reset_PlacementIndex + */ + PPIdx build_testScopes(); + + + /** complement to the helper: retrieve one of the dummy placements + * which is a Placement<> and way down into the hierarchy + */ + PlacementMO& retrieve_startElm(); + + + /** shortcut to explore the contents of a scope within the current index. + * Usually, clients would use QueryFocus or ScopeLocator to perform this task, + * but for the purpose of testing we're better off to invoke the query directly + */ + ScopeQuery::iterator explore_testScope (PlacementMO const& scopeTop); + + + +}}} // namespace mobject::session::test +#endif diff --git a/tests/components/proc/mobject/session/testclip.hpp b/tests/components/proc/mobject/session/testclip.hpp index dbac88087..34fa5154f 100644 --- a/tests/components/proc/mobject/session/testclip.hpp +++ b/tests/components/proc/mobject/session/testclip.hpp @@ -46,7 +46,7 @@ namespace test { /** * Sample or Test Clip for checking * various EDL, session and builder operations. - * @todo make this usable as Mock object to record invoked operations. + * @todo maybe use this as Mock object to record invoked operations? * */ class TestClip : public mobject::session::Clip diff --git a/tests/components/proc/mobject/session/testroot.hpp b/tests/components/proc/mobject/session/testroot.hpp new file mode 100644 index 000000000..a5402ea5a --- /dev/null +++ b/tests/components/proc/mobject/session/testroot.hpp @@ -0,0 +1,51 @@ +/* + TESTROOT.hpp - test dummy model root for checking EDL/Session functionality + + Copyright (C) Lumiera.org + 2009, 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 MOBJECT_SESSION_TESTROOT_H +#define MOBJECT_SESSION_TESTROOT_H + + +#include "proc/mobject/session/label.hpp" +#include "proc/mobject/session/mobjectfactory.hpp" +#include "lib/symbol.hpp" + +using lib::Symbol; + + +namespace mobject { +namespace session { +namespace test { + + inline Placement