From 311fb62c9dc0a0db8358ba1a8b52a96d9fbca254 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 6 Apr 2010 05:27:28 +0200 Subject: [PATCH 01/52] Collect properties for the new Advice concept --- wiki/renderengine.html | 54 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 5d8c9cabb..7bcf7eaf4 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -514,7 +514,7 @@ ColorPalette SiteUrl -
+
{{red{WIP 11/09}}}...//about to explicate a pattern which I'm aiming at within the design almost since the beginning//
 Expecting Advice and giving Advice — this collaboration ranges somewhere between messaging and dynamic properties, but cross-cutting the primary, often hierarchical relation of dependencies. Always happening at a certain //point of advice,// which creates a distinct, static nature different of being just a convention, on the other hand, Advice is deliberately kept optional and received synchronously, albeit possibly within an continuation.
 
@@ -527,10 +527,58 @@ Expecting Advice and giving Advice — this collaboration ranges somewhe
 * ''advice system''
 * the ''binding''
 * the ''advice''
-The ''advised'' entity opens the collaboration by requsting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice colaboration happens at a ''point of advice'', which needs to be derived first. To this end, the adviced puts up an request by providing his ''binding'', which is a pattern for matching. An entity willing to give advice //discovers//&nbsp possible ''advice channels'' by putting up an advisor binding, which similarily is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' — and in the most general case even multiple solutions. If we allow such, there needs to be a scheme for both sides to handle this (unexpected) multiplicity of advice points. Anyway, now the actual colaboration takes place by the advisor placing the piece of advice into the advice channel, causing it to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entitie(s). Typically this involves copying the advice data into a location managed by the advice system. In the most simple case, the advised entity accesses the advice synchronously (an non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this colaboration.
+The ''advised'' entity opens the collaboration by requsting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice colaboration happens at a ''point of advice'', which needs to be derived first. To this end, the adviced puts up an request by providing his ''binding'', which is a pattern for matching. An entity willing to give advice //discovers//  possible ''advice channels'' by putting up an advisor binding, which similarily is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' — and in the most general case even multiple solutions. If we allow such, there needs to be a scheme for both sides to handle this (unexpected) multiplicity of advice points. Anyway, now the actual colaboration takes place by the advisor placing the piece of advice into the advice channel, causing it to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entitie(s). Typically this involves copying the advice data into a location managed by the advice system. In the most simple case, the advised entity accesses the advice synchronously (an non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this colaboration.
 
 !!extensions
 In a more elaborate scheme, the advised entiy could provide a signal to be invoked either in the thread context of the advisor (being still blocked in the advice providing call), or in a completely separate thread. A third solution would be to allow the advised entity to block until recieving new advice. Both of these more elaborate schemes would also allow to create an advice queue. 
+
+→ AdviceSituations
+→ AdviceRequirements
+→ AdviceImplementation
+
+
+
+
From analysing a number of intended AdviceSituations, some requirements for an Advice collaboration and implementation can be extracted.
+
+* the piece of advice is //not shared// between advisor and the advised entities; rather, it is copied into storage managed by the advice system
+* the piece of advice can only be exposed {{{const}}}, as any created advice point solution might be shared
+* the actual mode of advice needs to be configurable by policy — signals (callback functors) might be used on both sides transparently
+* the client side (the advised entity) specifies initially, if a default answer is acceptable. If not, retrieving advice might block or fail
+* on both sides, the collaboration is initiated specifying an advice binding, which is an conjunction of predicates, optionally dynamic
+* there is a tension between matching performance and flexibility. The top level should be entirely static (advice type)
+* the analysed usage situations provide no common denominator on the preferences regarding the match implementation.
+* some cases require just a match out of a small number of tokens, while generally we might get even a double dispatch
+* even possible and partial solutions should be cached, similar to the rete algorithm. Dispatching a solution should work lock-free
+* advice can be overwritten by new advice, but is rarely retracted (indeed, we can rule out this possibility, by relying on a proxy)
+* when locking is left out, we can't give any guarantee as to when a given advice gets visible to the advised entity
+
+
+
+
[[Advice]] is a pattern extracted from several otherwise unrelated constellations
+
+!Proxy media in the engine
+Without rebuilding the engine network, we need the ability to reconfigure some parts to adapt to low resolution place-holder media temporarily. The collaboration required to make this happen seems to ''cross-cut'' the normal processing logic. Indeed, the nature of the adjustments is highly context dependent — not every processing node needs to be adjusted. There is a dangerous interference with the ongoing render processes, prompting for the possibility of picking up this information synchronously.
+* the addressing and delivery of the advice is based on a mix of static (type) and dynamic information
+* it is concievable that the actual matching may even include a token present in the direct invocation context (of a render)
+* the attempt to recieve and pick up advice needs to be failsafe
+* locking should be avoided by design
+
+!Dependency injection for testing
+While inversion of control is a guiding principle on all levels, the design of the Lumiera application deliberately stays just below the level of employing a dependency injection container. Instead, common services are accessible //by type// and the builder pattern is used more explicitly at places. Interestingly, the impact on writing unit tests was by far not so serious as one might expect, based on the usual reasoning of DI proponents. But there remain some situations, where sharing a common test fixture would come in handy
+* here the test depending on a fixture puts up a hard requirement for the actual advice to be there.
+* thus, the advice support system can be used to communicate a need for advice
+* but it seems unreasonable to extend it actually to transmitt a control flow
+
+!properties of placement
+The placement concept plays a fundamental role within Lumiera's HighLevelModel. Besides just being a way of sticking objects together and defining the common properties of //temporal position and output destination,// we try to push this approach to enable a more general, open and generic use. "Placement" is understood as locating within a grid coprised of various degrees of freedom — where locating in a specific way might create additional dimensions to be included into the placement. The standard example is an output connection creating additional adjustable parameters of how to including the connected object into a given presentation space (consider e.g. a sound object, which — just by connection, gains the ability of being //panned// by azimuth, elevation and distance)
+* in this case, obviously the colaboration is n:m, while each partner preferrably should only see a single link.
+* advice is used here to negotiate a direct colaboration, which is then handed off to another facility (wiring a control connection)
+* the possibility of an advice colaboration in this case is initiated rather from the side of the advisor
+* deriving an advice point solution includes some kind of negotioation or active re-evaluation
+* the possible adivsors have to be queried according to their placement scope relations
+* this queriying might even trigger a resolution process within the advising placement.
+
+→ AdviceRequirements
 
@@ -3203,7 +3251,7 @@ probably a LocatingPin but... {{red{TODO any details are yet unknown as of 5/08} !querying additional dimensions basically you resolve the Placement, yielding an ExplicitPlacement... {{red{TODO but any details of how additional dimensions are resolved is still undefined as of 5/08}}}
-
+
[[Placement]]s are at the very core of all [[editing operations|EditingOperations]], because they act as handles (smart pointers) to access the [[media objects|MObject]] to be manipulated. Placements themselves are lightweight and can be handled with //value semantics//. But, when adding a Placement to the [[Session]], it gains an distinguishable identity and should be treated by reference from then on: changing the location properties of this placement has a tangible effect on the way the placed object appears in the context of the session. Besides the direct (language) references, there is a special PlacementRef type which builds on this registration of the placement within the session, can be represented as POD and thus passed over external interfaces. Many editing tasks include finding some Placement in the session and reference as parameter. By acting //on the Placement object,// we can change parameters of the way the media object is placed (e.g. adjust an offset), while by //dereferencing//  the Placement object, we access the "real" media object (e.g. for trimming its length). Placements are ''templated'' on the type of the actual ~MObject they refer to, thus defining the interface/methods usable on this object.
 
 Actually, the way each Placement ties and locates its subject is implemented by one or several small LocatingPin objects, where subclasses of LocatingPin implement the various different methods of placing and resolving the final location. Notably, we can give a ~FixedLocation or we can atach to another ~MObject to get a ~RelativeLocation, etc. In the typical use case, these ~LocatingPins are added to the Placement, but never retrieved directly. Rather the Placement acts as a ''query interface'' for determining the location of the related object. Here, "location" can be thought of as encompassing multiple dimenstions at the same time. An object can be

From e3ebe2cc553766d6428a56109162b4737e007a2b Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Wed, 7 Apr 2010 04:20:20 +0200
Subject: [PATCH 02/52] expand on some detials and requirements for advice

---
 wiki/renderengine.html | 56 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 46 insertions(+), 10 deletions(-)

diff --git a/wiki/renderengine.html b/wiki/renderengine.html
index 7bcf7eaf4..a2f1894e7 100644
--- a/wiki/renderengine.html
+++ b/wiki/renderengine.html
@@ -514,7 +514,7 @@ ColorPalette
 
 SiteUrl
-
+
{{red{WIP 11/09}}}...//about to explicate a pattern which I'm aiming at within the design almost since the beginning//
 Expecting Advice and giving Advice — this collaboration ranges somewhere between messaging and dynamic properties, but cross-cutting the primary, often hierarchical relation of dependencies. Always happening at a certain //point of advice,// which creates a distinct, static nature different of being just a convention, on the other hand, Advice is deliberately kept optional and received synchronously, albeit possibly within an continuation.
 
@@ -527,17 +527,17 @@ Expecting Advice and giving Advice — this collaboration ranges somewhe
 * ''advice system''
 * the ''binding''
 * the ''advice''
-The ''advised'' entity opens the collaboration by requsting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice colaboration happens at a ''point of advice'', which needs to be derived first. To this end, the adviced puts up an request by providing his ''binding'', which is a pattern for matching. An entity willing to give advice //discovers//  possible ''advice channels'' by putting up an advisor binding, which similarily is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' — and in the most general case even multiple solutions. If we allow such, there needs to be a scheme for both sides to handle this (unexpected) multiplicity of advice points. Anyway, now the actual colaboration takes place by the advisor placing the piece of advice into the advice channel, causing it to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entitie(s). Typically this involves copying the advice data into a location managed by the advice system. In the most simple case, the advised entity accesses the advice synchronously (an non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this colaboration.
+The ''advised'' entity opens the collaboration by requsting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice colaboration happens at a ''point of advice'', which needs to be derived first. To this end, the advised puts up an request by providing his ''binding'', which is a pattern for matching. An entity willing to give advice //discovers//  possible ''advice channels'' by putting up an advisor binding, which similarily is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' — and in the most general case even multiple solutions. If we allow such, there needs to be a scheme for both sides to handle this (unexpected) multiplicity of advice points. Anyway, now the actual colaboration takes place by the advisor placing the piece of advice into the advice channel, causing it to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entitie(s). Typically this involves copying the advice data into a location managed by the advice system. In the most simple case, the advised entity accesses the advice synchronously (an non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this colaboration.
 
 !!extensions
-In a more elaborate scheme, the advised entiy could provide a signal to be invoked either in the thread context of the advisor (being still blocked in the advice providing call), or in a completely separate thread. A third solution would be to allow the advised entity to block until recieving new advice. Both of these more elaborate schemes would also allow to create an advice queue. 
+In a more elaborate scheme, the advised entiy could provide a signal to be invoked either in the thread context of the advisor (being still blocked in the advice providing call), or in a completely separate thread. A third solution would be to allow the advised entity to block until recieving new advice. Both of these more elaborate schemes would also allow to create an advice queue — thereby developing the advice colaboration into a kind of messaging system. Following this route seems questionable though.
 
 → AdviceSituations
 → AdviceRequirements
 → AdviceImplementation
 
-
+
From analysing a number of intended AdviceSituations, some requirements for an Advice collaboration and implementation can be extracted.
 
 * the piece of advice is //not shared// between advisor and the advised entities; rather, it is copied into storage managed by the advice system
@@ -551,27 +551,63 @@ In a more elaborate scheme, the advised entiy could provide a signal to be invok
 * even possible and partial solutions should be cached, similar to the rete algorithm. Dispatching a solution should work lock-free
 * advice can be overwritten by new advice, but is rarely retracted (indeed, we can rule out this possibility, by relying on a proxy)
 * when locking is left out, we can't give any guarantee as to when a given advice gets visible to the advised entity
+* throughput doesn't seem to be an issue, but picking up exsiting advice should be fast.
+
+!!questions
+;when does the advice colaboration actually happen?
+:when there is both a client (advised) and a server (advisor) and their advice bindings match
+;can there be multiple matches?
+:within the system as a whole there can be multiple solutions
+:but the individual partners never see more than one connection
+:each point of advice has exactly one binding and can establish one advice channel
+;but when an attempt is made to transfer more information?
+:both sides don't behave symmetrically, and thus the consequences are different
+:on the client side, advice is just //available.// When there is newer one, the previous advice is overwritten
+:the server side doesn't //contain// advice — rather, it is placed into the system. After that, the advisor can go away
+:thus, if an advisor places new advice into an existing advice provision, this effectively initiates a new colaboration
+:if the new advice reaches the same destination, it overwrites; but it may as well reach a different destination this time
+;can just one advice provision create multiplicity?
+:yes, because of the matching process there could be multiple solutions. But neither the client nor the server is aware of that.
+;can advice be changed?
+:No. When inserted into the system, the advisor looses any direct connection to the piece of advice (it is copied)
+:But an advisor can put up another piece of advice into the same advice provision, thereby effectively overwriting at the destination
+;can the binding be modified dynamically?
+:this is treated as if retracting the existing point of advice and opening a new one.
+;what drives the matching?
+:whenever a new point of adivice is opened, search for a matching solution happens.
+:thus, the actual colaboration can be initiated from both sides
+:when a match happens, the corresponding advice point solution gets added into the sytem
+;what about the lifetime of such a solution?
+:it is tied to the //referral// — but there is an asymetry between server and client
+:referral is bound to the server sided / client sided point of advice being still in existence
+:but the server sided point of advice is copied into the system, while the client sided is owned by the client
+:thus, when an advisor goes away, any actual solution remains valid, until no client refers to it anymore
+:on the client side there is an asymetry: actually, a new advice request can be opened, with an exactly identical binding
+:in this case, existing connections will be re-used. But any differences in the binding will require searching a new solution
+;is the search for an adivce point solution exhaustive?
+:from the server side, when a new advice provision / binding is put up, //any// possible advice channel will be searched
+:contrary to this, at the client side, the first match found wins and will establish an advice channel.
 
-
+
[[Advice]] is a pattern extracted from several otherwise unrelated constellations
 
 !Proxy media in the engine
-Without rebuilding the engine network, we need the ability to reconfigure some parts to adapt to low resolution place-holder media temporarily. The collaboration required to make this happen seems to ''cross-cut'' the normal processing logic. Indeed, the nature of the adjustments is highly context dependent — not every processing node needs to be adjusted. There is a dangerous interference with the ongoing render processes, prompting for the possibility of picking up this information synchronously.
+Without rebuilding the engine network, we need the ability to reconfigure some parts to adapt to low resolution place-holder media temporarily. The collaboration required to make this happen seems to ''cross-cut'' the normal processing logic. Indeed, the nature of the adjustments is highly context dependent — not every processing node needs to be adjusted. There is a dangerous interference with the ongoing render processes, prompting for the possibility to pick up this information synchronously.
 * the addressing and delivery of the advice is based on a mix of static (type) and dynamic information
-* it is concievable that the actual matching may even include a token present in the direct invocation context (of a render)
+* it is concievable that the actual matching may even include a token present in the direct invocation context (the ongoing render task)
 * the attempt to recieve and pick up advice needs to be failsafe
 * locking should be avoided by design
 
 !Dependency injection for testing
-While inversion of control is a guiding principle on all levels, the design of the Lumiera application deliberately stays just below the level of employing a dependency injection container. Instead, common services are accessible //by type// and the builder pattern is used more explicitly at places. Interestingly, the impact on writing unit tests was by far not so serious as one might expect, based on the usual reasoning of DI proponents. But there remain some situations, where sharing a common test fixture would come in handy
+While inversion of control is a guiding principle on all levels, the design of the Lumiera application deliberately stays just below the level of employing a dependency injection container. Instead, common services are accessible //by type// and the builder pattern is used more explicitly at places. Interestingly, the impact on writing unit tests was by far not so serious as one might expect, based on the usual reasoning of D.I. proponents. But there remain some situations, where sharing a common test fixture would come in handy
 * here the test depending on a fixture puts up a hard requirement for the actual advice to be there.
 * thus, the advice support system can be used to communicate a need for advice
 * but it seems unreasonable to extend it actually to transmitt a control flow
 
 !properties of placement
-The placement concept plays a fundamental role within Lumiera's HighLevelModel. Besides just being a way of sticking objects together and defining the common properties of //temporal position and output destination,// we try to push this approach to enable a more general, open and generic use. "Placement" is understood as locating within a grid coprised of various degrees of freedom — where locating in a specific way might create additional dimensions to be included into the placement. The standard example is an output connection creating additional adjustable parameters of how to including the connected object into a given presentation space (consider e.g. a sound object, which — just by connection, gains the ability of being //panned// by azimuth, elevation and distance)
-* in this case, obviously the colaboration is n:m, while each partner preferrably should only see a single link.
+The placement concept plays a fundamental role within Lumiera's HighLevelModel. Besides just being a way of sticking objects together and defining the common properties of //temporal position and output destination,// we try to push this approach to enable a more general, open and generic use. "Placement" is understood as locating within a grid comprised of various degrees of freedom — where locating in a specific way might create additional dimensions to be included into the placement. The standard example is an output connection creating additional adjustable parameters controlling the way the connected object is embedded into a given presentation space (consider e.g. a sound object, which — just by connection, gains the ability of being //panned// by azimuth, elevation and distance)
+* in this case, obviously the colaboration is n:m, while each partner preferrably should only see a single advice link.
 * advice is used here to negotiate a direct colaboration, which is then handed off to another facility (wiring a control connection)
 * the possibility of an advice colaboration in this case is initiated rather from the side of the advisor
 * deriving an advice point solution includes some kind of negotioation or active re-evaluation

From f322e5c4633c242181b670cede80de18cef4b594 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 10 Apr 2010 05:13:11 +0200
Subject: [PATCH 03/52] UML for Advice concept and implementation

---
 uml/lumiera/128517         | 312 ++++++++++++++++++++++++++++++++++++-
 uml/lumiera/141445.diagram |  74 +++++++++
 uml/lumiera/141573.diagram |  75 +++++++++
 uml/lumiera/5.session      |  11 +-
 uml/lumiera/lumiera.prj    |   2 +-
 5 files changed, 470 insertions(+), 4 deletions(-)
 create mode 100644 uml/lumiera/141445.diagram
 create mode 100644 uml/lumiera/141573.diagram

diff --git a/uml/lumiera/128517 b/uml/lumiera/128517
index 057be77a3..019609aa8 100644
--- a/uml/lumiera/128517
+++ b/uml/lumiera/128517
@@ -1,6 +1,6 @@
 format 58
 "CommonLib" // CommonLib
-  revision 16
+  revision 17
   modified_by 5 "hiv"
   // class settings
   //class diagram settings
@@ -215,6 +215,316 @@ ${inlines}
     end
   end
 
+  classview 134533 "Advice"
+    //class diagram settings
+    draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
+    //collaboration diagram settings
+    show_full_operations_definition default show_hierarchical_rank default write_horizontally default drawing_language default package_name_in_tab default show_context default draw_all_relations default shadow default show_stereotype_properties default
+    //object diagram settings
+     write_horizontally default package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default show_stereotype_properties default
+    //sequence diagram settings
+    show_full_operations_definition default write_horizontally default class_drawing_mode default drawing_language default draw_all_relations default shadow default show_stereotype_properties default
+    //state diagram settings
+    package_name_in_tab default show_context default auto_label_position default write_trans_label_horizontally default show_trans_definition default draw_all_relations default shadow default
+    show_activities default region_horizontally default drawing_language default show_stereotype_properties default
+    //class settings
+    //activity diagram settings
+    package_name_in_tab default show_context default show_opaque_action_definition default auto_label_position default write_flow_label_horizontally default draw_all_relations default shadow default
+    show_infonote default drawing_language default show_stereotype_properties default
+    classdiagram 141445 "Advice entities"
+      draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
+      size A4
+    end
+
+    class 163973 "Advice"
+      visibility package stereotype "entity"
+      cpp_decl "${comment}${template}class ${name}${inherit}
+  {
+${members}  };
+${inlines}
+"
+      java_decl "${comment}${@}${visibility}${final}${abstract}class ${name}${extends}${implements} {
+${members}}
+"
+      php_decl "${comment}${final}${visibility}${abstract}class ${name}${extends}${implements} {
+${members}}
+"
+      python_2_2 python_decl "class ${name}${inherit}:
+${docstring}${members}
+"
+      idl_decl "${comment}${abstract}${custom}valuetype ${name}${inherit} {
+${members}};
+"
+      explicit_switch_type ""
+      
+    end
+
+    class 164101 "PointOfAdvice"
+      visibility package 
+      cpp_decl "${comment}${template}class ${name}${inherit}
+  {
+${members}  };
+${inlines}
+"
+      java_decl ""
+      php_decl ""
+      python_2_2 python_decl ""
+      idl_decl ""
+      explicit_switch_type ""
+      
+      classrelation 198661 // 
+	relation 188165 --->
+	  stereotype "holds"
+	  a role_name "" protected
+	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
+"
+	    classrelation_ref 198661 // 
+	  b parent class_ref 163973 // Advice
+      end
+    end
+
+    class 164229 "Advisor"
+      visibility package stereotype "actor"
+      cpp_decl ""
+      java_decl ""
+      php_decl ""
+      python_2_2 python_decl ""
+      idl_decl ""
+      explicit_switch_type ""
+      
+      classrelation 199045 // 
+	relation 188549 --->
+	  stereotype "add"
+	  a role_name "" protected
+	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
+"
+	    classrelation_ref 199045 // 
+	  b parent class_ref 164613 // AdviceProvision
+      end
+    end
+
+    class 164357 "Advised"
+      visibility package stereotype "actor"
+      cpp_decl ""
+      java_decl ""
+      php_decl ""
+      python_2_2 python_decl ""
+      idl_decl ""
+      explicit_switch_type ""
+      
+      classrelation 198917 // 
+	relation 188421 --->
+	  stereotype "owns"
+	  a role_name "" protected
+	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
+"
+	    classrelation_ref 198917 // 
+	  b parent class_ref 164485 // AdviceRequest
+      end
+    end
+
+    class 164485 "AdviceRequest"
+      visibility package 
+      cpp_decl "${comment}${template}class ${name}${inherit}
+  {
+${members}  };
+${inlines}
+"
+      java_decl ""
+      php_decl ""
+      python_2_2 python_decl ""
+      idl_decl ""
+      explicit_switch_type ""
+      
+      classrelation 198789 // 
+	relation 188293 ---|>
+	  a public
+	    cpp default "${type}"
+	    classrelation_ref 198789 // 
+	  b parent class_ref 164101 // PointOfAdvice
+      end
+
+      classrelation 199685 // 
+	relation 188933 ----
+	  a role_name "" multiplicity "1" protected
+	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
+"
+	    classrelation_ref 199685 // 
+	  b role_name "" multiplicity "1" protected
+	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
+"
+	    classrelation_ref 199813 // 
+      end
+
+    end
+
+    class 164613 "AdviceProvision"
+      visibility package 
+      cpp_decl "${comment}${template}class ${name}${inherit}
+  {
+${members}  };
+${inlines}
+"
+      java_decl ""
+      php_decl ""
+      python_2_2 python_decl ""
+      idl_decl ""
+      explicit_switch_type ""
+      
+      classrelation 199173 // 
+	relation 188677 ----
+	  a role_name "" multiplicity "1" protected
+	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
+"
+	    classrelation_ref 199173 // 
+	  b role_name "" multiplicity "1" protected
+	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
+"
+	    classrelation_ref 199301 // 
+      end
+
+      classrelation 199941 // 
+	relation 189061 ---|>
+	  a public
+	    cpp default "${type}"
+	    classrelation_ref 199941 // 
+	  b parent class_ref 164101 // PointOfAdvice
+      end
+    end
+
+    class 164741 "Binding"
+      visibility package 
+      cpp_decl "${comment}${template}class ${name}${inherit}
+  {
+${members}  };
+${inlines}
+"
+      java_decl ""
+      php_decl ""
+      python_2_2 python_decl ""
+      idl_decl ""
+      explicit_switch_type ""
+      
+      classrelation 199301 // 
+	relation_ref 188677 // 
+      end
+
+      classrelation 199813 // 
+	relation_ref 188933 // 
+      end
+    end
+
+    objectdiagram 141573 "Advice solving"
+       write_horizontally default package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default show_stereotype_properties default
+      size A4
+    end
+
+    classinstance 142981 ""
+      type class_ref 164613 // AdviceProvision
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 143109 ""
+      type class_ref 164613 // AdviceProvision
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 143237 ""
+      type class_ref 164613 // AdviceProvision
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 143365 ""
+      type class_ref 164229 // Advisor
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 143493 ""
+      type class_ref 164357 // Advised
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 143621 ""
+      type class_ref 164485 // AdviceRequest
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 143749 ""
+      type class_ref 164357 // Advised
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 143877 ""
+      type class_ref 164485 // AdviceRequest
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 144005 ""
+      type class_ref 164741 // Binding
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 144133 ""
+      type class_ref 164741 // Binding
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 144261 ""
+      type class_ref 164741 // Binding
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 144389 ""
+      type class_ref 164741 // Binding
+      attributes
+        end
+      relations
+        end
+    end
+
+    classinstance 144517 ""
+      type class_ref 164741 // Binding
+      attributes
+        end
+      relations
+        end
+    end
+
+  end
+
   classview 129285 "StreamType"
     //class diagram settings
     draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
diff --git a/uml/lumiera/141445.diagram b/uml/lumiera/141445.diagram
new file mode 100644
index 000000000..f8d4b9195
--- /dev/null
+++ b/uml/lumiera/141445.diagram
@@ -0,0 +1,74 @@
+format 58
+
+classcanvas 128005 class_ref 163973 // Advice
+  draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
+  color lightmagenta
+  xyz 348 20 2000
+end
+classcanvas 128133 class_ref 164101 // PointOfAdvice
+  draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
+  xyz 265 102 2000
+end
+classcanvas 128389 class_ref 164229 // Advisor
+  draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
+  xyz 20 188 2000
+end
+classcanvas 128517 class_ref 164357 // Advised
+  draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
+  xyz 551 189 2000
+end
+classcanvas 128645 class_ref 164485 // AdviceRequest
+  draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
+  xyz 364 207 2000
+end
+classcanvas 129157 class_ref 164613 // AdviceProvision
+  draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
+  xyz 157 207 2000
+end
+classcanvas 129285 class_ref 164741 // Binding
+  draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default
+  xyz 283 207 2000
+end
+relationcanvas 128261 relation_ref 188165 // 
+  from ref 128133 z 1999 stereotype "<>" xyz 340 79 3000 to ref 128005
+  no_role_a no_role_b
+  no_multiplicity_a no_multiplicity_b
+end
+relationcanvas 128773 relation_ref 188293 // 
+  geometry VHV
+  from ref 128645 z 1999 to point 405 171
+  line 128901 z 1999 to point 304 171
+  line 129029 z 1999 to ref 128133
+  no_role_a no_role_b
+  no_multiplicity_a no_multiplicity_b
+end
+relationcanvas 129413 relation_ref 188421 // 
+  from ref 128517 z 1999 stereotype "<>" xyz 475 225 3000 to ref 128645
+  no_role_a no_role_b
+  no_multiplicity_a no_multiplicity_b
+end
+relationcanvas 129541 relation_ref 188549 // 
+  from ref 128389 z 1999 stereotype "<>" xyz 89 225 3000 to ref 129157
+  no_role_a no_role_b
+  no_multiplicity_a no_multiplicity_b
+end
+relationcanvas 129669 relation_ref 188677 // 
+  from ref 129157 z 1999 to ref 129285
+  no_role_a no_role_b
+  multiplicity_a_pos 266 232 3000 multiplicity_b_pos 259 232 3000
+end
+relationcanvas 129925 relation_ref 188933 // 
+  from ref 128645 z 1999 to ref 129285
+  no_role_a no_role_b
+  multiplicity_a_pos 341 232 3000 multiplicity_b_pos 347 232 3000
+end
+relationcanvas 130053 relation_ref 189061 // 
+  geometry VHV
+  from ref 129157 z 1999 to point 201 171
+  line 130181 z 1999 to point 304 171
+  line 130309 z 1999 to ref 128133
+  no_role_a no_role_b
+  no_multiplicity_a no_multiplicity_b
+end
+preferred_whz 635 331 1
+end
diff --git a/uml/lumiera/141573.diagram b/uml/lumiera/141573.diagram
new file mode 100644
index 000000000..2def53e54
--- /dev/null
+++ b/uml/lumiera/141573.diagram
@@ -0,0 +1,75 @@
+format 58
+
+classinstancecanvas 128005 classinstance_ref 142981 // 
+  xyz 149 66 2000
+end
+classinstancecanvas 128133 classinstance_ref 143109 // 
+  xyz 149 101 2000
+end
+classinstancecanvas 128261 classinstance_ref 143237 // 
+  xyz 149 135 2000
+end
+classinstancecanvas 128389 classinstance_ref 143365 // 
+  xyz 7 62 2005 color blue
+end
+classinstancecanvas 128645 classinstance_ref 143237 // 
+  xyz 7 135 2000
+end
+classinstancecanvas 128773 classinstance_ref 143493 // 
+  xyz 482 164 2000 color blue
+end
+classinstancecanvas 128901 classinstance_ref 143621 // 
+  xyz 388 164 2005
+end
+classinstancecanvas 129029 classinstance_ref 143749 // 
+  xyz 482 108 2000 color blue
+end
+classinstancecanvas 129157 classinstance_ref 143877 // 
+  xyz 388 108 2010
+end
+classinstancecanvas 129285 classinstance_ref 144005 // 
+  xyz 311 281 2000
+end
+classinstancecanvas 129413 classinstance_ref 144133 // 
+  xyz 311 308 2000
+end
+classinstancecanvas 129541 classinstance_ref 144261 // 
+  xyz 226 254 2000
+end
+classinstancecanvas 129669 classinstance_ref 144389 // 
+  xyz 226 281 2000
+end
+classinstancecanvas 129797 classinstance_ref 144517 // 
+  xyz 226 308 2000
+end
+textcanvas 131205 "match"
+  xyzwh 280 318 2005 29 13
+fragment 131333 "Binding index"
+  color green xyzwh 206 229 1994 164 113
+end
+note 131461 "Advice
+Solution"
+  color green  fg darkgreen  xyzwh 285 145 2004 63 44
+fragment 131589 "Advice system"
+  color lightgreen xyzwh 135 18 1989 245 334
+end
+objectlinkcanvas 131077 norel
+  from ref 129797 z 1999 to ref 129413
+  no_role_a no_role_b
+objectlinkcanvas 131973 norel
+  from ref 128901 z 1999 to ref 128261
+  no_role_a no_role_b
+line 130053 -_-_
+  from ref 128389 z 1999 to ref 128645
+line 130181 -_-_
+  from ref 128645 z 1999 to ref 128261
+line 130309 -_-_
+  from ref 128773 z 1999 to ref 128901
+line 130437 -_-_ geometry HVr
+  from ref 128901 z 1999 to point 428 316
+  line 130565 z 1999 to ref 129413
+line 130693 -_-_ geometry VH
+  from ref 128261 z 1999 to point 191 316
+  line 130949 z 1999 to ref 129797
+preferred_whz 556 483 1
+end
diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session
index b86df7d15..194b63b33 100644
--- a/uml/lumiera/5.session
+++ b/uml/lumiera/5.session
@@ -6,8 +6,12 @@ diagrams
     730 488 100 4 0 0
   classdiagram_ref 139141 // Meta-Asset Relations
     469 451 100 4 0 0
-  active  classdiagram_ref 140293 // TypedLookup
+  classdiagram_ref 140293 // TypedLookup
     721 697 100 4 0 0
+  classdiagram_ref 141445 // Advice entities
+    635 331 100 4 0 0
+  active  objectdiagram_ref 141573 // Advice solving
+    556 483 100 4 0 0
 end
 show_stereotypes
 selected 
@@ -33,7 +37,10 @@ open
   classview_ref 128261 // Builder Workings
   usecaseview_ref 128261 // config examples
   class_ref 133253 // Frame
-  classview_ref 129285 // StreamType
+  class_ref 164485 // AdviceRequest
+  class_ref 164613 // AdviceProvision
+  class_ref 164741 // Binding
+  class_ref 145285 // MediaKind
   
   package_ref 131077 // ConfigQuery
   class_ref 152965 // Handle
diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj
index 1b9206c7a..13b4b5791 100644
--- a/uml/lumiera/lumiera.prj
+++ b/uml/lumiera/lumiera.prj
@@ -1,6 +1,6 @@
 format 58
 "lumiera"
-  revision 61
+  revision 62
   modified_by 5 "hiv"
   cpp_root_dir "../../src/"
 

From 1245f873e62bb30b55b4d79a54b277bc27b88ac6 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 10 Apr 2010 06:04:14 +0200
Subject: [PATCH 04/52] Advice: Requirements, design conclusions,
 implementation draft.

---
 doc/devel/uml/class163973.html    |  21 ++++++++
 doc/devel/uml/class164101.html    |  25 ++++++++++
 doc/devel/uml/class164229.html    |  25 ++++++++++
 doc/devel/uml/class164357.html    |  25 ++++++++++
 doc/devel/uml/class164485.html    |  23 +++++++++
 doc/devel/uml/class164613.html    |  23 +++++++++
 doc/devel/uml/class164741.html    |  24 +++++++++
 doc/devel/uml/classdiagrams.html  |   1 +
 doc/devel/uml/classes.html        |   7 +++
 doc/devel/uml/classes_list.html   |   7 +++
 doc/devel/uml/fig141445.png       | Bin 0 -> 7905 bytes
 doc/devel/uml/fig141573.png       | Bin 0 -> 13160 bytes
 doc/devel/uml/index.html          |  66 ++++++++++++++++++-------
 doc/devel/uml/index_60.html       |  22 ++++-----
 doc/devel/uml/index_65.html       |  12 ++++-
 doc/devel/uml/index_66.html       |   3 +-
 doc/devel/uml/index_67.html       |  79 +++++++++++++++++-------------
 doc/devel/uml/index_69.html       |   2 +-
 doc/devel/uml/index_70.html       |   2 +-
 doc/devel/uml/index_72.html       |   2 +-
 doc/devel/uml/index_73.html       |   2 +-
 doc/devel/uml/index_77.html       |   2 +-
 doc/devel/uml/index_79.html       |   2 +-
 doc/devel/uml/index_80.html       |   1 +
 doc/devel/uml/index_82.html       |   2 +-
 doc/devel/uml/index_83.html       |  10 ++--
 doc/devel/uml/index_84.html       |   6 +--
 doc/devel/uml/index_86.html       |  16 +++---
 doc/devel/uml/objectdiagrams.html |   1 +
 wiki/renderengine.html            |  56 ++++++++++++++++++---
 30 files changed, 371 insertions(+), 96 deletions(-)
 create mode 100644 doc/devel/uml/class163973.html
 create mode 100644 doc/devel/uml/class164101.html
 create mode 100644 doc/devel/uml/class164229.html
 create mode 100644 doc/devel/uml/class164357.html
 create mode 100644 doc/devel/uml/class164485.html
 create mode 100644 doc/devel/uml/class164613.html
 create mode 100644 doc/devel/uml/class164741.html
 create mode 100644 doc/devel/uml/fig141445.png
 create mode 100644 doc/devel/uml/fig141573.png

diff --git a/doc/devel/uml/class163973.html b/doc/devel/uml/class163973.html
new file mode 100644
index 000000000..4a627eca4
--- /dev/null
+++ b/doc/devel/uml/class163973.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+Class Advice
+
+
+
+
+
+
Class Advice
+

+ + + + +

Declaration :

  • C++ : class Advice
  • Java : package class Advice
  • Php : class Advice

Stereotype: entity

+ + diff --git a/doc/devel/uml/class164101.html b/doc/devel/uml/class164101.html new file mode 100644 index 000000000..a7ea0ed91 --- /dev/null +++ b/doc/devel/uml/class164101.html @@ -0,0 +1,25 @@ + + + + + + +Class PointOfAdvice + + + + + +
Class PointOfAdvice
+

+ + + + +

Declaration :

  • C++ : class PointOfAdvice

Directly inherited by : AdviceProvision AdviceRequest

+
+ +
Relation <unidirectional association>

Declaration :

Stereotype: holds

+
+ + diff --git a/doc/devel/uml/class164229.html b/doc/devel/uml/class164229.html new file mode 100644 index 000000000..63bedaff3 --- /dev/null +++ b/doc/devel/uml/class164229.html @@ -0,0 +1,25 @@ + + + + + + +Class Advisor + + + + + +
Class Advisor
+

+ + + + +

Declaration :

    Stereotype: actor

    +
    + +
    Relation <unidirectional association>

    Declaration :

    Stereotype: add

    +
    + + diff --git a/doc/devel/uml/class164357.html b/doc/devel/uml/class164357.html new file mode 100644 index 000000000..46906439f --- /dev/null +++ b/doc/devel/uml/class164357.html @@ -0,0 +1,25 @@ + + + + + + +Class Advised + + + + + +
    Class Advised
    +

    + + + + +

    Declaration :

      Stereotype: actor

      +
      + +
      Relation <unidirectional association>

      Declaration :

      Stereotype: owns

      +
      + + diff --git a/doc/devel/uml/class164485.html b/doc/devel/uml/class164485.html new file mode 100644 index 000000000..4fe5afcad --- /dev/null +++ b/doc/devel/uml/class164485.html @@ -0,0 +1,23 @@ + + + + + + +Class AdviceRequest + + + + + +
      Class AdviceRequest
      +

      + + + + +

      Declaration :

      + +
      Relation <association>

      Declaration :

      + + diff --git a/doc/devel/uml/class164613.html b/doc/devel/uml/class164613.html new file mode 100644 index 000000000..47c23e875 --- /dev/null +++ b/doc/devel/uml/class164613.html @@ -0,0 +1,23 @@ + + + + + + +Class AdviceProvision + + + + + +
      Class AdviceProvision
      +

      + + + + +

      Declaration :

      + +
      Relation <association>

      Declaration :

      + + diff --git a/doc/devel/uml/class164741.html b/doc/devel/uml/class164741.html new file mode 100644 index 000000000..9f8dc59b9 --- /dev/null +++ b/doc/devel/uml/class164741.html @@ -0,0 +1,24 @@ + + + + + + +Class Binding + + + + + +
      Class Binding
      +

      + + + + +

      Declaration :

      • C++ : class Binding
      + +
      Relation <association>

      Declaration :

      +
      Relation <association>

      Declaration :

      + + diff --git a/doc/devel/uml/classdiagrams.html b/doc/devel/uml/classdiagrams.html index ed532bb62..d3ac050c6 100644 --- a/doc/devel/uml/classdiagrams.html +++ b/doc/devel/uml/classdiagrams.html @@ -16,6 +16,7 @@ + diff --git a/doc/devel/uml/classes.html b/doc/devel/uml/classes.html index ed22c27b6..c0cb231a9 100644 --- a/doc/devel/uml/classes.html +++ b/doc/devel/uml/classes.html @@ -17,6 +17,11 @@
      Advice entities
      Asset Kinds
      Automation Entities
      Builder Entities
      + + + + + @@ -28,6 +33,7 @@ + @@ -132,6 +138,7 @@ + diff --git a/doc/devel/uml/classes_list.html b/doc/devel/uml/classes_list.html index 916725182..adfef0f67 100644 --- a/doc/devel/uml/classes_list.html +++ b/doc/devel/uml/classes_list.html @@ -18,6 +18,11 @@
      AbstractMO
      Adviceentity
      AdviceProvision
      AdviceRequest
      Advisedactor
      Advisoractor
      AFrame
      Allocationa directive to place a MObject in a specific way
      AppconfigsingletonSingleton to hold inevitable global flags and constants and for performing erarly (static) global initialization tasks.
      AutoAutomation data for some parameter (i.e. a time varying function)
      BackendCache
      BareEntryID
      Binding
      Binding
      BuffHandle
      BuffTable
      PlayheadCursor
      Plug
      PluginAdapterAdapter used to integrage an effects processor in the render pipeline
      PointOfAdvice
      Prefetch
      Previewalternative version of the media data, probably with lower resolution
      Prockey abstraction: data processing asset
      - + @@ -37,28 +37,28 @@ - + - - - + + - - - + + - - - + + + + +
      AbstractMO
      +Advice
      +AdviceProvision
      +AdviceRequest
      +Advised
      +Advisor
      AFrame
      Allocation
      Appconfig
      @@ -29,6 +34,7 @@ Auto
      BackendCache
      BareEntryID
      +Binding
      Binding
      BuffHandle
      BuffTable
      @@ -133,6 +139,7 @@ PlayheadCursor
      Plug
      PluginAdapter
      +PointOfAdvice
      Prefetch
      Preview
      Proc
      diff --git a/doc/devel/uml/fig141445.png b/doc/devel/uml/fig141445.png new file mode 100644 index 0000000000000000000000000000000000000000..4309a900a297cf7bdaa10f37e11999392662ca1b GIT binary patch literal 7905 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 XtfKsG2AT{?*AN96)h7kgCU5=;k`5+> literal 0 HcmV?d00001 diff --git a/doc/devel/uml/fig141573.png b/doc/devel/uml/fig141573.png new file mode 100644 index 0000000000000000000000000000000000000000..986ef241de5831e10aefd08454087092522659be GIT binary patch literal 13160 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
      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 : 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, allocation, vframe, toolfactory, hub, buildable, abstractmo, exitnode, pathmanager, track, meta, fixedlocation, relativelocation, controllerfacade, rendergraph, pluginadapter, explicitplacement, auto, glrender

      +

      executable associated with : 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, 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

      Artifact main

      Stereotype: source

      @@ -1502,8 +1502,38 @@ undo + +

      5.2 Class View Advice

      +
      + +

      +

      Advice entities



      +
      Class Advice
      +
      +
      Class Advisor
      +
      Class Advised
      +
      +
      +
      Class Binding
      + +

      +

      Advice solving



      + +
      Class instance

      type :AdviceProvision

      +
      Class instance

      type :AdviceProvision

      +
      Class instance

      type :AdviceProvision

      +
      Class instance

      type :Advisor

      +
      Class instance

      type :Advised

      +
      Class instance

      type :AdviceRequest

      +
      Class instance

      type :Advised

      +
      Class instance

      type :AdviceRequest

      +
      Class instance

      type :Binding

      +
      Class instance

      type :Binding

      +
      Class instance

      type :Binding

      +
      Class instance

      type :Binding

      +
      Class instance

      type :Binding

      -

      5.2 Class View StreamType

      +

      5.3 Class View StreamType

      @@ -1515,10 +1545,10 @@ undo
      Class MediaKind
      -

      5.3 Package ConfigQuery

      +

      5.4 Package ConfigQuery

      -

      5.3.1 Component View Query System overview

      +

      5.4.1 Component View Query System overview

      @@ -1534,7 +1564,7 @@ undo
      Component DefaultsManager
      -

      5.3.2 Class View query

      +

      5.4.2 Class View query

      @@ -1559,27 +1589,27 @@ undo
      Class ResultSet
      -

      5.3.3 Use Case View query use

      +

      5.4.3 Use Case View query use

      when to query



      -

      5.3.3.1 Use Case create specific object

      +

      5.4.3.1 Use Case create specific object

      -

      5.3.3.2 Use Case use "default" object

      +

      5.4.3.2 Use Case use "default" object

      -

      5.3.3.3 Use Case load object from session

      +

      5.4.3.3 Use Case load object from session

      -

      5.3.3.4 Use Case add new object to session

      +

      5.4.3.4 Use Case add new object to session

      Class User
      -

      5.3.3.5 Use Case ConfigQuery

      +

      5.4.3.5 Use Case ConfigQuery

      -

      5.3.3.6 Use Case need sub object

      +

      5.4.3.6 Use Case need sub object

      "default" object



      @@ -1587,17 +1617,17 @@ undo
      Class instance predicate impl

      type :TypeHandler

      -

      5.4 Package Containers

      +

      5.5 Package Containers

      -

      5.4.1 Class View Custom holders

      +

      5.5.1 Class View Custom holders

      Class Handle
      Class P
      -

      5.5 Class View error

      +

      5.6 Class View error

      @@ -1611,7 +1641,7 @@ undo -

      5.6 Class View Service Components

      +

      5.7 Class View Service Components

      Class Tool
      @@ -1621,7 +1651,7 @@ undo
      Class Appconfig
      -

      5.7 Class View Posix Threads Abstraction

      +

      5.8 Class View Posix Threads Abstraction

      C++ wrapers for pthreads

      Class Thread
      @@ -1629,7 +1659,7 @@ undo
      Class Mutex
      -

      5.8 Class View SmartPointers

      +

      5.9 Class View SmartPointers

      diff --git a/doc/devel/uml/index_60.html b/doc/devel/uml/index_60.html index c84f0a7d2..c5e08071d 100644 --- a/doc/devel/uml/index_60.html +++ b/doc/devel/uml/index_60.html @@ -28,8 +28,8 @@
      <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
      <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 77e461db5..9f3b83f00 100644 --- a/doc/devel/uml/index_65.html +++ b/doc/devel/uml/index_65.html @@ -27,6 +27,14 @@ ad2class instance ad3class instance add new object to sessionuse case +Adviceclass +Adviceclass view +Advice entitiesclass diagram +Advice solvingobject diagram +AdviceProvisionclass +AdviceRequestclass +Advisedclass +Advisorclass AFrameclass aframeartifacta buffer and render process holding a Audio frame allocateBufferoperation @@ -57,12 +65,12 @@ 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 audio1class instance -audio1class instance autoartifactMedia Object holding automation data AutoclassAutomation data for some parameter (i.e. a time varying function) Automation Entitiesclass diagram diff --git a/doc/devel/uml/index_66.html b/doc/devel/uml/index_66.html index 329844354..7ae707608 100644 --- a/doc/devel/uml/index_66.html +++ b/doc/devel/uml/index_66.html @@ -24,6 +24,7 @@ BackendCacheclass BackendLayerpackage BareEntryIDclass +Bindingclass Bindingclass BuffHandleclass BuffTableclass @@ -39,8 +40,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 -Builderpackage builderpackagesourcecode package

      The Builder creating the Render Engine,
      located within the MObject Subsystem +Builderpackage 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 e1ddf1116..484313c80 100644 --- a/doc/devel/uml/index_67.html +++ b/doc/devel/uml/index_67.html @@ -35,49 +35,62 @@ 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 +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 clipartifacta Media Clip diff --git a/doc/devel/uml/index_69.html b/doc/devel/uml/index_69.html index f2006f6ac..cd8b1183a 100644 --- a/doc/devel/uml/index_69.html +++ b/doc/devel/uml/index_69.html @@ -22,8 +22,8 @@ EDL Example1object diagramA simple example showing how the actual objects are placed in the Fixture (=definitive playlist). It shows a Video and Audio clip placed on two tracks EDL Example2object diagramMore complex example showing the Object graph in the EDL and how it is linked into the Fixture to yield the actual locations. In this example, an HUE Effect is applied on a part of the Clip EffectclassEffect or media processing component -effectartifactEffect or media processing component effectartifactEDL representation of a pluggable and automatable effect. +effectartifactEffect or media processing component Effectclass effective timeline (Fixture)node effectiveTimelinerelation diff --git a/doc/devel/uml/index_70.html b/doc/devel/uml/index_70.html index e177ed876..f8b0d3398 100644 --- a/doc/devel/uml/index_70.html +++ b/doc/devel/uml/index_70.html @@ -41,8 +41,8 @@ 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_72.html b/doc/devel/uml/index_72.html index 2d011b5a4..cfc9228eb 100644 --- a/doc/devel/uml/index_72.html +++ b/doc/devel/uml/index_72.html @@ -25,8 +25,8 @@ 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 d6bd98c73..e57c8da0a 100644 --- a/doc/devel/uml/index_73.html +++ b/doc/devel/uml/index_73.html @@ -25,8 +25,8 @@ ImplFacadeclass In Memory Databaseclass diagram inFixtureactivity action pin -inputclass instance inputclass instance +inputclass instance inputclass instance instanceoperation InstanceHandleclass diff --git a/doc/devel/uml/index_77.html b/doc/devel/uml/index_77.html index bf5ec70f2..fd63eeb6b 100644 --- a/doc/devel/uml/index_77.html +++ b/doc/devel/uml/index_77.html @@ -34,8 +34,8 @@ MediaKindclass merge activity nodemerge activity node Metaclasskey abstraction: metadata and organisational asset -metaartifactkey abstraction: metadata and organisational asset metaartifactabstract base class of all MObjects representing meta data or processing instructions +metaartifactkey abstraction: metadata and organisational asset Metaclass Meta-Asset Relationsclass diagram mobjectartifactKey Abstraction: A Media Object in the Session diff --git a/doc/devel/uml/index_79.html b/doc/devel/uml/index_79.html index 8b2bac9de..c557cd0be 100644 --- a/doc/devel/uml/index_79.html +++ b/doc/devel/uml/index_79.html @@ -21,9 +21,9 @@ 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 Overview Render Enginedeployment diagram diff --git a/doc/devel/uml/index_80.html b/doc/devel/uml/index_80.html index 4593a9e60..1d12e75df 100644 --- a/doc/devel/uml/index_80.html +++ b/doc/devel/uml/index_80.html @@ -51,6 +51,7 @@ pluginadapterartifactAdapter for integrating various Effect processors in the render pipeline pnodenode pointattributeidentifying the point where the nodes should be attached +PointOfAdviceclass pos_relation Posix Threads Abstractionclass viewC++ wrapers for pthreads predecessorsrelation diff --git a/doc/devel/uml/index_82.html b/doc/devel/uml/index_82.html index 69336106c..1e6853045 100644 --- a/doc/devel/uml/index_82.html +++ b/doc/devel/uml/index_82.html @@ -27,8 +27,8 @@ relativelocationartifactPlacement implemnetaion providing various ways of attaching a MObject to another one RelativeLocationclass releaseBufferoperation -RelTypeclassthe possible kinds of RelativePlacements relTypeattributethe kind of relation denoted by this Placement +RelTypeclassthe possible kinds of RelativePlacements removeoperationremove the given asset <i>together with all its dependants</i> from the internal DB Render Entitiesclass diagram Render Mechanicsclass diagram diff --git a/doc/devel/uml/index_83.html b/doc/devel/uml/index_83.html index 1397452cc..122f728a5 100644 --- a/doc/devel/uml/index_83.html +++ b/doc/devel/uml/index_83.html @@ -71,15 +71,15 @@ Statenode Stateclass staterelation -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 actiontry to fetch existing definition 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 64ca32fb8..a164fedd0 100644 --- a/doc/devel/uml/index_84.html +++ b/doc/devel/uml/index_84.html @@ -44,13 +44,13 @@ trafoartifacttransforming processing Node treatoperation treatoperationThis operation is to be overloaded for the specific MObject subclasses to be treated. -treatoperation -treatoperation treatoperation treatoperation -treatoperation +treatoperation +treatoperation treatoperation treatoperation +treatoperation TypedIDclass TypedID::Indexclass TypedID::Linkclass diff --git a/doc/devel/uml/index_86.html b/doc/devel/uml/index_86.html index 91b807e2d..5ac8ddfee 100644 --- a/doc/devel/uml/index_86.html +++ b/doc/devel/uml/index_86.html @@ -22,20 +22,20 @@ 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 VirtualMediaclass Visitableclass visitorpackagesub-namespace for visitor library implementation diff --git a/doc/devel/uml/objectdiagrams.html b/doc/devel/uml/objectdiagrams.html index cb1f81a95..bb844651a 100644 --- a/doc/devel/uml/objectdiagrams.html +++ b/doc/devel/uml/objectdiagrams.html @@ -16,6 +16,7 @@ + diff --git a/wiki/renderengine.html b/wiki/renderengine.html index a2f1894e7..b904f4e4d 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -514,12 +514,16 @@ ColorPalette SiteUrl -
      +
      {{red{WIP 11/09}}}...//about to explicate a pattern which I'm aiming at within the design almost since the beginning//
       Expecting Advice and giving Advice &mdash; this collaboration ranges somewhere between messaging and dynamic properties, but cross-cutting the primary, often hierarchical relation of dependencies. Always happening at a certain //point of advice,// which creates a distinct, static nature different of being just a convention, on the other hand, Advice is deliberately kept optional and received synchronously, albeit possibly within an continuation.
       
       !Specification
       ''Definition'': Advice is an optional, mediated collaboration between entities taking on the roles of advisor and advised, thereby passing a custom piece of advice data, managed by the advice support system. The possibility of advice is created by the advised entity by exposing a point of advice, while the advising entity can discover this advice possibility.
      +[>img[Entities for Advice collaboration|uml/fig141445.png]]
      +
      +
      +
       !!Collaborators
       * the ''advised'' entity 
       * the ''advisor''
      @@ -537,21 +541,42 @@ In a more elaborate scheme, the advised entiy could provide a signal to be invok
       &rarr; AdviceImplementation
       
      -
      +
      +
      [<img[Advice solution|uml/fig141573.png]]
      +
      +
      +
      +
      +
      +The advice system is //templated on the advice type// &mdash; so basically there is an independent lookup table for each different kind of advice.The advice system is a sytem wide singleton service, but it is never addressed directly by the participants. Rather, instances of ~AdviceProvision and ~AdviceRequest act as point of access. But these aren't completely symmetric; while the ~AdviceRequest is owned by the advised entity, the ~AdviceProvision is a value object, a uniform holder used to introduce new advice into the system. ~AdviceProvision is copied into an internal buffer and managed by the advice system, as is the actual advice item, which is copied alongside.
      +
      +In order to find matches and provide advice solutions, the advice system maintains an index data structure called ''~BindingIndex''. The actual binding predicates are represented by value objects stored within this index table. The matching process is triggered whenever a new possibility for an advice solution enters the system, which could be a new request, a new provision or a change in the specified bindings. A successful match causes a pointer to be set within the ~AdviceRequest, pointing to the ~AdviceProvision acting as solution. Thus, when a solution exists, the advised entity can access the advice value object by dereferencing this pointer. A new advice solution just results in setting a different pointer, which is atomic and doesn't need to be protected by locking. But note, when omitting locking there is no memory barrier; thus the advised might not see a changed advice solution, until the corresponding thread(s) refresh their cpu cache. This might or might not be acceptable, depending on the context, and thus is configurable as policy. Similarily, the handling of default advice is configurable. Usually, advice is a default constructible value object. In this case, when there isn't any advice solution (yet), a pseudo solution holding the default constructed advice value is used to satisfy any advice access by the client (advised entity). The same can be used when the actual ~AdviceProvision gets //retracted.// As an alternative, when this default solution approach doesn't work, we can provide a policy either to throw or to wait blocking &mdash; but this alternative policy is similarily implemented with an //null object// (a placeholder ~AdviceProvision). Anyway, this implementation techinque causes the advice system to collect some advice provisions, bindings and advice objects over time. It should use a pooling custom allocator in the final version. As the number of advisors is expected to be rather small, the storage occupied by these elements, which is effectively blocked until application exit, isn't considered a problem.
      +
      +!organising the advice solution
      +This is the tricky part of the whole advice system implementation. A naive implementation will quickly degenerate in performance, as costs are of order ~AdviceProvisions * ~AdviceRequests * (average number of binding terms). But contrary to the standard solutions for rules based systems (either forward or backward chaining), in this case here always complete binding sets are to be matched, which allows to reduce the effort.
      +
      +!!!solution idea
      +The binding patterns are organised by //predicate symbol and the lists are normalised.// A simple normalisation could be lexicographic ordering of the predicates. Then the resulting representation can be //hashed.// When all predicates are constant, match can be found by hashtable lookup, otherwise, in case some predicates contain variable arguments ({{red{planned extension}}}), the lookup is followed by an unification.
      +
      +Yet still we need to store a successful match, together with backlinks, in order to handle changing and retracting of advice.
      +
      +
      +
      From analysing a number of intended AdviceSituations, some requirements for an Advice collaboration and implementation can be extracted.
       
       * the piece of advice is //not shared// between advisor and the advised entities; rather, it is copied into storage managed by the advice system
       * the piece of advice can only be exposed {{{const}}}, as any created advice point solution might be shared
       * the actual mode of advice needs to be configurable by policy &mdash; signals (callback functors) might be used on both sides transparently
       * the client side (the advised entity) specifies initially, if a default answer is acceptable. If not, retrieving advice might block or fail
      -* on both sides, the collaboration is initiated specifying an advice binding, which is an conjunction of predicates, optionally dynamic
      +* on both sides, the collaboration is initiated specifying an advice binding, which is an conjunction of predicates, --optionally dynamic--^^no!^^
       * there is a tension between matching performance and flexibility. The top level should be entirely static (advice type)
       * the analysed usage situations provide no common denominator on the preferences regarding the match implementation.
       * some cases require just a match out of a small number of tokens, while generally we might get even a double dispatch
      -* even possible and partial solutions should be cached, similar to the rete algorithm. Dispatching a solution should work lock-free
      -* advice can be overwritten by new advice, but is rarely retracted (indeed, we can rule out this possibility, by relying on a proxy)
      +* later, possible and partial solutions could be cached, similar to the rete algorithm. Dispatching a solution should work lock-free
      +* advice can be replaced by new advice, which causes all matching advice solutions to behave as being overwritten.
       * when locking is left out, we can't give any guarantee as to when a given advice gets visible to the advised entity
      -* throughput doesn't seem to be an issue, but picking up exsiting advice should be fast.
      +* throughput doesn't seem to be an issue, but picking up exsiting advice should be as fast as possible
      +* we expect a small number of advisors collaborating with and a larger number of advised entities.
       
       !!questions
       ;when does the advice colaboration actually happen?
      @@ -587,15 +612,28 @@ In a more elaborate scheme, the advised entiy could provide a signal to be invok
       ;is the search for an adivce point solution exhaustive?
       :from the server side, when a new advice provision / binding is put up, //any// possible advice channel will be searched
       :contrary to this, at the client side, the first match found wins and will establish an advice channel.
      +
      +!decisions
      +After considering the implementation possibilities, some not completely determined requirements can be narrowed down.
      +* we //do// support the //retracting of advice.//
      +* there is always an implicit //default advice solution.//
      +* advice //is not an messaging system// &mdash; no advice queue
      +* signals (continuations) are acceptable as a extension to be provided later
      +* we don't support any kind of dynamic re-evaluation of the binding match (this means not supporting the placement use case)
      +* the binding pattern is //interpreted strictly as a conjuction of logic predicates// &mdash; no partial match, but arguments are allowed
      +* we prepare for a later extension to //full unification of arguments,// and provide a way of accessing the created bindings as //advice parameters.//
      +
      +Combining all these requirements and properties provides the foundation for the &rarr; AdviceImplementation
      +
       
      -
      +
      [[Advice]] is a pattern extracted from several otherwise unrelated constellations
       
       !Proxy media in the engine
       Without rebuilding the engine network, we need the ability to reconfigure some parts to adapt to low resolution place-holder media temporarily. The collaboration required to make this happen seems to ''cross-cut'' the normal processing logic. Indeed, the nature of the adjustments is highly context dependent &mdash; not every processing node needs to be adjusted. There is a dangerous interference with the ongoing render processes, prompting for the possibility to pick up this information synchronously.
       * the addressing and delivery of the advice is based on a mix of static (type) and dynamic information
      -* it is concievable that the actual matching may even include a token present in the direct invocation context (the ongoing render task)
      +* it is concievable that the actual matching may even include a token present in the direct invocation context (but this possibility was ruled out by later decision)
       * the attempt to recieve and pick up advice needs to be failsafe
       * locking should be avoided by design
       
      @@ -613,6 +651,8 @@ The placement concept plays a fundamental role within Lumiera's HighLevelModel.
       * deriving an advice point solution includes some kind of negotioation or active re-evaluation
       * the possible adivsors have to be queried according to their placement scope relations
       * this queriying might even trigger a resolution process within the advising placement.
      +__Note__: after detailed analysis, this use case was deemed beyond the scope of the [[Advice]] core concept and idea.
      +//As a use case, it was dropped.// But we retain some of the properties discovered by considering this scenario, especially the n:m relation, the symmetry in terms of opening the collaboration, and the possibility to have a specially implemented predicate in the binding pattern.
       
       &rarr; AdviceRequirements
       
      From abe8d876dda1d5963363170691ba01774f65fad8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 11 Apr 2010 01:11:39 +0200 Subject: [PATCH 05/52] Start planning the Advice implementation: skeleton of unit tests --- src/lib/advice.hpp | 69 +++++++++ src/lib/advice/advice.cpp | 37 +++++ tests/40components.tests | 30 ++++ tests/lib/advice/advice-basics-test.cpp | 127 +++++++++++++++ .../advice/advice-binding-pattern-test.cpp | 127 +++++++++++++++ .../lib/advice/advice-configuration-test.cpp | 132 ++++++++++++++++ tests/lib/advice/advice-index-test.cpp | 146 ++++++++++++++++++ tests/lib/advice/advice-multiplicity-test.cpp | 134 ++++++++++++++++ tests/lib/advice/advice-situations-test.cpp | 115 ++++++++++++++ 9 files changed, 917 insertions(+) create mode 100644 src/lib/advice.hpp create mode 100644 src/lib/advice/advice.cpp create mode 100644 tests/lib/advice/advice-basics-test.cpp create mode 100644 tests/lib/advice/advice-binding-pattern-test.cpp create mode 100644 tests/lib/advice/advice-configuration-test.cpp create mode 100644 tests/lib/advice/advice-index-test.cpp create mode 100644 tests/lib/advice/advice-multiplicity-test.cpp create mode 100644 tests/lib/advice/advice-situations-test.cpp diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp new file mode 100644 index 000000000..5240d0124 --- /dev/null +++ b/src/lib/advice.hpp @@ -0,0 +1,69 @@ +/* + ADVICE.hpp - generic loosely coupled interaction guided by symbolic pattern + + 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 advice.hpp + ** Expecting Advice and giving Advice: a cross-cutting collaboration of loosely coupled participants. + ** TODO WIP-WIP + ** + ** @note as of 4/2010 this is an experimental setup and implemented just enough to work out + ** the interfaces. Ichthyo expects this collaboration service to play a central role + ** at various places within proc-layer. + ** + ** @see configrules.hpp + ** @see typed-lookup.cpp corresponding implementation + ** @see typed-id-test.cpp + ** + */ + + +#ifndef LIB_ADVICE_H +#define LIB_ADVICE_H + + +#include "lib/error.hpp" +//#include "proc/asset.hpp" +//#include "proc/asset/struct-scheme.hpp" +//#include "lib/hash-indexed.hpp" +//#include "lib/util.hpp" +#include "lib/symbol.hpp" + +//#include +//#include +//#include +//#include + +namespace lib { ///////TODO: how to arrange the namespaces best? +namespace advice { + + /** + * TODO type comment + */ + template + class PointOfAdvice; + + + + + +}} // namespace lib::advice +#endif diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp new file mode 100644 index 000000000..091a7d4f5 --- /dev/null +++ b/src/lib/advice/advice.cpp @@ -0,0 +1,37 @@ +/* + Advice - generic loosely coupled interaction guided by symbolic pattern + + 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/advice.hpp" + + +namespace lib { +namespace advice { + +// LUMIERA_ERROR_DEFINE (MISSING_INSTANCE, "Existing ID registration without associated instance"); + + + /* ohlolololohaha */ + + + +}} // namespace lib::advice diff --git a/tests/40components.tests b/tests/40components.tests index 113d065f8..ff99224f0 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -18,6 +18,36 @@ return: 0 END +PLANNED "Advice collaboration (basics)" AdviceBasics_test < + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +//#include "lib/test/test-helper.hpp" + +#include "lib/advice.hpp" +//#include "lib/p.hpp" +//#include "proc/assetmanager.hpp" +//#include "proc/asset/inventory.hpp" +//#include "proc/mobject/session/clip.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "lib/meta/trait-special.hpp" +//#include "lib/util-foreach.hpp" +//#include "lib/symbol.hpp" + +//#include +//#include + +//using lib::test::showSizeof; +//using lib::test::randStr; +//using util::isSameObject; +//using util::and_all; +//using util::for_each; +//using util::isnil; +//using lib::Literal; +//using lib::Symbol; +//using lumiera::P; +//using std::string; +//using std::cout; +//using std::endl; + + + +namespace lib { +namespace advice { +namespace test { + + namespace { + } + + + + /******************************************************************************* + * @test proof-of-concept for the Advice collaboration. + * Advice allows data exchange without coupling the participants tightly. + * This test demonstrates the basic expected behaviour in a simple but + * typical situation: two unrelated entities exchange a piece of data + * just by referring to a symbolic topic ID. + * + * @todo partially unimplemented and thus commented out ////////////////////TICKET #605 + * + * @see advice.hpp + * @see AdviceSituations_test + * @see AdviceMultiplicity_test + * @see AdviceConfiguration_test + * @see AdviceBindingPattern_test + * @see AdviceIndex_test implementation test + */ + class AdviceBasics_test : public Test + { + + virtual void + run (Arg) + { + simpleExchange(); + createCollaboration(); + overwriting_and_retracting(); + } + + + /** @test the very basic usage situation: the advisor sets an information value + * and the advised entity picks it up. */ + void + simpleExchange() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + + + /** @test multiple ways how to initiate the advice collaboration */ + void + createCollaboration() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + + + /** @test changing the provided advice, finally retracting it, + * causing fallback on the default value */ + void + overwriting_and_retracting() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + }; + + + + /** Register this test class... */ + LAUNCHER (AdviceBasics_test, "unit common"); + + +}}} // namespace lib::advice::test diff --git a/tests/lib/advice/advice-binding-pattern-test.cpp b/tests/lib/advice/advice-binding-pattern-test.cpp new file mode 100644 index 000000000..2ae234883 --- /dev/null +++ b/tests/lib/advice/advice-binding-pattern-test.cpp @@ -0,0 +1,127 @@ +/* + AdviceBindingPattern(Test) - cover pattern matching used to dispatch Advice + + 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/test/test-helper.hpp" + +#include "lib/advice.hpp" +//#include "lib/p.hpp" +//#include "proc/assetmanager.hpp" +//#include "proc/asset/inventory.hpp" +//#include "proc/mobject/session/clip.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "lib/meta/trait-special.hpp" +//#include "lib/util-foreach.hpp" +//#include "lib/symbol.hpp" + +//#include +//#include + +//using lib::test::showSizeof; +//using lib::test::randStr; +//using util::isSameObject; +//using util::and_all; +//using util::for_each; +//using util::isnil; +//using lib::Literal; +//using lib::Symbol; +//using lumiera::P; +//using std::string; +//using std::cout; +//using std::endl; + + + +namespace lib { +namespace advice { +namespace test { + + namespace { + } + + + + /******************************************************************************* + * @test the pattern matching machinery used to find an Advice solution. + * Each advice::Provision and advice::Request specifies a binding, used + * to discern various pieces of advice. Whenever patterns on the two sides + * match, an Advice channel is created, causing the advice provision to + * get visible to the advised entity. + * + * This test creates various patterns and verifies matching behaves + * as specified and documented. + * + * @todo partially unimplemented and thus commented out ////////////////////TICKET #605 + * + * @see advice.hpp + * @see AdviceBasics_test + * @see AdviceMultiplicity_test + * @see AdviceIndex_test implementation test + */ + class AdviceBindingPattern_test : public Test + { + + virtual void + run (Arg) + { + verifyPatternNormalisation(); + verifyStaticMatch(); + verifyDynamicMatch(); + } + + + void + verifyPatternNormalisation() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + + + void + verifyStaticMatch() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + + + /** @test match against patterns containing variables, + * verify the created solution arguments + * @todo this is a future extension + */ + void + verifyDynamicMatch() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + }; + + + + /** Register this test class... */ + LAUNCHER (AdviceBindingPattern_test, "unit common"); + + +}}} // namespace lib::advice::test diff --git a/tests/lib/advice/advice-configuration-test.cpp b/tests/lib/advice/advice-configuration-test.cpp new file mode 100644 index 000000000..c4448a67a --- /dev/null +++ b/tests/lib/advice/advice-configuration-test.cpp @@ -0,0 +1,132 @@ +/* + AdviceConfiguration(Test) - cover the various policies to configure Advice + + 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/test/test-helper.hpp" + +#include "lib/advice.hpp" +//#include "lib/p.hpp" +//#include "proc/assetmanager.hpp" +//#include "proc/asset/inventory.hpp" +//#include "proc/mobject/session/clip.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "lib/meta/trait-special.hpp" +//#include "lib/util-foreach.hpp" +//#include "lib/symbol.hpp" + +//#include +//#include + +//using lib::test::showSizeof; +//using lib::test::randStr; +//using util::isSameObject; +//using util::and_all; +//using util::for_each; +//using util::isnil; +//using lib::Literal; +//using lib::Symbol; +//using lumiera::P; +//using std::string; +//using std::cout; +//using std::endl; + + + +namespace lib { +namespace advice { +namespace test { + + namespace { + } + + + + /******************************************************************************* + * @test this is a collection of tests to cover the configuration options + * available as policy arguments when establishing the collaboration. + * - default advice values, or blocking or throwing + * - using activation signals on both sides + * - dispatch without locking (TODO any chance we can cover this by test??) + * - more to come.... + * + * @todo partially unimplemented and thus commented out ////////////////////TICKET #605 + * + * @see advice.hpp + * @see AdviceBasics_test + * @see AdviceSituations_test + */ + class AdviceConfiguration_test : public Test + { + + virtual void + run (Arg) + { + checkDefaultAdvice(); + blockOnAdvice(); + checkSignals(); + } + + + /** @test typically, advice is a default constructible value, + * so there is a natural fallback in case no active advice + * provision exists. Alternatively we may specify to throw. + */ + void + checkDefaultAdvice() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + + + /** @test when opening the advice collaboration, both sides may independently + * install a signal (callback functor) to be invoked when the actual + * advice solution gets established. + */ + void + checkSignals() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + + + /** @test instead of allowing default advice values, both sides + * may enter a blocking wait until an advice solution is available. + * This is implemented as special case of using signals + */ + void + blockOnAdvice() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + }; + + + + /** Register this test class... */ + LAUNCHER (AdviceConfiguration_test, "unit common"); + + +}}} // namespace lib::advice::test diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp new file mode 100644 index 000000000..cc30e67b4 --- /dev/null +++ b/tests/lib/advice/advice-index-test.cpp @@ -0,0 +1,146 @@ +/* + AdviceIndex(Test) - cover the index datastructure used to implement Advice dispatch + + 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/test/test-helper.hpp" + +#include "lib/advice.hpp" +//#include "lib/p.hpp" +//#include "proc/assetmanager.hpp" +//#include "proc/asset/inventory.hpp" +//#include "proc/mobject/session/clip.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "lib/meta/trait-special.hpp" +//#include "lib/util-foreach.hpp" +//#include "lib/symbol.hpp" + +//#include +//#include + +//using lib::test::showSizeof; +//using lib::test::randStr; +//using util::isSameObject; +//using util::and_all; +//using util::for_each; +//using util::isnil; +//using lib::Literal; +//using lib::Symbol; +//using lumiera::P; +//using std::string; +//using std::cout; +//using std::endl; + + + +namespace lib { +namespace advice { +namespace test { + + namespace { + } + + + + /******************************************************************************* + * @test the Advice system uses an index datastructure to support matching + * the bindings to get pairs of participants to connect by an individual + * advice channel. + * + * This test covers the properties of this implementation datastucture. + * + * @todo partially unimplemented and thus commented out ////////////////////TICKET #608 + * + * @see advice.hpp + * @see AdviceBasics_test + * @see AdviceBindingPattern_test + */ + class AdviceIndex_test : public Test + { + + virtual void + run (Arg) + { + checkInit(); + addEntry(); + checkLookup(); + removeEntry(); + checkCollisionHandling(); + checkCleanup(); + } + + + void + checkInit() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + } + + + void + addEntry() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + } + + + void + checkLookup() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + } + + + void + removeEntry() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + } + + + void + checkCollisionHandling() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + } + + + void + checkCleanup() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + } + }; + + + + /** Register this test class... */ + LAUNCHER (AdviceIndex_test, "function common"); + + +}}} // namespace lib::advice::test diff --git a/tests/lib/advice/advice-multiplicity-test.cpp b/tests/lib/advice/advice-multiplicity-test.cpp new file mode 100644 index 000000000..69e7b280d --- /dev/null +++ b/tests/lib/advice/advice-multiplicity-test.cpp @@ -0,0 +1,134 @@ +/* + AdviceMultiplicity(Test) - verify correctness when dispatching multiple Advices concurrently + + 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/test/test-helper.hpp" + +#include "lib/advice.hpp" +//#include "lib/p.hpp" +//#include "proc/assetmanager.hpp" +//#include "proc/asset/inventory.hpp" +//#include "proc/mobject/session/clip.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "lib/meta/trait-special.hpp" +//#include "lib/util-foreach.hpp" +//#include "lib/symbol.hpp" + +//#include +//#include + +//using lib::test::showSizeof; +//using lib::test::randStr; +//using util::isSameObject; +//using util::and_all; +//using util::for_each; +//using util::isnil; +//using lib::Literal; +//using lib::Symbol; +//using lumiera::P; +//using std::string; +//using std::cout; +//using std::endl; + + + +namespace lib { +namespace advice { +namespace test { + + namespace { + } + + + + /******************************************************************************* + * @test stress test for the Advice system: + * Concurrently add a multitude of advice provisions and check correct + * matching and dispatch of all advice. + * + * @todo advanced topic, deferred for now (4/10) ////////////////////TICKET #610 + * + * @see advice.hpp + * @see AdviceBasics_test + */ + class AdviceMultiplicity_test : public Test + { + + virtual void + run (Arg) + { + check_highLoadSimpleMatch(); + check_multipleMatch(); + check_unlockedDispatch(); + } + + + /** @test run simple pairs of collaborators in multiple threads. + * Intentionally, there should be just a single match per pair, + * but the timings of provision and pickup are choosen randomly + */ + void + check_highLoadSimpleMatch() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #610 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #610 + } + + + /** @test here, one advice might reach multiple advised entities and + * one entity may receive multiple pieces of advice, overwriting + * previous advice provisions. The receiving clients (advised entities) + * are polling irregularly, but finally should each pick up the correct + * value. To check this, advice values are generated with a specific + * pattern, which can be check summed */ + void + check_multipleMatch() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #610 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #610 + } + + + /** @test when dispatching Advice, some of the locking can be left out. + * Obviously this means we can't be sure anymore the client will + * see the newly dispatched piece of advice. But the main focus + * of this test is to ensure the advice system itself is working + * properly even without complete locking. + * To verify the results, each thread performs a kind of "flush" + * (actually creates a memory barrier) before picking up the + * final value */ + void + check_unlockedDispatch() + { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #610 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #610 + } + }; + + + + /** Register this test class... */ + LAUNCHER (AdviceMultiplicity_test, "function common"); + + +}}} // namespace lib::advice::test diff --git a/tests/lib/advice/advice-situations-test.cpp b/tests/lib/advice/advice-situations-test.cpp new file mode 100644 index 000000000..35110156a --- /dev/null +++ b/tests/lib/advice/advice-situations-test.cpp @@ -0,0 +1,115 @@ +/* + AdviceSituations(Test) - catalogue of standard Advice usage scenarios + + 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/test/test-helper.hpp" + +#include "lib/advice.hpp" +//#include "lib/p.hpp" +//#include "proc/assetmanager.hpp" +//#include "proc/asset/inventory.hpp" +//#include "proc/mobject/session/clip.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "lib/meta/trait-special.hpp" +//#include "lib/util-foreach.hpp" +//#include "lib/symbol.hpp" + +//#include +//#include + +//using lib::test::showSizeof; +//using lib::test::randStr; +//using util::isSameObject; +//using util::and_all; +//using util::for_each; +//using util::isnil; +//using lib::Literal; +//using lib::Symbol; +//using lumiera::P; +//using std::string; +//using std::cout; +//using std::endl; + + + +namespace lib { +namespace advice { +namespace test { + + namespace { + } + + + + /****************************************************************************************** + * @test documentation of the fundamental usage scenarios envisioned in the Advice concept. + * This test will be augmented and completed as the Lumiera application matures. + * + * @todo partially unimplemented and thus commented out ////////////////////TICKET #335 + * + * @see advice.hpp + * @see AdviceBasics_test + * @see AdviceConfiguration_test + */ + class AdviceSituations_test : public Test + { + + virtual void + run (Arg) + { + check_ProxyRenderingAdvice(); + check_DependencyInjection(); + TODO ("more advice usage scenarios.....?"); + } + + + /** @test usage scenario: switch a processing node into proxy mode. */ + void + check_ProxyRenderingAdvice() + { + UNIMPLEMENTED ("anything regarding proxy rendering"); +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #335 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #335 + } + + + /** @test usage scenario: dependency injection for tests */ + void + check_DependencyInjection() + { + UNIMPLEMENTED ("suitable advice to request and transfer test dependencies"); +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #335 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #335 + } + + // more to come..... + + }; + + + + /** Register this test class... */ + LAUNCHER (AdviceSituations_test, "function common"); + + +}}} // namespace lib::advice::test From b789c110fa1035ac5a83dab381ee5d2ad849f5c6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 11 Apr 2010 02:59:08 +0200 Subject: [PATCH 06/52] test-driven brainstorming: how the basic advice collaboration should work --- tests/lib/advice/advice-basics-test.cpp | 138 +++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-) diff --git a/tests/lib/advice/advice-basics-test.cpp b/tests/lib/advice/advice-basics-test.cpp index 65189fe3c..c2884c3b4 100644 --- a/tests/lib/advice/advice-basics-test.cpp +++ b/tests/lib/advice/advice-basics-test.cpp @@ -36,6 +36,7 @@ //#include //#include +#include //using lib::test::showSizeof; //using lib::test::randStr; @@ -47,6 +48,7 @@ //using lib::Symbol; //using lumiera::P; //using std::string; +using std::rand; //using std::cout; //using std::endl; @@ -57,6 +59,23 @@ namespace advice { namespace test { namespace { + + class TheAdvised + : private advice::Request + { + public: + bool got(int val) { return val == getAdvice(); } + }; + + + class TheAdvisor + { + advice::Provision link_; + + public: + void publish (int val) { link_.setAdvice (val); } + void clear() { link_.retractAdvice(); } + }; } @@ -95,6 +114,16 @@ namespace test { simpleExchange() { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + TheAdvised client; // implicitly opens an request-for-advice + CHECK (client.got (0)); // no advice yet --> getting the default int() + + TheAdvisor server; // implicitly prepares an advice provision + CHECK (client.got (0)); // but as no advice was provided yet, nothing happens + + int rr (1 + (rand() % 1000)); + + server.publish (rr); // now an match is detected, creating an advice channel + CHECK (client.got (rr)); // ..so the client can pick up the provided advice value #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 } @@ -104,16 +133,123 @@ namespace test { createCollaboration() { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + TheAdvised client1 ("topic1()"); + TheAdvisor server2 ("topic2()"); + + int r1 (1 + (rand() % 1000)); + int r2 (1 + (rand() % 1000)); + + server2.publish (r2); + CHECK (client1.got(0)); + + TheAdvised client2 ("topic2()"); + CHECK (client2.got(r2)); + + TheAdvisor server1; + CHECK (client1.got(0)); + + server1.publish (r1); + CHECK (client1.got(0)); + CHECK (client2.got(r2)); + + server1.rebind ("topic1()"); + CHECK (client1.got(r1)); + CHECK (client2.got(r2)); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 } /** @test changing the provided advice, finally retracting it, - * causing fallback on the default value */ + * causing fallback on the default value. Any given advisor + * can connect to the advice system with multiple bindings + * consecutively. The connection has no identity beside this + * binding, so another server (advisor) can step into an + * existing connection and overwrite or retract the advice. + * Unless retracted, advice remains in the system, + * even after the advisor is gone. + */ void overwriting_and_retracting() { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + TheAdvised client1 ("topic1()"); + TheAdvised client2 ("topic2()"); + CHECK (client1.got(0)); + CHECK (client2.got(0)); + + int r1 (1 + (rand() % 1000)); + int r2 (1 + (rand() % 1000)); + + { + TheAdvisor server("topic1()"); + CHECK (client1.got(0)); + CHECK (client2.got(0)); + + server.publish (r1); + CHECK (client1.got(r1)); + CHECK (client2.got(0)); + + server.publish (r2); + CHECK (client1.got(r2)); + CHECK (client2.got(0)); + + server.rebind("topic2()"); + CHECK (client1.got(0)); + CHECK (client2.got(r2)); + } + + CHECK (client1.got(0)); + CHECK (client2.got(r2)); + + { + TheAdvisor anotherServer("topic1()"); + CHECK (client1.got(0)); + CHECK (client2.got(r2)); + + anotherServer.publish (r1); + CHECK (client1.got(r1)); + CHECK (client2.got(r2)); + } + + CHECK (client1.got(r1)); + CHECK (client2.got(r2)); + + { + TheAdvisor yetAnotherServer("topic2()"); + CHECK (client1.got(r1)); + CHECK (client2.got(r2)); + + yetAnotherServer.publish (r1); + CHECK (client1.got(r1)); + CHECK (client2.got(r1)); + + yetAnotherserver.rebind("topic1()"); + CHECK (client1.got(r1)); + CHECK (client2.got(0)); + + yetAnotherserver.clear(); + CHECK (client1.got(0)); + CHECK (client2.got(0)); + + yetAnotherserver.rebind("topic2()"); + CHECK (client1.got(0)); + CHECK (client2.got(0)); + + yetAnotherServer.publish (r1); + CHECK (client1.got(0)); + CHECK (client2.got(r1)); + } + + CHECK (client1.got(0)); + CHECK (client2.got(r1)); + + client1.rebind("topic2()"); + CHECK (client1.got(r1)); + CHECK (client2.got(r1)); + + client2.rebind("nonExistingTopic()"); + CHECK (client1.got(r1)); + CHECK (client2.got(0)); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 } }; From 3e2b78b67076a905b4e9d59285017fbc67de642b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 11 Apr 2010 04:44:34 +0200 Subject: [PATCH 07/52] fill in the basic definitions to make the draft test compile --- src/lib/advice.hpp | 87 ++++++++++++++++++- src/lib/advice/binding.hpp | 111 ++++++++++++++++++++++++ tests/lib/advice/advice-basics-test.cpp | 43 ++++++++- wiki/renderengine.html | 12 +-- 4 files changed, 241 insertions(+), 12 deletions(-) create mode 100644 src/lib/advice/binding.hpp diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp index 5240d0124..517f1e1a8 100644 --- a/src/lib/advice.hpp +++ b/src/lib/advice.hpp @@ -23,6 +23,47 @@ /** @file advice.hpp ** Expecting Advice and giving Advice: a cross-cutting collaboration of loosely coupled participants. + ** This header exposes the basics of the advice system and the public access points. The advice system + ** is a system wide singleton service, but clients never talk directly to this singleton; rather they + ** use advice::Provision and advice::Request as access point. + ** + ** \par Advice collaboration pattern + ** Advice collaboration is a special pattern of interaction extracted from multiple use cases within + ** Lumiera. Creating this abstraction was partially inspired by aspect oriented programming, especially + ** the idea of cross-cutting the primary dependency hierarchy. Another source of inspiration where the + ** various incarnations of properties with dynamic binding. For defining the actual binding, we rely + ** on predicate notation and matching (later unification) as known from rule based systems. + ** + ** Definition: Advice is an optional, mediated collaboration between entities taking on + ** the roles of advisor and advised, thereby passing a custom piece of advice data, managed by + ** the advice support system. The possibility of advice is created by both of the collaborators + ** entering the system, where the advised entity exposes a point of advice, while the advising + ** entity provides an actual advice value. + ** + ** \par Collaborators + ** - the advised entity + ** - the advisor + ** - point of advice + ** - advice system + ** - the binding + ** - the advice + ** + ** Usually, the \em advised entity opens the collaboration by requesting an advice. The \em advice itself + ** is a piece of data of a custom type, which needs to be copyable. Obviously, both the advised and the + ** advisor need to share knowledge about the meaning of this advice data. The actual advice collaboration + ** happens at a \em point-of-advice, which needs to be derived first. To this end, the advised puts up an + ** \em request by providing his \em binding, which is a pattern for matching. An entity about to give advice + ** opens possible \advice \em channels by putting up an advisor binding, which similarly is a pattern. The + ** advice \em system as mediator resolves both sides, by matching (which in the most general case could be + ** an unification). This process creates an advice point \em solution -- allowing the advisor to fed the + ** piece of advice into the advice channel, causing it to be placed into the point of advice. After passing + ** a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets + ** exposed to the advised entities. Especially this involves copying the advice data into a location managed + ** by the advice system. In the standard case, the advised entity accesses the advice synchronously and + ** non-blocking. Typically, the advice data type is default constructible and thus there is always a basic + ** form of advice available, thereby completely decoupling the advised entity from the timings related + ** to this collaboration. + ** ** TODO WIP-WIP ** ** @note as of 4/2010 this is an experimental setup and implemented just enough to work out @@ -46,6 +87,7 @@ //#include "lib/hash-indexed.hpp" //#include "lib/util.hpp" #include "lib/symbol.hpp" +#include "lib/advice/binding.hpp" //#include //#include @@ -58,8 +100,49 @@ namespace advice { /** * TODO type comment */ - template - class PointOfAdvice; + template + class PointOfAdvice + { + public: + /** define or re-define the binding + * specifically designating this attachment to the advice system. + * @note issuing this on an existing connection is equivalent + * to re-connecting with the new binding. + */ + void defineBinding (Binding const& binding); + + /** access the \em current piece of advice */ + AD const& getAdvice(); + }; + + + /** + * Access point for the advised entity (client). + * TODO type comment + */ + template + class Request + : public PointOfAdvice + { + + public: + + }; + + + /** + * Access point for the advised entity (client). + * TODO type comment + */ + template + class Provision + : public PointOfAdvice + { + + public: + void setAdvice (AD const& pieceOfAdvice); + void retractAdvice(); + }; diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp new file mode 100644 index 000000000..7a40a8d15 --- /dev/null +++ b/src/lib/advice/binding.hpp @@ -0,0 +1,111 @@ +/* + BINDING.hpp - pattern defining a specific attachment to the Advice system + + 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 binding.hpp + ** A pattern to define and identify a specific attachment to the Advice system. + ** This pattern is comprised of a predicate list and intended to be matched or unified + ** against a similar pattern associated with the attachment of a possible collaboration partner. + ** Semantically, this list of atoms forms an conjunction of predicates to be resolved against + ** similar predicates of the partner. Informally, when two entities attach to the Advice system, + ** each specifying a binding, they can be paired up if, when combining, the expressions in their + ** bindings all evaluate to true. + ** + ** Typically, a binding includes a \em type-guard predicate \c adviceType(xx) where \c xx is an + ** identifier denoting a type used within an instantiation of the Advice collaboration, i.e. a type + ** used as advice value in a instantiation of the PointOfAdvice template. Besides the type guard, + ** a binding may narrow down the topic of the advice by providing further predicates. This allows for + ** Advice collaborations targeted at a more specific topic. The goal and intention behind this Advice + ** system is to allow collaboration of entities without requiring them to be tightly coupled. Indeed, + ** the only dependency besides the common type used as advice is to know any specific topic used + ** within the binding. Thus, and advisor entity could put up a piece of advice, i.e. a value of + ** the advice type, and another client entity (the advised entity) could pick up this value + ** without the need to now anything about the advisor. + ** + ** Any binding can be normalised into a hash value, which plays a crucial role within the + ** implementation of the advice system. + ** + ** TODO WIP-WIP + ** + ** @note as of 4/2010 this is an experimental setup and implemented just enough to work out + ** the interfaces. Ichthyo expects this collaboration service to play a central role + ** at various places within proc-layer. + ** + ** @see configrules.hpp + ** @see typed-lookup.cpp corresponding implementation + ** @see typed-id-test.cpp + ** + */ + + +#ifndef LIB_ADVICE_BINDING_H +#define LIB_ADVICE_BINDING_H + + +#include "lib/error.hpp" +//#include "proc/asset.hpp" +//#include "proc/asset/struct-scheme.hpp" +//#include "lib/hash-indexed.hpp" +//#include "lib/util.hpp" +#include "lib/symbol.hpp" + +//#include +//#include +//#include +//#include + +namespace lib { +namespace advice { + + /** + * Conjunction of predicates to be matched + * against a collaboration partner for establishing + * an Advice connection. + * TODO type comment + */ + class Binding + { + public: + /** create the empty binding, equivalent to \c true */ + Binding(); + + /** create the binding as defined by the given textual definition. + * @note implicit type conversion deliberately intended */ + Binding (Literal spec); + + /*-- Binding is default copyable --*/ + + /** extend the definition of this binding + * by adding a predicate according to the + * given textual definition */ + void addPredicate (Literal spec); + }; + + + ////TODO define the hash function here, to be picked up by ADL + + + + + +}} // namespace lib::advice +#endif diff --git a/tests/lib/advice/advice-basics-test.cpp b/tests/lib/advice/advice-basics-test.cpp index c2884c3b4..8ecdd852f 100644 --- a/tests/lib/advice/advice-basics-test.cpp +++ b/tests/lib/advice/advice-basics-test.cpp @@ -64,17 +64,52 @@ namespace test { : private advice::Request { public: - bool got(int val) { return val == getAdvice(); } + TheAdvised (Literal topic =0) + { + rebind (topic); + } + + void + rebind (Literal topic) + { + defineBinding (topic); + } + + bool + got(int val) + { + return val == getAdvice(); + } }; class TheAdvisor { - advice::Provision link_; + advice::Provision link_; public: - void publish (int val) { link_.setAdvice (val); } - void clear() { link_.retractAdvice(); } + TheAdvisor (Literal topic =0) + { + rebind (topic); + } + + void + rebind (Literal topic) + { + link_.defineBinding (topic); + } + + void + publish (int val) + { + link_.setAdvice (val); + } + + void + clear() + { + link_.retractAdvice(); + } }; } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index b904f4e4d..346053ef8 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -514,12 +514,12 @@ ColorPalette SiteUrl
      -
      +
      {{red{WIP 11/09}}}...//about to explicate a pattern which I'm aiming at within the design almost since the beginning//
       Expecting Advice and giving Advice &mdash; this collaboration ranges somewhere between messaging and dynamic properties, but cross-cutting the primary, often hierarchical relation of dependencies. Always happening at a certain //point of advice,// which creates a distinct, static nature different of being just a convention, on the other hand, Advice is deliberately kept optional and received synchronously, albeit possibly within an continuation.
       
       !Specification
      -''Definition'': Advice is an optional, mediated collaboration between entities taking on the roles of advisor and advised, thereby passing a custom piece of advice data, managed by the advice support system. The possibility of advice is created by the advised entity by exposing a point of advice, while the advising entity can discover this advice possibility.
      +''Definition'': Advice is an optional, mediated collaboration between entities taking on the roles of advisor and advised, thereby passing a custom piece of advice data, managed by the advice support system. The possibility of advice is created by both of the collaborators entering the system, where the advised entity exposes a point of advice, while the advising entity provides an actual advice value.
       [>img[Entities for Advice collaboration|uml/fig141445.png]]
       
       
      @@ -531,17 +531,17 @@ Expecting Advice and giving Advice &mdash; this collaboration ranges somewhe
       * ''advice system''
       * the ''binding''
       * the ''advice''
      -The ''advised'' entity opens the collaboration by requsting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice colaboration happens at a ''point of advice'', which needs to be derived first. To this end, the advised puts up an request by providing his ''binding'', which is a pattern for matching. An entity willing to give advice //discovers//&nbsp; possible ''advice channels'' by putting up an advisor binding, which similarily is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' &mdash; and in the most general case even multiple solutions. If we allow such, there needs to be a scheme for both sides to handle this (unexpected) multiplicity of advice points. Anyway, now the actual colaboration takes place by the advisor placing the piece of advice into the advice channel, causing it to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entitie(s). Typically this involves copying the advice data into a location managed by the advice system. In the most simple case, the advised entity accesses the advice synchronously (an non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this colaboration.
      +Usually, the ''advised'' entity opens the collaboration by requesting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice collaboration happens at a ''point of advice'', which needs to be derived first. To this end, the advised puts up an request by providing his ''binding'', which is a pattern for matching. An entity about to give advice //opens//&nbsp; possible ''advice channels'' by putting up an advisor binding, which similarly is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' &mdash; allowing the advisor to fed the piece of advice into the advice channel, causing it to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entities. Especially, this involves copying the advice data into a location managed by the advice system. In the standard case, the advised entity accesses the advice synchronously (an non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this collaboration.
       
       !!extensions
      -In a more elaborate scheme, the advised entiy could provide a signal to be invoked either in the thread context of the advisor (being still blocked in the advice providing call), or in a completely separate thread. A third solution would be to allow the advised entity to block until recieving new advice. Both of these more elaborate schemes would also allow to create an advice queue &mdash; thereby developing the advice colaboration into a kind of messaging system. Following this route seems questionable though.
      +In a more elaborate scheme, the advised entity could provide a signal to be invoked either in the thread context of the advisor (being still blocked in the advice providing call), or in a completely separate thread. A third solution would be to allow the advised entity to block until receiving new advice. Both of these more elaborate schemes would also allow to create an advice queue &mdash; thereby developing the advice collaboration into a kind of messaging system. Following this route seems questionable though.
       
       &rarr; AdviceSituations
       &rarr; AdviceRequirements
       &rarr; AdviceImplementation
       
      -
      +
      [<img[Advice solution|uml/fig141573.png]]
       
       
      @@ -556,7 +556,7 @@ In order to find matches and provide advice solutions, the advice system maintai
       This is the tricky part of the whole advice system implementation. A naive implementation will quickly degenerate in performance, as costs are of order ~AdviceProvisions * ~AdviceRequests * (average number of binding terms). But contrary to the standard solutions for rules based systems (either forward or backward chaining), in this case here always complete binding sets are to be matched, which allows to reduce the effort.
       
       !!!solution idea
      -The binding patterns are organised by //predicate symbol and the lists are normalised.// A simple normalisation could be lexicographic ordering of the predicates. Then the resulting representation can be //hashed.// When all predicates are constant, match can be found by hashtable lookup, otherwise, in case some predicates contain variable arguments ({{red{planned extension}}}), the lookup is followed by an unification.
      +The binding patterns are organised by //predicate symbol and the lists are normalised.// A simple normalisation could be lexicographic ordering of the predicate symbols. Then the resulting representation can be //hashed.// When all predicates are constant, match can be found by hashtable lookup, otherwise, in case some predicates contain variable arguments ({{red{planned extension}}}), the lookup is followed by an unification.
       
       Yet still we need to store a successful match, together with backlinks, in order to handle changing and retracting of advice.
       
      From e3c963378fa270729ba18a5c90b791fd487b861d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 11 Apr 2010 05:11:56 +0200 Subject: [PATCH 08/52] outline some implementation details regarding the Bindings to match --- src/lib/advice.hpp | 46 +++++++++++++------ src/lib/advice/binding.hpp | 11 ++++- .../advice/advice-binding-pattern-test.cpp | 41 +++++++++++++++-- 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp index 517f1e1a8..1bafc833c 100644 --- a/src/lib/advice.hpp +++ b/src/lib/advice.hpp @@ -112,21 +112,12 @@ namespace advice { void defineBinding (Binding const& binding); /** access the \em current piece of advice */ - AD const& getAdvice(); - }; - - - /** - * Access point for the advised entity (client). - * TODO type comment - */ - template - class Request - : public PointOfAdvice - { + AD const& getAdvice() const; - public: + /* == policy definitions == */ ////TODO: extract into policy classes + + AD const& handleMissingSolution() const; }; @@ -140,10 +131,39 @@ namespace advice { { public: + AD const& + getAdvice() const + { + UNIMPLEMENTED ("how to embody the piece of advice..."); + } + void setAdvice (AD const& pieceOfAdvice); void retractAdvice(); }; + + /** + * Access point for the advised entity (client). + * TODO type comment + */ + template + class Request + : public PointOfAdvice + { + Provision* solution_; + + public: + AD const& + getAdvice() const + { + if (!solution_) + return this->handleMissingSolution(); + else + return solution_->getAdvice(); + } + + }; + diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp index 7a40a8d15..c1f69914c 100644 --- a/src/lib/advice/binding.hpp +++ b/src/lib/advice/binding.hpp @@ -71,11 +71,14 @@ //#include //#include //#include -//#include +#include namespace lib { namespace advice { + using std::string; + + /** * Conjunction of predicates to be matched * against a collaboration partner for establishing @@ -98,6 +101,12 @@ namespace advice { * by adding a predicate according to the * given textual definition */ void addPredicate (Literal spec); + + template + void addTypeGuard(); + + + operator string() const; }; diff --git a/tests/lib/advice/advice-binding-pattern-test.cpp b/tests/lib/advice/advice-binding-pattern-test.cpp index 2ae234883..372c7605e 100644 --- a/tests/lib/advice/advice-binding-pattern-test.cpp +++ b/tests/lib/advice/advice-binding-pattern-test.cpp @@ -32,9 +32,10 @@ //#include "proc/mobject/session/track.hpp" //#include "lib/meta/trait-special.hpp" //#include "lib/util-foreach.hpp" +#include "lib/time.h" //#include "lib/symbol.hpp" -//#include +#include //#include //using lib::test::showSizeof; @@ -47,8 +48,8 @@ //using lib::Symbol; //using lumiera::P; //using std::string; -//using std::cout; -//using std::endl; +using std::cout; +using std::endl; @@ -94,6 +95,31 @@ namespace test { verifyPatternNormalisation() { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + Binding b0, b00; + Binding b1 ("cat1(), cat2()."); + Binding b2 (" cat2 ( ),cat1( ) . "); + + CHECK (b0 == b00); CHECK (b00 == b0); + CHECK (b1 == b2); CHECK (b2 == b1); + + CHECK (b0 != b1); CHECK (b1 != b0); + CHECK (b0 != b2); CHECK (b2 != b0); + + b2.addPredicate("cat1()"); + CHECK (b1 == b2); + b2.addPredicate("cat3(zzz)"); + CHECK (b1 != b2); + + b1.addTypeGuard(); + CHECK (b1 != b2); + b1.addPredicate(" cat3 ( zzz ) "); + CHECK (b1 != b2); + b2.addTypeGuard(); + CHECK (b1 == b2); + + cout << "b0==" << b0 << endl; + cout << "b1==" << b1 << endl; + cout << "b2==" << b2 << endl; #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 } @@ -102,6 +128,15 @@ namespace test { verifyStaticMatch() { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + CHECK ( matches (Binding(), Binding())); + CHECK ( matches (Binding("pred()"), Binding("pred( ) "))); + + CHECK ( matches (Binding("pred(x)"), Binding("pred(x)"))); + CHECK (!matches (Binding("pred()"), Binding("pred(x)"))); + CHECK (!matches (Binding("pred(x)"), Binding("pred(y)"))); + + CHECK ( matches (Binding("pred(x), pred(y)"), Binding("pred(y), pred(x)"))); + CHECK (!matches (Binding("pred(x), pred(y)"), Binding("pred(y), pred(y)"))); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 } From f27024172fd26773a25259c6bb174d81fa361ed6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 12 Apr 2010 05:04:27 +0200 Subject: [PATCH 09/52] Implementation skeleton for advice binding match --- src/lib/advice/binding.cpp | 71 ++++++++ src/lib/advice/binding.hpp | 165 +++++++++++++++--- src/proc/asset/category.hpp | 2 +- .../advice/advice-binding-pattern-test.cpp | 39 ++++- wiki/renderengine.html | 8 +- 5 files changed, 254 insertions(+), 31 deletions(-) create mode 100644 src/lib/advice/binding.cpp diff --git a/src/lib/advice/binding.cpp b/src/lib/advice/binding.cpp new file mode 100644 index 000000000..f3429bacc --- /dev/null +++ b/src/lib/advice/binding.cpp @@ -0,0 +1,71 @@ +/* + Binding - pattern defining a specific attachment to the Advice system + + 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/advice/binding.hpp" + +//#include + + +namespace lib { +namespace advice { + +// using std::tr1::hash; + +// LUMIERA_ERROR_DEFINE (MISSING_INSTANCE, "Existing ID registration without associated instance"); + + + /* ohlolololohaha */ + Binding::Binding () + { + UNIMPLEMENTED ("create a new empty binding"); + } + + Binding::Binding (Literal spec) + { + UNIMPLEMENTED ("parse the spec and create a new binding"); + } + + + void + Binding::addPredicate (Literal spec) + { + UNIMPLEMENTED ("parse the given spec and create an additional predicte, then re-normalise"); + } + + + + Binding::operator string() const + { + UNIMPLEMENTED ("diagnostic string representation of an advice binding"); + } + + + HashVal + Binding::calculateHash() const + { + UNIMPLEMENTED ("calculate the hash for a normalised advice binding"); + } + + + +}} // namespace lib::advice diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp index c1f69914c..79b3face1 100644 --- a/src/lib/advice/binding.hpp +++ b/src/lib/advice/binding.hpp @@ -70,7 +70,7 @@ //#include //#include -//#include +#include #include namespace lib { @@ -78,6 +78,9 @@ namespace advice { using std::string; + typedef size_t HashVal; + + /** * Conjunction of predicates to be matched @@ -87,30 +90,150 @@ namespace advice { */ class Binding { - public: - /** create the empty binding, equivalent to \c true */ - Binding(); - /** create the binding as defined by the given textual definition. - * @note implicit type conversion deliberately intended */ - Binding (Literal spec); - - /*-- Binding is default copyable --*/ - - /** extend the definition of this binding - * by adding a predicate according to the - * given textual definition */ - void addPredicate (Literal spec); - - template - void addTypeGuard(); - - - operator string() const; + public: + /** + * Functor object for matching against another Binding. + * Contains precompiled information necessary for + * determining a match. + */ + class Matcher + { + HashVal bindingHash_; + + + Matcher (HashVal ha) + : bindingHash_(ha) + { } + + friend class Binding; + + + public: + bool matches (Binding const& obi) const; + bool matches (Binding::Matcher const& oma) const; + + friend HashVal hash_value (Matcher const&); + }; + + + + + /** create the empty binding, equivalent to \c true */ + Binding(); + + /** create the binding as defined by the given textual definition. + * @note implicit type conversion deliberately intended */ + Binding (Literal spec); + + /*-- Binding is default copyable --*/ + + /** extend the definition of this binding + * by adding a predicate according to the + * given textual definition */ + void addPredicate (Literal spec); + + template + void addTypeGuard(); + + + Matcher buildMatcher() const; + HashVal calculateHash() const; + + operator string() const; + + + private: + void normalise(); ////TODO necessary?? }; - ////TODO define the hash function here, to be picked up by ADL + inline std::ostream& + operator<< (std::ostream& os, Binding const& bi) + { + return os << string(bi); + } + + template + inline void + Binding::addTypeGuard() + { + UNIMPLEMENTED ("create a new predicate spec to denote that this binding is related to the given advice type"); + } + + + + + /* === equality comparison and matching === */ + + /** bindings are considered equivalent if, after normalisation, + * their respective definitions are identical. + * @note for bindings without variable arguments, equivalence and matching + * always yield the same results. Contrary to this, two bindings with + * some variable arguments could match, without being defined identically. + * For example \c pred(X) matches \c pred(u) or any other binding of the + * form \c pred() + */ + inline bool + operator== (Binding const& b1, Binding const& b2) + { + UNIMPLEMENTED ("equality of bindings, based on term by term comparison"); + } + + inline bool + operator!= (Binding const& b1, Binding const& b2) + { + return ! (b1 == b2); + } + + + inline bool + matches (Binding const& b1, Binding const& b2) + { + return b1.buildMatcher().matches (b2); + } + + inline bool + matches (Binding::Matcher const& m1, Binding::Matcher const& m2) + { + return m1.matches (m2); + } + + + inline Binding::Matcher + Binding::buildMatcher() const + { + return Matcher (this->calculateHash()); + } + + + + /* == access hash values used for matching == */ + + inline bool + Binding::Matcher::matches (Binding const& obi) const + { + return bindingHash_ == obi.calculateHash(); + } + + inline bool + Binding::Matcher::matches (Binding::Matcher const& oma) const + { + return bindingHash_ == hash_value(oma); + } + + inline HashVal + hash_value (Binding::Matcher const& bm) + { + return bm.bindingHash_; + } + + inline HashVal + hash_value (Binding const& bi) + { + return bi.calculateHash(); + } + diff --git a/src/proc/asset/category.hpp b/src/proc/asset/category.hpp index 53ed8e4fa..71a24eac4 100644 --- a/src/proc/asset/category.hpp +++ b/src/proc/asset/category.hpp @@ -102,7 +102,7 @@ namespace asset { inline ostream& - operator<< (ostream& os, const Category& cat) + operator<< (ostream& os, Category const& cat) { return os << string(cat); } diff --git a/tests/lib/advice/advice-binding-pattern-test.cpp b/tests/lib/advice/advice-binding-pattern-test.cpp index 372c7605e..827d050db 100644 --- a/tests/lib/advice/advice-binding-pattern-test.cpp +++ b/tests/lib/advice/advice-binding-pattern-test.cpp @@ -35,6 +35,8 @@ #include "lib/time.h" //#include "lib/symbol.hpp" +//#include +//#include #include //#include @@ -48,6 +50,7 @@ //using lib::Symbol; //using lumiera::P; //using std::string; +//using boost::hash; using std::cout; using std::endl; @@ -87,6 +90,7 @@ namespace test { { verifyPatternNormalisation(); verifyStaticMatch(); + verifyPreparedMatch(); verifyDynamicMatch(); } @@ -94,10 +98,9 @@ namespace test { void verifyPatternNormalisation() { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 Binding b0, b00; Binding b1 ("cat1(), cat2()."); - Binding b2 (" cat2 ( ),cat1( ) . "); + Binding b2 (" cat2 ( ),cat1 . "); CHECK (b0 == b00); CHECK (b00 == b0); CHECK (b1 == b2); CHECK (b2 == b1); @@ -120,14 +123,12 @@ namespace test { cout << "b0==" << b0 << endl; cout << "b1==" << b1 << endl; cout << "b2==" << b2 << endl; -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 } void verifyStaticMatch() { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 CHECK ( matches (Binding(), Binding())); CHECK ( matches (Binding("pred()"), Binding("pred( ) "))); @@ -137,7 +138,35 @@ namespace test { CHECK ( matches (Binding("pred(x), pred(y)"), Binding("pred(y), pred(x)"))); CHECK (!matches (Binding("pred(x), pred(y)"), Binding("pred(y), pred(y)"))); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 + } + + + void + verifyPreparedMatch() + { + Binding b1 ("pred()"); + Binding b2 ("pred"); + Binding b3 ("pred, pred(x)"); + Binding b4 ("pred ( x ) , pred()."); + CHECK ( matches (b1,b2)); + CHECK ( matches (b3,b4)); + + Binding::Matcher bm1 (b1.buildMatcher()); + Binding::Matcher bm2 (b2.buildMatcher()); + Binding::Matcher bm3 (b3.buildMatcher()); + Binding::Matcher bm4 (b4.buildMatcher()); + + CHECK (hash_value(b1) == hash_value(bm1)); + CHECK (hash_value(b2) == hash_value(bm2)); + CHECK (hash_value(b3) == hash_value(bm3)); + CHECK (hash_value(b4) == hash_value(bm4)); + + CHECK (hash_value(b1) != hash_value(b3)); + + CHECK ( matches (bm1,bm2)); + CHECK ( matches (bm3,bm4)); + CHECK (!matches (bm1,bm3)); + CHECK (!matches (bm2,bm4)); } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 346053ef8..fb64d3a2b 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -541,7 +541,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo &rarr; AdviceImplementation
      -
      +
      [<img[Advice solution|uml/fig141573.png]]
       
       
      @@ -550,15 +550,15 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
       
       The advice system is //templated on the advice type// &mdash; so basically there is an independent lookup table for each different kind of advice.The advice system is a sytem wide singleton service, but it is never addressed directly by the participants. Rather, instances of ~AdviceProvision and ~AdviceRequest act as point of access. But these aren't completely symmetric; while the ~AdviceRequest is owned by the advised entity, the ~AdviceProvision is a value object, a uniform holder used to introduce new advice into the system. ~AdviceProvision is copied into an internal buffer and managed by the advice system, as is the actual advice item, which is copied alongside.
       
      -In order to find matches and provide advice solutions, the advice system maintains an index data structure called ''~BindingIndex''. The actual binding predicates are represented by value objects stored within this index table. The matching process is triggered whenever a new possibility for an advice solution enters the system, which could be a new request, a new provision or a change in the specified bindings. A successful match causes a pointer to be set within the ~AdviceRequest, pointing to the ~AdviceProvision acting as solution. Thus, when a solution exists, the advised entity can access the advice value object by dereferencing this pointer. A new advice solution just results in setting a different pointer, which is atomic and doesn't need to be protected by locking. But note, when omitting locking there is no memory barrier; thus the advised might not see a changed advice solution, until the corresponding thread(s) refresh their cpu cache. This might or might not be acceptable, depending on the context, and thus is configurable as policy. Similarily, the handling of default advice is configurable. Usually, advice is a default constructible value object. In this case, when there isn't any advice solution (yet), a pseudo solution holding the default constructed advice value is used to satisfy any advice access by the client (advised entity). The same can be used when the actual ~AdviceProvision gets //retracted.// As an alternative, when this default solution approach doesn't work, we can provide a policy either to throw or to wait blocking &mdash; but this alternative policy is similarily implemented with an //null object// (a placeholder ~AdviceProvision). Anyway, this implementation techinque causes the advice system to collect some advice provisions, bindings and advice objects over time. It should use a pooling custom allocator in the final version. As the number of advisors is expected to be rather small, the storage occupied by these elements, which is effectively blocked until application exit, isn't considered a problem.
      +In order to find matches and provide advice solutions, the advice system maintains an index data structure called ''~BindingIndex''. The actual binding predicates are represented by value objects stored within this index table. The matching process is triggered whenever a new possibility for an advice solution enters the system, which could be a new request, a new provision or a change in the specified bindings. A successful match causes a pointer to be set within the ~AdviceRequest, pointing to the ~AdviceProvision acting as solution. Thus, when a solution exists, the advised entity can access the advice value object by dereferencing this pointer. A new advice solution just results in setting a different pointer, which is atomic and doesn't need to be protected by locking. But note, omitting the locking means there is no memory barrier; thus the advised entity might not see any changed advice solution, until the corresponding thread(s) refresh their CPU cache. This might or might not be acceptable, depending on the context, and thus is configurable as policy. Similarly, the handling of default advice is configurable. Usually, advice is a default constructible value object. In this case, when there isn't any advice solution (yet), a pseudo solution holding the default constructed advice value is used to satisfy any advice access by the client (advised entity). The same can be used when the actual ~AdviceProvision gets //retracted.// As an alternative, when this default solution approach doesn't work, we can provide a policy either to throw or to wait blocking &mdash; but this alternative policy is similarly implemented with an //null object// (a placeholder ~AdviceProvision). Anyway, this implementation technique causes the advice system to collect some advice provisions, bindings and advice objects over time. It should use a pooling custom allocator in the final version. As the number of advisors is expected to be rather small, the storage occupied by these elements, which is effectively blocked until application exit, isn't considered a problem.
       
       !organising the advice solution
       This is the tricky part of the whole advice system implementation. A naive implementation will quickly degenerate in performance, as costs are of order ~AdviceProvisions * ~AdviceRequests * (average number of binding terms). But contrary to the standard solutions for rules based systems (either forward or backward chaining), in this case here always complete binding sets are to be matched, which allows to reduce the effort.
       
       !!!solution idea
      -The binding patterns are organised by //predicate symbol and the lists are normalised.// A simple normalisation could be lexicographic ordering of the predicate symbols. Then the resulting representation can be //hashed.// When all predicates are constant, match can be found by hashtable lookup, otherwise, in case some predicates contain variable arguments ({{red{planned extension}}}), the lookup is followed by an unification.
      +The binding patterns are organised by //predicate symbol and the lists are normalised.// A simple normalisation could be lexicographic ordering of the predicate symbols. Then the resulting representation can be //hashed.// When all predicates are constant, match can be found by hashtable lookup, otherwise, in case some predicates contain variable arguments ({{red{planned extension}}}), the lookup is followed by an unification. For this to work, we'll have to include the arity into the predicate symbols used in the first matching stage. Moreover, we'll create a //matching closure// (functor object), internally holding the arguments for unification. This approach allows for //actual interpretation of the arguments.// It is conceivable that in special cases we'll get multiple instances of the same predicate, just with different arguments. The unification of these terms needs to consider each possible pairwise combination (cartesian product) &mdash; but working out the details of the implementation can safely be deferred until we'll actually hit such a special situation, thanks to the implementation by a functor.
       
      -Yet still we need to store a successful match, together with backlinks, in order to handle changing and retracting of advice.
      +Fortunately, the calculation of this normalised patterns can be separated completely from the actual matching. Indeed, we don't even need to store the binding patterns at all within the binding index &mdash; storing the hash value is sufficient (and in case of patterns with arguments we'll attach the matching closure functor). Yet still we need to store a marker for each successful match, together with back-links, in order to handle changing and retracting of advice.
       
      From f2269b7e7878b71163ac879a4db225f25160a03c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 13 Apr 2010 06:37:21 +0200 Subject: [PATCH 10/52] Implement Advice binding pattern --- src/lib/advice/binding.cpp | 49 ++++- src/lib/advice/binding.hpp | 49 ++++- src/lib/cmdline.cpp | 4 +- src/lib/query.cpp | 8 +- src/lib/query.hpp | 2 +- src/proc/asset.hpp | 8 +- src/proc/mobject/session/defsregistry.hpp | 2 +- tests/42query.tests | 2 +- .../mobject/session/defsregistryimpltest.cpp | 2 +- tests/lib/query/query-utils-test.cpp | 169 +++++++++++++++++ tests/lib/query/queryutilstest.cpp | 172 ------------------ wiki/renderengine.html | 6 +- 12 files changed, 274 insertions(+), 199 deletions(-) create mode 100644 tests/lib/query/query-utils-test.cpp delete mode 100644 tests/lib/query/queryutilstest.cpp diff --git a/src/lib/advice/binding.cpp b/src/lib/advice/binding.cpp index f3429bacc..8944064e4 100644 --- a/src/lib/advice/binding.cpp +++ b/src/lib/advice/binding.cpp @@ -24,6 +24,14 @@ #include "lib/advice/binding.hpp" //#include +#include +#include +#include + +using boost::algorithm::join; +using boost::lexical_cast; + +using boost::hash_combine; namespace lib { @@ -31,39 +39,62 @@ namespace advice { // using std::tr1::hash; -// LUMIERA_ERROR_DEFINE (MISSING_INSTANCE, "Existing ID registration without associated instance"); + + + Binding::Atom::operator string() const + { + return sym_+"/"+lexical_cast (ari_) + +"("+arg_+")"; + } + + + void + Binding::parse_and_append (string def) + { + UNIMPLEMENTED ("do the actual parsing by regexp, create an Atom for each match"); + } - /* ohlolololohaha */ Binding::Binding () - { - UNIMPLEMENTED ("create a new empty binding"); - } + : atoms_() + { } Binding::Binding (Literal spec) { - UNIMPLEMENTED ("parse the spec and create a new binding"); + parse_and_append (spec); } void Binding::addPredicate (Literal spec) { - UNIMPLEMENTED ("parse the given spec and create an additional predicte, then re-normalise"); + parse_and_append (spec); } Binding::operator string() const { - UNIMPLEMENTED ("diagnostic string representation of an advice binding"); + return "Binding[" + join(atoms_, ", ") + "]"; } HashVal Binding::calculateHash() const { - UNIMPLEMENTED ("calculate the hash for a normalised advice binding"); + HashVal hash=0; + + typedef NormalisedAtoms::const_iterator AIter; + AIter pos = atoms_.begin(); + AIter end = atoms_.end(); + for ( ; pos!=end ; ++pos) + { + hash_combine (hash, pos->sym()); + hash_combine (hash, pos->arity()); + hash_combine (hash, pos->arg()); //////////////TODO: not in final version with variable arguments + } + + return hash; } diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp index 79b3face1..84ffcba5e 100644 --- a/src/lib/advice/binding.hpp +++ b/src/lib/advice/binding.hpp @@ -72,6 +72,7 @@ //#include #include #include +#include namespace lib { namespace advice { @@ -91,6 +92,51 @@ namespace advice { class Binding { + /** + * single predicate + * as part of an advice binding pattern + */ + class Atom + { + uint ari_; + string sym_; + string arg_; + + public: + Atom (uint arity, string const& symbol, string const& arg ="") + : ari_(arity) + , sym_(symbol) + , arg_(arg) + { } + + string const& sym() const { return sym_; } + string const& arg() const { return arg_; } + uint arity() const { return ari_; } + + operator string() const; + + int + compare (Atom const& oa) const + { + int res; + if (0 != (res=sym().compare (oi.sym()))) return res; + if (0 != (res=arity() - (oi.arity()))) return res; + return arg().compare (oi.arg()); /////TODO: in the final version, when we'll allow for variable arguments + } ///////// and unification, then variable arguments must not be part of + ///////// the comparison, otherwise the matching by hash will break! + friend bool + operator< (Atom const& a1, Atom const& a2) + { + return a1.compare(a2) < 0; + } + }; + + + typedef std::set NormalisedAtoms; + + NormalisedAtoms atoms_; + + public: /** * Functor object for matching against another Binding. @@ -144,7 +190,8 @@ namespace advice { private: - void normalise(); ////TODO necessary?? + /** internal: parse into atoms, and insert them */ + void parse_and_append (string def); }; diff --git a/src/lib/cmdline.cpp b/src/lib/cmdline.cpp index 89ebc2137..9f4d915ef 100644 --- a/src/lib/cmdline.cpp +++ b/src/lib/cmdline.cpp @@ -47,8 +47,8 @@ using boost::regex_search; #include -namespace util - { +namespace util { + /** create as a tokenised copy of the current commandline. * Note that argv[0] is always ignored. */ diff --git a/src/lib/query.cpp b/src/lib/query.cpp index 931d07ff4..61e376c5e 100644 --- a/src/lib/query.cpp +++ b/src/lib/query.cpp @@ -66,12 +66,12 @@ namespace lumiera { if (is_upper (first)) id[0] = std::tolower (first); } - - namespace // Implementation details - { + + namespace{ // Implementation details + map regexTable; Symbol matchArgument = "\\(\\s*([\\w_\\.\\-]+)\\s*\\),?\\s*"; @@ -128,7 +128,7 @@ namespace lumiera { * probably get for free when we embed a prolog system)... */ uint - countPraed (const string& q) + countPred (const string& q) { uint cnt (0); sregex_iterator end; diff --git a/src/lib/query.hpp b/src/lib/query.hpp index 65eba3869..e43f34724 100644 --- a/src/lib/query.hpp +++ b/src/lib/query.hpp @@ -77,7 +77,7 @@ namespace lumiera { * usable for ordering queries, as more predicates usually * mean more conditions, i.e. more constriction */ - uint countPraed (const string&); + uint countPred (const string&); const string extractID (Symbol, const string& termString); diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index 4fe2aa14c..900877aa4 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -183,7 +183,7 @@ namespace asset { const uint ver=1); - int compare (const Ident& other) const; + int compare (Ident const& other) const; /** @note equality ignores version differences */ bool operator== (Ident const& oi) const { return compare (oi) ==0; } @@ -308,7 +308,7 @@ namespace asset { * forwarded to the Asset comparison operators. * @note version info is irrelevant */ inline int - Asset::Ident::compare (const Asset::Ident& oi) const + Asset::Ident::compare (Asset::Ident const& oi) const { int res; if (0 != (res=category.compare (oi.category))) return res; @@ -320,7 +320,7 @@ namespace asset { /** promote subtype-ptr to PAsset, e.g. for comparing */ template inline const PcAsset - pAsset (const shared_ptr& subPtr) + pAsset (shared_ptr const& subPtr) { return static_pointer_cast (subPtr); } @@ -336,7 +336,7 @@ namespace asset { /** convenient for debugging */ - inline string str (const PcAsset& a) + inline string str (PcAsset const& a) { if (a) return string (*a.get()); diff --git a/src/proc/mobject/session/defsregistry.hpp b/src/proc/mobject/session/defsregistry.hpp index f37f08109..0dc6242c5 100644 --- a/src/proc/mobject/session/defsregistry.hpp +++ b/src/proc/mobject/session/defsregistry.hpp @@ -96,7 +96,7 @@ namespace mobject { weak_ptr objRef; Record (const Query& q, const P& obj) - : degree (lumiera::query::countPraed (q)), + : degree (lumiera::query::countPred (q)), query (q), objRef (obj) { } diff --git a/tests/42query.tests b/tests/42query.tests index 664e2912a..5caf37bb1 100644 --- a/tests/42query.tests +++ b/tests/42query.tests @@ -27,6 +27,6 @@ return: 0 END -TEST "count predicates in query" QueryUtils_test countPraed <instanceID); ASSERT ( ps[qx] == (*j)); - d = lumiera::query::countPraed (qx); + d = lumiera::query::countPred (qx); ASSERT ( d_prev <= d ); d_prev = d; } diff --git a/tests/lib/query/query-utils-test.cpp b/tests/lib/query/query-utils-test.cpp new file mode 100644 index 000000000..07c1403dc --- /dev/null +++ b/tests/lib/query/query-utils-test.cpp @@ -0,0 +1,169 @@ +/* + QueryUtils(Test) - checking various utils provided for dealing with config queries + + 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 "lib/util.hpp" +#include "lib/util-foreach.hpp" + +#include "lib/cmdline.hpp" +#include "lib/query.hpp" +#include "query/querydiagnostics.hpp" + +#include +#include + +using lumiera::Query; +using util::Cmdline; +using util::isnil; +using util::contains; +using util::for_each; + +using std::tr1::placeholders::_1; +using std::tr1::bind; +using std::string; +using std::cout; +using std::endl; + + + +namespace lumiera { +namespace query { +namespace test{ + + + struct Thing + { + virtual ~Thing() {} // add RTTI for Query.asKey(); + }; + + + + /************************************************************************ + * @test check the various small helpers and utilities we utilise + * for dealing with ConfigQuery + */ + class QueryUtils_test : public Test + { + + virtual void + run (Arg arg) + { + if (isnil(arg)) arg = Cmdline ("Query normaliseID extractID removeTerm countPred"); + + if (contains (arg, "Query" )) check_Query (); + if (contains (arg, "normaliseID")) check_normaliseID(); + if (contains (arg, "extractID" )) check_extractID (); + if (contains (arg, "removeTerm" )) check_removeTerm (); + if (contains (arg, "countPred" )) check_countPred (); + } + + + + /** @test Query wrapper class basics */ + void + check_Query () + { + cout << Query ("I am writing a test sentence.").asKey() << endl; + } + + + + /** @test sanitising and normalising various tokens */ + void + check_normaliseID () + { + Cmdline tokens ("a A AA dufte 1a _1 A_A BÄH"); + tokens.push_back (""); + tokens.push_back (" White space "); + tokens.push_back ("§&Ω%€GΩ%€ar ☠☠☠ baäääääge!!!!! "); + + cout << "..original : " << tokens << " :"< - - 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/util.hpp" -#include "lib/util-foreach.hpp" - -#include "lib/cmdline.hpp" -#include "lib/query.hpp" -#include "query/querydiagnostics.hpp" - -#include -#include - -using lumiera::Query; -using util::Cmdline; -using util::isnil; -using util::contains; -using util::for_each; - -using std::tr1::placeholders::_1; -using std::tr1::bind; -using std::string; -using std::cout; - - - -namespace lumiera { - namespace query { - namespace test{ - - - struct Thing - { - virtual ~Thing() {} // add RTTI for Query.asKey(); - }; - - - - /************************************************************************ - * @test check the various small helpers and utilities we utilise - * for dealing with ConfigQuery - */ - class QueryUtils_test : public Test - { - - virtual void - run (Arg arg) - { - if (isnil(arg)) arg = Cmdline ("Query normaliseID extractID removeTerm countPraed"); - - if (contains (arg, "Query" )) check_Query (); - if (contains (arg, "normaliseID")) check_normaliseID (); - if (contains (arg, "extractID" )) check_extractID (); - if (contains (arg, "removeTerm" )) check_removeTerm (); - if (contains (arg, "countPraed" )) check_countPraed (); - } - - - - /** @test Query wrapper class basics */ - void - check_Query () - { - cout << Query ("I am writing a test sentence.").asKey() << "\n"; - } - - - - /** @test sanitising and normalising various tokens */ - void - check_normaliseID () - { - Cmdline tokens ("a A AA dufte 1a _1 A_A BÄH"); - tokens.push_back (""); - tokens.push_back (" White space "); - tokens.push_back ("§&Ω%€GΩ%€ar Ω baäääääge!!!!! "); - - cout << "..original : " << tokens << " :\n"; - - for_each (tokens, bind ( &normaliseID, _1 )); - - cout << "normalised : " << tokens << " :\n"; - } - - - - /** @test the simple regexp extracting a parameter token */ - void - check_extractID () - { - ASSERT ("tok" == extractID ("pred", "pred(tok)." )); - ASSERT ("tok" == extractID ("pred", " pred( tok )" )); - ASSERT ("tok" == extractID ("pred", "pred(tok), pred(tux)." )); - ASSERT ("tok" == extractID ("pred", "other(xyz) pred(tok) pred(tux)" )); - ASSERT ("tok" == extractID ("pred", "some( pred(tok)" )); - - ASSERT (isnil (extractID ("pred", "pred (tok)"))); - ASSERT (isnil (extractID ("pred", "pred tok)" ))); - ASSERT (isnil (extractID ("pred", "pred(tok " ))); - } - - - - /** @test the regexp based cutting of a term with given symbol */ - void - check_removeTerm () - { - // successful------Symbol---input-string----------------------extracted------remaining------------- - ASSERT_removeTerm ("pred", "pred(tok).", "pred(tok)", "." ); - ASSERT_removeTerm ("pred", " pred( tok )", "pred(tok)", " " ); - ASSERT_removeTerm ("pred", "pred(tok), pred(tux).", "pred(tok)", "pred(tux)." ); - ASSERT_removeTerm ("pred", "other(xyz) pred(tok) pred(tux)", "pred(tok)", "other(xyz) pred(tux)" ); - ASSERT_removeTerm ("pred", "some( pred(tok)", "pred(tok)", "some( " ); - - // not successful - ASSERT_removeTerm ("pred", "pred (tok", "", "pred (tok" ); - ASSERT_removeTerm ("pred", "pred tok)", "", "pred tok)" ); - ASSERT_removeTerm ("pred", "pred(tok", "", "pred(tok" ); - } - - void - ASSERT_removeTerm (Symbol sym, string input, string extracted, string modified) - { - ASSERT (extracted == removeTerm (sym, input)); - ASSERT (modified == input); - } - - - - /** @test counting of predicates in a query - * (currently 4/08 regexp based...) - */ - void - check_countPraed () - { - for (uint i=1; i <= 30; ++i) - ASSERT ( i == countPraed (garbage_query (i))); - } - }; - - - /** Register this test class... */ - LAUNCHER (QueryUtils_test, "unit query"); - - - - } // namespace test - - } // namespace query - -} // namespace lumiera diff --git a/wiki/renderengine.html b/wiki/renderengine.html index fb64d3a2b..cbe454ed0 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -514,8 +514,8 @@ ColorPalette SiteUrl
      -
      -
      {{red{WIP 11/09}}}...//about to explicate a pattern which I'm aiming at within the design almost since the beginning//
      +
      +
      //pattern of collaboration for loosely coupled entities, to be used for various purposes within Proc...//
       Expecting Advice and giving Advice &mdash; this collaboration ranges somewhere between messaging and dynamic properties, but cross-cutting the primary, often hierarchical relation of dependencies. Always happening at a certain //point of advice,// which creates a distinct, static nature different of being just a convention, on the other hand, Advice is deliberately kept optional and received synchronously, albeit possibly within an continuation.
       
       !Specification
      @@ -531,7 +531,7 @@ Expecting Advice and giving Advice &mdash; this collaboration ranges somewhe
       * ''advice system''
       * the ''binding''
       * the ''advice''
      -Usually, the ''advised'' entity opens the collaboration by requesting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice collaboration happens at a ''point of advice'', which needs to be derived first. To this end, the advised puts up an request by providing his ''binding'', which is a pattern for matching. An entity about to give advice //opens//&nbsp; possible ''advice channels'' by putting up an advisor binding, which similarly is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' &mdash; allowing the advisor to fed the piece of advice into the advice channel, causing it to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entities. Especially, this involves copying the advice data into a location managed by the advice system. In the standard case, the advised entity accesses the advice synchronously (an non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this collaboration.
      +Usually, the ''advised'' entity opens the collaboration by requesting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice collaboration happens at a ''point of advice'', which needs to be derived first. To this end, two prerequisites are to be fulfilled (without fixed sequence): The advised puts up an ''advice request'' by specifying his ''binding'', which is a pattern for matching. An entity about to give advice attaches a possible ''advice provision'', combined with an advisor binding, which similarly is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' &mdash; allowing the advisor to fed the piece of advice into a kind of communication channel (&raquo;advice channel&laquo;), causing the advice data to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entities. Especially, this involves copying the advice data into a location managed by the advice system. In the standard case, the advised entity picks up the advice synchronously (and non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this collaboration.
       
       !!extensions
       In a more elaborate scheme, the advised entity could provide a signal to be invoked either in the thread context of the advisor (being still blocked in the advice providing call), or in a completely separate thread. A third solution would be to allow the advised entity to block until receiving new advice. Both of these more elaborate schemes would also allow to create an advice queue &mdash; thereby developing the advice collaboration into a kind of messaging system. Following this route seems questionable though.
      
      From 85f8035f928d51e2f7051008108564fb1ddb127e Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Wed, 14 Apr 2010 07:02:40 +0200
      Subject: [PATCH 11/52] Implement parsing of Advice binding pattern spec
      
      ---
       src/lib/advice/binding.cpp                    | 104 ++++++++++++++++--
       src/lib/advice/binding.hpp                    |  49 ++++-----
       src/lib/cmdline.cpp                           |   3 -
       src/lib/query.cpp                             |   2 +-
       src/lib/query.hpp                             |  11 ++
       .../advice/advice-binding-pattern-test.cpp    |  37 ++++++-
       6 files changed, 163 insertions(+), 43 deletions(-)
      
      diff --git a/src/lib/advice/binding.cpp b/src/lib/advice/binding.cpp
      index 8944064e4..94faf762b 100644
      --- a/src/lib/advice/binding.cpp
      +++ b/src/lib/advice/binding.cpp
      @@ -22,15 +22,27 @@
       
       
       #include "lib/advice/binding.hpp"
      +#include "lib/symbol.hpp"
       
       //#include 
       #include 
       #include 
       #include 
      +#include 
      +
      +
      +using lib::Literal;
       
       using boost::algorithm::join;
       using boost::lexical_cast;
       
      +using boost::regex;
      +using boost::smatch;
      +//using boost::regex_search;
      +using boost::sregex_iterator;
      +using boost::match_continuous;
      +
      +
       using boost::hash_combine;
       
       
      @@ -41,19 +53,44 @@ namespace advice {
       
         
         
      -  Binding::Atom::operator string()  const
      -  {
      -    return sym_+"/"+lexical_cast (ari_)
      -               +"("+arg_+")";
      +                                                                      /////////////////////TICKET #613 : centralise generally useful RegExps
      +  namespace{  // Implementation details
      +    
      +    const string matchSym = "(\\w[\\w_\\.\\-]*)";
      +    const string matchArg = "\\(\\s*"+matchSym+"?\\s*\\)"; 
      +    regex findPredicate ("\\s*"+matchSym+"("+matchArg+")?\\s*,?");    ///< \c sym(arg), groups: [symbol, parenthesis, argument symbol]
      +    
      +    /** detect the \em arity of an predicate, as matched by #findPredicate.
      +     *  Currently, we don't really parse predicate logic notation and thus we
      +     *  just distinguish nullary predicates (no argument) and predicates with
      +     *  one single constant argument. */
      +    inline uint
      +    detectArity (smatch const& match)
      +    {
      +      if (!match[2].matched) return 0;  // no parenthesis at all
      +      if (!match[3].matched) return 0;  // empty parenthesis
      +      
      +      // later we could analyse the argument in detail here...
      +      return 1;  // but now we just accept a single constant symbol
      +    }
         }
         
         
         void
      -  Binding::parse_and_append (string def)
      -  {
      -    UNIMPLEMENTED ("do the actual parsing by regexp, create an Atom for each match");
      +  Binding::parse_and_append (Literal lit)
      +  {      
      +    string def(lit);
      +    sregex_iterator end;
      +    sregex_iterator pos (def.begin(),def.end(), findPredicate, 
      +                                                match_continuous);    // continuous: don't allow garbage *not* matched by the RegExp
      +    while (pos != end)
      +      {
      +        smatch match = *pos;
      +        atoms_.insert (Atom (match[1], detectArity(match), match[3]));
      +        ++pos;
      +      }
         }
      -
      +  
         
         Binding::Binding ()
           : atoms_()
      @@ -61,6 +98,7 @@ namespace advice {
         
         Binding::Binding (Literal spec)
         {
      +    REQUIRE (spec);
           parse_and_append (spec);
         }
         
      @@ -68,6 +106,7 @@ namespace advice {
         void
         Binding::addPredicate (Literal spec)
         {
      +    REQUIRE (spec);
           parse_and_append (spec);
         }
       
      @@ -75,7 +114,25 @@ namespace advice {
         
         Binding::operator string()  const
         {
      -    return "Binding[" + join(atoms_, ", ") + "]";
      +    string repr("Binding[");
      +    typedef NormalisedAtoms::const_iterator AIter;
      +    AIter end = atoms_.end();
      +    AIter pos = atoms_.begin();
      +    for ( ; pos!=end ; ++pos)
      +      repr += string(*pos)+", ";
      +    
      +    if (0 < atoms_.size())
      +      repr.resize(repr.size()-2);
      +    
      +    repr += "]";
      +    return repr;
      +  }
      +  
      +  
      +  Binding::Atom::operator string()  const
      +  {
      +    return sym_+"/"+lexical_cast (ari_)
      +               +"("+arg_+")";
         }
         
         
      @@ -98,5 +155,34 @@ namespace advice {
         }
         
         
      +  /** bindings are considered equivalent if, after normalisation,
      +   *  their respective definitions are identical.
      +   *  @note for bindings without variable arguments, equivalence and matching
      +   *        always yield the same results. Contrary to this, two bindings with
      +   *        some variable arguments could match, without being defined identically.
      +   *        For example \c pred(X) matches \c pred(u) or any other binding of the
      +   *        form \c pred()
      +   */
      +  bool
      +  operator== (Binding const& b1, Binding const& b2)
      +  {
      +    if (b1.atoms_.size() != b2.atoms_.size())
      +      return false;
      +    
      +    ASSERT (b1.atoms_.size() == b2.atoms_.size());
      +    
      +    typedef Binding::NormalisedAtoms::const_iterator Iter;
      +    Iter end = b1.atoms_.end();
      +    Iter p1 = b1.atoms_.begin();
      +    Iter p2 = b2.atoms_.begin();
      +    
      +    for ( ; p1!=end;  ++p1, ++p2 )
      +      if (! p1->identical(*p2))
      +        return false;
      +    
      +    return true;
      +  }
      +  
      +  
         
       }} // namespace lib::advice
      diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp
      index 84ffcba5e..9a487ead1 100644
      --- a/src/lib/advice/binding.hpp
      +++ b/src/lib/advice/binding.hpp
      @@ -67,6 +67,7 @@
       //#include "lib/hash-indexed.hpp"
       //#include "lib/util.hpp"
       #include "lib/symbol.hpp"
      +#include "lib/query.hpp"
       
       //#include 
       //#include 
      @@ -103,10 +104,9 @@ namespace advice {
                 string arg_;
                 
               public:
      -          Atom (uint arity, string const& symbol, string const& arg ="")
      -            : ari_(arity)
      -            , sym_(symbol)
      -            , arg_(arg)
      +          explicit
      +          Atom (string const& symbol ="nil", uint arity =0, string const& arg ="")
      +            : ari_(arity), sym_(symbol), arg_(arg)
                   { }
                 
                 string const& sym()  const { return sym_; }
      @@ -115,15 +115,23 @@ namespace advice {
                 
                 operator string()  const;
                 
      +          bool
      +          identical (Atom const& oa)  const
      +            {
      +              return ari_ == oa.ari_
      +                  && sym_ == oa.sym_
      +                  && arg_ == oa.arg_;
      +            }
      +          
                 int 
      -          compare (Atom const& oa)  const
      +          compare (Atom const& oa)  const               ///< @note when #compare returns 0, the corresponding Atom counts as duplicate
                   { 
                     int res;
      -              if (0 != (res=sym().compare (oi.sym())))  return res;
      -              if (0 != (res=arity() - (oi.arity())))    return res;
      -              return arg().compare (oi.arg());                        /////TODO: in the final version, when we'll allow for variable arguments
      -            }                                                         /////////  and unification, then variable arguments must not be part of
      -                                                                      /////////  the comparison, otherwise the matching by hash will break!
      +              if (0 != (res=sym().compare (oa.sym())))  return res;
      +              if (0 != (res=arity() - (oa.arity())))    return res;
      +              return arg().compare (oa.arg());                        /////TODO: in the final version, when we'll allow for variable arguments
      +            }                                                         /////////: and unification, then variable arguments must not be part of
      +                                                                      /////////: the comparison, otherwise the matching by hash will break!
                 friend bool
                 operator< (Atom const& a1, Atom const& a2)
                 {
      @@ -188,10 +196,12 @@ namespace advice {
             
             operator string()  const;
             
      -      
      +      friend bool operator== (Binding const&, Binding const&);
      +    
      +    
           private:
             /** internal: parse into atoms, and insert them */
      -      void parse_and_append (string def);
      +      void parse_and_append (Literal def);
           };
         
         
      @@ -205,7 +215,7 @@ namespace advice {
         inline void
         Binding::addTypeGuard()
         {
      -    UNIMPLEMENTED ("create a new predicate spec to denote that this binding is related to the given advice type");
      +    atoms_.insert (Atom ("advice.type."+lumiera::query::buildTypeID()));
         }
       
         
      @@ -213,19 +223,6 @@ namespace advice {
         
         /* === equality comparison and matching === */
         
      -  /** bindings are considered equivalent if, after normalisation,
      -   *  their respective definitions are identical.
      -   *  @note for bindings without variable arguments, equivalence and matching
      -   *        always yield the same results. Contrary to this, two bindings with
      -   *        some variable arguments could match, without being defined identically.
      -   *        For example \c pred(X) matches \c pred(u) or any other binding of the
      -   *        form \c pred()
      -   */
      -  inline bool
      -  operator== (Binding const& b1, Binding const& b2)
      -  {
      -    UNIMPLEMENTED ("equality of bindings, based on term by term comparison");
      -  }
         
         inline bool
         operator!= (Binding const& b1, Binding const& b2)
      diff --git a/src/lib/cmdline.cpp b/src/lib/cmdline.cpp
      index 9f4d915ef..90335230e 100644
      --- a/src/lib/cmdline.cpp
      +++ b/src/lib/cmdline.cpp
      @@ -35,9 +35,6 @@ using boost::algorithm::split;
       using boost::algorithm::join;
       using boost::algorithm::is_any_of;
       using boost::algorithm::token_compress_on;
      -using boost::regex;
      -using boost::smatch;
      -using boost::regex_search;
       
       using boost::regex;
       using boost::smatch;
      diff --git a/src/lib/query.cpp b/src/lib/query.cpp
      index 61e376c5e..ab143cd0b 100644
      --- a/src/lib/query.cpp
      +++ b/src/lib/query.cpp
      @@ -69,7 +69,7 @@ namespace lumiera {
           
           
           
      -    
      +                                                                          //////////////////////TICKET #613 : centralise generally useful RegExps
           namespace{  // Implementation details
             
             map regexTable;
      diff --git a/src/lib/query.hpp b/src/lib/query.hpp
      index e43f34724..99bba9ec9 100644
      --- a/src/lib/query.hpp
      +++ b/src/lib/query.hpp
      @@ -85,5 +85,16 @@ namespace lumiera {
           const string removeTerm (Symbol, string& termString);
           
           
      +    template
      +    const string
      +    buildTypeID()
      +    {
      +      string typeID (typeid(TY).name());
      +      normaliseID (typeID);
      +      return typeID;
      +    }
      +    
      +    
      +    
       }} // namespace lumiera::query
       #endif
      diff --git a/tests/lib/advice/advice-binding-pattern-test.cpp b/tests/lib/advice/advice-binding-pattern-test.cpp
      index 827d050db..61f1f06e1 100644
      --- a/tests/lib/advice/advice-binding-pattern-test.cpp
      +++ b/tests/lib/advice/advice-binding-pattern-test.cpp
      @@ -88,6 +88,7 @@ namespace test {
             virtual void
             run (Arg)
               {
      +          verifyPatternSyntax();
                 verifyPatternNormalisation();
                 verifyStaticMatch();
                 verifyPreparedMatch();
      @@ -95,12 +96,42 @@ namespace test {
               }
             
             
      +      void
      +      verifyPatternSyntax()
      +        {
      +#define _PARSE_AND_SHOW(_STR_) \
      +          cout << _STR_ << "\t--->" << Binding(_STR_) << endl;
      +          
      +          _PARSE_AND_SHOW ("");
      +          _PARSE_AND_SHOW ("aSymbol");
      +          _PARSE_AND_SHOW ("aSymbol followed by Garbage : §&Ω%€GΩ%€ar☠☠☠baäääääge");
      +          _PARSE_AND_SHOW ("§&Ω%€GΩ%€ar☠☠☠baäääääge");
      +          _PARSE_AND_SHOW ("a, list , of ,symbols.");
      +          _PARSE_AND_SHOW ("nullary().");
      +          _PARSE_AND_SHOW ("nullary( )");
      +          _PARSE_AND_SHOW ("nothing ()");
      +          _PARSE_AND_SHOW ("predicate( with-argument )");
      +          _PARSE_AND_SHOW ("no( valid definition here)");
      +          
      +          Binding testBinding;
      +          testBinding.addTypeGuard();
      +          testBinding.addPredicate("one two(), three( four ).");
      +          
      +          cout << testBinding << endl;
      +        }
      +      
      +      
             void
             verifyPatternNormalisation()
               {
                 Binding b0, b00;
                 Binding b1 ("cat1(), cat2().");
      -          Binding b2 ("  cat2 (  ),cat1 . ");
      +          Binding b2 ("  cat2(  ) cat1  ****");
      +          
      +          cout << "b0==" << b0 << endl;
      +          cout << "b1==" << b1 << endl;
      +          cout << "b2==" << b2 << endl;
      +          
                 
                 CHECK (b0 == b00); CHECK (b00 == b0);
                 CHECK (b1 == b2);  CHECK (b2 == b1);
      @@ -115,13 +146,11 @@ namespace test {
                 
                 b1.addTypeGuard();
                 CHECK (b1 != b2);
      -          b1.addPredicate(" cat3 (  zzz   )  ");
      +          b1.addPredicate(" cat3(  zzz   )  ");
                 CHECK (b1 != b2);
                 b2.addTypeGuard();
                 CHECK (b1 == b2);
                 
      -          cout << "b0==" << b0 << endl;
      -          cout << "b1==" << b1 << endl;
                 cout << "b2==" << b2 << endl;
               }
             
      
      From 1e28c7f1abb02caf7b9f28aa07470c61e9969419 Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Thu, 15 Apr 2010 05:53:59 +0200
      Subject: [PATCH 12/52] get the advice binding unit test to pass thus far
      
      ---
       src/lib/advice/binding.cpp                    | 20 ++-----
       src/lib/advice/binding.hpp                    | 32 +++++-----
       tests/40components.tests                      | 15 +++++
       .../advice/advice-binding-pattern-test.cpp    | 60 ++++++++-----------
       4 files changed, 62 insertions(+), 65 deletions(-)
      
      diff --git a/src/lib/advice/binding.cpp b/src/lib/advice/binding.cpp
      index 94faf762b..9500b8a50 100644
      --- a/src/lib/advice/binding.cpp
      +++ b/src/lib/advice/binding.cpp
      @@ -24,33 +24,25 @@
       #include "lib/advice/binding.hpp"
       #include "lib/symbol.hpp"
       
      -//#include 
       #include 
      -#include 
       #include 
       #include 
       
       
       using lib::Literal;
       
      -using boost::algorithm::join;
      -using boost::lexical_cast;
      -
       using boost::regex;
       using boost::smatch;
      -//using boost::regex_search;
       using boost::sregex_iterator;
       using boost::match_continuous;
      -
      -
       using boost::hash_combine;
      +using boost::lexical_cast;
       
       
       namespace lib {
       namespace advice {
      -
      -//  using std::tr1::hash;
      -
      +  
      +  
         
         
                                                                             /////////////////////TICKET #613 : centralise generally useful RegExps
      @@ -109,8 +101,8 @@ namespace advice {
           REQUIRE (spec);
           parse_and_append (spec);
         }
      -
      -
      +  
      +  
         
         Binding::operator string()  const
         {
      @@ -148,7 +140,7 @@ namespace advice {
             {
               hash_combine (hash, pos->sym());
               hash_combine (hash, pos->arity());
      -        hash_combine (hash, pos->arg());              //////////////TODO: not in final version with variable arguments
      +        hash_combine (hash, pos->arg());              //////////////TICKET #615 : not in final version with variable arguments
             }
           
           return hash;
      diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp
      index 9a487ead1..428caeb41 100644
      --- a/src/lib/advice/binding.hpp
      +++ b/src/lib/advice/binding.hpp
      @@ -62,15 +62,9 @@
       
       
       #include "lib/error.hpp"
      -//#include "proc/asset.hpp"
      -//#include "proc/asset/struct-scheme.hpp"
      -//#include "lib/hash-indexed.hpp"
      -//#include "lib/util.hpp"
       #include "lib/symbol.hpp"
       #include "lib/query.hpp"
       
      -//#include 
      -//#include 
       #include 
       #include 
       #include 
      @@ -87,13 +81,17 @@ namespace advice {
         /**
          * Conjunction of predicates to be matched
          * against a collaboration partner for establishing
      -   * an Advice connection.
      +   * an Advice connection. The binding is defined by a
      +   * textual spec in prolog-like syntax. The internal
      +   * representation is immediately \em normalised.
      +   * Typically the goal is just to create a #Matcher
      +   * (Functor) to be stored for later match checks
          * TODO type comment
          */
         class Binding
           {
             
      -      /** 
      +      /**
              *  single predicate
              *  as part of an advice binding pattern
              */
      @@ -123,9 +121,9 @@ namespace advice {
                         && arg_ == oa.arg_;
                   }
                 
      -          int 
      +          int
                 compare (Atom const& oa)  const               ///< @note when #compare returns 0, the corresponding Atom counts as duplicate
      -            { 
      +            {
                     int res;
                     if (0 != (res=sym().compare (oa.sym())))  return res;
                     if (0 != (res=arity() - (oa.arity())))    return res;
      @@ -146,7 +144,7 @@ namespace advice {
             
             
           public:
      -      /** 
      +      /**
              * Functor object for matching against another Binding.
              * Contains precompiled information necessary for
              * determining a match.
      @@ -175,7 +173,7 @@ namespace advice {
             
             /** create the empty binding, equivalent to \c true */
             Binding();
      -    
      +      
             /** create the binding as defined by the given textual definition.
              *  @note implicit type conversion deliberately intended */
             Binding (Literal spec);
      @@ -197,8 +195,8 @@ namespace advice {
             operator string()  const;
             
             friend bool operator== (Binding const&, Binding const&);
      -    
      -    
      +      
      +      
           private:
             /** internal: parse into atoms, and insert them */
             void parse_and_append (Literal def);
      @@ -208,16 +206,16 @@ namespace advice {
         inline std::ostream&
         operator<< (std::ostream& os, Binding const& bi)
         {
      -    return os << string(bi); 
      +    return os << string(bi);
         }
      -      
      +  
         template
         inline void
         Binding::addTypeGuard()
         {
           atoms_.insert (Atom ("advice.type."+lumiera::query::buildTypeID()));
         }
      -
      +  
         
         
         
      diff --git a/tests/40components.tests b/tests/40components.tests
      index ff99224f0..38a3e34eb 100644
      --- a/tests/40components.tests
      +++ b/tests/40components.tests
      @@ -39,6 +39,21 @@ END
       
       
       PLANNED "Advice binding patterns" AdviceBindingPattern_test <Binding[]
      +out: aSymbol	--->Binding[aSymbol/0()]
      +out: aSymbol followed by Garbage §&Ω%€GΩ%€ar☠☠☠bäaäääge	--->Binding[Garbage/0(), aSymbol/0(), by/0(), followed/0()]
      +out: §&Ω%€GΩ%€ar☠☠☠baäääääge	--->Binding[]
      +out: a, list , of ,symbols.	--->Binding[a/0(), list/0(), of/0(), symbols./0()]
      +out: nullary().	--->Binding[nullary/0()]
      +out: nullary( )	--->Binding[nullary/0()]
      +out: nothing ()	--->Binding[nothing/0()]
      +out: predicate( with-argument )	--->Binding[predicate/1(with-argument)]
      +out: no (valid definition here)	--->Binding[no/0()]
      +out: Binding[advice.type.n3lib6advice4test12_GLOBAL__N_111DummyAdviceE/0(), one/0(), three/1(four), two/0()]
      +out: b0==Binding[]
      +out: b1==Binding[cat1/0(), cat2/0()]
      +out: b2==Binding[cat1/0(), cat2/0()]
      +out: b2==Binding[advice.type.n7lumiera4TimeE/0(), cat1/0(), cat2/0(), cat3/1(zzz)]
       return: 0
       END
       
      diff --git a/tests/lib/advice/advice-binding-pattern-test.cpp b/tests/lib/advice/advice-binding-pattern-test.cpp
      index 61f1f06e1..392a2737f 100644
      --- a/tests/lib/advice/advice-binding-pattern-test.cpp
      +++ b/tests/lib/advice/advice-binding-pattern-test.cpp
      @@ -22,45 +22,23 @@
       
       
       #include "lib/test/run.hpp"
      -//#include "lib/test/test-helper.hpp"
       
       #include "lib/advice.hpp"
      -//#include "lib/p.hpp"
      -//#include "proc/assetmanager.hpp"
      -//#include "proc/asset/inventory.hpp"
      -//#include "proc/mobject/session/clip.hpp"
      -//#include "proc/mobject/session/track.hpp"
      -//#include "lib/meta/trait-special.hpp"
      -//#include "lib/util-foreach.hpp"
       #include "lib/time.h"
      -//#include "lib/symbol.hpp"
       
      -//#include 
      -//#include 
       #include 
      -//#include 
       
      -//using lib::test::showSizeof;
      -//using lib::test::randStr;
      -//using util::isSameObject;
      -//using util::and_all;
      -//using util::for_each;
      -//using util::isnil;
      -//using lib::Literal;
      -//using lib::Symbol;
      -//using lumiera::P;
      -//using std::string;
      -//using boost::hash;
       using std::cout;
       using std::endl;
       
       
       
      -namespace lib {
      -namespace advice {
      -namespace test {
      +namespace lib   {
      +namespace advice{
      +namespace test  {
         
         namespace {
      +    class DummyAdvice { };
         }
         
         
      @@ -104,17 +82,17 @@ namespace test {
                 
                 _PARSE_AND_SHOW ("");
                 _PARSE_AND_SHOW ("aSymbol");
      -          _PARSE_AND_SHOW ("aSymbol followed by Garbage : §&Ω%€GΩ%€ar☠☠☠baäääääge");
      +          _PARSE_AND_SHOW ("aSymbol followed by Garbage §&Ω%€GΩ%€ar☠☠☠bäaäääge");
                 _PARSE_AND_SHOW ("§&Ω%€GΩ%€ar☠☠☠baäääääge");
                 _PARSE_AND_SHOW ("a, list , of ,symbols.");
                 _PARSE_AND_SHOW ("nullary().");
                 _PARSE_AND_SHOW ("nullary( )");
                 _PARSE_AND_SHOW ("nothing ()");
                 _PARSE_AND_SHOW ("predicate( with-argument )");
      -          _PARSE_AND_SHOW ("no( valid definition here)");
      +          _PARSE_AND_SHOW ("no (valid definition here)");
                 
                 Binding testBinding;
      -          testBinding.addTypeGuard();
      +          testBinding.addTypeGuard();
                 testBinding.addPredicate("one two(), three( four ).");
                 
                 cout << testBinding << endl;
      @@ -126,7 +104,7 @@ namespace test {
               {
                 Binding b0, b00;
                 Binding b1 ("cat1(), cat2().");
      -          Binding b2 ("  cat2(  ) cat1  ****");
      +          Binding b2 (" cat2 cat1  ***");
                 
                 cout << "b0==" << b0 << endl;
                 cout << "b1==" << b1 << endl;
      @@ -176,7 +154,7 @@ namespace test {
                 Binding b1 ("pred()");
                 Binding b2 ("pred");
                 Binding b3 ("pred, pred(x)");
      -          Binding b4 ("pred ( x ) , pred().");
      +          Binding b4 ("pred( x ) , pred().");
                 CHECK ( matches (b1,b2));
                 CHECK ( matches (b3,b4));
                 
      @@ -201,13 +179,27 @@ namespace test {
             
             /** @test match against patterns containing variables,
              *        verify the created solution arguments
      -       *  @todo this is a future extension
      +       *  @todo this is a future extension and its not clear
      +       *        if we need it and what the exact semantics
      +       *        could be  ///////////////////////////////TICKET #615
              */
             void
             verifyDynamicMatch()
               {
      -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605
      -#endif    /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605
      +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #615
      +          CHECK ( matches (Binding("pred(u)"), Binding("pred(X)")));
      +          CHECK ( matches (Binding("pred(f(u))"), Binding("pred(f(X))")));
      +          CHECK ( matches (Binding("pred(f(u,Y))"), Binding("pred(f(X,v))")));
      +          CHECK ( matches (Binding("pred(f(u,X))"), Binding("pred(f(X,v))")));   // the so called "standardisation apart"
      +          
      +          CHECK (!matches (Binding("pred(u,v)"), Binding("pred(X)")));
      +          CHECK (!matches (Binding("pred(f(u))"), Binding("pred(f(v))")));
      +          CHECK (!matches (Binding("pred(f(u))"), Binding("pred(g(X))")));
      +          CHECK (!matches (Binding("pred(f(u,v))"), Binding("pred(f(X,X))")));
      +          
      +          //////TODO should also cover the difference between equality and match, which gets tangible only in conjunction with variables
      +          
      +#endif    /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #615
               }
           };
         
      
      From 6bc78064d1db2d7704c14f3de7e0f0cd9e32d398 Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Fri, 16 Apr 2010 02:17:15 +0200
      Subject: [PATCH 13/52] SCons: improve dependency handling for the testsuite
      
      ---
       tests/SConscript | 30 +++++++++++++++++-------------
       1 file changed, 17 insertions(+), 13 deletions(-)
      
      diff --git a/tests/SConscript b/tests/SConscript
      index 516aa3f2a..fc0fba7e8 100644
      --- a/tests/SConscript
      +++ b/tests/SConscript
      @@ -5,6 +5,8 @@
       
       import os
       from os import path
      +from glob import glob
      +
       from Buildhelper import srcSubtree
       from Buildhelper import scanSubtree
       from Buildhelper import globRootdirs
      @@ -55,11 +57,12 @@ moduledirs = globRootdirs('*')
       
       
       
      -artifacts['testsuite'] = ts = ( [ testExecutable(env, dir) for dir in ['lib','components'] ] 
      +artifacts['testsuite'] = ts = ( [ testExecutable(env, dir) for dir in ['lib','components'] ]
                                     + [ testCollection(env, dir) for dir in moduledirs if not dir in specials]
                                     + createPlugins(envPlu, 'plugin')
      -                              ) 
      -                              
      +                              + env.File(glob('*.tests'))     # depending on the test definition files for test.sh
      +                              )
      +
       
       
       
      @@ -74,8 +77,9 @@ Depends(ts,vgsuppr)
       #
       #  - the product of running the Testsuite is the ",testlog"
       #  - it depends on all artifacts defined as "ts" above
      -#  - if not set via options switch, the environment variable TESTSUITES
      -#    is explicitly propagated to test.sh
      +#  - including the tests/*.tests (suite definition files)
      +#  - if not set via options switch, the environment variables
      +#    TESTSUITES and VALGRINDFLAGS are explicitly propagated to test.sh
       #
       testEnv = env.Clone()
       
      @@ -84,25 +88,25 @@ if not valgrind and not env['VALGRIND']:
           valgrind = 'DISABLE'
       
       testEnv.Append(ENV = { 'VALGRINDFLAGS' : valgrind
      -                     , 'LUMIERA_CONFIG_PATH' : './' 
      +                     , 'LUMIERA_CONFIG_PATH' : './'
                            })
      -    
      +
       testsuites = env['TESTSUITES'] or os.environ.get('TESTSUITES')
       if testsuites:
      -    testEnv['ENV']['TESTSUITES'] = testsuites 
      +    testEnv['ENV']['TESTSUITES'] = testsuites
           
       pluginpath = os.environ.get('LUMIERA_PLUGIN_PATH')
       if testsuites:
      -    testEnv['ENV']['LUMIERA_PLUGIN_PATH'] = pluginpath 
      +    testEnv['ENV']['LUMIERA_PLUGIN_PATH'] = pluginpath
       
       # specify path to test.conf
      -testEnv['ENV']['TEST_CONF'] = env.File("test.conf").abspath 
      +testEnv['ENV']['TEST_CONF'] = env.File("test.conf").abspath
      +
       
      - 
       testDir = env.Dir('#$BINDIR')
       runTest = env.File("test.sh").abspath
       
      -runTs = testEnv.Command(',testlog', ts, runTest,  chdir=testDir)
      +runTs = testEnv.Command('#$BINDIR/,testlog', ts, runTest,  chdir=testDir)
       
       
       
      @@ -115,4 +119,4 @@ env.Alias('testcode', ts )
       env.Alias('check', runTs )
       
       # allow tempfiles of test.sh to be cleaned  
      -env.Clean ('check', [',testlog.pre',',expect_stdout',',stdout',',stderr',',testtmp','.libs']) 
      +env.Clean ('check', [',testlog',',testlog.pre',',expect_stdout',',stdout',',stderr',',testtmp','.libs'])
      
      From 0514c24487f3822812e3faadc6684448263d7886 Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Fri, 16 Apr 2010 04:28:02 +0200
      Subject: [PATCH 14/52] Advice binding pattern finished, passing unit test now
       detecting a lot of syntax errors
      
      ---
       src/lib/advice/binding.cpp                    | 20 ++++++++---
       src/lib/advice/binding.hpp                    | 27 +++++++++++----
       tests/40components.tests                      | 33 +++++++++----------
       tests/42query.tests                           |  4 +--
       .../advice/advice-binding-pattern-test.cpp    | 14 +++++---
       5 files changed, 64 insertions(+), 34 deletions(-)
      
      diff --git a/src/lib/advice/binding.cpp b/src/lib/advice/binding.cpp
      index 9500b8a50..4a8d35d29 100644
      --- a/src/lib/advice/binding.cpp
      +++ b/src/lib/advice/binding.cpp
      @@ -42,13 +42,16 @@ using boost::lexical_cast;
       namespace lib {
       namespace advice {
         
      +  LUMIERA_ERROR_DEFINE (BINDING_PATTERN_SYNTAX, "Unable to parse the given binding pattern definition");
      +  
      +  
         
         
         
                                                                             /////////////////////TICKET #613 : centralise generally useful RegExps
         namespace{  // Implementation details
           
      -    const string matchSym = "(\\w[\\w_\\.\\-]*)";
      +    const string matchSym = "(\\w+(?:[\\.\\-]\\w+)*)";
           const string matchArg = "\\(\\s*"+matchSym+"?\\s*\\)"; 
           regex findPredicate ("\\s*"+matchSym+"("+matchArg+")?\\s*,?");    ///< \c sym(arg), groups: [symbol, parenthesis, argument symbol]
           
      @@ -72,6 +75,8 @@ namespace advice {
         Binding::parse_and_append (Literal lit)
         {      
           string def(lit);
      +    string::const_iterator end_of_last_match = def.begin();
      +    
           sregex_iterator end;
           sregex_iterator pos (def.begin(),def.end(), findPredicate, 
                                                       match_continuous);    // continuous: don't allow garbage *not* matched by the RegExp
      @@ -79,8 +84,15 @@ namespace advice {
             {
               smatch match = *pos;
               atoms_.insert (Atom (match[1], detectArity(match), match[3]));
      +        end_of_last_match = match[0].second;
               ++pos;
             }
      +    
      +    if (  end_of_last_match !=def.end()
      +       && *end_of_last_match !='.'
      +       ) // if the match did *not stop at the end of the pattern definition list 
      +      throw lumiera::error::Invalid ("Trailing garbage in binding pattern definition"                 ///////////////TICKET #197  should include the garbage, i.e. where the parsing stops
      +                                    , LUMIERA_ERROR_BINDING_PATTERN_SYNTAX);
         }
         
         
      @@ -147,13 +159,13 @@ namespace advice {
         }
         
         
      -  /** bindings are considered equivalent if, after normalisation,
      -   *  their respective definitions are identical.
      +  /** bindings are considered equivalent if,
      +   *  after normalisation, their respective definitions are identical.
          *  @note for bindings without variable arguments, equivalence and matching
          *        always yield the same results. Contrary to this, two bindings with
          *        some variable arguments could match, without being defined identically.
          *        For example \c pred(X) matches \c pred(u) or any other binding of the
      -   *        form \c pred()
      +   *        form \c pred()  ////TICKET #615 not yet implemented
          */
         bool
         operator== (Binding const& b1, Binding const& b2)
      diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp
      index 428caeb41..c73378c31 100644
      --- a/src/lib/advice/binding.hpp
      +++ b/src/lib/advice/binding.hpp
      @@ -27,10 +27,10 @@
        ** against a similar pattern associated with the attachment of a possible collaboration partner.
        ** Semantically, this list of atoms forms an conjunction of predicates to be resolved against 
        ** similar predicates of the partner. Informally, when two entities attach to the Advice system,
      - ** each specifying a binding, they can be paired up if, when combining, the expressions in their
      - ** bindings all evaluate to true.
      + ** each specifying a binding, they can be paired up if any condition included into the binding
      + ** holds true for both sides.
        ** 
      - ** Typically, a binding includes a \em type-guard predicate \c adviceType(xx) where \c xx is an 
      + ** Typically, a binding includes a \em type-guard predicate \c advice.type.xx where \c xx is an 
        ** identifier denoting a type used within an instantiation of the Advice collaboration, i.e. a type
        ** used as advice value in a instantiation of the PointOfAdvice template. Besides the type guard,
        ** a binding may narrow down the topic of the advice by providing further predicates. This allows for
      @@ -41,14 +41,27 @@
        ** the advice type, and another client entity (the advised entity) could pick up this value
        ** without the need to now anything about the advisor.
        ** 
      - ** Any binding can be normalised into a hash value, which plays a crucial role within the
      - ** implementation of the advice system.
      + ** \par implementation notes
      + ** Any binding will be normalised prior to further processing. This normalisation is based
      + ** on ordering by predicate symbol and arity. Patterns just comprised of constant symbols
      + ** (nullary atoms) can even be condensed into a single hash value, which allows for fast
      + ** match checking. For each pattern, we provide a matcher functor, allowing to check
      + ** a match against this pattern. In case of the mentioned symbol-only patterns,
      + ** this matcher will just hold the hash value of the normalised pattern.
        ** 
      - ** TODO WIP-WIP
      + ** The advice system uses a binding index datastructure to keep track of any participating
      + ** patterns and especially of the matching pairs. Actually, this datastructure needs to store
      + ** only these matcher functors; thus, for a new binding to be used within the advice system,
      + ** the symbolic definition is parsed, then normalised and finally, after creating the matcher
      + ** functor, the full pattern definition can be discarded.
        ** 
        ** @note as of 4/2010 this is an experimental setup and implemented just enough to work out
        **       the interfaces. Ichthyo expects this collaboration service to play a central role
        **       at various places within proc-layer.
      + ** @todo for now, \em only the case of a completely constant (ground) pattern is implemented.
      + **       Later we may consider to extend the binding patterns to allow variables, which, on match
      + **       could be fed as parameters to the bound advice. But this extension requires to extend
      + **       the simple hash-based match check to an actual unification of the patterns. ///TICKET #615
        ** 
        ** @see configrules.hpp
        ** @see typed-lookup.cpp corresponding implementation
      @@ -76,6 +89,8 @@ namespace advice {
         
         typedef size_t HashVal;
         
      +  LUMIERA_ERROR_DECLARE (BINDING_PATTERN_SYNTAX); ///< Unable to parse the given binding pattern definition
      +  
         
         
         /**
      diff --git a/tests/40components.tests b/tests/40components.tests
      index 38a3e34eb..d8719d0db 100644
      --- a/tests/40components.tests
      +++ b/tests/40components.tests
      @@ -3,7 +3,7 @@ TESTING "Component Test Suite: common and basic components" ./test-lib --group=c
       
       
       TEST "Hello test world" HelloWorld_test 3 <Binding[]
      -out: aSymbol	--->Binding[aSymbol/0()]
      -out: aSymbol followed by Garbage §&Ω%€GΩ%€ar☠☠☠bäaäääge	--->Binding[Garbage/0(), aSymbol/0(), by/0(), followed/0()]
      -out: §&Ω%€GΩ%€ar☠☠☠baäääääge	--->Binding[]
      -out: a, list , of ,symbols.	--->Binding[a/0(), list/0(), of/0(), symbols./0()]
      -out: nullary().	--->Binding[nullary/0()]
      -out: nullary( )	--->Binding[nullary/0()]
      -out: nothing ()	--->Binding[nothing/0()]
      -out: predicate( with-argument )	--->Binding[predicate/1(with-argument)]
      -out: no (valid definition here)	--->Binding[no/0()]
      -out: Binding[advice.type.n3lib6advice4test12_GLOBAL__N_111DummyAdviceE/0(), one/0(), three/1(four), two/0()]
      -out: b0==Binding[]
      -out: b1==Binding[cat1/0(), cat2/0()]
      -out: b2==Binding[cat1/0(), cat2/0()]
      -out: b2==Binding[advice.type.n7lumiera4TimeE/0(), cat1/0(), cat2/0(), cat3/1(zzz)]
      +TEST "Advice binding patterns" AdviceBindingPattern_test <Binding[]
      +out-lit: aSymbol	--->Binding[aSymbol/0()]
      +out-lit: a.compound_Symbol-with-various.parts	--->Binding[a.compound_Symbol-with-various.parts/0()]
      +out-lit: trailing Garbage allowed. ☢☢ eat ☠☠☠ atomic ☠☠☠ waste ☢☢	--->Binding[Garbage/0(), allowed/0(), trailing/0()]
      +out-lit: a, list , of ,symbols.	--->Binding[a/0(), list/0(), of/0(), symbols/0()]
      +out-lit: nullary().	--->Binding[nullary/0()]
      +out-lit: nullary( )	--->Binding[nullary/0()]
      +out-lit: nullary  .	--->Binding[nullary/0()]
      +out-lit: predicate( with-argument )	--->Binding[predicate/1(with-argument)]
      +out-lit: Binding[advice.type.n3lib6advice4test12_GLOBAL__N_111DummyAdviceE/0(), one/0(), three/1(four), two/0()]
      +out-lit: b0==Binding[]
      +out-lit: b1==Binding[cat1/0(), cat2/0()]
      +out-lit: b2==Binding[cat1/0(), cat2/0()]
      +out-lit: b2==Binding[advice.type.n7lumiera4TimeE/0(), cat1/0(), cat2/0(), cat3/1(zzz)]
       return: 0
       END
       
      diff --git a/tests/42query.tests b/tests/42query.tests
      index 5caf37bb1..98983c3b0 100644
      --- a/tests/42query.tests
      +++ b/tests/42query.tests
      @@ -12,8 +12,8 @@ END
       
       
       TEST "normalise ID" QueryUtils_test  normaliseID  <();
      @@ -104,7 +108,7 @@ namespace test  {
               {
                 Binding b0, b00;
                 Binding b1 ("cat1(), cat2().");
      -          Binding b2 (" cat2 cat1  ***");
      +          Binding b2 (" cat2 cat1 ....");
                 
                 cout << "b0==" << b0 << endl;
                 cout << "b1==" << b1 << endl;
      
      From 5b48b9f864d683abc69719f4350461cda7bdb4f5 Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Sat, 17 Apr 2010 01:56:14 +0200
      Subject: [PATCH 15/52] fix a regression regarding struct-asset naming scheme
      
      ---
       src/proc/asset/entry-id.hpp            |  6 +-
       src/proc/asset/struct-factory-impl.hpp |  8 +--
       src/proc/asset/struct-scheme.hpp       | 90 +++++++++++++++++---------
       src/proc/asset/struct.cpp              | 35 ----------
       tests/42query.tests                    |  2 +-
       tests/lib/query/query-utils-test.cpp   |  2 +-
       wiki/renderengine.html                 |  4 +-
       7 files changed, 72 insertions(+), 75 deletions(-)
      
      diff --git a/src/proc/asset/entry-id.hpp b/src/proc/asset/entry-id.hpp
      index 451000931..3f736892e 100644
      --- a/src/proc/asset/entry-id.hpp
      +++ b/src/proc/asset/entry-id.hpp
      @@ -202,14 +202,14 @@ namespace asset {
             Asset::Ident
             getIdent()  const
               {
      -          Category cat (STRUCT, idi::StructTraits::catFolder);
      +          Category cat (STRUCT, idi::StructTraits::catFolder());
                 return Asset::Ident (this->getSym(), cat);
               }
             
             static idi::HashVal
             getTypeHash()
               {
      -          return hash_value (Category (STRUCT, idi::StructTraits::catFolder));
      +          return hash_value (Category (STRUCT, idi::StructTraits::catFolder()));
               }
             
             
      @@ -237,7 +237,7 @@ namespace asset {
             
             operator string ()  const
               {
      -          return "ID<"+idi::StructTraits::idSymbol+">-"+EntryID::getSym();
      +          return "ID<"+idi::StructTraits::idSymbol()+">-"+EntryID::getSym();
               }
             
             friend ostream& operator<<   (ostream& os, EntryID const& id) { return os << string(id); }
      diff --git a/src/proc/asset/struct-factory-impl.hpp b/src/proc/asset/struct-factory-impl.hpp
      index 0fe969261..82050fc5e 100644
      --- a/src/proc/asset/struct-factory-impl.hpp
      +++ b/src/proc/asset/struct-factory-impl.hpp
      @@ -99,7 +99,7 @@ namespace asset {
                 // does the query somehow specify the desired name-ID?
                 string nameID = extractID (genericIdSymbol, query);
                 if (isnil (nameID))
      -            nameID = extractID (StructTraits::idSymbol, query);
      +            nameID = extractID (StructTraits::idSymbol(), query);
                 if (isnil (nameID))
                   {
                      // no name-ID contained in the query...
      @@ -107,15 +107,15 @@ namespace asset {
                     static int i=0;
                     static format namePattern ("%s.%d");
                     static format predPattern ("%s(%s), ");
      -              nameID = str(namePattern % StructTraits::namePrefix % (++i) );
      +              nameID = str(namePattern % StructTraits::namePrefix() % (++i) );
                     name.insert(0, 
      -                       str(predPattern % StructTraits::idSymbol % nameID ));
      +                       str(predPattern % StructTraits::idSymbol() % nameID ));
                   }
                 ENSURE (!isnil (name));
                 ENSURE (!isnil (nameID));
                 ENSURE (contains (name, nameID));
                 
      -          Category cat (STRUCT, StructTraits::catFolder);
      +          Category cat (STRUCT, StructTraits::catFolder());
                 return Asset::Ident (name, cat );                       ///////////////////////TICKET #565  the ID field should be just the ID, the query should go into a dedicated "capabilities" field.
               }
             
      diff --git a/src/proc/asset/struct-scheme.hpp b/src/proc/asset/struct-scheme.hpp
      index 588b01551..c8e0d09a4 100644
      --- a/src/proc/asset/struct-scheme.hpp
      +++ b/src/proc/asset/struct-scheme.hpp
      @@ -36,30 +36,14 @@
       #define ASSET_STRUCT_SCHEME_H
       
       
      -//#include "proc/mobject/session.hpp"
      -//#include "proc/mobject/mobject.hpp"
      -
       #include "lib/symbol.hpp"
      -//#include "lib/error.hpp"
      -//#include "lib/util.hpp"
      -
      -//#include 
      -
      -#include 
      -using boost::format;
      -/////////////////////////////////////////////////////////TODO needs to be pushed down into a *.cpp
       
       #include 
       
      -//using mobject::Session;
      -//using mobject::MObject;
      +/////////////////////////////////////////////////////////TICKET #166 : needs to be pushed down into a *.cpp
      +#include 
      +using boost::format;
       
      -using lib::Symbol;
      -//using util::isnil;
      -//using util::contains;
      -//using asset::Query;
      -//using lumiera::query::LUMIERA_ERROR_CAPABILITY_QUERY;
      -//using lumiera::query::extractID;
       
       namespace mobject {
       namespace session {
      @@ -77,28 +61,76 @@ namespace asset{
         class Timeline;
         class Sequence;
         
      +  
         namespace idi  {
           
      -    // structural asset ID scheme   ///////////////////////////////////////////////////////////TICKET #565
      +    using lib::Symbol;
      +    
      +    
      +    
      +    /* ==== structural asset ID scheme ==== */  /////////////////////////////////////////////TICKET #565 : better organisation of this naming scheme
           
           template
           struct StructTraits
             {
      -        static Symbol namePrefix;
      -        static Symbol catFolder;
      -        static Symbol idSymbol;
      +        static Symbol namePrefix();
      +        static Symbol catFolder();
      +        static Symbol idSymbol();
             };
           
      -    // Note: individual defaults are defined in stuct.cpp
      +    
      +  ///////////////////////////////////////////////////////////////////////////////////////////TICKET #581 intending to abandon asset::Track in favour of a plain EntryID 
      +    template<> struct StructTraits
      +      {
      +        static Symbol namePrefix() { return "track"; }
      +        static Symbol catFolder()  { return "tracks";}
      +        static Symbol idSymbol()   { return "track"; }
      +      };
      +    template<> struct StructTraits
      +      {
      +        static Symbol namePrefix() { return "track"; }
      +        static Symbol catFolder()  { return "tracks";}
      +        static Symbol idSymbol()   { return "track"; }
      +      };
      +    template<> struct StructTraits
      +      {
      +        static Symbol namePrefix() { return "clip"; }
      +        static Symbol catFolder()  { return "clips";}
      +        static Symbol idSymbol()   { return "clip"; }
      +      };
      +    template<> struct StructTraits
      +      {
      +        static Symbol namePrefix() { return "pipe"; }
      +        static Symbol catFolder()  { return "pipes";}
      +        static Symbol idSymbol()   { return "pipe"; }
      +      };
      +    template<> struct StructTraits
      +      {
      +        static Symbol namePrefix() { return "patt";           }
      +        static Symbol catFolder()  { return "build-templates";}
      +        static Symbol idSymbol()   { return "procPatt";       }
      +      };
      +    template<> struct StructTraits
      +      {
      +        static Symbol namePrefix() { return "tL";       }
      +        static Symbol catFolder()  { return "timelines";}
      +        static Symbol idSymbol()   { return "timeline"; }
      +      };
      +    template<> struct StructTraits
      +      {
      +        static Symbol namePrefix() { return "seq";      }
      +        static Symbol catFolder()  { return "sequences";}
      +        static Symbol idSymbol()   { return "sequence"; }
      +      };
           
           
           /* catch-all defaults */
           template
      -    Symbol StructTraits::idSymbol = typeid(X).name(); ////////////////////TICKET #583   this default works but is ugly
      +    Symbol StructTraits::idSymbol() { return typeid(X).name(); } ////////////////////TICKET #583   this default works but is ugly
           template
      -    Symbol StructTraits::catFolder = StructTraits::idSymbol;
      +    Symbol StructTraits::catFolder(){ return idSymbol(); }
           template
      -    Symbol StructTraits::namePrefix = StructTraits::idSymbol;
      +    Symbol StructTraits::namePrefix(){return idSymbol(); }
           
           
           
      @@ -109,9 +141,9 @@ namespace asset{
           {
               static uint i=0;
               static format namePattern ("%s.%03d");
      -        /////////////////////////////////////////////////////////TODO needs to be pushed down into a *.cpp
      +        ////////////////////////////////////////////////////////////////////////////////TICKET #166 : needs to be pushed down into a *.cpp
               
      -        return str(namePattern % StructTraits::namePrefix % (++i) );
      +        return str(namePattern % StructTraits::namePrefix() % (++i) );
           }
           
           
      diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp
      index 387d8b3bf..128745279 100644
      --- a/src/proc/asset/struct.cpp
      +++ b/src/proc/asset/struct.cpp
      @@ -155,39 +155,4 @@ namespace asset {
         template PSequence   StructFactory::operator() (const Query& query);
         
         
      -  
      -  
      -  /* ======= struct asset naming scheme ======== */
      -  
      -  ///////////////////////////////////////////////////////////////////////////////////////////TICKET #565 better organisation for the asset::Struct naming scheme 
      -  ///////////////////////////////////////////////////////////////////////////////////////////TICKET #581 intending to abandon asset::Track in favour of a plain EntryID 
      -  template<> Symbol StructTraits::namePrefix = "track";
      -  template<> Symbol StructTraits::catFolder  = "tracks";
      -  template<> Symbol StructTraits::idSymbol   = "track";
      -  
      -  template<> Symbol StructTraits::namePrefix = "track";
      -  template<> Symbol StructTraits::catFolder  = "tracks";
      -  template<> Symbol StructTraits::idSymbol   = "track";
      -  
      -  template<> Symbol StructTraits::namePrefix = "clip";
      -  template<> Symbol StructTraits::catFolder  = "clips";
      -  template<> Symbol StructTraits::idSymbol   = "clip";
      -  
      -  template<> Symbol StructTraits::namePrefix = "pipe";
      -  template<> Symbol StructTraits::catFolder  = "pipes";
      -  template<> Symbol StructTraits::idSymbol   = "pipe";
      -  
      -  template<> Symbol StructTraits::namePrefix = "patt";
      -  template<> Symbol StructTraits::catFolder  = "build-templates";
      -  template<> Symbol StructTraits::idSymbol   = "procPatt";
      -  
      -  template<> Symbol StructTraits::namePrefix = "tL";
      -  template<> Symbol StructTraits::catFolder  = "timelines";
      -  template<> Symbol StructTraits::idSymbol   = "timeline";
      -  
      -  template<> Symbol StructTraits::namePrefix = "seq";
      -  template<> Symbol StructTraits::catFolder  = "sequences";
      -  template<> Symbol StructTraits::idSymbol   = "sequence";
      -    
      -  
       } // namespace asset
      diff --git a/tests/42query.tests b/tests/42query.tests
      index 98983c3b0..717f0bde7 100644
      --- a/tests/42query.tests
      +++ b/tests/42query.tests
      @@ -12,7 +12,7 @@ END
       
       
       TEST "normalise ID" QueryUtils_test  normaliseID  <
       
      -
      +
      [<img[Advice solution|uml/fig141573.png]]
       
       
      @@ -556,7 +556,7 @@ In order to find matches and provide advice solutions, the advice system maintai
       This is the tricky part of the whole advice system implementation. A naive implementation will quickly degenerate in performance, as costs are of order ~AdviceProvisions * ~AdviceRequests * (average number of binding terms). But contrary to the standard solutions for rules based systems (either forward or backward chaining), in this case here always complete binding sets are to be matched, which allows to reduce the effort.
       
       !!!solution idea
      -The binding patterns are organised by //predicate symbol and the lists are normalised.// A simple normalisation could be lexicographic ordering of the predicate symbols. Then the resulting representation can be //hashed.// When all predicates are constant, match can be found by hashtable lookup, otherwise, in case some predicates contain variable arguments ({{red{planned extension}}}), the lookup is followed by an unification. For this to work, we'll have to include the arity into the predicate symbols used in the first matching stage. Moreover, we'll create a //matching closure// (functor object), internally holding the arguments for unification. This approach allows for //actual interpretation of the arguments.// It is conceivable that in special cases we'll get multiple instances of the same predicate, just with different arguments. The unification of these terms needs to consider each possible pairwise combination (cartesian product) &mdash; but working out the details of the implementation can safely be deferred until we'll actually hit such a special situation, thanks to the implementation by a functor.
      +The binding patterns are organised by //predicate symbol and the lists are normalised.// A simple normalisation could be lexicographic ordering of the predicate symbols. Then the resulting representation can be //hashed.// When all predicates are constant, a match can be detected by hashtable lookup, otherwise, in case some of the predicates contain variable arguments ({{red{planned extension}}}), the lookup is followed by an unification. For this to work, we'll have to include the arity into the predicate symbols used in the first matching stage. Moreover, we'll create a //matching closure// (functor object), internally holding the arguments for unification. This approach allows for //actual interpretation of the arguments.// It is conceivable that in special cases we'll get multiple instances of the same predicate, just with different arguments. The unification of these terms needs to consider each possible pairwise combination (cartesian product) &mdash; but working out the details of the implementation can safely be deferred until we'll actually hit such a special situation, thanks to the implementation by a functor.
       
       Fortunately, the calculation of this normalised patterns can be separated completely from the actual matching. Indeed, we don't even need to store the binding patterns at all within the binding index &mdash; storing the hash value is sufficient (and in case of patterns with arguments we'll attach the matching closure functor). Yet still we need to store a marker for each successful match, together with back-links, in order to handle changing and retracting of advice.
       
      From c8ac2b04478e3c80a36d793167a166e42a28d579 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 24 Apr 2010 17:31:01 +0200 Subject: [PATCH 16/52] planning the advice binding index implementation --- doc/devel/draw/AdviceBindingIndex-1.svg | 1000 +++++++++++++++++ src/lib/advice.hpp | 2 +- src/lib/advice/advice.cpp | 1 + src/lib/advice/index.hpp | 154 +++ tests/lib/advice/advice-basics-test.cpp | 16 +- tests/lib/advice/advice-index-test.cpp | 297 ++++- tests/lib/advice/advice-multiplicity-test.cpp | 2 +- wiki/draw/AdviceBindingIndex1.png | Bin 0 -> 22347 bytes wiki/renderengine.html | 41 +- 9 files changed, 1482 insertions(+), 31 deletions(-) create mode 100644 doc/devel/draw/AdviceBindingIndex-1.svg create mode 100644 src/lib/advice/index.hpp create mode 100644 wiki/draw/AdviceBindingIndex1.png diff --git a/doc/devel/draw/AdviceBindingIndex-1.svg b/doc/devel/draw/AdviceBindingIndex-1.svg new file mode 100644 index 000000000..ea7a5aaa0 --- /dev/null +++ b/doc/devel/draw/AdviceBindingIndex-1.svg @@ -0,0 +1,1000 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + Advice Binding Index Structures + + + Ichthyostega + + + design sketch: Advice binding match implementation + 2010 + + + + + + + + + + + + + + + Provisions + + + + + + Requests + Match + + AdviceProvision + + + + hash + + + + + + + hash + + + + + + + + + + AdviceProvision + + + + AdviceRequest + + + + AdviceRequest + + + + AdviceRequest + + + + AdviceRequest + + + + + + + + + + + + + + + Advice Solution + diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp index 1bafc833c..38ffa8ff8 100644 --- a/src/lib/advice.hpp +++ b/src/lib/advice.hpp @@ -122,7 +122,7 @@ namespace advice { /** - * Access point for the advised entity (client). + * Access point for the advising entity (server). * TODO type comment */ template diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp index 091a7d4f5..dfb9dc48c 100644 --- a/src/lib/advice/advice.cpp +++ b/src/lib/advice/advice.cpp @@ -22,6 +22,7 @@ #include "lib/advice.hpp" +#include "lib/advice/index.hpp" namespace lib { diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp new file mode 100644 index 000000000..2a44fd3fb --- /dev/null +++ b/src/lib/advice/index.hpp @@ -0,0 +1,154 @@ +/* + INDEX.hpp - data structure for organising advice solutions and matching + + 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 index.hpp + ** Implementation datastructure for use by the Advice system. + ** To support the \em Advice collaboration, it is necessary to match advice requests with + ** existing advice provisions. Each successful match creates an advice solution, resulting in + ** the bound piece of advice (data) to become visible to all the advised entities having placed + ** a matching advice request into the advice system. + ** + ** This header is intended to be incorporated as part of the advice system implementation (advice.cpp). + ** It is \em not usable as an external interface. But it is written in a rather self-contained manner, + ** in order to be testable in isolation. To this end, the actual PointOfAdvice entities being organised + ** by this index datastructure remain abstract (defined as template parameter). As link for dealing + ** with those entities, we employ the free functions \c getSolution(POA) and \c setSolution(POA) + ** -- expected to be picked up by ADL. + ** + ** \par implementation notes + ** The advice binding index is implemented by two hashtables holding Binding::Matcher entries. + ** Each entry associates a back-link to the corresponding POA (PointOfAdvice), which is assumed + ** to be maintained outside the index. PointOfAdvice is an type-erased interface baseclass. + ** Actually the advice system will have to deal with concrete advice::Request and advice::Provision + ** objects, which are templated to a specific advice type; but this specifically typed context + ** is kept on the interface level (advice.hpp) and the type information is stripped before + ** calling into the actual implementation, so the index can be realised in a generic fashion. + ** + ** @note as of 4/2010 this is an experimental setup and implemented just enough to work out + ** the interfaces. Ichthyo expects this collaboration service to play a central role + ** at various places within proc-layer. + ** @note for now, \em only the case of a completely constant (ground) pattern is implemented. + ** Later we may consider to extend the binding patterns to allow variables. The mechanics + ** of the index are designed right from start to support this case (and indeed the index + ** could be much simpler if it wasn't to deal with this foreseeable additional complexity. + ** When a pattern contains variables, then even within one bucket of the hashtable there + ** might be non-matching entries. Each individual pair of (provision, request) has to be + ** checked explicitly to determine a match. /////////////////////////TICKET #615 + ** + ** @see advice.hpp + ** @see binding.hpp + ** @see advice-index-test.cpp + ** @see advice-binding-pattern-test.cpp + ** @see advice-basics-test.cpp + ** + */ + + +#ifndef LIB_ADVICE_INDEX_H +#define LIB_ADVICE_INDEX_H + + +#include "lib/error.hpp" +#include "lib/advice/binding.hpp" +//#include "lib/symbol.hpp" +//#include "lib/query.hpp" + +//#include +//#include +//#include + +namespace lib { +namespace advice { + +// using std::string; + +// LUMIERA_ERROR_DECLARE (BINDING_PATTERN_SYNTAX); ///< Unable to parse the given binding pattern definition + + + + /** + * Index datastructure for organising advice solutions. + * Based on two hashtables for advice provisions and requests, + * the index allows to add, modify and remove entities of these + * two kinds. Each of these mutating operations immediately + * re-computes the advice solutions and publishes the results + * by invoking the free function \c setSolution(POA) for the + * corresponding PointOfAdvice entity. + * + * @note the diagnostic API is mainly intended for unit testing + * and \em not implemented with focus on performance. + */ + template + class Index + { + + public: + + void + clear () + { + UNIMPLEMENTED ("clear all index tables"); + } + + /* == diagnostics == */ + + /** validity self-check */ + bool isValid() const; + + size_t + size() const + { + UNIMPLEMENTED ("sum up size of both tables"); + } + + + private: + /** internal: parse into atoms, and insert them */ + }; + + + + + + + /* === equality comparison and matching === */ + + + + + + /* == diagnostics == */ + template + bool + Index::isValid() const + { + UNIMPLEMENTED ("verify the index invariant"); + } + + + + + + +}} // namespace lib::advice +#endif diff --git a/tests/lib/advice/advice-basics-test.cpp b/tests/lib/advice/advice-basics-test.cpp index 8ecdd852f..7ed8e3b7b 100644 --- a/tests/lib/advice/advice-basics-test.cpp +++ b/tests/lib/advice/advice-basics-test.cpp @@ -207,8 +207,8 @@ namespace test { overwriting_and_retracting() { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 - TheAdvised client1 ("topic1()"); - TheAdvised client2 ("topic2()"); + TheAdvised client1 ("topic1"); + TheAdvised client2 ("topic2"); CHECK (client1.got(0)); CHECK (client2.got(0)); @@ -237,7 +237,7 @@ namespace test { CHECK (client2.got(r2)); { - TheAdvisor anotherServer("topic1()"); + TheAdvisor anotherServer("topic1"); CHECK (client1.got(0)); CHECK (client2.got(r2)); @@ -250,7 +250,7 @@ namespace test { CHECK (client2.got(r2)); { - TheAdvisor yetAnotherServer("topic2()"); + TheAdvisor yetAnotherServer("topic2"); CHECK (client1.got(r1)); CHECK (client2.got(r2)); @@ -258,7 +258,7 @@ namespace test { CHECK (client1.got(r1)); CHECK (client2.got(r1)); - yetAnotherserver.rebind("topic1()"); + yetAnotherserver.rebind("topic1"); CHECK (client1.got(r1)); CHECK (client2.got(0)); @@ -266,7 +266,7 @@ namespace test { CHECK (client1.got(0)); CHECK (client2.got(0)); - yetAnotherserver.rebind("topic2()"); + yetAnotherserver.rebind("topic2"); CHECK (client1.got(0)); CHECK (client2.got(0)); @@ -278,11 +278,11 @@ namespace test { CHECK (client1.got(0)); CHECK (client2.got(r1)); - client1.rebind("topic2()"); + client1.rebind("topic2"); CHECK (client1.got(r1)); CHECK (client2.got(r1)); - client2.rebind("nonExistingTopic()"); + client2.rebind("nonExistingTopic"); CHECK (client1.got(r1)); CHECK (client2.got(0)); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605 diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp index cc30e67b4..ee4732b0c 100644 --- a/tests/lib/advice/advice-index-test.cpp +++ b/tests/lib/advice/advice-index-test.cpp @@ -24,7 +24,7 @@ #include "lib/test/run.hpp" //#include "lib/test/test-helper.hpp" -#include "lib/advice.hpp" +#include "lib/advice/index.hpp" //#include "lib/p.hpp" //#include "proc/assetmanager.hpp" //#include "proc/asset/inventory.hpp" @@ -43,7 +43,7 @@ //using util::and_all; //using util::for_each; //using util::isnil; -//using lib::Literal; +using lib::Literal; //using lib::Symbol; //using lumiera::P; //using std::string; @@ -56,17 +56,50 @@ namespace lib { namespace advice { namespace test { - namespace { + using lib::Literal; + + namespace { // test support definitions + + struct TestPOA + { + + }; + + + /** convenience shortcut for writing testcases inline */ + inline Binding::Matcher + _entry (uint id, Literal spec) + { + return Binding(spec).buildMatcher(); + } + + /** check if the given request got the denoted solution */ + inline bool + _hasSolution (uint req, uint prov) + { + UNIMPLEMENTED ("check test solution"); + } + + /** check if the given request holds a default solution */ + inline bool + _hasDefault (uint req) + { + UNIMPLEMENTED ("check pseudo default solution, which is NULL for this test"); + } } + typedef Index Index; - /******************************************************************************* - * @test the Advice system uses an index datastructure to support matching - * the bindings to get pairs of participants to connect by an individual - * advice channel. + + /****************************************************************************************** + * @test the Advice system uses an index datastructure to support matching the bindings + * to get pairs of participants to connect by an individual advice channel. * - * This test covers the properties of this implementation datastucture. + * This test covers the properties of this implementation datastructure in isolation. + * We employ special test entries, different from what is used in the advice system, + * and we create a specific instantiation of the advice::Index template solely + * for this test * * @todo partially unimplemented and thus commented out ////////////////////TICKET #608 * @@ -80,58 +113,282 @@ namespace test { virtual void run (Arg) { - checkInit(); - addEntry(); - checkLookup(); - removeEntry(); - checkCollisionHandling(); - checkCleanup(); + Index idx; + buildIndex (idx); + + addRequest (idx); + addProvision (idx); + removeRequest (idx); + retractProvision (idx); + modifyRequest (idx); + modifyProvision (idx); + + clearIndex (idx); } void - checkInit() + buildIndex (Index& idx) { + CHECK (idx.isValid()); + CHECK (0 == idx.size()); + #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + idx.addRequest (_entry (1,"cat")); + idx.addRequest (_entry (2,"cat")); + idx.addRequest (_entry (3,"dog")); + CHECK (3 == idx.size()); + CHECK (3 == idx.request_count()); + CHECK (0 == idx.provision_count()); + + idx.addProvision (_entry (4,"dog")); + CHECK (4 == idx.size()); + CHECK (3 == idx.request_count()); + CHECK (1 == idx.provision_count()); + + CHECK (_hasDefault (1)); + CHECK (_hasDefault (2)); + CHECK (_hasSolution (3,4)); + CHECK (idx.isValid()); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void - addEntry() + addRequest (Index& idx) { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + CHECK (idx.isValid()); + uint req_cnt = idx.request_count(); + + idx.addRequest (_entry (5,"dog")); + idx.addRequest (_entry (6,"cat")); + + CHECK (idx.hasRequest (_entry (5,"dog"))); + CHECK (idx.hasRequest (_entry (6,"cat"))); + + CHECK (_hasDefault (6)); + CHECK (_hasSolution (5,4)); + CHECK (idx.isValid()); + CHECK (2 + req_cnt == idx.request_count()); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void - checkLookup() + addProvision (Index& idx) { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + CHECK (idx.isValid()); + uint r_cnt = idx.request_count(); + uint p_cnt = idx.provision_count(); + + CHECK (_hasDefault (1)); + CHECK (_hasDefault (2)); + CHECK (_hasDefault (6)); + CHECK (_hasSolution (3,4)); + CHECK (_hasSolution (5,4)); + + idx.addProvision (_entry (7,"cat")); + CHECK (idx.hasProvision (_entry (7,"cat"))); + + CHECK (_hasSolution (1,7)); // all cats got the cat solution + CHECK (_hasSolution (2,7)); + CHECK (_hasSolution (6,7)); + CHECK (_hasSolution (3,4)); // dogs unaltered + CHECK (_hasSolution (5,4)); + CHECK (idx.isValid()); + CHECK (1 + p_cnt == idx.provision_count()); + CHECK (0 + r_cnt == idx.request_count()); + + idx.addProvision (_entry (8,"dog")); + + CHECK (_hasSolution (1,7)); // cats remain unaffected + CHECK (_hasSolution (2,7)); + CHECK (_hasSolution (6,7)); + CHECK (_hasSolution (3,8)); // all dogs got the new solution + CHECK (_hasSolution (5,8)); + CHECK (idx.isValid()); + CHECK (2 + p_cnt == idx.provision_count()); + CHECK (0 + r_cnt == idx.request_count()); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void - removeEntry() + removeRequest (Index& idx) { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + CHECK (idx.isValid()); + uint r_cnt = idx.request_count(); + uint p_cnt = idx.provision_count(); + CHECK (_hasSolution (1,7)); + CHECK (_hasSolution (2,7)); + CHECK (_hasSolution (6,7)); + CHECK (_hasSolution (3,8)); + CHECK (_hasSolution (5,8)); + + CHECK ( idx.hasRequest (_entry (2,"cat"))); + + idx.removeRequest (_entry (2,"cat")); + + CHECK (!idx.hasRequest (_entry (2,"cat"))); + CHECK (p_cnt == idx.provision_count()); + CHECK (r_cnt-1 == idx.request_count()); + + CHECK (_hasSolution (1,7)); // no effect on the other requests + CHECK (_hasSolution (6,7)); + CHECK (_hasSolution (3,8)); + CHECK (_hasSolution (5,8)); + + idx.removeRequest (_entry (2,"cat")); // idempotent + CHECK (!idx.hasRequest (_entry (2,"cat"))); + CHECK (p_cnt == idx.provision_count()); + CHECK (r_cnt-1 == idx.request_count()); + CHECK (idx.isValid()); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void - checkCollisionHandling() + retractProvision (Index& idx) { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + CHECK (idx.isValid()); + uint r_cnt = idx.request_count(); + uint p_cnt = idx.provision_count(); + CHECK (_hasSolution (1,7)); + CHECK (_hasSolution (6,7)); + CHECK (_hasSolution (3,8)); + CHECK (_hasSolution (5,8)); + + CHECK ( idx.hasProvision (_entry (4,"dog"))); + + idx.removeProvision (_entry (4,"dog")); + + CHECK (!idx.hasProvision (_entry (4,"dog"))); + CHECK (p_cnt-1 == idx.provision_count()); + CHECK (r_cnt == idx.request_count()); + + CHECK (_hasSolution (1,7)); // no effect on the solutions, because of the more recent dog solution 8 + CHECK (_hasSolution (6,7)); + CHECK (_hasSolution (3,8)); + CHECK (_hasSolution (5,8)); + + CHECK ( idx.hasProvision (_entry (8,"dog"))); + + idx.removeProvision (_entry (8,"dog")); + + CHECK (!idx.hasProvision (_entry (8,"dog"))); + CHECK (p_cnt-2 == idx.provision_count()); + CHECK (r_cnt == idx.request_count()); + + CHECK (_hasSolution (1,7)); // no effect on the cat solutions + CHECK (_hasSolution (6,7)); + CHECK (!_hasSolution (3,8)); + CHECK (!_hasSolution (5,8)); + CHECK (_hasDefault (3)); // but all dog requests reverted to default + CHECK (_hasDefault (5)); + + idx.removeProvision (_entry (8,"dog")); // idempotent + CHECK (!idx.hasProvision (_entry (8,"dog"))); + CHECK (p_cnt-2 == idx.provision_count()); + CHECK (r_cnt == idx.request_count()); + CHECK (idx.isValid()); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void - checkCleanup() + modifyRequest (Index& idx) { +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + CHECK (idx.isValid()); + uint r_cnt = idx.request_count(); + uint p_cnt = idx.provision_count(); + CHECK (_hasSolution (1,7)); + CHECK (_hasSolution (6,7)); + CHECK (_hasDefault (3)); + CHECK (_hasDefault (5)); + + CHECK (!idx.hasRequest (_entry (2,"cat"))); + CHECK ( idx.hasRequest (_entry (5,"dog"))); + + idx.modifyRequest (_entry (5,"dog"), _entry (2,"cat")); + + CHECK ( idx.hasRequest (_entry (2,"cat"))); + CHECK (!idx.hasRequest (_entry (5,"dog"))); + CHECK (p_cnt == idx.provision_count()); + CHECK (r_cnt == idx.request_count()); + CHECK (_hasSolution (1,7)); + CHECK (_hasSolution (6,7)); + CHECK (_hasDefault (3)); + CHECK (_hasSolution (2,7)); // automatically got the current cat solution +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + } + + + void + modifyProvision (Index& idx) + { + CHECK (idx.isValid()); +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + uint r_cnt = idx.request_count(); + uint p_cnt = idx.provision_count(); + CHECK (_hasSolution (1,7)); + CHECK (_hasSolution (2,7)); + CHECK (_hasSolution (6,7)); + CHECK (_hasDefault (3)); + + CHECK ( idx.hasProvision (_entry (7,"cat"))); + CHECK (!idx.hasProvision (_entry (8,"dog"))); + + idx.modifyProvision (_entry (7,"cat"), _entry (8,"dog")); + CHECK (!idx.hasProvision (_entry (7,"cat"))); + CHECK ( idx.hasProvision (_entry (8,"dog"))); + CHECK (p_cnt == idx.provision_count()); + CHECK (r_cnt == idx.request_count()); + CHECK (_hasDefault (1)); + CHECK (_hasDefault (2)); + CHECK (_hasDefault (3)); + CHECK (_hasSolution (3,8)); + + idx.addProvision (_entry (7,"cat")); + idx.addProvision (_entry (9,"cat")); + CHECK (idx.hasProvision (_entry (7,"cat"))); + CHECK (idx.hasProvision (_entry (9,"cat"))); + CHECK (_hasSolution (1,9)); // all cats got the second cat solution + CHECK (_hasSolution (2,9)); + CHECK (_hasSolution (6,9)); + CHECK (_hasSolution (3,8)); // the dog is unaffected + + CHECK ( idx.hasProvision (_entry (7,"cat"))); + CHECK (!idx.hasProvision (_entry (4,"dog"))); + + idx.modifyProvision (_entry (7,"cat"), _entry (4,"dog")); + + CHECK (!idx.hasProvision (_entry (7,"cat"))); + CHECK ( idx.hasProvision (_entry (4,"dog"))); + CHECK (p_cnt == idx.provision_count()); + CHECK (r_cnt == idx.request_count()); + CHECK (_hasSolution (1,9)); // cats unaffected, because we're changing a shadowed cat solution + CHECK (_hasSolution (2,9)); + CHECK (_hasSolution (6,9)); + CHECK (_hasSolution (3,4)); // but the dog got switched to the transmogrified-into-dog solution, + // because it was added later than the existing solution 8 + CHECK (p_cnt == idx.provision_count()); + CHECK (r_cnt == idx.request_count()); + CHECK (idx.isValid()); +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 + } + + + void + clearIndex (Index& idx) + { + idx.clear(); + CHECK (idx.isValid()); + CHECK (0 == idx.size()); #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } diff --git a/tests/lib/advice/advice-multiplicity-test.cpp b/tests/lib/advice/advice-multiplicity-test.cpp index 69e7b280d..35cf42e5b 100644 --- a/tests/lib/advice/advice-multiplicity-test.cpp +++ b/tests/lib/advice/advice-multiplicity-test.cpp @@ -85,7 +85,7 @@ namespace test { /** @test run simple pairs of collaborators in multiple threads. * Intentionally, there should be just a single match per pair, - * but the timings of provision and pickup are choosen randomly + * but the timings of provision and pickup are chosen randomly */ void check_highLoadSimpleMatch() diff --git a/wiki/draw/AdviceBindingIndex1.png b/wiki/draw/AdviceBindingIndex1.png new file mode 100644 index 0000000000000000000000000000000000000000..87c52774402be4594e38237e490eee827ce9083f GIT binary patch literal 22347 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 KVYNp0pZ*V$PcP#D literal 0 HcmV?d00001 diff --git a/wiki/renderengine.html b/wiki/renderengine.html index f59a98b92..1c68a868a 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -541,7 +541,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo &rarr; AdviceImplementation
      -
      +
      [<img[Advice solution|uml/fig141573.png]]
       
       
      @@ -559,6 +559,45 @@ This is the tricky part of the whole advice system implementation. A naive imple
       The binding patterns are organised by //predicate symbol and the lists are normalised.// A simple normalisation could be lexicographic ordering of the predicate symbols. Then the resulting representation can be //hashed.// When all predicates are constant, a match can be detected by hashtable lookup, otherwise, in case some of the predicates contain variable arguments ({{red{planned extension}}}), the lookup is followed by an unification. For this to work, we'll have to include the arity into the predicate symbols used in the first matching stage. Moreover, we'll create a //matching closure// (functor object), internally holding the arguments for unification. This approach allows for //actual interpretation of the arguments.// It is conceivable that in special cases we'll get multiple instances of the same predicate, just with different arguments. The unification of these terms needs to consider each possible pairwise combination (cartesian product) &mdash; but working out the details of the implementation can safely be deferred until we'll actually hit such a special situation, thanks to the implementation by a functor.
       
       Fortunately, the calculation of this normalised patterns can be separated completely from the actual matching. Indeed, we don't even need to store the binding patterns at all within the binding index &mdash; storing the hash value is sufficient (and in case of patterns with arguments we'll attach the matching closure functor). Yet still we need to store a marker for each successful match, together with back-links, in order to handle changing and retracting of advice.
      +
      +!!!storage and registrations
      +We have to provide dedicated storage for the actual advice provisions and for the index entries. Mostly, these objects to be managed are attached through a single link &mdash; and moreover the advice system is considered performance critical, so it doesn't make sense to implement the management of these entries by smart-ptr. This rules out ~TypedAllocationManager and prompts to write a dedicated storage frontend, later to be backed by Lumiera's mpool facility.
      +* both the advice provision and the advice requests attach to the advice system after fulfilling some prerequisites; they need to detach automatically on destruction.
      +* in case of the provision, there is a cascaded relation: the externally maintained provision creates an internal provision record, which in turn attaches an index entry.
      +* both in case of the provision and the request, the relation of the index bears some multiplicity:
      +** a multitude of advice provisions can attach with the same binding (which could be the same binding pattern terms, but different variable arguments). Each of them could create a separate advice solution (at least when variable arguments are involved); it would be desirable to establish a defined LIFO order for any search for possibly matching advice.
      +** a multitude of advice requests can attach with the same binding, and each of them needs to be visited in case a match is detected.
      +* in both cases, any of these entries could be removed any time on de-registration of the corresponding external entity
      +* we need to track existing advice solutions, because we need to be able to overwrite with new advice and to remove all solutions bound to a given pattern about to leave the system. One provision could create a large number of solutions, while each registration always holds onto exactly one solution (which could be a default/placeholder solution though)
      +
      +!!!index datastructure
      +It is clear by now that the implementation datastrucutre has to serve as a kind of //reference count.// Within this datastructure, any constructed advice solution needs to be reflected somehow, to prevent us from discarding an advice provision still accessible. Allowing lock-free access to the advice solution (planned feature) adds an special twist, because in this case we can't even tell for sure if an overwritten old solution is actually gone (or if its still referred from some thread's cached memeory). This could be addressed with an transactional approach (which might be good anyway) &mdash; but I tend to leave this special concern asside for now.
      +
      +To start with, any advice matching and solution will //always happen within matching buckets of a hash based pattern organisation.// The binding index thus should build on two hashtables (one for the requests and one for the provisions), but using specifically crafted datastructures as buckets. The individual entries within these bucket structures in both cases will be comprised of a binding matcher (to determine if an match actually happens) and a back-link to the registered entitiy (provision or request). Given the special pattern of the advice solutions, existing solutions could be tracked within the entries at the request side.
      +* Advice provisions are expected to happen only in small numbers; they will be searched stack-like, starting from the newes provisions, until a match is found.
      +* Each advised entity basically creates an advice request, so there could be a larger number of request entries. In the typical search triggered from the provision side, each request entry will be visited and checked for match, which, if successful, causes a pointer to be set within the ~AdviceRequest object (located outside the realm of the advice system). While &mdash; obviously &mdash; multiple requests with similar binding match could be folded into a sub-list, we need actual timing measurements to determine the weight of these two calculation steps of matching and storing, which together comprise the handling of an advice solution.
      +
      +The above considerations don't fully solve the question how to represent an computed solution within the index datastructure, candidates being to use the index within the provision list, or a direct pointer to the provision or even just to re-use the pointer stored into the ~AdviceRequest. Besides solutions found by matching, we need //fallback solutions// holding a default constructed piece of advice of the requested type. As these defaults aren't correlated at all to the involved bindings, but only to the advice type as such, it seems reasonable to keep them completely apart, like e.g. placing them into static memory managed by the ~AdviceProvision template instantiations.
      +
      +!!!interactions to be served by the index
      +[>img[Advice solution|draw/AdviceBindingIndex1.png]]
      +
      +;add request
      +:check existing provisions starting from top until match; use default solution in case no match is found; publish solution into the new request; finally attach the new request entry
      +;remove request
      +:just remove the request entry
      +;modify request
      +:handle as if newly added
      +;add provision
      +:push new provision entry on top; traverse all request entries and check for match with this new provision entry, publish new solution for each match
      +;retract provision
      +:remove the provision entry; traverse all request entries to find those using this provision as advice solution, treat these as if they where newly added requests
      +;modify provision
      +:add a new (copy of the) provision, followed by retracting the old one; actually these two traversals of all requests can be combined, thus treating a request which used the old provision but doesn't match the new one is treated like a new request
      +<<<
      +__Invariant__: each request has a valid soultion pointer set (maybe pointing to a default solution). Whenever such a solution points to a registered provision, there is a match between the index entries and this is the top-most possible match to any provision entry for this request entry
      +<<<
      +Clearly, retracting advice (and consequently also the modification) is expensive. After finishing these operations, the old/retracted provision can be discarded (or put asside in case of non-locking advice access). Other operations don't cause de-allocation, as provisions remain within the system, even if the original advising entity is gone.
       
      From 530940254e72c653ca1f6bc77372c4b3799f2908 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Apr 2010 01:51:30 +0200 Subject: [PATCH 17/52] stubbed advice binding index implementation --- src/lib/advice/index.hpp | 64 +++++++++++++++++++++++ tests/lib/advice/advice-index-test.cpp | 70 ++++++++++++++++++-------- 2 files changed, 112 insertions(+), 22 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 2a44fd3fb..99d32616a 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -104,12 +104,52 @@ namespace advice { public: + void + addRequest (POA& entry) + { + UNIMPLEMENTED ("add advice request entry"); + } + + void + modifyRequest (POA const& oldRef, POA& newEntry) + { + UNIMPLEMENTED ("replace denoted entry with new advice request"); + } + + void + removeRequest (POA const& refEntry) + { + UNIMPLEMENTED ("drop advice request"); + } + + + void + addProvision (POA& entry) + { + UNIMPLEMENTED ("add advice provision entry"); + } + + void + modifyProvision (POA const& oldRef, POA& newEntry) + { + UNIMPLEMENTED ("replace denoted entry with new advice provision"); + } + + void + removeProvision (POA const& refEntry) + { + UNIMPLEMENTED ("retract advice provision entry"); + } + + void clear () { UNIMPLEMENTED ("clear all index tables"); } + + /* == diagnostics == */ /** validity self-check */ @@ -121,6 +161,30 @@ namespace advice { UNIMPLEMENTED ("sum up size of both tables"); } + size_t + request_count() const + { + UNIMPLEMENTED ("number of request entries"); + } + + size_t + provision_count() const + { + UNIMPLEMENTED ("number of provision entries"); + } + + bool + hasRequest (POA const& refEntry) const + { + UNIMPLEMENTED ("do we hold this entry?"); + } + + bool + hasProvision (POA const& refEntry) const + { + UNIMPLEMENTED ("do we hold this entry?"); + } + private: /** internal: parse into atoms, and insert them */ diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp index ee4732b0c..8ea89047c 100644 --- a/tests/lib/advice/advice-index-test.cpp +++ b/tests/lib/advice/advice-index-test.cpp @@ -35,6 +35,7 @@ //#include "lib/symbol.hpp" //#include +#include //#include //using lib::test::showSizeof; @@ -62,29 +63,72 @@ namespace test { struct TestPOA { + TestPOA* solution_; + Binding::Matcher pattern_; + explicit + TestPOA(Literal spec="missing") + : solution_(0) + , pattern_(Binding(spec).buildMatcher()) + { } + + bool + matches (Literal refSpec) const + { + return pattern_.matches (Binding(refSpec)); + } + + + friend TestPOA* + getSolution (TestPOA& entry) + { + return entry.solution_; + } + + friend void + setSolution (TestPOA& entry, TestPOA& solution) + { + entry.solution_ = &solution; + } }; + + + const uint MAX_TEST_ENTRIES = 10; + + std::vector testEntries(MAX_TEST_ENTRIES); + + + /** convenience shortcut for writing testcases inline */ - inline Binding::Matcher + inline TestPOA& _entry (uint id, Literal spec) { - return Binding(spec).buildMatcher(); + REQUIRE (id < testEntries.size()); + + if (!testEntries[id].matches(spec)) + testEntries[id] = TestPOA(spec); + + return testEntries[id]; } /** check if the given request got the denoted solution */ inline bool _hasSolution (uint req, uint prov) { - UNIMPLEMENTED ("check test solution"); + REQUIRE (req < testEntries.size()); + REQUIRE (prov < testEntries.size()); + + return testEntries[req].solution_ == & testEntries[prov]; } /** check if the given request holds a default solution */ inline bool _hasDefault (uint req) { - UNIMPLEMENTED ("check pseudo default solution, which is NULL for this test"); + REQUIRE (req < testEntries.size()); + return NULL == testEntries[req].solution_; } } @@ -101,8 +145,6 @@ namespace test { * and we create a specific instantiation of the advice::Index template solely * for this test * - * @todo partially unimplemented and thus commented out ////////////////////TICKET #608 - * * @see advice.hpp * @see AdviceBasics_test * @see AdviceBindingPattern_test @@ -133,7 +175,6 @@ namespace test { CHECK (idx.isValid()); CHECK (0 == idx.size()); -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 idx.addRequest (_entry (1,"cat")); idx.addRequest (_entry (2,"cat")); idx.addRequest (_entry (3,"dog")); @@ -150,14 +191,12 @@ namespace test { CHECK (_hasDefault (2)); CHECK (_hasSolution (3,4)); CHECK (idx.isValid()); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void addRequest (Index& idx) { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 CHECK (idx.isValid()); uint req_cnt = idx.request_count(); @@ -171,14 +210,12 @@ namespace test { CHECK (_hasSolution (5,4)); CHECK (idx.isValid()); CHECK (2 + req_cnt == idx.request_count()); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void addProvision (Index& idx) { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 CHECK (idx.isValid()); uint r_cnt = idx.request_count(); uint p_cnt = idx.provision_count(); @@ -211,14 +248,12 @@ namespace test { CHECK (idx.isValid()); CHECK (2 + p_cnt == idx.provision_count()); CHECK (0 + r_cnt == idx.request_count()); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void removeRequest (Index& idx) { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 CHECK (idx.isValid()); uint r_cnt = idx.request_count(); uint p_cnt = idx.provision_count(); @@ -246,14 +281,12 @@ namespace test { CHECK (p_cnt == idx.provision_count()); CHECK (r_cnt-1 == idx.request_count()); CHECK (idx.isValid()); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void retractProvision (Index& idx) { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 CHECK (idx.isValid()); uint r_cnt = idx.request_count(); uint p_cnt = idx.provision_count(); @@ -295,14 +328,12 @@ namespace test { CHECK (p_cnt-2 == idx.provision_count()); CHECK (r_cnt == idx.request_count()); CHECK (idx.isValid()); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } void modifyRequest (Index& idx) { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 CHECK (idx.isValid()); uint r_cnt = idx.request_count(); uint p_cnt = idx.provision_count(); @@ -324,7 +355,6 @@ namespace test { CHECK (_hasSolution (6,7)); CHECK (_hasDefault (3)); CHECK (_hasSolution (2,7)); // automatically got the current cat solution -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } @@ -332,7 +362,6 @@ namespace test { modifyProvision (Index& idx) { CHECK (idx.isValid()); -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 uint r_cnt = idx.request_count(); uint p_cnt = idx.provision_count(); CHECK (_hasSolution (1,7)); @@ -379,7 +408,6 @@ namespace test { CHECK (p_cnt == idx.provision_count()); CHECK (r_cnt == idx.request_count()); CHECK (idx.isValid()); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } @@ -389,8 +417,6 @@ namespace test { idx.clear(); CHECK (idx.isValid()); CHECK (0 == idx.size()); -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #608 } }; From 3c35e2a95f4142e1c35cde06c3ab9865d5f01f44 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Apr 2010 03:12:18 +0200 Subject: [PATCH 18/52] WIP code up index functionality... --- src/lib/advice/index.hpp | 70 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 99d32616a..e0de1029b 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -72,7 +72,10 @@ #include "lib/advice/binding.hpp" //#include "lib/symbol.hpp" //#include "lib/query.hpp" +#include "include/logging.h" +#include "lib/util.hpp" +#include //#include //#include //#include @@ -80,7 +83,11 @@ namespace lib { namespace advice { + using util::contains; // using std::string; + using std::pair; + using std::vector; + using std::tr1::unordered_map; // LUMIERA_ERROR_DECLARE (BINDING_PATTERN_SYNTAX); ///< Unable to parse the given binding pattern definition @@ -101,13 +108,58 @@ namespace advice { template class Index { - + typedef pair Entry; + typedef vector EntryList; + + class Cluster + { + EntryList elms_; + public: + void + append (POA& elm) + { + Entry entry (getMatcher(elm), &elm); + REQUIRE (!contains (elms_, entry)); + elms_.push_back(entry); + } + }; + + struct RequestCluster + : Cluster + { + void + publish_all_solutions (POA& provisionElm) + { + UNIMPLEMENTED ("traverse all, check match, publish solution"); + } + }; + + struct ProvisionCluster + : Cluster + { + void + publish_latest_solution (POA& requestElm) + { + UNIMPLEMENTED ("visit from back, find first match, publish solution"); + } + }; + + + typedef unordered_map RTable; + typedef unordered_map PTable; + + RTable requestEntries_; + PTable provisionEntries_; + + public: void addRequest (POA& entry) { - UNIMPLEMENTED ("add advice request entry"); + HashVal key (hash_value(entry)); + requestEntries_[key].add (entry); + provisionEntries_[key].publish_latest_solution (entry); } void @@ -126,7 +178,9 @@ namespace advice { void addProvision (POA& entry) { - UNIMPLEMENTED ("add advice provision entry"); + HashVal key (hash_value(entry)); + provisionEntries_[key].append (entry); + requestEntries_[key].publish_all_solutions (entry); } void @@ -142,10 +196,16 @@ namespace advice { } + /** @warning calling this effectively detaches any existing advice information, + * but doesn't clean up storage of advice provisions incorporated + * within the advice system in general. + */ void clear () { - UNIMPLEMENTED ("clear all index tables"); + WARN (library, "Purging Advice Binding Index..."); + requestEntries_.clear(); + provisionEntries_.clear(); } @@ -158,7 +218,7 @@ namespace advice { size_t size() const { - UNIMPLEMENTED ("sum up size of both tables"); + return request_count() + provision_count(); } size_t From bf02d6d03f32c11043fae758d821497543ef89d8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Apr 2010 15:15:53 +0200 Subject: [PATCH 19/52] adapter interface for the test-entry --- src/lib/advice/index.hpp | 30 +++++++++++++++++++++++--- tests/lib/advice/advice-index-test.cpp | 14 ++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index e0de1029b..437ce2760 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -108,22 +108,46 @@ namespace advice { template class Index { - typedef pair Entry; + + + struct Entry + : pair + { + Entry (POA& elm) + : pair (getMatcher(elm), &elm) + { } + + friend bool + operator== (Entry const& a, Entry const& b) + { + return a.second == b.second; + } + + friend bool + operator!= (Entry const& a, Entry const& b) + { + return a.second != b.second; + } + }; + typedef vector EntryList; + class Cluster { EntryList elms_; + public: void append (POA& elm) { - Entry entry (getMatcher(elm), &elm); + Entry entry (elm); REQUIRE (!contains (elms_, entry)); elms_.push_back(entry); } }; + struct RequestCluster : Cluster { @@ -158,7 +182,7 @@ namespace advice { addRequest (POA& entry) { HashVal key (hash_value(entry)); - requestEntries_[key].add (entry); + requestEntries_[key].append (entry); provisionEntries_[key].publish_latest_solution (entry); } diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp index 8ea89047c..821ec2e82 100644 --- a/tests/lib/advice/advice-index-test.cpp +++ b/tests/lib/advice/advice-index-test.cpp @@ -79,6 +79,20 @@ namespace test { } + /* == Adapter interface for use within the Index == */ + + friend HashVal + hash_value (TestPOA const& entry) + { + return hash_value (entry.pattern_); + } + + friend const Binding::Matcher + getMatcher (TestPOA const& entry) + { + return entry.pattern_; + } + friend TestPOA* getSolution (TestPOA& entry) { From d4433fb3f359d4ea3e567bf5275cc2e45ae2fca7 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Apr 2010 16:18:28 +0200 Subject: [PATCH 20/52] WIP code high-level index functionality --- src/lib/advice/index.hpp | 71 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 437ce2760..8260691ab 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -113,6 +113,7 @@ namespace advice { struct Entry : pair { + explicit Entry (POA& elm) : pair (getMatcher(elm), &elm) { } @@ -131,6 +132,7 @@ namespace advice { }; typedef vector EntryList; + typedef typename EntryList::iterator EIter; class Cluster @@ -142,9 +144,31 @@ namespace advice { append (POA& elm) { Entry entry (elm); - REQUIRE (!contains (elms_, entry)); + REQUIRE (!contains (elms_, entry), "Duplicate entry"); elms_.push_back(entry); } + + void + overwrite (POA const& oldRef, POA& newEntry) + { + EIter pos = std::find (elms_.begin(),elms_.end(), oldRef); + REQUIRE (pos!=elms_.end(), "Attempt to overwrite an entry which isn't there."); +////TODO REQUIRE (!contains (elms_, newEntry), "Duplicate entry"); + + *pos = Entry(newEntry); + +////TODO ENSURE (!contains (elms_, oldRef), "Duplicate entry"); + } + + void + remove (POA const& refEntry) + { + EIter pos = std::find (elms_.begin(),elms_.end(), refEntry); /////////////////////////////TODO can't compare to refEntry, need a Entry. Maybe define other operator== + if (pos!=elms_.end()) + elms_.erase(pos); + +////TODO ENSURE (!contains (elms_, refEntry), "Duplicate entry"); + } }; @@ -156,6 +180,18 @@ namespace advice { { UNIMPLEMENTED ("traverse all, check match, publish solution"); } + + void + rewrite_all_solutions (POA const& oldProv, POA& newProv) + { + UNIMPLEMENTED ("traverse all, check match, publish solution, treat solutions with old Provision as if newly added request"); + } + + void + retract_all_solutions (POA const& oldProv) + { + UNIMPLEMENTED ("traverse all, check match, treat matching as if newly added request"); + } }; struct ProvisionCluster @@ -189,13 +225,23 @@ namespace advice { void modifyRequest (POA const& oldRef, POA& newEntry) { - UNIMPLEMENTED ("replace denoted entry with new advice request"); + HashVal oKey (hash_value(oldRef)); + HashVal nKey (hash_value(newEntry)); + if (oKey != nKey) + { + requestEntries_[oKey].remove (oldRef); + requestEntries_[nKey].append (newEntry); + } + else + requestEntries_[nKey].overwrite (oldRef, newEntry); + provisionEntries_[nKey].publish_latest_solution (newEntry); } void removeRequest (POA const& refEntry) { - UNIMPLEMENTED ("drop advice request"); + HashVal oKey (hash_value(refEntry)); + requestEntries_[oKey].remove (refEntry); } @@ -210,13 +256,28 @@ namespace advice { void modifyProvision (POA const& oldRef, POA& newEntry) { - UNIMPLEMENTED ("replace denoted entry with new advice provision"); + HashVal oKey (hash_value(oldRef)); + HashVal nKey (hash_value(newEntry)); + if (oKey != nKey) + { + provisionEntries_[oKey].remove (oldRef); + provisionEntries_[nKey].append (newEntry); + requestEntries_[nKey].publish_all_solutions (newEntry); + requestEntries_[oKey].retract_all_solutions (oldRef); + } + else + { + provisionEntries_[nKey].overwrite (oldRef, newEntry); + requestEntries_[nKey].rewrite_all_solutions (oldRef,newEntry); + } } void removeProvision (POA const& refEntry) { - UNIMPLEMENTED ("retract advice provision entry"); + HashVal oKey (hash_value(refEntry)); + provisionEntries_[oKey].remove (refEntry); + requestEntries_[oKey].retract_all_solutions (refEntry); } From f1be9886fac21fe4d53547d2826806dfa6e91c07 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 27 Apr 2010 03:14:37 +0200 Subject: [PATCH 21/52] fix problem with comparisions / containment check --- src/lib/advice/index.hpp | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 8260691ab..515abc507 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -75,6 +75,7 @@ #include "include/logging.h" #include "lib/util.hpp" +#include #include //#include //#include @@ -111,7 +112,9 @@ namespace advice { struct Entry - : pair + : pair + , boost::equality_comparable > { explicit Entry (POA& elm) @@ -125,9 +128,9 @@ namespace advice { } friend bool - operator!= (Entry const& a, Entry const& b) + operator== (Entry const& a, POA const& p) { - return a.second != b.second; + return a.second != &p; } }; @@ -143,9 +146,8 @@ namespace advice { void append (POA& elm) { - Entry entry (elm); - REQUIRE (!contains (elms_, entry), "Duplicate entry"); - elms_.push_back(entry); + REQUIRE (!contains (elm), "Duplicate entry"); + elms_.push_back (Entry(elm)); } void @@ -153,21 +155,31 @@ namespace advice { { EIter pos = std::find (elms_.begin(),elms_.end(), oldRef); REQUIRE (pos!=elms_.end(), "Attempt to overwrite an entry which isn't there."); -////TODO REQUIRE (!contains (elms_, newEntry), "Duplicate entry"); + REQUIRE (!contains (newEntry), "Duplicate entry"); *pos = Entry(newEntry); -////TODO ENSURE (!contains (elms_, oldRef), "Duplicate entry"); + ENSURE (!contains (oldRef), "Duplicate entry"); } void remove (POA const& refEntry) { - EIter pos = std::find (elms_.begin(),elms_.end(), refEntry); /////////////////////////////TODO can't compare to refEntry, need a Entry. Maybe define other operator== + EIter pos = std::find (elms_.begin(),elms_.end(), refEntry); if (pos!=elms_.end()) elms_.erase(pos); -////TODO ENSURE (!contains (elms_, refEntry), "Duplicate entry"); + ENSURE (!contains (refEntry), "Duplicate entry"); + } + + private: + bool + contains (POA const& refElm) + { + for (EIter i=elms_.begin(); i!=elms_.end(); ++i) + if (i->second == &refElm) + return true; + return false; } }; From e0cfa6798f11a444966930b76a101a1ffc21075b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 27 Apr 2010 03:46:43 +0200 Subject: [PATCH 22/52] implement the diagnostic operations --- src/lib/advice/index.hpp | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 515abc507..72441aef6 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -73,6 +73,8 @@ //#include "lib/symbol.hpp" //#include "lib/query.hpp" #include "include/logging.h" +#include "lib/iter-adapter-stl.hpp" +//#include "lib/util-foreach.hpp" #include "lib/util.hpp" #include @@ -84,6 +86,8 @@ namespace lib { namespace advice { + using lib::iter_stl::eachVal; +// using util::for_each; using util::contains; // using std::string; using std::pair; @@ -143,6 +147,12 @@ namespace advice { EntryList elms_; public: + size_t + size() const + { + return elms_.size(); + } + void append (POA& elm) { @@ -172,7 +182,6 @@ namespace advice { ENSURE (!contains (refEntry), "Duplicate entry"); } - private: bool contains (POA const& refElm) { @@ -181,6 +190,7 @@ namespace advice { return true; return false; } + private: }; @@ -216,12 +226,15 @@ namespace advice { } }; + + + /* ==== Index Tables ===== */ typedef unordered_map RTable; typedef unordered_map PTable; - RTable requestEntries_; - PTable provisionEntries_; + mutable RTable requestEntries_; + mutable PTable provisionEntries_; public: @@ -321,30 +334,40 @@ namespace advice { size_t request_count() const { - UNIMPLEMENTED ("number of request entries"); + return sumClusters (eachVal (requestEntries_)); } size_t provision_count() const { - UNIMPLEMENTED ("number of provision entries"); + return sumClusters (eachVal (provisionEntries_)); } bool hasRequest (POA const& refEntry) const { - UNIMPLEMENTED ("do we hold this entry?"); + return requestEntries_[hash_value(refEntry)].contains (refEntry); } bool hasProvision (POA const& refEntry) const { - UNIMPLEMENTED ("do we hold this entry?"); + return provisionEntries_[hash_value(refEntry)].contains (refEntry); } private: - /** internal: parse into atoms, and insert them */ + /** internal: sum element count over all + * clusters in the given hashtable */ + template + static size_t + sumClusters (IT ii) + { + size_t sum=0; + for ( ; ii; ++ii ) + sum += ii->size(); + return sum; + } }; From d00d42b58c9c96870c4db9f5a05a6d23363d869a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 27 Apr 2010 05:07:40 +0200 Subject: [PATCH 23/52] code up the core solution finding logic --- src/lib/advice/index.hpp | 95 ++++++++++++++++++-------- tests/lib/advice/advice-index-test.cpp | 5 +- 2 files changed, 68 insertions(+), 32 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 72441aef6..9550c8fff 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -142,11 +142,10 @@ namespace advice { typedef typename EntryList::iterator EIter; - class Cluster + struct Cluster { EntryList elms_; - public: size_t size() const { @@ -190,39 +189,74 @@ namespace advice { return true; return false; } - private: }; - struct RequestCluster - : Cluster - { - void - publish_all_solutions (POA& provisionElm) - { - UNIMPLEMENTED ("traverse all, check match, publish solution"); - } - - void - rewrite_all_solutions (POA const& oldProv, POA& newProv) - { - UNIMPLEMENTED ("traverse all, check match, publish solution, treat solutions with old Provision as if newly added request"); - } - - void - retract_all_solutions (POA const& oldProv) - { - UNIMPLEMENTED ("traverse all, check match, treat matching as if newly added request"); - } - }; - struct ProvisionCluster : Cluster { void publish_latest_solution (POA& requestElm) { - UNIMPLEMENTED ("visit from back, find first match, publish solution"); + typedef typename EntryList::reverse_iterator RIter; + Binding::Matcher pattern (getMatcher (requestElm)); + for (RIter ii=this->elms_.rbegin(); + ii!=this->elms_.rend(); + ++ii ) + if (ii->first.matches (pattern)) + { // found the most recent advice provision satisfying the (new) request + // thus publish this new advice solution into the request object + setSolution (&requestElm, ii->second); + return; + } + // if we reach this point, non of the existing provisions is suitable. + // thus we report "no solution" which causes a default solution to be used + setSolution (&requestElm, NULL ); + } + }; + + struct RequestCluster + : Cluster + { + void + publish_all_solutions (POA& provisionElm) + { + Binding::Matcher pattern (getMatcher (provisionElm)); + for (EIter ii=this->elms_.begin(); + ii!=this->elms_.end(); + ++ii ) + if (pattern.matches (ii->first)) + // the given (new) advice provision satisfies this request + // thus publish this new advice solution into the request object + setSolution (ii->second, &provisionElm); + } + + void + retract_all_solutions (POA const& oldProv, ProvisionCluster& possibleReplacementSolutions) + { + Binding::Matcher pattern (getMatcher (oldProv)); + for (EIter ii=this->elms_.begin(); + ii!=this->elms_.end(); + ++ii ) + if (pattern.matches (ii->first)) + // the old advice provision (to be dropped) satisfied this request + // which thus needs to be treated anew (could cause quadratic complexity) + possibleReplacementSolutions.publish_latest_solution (*(ii->second)); + } + + void + rewrite_all_solutions (POA const& oldProv, POA& newProv, ProvisionCluster& possibleReplacementSolutions) + { + Binding::Matcher oldPattern (getMatcher (oldProv)); + Binding::Matcher newPattern (getMatcher (newProv)); + for (EIter ii=this->elms_.begin(); + ii!=this->elms_.end(); + ++ii ) + if (newPattern.matches (ii->first)) + setSolution (ii->second, &newProv); + else + if (oldPattern.matches (ii->first)) + possibleReplacementSolutions.publish_latest_solution (*(ii->second)); } }; @@ -288,12 +322,12 @@ namespace advice { provisionEntries_[oKey].remove (oldRef); provisionEntries_[nKey].append (newEntry); requestEntries_[nKey].publish_all_solutions (newEntry); - requestEntries_[oKey].retract_all_solutions (oldRef); + requestEntries_[oKey].retract_all_solutions (oldRef, provisionEntries_[oKey]); } else { provisionEntries_[nKey].overwrite (oldRef, newEntry); - requestEntries_[nKey].rewrite_all_solutions (oldRef,newEntry); + requestEntries_[nKey].rewrite_all_solutions (oldRef,newEntry, provisionEntries_[nKey]); } } @@ -302,7 +336,7 @@ namespace advice { { HashVal oKey (hash_value(refEntry)); provisionEntries_[oKey].remove (refEntry); - requestEntries_[oKey].retract_all_solutions (refEntry); + requestEntries_[oKey].retract_all_solutions (refEntry, provisionEntries_[oKey]); } @@ -353,7 +387,8 @@ namespace advice { hasProvision (POA const& refEntry) const { return provisionEntries_[hash_value(refEntry)].contains (refEntry); - } + } // note: even just lookup might create a new (empty) cluster; + // thus the tables are defined as mutable private: diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp index 821ec2e82..dfc1ce73f 100644 --- a/tests/lib/advice/advice-index-test.cpp +++ b/tests/lib/advice/advice-index-test.cpp @@ -100,9 +100,10 @@ namespace test { } friend void - setSolution (TestPOA& entry, TestPOA& solution) + setSolution (TestPOA* entry, TestPOA* solution =0) { - entry.solution_ = &solution; + REQUIRE (entry); + entry->solution_ = solution; } }; From ca93b11010b8f83bc2619757753dfec6c3e5a47d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 28 Apr 2010 05:32:14 +0200 Subject: [PATCH 24/52] provide self-verification. Advice index impl. now complete but not yet tested... --- src/lib/advice/index.hpp | 155 +++++++++++++++++++++++++++++------ src/lib/iter-adapter-stl.hpp | 12 +++ 2 files changed, 140 insertions(+), 27 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 9550c8fff..4f98ea2a1 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -42,11 +42,11 @@ ** Actually the advice system will have to deal with concrete advice::Request and advice::Provision ** objects, which are templated to a specific advice type; but this specifically typed context ** is kept on the interface level (advice.hpp) and the type information is stripped before - ** calling into the actual implementation, so the index can be realised in a generic fashion. + ** calling into the actual implementation, so the index can be implemented generic. ** ** @note as of 4/2010 this is an experimental setup and implemented just enough to work out ** the interfaces. Ichthyo expects this collaboration service to play a central role - ** at various places within proc-layer. + ** later at various places within proc-layer. ** @note for now, \em only the case of a completely constant (ground) pattern is implemented. ** Later we may consider to extend the binding patterns to allow variables. The mechanics ** of the index are designed right from start to support this case (and indeed the index @@ -70,31 +70,36 @@ #include "lib/error.hpp" #include "lib/advice/binding.hpp" -//#include "lib/symbol.hpp" +#include "lib/symbol.hpp" //#include "lib/query.hpp" #include "include/logging.h" #include "lib/iter-adapter-stl.hpp" -//#include "lib/util-foreach.hpp" +#include "lib/util-foreach.hpp" #include "lib/util.hpp" #include #include //#include -//#include +#include //#include namespace lib { namespace advice { - using lib::iter_stl::eachVal; -// using util::for_each; - using util::contains; -// using std::string; - using std::pair; - using std::vector; + using std::tr1::placeholders::_1; using std::tr1::unordered_map; + using lib::iter_stl::eachVal; + using lib::iter_stl::eachElm; + using util::for_each; + using util::contains; + using util::unConst; + using lib::Literal; + using std::string; + using std::vector; + using std::pair; + + using namespace lumiera; -// LUMIERA_ERROR_DECLARE (BINDING_PATTERN_SYNTAX); ///< Unable to parse the given binding pattern definition @@ -138,6 +143,7 @@ namespace advice { } }; + typedef vector EntryList; typedef typename EntryList::iterator EIter; @@ -189,14 +195,20 @@ namespace advice { return true; return false; } + + RangeIter + allElms () + { + return eachElm (elms_); + } }; struct ProvisionCluster : Cluster { - void - publish_latest_solution (POA& requestElm) + POA* + find_latest_solution (POA& requestElm) { typedef typename EntryList::reverse_iterator RIter; Binding::Matcher pattern (getMatcher (requestElm)); @@ -204,14 +216,22 @@ namespace advice { ii!=this->elms_.rend(); ++ii ) if (ii->first.matches (pattern)) - { // found the most recent advice provision satisfying the (new) request - // thus publish this new advice solution into the request object - setSolution (&requestElm, ii->second); - return; - } - // if we reach this point, non of the existing provisions is suitable. - // thus we report "no solution" which causes a default solution to be used - setSolution (&requestElm, NULL ); + return ii->second; + + return NULL; + } + + void + publish_latest_solution (POA& requestElm) + { + POA* solution = find_latest_solution (requestElm); + if (solution) + // found the most recent advice provision satisfying the (new) request + // thus publish this new advice solution into the request object + setSolution (&requestElm, solution); + else + setSolution (&requestElm, NULL ); + // report "no solution" which causes a default solution to be used } }; @@ -403,6 +423,9 @@ namespace advice { sum += ii->size(); return sum; } + + void verify_Entry (Entry const&, HashVal) const; + void verify_Request (Entry const&, HashVal) const; }; @@ -410,23 +433,101 @@ namespace advice { - /* === equality comparison and matching === */ - /* == diagnostics == */ + /* == Self-Verification == */ + + namespace { // self-check implementation helpers... + + LUMIERA_ERROR_DEFINE(INDEX_CORRUPTED, "Advice-Index corrupted"); + + struct SelfCheckFailure + : error::Fatal + { + SelfCheckFailure (Literal failure) + : error::Fatal (string("Failed test: ")+failure + ,LUMIERA_ERROR_INDEX_CORRUPTED) + { } + }; + + } + + + + /** Advice index self-verification: traverses the tables to check + * each entry is valid. Moreover, when a advice request has a stored solution + * which points back into the current advice provisions, this solution will be + * re-computed with the current data to prove it's still valid. + * @note expensive operation + */ template bool Index::isValid() const { - UNIMPLEMENTED ("verify the index invariant"); + typedef typename RTable::const_iterator RTIter; + typedef typename PTable::const_iterator PTIter; + + try { + for (PTIter ii=provisionEntries_.begin(); + ii != provisionEntries_.end(); ++ii) + { + HashVal hash (ii->first); + Cluster& clu = unConst(ii->second); + for_each (clu.allElms(), &Index::verify_Entry, this, _1, hash); + } + for (RTIter ii=requestEntries_.begin(); + ii != requestEntries_.end(); ++ii) + { + HashVal hash (ii->first); + Cluster& clu = unConst(ii->second); + for_each (clu.allElms(), &Index::verify_Request, this, _1, hash); + } + return true; + } + + catch(SelfCheckFailure& failure) + { + lumiera_error(); + ERROR (library, "%s", failure.what()); + } + return false; + } + + + +#define VERIFY(_CHECK_, DESCRIPTION) \ + if (!(_CHECK_)) \ + throw SelfCheckFailure ((DESCRIPTION)); + + + template + void + Index::verify_Entry (Entry const& e, HashVal hash) const + { + VERIFY (hash == hash_value(e.first), "Wrong bucket, hash doesn't match bucket"); + VERIFY (e.second, "Invalid Entry: back-link is NULL"); } + template + void + Index::verify_Request (Entry const& e, HashVal hash) const + { + verify_Entry (e,hash); + POA& request = *(e.second); + POA* solution (getSolution (request)); + if (solution && hasProvision(*solution)) + { + POA* currentSolution = provisionEntries_[hash].find_latest_solution (request); + VERIFY (e.first.matches (getMatcher(*solution)), "stored advice solution not supported by binding match"); + VERIFY (bool(currentSolution), "unable to reproduce stored solution with the current provisions") + VERIFY (solution == currentSolution, "stored advice solution isn't the topmost solution for this request") + } + } - - +#undef VERIFY }} // namespace lib::advice diff --git a/src/lib/iter-adapter-stl.hpp b/src/lib/iter-adapter-stl.hpp index 63ec756cb..13e183113 100644 --- a/src/lib/iter-adapter-stl.hpp +++ b/src/lib/iter-adapter-stl.hpp @@ -278,6 +278,18 @@ namespace iter_stl { + /** @return Lumiera Forward Iterator + * to yield each Element from a STL container + */ + template + inline typename _SeqT::Range + eachElm (CON& coll) + { + typedef typename _SeqT::Range Range; + return Range (coll.begin(), coll.end()); + } + + /** @return Lumiera Forward Iterator to yield * each key of a map/multimap */ From 0c123e4af30c6d2976f4e59babf532b48d05d5cb Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 5 May 2010 04:01:26 +0200 Subject: [PATCH 25/52] Bugfix --- src/lib/advice/index.hpp | 2 +- tests/lib/advice/advice-index-test.cpp | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 4f98ea2a1..2f842ae24 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -139,7 +139,7 @@ namespace advice { friend bool operator== (Entry const& a, POA const& p) { - return a.second != &p; + return a.second == &p; } }; diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp index dfc1ce73f..3a645ca05 100644 --- a/tests/lib/advice/advice-index-test.cpp +++ b/tests/lib/advice/advice-index-test.cpp @@ -394,11 +394,12 @@ namespace test { CHECK (r_cnt == idx.request_count()); CHECK (_hasDefault (1)); CHECK (_hasDefault (2)); - CHECK (_hasDefault (3)); + CHECK (_hasDefault (6)); CHECK (_hasSolution (3,8)); idx.addProvision (_entry (7,"cat")); idx.addProvision (_entry (9,"cat")); + CHECK (p_cnt+2 == idx.provision_count()); CHECK (idx.hasProvision (_entry (7,"cat"))); CHECK (idx.hasProvision (_entry (9,"cat"))); CHECK (_hasSolution (1,9)); // all cats got the second cat solution @@ -413,14 +414,12 @@ namespace test { CHECK (!idx.hasProvision (_entry (7,"cat"))); CHECK ( idx.hasProvision (_entry (4,"dog"))); - CHECK (p_cnt == idx.provision_count()); - CHECK (r_cnt == idx.request_count()); CHECK (_hasSolution (1,9)); // cats unaffected, because we're changing a shadowed cat solution CHECK (_hasSolution (2,9)); CHECK (_hasSolution (6,9)); CHECK (_hasSolution (3,4)); // but the dog got switched to the transmogrified-into-dog solution, // because it was added later than the existing solution 8 - CHECK (p_cnt == idx.provision_count()); + CHECK (p_cnt+2 == idx.provision_count()); CHECK (r_cnt == idx.request_count()); CHECK (idx.isValid()); } From c9437b3bff075affd3cab5ed2185c206e727b177 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 6 May 2010 03:52:11 +0200 Subject: [PATCH 26/52] binding index unit test pass --- src/lib/advice/index.hpp | 90 ++++++++++++++++++-------- tests/lib/advice/advice-index-test.cpp | 54 +++++++--------- wiki/renderengine.html | 4 +- 3 files changed, 89 insertions(+), 59 deletions(-) diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 2f842ae24..f4a96dd57 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -32,8 +32,11 @@ ** It is \em not usable as an external interface. But it is written in a rather self-contained manner, ** in order to be testable in isolation. To this end, the actual PointOfAdvice entities being organised ** by this index datastructure remain abstract (defined as template parameter). As link for dealing - ** with those entities, we employ the free functions \c getSolution(POA) and \c setSolution(POA) - ** -- expected to be picked up by ADL. + ** with those entities, we employ free functions to be picked up by ADL + ** - \c hash_value(POA) + ** - \c getMatcher(POA) + ** - \c getSolution(POA) + ** - \c setSolution(POA,solution) ** ** \par implementation notes ** The advice binding index is implemented by two hashtables holding Binding::Matcher entries. @@ -44,13 +47,29 @@ ** is kept on the interface level (advice.hpp) and the type information is stripped before ** calling into the actual implementation, so the index can be implemented generic. ** + ** While both hashtables are organised by the binding pattern hash, the individual buckets are + ** coded explicitly as ProvisionCluster and RequestCluster -- both based on a vector of entries. + ** In case of the provisions, there is a stack-like order, inasmuch additions happen at the back + ** and solutions are always searched starting from the end. Because of the basic structure of + ** a binding match, solutions are possible \only between provision/request - clusters with the + ** same hash value (which is based on the predicate symbols within the patterns to match). Thus, + ** in case of changing an existing request or solution, the internal handling is different, + ** depending on the new value to belong or don't belong to the same cluster (hash code). + ** It's possible (for patterns including variables) that an entry leading to a solution with + ** the old provision doesn't match a new provision (and vice versa); thus we'll have to traverse + ** the contents of the whole cluster, find all old solutions, match against the new counterpart + ** and treating those entries \em not matching with the new value as if they where completely + ** newly added entries. In case we don't find any solution, the entries are supposed to be + ** implemented such as to fall back to an default solution automatically (when receiving + ** a \c NULL solution) + ** ** @note as of 4/2010 this is an experimental setup and implemented just enough to work out ** the interfaces. Ichthyo expects this collaboration service to play a central role ** later at various places within proc-layer. ** @note for now, \em only the case of a completely constant (ground) pattern is implemented. ** Later we may consider to extend the binding patterns to allow variables. The mechanics ** of the index are designed right from start to support this case (and indeed the index - ** could be much simpler if it wasn't to deal with this foreseeable additional complexity. + ** could be much simpler if it wasn't to deal with this foreseeable additional complexity: ** When a pattern contains variables, then even within one bucket of the hashtable there ** might be non-matching entries. Each individual pair of (provision, request) has to be ** checked explicitly to determine a match. /////////////////////////TICKET #615 @@ -71,7 +90,6 @@ #include "lib/error.hpp" #include "lib/advice/binding.hpp" #include "lib/symbol.hpp" -//#include "lib/query.hpp" #include "include/logging.h" #include "lib/iter-adapter-stl.hpp" #include "lib/util-foreach.hpp" @@ -79,9 +97,8 @@ #include #include -//#include +#include #include -//#include namespace lib { namespace advice { @@ -97,6 +114,9 @@ namespace advice { using std::string; using std::vector; using std::pair; + using std::ostream; + using std::cout; + using std::endl; using namespace lumiera; @@ -141,9 +161,15 @@ namespace advice { { return a.second == &p; } + + friend ostream& + operator<< (ostream& os, Entry const& ent) + { + return os << "E-"< " << ent.second ; + } }; - + typedef vector EntryList; typedef typename EntryList::iterator EIter; @@ -166,36 +192,43 @@ namespace advice { } void - overwrite (POA const& oldRef, POA& newEntry) + overwrite (POA const& oldRef, POA& newElm) { EIter pos = std::find (elms_.begin(),elms_.end(), oldRef); REQUIRE (pos!=elms_.end(), "Attempt to overwrite an entry which isn't there."); - REQUIRE (!contains (newEntry), "Duplicate entry"); + REQUIRE (!contains (newElm), "Duplicate entry"); - *pos = Entry(newEntry); + *pos = Entry(newElm); ENSURE (!contains (oldRef), "Duplicate entry"); } void - remove (POA const& refEntry) + remove (POA const& refElm) { - EIter pos = std::find (elms_.begin(),elms_.end(), refEntry); + EIter pos = std::find (elms_.begin(),elms_.end(), refElm); if (pos!=elms_.end()) elms_.erase(pos); - ENSURE (!contains (refEntry), "Duplicate entry"); + ENSURE (!contains (refElm), "Duplicate entry"); } bool contains (POA const& refElm) { for (EIter i=elms_.begin(); i!=elms_.end(); ++i) - if (i->second == &refElm) - return true; + if (*i == refElm) return true; return false; } + void + dump() ///< debugging helper: Cluster contents --> STDOUT + { + cout << "elmList("<< elms_.size()<<")" << endl; + for (EIter i=elms_.begin(); i!=elms_.end(); ++i) + cout << "E...:"<< (*i) << endl; + } + RangeIter allElms () { @@ -281,16 +314,17 @@ namespace advice { }; - + /* ==== Index Tables ===== */ - - typedef unordered_map RTable; + + typedef unordered_map RTable; typedef unordered_map PTable; mutable RTable requestEntries_; mutable PTable provisionEntries_; + public: void @@ -439,7 +473,7 @@ namespace advice { /* == Self-Verification == */ - + namespace { // self-check implementation helpers... LUMIERA_ERROR_DEFINE(INDEX_CORRUPTED, "Advice-Index corrupted"); @@ -452,9 +486,9 @@ namespace advice { ,LUMIERA_ERROR_INDEX_CORRUPTED) { } }; - } - + + /** Advice index self-verification: traverses the tables to check @@ -469,16 +503,16 @@ namespace advice { { typedef typename RTable::const_iterator RTIter; typedef typename PTable::const_iterator PTIter; - + try { - for (PTIter ii=provisionEntries_.begin(); + for (PTIter ii =provisionEntries_.begin(); ii != provisionEntries_.end(); ++ii) { HashVal hash (ii->first); Cluster& clu = unConst(ii->second); for_each (clu.allElms(), &Index::verify_Entry, this, _1, hash); } - for (RTIter ii=requestEntries_.begin(); + for (RTIter ii=requestEntries_.begin(); ii != requestEntries_.end(); ++ii) { HashVal hash (ii->first); @@ -495,11 +529,11 @@ namespace advice { } return false; } - - + + #define VERIFY(_CHECK_, DESCRIPTION) \ - if (!(_CHECK_)) \ + if (!(_CHECK_)) \ throw SelfCheckFailure ((DESCRIPTION)); @@ -527,7 +561,7 @@ namespace advice { } } -#undef VERIFY +#undef VERIFY }} // namespace lib::advice diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp index 3a645ca05..4b4b25766 100644 --- a/tests/lib/advice/advice-index-test.cpp +++ b/tests/lib/advice/advice-index-test.cpp @@ -22,34 +22,11 @@ #include "lib/test/run.hpp" -//#include "lib/test/test-helper.hpp" - #include "lib/advice/index.hpp" -//#include "lib/p.hpp" -//#include "proc/assetmanager.hpp" -//#include "proc/asset/inventory.hpp" -//#include "proc/mobject/session/clip.hpp" -//#include "proc/mobject/session/track.hpp" -//#include "lib/meta/trait-special.hpp" -//#include "lib/util-foreach.hpp" -//#include "lib/symbol.hpp" -//#include #include -//#include -//using lib::test::showSizeof; -//using lib::test::randStr; -//using util::isSameObject; -//using util::and_all; -//using util::for_each; -//using util::isnil; using lib::Literal; -//using lib::Symbol; -//using lumiera::P; -//using std::string; -//using std::cout; -//using std::endl; @@ -57,10 +34,16 @@ namespace lib { namespace advice { namespace test { - using lib::Literal; - namespace { // test support definitions + /** + * Test dummy record, representing + * either a provision or an request. + * The advice binding is simulated by + * storing a pattern matcher, and for + * the case of the advice request, the + * solution is simulated by a \c TestPOA* + */ struct TestPOA { TestPOA* solution_; @@ -156,9 +139,11 @@ namespace test { * to get pairs of participants to connect by an individual advice channel. * * This test covers the properties of this implementation datastructure in isolation. - * We employ special test entries, different from what is used in the advice system, - * and we create a specific instantiation of the advice::Index template solely - * for this test + * We employ special \link TestPOA test entries \endlink, different from what is used + * in the advice system (contrary to the real thing we're not differentiating between + * advice request and advice provision, as for the test all we need is the possibility + * to set an "advice solution"). To use these test records, we create a specific + * instantiation of the advice::Index template solely for this test. * * @see advice.hpp * @see AdviceBasics_test @@ -406,7 +391,7 @@ namespace test { CHECK (_hasSolution (2,9)); CHECK (_hasSolution (6,9)); CHECK (_hasSolution (3,8)); // the dog is unaffected - + CHECK ( idx.hasProvision (_entry (7,"cat"))); CHECK (!idx.hasProvision (_entry (4,"dog"))); @@ -419,6 +404,17 @@ namespace test { CHECK (_hasSolution (6,9)); CHECK (_hasSolution (3,4)); // but the dog got switched to the transmogrified-into-dog solution, // because it was added later than the existing solution 8 + + // a switch within the same cluster ("cat") + idx.modifyProvision (_entry (9,"cat"), _entry (7,"cat")); + CHECK (!idx.hasProvision (_entry (9,"cat"))); + CHECK ( idx.hasProvision (_entry (7,"cat"))); + CHECK ( idx.hasProvision (_entry (4,"dog"))); + CHECK (_hasSolution (1,7)); // because cat-7 is newly added, it shaddows the older cat-9 + CHECK (_hasSolution (2,7)); + CHECK (_hasSolution (6,7)); + CHECK (_hasSolution (3,4)); // but dog remains dog + CHECK (p_cnt+2 == idx.provision_count()); CHECK (r_cnt == idx.request_count()); CHECK (idx.isValid()); diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 1c68a868a..50d0496ec 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -541,7 +541,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo &rarr; AdviceImplementation
      -
      +
      [<img[Advice solution|uml/fig141573.png]]
       
       
      @@ -577,7 +577,7 @@ To start with, any advice matching and solution will //always happen within matc
       * Advice provisions are expected to happen only in small numbers; they will be searched stack-like, starting from the newes provisions, until a match is found.
       * Each advised entity basically creates an advice request, so there could be a larger number of request entries. In the typical search triggered from the provision side, each request entry will be visited and checked for match, which, if successful, causes a pointer to be set within the ~AdviceRequest object (located outside the realm of the advice system). While &mdash; obviously &mdash; multiple requests with similar binding match could be folded into a sub-list, we need actual timing measurements to determine the weight of these two calculation steps of matching and storing, which together comprise the handling of an advice solution.
       
      -The above considerations don't fully solve the question how to represent an computed solution within the index datastructure, candidates being to use the index within the provision list, or a direct pointer to the provision or even just to re-use the pointer stored into the ~AdviceRequest. Besides solutions found by matching, we need //fallback solutions// holding a default constructed piece of advice of the requested type. As these defaults aren't correlated at all to the involved bindings, but only to the advice type as such, it seems reasonable to keep them completely apart, like e.g. placing them into static memory managed by the ~AdviceProvision template instantiations.
      +The above considerations don't fully solve the question how to represent an computed solution within the index datastructure, candidates being to use the index within the provision list, or a direct pointer to the provision or even just to re-use the pointer stored into the ~AdviceRequest. My decision is to do the latter. Besides solutions found by matching, we need //fallback solutions// holding a default constructed piece of advice of the requested type. As these defaults aren't correlated at all to the involved bindings, but only to the advice type as such, it seems reasonable to keep them completely apart, like e.g. placing them into static memory managed by the ~AdviceProvision template instantiations.
       
       !!!interactions to be served by the index
       [>img[Advice solution|draw/AdviceBindingIndex1.png]]
      
      From 83b5c8c2c229581b7f2fef8239721438395aae29 Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Sat, 8 May 2010 21:05:01 +0200
      Subject: [PATCH 27/52] WIP code up external advice API
      
      ---
       src/lib/advice.hpp                            | 137 +++++++++++++++---
       src/lib/advice/binding.hpp                    |   5 +-
       .../advice/advice-binding-pattern-test.cpp    |   3 +-
       wiki/renderengine.html                        |   4 +-
       4 files changed, 127 insertions(+), 22 deletions(-)
      
      diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
      index 38ffa8ff8..df284ef0d 100644
      --- a/src/lib/advice.hpp
      +++ b/src/lib/advice.hpp
      @@ -100,68 +100,171 @@ namespace advice {
         /**
          * TODO type comment
          */
      -  template
         class PointOfAdvice
           {
      -    public:
      -      /** define or re-define the binding
      -       *  specifically designating this attachment to the advice system.
      +      Binding::Matcher pattern_;
      +      PointOfAdvice* resolution_;
      +
      +    protected:
      +      /** define or re-define the binding, which
      +       *  specifically labels this attachment to the advice system.
              *  @note issuing this on an existing connection is equivalent
              *        to re-connecting with the new binding.  
              */
      -      void defineBinding (Binding const& binding);
      +      void setBindingPattern (Binding const& binding)
      +        {
      +          pattern_ = binding.buildMatcher();
      +        }
             
      -      /** access the \em current piece of advice */
      -      AD const& getAdvice()  const;
      +    public:
      +      explicit
      +      PointOfAdvice (Binding const& binding)
      +        : pattern_(binding.buildMatcher())
      +        , resolution_(0)
      +        { }
      +      
      +      // using default copy/assignment
             
             
      -      /* == policy definitions == */    ////TODO: extract into policy classes
             
      -      AD const& handleMissingSolution()  const;
      +      /* == Adapter interface for use within the Index == */
      +        
      +      friend HashVal
      +      hash_value (PointOfAdvice const& entry)
      +      {
      +        return hash_value (entry.pattern_);
      +      }
      +      
      +      friend const Binding::Matcher
      +      getMatcher (PointOfAdvice const& entry)
      +      {
      +        return entry.pattern_;
      +      }
      +      
      +      friend PointOfAdvice*
      +      getSolution (PointOfAdvice& entry)
      +      {
      +        return entry.resolution_;
      +      }
      +      
      +      friend void
      +      setSolution (PointOfAdvice* entry, PointOfAdvice* solution =0)
      +      {
      +        REQUIRE (entry);
      +        entry->resolution_ = solution;
      +      }
           };
         
         
      +  
      +  
         /**
          * Access point for the advising entity (server).
          * TODO type comment
          */
         template
         class Provision
      -    : public PointOfAdvice
      +    : public PointOfAdvice
           {
      +      AD theAdvice_;
      +      
      +      
      +      /* == policy definitions == */    ////TODO: extract into policy classes
      +      
      +      AD const& handleMissingSolution()  const { return AD(); }
      +      void deregistrate()                      { /* NOP */ }
      +      
             
           public:
      +      explicit
      +      Provision (Literal bindingSpec =0)
      +        : PointOfAdvice (Binding(bindingSpec).addTypeGuard())
      +        , theAdvice_()
      +        { }
      +      
      +     ~Provision()
      +        {
      +          this->deregistrate();
      +        }
      +      
      +      
             AD const&
             getAdvice()  const
               {
      -          UNIMPLEMENTED ("how to embody the piece of advice...");
      +          return theAdvice_;
               }
             
      -      void setAdvice (AD const& pieceOfAdvice);
      -      void retractAdvice();
      +      void setAdvice (AD const& pieceOfAdvice)
      +        {
      +          theAdvice_ = pieceOfAdvice;
      +          UNIMPLEMENTED ("change advice provision registration");
      +        }
      +      
      +      void retractAdvice()
      +        {
      +          theAdvice_ = this->handleMissingSolution();
      +          UNIMPLEMENTED ("notify index of retracted advice");
      +        }
      +      
      +      void
      +      defineBinding (Literal topic)
      +        {
      +          setBindingPattern (Binding(topic).addTypeGuard());
      +          UNIMPLEMENTED ("propagate binding change to index");
      +        }
           };
         
      +    
      +    
         
      +    
         /**
          * Access point for the advised entity (client).
          * TODO type comment
          */
         template
         class Request
      -    : public PointOfAdvice
      +    : public PointOfAdvice
           {
      -      Provision* solution_;
      +      typedef Provision AdviceProvision;
      +      
      +      
      +      /* == policy definitions == */    ////TODO: extract into policy classes
      +      
      +      AD const& handleMissingSolution()  const { return AD(); }
      +      
             
           public:
      +      explicit
      +      Request (Literal bindingSpec =0)
      +        : PointOfAdvice (Binding(bindingSpec).addTypeGuard())
      +        {
      +          UNIMPLEMENTED ("registration with the index");
      +        }
      +      
      +     ~Request()
      +        {
      +          UNIMPLEMENTED ("detach from index");
      +        }
      +      
      +      
             AD const&
             getAdvice()  const
               {
      -          if (!solution_)
      +          AdviceProvision* solution = static_cast (getSolution (*this));
      +          if (!solution)
                   return this->handleMissingSolution();
                 else
      -            return solution_->getAdvice();
      +            return solution->getAdvice();
               }
             
      +      
      +      void
      +      defineBinding (Literal topic)
      +        {
      +          setBindingPattern (Binding(topic).addTypeGuard());
      +          UNIMPLEMENTED ("propagate binding change to index");
      +        }
           };
         
       
      diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp
      index c73378c31..5c2641d73 100644
      --- a/src/lib/advice/binding.hpp
      +++ b/src/lib/advice/binding.hpp
      @@ -201,7 +201,7 @@ namespace advice {
             void addPredicate (Literal spec);
             
             template
      -      void addTypeGuard();
      +      Binding const& addTypeGuard();
             
             
             Matcher buildMatcher()  const;
      @@ -225,10 +225,11 @@ namespace advice {
         }
         
         template
      -  inline void
      +  inline Binding const&
         Binding::addTypeGuard()
         {
           atoms_.insert (Atom ("advice.type."+lumiera::query::buildTypeID()));
      +    return *this;
         }
         
         
      diff --git a/tests/lib/advice/advice-binding-pattern-test.cpp b/tests/lib/advice/advice-binding-pattern-test.cpp
      index 9cbb8fa0c..285b3065e 100644
      --- a/tests/lib/advice/advice-binding-pattern-test.cpp
      +++ b/tests/lib/advice/advice-binding-pattern-test.cpp
      @@ -121,7 +121,8 @@ namespace test  {
                 CHECK (b0 != b1);  CHECK (b1 != b0);
                 CHECK (b0 != b2);  CHECK (b2 != b0);
                 
      -          b2.addPredicate("cat1()");
      +          b2.addPredicate("cat1()");          // adding the same predicate multiple times has no effect 
      +          b2.addPredicate(" cat1 "); 
                 CHECK (b1 == b2);
                 b2.addPredicate("cat3(zzz)");
                 CHECK (b1 != b2);
      diff --git a/wiki/renderengine.html b/wiki/renderengine.html
      index 50d0496ec..b692529b5 100644
      --- a/wiki/renderengine.html
      +++ b/wiki/renderengine.html
      @@ -541,14 +541,14 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
       &rarr; AdviceImplementation
       
      -
      +
      [<img[Advice solution|uml/fig141573.png]]
       
       
       
       
       
      -The advice system is //templated on the advice type// &mdash; so basically there is an independent lookup table for each different kind of advice.The advice system is a sytem wide singleton service, but it is never addressed directly by the participants. Rather, instances of ~AdviceProvision and ~AdviceRequest act as point of access. But these aren't completely symmetric; while the ~AdviceRequest is owned by the advised entity, the ~AdviceProvision is a value object, a uniform holder used to introduce new advice into the system. ~AdviceProvision is copied into an internal buffer and managed by the advice system, as is the actual advice item, which is copied alongside.
      +The advice system is //templated on the advice type// &mdash; so basically any collaboration is limited to a distinct advice type. But currently (as of 5/2010), this typed context is kept on the interface level, while the implementation is built on top of a single lookup table (which might create contention problems in the future and thus may be changed without further notice). The advice system is a system wide singleton service, but it is never addressed directly by the participants. Rather, instances of ~AdviceProvision and ~AdviceRequest act as point of access. But these aren't completely symmetric; while the ~AdviceRequest is owned by the advised entity, the ~AdviceProvision is a value object, a uniform holder used to introduce new advice into the system. ~AdviceProvision is copied into an internal buffer and managed by the advice system, as is the actual advice item, which is copied alongside.
       
       In order to find matches and provide advice solutions, the advice system maintains an index data structure called ''~BindingIndex''. The actual binding predicates are represented by value objects stored within this index table. The matching process is triggered whenever a new possibility for an advice solution enters the system, which could be a new request, a new provision or a change in the specified bindings. A successful match causes a pointer to be set within the ~AdviceRequest, pointing to the ~AdviceProvision acting as solution. Thus, when a solution exists, the advised entity can access the advice value object by dereferencing this pointer. A new advice solution just results in setting a different pointer, which is atomic and doesn't need to be protected by locking. But note, omitting the locking means there is no memory barrier; thus the advised entity might not see any changed advice solution, until the corresponding thread(s) refresh their CPU cache. This might or might not be acceptable, depending on the context, and thus is configurable as policy. Similarly, the handling of default advice is configurable. Usually, advice is a default constructible value object. In this case, when there isn't any advice solution (yet), a pseudo solution holding the default constructed advice value is used to satisfy any advice access by the client (advised entity). The same can be used when the actual ~AdviceProvision gets //retracted.// As an alternative, when this default solution approach doesn't work, we can provide a policy either to throw or to wait blocking &mdash; but this alternative policy is similarly implemented with an //null object// (a placeholder ~AdviceProvision). Anyway, this implementation technique causes the advice system to collect some advice provisions, bindings and advice objects over time. It should use a pooling custom allocator in the final version. As the number of advisors is expected to be rather small, the storage occupied by these elements, which is effectively blocked until application exit, isn't considered a problem.
       
      
      From 7dcdff3287fb95d6e158629f62cf4be8c59c4a49 Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Sat, 22 May 2010 03:56:09 +0200
      Subject: [PATCH 28/52] advice-basics: stubbed and fixed to pass compiler
      
      ---
       src/lib/advice.hpp                      | 10 +++++-----
       src/lib/advice/index.hpp                |  2 +-
       tests/lib/advice/advice-basics-test.cpp | 12 +++---------
       tests/lib/advice/advice-index-test.cpp  |  4 ++--
       4 files changed, 11 insertions(+), 17 deletions(-)
      
      diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
      index df284ef0d..a5f03d6ce 100644
      --- a/src/lib/advice.hpp
      +++ b/src/lib/advice.hpp
      @@ -141,8 +141,8 @@ namespace advice {
               return entry.pattern_;
             }
             
      -      friend PointOfAdvice*
      -      getSolution (PointOfAdvice& entry)
      +      friend const PointOfAdvice*
      +      getSolution (PointOfAdvice const& entry)
             {
               return entry.resolution_;
             }
      @@ -171,7 +171,7 @@ namespace advice {
             
             /* == policy definitions == */    ////TODO: extract into policy classes
             
      -      AD const& handleMissingSolution()  const { return AD(); }
      +      AD const& handleMissingSolution()  const { return AD(); }              /////////////////////TODO either return value or build a registry of defaults
             void deregistrate()                      { /* NOP */ }
             
             
      @@ -226,12 +226,12 @@ namespace advice {
         class Request
           : public PointOfAdvice
           {
      -      typedef Provision AdviceProvision;
      +      typedef const Provision AdviceProvision;
             
             
             /* == policy definitions == */    ////TODO: extract into policy classes
             
      -      AD const& handleMissingSolution()  const { return AD(); }
      +      AD const& handleMissingSolution()  const { return AD(); }              /////////////////////TODO either return value or build a registry of defaults
             
             
           public:
      diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp
      index f4a96dd57..1a1fe273f 100644
      --- a/src/lib/advice/index.hpp
      +++ b/src/lib/advice/index.hpp
      @@ -551,7 +551,7 @@ namespace advice {
         {
           verify_Entry (e,hash);
           POA& request = *(e.second);
      -    POA* solution (getSolution (request));
      +    const POA* solution (getSolution (request));
           if (solution && hasProvision(*solution))
             {
               POA* currentSolution = provisionEntries_[hash].find_latest_solution (request); 
      diff --git a/tests/lib/advice/advice-basics-test.cpp b/tests/lib/advice/advice-basics-test.cpp
      index 7ed8e3b7b..8b1484dd8 100644
      --- a/tests/lib/advice/advice-basics-test.cpp
      +++ b/tests/lib/advice/advice-basics-test.cpp
      @@ -148,7 +148,6 @@ namespace test {
             void
             simpleExchange()
               {
      -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605
                 TheAdvised client;         // implicitly opens an request-for-advice
                 CHECK (client.got (0));    // no advice yet --> getting the default int()
                 
      @@ -159,7 +158,6 @@ namespace test {
                 
                 server.publish (rr);       // now an match is detected, creating an advice channel
                 CHECK (client.got (rr));   // ..so the client can pick up the provided advice value
      -#endif    /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605
               }
             
             
      @@ -167,7 +165,6 @@ namespace test {
             void
             createCollaboration()
               {
      -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605
                 TheAdvised client1 ("topic1()");
                 TheAdvisor server2 ("topic2()");
                 
      @@ -190,7 +187,6 @@ namespace test {
                 server1.rebind ("topic1()");
                 CHECK (client1.got(r1));
                 CHECK (client2.got(r2));
      -#endif    /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605
               }
             
             
      @@ -206,7 +202,6 @@ namespace test {
             void
             overwriting_and_retracting()
               {
      -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605
                 TheAdvised client1 ("topic1");
                 TheAdvised client2 ("topic2");
                 CHECK (client1.got(0));
      @@ -258,15 +253,15 @@ namespace test {
                   CHECK (client1.got(r1));
                   CHECK (client2.got(r1));
                   
      -            yetAnotherserver.rebind("topic1");
      +            yetAnotherServer.rebind("topic1");
                   CHECK (client1.got(r1));
                   CHECK (client2.got(0));
                   
      -            yetAnotherserver.clear();
      +            yetAnotherServer.clear();
                   CHECK (client1.got(0));
                   CHECK (client2.got(0));
                   
      -            yetAnotherserver.rebind("topic2");
      +            yetAnotherServer.rebind("topic2");
                   CHECK (client1.got(0));
                   CHECK (client2.got(0));
                   
      @@ -285,7 +280,6 @@ namespace test {
                 client2.rebind("nonExistingTopic");
                 CHECK (client1.got(r1));
                 CHECK (client2.got(0));
      -#endif    /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #605
               }
           };
         
      diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp
      index 4b4b25766..d1100ac32 100644
      --- a/tests/lib/advice/advice-index-test.cpp
      +++ b/tests/lib/advice/advice-index-test.cpp
      @@ -76,8 +76,8 @@ namespace test {
                 return entry.pattern_;
               }
               
      -        friend TestPOA*
      -        getSolution (TestPOA& entry)
      +        friend const TestPOA*
      +        getSolution (TestPOA const& entry)
               {
                 return entry.solution_;
               }
      
      From 69af7350700e27d6488099bc21ffcc25c714d325 Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Tue, 25 May 2010 06:51:37 +0200
      Subject: [PATCH 29/52] reconsider advice implementation. Investigate some
       tricky implementation decisions
      
      ---
       src/lib/advice.hpp                     |  7 ++++
       src/lib/advice/index.hpp               |  4 +++
       tests/lib/advice/advice-index-test.cpp |  2 +-
       wiki/renderengine.html                 | 44 ++++++++++++++++++--------
       4 files changed, 42 insertions(+), 15 deletions(-)
      
      diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
      index a5f03d6ce..c1fef9eab 100644
      --- a/src/lib/advice.hpp
      +++ b/src/lib/advice.hpp
      @@ -161,6 +161,13 @@ namespace advice {
         /**
          * Access point for the advising entity (server).
          * TODO type comment
      +   * 
      +   * TODO planned implementation of memory handling: see notes in TiddlyWiki
      +   *      Basically I'll use this->resolution_ to point to the copy incorporated into the advice system.
      +   *      This is some kind of "unofficial" ownership and slightly incorrect, but seems the most straight forward implementation.
      +   *      Thus each Provision cares for "his" advice and just detaches when going away. Consequently, by default, advice provisions
      +   *      aren't freed during the lifetime of the application. We'll see if this causes problems. 
      +   *      
          */
         template
         class Provision
      diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp
      index 1a1fe273f..31e2bf0ca 100644
      --- a/src/lib/advice/index.hpp
      +++ b/src/lib/advice/index.hpp
      @@ -132,6 +132,10 @@ namespace advice {
          * by invoking the free function \c setSolution(POA) for the
          * corresponding PointOfAdvice entity.
          * 
      +   * @note element \em identity is defined in terms of pointing 
      +   *       to the same memory location of a POA (point of advice).
      +   *       Thus e.g. #hasProvision means this index holds an entry
      +   *       pointing to exactly this given data entity.
          * @note the diagnostic API is mainly intended for unit testing
          *       and \em not implemented with focus on performance. 
          */
      diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp
      index d1100ac32..268089ddc 100644
      --- a/tests/lib/advice/advice-index-test.cpp
      +++ b/tests/lib/advice/advice-index-test.cpp
      @@ -410,7 +410,7 @@ namespace test {
                 CHECK (!idx.hasProvision (_entry (9,"cat")));
                 CHECK ( idx.hasProvision (_entry (7,"cat")));
                 CHECK ( idx.hasProvision (_entry (4,"dog")));
      -          CHECK (_hasSolution (1,7));                  // because cat-7 is newly added, it shaddows the older cat-9
      +          CHECK (_hasSolution (1,7));                  // because cat-7 is newly added, it shadows the older cat-9
                 CHECK (_hasSolution (2,7));
                 CHECK (_hasSolution (6,7));
                 CHECK (_hasSolution (3,4));                  // but dog remains dog
      diff --git a/wiki/renderengine.html b/wiki/renderengine.html
      index b692529b5..51daa57fa 100644
      --- a/wiki/renderengine.html
      +++ b/wiki/renderengine.html
      @@ -541,7 +541,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
       &rarr; AdviceImplementation
       
      -
      +
      [<img[Advice solution|uml/fig141573.png]]
       
       
      @@ -550,7 +550,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
       
       The advice system is //templated on the advice type// &mdash; so basically any collaboration is limited to a distinct advice type. But currently (as of 5/2010), this typed context is kept on the interface level, while the implementation is built on top of a single lookup table (which might create contention problems in the future and thus may be changed without further notice). The advice system is a system wide singleton service, but it is never addressed directly by the participants. Rather, instances of ~AdviceProvision and ~AdviceRequest act as point of access. But these aren't completely symmetric; while the ~AdviceRequest is owned by the advised entity, the ~AdviceProvision is a value object, a uniform holder used to introduce new advice into the system. ~AdviceProvision is copied into an internal buffer and managed by the advice system, as is the actual advice item, which is copied alongside.
       
      -In order to find matches and provide advice solutions, the advice system maintains an index data structure called ''~BindingIndex''. The actual binding predicates are represented by value objects stored within this index table. The matching process is triggered whenever a new possibility for an advice solution enters the system, which could be a new request, a new provision or a change in the specified bindings. A successful match causes a pointer to be set within the ~AdviceRequest, pointing to the ~AdviceProvision acting as solution. Thus, when a solution exists, the advised entity can access the advice value object by dereferencing this pointer. A new advice solution just results in setting a different pointer, which is atomic and doesn't need to be protected by locking. But note, omitting the locking means there is no memory barrier; thus the advised entity might not see any changed advice solution, until the corresponding thread(s) refresh their CPU cache. This might or might not be acceptable, depending on the context, and thus is configurable as policy. Similarly, the handling of default advice is configurable. Usually, advice is a default constructible value object. In this case, when there isn't any advice solution (yet), a pseudo solution holding the default constructed advice value is used to satisfy any advice access by the client (advised entity). The same can be used when the actual ~AdviceProvision gets //retracted.// As an alternative, when this default solution approach doesn't work, we can provide a policy either to throw or to wait blocking &mdash; but this alternative policy is similarly implemented with an //null object// (a placeholder ~AdviceProvision). Anyway, this implementation technique causes the advice system to collect some advice provisions, bindings and advice objects over time. It should use a pooling custom allocator in the final version. As the number of advisors is expected to be rather small, the storage occupied by these elements, which is effectively blocked until application exit, isn't considered a problem.
      +In order to find matches and provide advice solutions, the advice system maintains an index data structure called ''~Binding-Index''. The actual binding predicates are represented by value objects stored within this index table. The matching process is triggered whenever a new possibility for an advice solution enters the system, which could be a new request, a new provision or a change in the specified bindings. A successful match causes a pointer to be set within the ~AdviceRequest, pointing to the ~AdviceProvision acting as solution. Thus, when a solution exists, the advised entity can access the advice value object by dereferencing this pointer. A new advice solution just results in setting a different pointer, which is atomic and doesn't need to be protected by locking. But note, omitting the locking means there is no memory barrier; thus the advised entity might not see any changed advice solution, until the corresponding thread(s) refresh their CPU cache. This might or might not be acceptable, depending on the context, and thus is configurable as policy. Similarly, the handling of default advice is configurable. Usually, advice is a default constructible value object. In this case, when there isn't any advice solution (yet), a pseudo solution holding the default constructed advice value is used to satisfy any advice access by the client (advised entity). The same can be used when the actual ~AdviceProvision gets //retracted.// As an alternative, when this default solution approach doesn't work, we can provide a policy either to throw or to wait blocking &mdash; but this alternative policy is similarly implemented with an //null object// (a placeholder ~AdviceProvision). Anyway, this implementation technique causes the advice system to collect some advice provisions, bindings and advice objects over time. It should use a pooling custom allocator in the final version. As the number of advisors is expected to be rather small, the storage occupied by these elements, which is effectively blocked until application exit, isn't considered a problem.
       
       !organising the advice solution
       This is the tricky part of the whole advice system implementation. A naive implementation will quickly degenerate in performance, as costs are of order ~AdviceProvisions * ~AdviceRequests * (average number of binding terms). But contrary to the standard solutions for rules based systems (either forward or backward chaining), in this case here always complete binding sets are to be matched, which allows to reduce the effort.
      @@ -570,6 +570,18 @@ We have to provide dedicated storage for the actual advice provisions and for th
       * in both cases, any of these entries could be removed any time on de-registration of the corresponding external entity
       * we need to track existing advice solutions, because we need to be able to overwrite with new advice and to remove all solutions bound to a given pattern about to leave the system. One provision could create a large number of solutions, while each registration always holds onto exactly one solution (which could be a default/placeholder solution though)
       
      +!!!!subtle variations in semantics
      +While generally advice has value semantics and there is no ownership or distinguishable identity, the actual implementation technique creates the possibility for some subtle semantic variations. At the time of this writing (5/2010) no external point of reference was available to decide upon the correct implementation variant. These variations get visible when advice is //retracted.// Ideally, a new advisor would re-attach to an existing provision and supersede the contained advice information with new data. Thus, after a chain of such new provisions all attaching with the identical binding, when finally the advice gets retracted, any advice provisions would be gone and we'd fall back onto the default solution. Thus, "retracting" would mean to void any advice given with this binding.
      +But there is another conceivable variation of semantics, which yields some benefits implementation-wise: Advice can be provided as "I don't care what was said, but here is new information". In this case, the mechanism of resolving and finding a match would be responsible to pick the latest addition, while the provisions would just be dumped into the system. In this case, "retracting" would mean just to cancel //one specific//&nbsp; piece of information and might cause in an older advice solution to be uncovered and revived. The default (empty) solution would be used in this case only after retracting all advice provisions.
      +
      +!!!!implementation variants with respect to attachment and memory management
      +Aside from the index, handling of the advice provisions turns out to be tricky.
      +* management by ref-count was ruled out due to contention and locality considerations
      +* the most straight forward implementation would be for the ~AdviceProvision within the advisor to keep kind of an "inofficial" link to "its" provision, allowing to modify and retract it during the lifetime of the advisor. When going away without retracting (the default behaviour), the provision, as added into the system would remain there as a dangling entry. It is still reachable via the index, but not maintained in any further way. If memory usage turns out to be a problem, we'd need to enqueue these entries for clean-up.
      +* but as this simple solution contradicts the general advice semantics in a subtle way (see previous paragraph), we could insist on really re-capturing and retracting previous advice automatically on each new advice provision or modification. In this case, due to the requirement of thread safety, each addition, binding modification, placing of new advice or retraction would require to do an index search to find an existing provision with equivalent binding (same binding definition, not just a matching binding pattern). As a later provision could stomp upon an existing provision without the original advisor noticing this, we can't use the internal references anymore; we really need to search each time and also need a global lock during the modification transaction.
      +* an attempt to reduce this considerable overhead would be to use an back-link from the provision as added to the system to the original source (the ~AdviceProvision owned by the advisor). On modification, this original source would be notified and thus detached. Of course this is tricky to implement correctly, and also requires locking.
      +The decision for the initial implementation is to use the first variant and just accept the slightly imprecise semantics.
      +
       !!!index datastructure
       It is clear by now that the implementation datastrucutre has to serve as a kind of //reference count.// Within this datastructure, any constructed advice solution needs to be reflected somehow, to prevent us from discarding an advice provision still accessible. Allowing lock-free access to the advice solution (planned feature) adds an special twist, because in this case we can't even tell for sure if an overwritten old solution is actually gone (or if its still referred from some thread's cached memeory). This could be addressed with an transactional approach (which might be good anyway) &mdash; but I tend to leave this special concern asside for now.
       
      @@ -600,7 +612,7 @@ __Invariant__: each request has a valid soultion pointer set (maybe pointing to
       Clearly, retracting advice (and consequently also the modification) is expensive. After finishing these operations, the old/retracted provision can be discarded (or put asside in case of non-locking advice access). Other operations don't cause de-allocation, as provisions remain within the system, even if the original advising entity is gone.
       
      -
      +
      From analysing a number of intended AdviceSituations, some requirements for an Advice collaboration and implementation can be extracted.
       
       * the piece of advice is //not shared// between advisor and the advised entities; rather, it is copied into storage managed by the advice system
      @@ -614,11 +626,11 @@ Clearly, retracting advice (and consequently also the modification) is expensive
       * later, possible and partial solutions could be cached, similar to the rete algorithm. Dispatching a solution should work lock-free
       * advice can be replaced by new advice, which causes all matching advice solutions to behave as being overwritten.
       * when locking is left out, we can't give any guarantee as to when a given advice gets visible to the advised entity
      -* throughput doesn't seem to be an issue, but picking up exsiting advice should be as fast as possible
      +* throughput doesn't seem to be an issue, but picking up existing advice should be as fast as possible
       * we expect a small number of advisors collaborating with and a larger number of advised entities.
       
       !!questions
      -;when does the advice colaboration actually happen?
      +;when does the advice collaboration actually happen?
       :when there is both a client (advised) and a server (advisor) and their advice bindings match
       ;can there be multiple matches?
       :within the system as a whole there can be multiple solutions
      @@ -628,27 +640,30 @@ Clearly, retracting advice (and consequently also the modification) is expensive
       :both sides don't behave symmetrically, and thus the consequences are different
       :on the client side, advice is just //available.// When there is newer one, the previous advice is overwritten
       :the server side doesn't //contain// advice &mdash; rather, it is placed into the system. After that, the advisor can go away
      -:thus, if an advisor places new advice into an existing advice provision, this effectively initiates a new colaboration
      +:thus, if an advisor places new advice into an existing advice provision, this effectively initiates a new collaboration
       :if the new advice reaches the same destination, it overwrites; but it may as well reach a different destination this time
       ;can just one advice provision create multiplicity?
       :yes, because of the matching process there could be multiple solutions. But neither the client nor the server is aware of that.
       ;can advice be changed?
       :No. When inserted into the system, the advisor looses any direct connection to the piece of advice (it is copied)
       :But an advisor can put up another piece of advice into the same advice provision, thereby effectively overwriting at the destination
      +;if advice is copied, what about ownership and identity?
      +:advice has //value semantics.// Thus it has no distinguishable identity beyond the binding used to attach it
      +:a provision does not "own" advice. It is a piece of information, and the latest information is what counts
       ;can the binding be modified dynamically?
       :this is treated as if retracting the existing point of advice and opening a new one.
       ;what drives the matching?
      -:whenever a new point of adivice is opened, search for a matching solution happens.
      -:thus, the actual colaboration can be initiated from both sides
      -:when a match happens, the corresponding advice point solution gets added into the sytem
      +:whenever a new point of advice is opened, search for a matching solution happens.
      +:thus, the actual collaboration can be initiated from both sides
      +:when a match happens, the corresponding advice point solution gets added into the system
       ;what about the lifetime of such a solution?
      -:it is tied to the //referral// &mdash; but there is an asymetry between server and client
      +:it is tied to the //referral// &mdash; but there is an asymmetry between server and client
       :referral is bound to the server sided / client sided point of advice being still in existence
       :but the server sided point of advice is copied into the system, while the client sided is owned by the client
      -:thus, when an advisor goes away, any actual solution remains valid, until no client refers to it anymore
      -:on the client side there is an asymetry: actually, a new advice request can be opened, with an exactly identical binding
      +:thus, when an advisor goes away without explicitly //retracting//&nbsp; the advice, any actual solution remains valid
      +:on the client side there is an asymmetry: actually, a new advice request can be opened, with an exactly identical binding
       :in this case, existing connections will be re-used. But any differences in the binding will require searching a new solution
      -;is the search for an adivce point solution exhaustive?
      +;is the search for an advice point solution exhaustive?
       :from the server side, when a new advice provision / binding is put up, //any// possible advice channel will be searched
       :contrary to this, at the client side, the first match found wins and will establish an advice channel.
       
      @@ -658,8 +673,9 @@ After considering the implementation possibilities, some not completely determin
       * there is always an implicit //default advice solution.//
       * advice //is not an messaging system// &mdash; no advice queue
       * signals (continuations) are acceptable as a extension to be provided later
      +* retracting advice means to retreat a specific solution. This might or might not uncover earlier solutions (undefined behaviour)
       * we don't support any kind of dynamic re-evaluation of the binding match (this means not supporting the placement use case)
      -* the binding pattern is //interpreted strictly as a conjuction of logic predicates// &mdash; no partial match, but arguments are allowed
      +* the binding pattern is //interpreted strictly as a conjunction of logic predicates// &mdash; no partial match, but arguments are allowed
       * we prepare for a later extension to //full unification of arguments,// and provide a way of accessing the created bindings as //advice parameters.//
       
       Combining all these requirements and properties provides the foundation for the &rarr; AdviceImplementation
      
      From d5ebe14d73f05fbf07e15abaadf03862005c4954 Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Thu, 27 May 2010 03:42:23 +0200
      Subject: [PATCH 30/52] add (protected) calls to the AdviceSystem
      
      ---
       src/lib/advice.hpp        | 20 +++++++++++++------
       src/lib/advice/advice.cpp | 42 +++++++++++++++++++++++++++++++++++++++
       2 files changed, 56 insertions(+), 6 deletions(-)
      
      diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
      index c1fef9eab..33cc3392e 100644
      --- a/src/lib/advice.hpp
      +++ b/src/lib/advice.hpp
      @@ -116,6 +116,14 @@ namespace advice {
                 pattern_ = binding.buildMatcher();
               }
             
      +      void publishProvision();
      +      void discardSolutions ();
      +      void publishBindingChange();
      +      void publishRequestBindingChange();
      +      
      +      void registrateRequest();
      +      void deregistrateRequest();
      +      
           public:
             explicit
             PointOfAdvice (Binding const& binding)
      @@ -204,20 +212,20 @@ namespace advice {
             void setAdvice (AD const& pieceOfAdvice)
               {
                 theAdvice_ = pieceOfAdvice;
      -          UNIMPLEMENTED ("change advice provision registration");
      +          publishProvision (); ///////////////////////////TODO how to propagate without specific typing?
               }
             
             void retractAdvice()
               {
                 theAdvice_ = this->handleMissingSolution();
      -          UNIMPLEMENTED ("notify index of retracted advice");
      +          discardSolutions ();
               }
             
             void
             defineBinding (Literal topic)
               {
                 setBindingPattern (Binding(topic).addTypeGuard());
      -          UNIMPLEMENTED ("propagate binding change to index");
      +          publishBindingChange();
               }
           };
         
      @@ -246,12 +254,12 @@ namespace advice {
             Request (Literal bindingSpec =0)
               : PointOfAdvice (Binding(bindingSpec).addTypeGuard())
               {
      -          UNIMPLEMENTED ("registration with the index");
      +          registrateRequest();
               }
             
            ~Request()
               {
      -          UNIMPLEMENTED ("detach from index");
      +          deregistrateRequest();
               }
             
             
      @@ -270,7 +278,7 @@ namespace advice {
             defineBinding (Literal topic)
               {
                 setBindingPattern (Binding(topic).addTypeGuard());
      -          UNIMPLEMENTED ("propagate binding change to index");
      +          publishRequestBindingChange();
               }
           };
         
      diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
      index dfb9dc48c..1ed7889fb 100644
      --- a/src/lib/advice/advice.cpp
      +++ b/src/lib/advice/advice.cpp
      @@ -32,6 +32,48 @@ namespace advice {
       
         
         /* ohlolololohaha */
      +  void
      +  PointOfAdvice::publishProvision()
      +  {
      +    UNIMPLEMENTED ("change advice provision registration");
      +  }
      +  
      +  
      +  void
      +  PointOfAdvice::discardSolutions ()
      +  {
      +    UNIMPLEMENTED ("notify index of retracted advice");
      +  }
      +  
      +  
      +  void
      +  PointOfAdvice::publishBindingChange ()
      +  {
      +    UNIMPLEMENTED ("propagate binding change to index");
      +  }
      +      
      +      
      +  void
      +  PointOfAdvice::publishRequestBindingChange()
      +  {
      +    UNIMPLEMENTED ("propagate binding change to index");
      +  }
      +  
      +  
      +  void
      +  PointOfAdvice::registrateRequest()
      +  {
      +    UNIMPLEMENTED ("registrate request with the index");
      +  }
      +  
      +  
      +  void
      +  PointOfAdvice::deregistrateRequest()
      +  {
      +    UNIMPLEMENTED ("detach request from index");
      +  }
      +
      +
         
         
         
      
      From 74e12dd17ac68b65dac49430499b9fa1bd64b845 Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Sat, 29 May 2010 01:25:14 +0200
      Subject: [PATCH 31/52] factor advice holding buffer into separate Class
      
      ---
       src/lib/advice.hpp        | 75 ++++++++++++++++++++++++++++++---------
       src/lib/advice/advice.cpp | 21 ++++++++---
       src/lib/advice/index.hpp  |  6 ++--
       3 files changed, 78 insertions(+), 24 deletions(-)
      
      diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
      index 33cc3392e..7a33ceffa 100644
      --- a/src/lib/advice.hpp
      +++ b/src/lib/advice.hpp
      @@ -116,13 +116,15 @@ namespace advice {
                 pattern_ = binding.buildMatcher();
               }
             
      -      void publishProvision();
      +      void publishProvision (PointOfAdvice*);
             void discardSolutions ();
             void publishBindingChange();
             void publishRequestBindingChange();
             
      -      void registrateRequest();
      -      void deregistrateRequest();
      +      void registerRequest();
      +      void deregisterRequest();
      +      
      +      void* getBuffer(size_t);
             
           public:
             explicit
      @@ -181,7 +183,6 @@ namespace advice {
         class Provision
           : public PointOfAdvice
           {
      -      AD theAdvice_;
             
             
             /* == policy definitions == */    ////TODO: extract into policy classes
      @@ -194,7 +195,6 @@ namespace advice {
             explicit
             Provision (Literal bindingSpec =0)
               : PointOfAdvice (Binding(bindingSpec).addTypeGuard())
      -        , theAdvice_()
               { }
             
            ~Provision()
      @@ -203,21 +203,13 @@ namespace advice {
               }
             
             
      -      AD const&
      -      getAdvice()  const
      -        {
      -          return theAdvice_;
      -        }
      -      
             void setAdvice (AD const& pieceOfAdvice)
               {
      -          theAdvice_ = pieceOfAdvice;
      -          publishProvision (); ///////////////////////////TODO how to propagate without specific typing?
      +          publishProvision (storeCopy (pieceOfAdvice));
               }
             
             void retractAdvice()
               {
      -          theAdvice_ = this->handleMissingSolution();
                 discardSolutions ();
               }
             
      @@ -227,8 +219,57 @@ namespace advice {
                 setBindingPattern (Binding(topic).addTypeGuard());
                 publishBindingChange();
               }
      +      
      +    private:
      +      PointOfAdvice* storeCopy (AD const& advice_given);
           };
         
      +  
      +  /**
      +   * Piece of Advice as incorporated into the AdviceSystem.
      +   * This holder-object contains a copy of the advice data
      +   * and is placed into the internal storage buffer; the
      +   * advice index keeps a (type erased) pointer to serve
      +   * any requests which happen to match the binding.
      +   */
      +  template
      +  class ActiveProvision
      +    : public PointOfAdvice
      +    {
      +      AD theAdvice_;
      +      
      +    public:
      +      AD const&
      +      getAdvice()  const
      +        {
      +          return theAdvice_;
      +        }
      +      
      +    protected:
      +      ActiveProvision (PointOfAdvice const& refPoint, AD const& advice_given)
      +        : PointOfAdvice(refPoint)
      +        , theAdvice_(advice_given)
      +        {
      +          setSolution (this, this);
      +        }
      +      
      +      friend class Provision;
      +    };
      +  
      +    
      +  /** function to copy advice into an internal buffer,
      +      @return type erased pointer to the data holder created
      +      @throw  error::External on allocation problems, plus anything
      +              the advice data may throw during copy construction. */
      +  template
      +  PointOfAdvice*
      +  Provision::storeCopy (AD const& advice_given)
      +    {
      +      typedef ActiveProvision Holder;
      +      return new(getBuffer(sizeof(Holder))) Holder (*this, advice_given);
      +    }
      +
      +  
           
           
         
      @@ -241,7 +282,7 @@ namespace advice {
         class Request
           : public PointOfAdvice
           {
      -      typedef const Provision AdviceProvision;
      +      typedef const ActiveProvision AdviceProvision;
             
             
             /* == policy definitions == */    ////TODO: extract into policy classes
      @@ -254,12 +295,12 @@ namespace advice {
             Request (Literal bindingSpec =0)
               : PointOfAdvice (Binding(bindingSpec).addTypeGuard())
               {
      -          registrateRequest();
      +          registerRequest();
               }
             
            ~Request()
               {
      -          deregistrateRequest();
      +          deregisterRequest();
               }
             
             
      diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
      index 1ed7889fb..e7f729055 100644
      --- a/src/lib/advice/advice.cpp
      +++ b/src/lib/advice/advice.cpp
      @@ -31,9 +31,22 @@ namespace advice {
       //  LUMIERA_ERROR_DEFINE (MISSING_INSTANCE, "Existing ID registration without associated instance");
       
         
      -  /* ohlolololohaha */
      +  /** allocate raw storage for a buffer holding the actual piece of advice.
      +      We need to manage this internally, as the original advice::Provision
      +      may go out of scope, while the advice information as such remains valid.
      +      @note the special twist is the size of the buffer depending on the actual
      +            advice type, which we need to erase for tracking all advice provisions
      +            and advice requests through an generic index datastructure.
      +      @todo rewrite to use Lumiera's block allocator / memory pool */
      +  void*
      +  PointOfAdvice::getBuffer(size_t)
      +  {
      +    UNIMPLEMENTED ("raw allocation and de-allocation of advice holding buffer");
      +  }
      +  
      +  
         void
      -  PointOfAdvice::publishProvision()
      +  PointOfAdvice::publishProvision (PointOfAdvice*)
         {
           UNIMPLEMENTED ("change advice provision registration");
         }
      @@ -61,14 +74,14 @@ namespace advice {
         
         
         void
      -  PointOfAdvice::registrateRequest()
      +  PointOfAdvice::registerRequest()
         {
           UNIMPLEMENTED ("registrate request with the index");
         }
         
         
         void
      -  PointOfAdvice::deregistrateRequest()
      +  PointOfAdvice::deregisterRequest()
         {
           UNIMPLEMENTED ("detach request from index");
         }
      diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp
      index 31e2bf0ca..e15c308d0 100644
      --- a/src/lib/advice/index.hpp
      +++ b/src/lib/advice/index.hpp
      @@ -392,9 +392,9 @@ namespace advice {
             void
             removeProvision (POA const& refEntry)
               {
      -          HashVal oKey (hash_value(refEntry));
      -          provisionEntries_[oKey].remove (refEntry);
      -          requestEntries_[oKey].retract_all_solutions (refEntry, provisionEntries_[oKey]);
      +          HashVal key (hash_value(refEntry));
      +          provisionEntries_[key].remove (refEntry);
      +          requestEntries_[key].retract_all_solutions (refEntry, provisionEntries_[key]);
               }
             
             
      
      From a9595d0a7f682c97c1b91718b65091de1f3b700e Mon Sep 17 00:00:00 2001
      From: Ichthyostega 
      Date: Sat, 29 May 2010 04:22:24 +0200
      Subject: [PATCH 32/52] refactor link to the advice system into separate
       baseclass
      
      ---
       doc/devel/uml/class164101.html       |   6 +-
       doc/devel/uml/class164229.html       |   2 +-
       doc/devel/uml/class164357.html       |   2 +-
       doc/devel/uml/class164485.html       |  10 +-
       doc/devel/uml/class164613.html       |  10 +-
       doc/devel/uml/class164741.html       |   4 +-
       doc/devel/uml/class165893.html       |  25 ++++
       doc/devel/uml/class166021.html       |  24 ++++
       doc/devel/uml/class166149.html       |  23 ++++
       doc/devel/uml/class166277.html       |  23 ++++
       doc/devel/uml/classes.html           |   8 +-
       doc/devel/uml/classes_list.html      |   8 +-
       doc/devel/uml/fig141445.png          | Bin 7905 -> 12661 bytes
       doc/devel/uml/index.html             |  20 +--
       doc/devel/uml/index_60.html          |  20 +--
       doc/devel/uml/index_65.html          |   7 +-
       doc/devel/uml/index_67.html          |  82 +++++------
       doc/devel/uml/index_68.html          |   2 +-
       doc/devel/uml/index_71.html          |   1 +
       doc/devel/uml/index_73.html          |   3 +-
       doc/devel/uml/index_77.html          |   2 +-
       doc/devel/uml/index_79.html          |   4 +-
       doc/devel/uml/index_80.html          |   1 +
       doc/devel/uml/index_82.html          |   3 +-
       doc/devel/uml/index_83.html          |  11 +-
       doc/devel/uml/index_84.html          |   8 +-
       doc/devel/uml/index_86.html          |  14 +-
       doc/devel/uml/public_operations.html |  10 +-
       src/lib/advice.hpp                   |  51 +++++--
       src/lib/advice/advice.cpp            |  14 +-
       uml/lumiera/128517                   | 194 +++++++++++++++++++++++----
       uml/lumiera/141445.diagram           | 103 ++++++++++----
       uml/lumiera/5.session                |  11 +-
       uml/lumiera/lumiera.prj              |   2 +-
       wiki/renderengine.html               |   7 +-
       35 files changed, 522 insertions(+), 193 deletions(-)
       create mode 100644 doc/devel/uml/class165893.html
       create mode 100644 doc/devel/uml/class166021.html
       create mode 100644 doc/devel/uml/class166149.html
       create mode 100644 doc/devel/uml/class166277.html
      
      diff --git a/doc/devel/uml/class164101.html b/doc/devel/uml/class164101.html
      index a7ea0ed91..0c7acab23 100644
      --- a/doc/devel/uml/class164101.html
      +++ b/doc/devel/uml/class164101.html
      @@ -16,10 +16,6 @@
       
       
       
      -

      Declaration :

      • C++ : class PointOfAdvice

      Directly inherited by : AdviceProvision AdviceRequest

      -
      - -
      Advice solving
      EDL Example1A simple example showing how the actual objects are placed in the Fixture (=definitive playlist). It shows a Video and Audio clip placed on two tracks
      EDL Example2More complex example showing the Object graph in the EDL and how it is linked into the Fixture to yield the actual locations. In this example, an HUE Effect is applied on a part of the Clip
      Engine Example1Example1 (from EDL) continued: here the RenderEngine to be created by the Builder from the Input shown in Example1
      Relation <unidirectional association>

      Declaration :

      Stereotype: holds

      -
      +

      Declaration :

      • C++ : class PointOfAdvice

      Directly inherited by : ActiveProvision AdviceLink

      diff --git a/doc/devel/uml/class164229.html b/doc/devel/uml/class164229.html index 63bedaff3..8272e8df6 100644 --- a/doc/devel/uml/class164229.html +++ b/doc/devel/uml/class164229.html @@ -19,7 +19,7 @@

      Declaration :

        Stereotype: actor

        -
        Relation <unidirectional association>

        Declaration :

        Stereotype: add

        +
        Relation <unidirectional association>

        Declaration :

        Stereotype: add

        diff --git a/doc/devel/uml/class164357.html b/doc/devel/uml/class164357.html index 46906439f..d81837c75 100644 --- a/doc/devel/uml/class164357.html +++ b/doc/devel/uml/class164357.html @@ -19,7 +19,7 @@

        Declaration :

          Stereotype: actor

          -
          Relation <unidirectional association>

          Declaration :

          Stereotype: owns

          +
          Relation <unidirectional association>

          Declaration :

          Stereotype: owns

          diff --git a/doc/devel/uml/class164485.html b/doc/devel/uml/class164485.html index 4fe5afcad..877b85817 100644 --- a/doc/devel/uml/class164485.html +++ b/doc/devel/uml/class164485.html @@ -4,20 +4,22 @@ -Class AdviceRequest +Class Request -
          Class AdviceRequest
          +
          Class Request

          -

          Declaration :

          +

          Declaration :

          • C++ : template<class AD> class Request : public AdviceLink
          -
          Relation <association>

          Declaration :

          +
          Relation <association>

          Declaration :

          +
          Operation getAdvice

          Declaration :

          • Uml : + getAdvice() :
          • C++ : public: getAdvice ()
          +

          All public operations : getAdvice

          diff --git a/doc/devel/uml/class164613.html b/doc/devel/uml/class164613.html index 47c23e875..d65a66606 100644 --- a/doc/devel/uml/class164613.html +++ b/doc/devel/uml/class164613.html @@ -4,20 +4,22 @@ -Class AdviceProvision +Class Provision -
          Class AdviceProvision
          +
          Class Provision

          -

          Declaration :

          +

          Declaration :

          • C++ : template<class AD> class Provision : public AdviceLink
          -
          Relation <association>

          Declaration :

          +
          Relation <association>

          Declaration :

          +
          Operation setAdvice

          Declaration :

          • Uml : + setAdvice() :
          • C++ : public: setAdvice ()
          +

          All public operations : setAdvice

          diff --git a/doc/devel/uml/class164741.html b/doc/devel/uml/class164741.html index 9f8dc59b9..ff2e4bdb7 100644 --- a/doc/devel/uml/class164741.html +++ b/doc/devel/uml/class164741.html @@ -18,7 +18,7 @@

          Declaration :

          • C++ : class Binding
          -
          Relation <association>

          Declaration :

          -
          Relation <association>

          Declaration :

          +
          Relation <association>

          Declaration :

          +
          Relation <association>

          Declaration :

          diff --git a/doc/devel/uml/class165893.html b/doc/devel/uml/class165893.html new file mode 100644 index 000000000..273315c31 --- /dev/null +++ b/doc/devel/uml/class165893.html @@ -0,0 +1,25 @@ + + + + + + +Class AdviceLink + + + + + +
          Class AdviceLink
          +

          + + + + +

          Declaration :

          Directly inherited by : Provision Request

          +
          + +
          Relation <unidirectional association>

          Declaration :

          Stereotype: attach

          +
          + + diff --git a/doc/devel/uml/class166021.html b/doc/devel/uml/class166021.html new file mode 100644 index 000000000..76eeedbec --- /dev/null +++ b/doc/devel/uml/class166021.html @@ -0,0 +1,24 @@ + + + + + + +Class ActiveProvision + + + + + +
          Class ActiveProvision
          +

          + + + + +

          Declaration :

          • C++ : template<class AD> class ActiveProvision : public PointOfAdvice
          + +
          Relation <unidirectional association>

          Declaration :

          Stereotype: holds

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

          + + + + +

          Declaration :

          • C++ : class AdviceSystem
          + +
          Relation <unidirectional association>

          Declaration :

          + + diff --git a/doc/devel/uml/class166277.html b/doc/devel/uml/class166277.html new file mode 100644 index 000000000..34565c66b --- /dev/null +++ b/doc/devel/uml/class166277.html @@ -0,0 +1,23 @@ + + + + + + +Class Index + + + + + +
          Class Index
          +

          + + + + +

          Declaration :

          • C++ : class Index
          + +
          Relation <directional composition>

          Declaration :

          + + diff --git a/doc/devel/uml/classes.html b/doc/devel/uml/classes.html index c0cb231a9..48eed5347 100644 --- a/doc/devel/uml/classes.html +++ b/doc/devel/uml/classes.html @@ -17,9 +17,10 @@ + - - + + @@ -97,6 +98,7 @@ + @@ -149,6 +151,7 @@ + @@ -167,6 +170,7 @@ + diff --git a/doc/devel/uml/classes_list.html b/doc/devel/uml/classes_list.html index adfef0f67..4551eea74 100644 --- a/doc/devel/uml/classes_list.html +++ b/doc/devel/uml/classes_list.html @@ -18,9 +18,10 @@
          AbstractMO
          ActiveProvision
          Adviceentity
          AdviceProvision
          AdviceRequest
          AdviceLink
          AdviceSystem
          Advisedactor
          Advisoractor
          AFrame
          HandlingPatterninterface
          Id
          ImplFacade
          Index
          InstanceHandle
          InterpolatorProvides the implementation for getting the acutal value of a time varying or automated effect/plugin parameter
          Invalid
          Project
          ProjectorSpecial video processing node used to scale and translate image data.
          Prototype
          Provision
          Proxy
          PullInput
          Query
          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
          Request
          Resolution
          ResolverBase
          ResolvingFacility
          - + - + - + - - - - - - - + + + + + + + diff --git a/doc/devel/uml/index_65.html b/doc/devel/uml/index_65.html index 9f3b83f00..d7919f28c 100644 --- a/doc/devel/uml/index_65.html +++ b/doc/devel/uml/index_65.html @@ -21,6 +21,7 @@ + @@ -31,8 +32,8 @@ - - + + @@ -65,8 +66,8 @@ - + diff --git a/doc/devel/uml/index_67.html b/doc/devel/uml/index_67.html index 484313c80..b7aadf243 100644 --- a/doc/devel/uml/index_67.html +++ b/doc/devel/uml/index_67.html @@ -35,62 +35,62 @@ - + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + - - - - + + - - - - + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/doc/devel/uml/index_68.html b/doc/devel/uml/index_68.html index 9866cde59..0af5dabf9 100644 --- a/doc/devel/uml/index_68.html +++ b/doc/devel/uml/index_68.html @@ -33,8 +33,8 @@ - + diff --git a/doc/devel/uml/index_71.html b/doc/devel/uml/index_71.html index 7a7e73ee2..a06017401 100644 --- a/doc/devel/uml/index_71.html +++ b/doc/devel/uml/index_71.html @@ -31,6 +31,7 @@ + diff --git a/doc/devel/uml/index_73.html b/doc/devel/uml/index_73.html index e57c8da0a..60e9bcda6 100644 --- a/doc/devel/uml/index_73.html +++ b/doc/devel/uml/index_73.html @@ -24,10 +24,11 @@ + - + diff --git a/doc/devel/uml/index_77.html b/doc/devel/uml/index_77.html index fd63eeb6b..bf5ec70f2 100644 --- a/doc/devel/uml/index_77.html +++ b/doc/devel/uml/index_77.html @@ -34,8 +34,8 @@ - + diff --git a/doc/devel/uml/index_79.html b/doc/devel/uml/index_79.html index c557cd0be..7a6016f25 100644 --- a/doc/devel/uml/index_79.html +++ b/doc/devel/uml/index_79.html @@ -21,9 +21,9 @@ - - + + diff --git a/doc/devel/uml/index_80.html b/doc/devel/uml/index_80.html index 1d12e75df..b75bcbbcc 100644 --- a/doc/devel/uml/index_80.html +++ b/doc/devel/uml/index_80.html @@ -81,6 +81,7 @@ + diff --git a/doc/devel/uml/index_82.html b/doc/devel/uml/index_82.html index 1e6853045..9afaba1ca 100644 --- a/doc/devel/uml/index_82.html +++ b/doc/devel/uml/index_82.html @@ -27,8 +27,8 @@ - + @@ -46,6 +46,7 @@ + diff --git a/doc/devel/uml/index_83.html b/doc/devel/uml/index_83.html index 122f728a5..20dc11c66 100644 --- a/doc/devel/uml/index_83.html +++ b/doc/devel/uml/index_83.html @@ -43,8 +43,8 @@ - + @@ -53,6 +53,7 @@ + @@ -71,15 +72,15 @@ - - + - + - + + diff --git a/doc/devel/uml/index_84.html b/doc/devel/uml/index_84.html index a164fedd0..0df6c9aef 100644 --- a/doc/devel/uml/index_84.html +++ b/doc/devel/uml/index_84.html @@ -44,13 +44,13 @@ - - + - - + + + diff --git a/doc/devel/uml/index_86.html b/doc/devel/uml/index_86.html index 5ac8ddfee..99d65bb91 100644 --- a/doc/devel/uml/index_86.html +++ b/doc/devel/uml/index_86.html @@ -22,20 +22,20 @@ + + - - - - - - + + - + + + diff --git a/doc/devel/uml/public_operations.html b/doc/devel/uml/public_operations.html index 649a88f03..360dc30db 100644 --- a/doc/devel/uml/public_operations.html +++ b/doc/devel/uml/public_operations.html @@ -36,6 +36,7 @@ + @@ -72,15 +73,16 @@ + - - - - + + + + diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp index 7a33ceffa..3281c7de2 100644 --- a/src/lib/advice.hpp +++ b/src/lib/advice.hpp @@ -116,16 +116,6 @@ namespace advice { pattern_ = binding.buildMatcher(); } - void publishProvision (PointOfAdvice*); - void discardSolutions (); - void publishBindingChange(); - void publishRequestBindingChange(); - - void registerRequest(); - void deregisterRequest(); - - void* getBuffer(size_t); - public: explicit PointOfAdvice (Binding const& binding) @@ -168,6 +158,39 @@ namespace advice { + /** + * Advice Collaboration partner, internally connected to the AdviceSystem. + * Both advice::Request and advice::Provision are linked in this way + * to an internal index datastructure, which allows to carry out + * the actual advice exchange and collaboration. + */ + class AdviceLink + : public PointOfAdvice + { + protected: + void publishProvision (PointOfAdvice*); + void discardSolutions (); + void publishBindingChange(); + void publishRequestBindingChange(); + + void registerRequest(); + void deregisterRequest(); + + void* getBuffer(size_t); + + public: + explicit + AdviceLink (Binding const& binding) + : PointOfAdvice(binding) + { } + + // using default copy/assignment + }; + + + + + /** * Access point for the advising entity (server). * TODO type comment @@ -181,7 +204,7 @@ namespace advice { */ template class Provision - : public PointOfAdvice + : public AdviceLink { @@ -194,7 +217,7 @@ namespace advice { public: explicit Provision (Literal bindingSpec =0) - : PointOfAdvice (Binding(bindingSpec).addTypeGuard()) + : AdviceLink (Binding(bindingSpec).addTypeGuard()) { } ~Provision() @@ -280,7 +303,7 @@ namespace advice { */ template class Request - : public PointOfAdvice + : public AdviceLink { typedef const ActiveProvision AdviceProvision; @@ -293,7 +316,7 @@ namespace advice { public: explicit Request (Literal bindingSpec =0) - : PointOfAdvice (Binding(bindingSpec).addTypeGuard()) + : AdviceLink (Binding(bindingSpec).addTypeGuard()) { registerRequest(); } diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp index e7f729055..0c0104e2e 100644 --- a/src/lib/advice/advice.cpp +++ b/src/lib/advice/advice.cpp @@ -39,49 +39,49 @@ namespace advice { and advice requests through an generic index datastructure. @todo rewrite to use Lumiera's block allocator / memory pool */ void* - PointOfAdvice::getBuffer(size_t) + AdviceLink::getBuffer(size_t) { UNIMPLEMENTED ("raw allocation and de-allocation of advice holding buffer"); } void - PointOfAdvice::publishProvision (PointOfAdvice*) + AdviceLink::publishProvision (PointOfAdvice*) { UNIMPLEMENTED ("change advice provision registration"); } void - PointOfAdvice::discardSolutions () + AdviceLink::discardSolutions () { UNIMPLEMENTED ("notify index of retracted advice"); } void - PointOfAdvice::publishBindingChange () + AdviceLink::publishBindingChange () { UNIMPLEMENTED ("propagate binding change to index"); } void - PointOfAdvice::publishRequestBindingChange() + AdviceLink::publishRequestBindingChange() { UNIMPLEMENTED ("propagate binding change to index"); } void - PointOfAdvice::registerRequest() + AdviceLink::registerRequest() { UNIMPLEMENTED ("registrate request with the index"); } void - PointOfAdvice::deregisterRequest() + AdviceLink::deregisterRequest() { UNIMPLEMENTED ("detach request from index"); } diff --git a/uml/lumiera/128517 b/uml/lumiera/128517 index 019609aa8..28202debe 100644 --- a/uml/lumiera/128517 +++ b/uml/lumiera/128517 @@ -1,6 +1,6 @@ format 58 "CommonLib" // CommonLib - revision 17 + revision 18 modified_by 5 "hiv" // class settings //class diagram settings @@ -272,15 +272,6 @@ ${inlines} idl_decl "" explicit_switch_type "" - classrelation 198661 // - relation 188165 ---> - stereotype "holds" - a role_name "" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 198661 // - b parent class_ref 163973 // Advice - end end class 164229 "Advisor" @@ -299,7 +290,7 @@ ${inlines} cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; " classrelation_ref 199045 // - b parent class_ref 164613 // AdviceProvision + b parent class_ref 164613 // Provision end end @@ -319,11 +310,11 @@ ${inlines} cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; " classrelation_ref 198917 // - b parent class_ref 164485 // AdviceRequest + b parent class_ref 164485 // Request end end - class 164485 "AdviceRequest" + class 165893 "AdviceLink" visibility package cpp_decl "${comment}${template}class ${name}${inherit} { @@ -336,14 +327,41 @@ ${inlines} idl_decl "" explicit_switch_type "" - classrelation 198789 // - relation 188293 ---|> + classrelation 201093 // + relation 190213 ---|> a public cpp default "${type}" - classrelation_ref 198789 // + classrelation_ref 201093 // b parent class_ref 164101 // PointOfAdvice end + classrelation 201733 // + relation 190853 ---> + stereotype "attach" + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 201733 // + b parent class_ref 166149 // AdviceSystem + end + end + + class 164485 "Request" + visibility package + nformals 1 + formal name "AD" type "class" explicit_default_value "" + explicit_extends "" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + php_decl "" + python_2_2 python_decl "" + idl_decl "" + explicit_switch_type "" + classrelation 199685 // relation 188933 ---- a role_name "" multiplicity "1" protected @@ -356,10 +374,37 @@ ${inlines} classrelation_ref 199813 // end + classrelation 201349 // + relation 190469 ---|> + a public + cpp default "${type}" + classrelation_ref 201349 // + b parent class_ref 165893 // AdviceLink + end + + operation 143749 "getAdvice" + public explicit_return_type "" + nparams 0 + cpp_decl " ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}${)}${const}${volatile} ${throw}${abstract};" + cpp_def "${comment}${inline}${type} +${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl} +{ + ${body} +} + +" + + + + + end end - class 164613 "AdviceProvision" + class 164613 "Provision" visibility package + nformals 1 + formal name "AD" type "class" explicit_default_value "" + explicit_extends "" cpp_decl "${comment}${template}class ${name}${inherit} { ${members} }; @@ -383,11 +428,63 @@ ${inlines} classrelation_ref 199301 // end - classrelation 199941 // - relation 189061 ---|> + classrelation 201221 // + relation 190341 ---|> a public cpp default "${type}" - classrelation_ref 199941 // + classrelation_ref 201221 // + b parent class_ref 165893 // AdviceLink + end + + operation 143621 "setAdvice" + public explicit_return_type "" + nparams 0 + cpp_decl " ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}${)}${const}${volatile} ${throw}${abstract};" + cpp_def "${comment}${inline}${type} +${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl} +{ + ${body} +} + +" + + + + + end + end + + class 166021 "ActiveProvision" + visibility package + nformals 1 + formal name "AD" type "class" explicit_default_value "" + explicit_extends "" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + php_decl "" + python_2_2 python_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 201477 // + relation 190597 ---> + stereotype "holds" + a role_name "" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 201477 // + b multiplicity "1" parent class_ref 163973 // Advice + end + + classrelation 201605 // + relation 190725 ---|> + a public + cpp default "${type}" + classrelation_ref 201605 // b parent class_ref 164101 // PointOfAdvice end end @@ -414,13 +511,59 @@ ${inlines} end end + class 166149 "AdviceSystem" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + php_decl "" + python_2_2 python_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 201989 // + relation 191109 ---> + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 201989 // + b parent class_ref 166277 // Index + end + end + + class 166277 "Index" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + php_decl "" + python_2_2 python_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 201861 // + relation 190981 *--> + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 201861 // + b parent class_ref 164741 // Binding + end + end + objectdiagram 141573 "Advice solving" write_horizontally default package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default show_stereotype_properties default size A4 end classinstance 142981 "" - type class_ref 164613 // AdviceProvision + type class_ref 164613 // Provision attributes end relations @@ -428,7 +571,7 @@ ${inlines} end classinstance 143109 "" - type class_ref 164613 // AdviceProvision + type class_ref 164613 // Provision attributes end relations @@ -436,7 +579,7 @@ ${inlines} end classinstance 143237 "" - type class_ref 164613 // AdviceProvision + type class_ref 164613 // Provision attributes end relations @@ -460,7 +603,7 @@ ${inlines} end classinstance 143621 "" - type class_ref 164485 // AdviceRequest + type class_ref 164485 // Request attributes end relations @@ -476,7 +619,7 @@ ${inlines} end classinstance 143877 "" - type class_ref 164485 // AdviceRequest + type class_ref 164485 // Request attributes end relations @@ -522,7 +665,6 @@ ${inlines} relations end end - end classview 129285 "StreamType" diff --git a/uml/lumiera/141445.diagram b/uml/lumiera/141445.diagram index f8d4b9195..9d099c054 100644 --- a/uml/lumiera/141445.diagram +++ b/uml/lumiera/141445.diagram @@ -3,70 +3,117 @@ format 58 classcanvas 128005 class_ref 163973 // Advice draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default color lightmagenta - xyz 348 20 2000 + xyz 67 17 2000 end classcanvas 128133 class_ref 164101 // PointOfAdvice draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default - xyz 265 102 2000 + xyz 266 11 2000 end classcanvas 128389 class_ref 164229 // Advisor draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default - xyz 20 188 2000 + xyz 19 202 2000 end classcanvas 128517 class_ref 164357 // Advised draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default - xyz 551 189 2000 + xyz 551 202 2000 end -classcanvas 128645 class_ref 164485 // AdviceRequest +classcanvas 128645 class_ref 164485 // Request draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default - xyz 364 207 2000 + xyz 435 207 2000 end -classcanvas 129157 class_ref 164613 // AdviceProvision +classcanvas 129157 class_ref 164613 // Provision draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default - xyz 157 207 2000 + xyz 174 207 2000 end classcanvas 129285 class_ref 164741 // Binding draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default - xyz 283 207 2000 + xyz 283 219 2000 end -relationcanvas 128261 relation_ref 188165 // - from ref 128133 z 1999 stereotype "<>" xyz 340 79 3000 to ref 128005 - no_role_a no_role_b - no_multiplicity_a no_multiplicity_b +classcanvas 130437 class_ref 165893 // AdviceLink + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default + xyz 274 90 2005 end -relationcanvas 128773 relation_ref 188293 // - geometry VHV - from ref 128645 z 1999 to point 405 171 - line 128901 z 1999 to point 304 171 - line 129029 z 1999 to ref 128133 - no_role_a no_role_b - no_multiplicity_a no_multiplicity_b +classcanvas 131461 class_ref 166021 // ActiveProvision + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default + xyz 157 90 2000 +end +classcanvas 132101 class_ref 166149 // AdviceSystem + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default + xyz 405 90 2000 +end +classcanvas 132229 class_ref 166277 // Index + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_members_multiplicity default show_members_initialization default member_max_width 0 show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default show_stereotype_properties default + xyz 363 128 2000 end relationcanvas 129413 relation_ref 188421 // - from ref 128517 z 1999 stereotype "<>" xyz 475 225 3000 to ref 128645 + from ref 128517 z 1999 stereotype "<>" xyz 510 223 3000 to ref 128645 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end relationcanvas 129541 relation_ref 188549 // - from ref 128389 z 1999 stereotype "<>" xyz 89 225 3000 to ref 129157 + from ref 128389 z 1999 stereotype "<>" xyz 72 223 3000 to ref 129157 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end relationcanvas 129669 relation_ref 188677 // from ref 129157 z 1999 to ref 129285 no_role_a no_role_b - multiplicity_a_pos 266 232 3000 multiplicity_b_pos 259 232 3000 + multiplicity_a_pos 275 240 3000 multiplicity_b_pos 237 240 3000 end relationcanvas 129925 relation_ref 188933 // from ref 128645 z 1999 to ref 129285 no_role_a no_role_b - multiplicity_a_pos 341 232 3000 multiplicity_b_pos 347 232 3000 + multiplicity_a_pos 333 240 3000 multiplicity_b_pos 427 241 3000 end -relationcanvas 130053 relation_ref 189061 // +relationcanvas 130565 relation_ref 190213 // + from ref 130437 z 1999 to ref 128133 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 130693 relation_ref 190341 // + geometry VHV unfixed + from ref 129157 z 1999 to point 203 184 + line 131205 z 1999 to point 305 184 + line 131333 z 1999 to ref 130437 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 130821 relation_ref 190469 // + geometry VHV unfixed + from ref 128645 z 1999 to point 465 184 + line 130949 z 1999 to point 305 184 + line 131077 z 1999 to ref 130437 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 131589 relation_ref 190597 // + from ref 131461 z 1999 stereotype "<>" xyz 101 79 3000 to ref 128005 + no_role_a no_role_b + multiplicity_a_pos 114 65 3000 multiplicity_b_pos 147 92 3000 +end +relationcanvas 131717 relation_ref 190725 // geometry VHV - from ref 129157 z 1999 to point 201 171 - line 130181 z 1999 to point 304 171 - line 130309 z 1999 to ref 128133 + from ref 131461 z 1999 to point 200 67 + line 131845 z 1999 to point 305 67 + line 131973 z 1999 to ref 128133 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 132613 relation_ref 190853 // + from ref 130437 z 1999 stereotype "<>" xyz 343 96 3000 to ref 132101 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 132741 relation_ref 190981 // + from ref 132229 z 1999 to point 383 199 + line 132997 z 1999 to ref 129285 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 133125 relation_ref 191109 // + geometry HVr + from ref 132101 z 1999 to point 444 145 + line 133253 z 1999 to ref 132229 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session index 194b63b33..522c2745b 100644 --- a/uml/lumiera/5.session +++ b/uml/lumiera/5.session @@ -8,9 +8,9 @@ diagrams 469 451 100 4 0 0 classdiagram_ref 140293 // TypedLookup 721 697 100 4 0 0 - classdiagram_ref 141445 // Advice entities + active classdiagram_ref 141445 // Advice entities 635 331 100 4 0 0 - active objectdiagram_ref 141573 // Advice solving + objectdiagram_ref 141573 // Advice solving 556 483 100 4 0 0 end show_stereotypes @@ -37,9 +37,12 @@ open classview_ref 128261 // Builder Workings usecaseview_ref 128261 // config examples class_ref 133253 // Frame - class_ref 164485 // AdviceRequest - class_ref 164613 // AdviceProvision + class_ref 164485 // Request + class_ref 164613 // Provision + class_ref 166021 // ActiveProvision class_ref 164741 // Binding + class_ref 166277 // Index + classinstance_ref 144517 // class_ref 145285 // MediaKind package_ref 131077 // ConfigQuery diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj index 13b4b5791..f3b36633d 100644 --- a/uml/lumiera/lumiera.prj +++ b/uml/lumiera/lumiera.prj @@ -1,6 +1,6 @@ format 58 "lumiera" - revision 62 + revision 63 modified_by 5 "hiv" cpp_root_dir "../../src/" diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 51daa57fa..9643f5c49 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -514,7 +514,7 @@ ColorPalette SiteUrl -
          +
          //pattern of collaboration for loosely coupled entities, to be used for various purposes within Proc...//
           Expecting Advice and giving Advice &mdash; this collaboration ranges somewhere between messaging and dynamic properties, but cross-cutting the primary, often hierarchical relation of dependencies. Always happening at a certain //point of advice,// which creates a distinct, static nature different of being just a convention, on the other hand, Advice is deliberately kept optional and received synchronously, albeit possibly within an continuation.
           
          @@ -523,7 +523,6 @@ Expecting Advice and giving Advice &mdash; this collaboration ranges somewhe
           [>img[Entities for Advice collaboration|uml/fig141445.png]]
           
           
          -
           !!Collaborators
           * the ''advised'' entity 
           * the ''advisor''
          @@ -541,7 +540,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
           &rarr; AdviceImplementation
           
          -
          +
          [<img[Advice solution|uml/fig141573.png]]
           
           
          @@ -555,7 +554,7 @@ In order to find matches and provide advice solutions, the advice system maintai
           !organising the advice solution
           This is the tricky part of the whole advice system implementation. A naive implementation will quickly degenerate in performance, as costs are of order ~AdviceProvisions * ~AdviceRequests * (average number of binding terms). But contrary to the standard solutions for rules based systems (either forward or backward chaining), in this case here always complete binding sets are to be matched, which allows to reduce the effort.
           
          -!!!solution idea
          +!!!solution mechanics
           The binding patterns are organised by //predicate symbol and the lists are normalised.// A simple normalisation could be lexicographic ordering of the predicate symbols. Then the resulting representation can be //hashed.// When all predicates are constant, a match can be detected by hashtable lookup, otherwise, in case some of the predicates contain variable arguments ({{red{planned extension}}}), the lookup is followed by an unification. For this to work, we'll have to include the arity into the predicate symbols used in the first matching stage. Moreover, we'll create a //matching closure// (functor object), internally holding the arguments for unification. This approach allows for //actual interpretation of the arguments.// It is conceivable that in special cases we'll get multiple instances of the same predicate, just with different arguments. The unification of these terms needs to consider each possible pairwise combination (cartesian product) &mdash; but working out the details of the implementation can safely be deferred until we'll actually hit such a special situation, thanks to the implementation by a functor.
           
           Fortunately, the calculation of this normalised patterns can be separated completely from the actual matching. Indeed, we don't even need to store the binding patterns at all within the binding index &mdash; storing the hash value is sufficient (and in case of patterns with arguments we'll attach the matching closure functor). Yet still we need to store a marker for each successful match, together with back-links, in order to handle changing and retracting of advice.
          
          From 91c2763fa4879d08ba253da9404a6b6e6edda086 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Tue, 1 Jun 2010 05:59:34 +0200
          Subject: [PATCH 33/52] WIP considering how to manage default / fallback advice
          
          ---
           src/lib/advice.hpp     |  8 ++++++--
           wiki/renderengine.html | 14 +++++++++++++-
           2 files changed, 19 insertions(+), 3 deletions(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index 3281c7de2..b04096036 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -254,6 +254,10 @@ namespace advice {
              * and is placed into the internal storage buffer; the
              * advice index keeps a (type erased) pointer to serve
              * any requests which happen to match the binding.
          +   * 
          +   * @note the ptr-to-solution in the inherited PointOfAdvice
          +   *       is currently (5/10) not used, because this \em is
          +   *       already the solution. 
              */
             template
             class ActiveProvision
          @@ -273,7 +277,7 @@ namespace advice {
                   : PointOfAdvice(refPoint)
                   , theAdvice_(advice_given)
                   {
          -          setSolution (this, this);
          +          setSolution (this, this); // not used currently (5/10)
                   }
                 
                 friend class Provision;
          @@ -310,7 +314,7 @@ namespace advice {
                 
                 /* == policy definitions == */    ////TODO: extract into policy classes
                 
          -      AD const& handleMissingSolution()  const { return AD(); }              /////////////////////TODO either return value or build a registry of defaults
          +      AD const& handleMissingSolution()  const { return AD(); }              /////////////////////TODO singleton or registry for default advice. See TiddlyWiki for discussion
                 
                 
               public:
          diff --git a/wiki/renderengine.html b/wiki/renderengine.html
          index 9643f5c49..80b45c3ed 100644
          --- a/wiki/renderengine.html
          +++ b/wiki/renderengine.html
          @@ -540,7 +540,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
           &rarr; AdviceImplementation
           
          -
          +
          [<img[Advice solution|uml/fig141573.png]]
           
           
          @@ -581,6 +581,18 @@ Aside from the index, handling of the advice provisions turns out to be tricky.
           * an attempt to reduce this considerable overhead would be to use an back-link from the provision as added to the system to the original source (the ~AdviceProvision owned by the advisor). On modification, this original source would be notified and thus detached. Of course this is tricky to implement correctly, and also requires locking.
           The decision for the initial implementation is to use the first variant and just accept the slightly imprecise semantics.
           
          +!!!lifecycle considerations
          +Behind the scenes, hidden within the {{{advice.cpp}}} implementation file, the ~AdviceSystem is maintained as singleton. According to a general lifecycle policy within Lumiera, no significant logic is allowed to execute in the shutdown phase of the application, once the {{{main()}}} has exited. Thus, any advice related operations might throw {{{error::Logic}}} after that point. The {{{~AdviceSystem()}}} also is a good place to free any buffers holding incorporated advice data, after having freed the index datastructure referring to these buffer storage, of course.
          +
          +!!!!handling of default advice
          +Basically, the behaviour when requesting non-existing advice may be configured by policy. But the default policy is to return ref to a default constructed instance of the advice type in that case. Just the (implementation related) problem is that we return advice by {{{const&}}}, not by value, so we're bound to create and manage this piece of default advice during the lifetime of the ~AdviceSystem. The way the ~AdviceSystem is accessed (only through the frontend of {{{advice::Request}}} and {{{advice::Provision}}} objects, in conjunction with the desire to control this behaviour by policy, creates a tricky implementation situation. Here we might also consider to use some separate kind of singleton bundle just for these default advice data (e.g. a templated version of //Meyer's Singleton...//), but this would create yet another difficult to define relation between the lifecycle of the ~AdviceSystem and such a singleton bundle.
          +<<<
          +{{red{WIP ... solution idea}}}: //let the handling-function for missing advice create an {{{advice::Provision<AD>}}}, with the same binding as the current request,//
          +i.e. fabricate the missing solution on-the-fly, setting a default constructed piece of advice data.
          +__pro__: simple to implement, avoids to re-create for this special case some of the functionality the index already provides
          +__con__: difficult to check and verify, loads additional data into the index table, the first request failure gets as expensive as an advice provision, how to fabricate a reliably matching solution is not obvious in case we allow variables in the binding pattern.
          +<<<
          +
           !!!index datastructure
           It is clear by now that the implementation datastrucutre has to serve as a kind of //reference count.// Within this datastructure, any constructed advice solution needs to be reflected somehow, to prevent us from discarding an advice provision still accessible. Allowing lock-free access to the advice solution (planned feature) adds an special twist, because in this case we can't even tell for sure if an overwritten old solution is actually gone (or if its still referred from some thread's cached memeory). This could be addressed with an transactional approach (which might be good anyway) &mdash; but I tend to leave this special concern asside for now.
           
          
          From 72c01e12c90f3293a855ad2781af2ea43cc9bea8 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Wed, 2 Jun 2010 06:03:06 +0200
          Subject: [PATCH 34/52] implement a simple singleton holder for NIL/default
           objects
          
          ---
           src/lib/null-value.hpp        | 84 ++++++++++++++++++++++++++++++
           tests/40components.tests      |  5 ++
           tests/lib/null-value-test.cpp | 96 +++++++++++++++++++++++++++++++++++
           3 files changed, 185 insertions(+)
           create mode 100644 src/lib/null-value.hpp
           create mode 100644 tests/lib/null-value-test.cpp
          
          diff --git a/src/lib/null-value.hpp b/src/lib/null-value.hpp
          new file mode 100644
          index 000000000..5b102d110
          --- /dev/null
          +++ b/src/lib/null-value.hpp
          @@ -0,0 +1,84 @@
          +/*
          +  NULL-VALUE.hpp  -  maintain per-type NIL values in static memory 
          + 
          +  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 null-value.hpp
          + ** Singleton-style holder for \em NIL or \em default values.
          + ** This template allows to maintain a "Null Object" value, with type-based access.
          + ** It is implemented as a cluster of Meyer's Singletons, thus the creation happens
          + ** on demand, and the destruction happens "sometime" during application shutdown.
          + ** Contrary to the generic lumiera Singleton holder, this implementation is
          + ** lightweight and without any further prerequisites, contains no logging,
          + ** no assertions and no locking.
          + ** @warning we can't make any assumptions regarding the exact time when the dtor
          + **          is called, and it is even impossible to detect if this happened already.
          + **          Any access after that point will use a defunct object, thus the user
          + **          needs to assure this facility is never used during application shutdown
          + ** 
          + ** \par purpose of NIL objects
          + ** Employing the NIL object pattern instead of NULL pointers typically leads to
          + ** greatly simplified and more robust code. Usually the only problem is these NIL
          + ** marker objects need to exist somewhere. In case no factory is used for object
          + ** creation, this NullValue holder might satisfy this need.
          + ** 
          + ** NIL objects are assumed to be default constructible for now. Initialisation
          + ** may introduce a race, which is considered acceptable here, as these objects
          + ** are assumed to be simple, constant and value-like.
          + ** 
          + ** @todo initialisation could be extended to use a free function to fabricate
          + **       the NIL value object, so to support the special case of an NIL object
          + **       not being default constructible
          + ** 
          + ** @see null-value-test.cpp
          + ** @see lib::advice::Request usage example
          + **
          + */
          +
          +
          +
          +#ifndef LIB_NULL_VALUE_H
          +#define LIB_NULL_VALUE_H
          +
          +
          +
          +namespace lib {
          +  
          +  /** 
          +   * Singleton holder for NIL or default value objects.
          +   * Implemented as a cluster of Meyer's singletons, maintaining
          +   * a single value per type.
          +   */
          +  template
          +  struct NullValue
          +    {
          +      static TY const&
          +      get()
          +        {
          +          static TY nilValue;
          +          return nilValue;
          +        }
          +    };
          +  
          +  
          +  
          +} // namespace lib
          +#endif
          diff --git a/tests/40components.tests b/tests/40components.tests
          index d8719d0db..eafc67b76 100644
          --- a/tests/40components.tests
          +++ b/tests/40components.tests
          @@ -359,6 +359,11 @@ return: 0
           END
           
           
          +TEST "NIL object singleton" NullValue_test  <
          + 
          +  This program is free software; you can redistribute it and/or
          +  modify it under the terms of the GNU General Public License as
          +  published by the Free Software Foundation; either version 2 of the
          +  License, or (at your option) any later version.
          + 
          +  This program is distributed in the hope that it will be useful,
          +  but WITHOUT ANY WARRANTY; without even the implied warranty of
          +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
          +  GNU General Public License for more details.
          + 
          +  You should have received a copy of the GNU General Public License
          +  along with this program; if not, write to the Free Software
          +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
          + 
          +* *****************************************************/
          +
          +
          +
          +
          +#include "lib/test/run.hpp"
          +#include "lib/null-value.hpp"
          +#include "lib/util.hpp"
          +
          +#include 
          +
          +
          +namespace lib {
          +namespace test{
          +  
          +  using util::isSameObject;
          +  using std::rand;
          +  
          +  
          +  namespace { // test data and helpers...
          +    
          +    
          +    /** Test dummy to track ctor call */
          +    struct DummyType
          +      {
          +        static bool created;
          +        
          +        uint id_;
          +        
          +        DummyType()
          +          : id_(1 + (rand() % 100))
          +          {
          +            created = true;
          +          }
          +      };
          +    
          +    bool DummyType::created  = false;
          +    
          +    
          +  }
          +  
          +  
          +  
          +  /***************************************************************************************
          +   * @test Access "NIL values" just by type, verify these are actually singletons
          +   *       and are indeed created on demand.
          +   * 
          +   * @see null-value.hpp
          +   * @see lib::advice::Request usage example
          +   */
          +  class NullValue_test : public Test
          +    {
          +      
          +      void
          +      run (Arg) 
          +        {
          +          CHECK (long() == NullValue::get());
          +          CHECK (short() == NullValue::get());
          +          CHECK (isSameObject(NullValue::get(), NullValue::get()));
          +          
          +          CHECK (!DummyType::created);
          +          DummyType copy (NullValue::get());
          +          CHECK ( DummyType::created);
          +          
          +          CHECK ( copy.id_ == NullValue::get().id_);
          +          CHECK (!isSameObject(NullValue::get(), copy));
          +          CHECK ( isSameObject(NullValue::get(), NullValue::get()));
          +        }
          +    };
          +  
          +  
          +  /** Register this test class... */
          +  LAUNCHER (NullValue_test, "unit common");
          +  
          +  
          +}} // namespace lib::test
          
          From d0e7f9b77d9ff0b087e77d5993ca123ca728ad56 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Wed, 2 Jun 2010 06:20:46 +0200
          Subject: [PATCH 35/52] use the NullValue holder to solve the problem with
           default advice solutions Implementation is simple, but the implications might
           be tricky
          
          ---
           src/lib/advice.hpp     |  6 +++---
           wiki/renderengine.html | 13 +++++--------
           2 files changed, 8 insertions(+), 11 deletions(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index b04096036..29a20d664 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -86,6 +86,7 @@
           //#include "proc/asset/struct-scheme.hpp"
           //#include "lib/hash-indexed.hpp"
           //#include "lib/util.hpp"
          +#include "lib/null-value.hpp"
           #include "lib/symbol.hpp"
           #include "lib/advice/binding.hpp"
           
          @@ -210,8 +211,7 @@ namespace advice {
                 
                 /* == policy definitions == */    ////TODO: extract into policy classes
                 
          -      AD const& handleMissingSolution()  const { return AD(); }              /////////////////////TODO either return value or build a registry of defaults
          -      void deregistrate()                      { /* NOP */ }
          +      void deregistrate() { /* NOP */ }
                 
                 
               public:
          @@ -314,7 +314,7 @@ namespace advice {
                 
                 /* == policy definitions == */    ////TODO: extract into policy classes
                 
          -      AD const& handleMissingSolution()  const { return AD(); }              /////////////////////TODO singleton or registry for default advice. See TiddlyWiki for discussion
          +      AD const& handleMissingSolution()  const { return NullValue::get(); }  ///< @warning might segfault when used during shutdown
                 
                 
               public:
          diff --git a/wiki/renderengine.html b/wiki/renderengine.html
          index 80b45c3ed..4ee4eba5f 100644
          --- a/wiki/renderengine.html
          +++ b/wiki/renderengine.html
          @@ -540,7 +540,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
           &rarr; AdviceImplementation
           
          -
          +
          [<img[Advice solution|uml/fig141573.png]]
           
           
          @@ -585,13 +585,10 @@ The decision for the initial implementation is to use the first variant and just
           Behind the scenes, hidden within the {{{advice.cpp}}} implementation file, the ~AdviceSystem is maintained as singleton. According to a general lifecycle policy within Lumiera, no significant logic is allowed to execute in the shutdown phase of the application, once the {{{main()}}} has exited. Thus, any advice related operations might throw {{{error::Logic}}} after that point. The {{{~AdviceSystem()}}} also is a good place to free any buffers holding incorporated advice data, after having freed the index datastructure referring to these buffer storage, of course.
           
           !!!!handling of default advice
          -Basically, the behaviour when requesting non-existing advice may be configured by policy. But the default policy is to return ref to a default constructed instance of the advice type in that case. Just the (implementation related) problem is that we return advice by {{{const&}}}, not by value, so we're bound to create and manage this piece of default advice during the lifetime of the ~AdviceSystem. The way the ~AdviceSystem is accessed (only through the frontend of {{{advice::Request}}} and {{{advice::Provision}}} objects, in conjunction with the desire to control this behaviour by policy, creates a tricky implementation situation. Here we might also consider to use some separate kind of singleton bundle just for these default advice data (e.g. a templated version of //Meyer's Singleton...//), but this would create yet another difficult to define relation between the lifecycle of the ~AdviceSystem and such a singleton bundle.
          -<<<
          -{{red{WIP ... solution idea}}}: //let the handling-function for missing advice create an {{{advice::Provision<AD>}}}, with the same binding as the current request,//
          -i.e. fabricate the missing solution on-the-fly, setting a default constructed piece of advice data.
          -__pro__: simple to implement, avoids to re-create for this special case some of the functionality the index already provides
          -__con__: difficult to check and verify, loads additional data into the index table, the first request failure gets as expensive as an advice provision, how to fabricate a reliably matching solution is not obvious in case we allow variables in the binding pattern.
          -<<<
          +Basically, the behaviour when requesting non-existing advice may be configured by policy. But the default policy is to return ref to a default constructed instance of the advice type in that case. Just the (implementation related) problem is that we return advice by {{{const&}}}, not by value, so we're bound to create and manage this piece of default advice during the lifetime of the ~AdviceSystem. The way the ~AdviceSystem is accessed (only through the frontend of {{{advice::Request}}} and {{{advice::Provision}}} objects, in conjunction with the desire to control this behaviour by policy, creates a tricky implementation situation.
          +* regarding the lifecycle (and also from the logical viewpoint) it would be desirable to handle this "default" or "no solution" case similar to accessing an existing solution. But unfortunately doing so would require a fully typed context; thus basically on inserting a new request, when returning from the index search without a dedicated solution, we'd need to fabricate a fallback solution to insert it into the provision index, while still holding the index lock. At that point it is not determined if we ever need that fallback solution. Alternatively we could consider to fabricate this fallback solution on first unsuccessful advice fetch. But this seems sill worse, as it turns an (possibly even lock free) ptr access into an index operation. Having a very cheap advice access seems like an asset.
          +* on the other hand, using some separate kind of singleton bundle just for these default advice data (e.g. a templated version of //Meyer's Singleton...//), the fallback solution can be settled independent from the ~AdviceSystem, right in the {{{advice.hpp}}} and using static memory, but the downside is now the fallback solution might be destroyed prior to shutdown of the ~AdviceSystem, as it lives in another compilation unit.
          +Thus the second approach looks favourable, but we should //note the fact that it is hard to secure this possible access to an already destroyed solution,// unless we decline using the advice feature after the end of {{{main()}}}. Such a policy seems to be reasonable anyway, as the current implementation also has difficulties to prevent accessing an already destroyed {{{advice::Provision}}}, being incorporated in the ~AdviceSystem, but accessed through a direct pointer in the {{{advice::Request}}}.
           
           !!!index datastructure
           It is clear by now that the implementation datastrucutre has to serve as a kind of //reference count.// Within this datastructure, any constructed advice solution needs to be reflected somehow, to prevent us from discarding an advice provision still accessible. Allowing lock-free access to the advice solution (planned feature) adds an special twist, because in this case we can't even tell for sure if an overwritten old solution is actually gone (or if its still referred from some thread's cached memeory). This could be addressed with an transactional approach (which might be good anyway) &mdash; but I tend to leave this special concern asside for now.
          
          From 666d57f6ef2811a1e463ed78808793f9d279bca2 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Fri, 4 Jun 2010 04:35:40 +0200
          Subject: [PATCH 36/52] code up the obvious part of the AdviceSystem
           implementation
          
          ---
           src/lib/advice.hpp        | 32 ++++++++++++----
           src/lib/advice/advice.cpp | 80 +++++++++++++++++++++++++++++++++------
           src/lib/advice/index.hpp  |  4 +-
           3 files changed, 96 insertions(+), 20 deletions(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index 29a20d664..0ef5ede28 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -171,7 +171,6 @@ namespace advice {
               protected:
                 void publishProvision (PointOfAdvice*);
                 void discardSolutions ();
          -      void publishBindingChange();
                 void publishRequestBindingChange();
                 
                 void registerRequest();
          @@ -240,11 +239,12 @@ namespace advice {
                 defineBinding (Literal topic)
                   {
                     setBindingPattern (Binding(topic).addTypeGuard());
          -          publishBindingChange();
          +          maybe_rePublish();
                   }
                 
               private:
                 PointOfAdvice* storeCopy (AD const& advice_given);
          +      void maybe_rePublish ();
               };
             
             
          @@ -289,12 +289,29 @@ namespace advice {
                 @throw  error::External on allocation problems, plus anything
                         the advice data may throw during copy construction. */
             template
          -  PointOfAdvice*
          +  inline PointOfAdvice*
             Provision::storeCopy (AD const& advice_given)
          -    {
          -      typedef ActiveProvision Holder;
          -      return new(getBuffer(sizeof(Holder))) Holder (*this, advice_given);
          -    }
          +  {
          +    typedef ActiveProvision Holder;
          +    return new(getBuffer(sizeof(Holder))) Holder (*this, advice_given);
          +  }
          +  
          +  
          +  /** @internal in case we've already published this provision,
          +   *            we temporarily need a new provision entry, to allow the
          +   *            AdviceSystem implementation to rewrite the internal index
          +   */
          +  template
          +  inline void
          +  Provision::maybe_rePublish ()
          +  {
          +    typedef const ActiveProvision AdviceProvision;
          +    AdviceProvision* solution = static_cast (getSolution (*this));
          +    
          +    if (solution)    // create copy of the data holder, using the new binding 
          +      publishProvision (storeCopy (solution->getAdvice()));
          +  }
          +  
           
             
               
          @@ -346,6 +363,7 @@ namespace advice {
                 defineBinding (Literal topic)
                   {
                     setBindingPattern (Binding(topic).addTypeGuard());
          +    ////////////////////////////////////////////////////////////////////////////TODO: conceptual mismatch here! we don't have an "old entry", because we ourselves are the entry ;-)
                     publishRequestBindingChange();
                   }
               };
          diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
          index 0c0104e2e..ba55fb30f 100644
          --- a/src/lib/advice/advice.cpp
          +++ b/src/lib/advice/advice.cpp
          @@ -23,14 +23,51 @@
           
           #include "lib/advice.hpp"
           #include "lib/advice/index.hpp"
          +#include "lib/singleton.hpp"
          +#include "include/logging.h"
           
          +#include 
          +
          +using lib::Singleton;
           
           namespace lib {
           namespace advice {
             
           //  LUMIERA_ERROR_DEFINE (MISSING_INSTANCE, "Existing ID registration without associated instance");
          +  
          +  namespace { // ======= implementation of the AdviceSystem ============
          +    
          +    class AdviceSystem
          +      : public Index
          +      , boost::noncopyable
          +      {
          +        
          +      public:
          +        AdviceSystem()
          +          {
          +            INFO (library, "Initialising Advice Index tables.");
          +          }
          +        
          +       ~AdviceSystem()
          +          {
          +            INFO (library, "Shutting down Advice system.");
          +          }
          +      };
          +    
          +    
          +    /** hidden implementation-level access to the AdviceSystem */
          +    Singleton aSys;
          +    
          +    
          +  } //(End) AdviceSystem implementation
           
             
          +  
          +  
          +  
          +  /*  ====== AdviceLink : access point for Provisions and Requests ====== */  
          +  
          +  
             /** allocate raw storage for a buffer holding the actual piece of advice.
                 We need to manage this internally, as the original advice::Provision
                 may go out of scope, while the advice information as such remains valid.
          @@ -45,30 +82,49 @@ namespace advice {
             }
             
             
          +  /** when the Provision actually sets advice data, this is copied
          +   *  into an internal buffer within the AdviceSystem. We then use the
          +   *  Index to remember the presence of this advice data and to detect
          +   *  possible matches with existing advice::Request entries.
          +   *  @param adviceData pointer to the copied data,
          +   *         actually pointing to an ActiveProvision
          +   */
             void
          -  AdviceLink::publishProvision (PointOfAdvice*)
          +  AdviceLink::publishProvision (PointOfAdvice* newProvision)
             {
          -    UNIMPLEMENTED ("change advice provision registration");
          +    const PointOfAdvice* previousProvision (getSolution (*this));
          +    setSolution (this, newProvision);
          +    
          +    if (!previousProvision && newProvision)
          +      aSys().addProvision (*newProvision);
          +    else
          +    if (previousProvision && newProvision)
          +      aSys().modifyProvision (*previousProvision, *newProvision);
          +    else
          +    if (previousProvision && !newProvision)
          +      aSys().removeProvision (*previousProvision);  ////////////////////////////TODO: don't we need to release buffer storage here?
             }
             
             
          +  /** when advice is retracted explicitly,
          +   *  after removing the provision index entry
          +   *  we also need to re-process any requests
          +   *  which happen to match our binding... 
          +   */
             void
             AdviceLink::discardSolutions ()
             {
          -    UNIMPLEMENTED ("notify index of retracted advice");
          +    const PointOfAdvice* existingProvision (getSolution (*this));
          +    setSolution (this, NULL );
          +    if (existingProvision)
          +      aSys().removeProvision (*existingProvision);  ////////////////////////////TODO: don't we need to release buffer storage here?
             }
             
             
          -  void
          -  AdviceLink::publishBindingChange ()
          -  {
          -    UNIMPLEMENTED ("propagate binding change to index");
          -  }
          -      
          -      
             void
             AdviceLink::publishRequestBindingChange()
             {
          +    ////////////////////////////////////////////////////////////////////////////TODO: conceptual mismatch here! we don't have an "old entry", because we ourselves are the entry ;-)
               UNIMPLEMENTED ("propagate binding change to index");
             }
             
          @@ -76,14 +132,14 @@ namespace advice {
             void
             AdviceLink::registerRequest()
             {
          -    UNIMPLEMENTED ("registrate request with the index");
          +    aSys().addRequest (*this);
             }
             
             
             void
             AdviceLink::deregisterRequest()
             {
          -    UNIMPLEMENTED ("detach request from index");
          +    aSys().removeRequest (*this);
             }
           
           
          diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp
          index e15c308d0..0fa0f9201 100644
          --- a/src/lib/advice/index.hpp
          +++ b/src/lib/advice/index.hpp
          @@ -350,7 +350,9 @@ namespace advice {
                         requestEntries_[nKey].append (newEntry);
                       }
                     else
          -            requestEntries_[nKey].overwrite (oldRef, newEntry);
          +            {
          +              requestEntries_[nKey].overwrite (oldRef, newEntry);
          +            }
                     provisionEntries_[nKey].publish_latest_solution (newEntry);
                   }
                 
          
          From 7895ce5f49c86ebe4f3a67ad2cfdd9b50f7e3c39 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Fri, 4 Jun 2010 17:25:33 +0200
          Subject: [PATCH 37/52] solve the problem with re-binding and advice::Request
          
          ---
           doc/devel/uml/fig141445.png            | Bin 12661 -> 13377 bytes
           doc/devel/uml/index.html               |   2 +-
           src/lib/advice.hpp                     |   6 ++---
           src/lib/advice/advice.cpp              |   5 ++--
           src/lib/advice/index.hpp               |  23 +++++++++++------
           tests/lib/advice/advice-index-test.cpp |  33 ++++++++++++++++---------
           uml/lumiera/128517                     |  11 ++++++++-
           uml/lumiera/141445.diagram             |   9 ++++++-
           uml/lumiera/5.session                  |   1 -
           9 files changed, 60 insertions(+), 30 deletions(-)
          
          diff --git a/doc/devel/uml/fig141445.png b/doc/devel/uml/fig141445.png
          index 46c0f22b691664fb9ea63bababc61ae67ea69ed0..7eab04117e733f7c4d978d882d1622e679ad827a 100644
          GIT binary patch
          literal 13377
          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
          LC{+l1?fbs~<#Q^Z
          
          diff --git a/doc/devel/uml/index.html b/doc/devel/uml/index.html
          index 6409f6544..2a066763e 100644
          --- a/doc/devel/uml/index.html
          +++ b/doc/devel/uml/index.html
          @@ -147,7 +147,7 @@ Documentation
           
          AbstractMO
          +ActiveProvision
          Advice
          -AdviceProvision
          -AdviceRequest
          +AdviceLink
          +AdviceSystem
          Advised
          Advisor
          AFrame
          @@ -98,6 +99,7 @@ HandlingPattern
          Id
          ImplFacade
          +Index
          InstanceHandle
          Interpolator
          Invalid
          @@ -150,6 +152,7 @@ Project
          Projector
          Prototype
          +Provision
          Proxy
          PullInput
          Query
          @@ -168,6 +171,7 @@ RenderGraph
          RenderState
          RenderTask
          +Request
          Resolution
          ResolverBase
          ResolvingFacility
          diff --git a/doc/devel/uml/fig141445.png b/doc/devel/uml/fig141445.png index 4309a900a297cf7bdaa10f37e11999392662ca1b..46c0f22b691664fb9ea63bababc61ae67ea69ed0 100644 GIT binary patch literal 12661 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 LC{+l1?fbs~<#Q^Z literal 7905 zcmcJU2T)Vpm%t;Sf++AIh?G#2fJhUhcTsv1PX)V;d2;_!>{1Xib z1kW4-xpb2d58T-|iFJoS=(81`JbLDtxHau<@cenx#SUC3#H6++CNtgS-uMP1Rneui zw(CW1w{M;xIwF|gM15IK7YglJR1Q-XA&p}~ovJ-=%Wu@Oxx@yu%tCOK%1 zCoDUNadVd81ktm-^tx51=kigF@u{<&os_66}k_jY%H=D}&a2 zE7Z8$YmJ*0eM`>CPsQhPcV9NUyI%@IP+Zw0YvI;2EkLOeW(_1>XT?$ z4Ls|Rs$dvTXl6tPL7x9J;!SA>K&oPI9Y)bF$Z5CcK4 z@-VpdNL*DR`7@;U9t6VpSOf3hnrsi=$H`s!~c!Pq1f=L-vm6WPIwr7&Xy#vXF zg@r|uddA0vd3iPRADXp<%*~lFwX}uPLZQ%iVPT3&N;j?qklkTt?`m#Nhi{BH)$GVB zD1?%wRa6M^@eOr!HbVCH^wha;eGx$z7#OIlt3P_w_-np- z-|MV7nABl_I~7xrLM|0fA+xi$*WKHz?FV;uX1jmi3!Rgtnk=@yx_a2fU0-T5$Ra3M zZq=I%Ualf99}*sJSY*~Z=~SN-7q_~;o^vluD_7k6ATKg9(mDC;cwf|gGk#~Zsj0~- z#b;y!ijNN9f%(%UiNNnmO8Q-#pH)^?uJ)!N^YW(Ze5&K(w9U*G)(5i|7Z-L=V=)sj8xDjkQBSPFlc!qzS+Fzw}{vDh{T>L-Z3UHv}|NO6~sSAMUcf zz7-x%U@HS2qT(SMx~xD{`m}}lsoZHUg!3nn_GuVd3P<7>PRF`b{-xsB@#G&{VvYgboS1#JeHnOZucS@H4k zjJ(#rH8eD6W~oxM3L|ziQc{dfOiZ3Vi_wdUiXtZ?>q8n#N=nuT1_lCIVWuieii-z? zLJ>qJSriaXsj`dBS>Kbbz4bxAi<4QWvBLSrfUCo?giKrp6)(4E#Ni|}GczX#TbdM> zy~*Nrb#-l@y}iAG5o)T(AnT45^T#t)65dg9-w$)yo~aEYrt-ZwJKWjX0e!X_8Usn9 z9uzV>+?O_Qf<+OoC{$Ya-vRbBn5CwqI7F2D{rh{@KHIY8<>jz6G0$HO{r&wq?K(zU zTA3qLwcZ|{o=1IOAIrVJUF0w+Q1$|WK%Hmz3DuzqEN{R*i_yZmNT<7DBC0|@>%W)H#o^K8Y1|0wC)AIVd4aec`?gTg;J}^Bdfr@0r zZjKc#mh?)vy1V~2PoUdpCx=L*+A7=O?_g0ZEG!4>gK~tXMtEaPs@wRe#MAr9VPRpM z`ad!4}JlaCdRJcKtfI zr$qr{W3$M3=(l>*kP>mVZmpFW8Hrm;# zn6Jgoji8H7mNXFtckP|k2>b3;C=pmEhbW{L{jGKnTl~qbpMd@;vS_KrJ8Z9C1jQ53 zKoyAi7+RQ3h(L!jS+sx9-+y;)@Fy>%iz2t)4N+)F1A1t4m*tYuqTlswqj$&d#0U8P z1Yl!_GHm?4?7vorc#rR(a%512pHOqpnii+j6D_GaF> z+ve>bj?<0`Wwx{Txws5Vt)t1L)ni~v0@c-#Besvd_B=(|Y~FeCqk1Ld5T5VXN4N3I zd~MO%G%CL`6jI`Q71N1&x~h$k-|#)@m|;(~gGpdep+ccMX1{_NShV%O0!^5oM{1vp zkV;N{7Jev0Smd(&L)cX!;eqK-zYCAkK%&Ph-8c@IWi{Et@%}c_u)55=9k1;Cc;8#p z15=1_1!^P%O<>g(@oxuq4X32rqypdDYq+^bL1cGWS0`uB-OX~f@KgNGll)E>1If}# z_pAa;Q;ufmr^kvIM1^Yw?8oS2)MX=1A&cK^7eVlOYxm7d;QuiW=6T<}F)%oLS01y$VJw{0TAwIjLON3Zd%>rW#lKQD2Q;=<0Ip=35_ESf3P|*lVic{~dSe$f7 zx|}uz#T3akv_l?tK*>lOIYTaO@q&v|I#E2~e&B=K2M9zZDa{hYt%KsmLSw?eph;up zPDt>S8)oWJ(gPrkk9VoU-YI!(iST&7Of51X`{p~gCL=L3K4z_9>zS@cD+#pea-_d@))6?D zFM2L3-GaixvsG0Q&-`i;*mkRwttlb)%hs2GT@<)gVKVCvFk5wQ>#@2eZT1sxg@)Cv zRqzcR9nZDRi}hxc-i(mEBs@ghasyLD33 zrTMK7HMMI}QWEngLqk#c_6#n+e8uNihgk zpnIqPA2{tljvVybw&1s4B8(#cU@hzsI#xyGZ@BnBxNaEUP{<@J79ynvUvOFLxs=LoN;F0kMP5ieoSeYSamias1MdfG zWnge2fqjJ1CWJQEoNO0)ZS0x?(HIm%erfZXobmrx?(p9yB>nfo%r*p4#|NzW(8K~I zRp#G@iF1jy=Bziaq{=+N^gQ**<7-g;5L0+XVtW)Ckl{6tCCKwnM;3B~zje4C+bVEH zX)%oc@4)C!bo9S!><`o@`#Vh&acB1RW`$gNuiL&F_G&`g%Wk^(Pn#DvF(T}Wt0)4-)0>;>p z?J`ugy^p|nsa}NMQUgJZ>GXoGOE?4=qP+!^9Ny0 zjFA8*?Fw&&BQp5X^2H^uagAah) z%663-l2p{(EbII-nIL;p%xx`&!>jXqMTJ{`no4Yfgx-MHwCO{RW?ZP3d&c^~ zgze;HV}O#xncGTF(nXE)V(_tGNrCUtd{6ghwtpGtl=9Y$#H%9%y$QdW>cg&Nan>M^ zq0OS*%#)IgBZ24AvuX*6d=rpG#3bN2wY_#*@bL|we{QAuSKe=$bB@W?_2}*;+r=CXW)y6FU}yAO?Gk8C@J7RT;WXY>QZ;M<;42K zmj4%Sbr#nysroZ6`yPnalne~6z|nm6xZMl(zz21f5)5!Q^LF3OrM-zlQ`gO{rZXH>qC>K|N#F0r3?tvjEPfF)2EUobFU8X1Xz6?4}u%@05F{qTr!rrbf zpFYNm!os*4Z_lJd*4A1;1Pc|fN&`Z%O#-_w7h!OZi)*@Uqh+q~b(;%Q%Th}>fO^&CQsB>h&p%fq8V6u}_q_|jr& z_LYyfQN=HW=aHS)+38i%`^-wGnCi5cn6347SKx@<7M>K?7EYCfVBAj0sIL1t;^rqB*`9ia?dYA}Yr*spQbVy%c0|_*Fs_twJGtH`% z7w;$%>{M6DLxUURo)jk}h?+u!!SQqh>X( zbg4>DKN$G-rnFRY-EG?3d>^}#U+uhjwSycuPL%`!UX~X!&p(kv#as3`vAFEzHrwT8 zQd+B4esY*pGJ_o-Y^M!mqG zQrLbhF^HJ;i?(L@EqLX{zA-I>jg`v7ID22~B75P?XHHOuBGRM62+gcruvUKkpnDO~hdpUi__1_Dp32&1S%;@ee`TW_cq_`&(O)qNpFAH|@vQf~S@ycG82c7Ya77n($0*)Pd}$r;>??)^i8phdb-k6ho6HV{wUeuBS)Ksi}v` zy-qSuu5)qJh`TK1I!p*9^f19JWo6r5`}-@<(;My|zm^WUOq@n3|h9y%qo2=3U`iL$%(khDl!tDPj9Zu6S-_Cw$! zdJ_cId>oPzX7Wl_vQ+fx$x>;>y&5pn<4$$B)$RJ(gS|lql?jt!Bf-#c6_6{T43UFy zrxt2G#NeAww@9n9xxz+7r|n6muM{H(t^e~;JRDA3(E9)#5^~wmu{Tc_D>oP)C_ZOA zAWg4Zq&0b>E6N6|HH(}z$*YQGxqqMU{{5kmd~3x#Vf1oJzqGwj=K|Nq7jFh@{lyts zI5S4nV`btThcoivv}PU`LOS054u3_XKJ7;pM@*7cpR_kl;M)hqm(nFf7U#Jo7aL7J z#g7oZNt!uS*8hZ|VETG#1OF^u^(mp*fD0P9+CJk(8ijHHk7XXVsD>^L~bv2LtEBWoFBv&Fl#?b!w`*JhD;dt!CT5a2{nZRmDOB8RZ>-4t`Sa(u zrn&haZdzQ_t4ZLNu)UJT^}c7s+%-=%J3t&E;50M!^>MIPz8(w)V+&hYTRZv6eBprILAS#hzk zBErJqP*L}>Ler+IlW&>1ACW#PDk|X-5y?W%X~%!H#mJ_2pisl>Zjmvo%gYEauZhPd zk+gyZd3hWxEGsC%+4o^#wzGA$2nA11PXKQp_KLagqlYsxn3)3O;znm`y@Rh)yR7vw z!6jB;(jfrk6zG+q7h2zihKBka@8$f+aCUx|kpIuh&oMd&)dMRLNx}dKjDMA+yR&n5 zZ;wKHZ)@@phzcs=b{hz7bG#%eG4a)_S3}faNM3quj_r(Fr3j0P8dtlc+S^xwoJMB3 z`PIY4GGFZvYXhADNZe_*Zfj{Tcbg=Sjm>GgijtPL+O+wttbN;Jc6Rnyv89r&?eAIn z`1mle;Z9~R>ReZQ3Jj~gyu2{e)q=dd#Xx5Og9G^Y_3PIF*oLJgiXnDCMgh57Sz4+j ziSXaMCqMlXr9`9MbsFy!!2>f_BraN0jNK0E?Ci``{ygygc`mqGTC(u-^J8jh3B3uW zqXV+%ci$X4*qZ#!FypT~3{xp6DAY{C~M`2v|>7MI^E z!XU>{wNZHPo5M0fXU5OLMvD!j4``fQUgo#%OD!yX5YWgN7!nbInJnM#PnQGyDQ_e+ zBt*z%N#5Cc2Wu=Y*g`*NleTDIV$P- zODbPiLxb0GszTNtQPy1^f5qu>xDdOJysYe7B+|*(*Ec^16^gi;;1ic{>m5d9)1v+v zpcF^H=1WUU0YKgwFOehs7#*EHxSp7lbocJvVUfGC?+HmrZb{ouRREb60SzfFeWpS! zqYmT{J z+M_o`QqpdO1BiYx7}?j?2SjE+Tjz6#nKo~a;7u9#Zk^u!@UR~Xut*-~OqNJoeKR=%=cLLB?QCT^W$Gi<3 z+yB10A!yW|SLM2@YGbnw&ZGL%-7aC*m6q1lec-&;2fqD2l1gnftKGK%_0iJNxd+0h z(gUie>EpQvgKi}Z$CDk|c$~2!EuFo+9xq>#NrS0nKh7H(dIp#~0NsIs1Unl{BVm;6 z%Bv=HX5g@tk&`24>PZxij*ebLqrYoaAh4OZ>l?ZKcUZ;6r%@nxjHOLV$aclaVR28EkVSQIk9?)ymx(%!&kL2y9Xi*~Umdz@Tq{ zt^&*9<>dvErp+ybKoUw?$hxMdryCnh2QyX1$H!NDl3d|%{uEOmemxB?{U7$@#g=Wx zpfWH-1?pWs8JYF<_3M^TKp)HQ#}cy4jn;_kHwo*zn8)BV_f@EsK9OnodE+#<8o&T!B?^;Sl+SR|=^nYLi04#x5{H_Fzm}@`gp!{9s`K1GDJO5?j^Z(Y-eSsek XtfKsG2AT{?*AN96)h7kgCU5=;k`5+> diff --git a/doc/devel/uml/index.html b/doc/devel/uml/index.html index 44cff5b16..6409f6544 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 : 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, 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

          +

          executable associated with : placement, sessionimpl, builderfacade, 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

          Artifact main

          Stereotype: source

          @@ -1512,21 +1512,25 @@ undo
          Class Advisor
          Class Advised
          -
          -
          +
          +
          Class Request
          +
          Class Provision
          +
          Class Binding
          +
          +
          Class Index

          Advice solving



          -
          Class instance

          type :AdviceProvision

          -
          Class instance

          type :AdviceProvision

          -
          Class instance

          type :AdviceProvision

          +
          Class instance

          type :Provision

          +
          Class instance

          type :Provision

          +
          Class instance

          type :Provision

          Class instance

          type :Advisor

          Class instance

          type :Advised

          -
          Class instance

          type :AdviceRequest

          +
          Class instance

          type :Request

          Class instance

          type :Advised

          -
          Class instance

          type :AdviceRequest

          +
          Class instance

          type :Request

          Class instance

          type :Binding

          Class instance

          type :Binding

          Class instance

          type :Binding

          diff --git a/doc/devel/uml/index_60.html b/doc/devel/uml/index_60.html index c5e08071d..ed93942a9 100644 --- a/doc/devel/uml/index_60.html +++ b/doc/devel/uml/index_60.html @@ -30,32 +30,32 @@
          <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
          <transition>transition
          <transition>transition
          <transition>transition
          <transition>transition
          <transition>transition
          AbstractMOclass
          access Channeluse case
          access Fileuse case
          ActiveProvisionclass
          activity finalactivity final
          activity finalactivity final
          ad1class instance
          Adviceclass view
          Advice entitiesclass diagram
          Advice solvingobject diagram
          AdviceProvisionclass
          AdviceRequestclass
          AdviceLinkclass
          AdviceSystemclass
          Advisedclass
          Advisorclass
          AFrameclass
          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
          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
          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
          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
          clipartifacta Media Clip
          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
          getoperationaccess the configuation value for a given key.
          @return empty string for unknown keys, else the corresponding configuration value
          get frameactivity
          get_reproperation
          getAdviceoperation
          getAssetoperationfind and return corresponging object
          getAutomationoperation
          getConnectionoperationTODO
          id_relation
          ImplFacadeclass
          In Memory Databaseclass diagram
          Indexclass
          inFixtureactivity action pin
          inputclass instance
          inputclass instance
          inputclass instance
          inputclass instance
          instanceoperation
          InstanceHandleclass
          instructionsrelation
          MediaKindclass
          merge activity nodemerge activity node
          Metaclasskey abstraction: metadata and organisational asset
          metaartifactabstract base class of all MObjects representing meta data or processing instructions
          metaartifactkey abstraction: metadata and organisational asset
          metaartifactabstract base class of all MObjects representing meta data or processing instructions
          Metaclass
          Meta-Asset Relationsclass diagram
          mobjectartifactKey Abstraction: A Media Object in the Session
          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
          ouputclass instance
          outPortrelationthe Port this MObject wants to be conected to
          Overviewcomponent diagramThis drawing shows the top level compoents and relations
          Overview Render Enginedeployment diagram
          projectorartifactvideo ProcNode for scaling and translating image data
          Prototypeclass
          providerrelation
          Provisionclass
          Proxyclass
          pulloperation
          PullInputclass
          relativelocationartifactPlacement implemnetaion providing various ways of attaching a MObject to another one
          RelativeLocationclass
          releaseBufferoperation
          relTypeattributethe kind of relation denoted by this Placement
          RelTypeclassthe possible kinds of RelativePlacements
          relTypeattributethe kind of relation denoted by this Placement
          removeoperationremove the given asset <i>together with all its dependants</i> from the internal DB
          Render Entitiesclass diagram
          Render Mechanicsclass diagram
          renderstateartifactrenderengine state manager
          RenderTaskclass
          reprattributehuman readable representation of the condition characterizing this allocaton, e.g. "t >= 10"
          Requestclass
          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.
          ServiceImplclass
          Sessioncomponent
          sessionartifactInterface: the session edited by the user
          sessionpackagesourcecode package

          Everything concerning the EDL and Session, within the MObject Subsystem
          Sessionpackage
          sessionpackagesourcecode package

          Everything concerning the EDL and Session, within the MObject Subsystem
          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
          SessionImplclassImplementation class for the Session interface
          sessmanagerartifactglobal session access and lifecycle
          SessManagerclass
          setAdviceoperation
          setup Build Paramsopaque activity action
          setup StateProxyopaque activity action
          shared_ptrclass
          Statenode
          Stateclass
          staterelation
          state actionstate action
          state actionstate action
          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 actiontry to fetch existing definition
          state actionstate action
          state actionstate action
          state actionstate action
          StateAdapterclass
          StateAdapter compositionclass diagram
          StateProxyclass
          trafoartifacttransforming processing Node
          treatoperation
          treatoperationThis operation is to be overloaded for the specific MObject subclasses to be treated.
          treatoperation
          treatoperation
          treatoperation
          treatoperation
          treatoperation
          treatoperation
          treatoperation
          treatoperation
          treatoperation
          treatoperation
          treatoperation
          TypedIDclass
          TypedID::Indexclass
          TypedID::Linkclass
          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
          videoclass instance
          videoclass instance
          videoclass instance
          videoclass instance
          video1class instance
          video1class instance
          videoclass instance
          videoclass instance
          video1class instance
          video1class instance
          video1class instance
          video1class instance
          video1class instance
          video1class instance
          video1class instance
          VirtualMediaclass
          Visitableclass
          visitorpackagesub-namespace for visitor library implementation
          findTypeHandler
          getAppconfigaccess the configuation value for a given key.
          @return empty string for unknown keys, else the corresponding configuration value
          get_reprAllocation
          getAdviceRequest
          getAssetAssetManagerfind and return corresponging object
          getAutomationFixture
          getConnectionConManagerTODO
          retrieveStateAdapter
          rootCauseErrorIf 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
          saveSessManagercreate a complete, serialized representation
          of the current session config and contents.
          @todo how to serialize, prameters, return value?
          setAdviceProvision
          treatApplicable
          treatBuilderToolThis operation is to be overloaded for the specific MObject subclasses to be treated.
          treatNodeCreatorTool
          treatNodeCreatorTool
          treatNodeCreatorTool
          treatNodeCreatorTool
          treatSegmentationTool
          treatNodeCreatorTool
          treatNodeCreatorTool
          treatNodeCreatorTool
          treatSegmentationTool
          treatSegmentationTool
          treatSegmentationTool
          useFileFileProviderAnnounces that the application intends to use this file with mode (READ|WRITE|READWRITE)
          useTemporaryStorageFileProviderProvides a pool for interminate frames
          whatError
          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 : placement, sessionimpl, builderfacade, 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

          +

          executable associated with : 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, allocation, vframe, toolfactory, hub, buildable, abstractmo, exitnode, pathmanager, track, meta, fixedlocation, relativelocation, controllerfacade, rendergraph, pluginadapter

          Artifact main

          Stereotype: source

          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp index 0ef5ede28..a91c27db0 100644 --- a/src/lib/advice.hpp +++ b/src/lib/advice.hpp @@ -171,7 +171,7 @@ namespace advice { protected: void publishProvision (PointOfAdvice*); void discardSolutions (); - void publishRequestBindingChange(); + void publishRequestBindingChange(HashVal); void registerRequest(); void deregisterRequest(); @@ -362,9 +362,9 @@ namespace advice { void defineBinding (Literal topic) { + HashVal previous_bindingKey (hash_value(*this)); setBindingPattern (Binding(topic).addTypeGuard()); - ////////////////////////////////////////////////////////////////////////////TODO: conceptual mismatch here! we don't have an "old entry", because we ourselves are the entry ;-) - publishRequestBindingChange(); + publishRequestBindingChange (previous_bindingKey); } }; diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp index ba55fb30f..84c13de09 100644 --- a/src/lib/advice/advice.cpp +++ b/src/lib/advice/advice.cpp @@ -122,10 +122,9 @@ namespace advice { void - AdviceLink::publishRequestBindingChange() + AdviceLink::publishRequestBindingChange(HashVal previous_bindingKey) { - ////////////////////////////////////////////////////////////////////////////TODO: conceptual mismatch here! we don't have an "old entry", because we ourselves are the entry ;-) - UNIMPLEMENTED ("propagate binding change to index"); + aSys().modifyRequest(previous_bindingKey, *this); } diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 0fa0f9201..7163e2731 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -136,6 +136,8 @@ namespace advice { * to the same memory location of a POA (point of advice). * Thus e.g. #hasProvision means this index holds an entry * pointing to exactly this given data entity. + * @note the implementation of modifying a Request entry + * explicitly relies on that definition of equality. * @note the diagnostic API is mainly intended for unit testing * and \em not implemented with focus on performance. */ @@ -339,21 +341,26 @@ namespace advice { provisionEntries_[key].publish_latest_solution (entry); } + /** @note explicitly relying on the implementation of \c == + * which checks only the memory location of the Request. + * Thus we can use the already modified Request to find + * the old entry within the index pointing to this Request. + * @param oKey the binding hash value prior to modification + */ void - modifyRequest (POA const& oldRef, POA& newEntry) + modifyRequest (HashVal oKey, POA& entry) { - HashVal oKey (hash_value(oldRef)); - HashVal nKey (hash_value(newEntry)); + HashVal nKey (hash_value(entry)); if (oKey != nKey) { - requestEntries_[oKey].remove (oldRef); - requestEntries_[nKey].append (newEntry); + requestEntries_[oKey].remove (entry); + requestEntries_[nKey].append (entry); } else - { - requestEntries_[nKey].overwrite (oldRef, newEntry); + { // rewrite Entry to include the new binding + requestEntries_[nKey].overwrite (entry, entry); } - provisionEntries_[nKey].publish_latest_solution (newEntry); + provisionEntries_[nKey].publish_latest_solution (entry); } void diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp index 268089ddc..c098552c7 100644 --- a/tests/lib/advice/advice-index-test.cpp +++ b/tests/lib/advice/advice-index-test.cpp @@ -61,6 +61,12 @@ namespace test { return pattern_.matches (Binding(refSpec)); } + void + changeBinding (Literal newSpec) + { + pattern_ = Binding(newSpec).buildMatcher(); + } + /* == Adapter interface for use within the Index == */ @@ -342,19 +348,22 @@ namespace test { CHECK (_hasDefault (3)); CHECK (_hasDefault (5)); - CHECK (!idx.hasRequest (_entry (2,"cat"))); + HashVal dogHash (hash_value (_entry (5,"dog"))); + CHECK ( idx.hasRequest (_entry (5,"dog"))); + _entry (5,"dog").changeBinding("cat"); // transmogrify existing request into cat-request + CHECK (_hasDefault (5)); // of course this didn't change the solution + CHECK (!idx.hasRequest (_entry (5,"cat"))); // can't find it anymore because of changed binding - idx.modifyRequest (_entry (5,"dog"), _entry (2,"cat")); + idx.modifyRequest (dogHash, _entry (5,"cat")); - CHECK ( idx.hasRequest (_entry (2,"cat"))); - CHECK (!idx.hasRequest (_entry (5,"dog"))); + CHECK ( idx.hasRequest (_entry (5,"cat"))); CHECK (p_cnt == idx.provision_count()); CHECK (r_cnt == idx.request_count()); CHECK (_hasSolution (1,7)); CHECK (_hasSolution (6,7)); CHECK (_hasDefault (3)); - CHECK (_hasSolution (2,7)); // automatically got the current cat solution + CHECK (_hasSolution (5,7)); // automatically got the current cat solution } @@ -365,7 +374,7 @@ namespace test { uint r_cnt = idx.request_count(); uint p_cnt = idx.provision_count(); CHECK (_hasSolution (1,7)); - CHECK (_hasSolution (2,7)); + CHECK (_hasSolution (5,7)); CHECK (_hasSolution (6,7)); CHECK (_hasDefault (3)); @@ -378,7 +387,7 @@ namespace test { CHECK (p_cnt == idx.provision_count()); CHECK (r_cnt == idx.request_count()); CHECK (_hasDefault (1)); - CHECK (_hasDefault (2)); + CHECK (_hasDefault (5)); CHECK (_hasDefault (6)); CHECK (_hasSolution (3,8)); @@ -388,7 +397,7 @@ namespace test { CHECK (idx.hasProvision (_entry (7,"cat"))); CHECK (idx.hasProvision (_entry (9,"cat"))); CHECK (_hasSolution (1,9)); // all cats got the second cat solution - CHECK (_hasSolution (2,9)); + CHECK (_hasSolution (5,9)); CHECK (_hasSolution (6,9)); CHECK (_hasSolution (3,8)); // the dog is unaffected @@ -399,10 +408,10 @@ namespace test { CHECK (!idx.hasProvision (_entry (7,"cat"))); CHECK ( idx.hasProvision (_entry (4,"dog"))); - CHECK (_hasSolution (1,9)); // cats unaffected, because we're changing a shadowed cat solution - CHECK (_hasSolution (2,9)); + CHECK (_hasSolution (1,9)); // cats unaffected, because we're changing a shadowed cat provision + CHECK (_hasSolution (5,9)); CHECK (_hasSolution (6,9)); - CHECK (_hasSolution (3,4)); // but the dog got switched to the transmogrified-into-dog solution, + CHECK (_hasSolution (3,4)); // but the dog got switched to the replaced-by-dog solution, // because it was added later than the existing solution 8 // a switch within the same cluster ("cat") @@ -411,7 +420,7 @@ namespace test { CHECK ( idx.hasProvision (_entry (7,"cat"))); CHECK ( idx.hasProvision (_entry (4,"dog"))); CHECK (_hasSolution (1,7)); // because cat-7 is newly added, it shadows the older cat-9 - CHECK (_hasSolution (2,7)); + CHECK (_hasSolution (5,7)); CHECK (_hasSolution (6,7)); CHECK (_hasSolution (3,4)); // but dog remains dog diff --git a/uml/lumiera/128517 b/uml/lumiera/128517 index 28202debe..d87549fd1 100644 --- a/uml/lumiera/128517 +++ b/uml/lumiera/128517 @@ -1,6 +1,6 @@ format 58 "CommonLib" // CommonLib - revision 18 + revision 19 modified_by 5 "hiv" // class settings //class diagram settings @@ -451,6 +451,15 @@ ${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl} + end + + classrelation 203141 // + relation 192261 -_-> + stereotype "create" + a package + cpp default "#include in source" + classrelation_ref 203141 // + b parent class_ref 166021 // ActiveProvision end end diff --git a/uml/lumiera/141445.diagram b/uml/lumiera/141445.diagram index 9d099c054..61830e5ae 100644 --- a/uml/lumiera/141445.diagram +++ b/uml/lumiera/141445.diagram @@ -58,7 +58,7 @@ end relationcanvas 129669 relation_ref 188677 // from ref 129157 z 1999 to ref 129285 no_role_a no_role_b - multiplicity_a_pos 275 240 3000 multiplicity_b_pos 237 240 3000 + multiplicity_a_pos 266 244 3000 multiplicity_b_pos 246 244 3000 end relationcanvas 129925 relation_ref 188933 // from ref 128645 z 1999 to ref 129285 @@ -117,5 +117,12 @@ relationcanvas 133125 relation_ref 191109 // no_role_a no_role_b no_multiplicity_a no_multiplicity_b end +relationcanvas 133381 relation_ref 192261 // + decenter_end 98 + from ref 129157 z 1999 stereotype "<>" xyz 109 149 3000 to point 163 194 + line 133765 z 1999 to ref 131461 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end preferred_whz 635 331 1 end diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session index 522c2745b..293f4231c 100644 --- a/uml/lumiera/5.session +++ b/uml/lumiera/5.session @@ -42,7 +42,6 @@ open class_ref 166021 // ActiveProvision class_ref 164741 // Binding class_ref 166277 // Index - classinstance_ref 144517 // class_ref 145285 // MediaKind package_ref 131077 // ConfigQuery From 5a615ee4f800f09c7fd07c4cd3c43299a13db3c8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 4 Jun 2010 18:39:39 +0200 Subject: [PATCH 38/52] consider advice::Index exception safety --- src/lib/advice/binding.hpp | 1 + src/lib/advice/index.hpp | 25 +++++++++++++++++++------ wiki/renderengine.html | 8 +++++++- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp index 5c2641d73..9d5ef0f80 100644 --- a/src/lib/advice/binding.hpp +++ b/src/lib/advice/binding.hpp @@ -163,6 +163,7 @@ namespace advice { * Functor object for matching against another Binding. * Contains precompiled information necessary for * determining a match. + * @note Matcher is POD, copyable, no-throw */ class Matcher { diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp index 7163e2731..a4bb7addd 100644 --- a/src/lib/advice/index.hpp +++ b/src/lib/advice/index.hpp @@ -140,6 +140,12 @@ namespace advice { * explicitly relies on that definition of equality. * @note the diagnostic API is mainly intended for unit testing * and \em not implemented with focus on performance. + * + * \par Exception safety + * Adding new registrations might throw error::Fatal or bad_alloc. + * The addition in this case has no effect and the index remains valid. + * The other mutating operations are NO_THROW, given that Binding::Matcher + * is a POD and std::vector fulfils the guarantee for POD content elements. */ template class Index @@ -156,6 +162,8 @@ namespace advice { : pair (getMatcher(elm), &elm) { } + // using default-copy, thus assuming copy is NO_THROW + friend bool operator== (Entry const& a, Entry const& b) { @@ -194,7 +202,12 @@ namespace advice { append (POA& elm) { REQUIRE (!contains (elm), "Duplicate entry"); - elms_.push_back (Entry(elm)); + try { elms_.push_back (Entry(elm)); } + + catch(std::bad_alloc&) + { + throw error::Fatal("AdviceSystem failure due to exhausted memory"); + } } void @@ -337,7 +350,7 @@ namespace advice { addRequest (POA& entry) { HashVal key (hash_value(entry)); - requestEntries_[key].append (entry); + requestEntries_[key].append (entry); // might throw provisionEntries_[key].publish_latest_solution (entry); } @@ -353,8 +366,8 @@ namespace advice { HashVal nKey (hash_value(entry)); if (oKey != nKey) { + requestEntries_[nKey].append (entry); // might throw requestEntries_[oKey].remove (entry); - requestEntries_[nKey].append (entry); } else { // rewrite Entry to include the new binding @@ -375,7 +388,7 @@ namespace advice { addProvision (POA& entry) { HashVal key (hash_value(entry)); - provisionEntries_[key].append (entry); + provisionEntries_[key].append (entry); // might throw requestEntries_[key].publish_all_solutions (entry); } @@ -386,8 +399,8 @@ namespace advice { HashVal nKey (hash_value(newEntry)); if (oKey != nKey) { + provisionEntries_[nKey].append (newEntry); // might throw, in which case it has no effect provisionEntries_[oKey].remove (oldRef); - provisionEntries_[nKey].append (newEntry); requestEntries_[nKey].publish_all_solutions (newEntry); requestEntries_[oKey].retract_all_solutions (oldRef, provisionEntries_[oKey]); } @@ -402,7 +415,7 @@ namespace advice { removeProvision (POA const& refEntry) { HashVal key (hash_value(refEntry)); - provisionEntries_[key].remove (refEntry); + provisionEntries_[key].remove (refEntry); // NO_THROW requestEntries_[key].retract_all_solutions (refEntry, provisionEntries_[key]); } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 4ee4eba5f..4d95742e1 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -540,7 +540,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo &rarr; AdviceImplementation
          -
          +
          [<img[Advice solution|uml/fig141573.png]]
           
           
          @@ -590,6 +590,12 @@ Basically, the behaviour when requesting non-existing advice may be configured b
           * on the other hand, using some separate kind of singleton bundle just for these default advice data (e.g. a templated version of //Meyer's Singleton...//), the fallback solution can be settled independent from the ~AdviceSystem, right in the {{{advice.hpp}}} and using static memory, but the downside is now the fallback solution might be destroyed prior to shutdown of the ~AdviceSystem, as it lives in another compilation unit.
           Thus the second approach looks favourable, but we should //note the fact that it is hard to secure this possible access to an already destroyed solution,// unless we decline using the advice feature after the end of {{{main()}}}. Such a policy seems to be reasonable anyway, as the current implementation also has difficulties to prevent accessing an already destroyed {{{advice::Provision}}}, being incorporated in the ~AdviceSystem, but accessed through a direct pointer in the {{{advice::Request}}}.
           
          +!!!locking and exception safety
          +The advice system is (hopefully) written such as not to be corrupted in case an exception is thrown. Adding new requests, setting advice data on a provision and any binding change might fail due to exhausted memory. The advice system remains operational in this case, but the usual reaction would be //subsystem shutdown,// because the Advice facility typically is used in a very low-level manner, assuming it //just works.// As far as I can see, the other mutation operations can't throw.
          +
          +The individual operations on the interface objects are //deliberately not thread-safe.// The general assumption is that {{{advice::Request}}} and {{{advice::Provision}}} will be used in a safe environment and not be accessed or modified concurrently. An notable exception to this rule is accessing Advice: as this just includes checking and dereferentiating a pointer, it might be done concurrently. But note, //the advice system does nothing to ensure visibility of the solution within a separate thread.// If this thread still has the old pointer value in his local cache, it won't pick up the new solution. In case the old solution got retracted, this even might cause access to already released objects. You have been warned. So it's probably a good idea to ensure a read barrier happens somewhere in the enclosing usage context prior to picking up a possibly changed advice solution concurrently.
          +{{red{TODO}}}: the underlying operations on the embedded global {{{advice::Index}}} obviously need to be protected by locking the whole index table on each mutation, which also ensures a memory barrier and thus propagates changed solutions.
          +
           !!!index datastructure
           It is clear by now that the implementation datastrucutre has to serve as a kind of //reference count.// Within this datastructure, any constructed advice solution needs to be reflected somehow, to prevent us from discarding an advice provision still accessible. Allowing lock-free access to the advice solution (planned feature) adds an special twist, because in this case we can't even tell for sure if an overwritten old solution is actually gone (or if its still referred from some thread's cached memeory). This could be addressed with an transactional approach (which might be good anyway) &mdash; but I tend to leave this special concern asside for now.
           
          
          From 203b955a33c4fb439c0cf29409b09d245d81ada3 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Fri, 4 Jun 2010 19:33:42 +0200
          Subject: [PATCH 39/52] add preliminary buffer memory management by heap
           allocation TODO: use the lumiera pool allocator, prevent leak of any advice
           data not explicitly retracted!
          
          ---
           src/lib/advice.hpp        | 53 +++++++++++++++++++++++++++++++--------
           src/lib/advice/advice.cpp | 40 +++++++++++++++++++++++------
           2 files changed, 74 insertions(+), 19 deletions(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index a91c27db0..c1477b05f 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -169,14 +169,15 @@ namespace advice {
               : public PointOfAdvice
               {
               protected:
          -      void publishProvision (PointOfAdvice*);
          -      void discardSolutions ();
          +      const PointOfAdvice* publishProvision (PointOfAdvice*);
          +      const PointOfAdvice* discardSolutions ();
                 void publishRequestBindingChange(HashVal);
                 
                 void registerRequest();
                 void deregisterRequest();
                 
                 void* getBuffer(size_t);
          +      void  releaseBuffer (const void*, size_t);
                 
               public:
                 explicit
          @@ -201,6 +202,7 @@ namespace advice {
              *      Thus each Provision cares for "his" advice and just detaches when going away. Consequently, by default, advice provisions
              *      aren't freed during the lifetime of the application. We'll see if this causes problems. 
              *      
          +   * @todo currently leaking buffer storage for all the advice data which isn't explicitly retracted.
              */
             template
             class Provision
          @@ -210,7 +212,11 @@ namespace advice {
                 
                 /* == policy definitions == */    ////TODO: extract into policy classes
                 
          -      void deregistrate() { /* NOP */ }
          +      void
          +      deregistrate()
          +        {
          +          TODO ("hand-over deallocation information to the AdviceSystem");
          +        }
                 
                 
               public:
          @@ -227,12 +233,15 @@ namespace advice {
                 
                 void setAdvice (AD const& pieceOfAdvice)
                   {
          -          publishProvision (storeCopy (pieceOfAdvice));
          +          maybe_deallocateOld (
          +              publishProvision(
          +                  storeCopy (pieceOfAdvice)));
                   }
                 
                 void retractAdvice()
                   {
          -          discardSolutions ();
          +          maybe_deallocateOld(
          +              discardSolutions());
                   }
                 
                 void
          @@ -244,6 +253,7 @@ namespace advice {
                 
               private:
                 PointOfAdvice* storeCopy (AD const& advice_given);
          +      void maybe_deallocateOld(const PointOfAdvice*);
                 void maybe_rePublish ();
               };
             
          @@ -283,10 +293,12 @@ namespace advice {
                 friend class Provision;
               };
             
          -    
          -  /** function to copy advice into an internal buffer,
          +  
          +  /*  ==== memory management for Provision data ===== */
          +  
          +  /** function to copy advice into an internal buffer.
                 @return type erased pointer to the data holder created
          -      @throw  error::External on allocation problems, plus anything
          +      @throw  error::Fatal on allocation problems, plus anything
                         the advice data may throw during copy construction. */
             template
             inline PointOfAdvice*
          @@ -297,9 +309,26 @@ namespace advice {
             }
             
             
          +  /** @internal assist the AdviceSystem with deallocating buffer storage.
          +   *  Problem is we need to know the exact size of the advice value holder,
          +   *  which information is available only here, in the fully typed context.
          +   *  @note the assumption is that \em any binding created will automatically
          +   *        contain a type guard, which ensures the existingEntry passed in here
          +   *        originally was allocated by #storeCopy within the same typed context.
          +   */
          +  template
          +  inline void
          +  Provision::maybe_deallocateOld (const PointOfAdvice* existingEntry)
          +  {
          +    typedef ActiveProvision Holder;
          +    if (existingEntry)
          +      releaseBuffer (existingEntry, sizeof(Holder));
          +  }
          +  
          +  
             /** @internal in case we've already published this provision,
          -   *            we temporarily need a new provision entry, to allow the
          -   *            AdviceSystem implementation to rewrite the internal index
          +   *  we temporarily need a new provision entry, to allow the
          +   *  AdviceSystem implementation to rewrite the internal index
              */
             template
             inline void
          @@ -309,7 +338,9 @@ namespace advice {
               AdviceProvision* solution = static_cast (getSolution (*this));
               
               if (solution)    // create copy of the data holder, using the new binding 
          -      publishProvision (storeCopy (solution->getAdvice()));
          +      maybe_deallocateOld (
          +          publishProvision(
          +              storeCopy (solution->getAdvice())));
             }
             
           
          diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
          index 84c13de09..17504e900 100644
          --- a/src/lib/advice/advice.cpp
          +++ b/src/lib/advice/advice.cpp
          @@ -72,24 +72,42 @@ namespace advice {
                 We need to manage this internally, as the original advice::Provision
                 may go out of scope, while the advice information as such remains valid.
                 @note the special twist is the size of the buffer depending on the actual
          -            advice type, which we need to erase for tracking all advice provisions
          -            and advice requests through an generic index datastructure.
          +            advice type, which type information we need to erase for tracking all
          +            advice provisions and requests through an generic index datastructure.
                 @todo rewrite to use Lumiera's block allocator / memory pool */
             void*
          -  AdviceLink::getBuffer(size_t)
          +  AdviceLink::getBuffer(size_t siz)
             {
          -    UNIMPLEMENTED ("raw allocation and de-allocation of advice holding buffer");
          +    try { return new char[siz]; }
          +    
          +    catch(std::bad_alloc&)
          +      {
          +        throw error::Fatal("Unable to store Advice due to memory exhaustion");
          +      }
             }
             
             
          +  void
          +  AdviceLink::releaseBuffer (const void* buff, size_t)
          +  { 
          +    delete[] (char*)buff; 
          +  }
          +
          +  
          +  
             /** when the Provision actually sets advice data, this is copied
              *  into an internal buffer within the AdviceSystem. We then use the
              *  Index to remember the presence of this advice data and to detect
              *  possible matches with existing advice::Request entries.
              *  @param adviceData pointer to the copied data,
              *         actually pointing to an ActiveProvision
          +   *  @return pointer to an superseded old provision entry,
          +   *          which the caller then needs to de-allocate.
          +   *          The caller is assumed to know the actual type
          +   *          and thus the size of the entry to deallocate.
          +   *          Returning \c NULL in case no old entry exists. 
              */
          -  void
          +  const PointOfAdvice*
             AdviceLink::publishProvision (PointOfAdvice* newProvision)
             {
               const PointOfAdvice* previousProvision (getSolution (*this));
          @@ -102,7 +120,9 @@ namespace advice {
                 aSys().modifyProvision (*previousProvision, *newProvision);
               else
               if (previousProvision && !newProvision)
          -      aSys().removeProvision (*previousProvision);  ////////////////////////////TODO: don't we need to release buffer storage here?
          +      aSys().removeProvision (*previousProvision);
          +    
          +    return previousProvision;  // to be deallocated by caller if non-NULL
             }
             
             
          @@ -110,14 +130,18 @@ namespace advice {
              *  after removing the provision index entry
              *  we also need to re-process any requests
              *  which happen to match our binding... 
          +   *  @return pointer to the existing provision entry,
          +   *          to be deallocated by the caller, which
          +   *          is assumed to know it's exact type.
              */
          -  void
          +  const PointOfAdvice*
             AdviceLink::discardSolutions ()
             {
               const PointOfAdvice* existingProvision (getSolution (*this));
               setSolution (this, NULL );
               if (existingProvision)
          -      aSys().removeProvision (*existingProvision);  ////////////////////////////TODO: don't we need to release buffer storage here?
          +      aSys().removeProvision (*existingProvision);
          +    return existingProvision;
             }
             
             
          
          From 7d93dae8ea6428fecc5e8039d77d4bbc671ed610 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Fri, 4 Jun 2010 20:10:46 +0200
          Subject: [PATCH 40/52] fix some simple problems (but doesn't pass tests yet)
           looks like a logic error: new advice::Request got solution
          
          ---
           src/lib/advice/binding.cpp | 6 ++++--
           src/lib/advice/binding.hpp | 5 ++---
           src/lib/advice/index.hpp   | 6 +++---
           3 files changed, 9 insertions(+), 8 deletions(-)
          
          diff --git a/src/lib/advice/binding.cpp b/src/lib/advice/binding.cpp
          index 4a8d35d29..c123f04d7 100644
          --- a/src/lib/advice/binding.cpp
          +++ b/src/lib/advice/binding.cpp
          @@ -23,6 +23,7 @@
           
           #include "lib/advice/binding.hpp"
           #include "lib/symbol.hpp"
          +#include "lib/util.hpp"
           
           #include 
           #include 
          @@ -30,6 +31,7 @@
           
           
           using lib::Literal;
          +using util::isnil;
           
           using boost::regex;
           using boost::smatch;
          @@ -102,8 +104,8 @@ namespace advice {
             
             Binding::Binding (Literal spec)
             {
          -    REQUIRE (spec);
          -    parse_and_append (spec);
          +    if (!isnil(spec))
          +      parse_and_append (spec);
             }
             
             
          diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp
          index 9d5ef0f80..23d2b5ae4 100644
          --- a/src/lib/advice/binding.hpp
          +++ b/src/lib/advice/binding.hpp
          @@ -63,9 +63,8 @@
            **       could be fed as parameters to the bound advice. But this extension requires to extend
            **       the simple hash-based match check to an actual unification of the patterns. ///TICKET #615
            ** 
          - ** @see configrules.hpp
          - ** @see typed-lookup.cpp corresponding implementation
          - ** @see typed-id-test.cpp
          + ** @see advice.hpp
          + ** @see advice-binding-pattern-test.cpp
            ** 
            */
           
          diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp
          index a4bb7addd..610f793a1 100644
          --- a/src/lib/advice/index.hpp
          +++ b/src/lib/advice/index.hpp
          @@ -214,12 +214,12 @@ namespace advice {
                      overwrite (POA const& oldRef, POA& newElm)
                        {
                          EIter pos = std::find (elms_.begin(),elms_.end(), oldRef);
          -               REQUIRE (pos!=elms_.end(), "Attempt to overwrite an entry which isn't there.");
          -               REQUIRE (!contains (newElm), "Duplicate entry");
          +               REQUIRE    (pos!=elms_.end(), "Attempt to overwrite an entry which isn't there.");
          +               REQUIRE_IF (&oldRef != &newElm, !contains (newElm), "Duplicate entry");
                          
                          *pos = Entry(newElm);
                          
          -               ENSURE (!contains (oldRef), "Duplicate entry");
          +               REQUIRE_IF (&oldRef != &newElm, !contains (oldRef), "Duplicate entry");
                        }
                      
                      void
          
          From 2360f9b4c0754d21ba7c56a9112990d1d284f4bc Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Sat, 5 Jun 2010 05:09:42 +0200
          Subject: [PATCH 41/52] Advice colaboration: implemented and passes basic unit
           test
          
          ---
           src/lib/advice.hpp                      | 82 +++++++++++++++----------
           src/lib/advice/advice.cpp               | 75 +++++++++++++++++++---
           tests/40components.tests                |  4 +-
           tests/lib/advice/advice-basics-test.cpp | 79 ++++++++----------------
           wiki/renderengine.html                  |  9 ++-
           5 files changed, 154 insertions(+), 95 deletions(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index c1477b05f..8857c2556 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -32,7 +32,7 @@
            ** Lumiera. Creating this abstraction was partially inspired by aspect oriented programming, especially
            ** the idea of cross-cutting the primary dependency hierarchy. Another source of inspiration where the
            ** various incarnations of properties with dynamic binding. For defining the actual binding, we rely
          - ** on predicate notation and matching (later unification) as known from rule based systems.
          + ** on predicate notation and matching (planned: unification) as known from rule based systems.
            ** 
            ** Definition: Advice is an optional, mediated collaboration between entities taking on
            ** the roles of advisor and advised, thereby passing a custom piece of advice data, managed by
          @@ -53,7 +53,7 @@
            ** advisor need to share knowledge about the meaning of this advice data. The actual advice collaboration
            ** happens at a \em point-of-advice, which needs to be derived first. To this end, the advised puts up an
            ** \em request by providing his \em binding, which is a pattern for matching. An entity about to give advice
          - ** opens possible \advice \em channels by putting up an advisor binding, which similarly is a pattern. The
          + ** opens possible advice \em channels by putting up an advisor binding, which similarly is a pattern. The
            ** advice \em system as mediator resolves both sides, by matching (which in the most general case could be
            ** an unification). This process creates an advice point \em solution -- allowing the advisor to fed the
            ** piece of advice into the advice channel, causing it to be placed into the point of advice. After passing
          @@ -64,11 +64,13 @@
            ** form of advice available, thereby completely decoupling the advised entity from the timings related
            ** to this collaboration.
            ** 
          - ** TODO WIP-WIP
          - ** 
          - ** @note as of 4/2010 this is an experimental setup and implemented just enough to work out
          - **       the interfaces. Ichthyo expects this collaboration service to play a central role
          - **       at various places within proc-layer.
          + ** @note as of 6/2010 this is an experimental setup and implemented just enough to work out
          + **       the interfaces and gain practical usage experiences. Ichthyo expects this collaboration
          + **       service to play a central role at various places within proc-layer.
          + ** @todo allow variables in binding patterns
          + ** @todo use the lumiera MPool instead of heap allocations
          + ** @todo consider to provide variations of the basic behaviour by policy classes
          + ** @todo the implementation is generic/defensive, and could be improved and optimised
            ** 
            ** @see configrules.hpp
            ** @see typed-lookup.cpp corresponding implementation
          @@ -82,20 +84,17 @@
           
           
           #include "lib/error.hpp"
          -//#include "proc/asset.hpp"
          -//#include "proc/asset/struct-scheme.hpp"
          -//#include "lib/hash-indexed.hpp"
          -//#include "lib/util.hpp"
           #include "lib/null-value.hpp"
          -#include "lib/symbol.hpp"
           #include "lib/advice/binding.hpp"
          +#include "lib/symbol.hpp"
          +#include "lib/util.hpp"
           
          -//#include 
          -//#include 
          -//#include 
          -//#include 
          +#include 
           
          -namespace lib    {  ///////TODO: how to arrange the namespaces best?
          +using util::isSameObject;
          +
          +
          +namespace lib    {
           namespace advice {
             
             /**
          @@ -105,12 +104,12 @@ namespace advice {
               {
                 Binding::Matcher pattern_;
                 PointOfAdvice* resolution_;
          -
          +      
               protected:
                 /** define or re-define the binding, which
                  *  specifically labels this attachment to the advice system.
                  *  @note issuing this on an existing connection is equivalent
          -       *        to re-connecting with the new binding.  
          +       *        to re-connecting with the new binding.
                  */
                 void setBindingPattern (Binding const& binding)
                   {
          @@ -187,7 +186,7 @@ namespace advice {
                 
                 // using default copy/assignment
               };
          -
          +  
             
             
             
          @@ -196,12 +195,6 @@ namespace advice {
              * Access point for the advising entity (server).
              * TODO type comment
              * 
          -   * TODO planned implementation of memory handling: see notes in TiddlyWiki
          -   *      Basically I'll use this->resolution_ to point to the copy incorporated into the advice system.
          -   *      This is some kind of "unofficial" ownership and slightly incorrect, but seems the most straight forward implementation.
          -   *      Thus each Provision cares for "his" advice and just detaches when going away. Consequently, by default, advice provisions
          -   *      aren't freed during the lifetime of the application. We'll see if this causes problems. 
          -   *      
              * @todo currently leaking buffer storage for all the advice data which isn't explicitly retracted.
              */
             template
          @@ -230,6 +223,22 @@ namespace advice {
                     this->deregistrate();
                   }
                 
          +      Provision (Provision const& o)
          +        : AdviceLink(o)
          +        {
          +          setSolution (this, NULL );
          +        }
          +      
          +      Provision&
          +      operator= (Provision const& o)
          +        {
          +          if (!isSameObject(*this, o))
          +            {
          +              AdviceLink::operator= (o);
          +              setSolution (this, NULL );
          +            }
          +        }
          +      
                 
                 void setAdvice (AD const& pieceOfAdvice)
                   {
          @@ -267,11 +276,12 @@ namespace advice {
              * 
              * @note the ptr-to-solution in the inherited PointOfAdvice
              *       is currently (5/10) not used, because this \em is
          -   *       already the solution. 
          +   *       already the solution.
              */
             template
             class ActiveProvision
               : public PointOfAdvice
          +    , boost::noncopyable
               {
                 AD theAdvice_;
                 
          @@ -343,12 +353,12 @@ namespace advice {
                         storeCopy (solution->getAdvice())));
             }
             
          -
             
          -    
          -    
             
          -    
          +  
          +  
          +  
          +  
             /**
              * Access point for the advised entity (client).
              * TODO type comment
          @@ -362,7 +372,11 @@ namespace advice {
                 
                 /* == policy definitions == */    ////TODO: extract into policy classes
                 
          -      AD const& handleMissingSolution()  const { return NullValue::get(); }  ///< @warning might segfault when used during shutdown
          +      AD const&
          +      handleMissingSolution()  const  ///< @warning might segfault when used during shutdown
          +        {
          +          return NullValue::get();
          +        }
                 
                 
               public:
          @@ -378,6 +392,8 @@ namespace advice {
                     deregisterRequest();
                   }
                 
          +      // copying Requests is allowed, using default
          +      
                 
                 AD const&
                 getAdvice()  const
          @@ -399,7 +415,7 @@ namespace advice {
                   }
               };
             
          -
          +  
             
             
             
          diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
          index 17504e900..538deed41 100644
          --- a/src/lib/advice/advice.cpp
          +++ b/src/lib/advice/advice.cpp
          @@ -21,6 +21,67 @@
           * *****************************************************/
           
           
          +/** @file advice.cpp 
          + ** Implementation the AdviceSystem, to support the advice collaboration.
          + ** The AdviceSystem is implemented as singleton, but is never accessed directly
          + ** by clients participating in an advice collaboration. Rather, they use the
          + ** advice::Request and advice::Provision value classes as a frontend. While
          + ** these frontend classes are templated on the concrete advice type, the common
          + ** baseclass AdviceLink isn't, allowing the AdviceSystem to operate on type erased
          + ** PointOfAdvice entries. The protected access functions within AdviceLink are
          + ** implemented in this compilation unit and access the AdviceSystem singleton
          + ** defined here locally.
          + ** 
          + ** \par memory management
          + ** Advice data, when added by an advice::Provision, is copied into a ActiveProvision,
          + ** which acts as a value holding buffer. This way, the provided advice data is copied
          + ** into storage managed by the AdviceSystem, allowing to access the data even after the
          + ** original advice::Provision went out of scope.
          + ** 
          + ** But while the Provision is still alive, it may be used to set new advice, modify the
          + ** binding or even retract the given piece of advice. Thus we need a mechanism to link
          + ** the ActiveProvision (value holder) to its origin while the latter is still there.
          + ** Basically we'll use the PointOfAdvice::resolution_ pointer embedded within advice::Provision
          + ** to point to the ActiveProvision entry incorporated into the advice system.
          + ** (For advice::Request, the same pointer is used to link to the ActiveProvision yielding
          + ** the advice solution, if any). Handling the relation between Provision and ActiveProvision
          + ** this way entails some kind of "unofficial" ownership and is slightly incorrect, but seems
          + ** the most straight forward implementation. Thus each Provision cares for "his" advice and
          + ** just detaches when going away. Consequently, by default, advice provisions remain active
          + ** during the lifetime of the application. We'll see if this causes problems.
          + ** 
          + ** @note when a Provision is copied, this hidden link is not shared with the copy, which
          + ** therefore behaves as if newly created with the same binding, but without providing Advice.
          + ** 
          + ** \par implementing the allocations
          + ** The problem with copying and incorporating the ActiveProvision objects is the undetermined
          + ** size of these value holders, because the frontend objects are templated on the advice type,
          + ** while the AdviceSystem doesn't have any knowledge of the specific advice type. This advice
          + ** type is used to set a type guard predicate into each binding, but there is no way to 
          + ** re-discover the specifically typed context; the type guards can only be checked for a match.
          + ** Thus we need the help of the frontend objects, which need to provide a deleter function
          + ** when providing concrete advice data; this deleter function will be saved as function pointer
          + ** so to be able to deallocate all advice data when the AdviceSystem is shut down
          + **
          + ** @todo currently this is unimplemented and we happily leak memory....
          + ** @todo rewrite the allocation to use Lumiera's mpool instead of heap allocations
          + ** 
          + ** \par synchronisation
          + ** While the frontend objects are deliberately \em not threadsafe, the lookup implementation
          + ** within the AdviceSystem uses a system wide advice::Index table and thus needs locking.
          + ** Besides the protection against corrupting the index, this also serves as memory barrier,
          + ** so that when a new advice solution is determined and set as a pointer within the matching
          + ** requests, this change is actually "committed" from cache to memory. But note, when using
          + ** advice::Request concurrently, you need to employ an additional read barrier to ensure
          + ** your thread/CPU picks up such newly determined solutions from main memory. Otherwise
          + ** you might even try to access superseded and already deleted advice data.
          + ** 
          + ** @see advice.hpp
          + ** @see advice::Index
          + **
          + */
          +
          +
           #include "lib/advice.hpp"
           #include "lib/advice/index.hpp"
           #include "lib/singleton.hpp"
          @@ -33,7 +94,6 @@ using lib::Singleton;
           namespace lib {
           namespace advice {
             
          -//  LUMIERA_ERROR_DEFINE (MISSING_INSTANCE, "Existing ID registration without associated instance");
             
             namespace { // ======= implementation of the AdviceSystem ============
               
          @@ -60,12 +120,13 @@ namespace advice {
               
               
             } //(End) AdviceSystem implementation
          -
             
             
             
             
          -  /*  ====== AdviceLink : access point for Provisions and Requests ====== */  
          +  
          +  
          +  /*  ====== AdviceLink : access point for Provisions and Requests ====== */
             
             
             /** allocate raw storage for a buffer holding the actual piece of advice.
          @@ -92,7 +153,7 @@ namespace advice {
             { 
               delete[] (char*)buff; 
             }
          -
          +  
             
             
             /** when the Provision actually sets advice data, this is copied
          @@ -105,7 +166,7 @@ namespace advice {
              *          which the caller then needs to de-allocate.
              *          The caller is assumed to know the actual type
              *          and thus the size of the entry to deallocate.
          -   *          Returning \c NULL in case no old entry exists. 
          +   *          Returning \c NULL in case no old entry exists.
              */
             const PointOfAdvice*
             AdviceLink::publishProvision (PointOfAdvice* newProvision)
          @@ -164,8 +225,8 @@ namespace advice {
             {
               aSys().removeRequest (*this);
             }
          -
          -
          +  
          +  
             
             
             
          diff --git a/tests/40components.tests b/tests/40components.tests
          index eafc67b76..174fc20d2 100644
          --- a/tests/40components.tests
          +++ b/tests/40components.tests
          @@ -18,7 +18,7 @@ return: 0
           END
           
           
          -PLANNED "Advice collaboration (basics)" AdviceBasics_test <
          -//#include 
           #include 
           
          -//using lib::test::showSizeof;
          -//using lib::test::randStr;
          -//using util::isSameObject;
          -//using util::and_all;
          -//using util::for_each;
          -//using util::isnil;
          -//using lib::Literal;
          -//using lib::Symbol;
          -//using lumiera::P;
          -//using std::string;
           using std::rand;
          -//using std::cout;
          -//using std::endl;
           
           
           
          @@ -58,7 +34,8 @@ namespace lib {
           namespace advice {
           namespace test {
             
          -  namespace {
          +  namespace { // Some test classes using the advice system...
          +    
               
               class TheAdvised
                 : private advice::Request
          @@ -108,7 +85,7 @@ namespace test {
                   void
                   clear()
                     {
          -            link_.retractAdvice(); 
          +            link_.retractAdvice();
                     }
                 };
             }
          @@ -122,8 +99,6 @@ namespace test {
              *       typical situation: two unrelated entities exchange a piece of data
              *       just by referring to a symbolic topic ID.
              * 
          -   * @todo partially unimplemented and thus commented out ////////////////////TICKET #605
          -   * 
              * @see advice.hpp
              * @see AdviceSituations_test
              * @see AdviceMultiplicity_test
          @@ -202,8 +177,8 @@ namespace test {
                 void
                 overwriting_and_retracting()
                   {
          -          TheAdvised client1 ("topic1");
          -          TheAdvised client2 ("topic2");
          +          TheAdvised client1 ("slot1");
          +          TheAdvised client2 ("slot2");
                     CHECK (client1.got(0));
                     CHECK (client2.got(0));
                     
          @@ -211,7 +186,7 @@ namespace test {
                     int r2 (1 + (rand() % 1000));
                     
                     {
          -            TheAdvisor server("topic1()");
          +            TheAdvisor server("slot1()");
                       CHECK (client1.got(0));
                       CHECK (client2.got(0));
                       
          @@ -223,7 +198,7 @@ namespace test {
                       CHECK (client1.got(r2));
                       CHECK (client2.got(0));
                       
          -            server.rebind("topic2()");
          +            server.rebind("slot2()");
                       CHECK (client1.got(0));
                       CHECK (client2.got(r2));
                     }
          @@ -232,7 +207,7 @@ namespace test {
                     CHECK (client2.got(r2));
                     
                     {
          -            TheAdvisor anotherServer("topic1");
          +            TheAdvisor anotherServer("slot1");
                       CHECK (client1.got(0));
                       CHECK (client2.got(r2));
                       
          @@ -245,7 +220,7 @@ namespace test {
                     CHECK (client2.got(r2));
                     
                     {
          -            TheAdvisor yetAnotherServer("topic2");
          +            TheAdvisor yetAnotherServer("slot2");
                       CHECK (client1.got(r1));
                       CHECK (client2.got(r2));
                       
          @@ -253,32 +228,32 @@ namespace test {
                       CHECK (client1.got(r1));
                       CHECK (client2.got(r1));
                       
          -            yetAnotherServer.rebind("topic1");
          +            yetAnotherServer.rebind("slot1");
                       CHECK (client1.got(r1));
          -            CHECK (client2.got(0));
          -            
          +            CHECK (client2.got(r2));          // ideally it should be 0, but actually we uncover the old provision
          +                                              // the decision was to err for a simple implementation         /////////TICKET #623
                       yetAnotherServer.clear();
          -            CHECK (client1.got(0));
          -            CHECK (client2.got(0));
          +            CHECK (client1.got(r1));          // should be 0, but again the existing provision is uncovered
          +            CHECK (client2.got(r2));          // should be 0
                       
          -            yetAnotherServer.rebind("topic2");
          -            CHECK (client1.got(0));
          -            CHECK (client2.got(0));
          +            yetAnotherServer.rebind("slot2"); // no effect, because it doesn't provide advice anymore
          +            CHECK (client1.got(r1));
          +            CHECK (client2.got(r2));
                       
          -            yetAnotherServer.publish (r1);
          -            CHECK (client1.got(0));
          -            CHECK (client2.got(r1));
          +            yetAnotherServer.publish (5);
          +            CHECK (client1.got(r1));
          +            CHECK (client2.got(5));
                     }
                     
          -          CHECK (client1.got(0));
          -          CHECK (client2.got(r1));
          -          
          -          client1.rebind("topic2");
                     CHECK (client1.got(r1));
          -          CHECK (client2.got(r1));
          +          CHECK (client2.got(5));
                     
          -          client2.rebind("nonExistingTopic");
          -          CHECK (client1.got(r1));
          +          client1.rebind("slot2");
          +          CHECK (client1.got(5));
          +          CHECK (client2.got(5));
          +          
          +          client2.rebind("nonExistingSlot");
          +          CHECK (client1.got(5));
                     CHECK (client2.got(0));
                   }
               };
          diff --git a/wiki/renderengine.html b/wiki/renderengine.html
          index 4d95742e1..6c60655fe 100644
          --- a/wiki/renderengine.html
          +++ b/wiki/renderengine.html
          @@ -540,7 +540,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
           &rarr; AdviceImplementation
           
          -
          +
          [<img[Advice solution|uml/fig141573.png]]
           
           
          @@ -580,6 +580,13 @@ Aside from the index, handling of the advice provisions turns out to be tricky.
           * but as this simple solution contradicts the general advice semantics in a subtle way (see previous paragraph), we could insist on really re-capturing and retracting previous advice automatically on each new advice provision or modification. In this case, due to the requirement of thread safety, each addition, binding modification, placing of new advice or retraction would require to do an index search to find an existing provision with equivalent binding (same binding definition, not just a matching binding pattern). As a later provision could stomp upon an existing provision without the original advisor noticing this, we can't use the internal references anymore; we really need to search each time and also need a global lock during the modification transaction.
           * an attempt to reduce this considerable overhead would be to use an back-link from the provision as added to the system to the original source (the ~AdviceProvision owned by the advisor). On modification, this original source would be notified and thus detached. Of course this is tricky to implement correctly, and also requires locking.
           The decision for the initial implementation is to use the first variant and just accept the slightly imprecise semantics.
          +When copying a Provision, the hidden link to existing advice data is //not shared.//
          +
          +!!!!de-allocation of advice data
          +It is desirable that the dtors of each piece of advice data be called eventually. But ensuring this reliably is tricky, because advice 
          +data may be of various types and is added to the system to remain available, even after the original {{{advice::Provision}}} went out of scope. Moreover, the implementation decision was //not//&nbsp; to employ a vtable for the advice collaborators and data holders, so we're bound to invoke the dtor with the correct specific type.
          +There are some special cases when de-allocation happens while the original provision is still alive (new advice, changed binding, retracting). But in any other case, responsibility for de-allocation has to be taken by the ~AdviceSystem, which unfortunately can't handle the specific type information. Thus the original provision needs to provide a deleter function, and there is no way to avoid storing a function pointer to this deleter within the ~AdviceSystem, together with the advice data holder.
          +It seems reasonable to create this deleter right away and not to share the link to advice data, when copying a provision, to keep responsibilities straight. {{red{Question: does this even work?? }}} to be verified: does the address of the advice data buffer really determine alone what is found as "existing" provision?
           
           !!!lifecycle considerations
           Behind the scenes, hidden within the {{{advice.cpp}}} implementation file, the ~AdviceSystem is maintained as singleton. According to a general lifecycle policy within Lumiera, no significant logic is allowed to execute in the shutdown phase of the application, once the {{{main()}}} has exited. Thus, any advice related operations might throw {{{error::Logic}}} after that point. The {{{~AdviceSystem()}}} also is a good place to free any buffers holding incorporated advice data, after having freed the index datastructure referring to these buffer storage, of course.
          
          From dee4c33c553f81625098cc750da389558652de04 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Sun, 6 Jun 2010 02:11:40 +0200
          Subject: [PATCH 42/52] change the index-interface from free to member
           functions part of Ticket #628
          
          ---
           src/lib/advice.hpp                     | 47 +++++++++++++-------------
           src/lib/advice/advice.cpp              |  8 ++---
           src/lib/advice/index.hpp               | 36 ++++++++++----------
           tests/lib/advice/advice-index-test.cpp | 23 +++----------
           4 files changed, 49 insertions(+), 65 deletions(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index 8857c2556..78f44b4b0 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -128,31 +128,30 @@ namespace advice {
                 
                 
                 /* == Adapter interface for use within the Index == */
          +      
          +      void
          +      setSolution (PointOfAdvice* solution =0)
          +        {
          +          resolution_ = solution;
          +        }
                   
          +      const PointOfAdvice*
          +      getSolution ()  const
          +        {
          +          return resolution_;
          +        }
          +      
          +      Binding::Matcher
          +      getMatcher ()  const
          +        {
          +          return pattern_;
          +        }
          +      
                 friend HashVal
                 hash_value (PointOfAdvice const& entry)
                 {
                   return hash_value (entry.pattern_);
                 }
          -      
          -      friend const Binding::Matcher
          -      getMatcher (PointOfAdvice const& entry)
          -      {
          -        return entry.pattern_;
          -      }
          -      
          -      friend const PointOfAdvice*
          -      getSolution (PointOfAdvice const& entry)
          -      {
          -        return entry.resolution_;
          -      }
          -      
          -      friend void
          -      setSolution (PointOfAdvice* entry, PointOfAdvice* solution =0)
          -      {
          -        REQUIRE (entry);
          -        entry->resolution_ = solution;
          -      }
               };
             
             
          @@ -226,7 +225,7 @@ namespace advice {
                 Provision (Provision const& o)
                   : AdviceLink(o)
                   {
          -          setSolution (this, NULL );
          +          setSolution ( NULL );
                   }
                 
                 Provision&
          @@ -235,7 +234,7 @@ namespace advice {
                     if (!isSameObject(*this, o))
                       {
                         AdviceLink::operator= (o);
          -              setSolution (this, NULL );
          +              setSolution ( NULL );
                       }
                   }
                 
          @@ -297,7 +296,7 @@ namespace advice {
                   : PointOfAdvice(refPoint)
                   , theAdvice_(advice_given)
                   {
          -          setSolution (this, this); // not used currently (5/10)
          +          this->setSolution (this); // not used currently (5/10)
                   }
                 
                 friend class Provision;
          @@ -345,7 +344,7 @@ namespace advice {
             Provision::maybe_rePublish ()
             {
               typedef const ActiveProvision AdviceProvision;
          -    AdviceProvision* solution = static_cast (getSolution (*this));
          +    AdviceProvision* solution = static_cast (getSolution());
               
               if (solution)    // create copy of the data holder, using the new binding 
                 maybe_deallocateOld (
          @@ -398,7 +397,7 @@ namespace advice {
                 AD const&
                 getAdvice()  const
                   {
          -          AdviceProvision* solution = static_cast (getSolution (*this));
          +          AdviceProvision* solution = static_cast (this->getSolution());
                     if (!solution)
                       return this->handleMissingSolution();
                     else
          diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
          index 538deed41..6d0e32b06 100644
          --- a/src/lib/advice/advice.cpp
          +++ b/src/lib/advice/advice.cpp
          @@ -171,8 +171,8 @@ namespace advice {
             const PointOfAdvice*
             AdviceLink::publishProvision (PointOfAdvice* newProvision)
             {
          -    const PointOfAdvice* previousProvision (getSolution (*this));
          -    setSolution (this, newProvision);
          +    const PointOfAdvice* previousProvision (getSolution());
          +    this->setSolution (newProvision);
               
               if (!previousProvision && newProvision)
                 aSys().addProvision (*newProvision);
          @@ -198,8 +198,8 @@ namespace advice {
             const PointOfAdvice*
             AdviceLink::discardSolutions ()
             {
          -    const PointOfAdvice* existingProvision (getSolution (*this));
          -    setSolution (this, NULL );
          +    const PointOfAdvice* existingProvision (getSolution());
          +    this->setSolution ( NULL );
               if (existingProvision)
                 aSys().removeProvision (*existingProvision);
               return existingProvision;
          diff --git a/src/lib/advice/index.hpp b/src/lib/advice/index.hpp
          index 610f793a1..7d3b07fc0 100644
          --- a/src/lib/advice/index.hpp
          +++ b/src/lib/advice/index.hpp
          @@ -31,12 +31,12 @@
            ** This header is intended to be incorporated as part of the advice system implementation (advice.cpp).
            ** It is \em not usable as an external interface. But it is written in a rather self-contained manner,
            ** in order to be testable in isolation. To this end, the actual PointOfAdvice entities being organised
          - ** by this index datastructure remain abstract (defined as template parameter). As link for dealing 
          - ** with those entities, we employ free functions to be picked up by ADL
          + ** by this index datastructure remain abstract (defined as template parameter), and are only manipulated
          + ** through the following functions:
            ** - \c hash_value(POA)
          - ** - \c getMatcher(POA)
          - ** - \c getSolution(POA)
          - ** - \c setSolution(POA,solution)
          + ** - \c POA::getMatcher()
          + ** - \c POA::getSolution()
          + ** - \c POA::setSolution(solution*)
            ** 
            ** \par implementation notes
            ** The advice binding index is implemented by two hashtables holding Binding::Matcher entries.
          @@ -129,7 +129,7 @@ namespace advice {
              * the index allows to add, modify and remove entities of these
              * two kinds. Each of these mutating operations immediately
              * re-computes the advice solutions and publishes the results
          -   * by invoking the free function \c setSolution(POA) for the
          +   * by invoking the \c setSolution() function on the
              * corresponding PointOfAdvice entity.
              * 
              * @note element \em identity is defined in terms of pointing 
          @@ -159,7 +159,7 @@ namespace advice {
                   {
                     explicit
                     Entry (POA& elm)
          -            : pair (getMatcher(elm), &elm)
          +            : pair (elm.getMatcher(), &elm)
                       { }
                     
                     // using default-copy, thus assuming copy is NO_THROW
          @@ -263,7 +263,7 @@ namespace advice {
                     find_latest_solution (POA& requestElm)
                       {
                         typedef typename EntryList::reverse_iterator RIter;
          -              Binding::Matcher pattern (getMatcher (requestElm));
          +              Binding::Matcher pattern (requestElm.getMatcher());
                         for (RIter ii=this->elms_.rbegin();
                              ii!=this->elms_.rend();
                              ++ii )
          @@ -280,9 +280,9 @@ namespace advice {
                         if (solution)
                            // found the most recent advice provision satisfying the (new) request
                           //  thus publish this new advice solution into the request object
          -                setSolution (&requestElm, solution);
          +                requestElm.setSolution (solution);
                         else
          -                setSolution (&requestElm, NULL );
          +                requestElm.setSolution ( NULL );
                           //  report "no solution" which causes a default solution to be used
                       }
                   };
          @@ -293,20 +293,20 @@ namespace advice {
                     void
                     publish_all_solutions (POA& provisionElm)
                       {
          -              Binding::Matcher pattern (getMatcher (provisionElm));
          +              Binding::Matcher pattern (provisionElm.getMatcher());
                         for (EIter ii=this->elms_.begin();
                              ii!=this->elms_.end();
                              ++ii )
                           if (pattern.matches (ii->first))
                              // the given (new) advice provision satisfies this request
                             //  thus publish this new advice solution into the request object
          -                  setSolution (ii->second, &provisionElm);
          +                  ii->second->setSolution (&provisionElm);
                       }
                     
                     void
                     retract_all_solutions (POA const& oldProv, ProvisionCluster& possibleReplacementSolutions)
                       {
          -              Binding::Matcher pattern (getMatcher (oldProv));
          +              Binding::Matcher pattern (oldProv.getMatcher());
                         for (EIter ii=this->elms_.begin();
                              ii!=this->elms_.end();
                              ++ii )
          @@ -319,13 +319,13 @@ namespace advice {
                     void
                     rewrite_all_solutions (POA const& oldProv, POA& newProv, ProvisionCluster& possibleReplacementSolutions)
                       {
          -              Binding::Matcher oldPattern (getMatcher (oldProv));
          -              Binding::Matcher newPattern (getMatcher (newProv));
          +              Binding::Matcher oldPattern (oldProv.getMatcher());
          +              Binding::Matcher newPattern (newProv.getMatcher ());
                         for (EIter ii=this->elms_.begin();
                              ii!=this->elms_.end();
                              ++ii )
                           if (newPattern.matches (ii->first))
          -                  setSolution (ii->second, &newProv);
          +                  ii->second->setSolution (&newProv);
                           else
                           if (oldPattern.matches (ii->first))
                             possibleReplacementSolutions.publish_latest_solution (*(ii->second));
          @@ -577,11 +577,11 @@ namespace advice {
             {
               verify_Entry (e,hash);
               POA& request = *(e.second);
          -    const POA* solution (getSolution (request));
          +    const POA* solution (request.getSolution());
               if (solution && hasProvision(*solution))
                 {
                   POA* currentSolution = provisionEntries_[hash].find_latest_solution (request); 
          -        VERIFY (e.first.matches (getMatcher(*solution)), "stored advice solution not supported by binding match");
          +        VERIFY (e.first.matches (solution->getMatcher()),"stored advice solution not supported by binding match");
                   VERIFY (bool(currentSolution),                   "unable to reproduce stored solution with the current provisions")
                   VERIFY (solution == currentSolution,             "stored advice solution isn't the topmost solution for this request")
                 }
          diff --git a/tests/lib/advice/advice-index-test.cpp b/tests/lib/advice/advice-index-test.cpp
          index c098552c7..1e516c958 100644
          --- a/tests/lib/advice/advice-index-test.cpp
          +++ b/tests/lib/advice/advice-index-test.cpp
          @@ -70,30 +70,15 @@ namespace test {
                   
                   /* == Adapter interface for use within the Index == */
                   
          +        void setSolution (TestPOA* p)        { solution_ = p;   }
          +        const TestPOA*  getSolution () const { return solution_;}
          +        Binding::Matcher getMatcher () const { return pattern_; }
          +        
                   friend HashVal
                   hash_value (TestPOA const& entry)
                   {
                     return hash_value (entry.pattern_);
                   }
          -        
          -        friend const Binding::Matcher
          -        getMatcher (TestPOA const& entry)
          -        {
          -          return entry.pattern_;
          -        }
          -        
          -        friend const TestPOA*
          -        getSolution (TestPOA const& entry)
          -        {
          -          return entry.solution_;
          -        }
          -        
          -        friend void
          -        setSolution (TestPOA* entry, TestPOA* solution =0)
          -        {
          -          REQUIRE (entry);
          -          entry->solution_ = solution;
          -        }
                 };
               
               
          
          From 6b907674681c5e9ab3b87c2de5ae5f992c5b9720 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Sun, 6 Jun 2010 04:26:23 +0200
          Subject: [PATCH 43/52] draft a component to manage deleter functions
          
          ---
           src/lib/del-stash.hpp        | 146 ++++++++++++++++++++++++
           tests/40components.tests     |   5 +
           tests/lib/del-stash-test.cpp | 207 +++++++++++++++++++++++++++++++++++
           3 files changed, 358 insertions(+)
           create mode 100644 src/lib/del-stash.hpp
           create mode 100644 tests/lib/del-stash-test.cpp
          
          diff --git a/src/lib/del-stash.hpp b/src/lib/del-stash.hpp
          new file mode 100644
          index 000000000..da26c13f0
          --- /dev/null
          +++ b/src/lib/del-stash.hpp
          @@ -0,0 +1,146 @@
          +/*
          +  DEL-STASH.hpp  -  collect and execute deleter functions
          + 
          +  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 del-stash.hpp
          + ** Collecting and finally triggering deleter functions.
          + ** This building block for custom memory management allows memorising how to kill an object.
          + ** Frequently, custom allocation schemes have to deal with type erased elements, where the
          + ** full typed context is only available during construction. When implementing these objects
          + ** without vtable, we need a reliable way of recalling the correct destructor to invoke.
          + ** Typically, such entry objects are to be de-allocated in bulk during shutdown, with
          + ** the possibility to deallocate some objects beforehand explicitly.
          + ** 
          + ** The implementation is based on using a vector in a stack-like fashion, thus the
          + ** deallocation of individual objects might degenerate in performance.
          + ** 
          + ** @see DelStash_test
          + ** @see AdviceSystem usage example
          + **
          + */
          +
          +
          +
          +#ifndef LIB_DEL_STASH_H
          +#define LIB_DEL_STASH_H
          +
          +
          +#include "lib/error.hpp"
          +
          +//#include 
          +//#include       /////TODO better push the hash implementation into a cpp file (and btw, do it more seriously!)
          +
          +//#include 
          +//#include 
          +#include 
          +
          +
          +namespace lib {
          +
          +//  using boost::hash_value;
          +  
          +  
          +  /** 
          +   * Manage a collection of deleter functions.
          +   * This component can memorise addresses and deleter functions
          +   * and trigger deletion of single objects, or delete all objects
          +   * on demand or automatically on shutdown.
          +   */
          +  class DelStash
          +    : boost::noncopyable
          +    {
          +      
          +    public:
          +      DelStash (size_t elms_to_reserve =0)
          +        { 
          +          if (elms_to_reserve)
          +            {
          +              //
          +            }
          +        }
          +      
          +     ~DelStash ()
          +        {
          +          try { killAll(); }
          +          
          +          catch(...)
          +            {
          +              Symbol errID = lumiera_error();
          +              WARN (memory, "Problems on de-allocation: %s", errID.c());
          +            }
          +        }
          +      
          +      size_t
          +      size ()  const
          +        {
          +          UNIMPLEMENTED ("killer size");
          +        }
          +      
          +      
          +      template
          +      void
          +      manage (TY* obj)
          +        {
          +          UNIMPLEMENTED ("accept typed ptr for later killing");      
          +        }
          +      
          +      template
          +      void
          +      manage (TY& obj)
          +        {
          +          UNIMPLEMENTED ("accept typed obj ref for later killing");      
          +        }
          +      
          +      template
          +      void
          +      manage (void *obj)
          +        {
          +          UNIMPLEMENTED ("accept object by void* and type information");      
          +        }
          +      
          +      
          +      template
          +      void
          +      kill (TY* obj)
          +        {
          +          UNIMPLEMENTED ("pick and kill object denoted by address");      
          +        }
          +      
          +      template
          +      void
          +      kill (TY& obj)
          +        {
          +          UNIMPLEMENTED ("pick and kill object denoted by reference");      
          +        }
          +      
          +      void
          +      killAll ()
          +        {
          +          UNIMPLEMENTED ("mass kill");
          +        }
          +    };
          +  
          +  
          +  
          +  
          +} // namespace lib
          +#endif
          diff --git a/tests/40components.tests b/tests/40components.tests
          index 174fc20d2..d729cc964 100644
          --- a/tests/40components.tests
          +++ b/tests/40components.tests
          @@ -226,6 +226,11 @@ return: 0
           END
           
           
          +PLANNED "Deleter function collection" DelStash_test <	 : Yes
           out: HasNested_Core	 : No
          diff --git a/tests/lib/del-stash-test.cpp b/tests/lib/del-stash-test.cpp
          new file mode 100644
          index 000000000..3fb9002cf
          --- /dev/null
          +++ b/tests/lib/del-stash-test.cpp
          @@ -0,0 +1,207 @@
          +/*
          +  DelStash(Test)  -  verify a facility to memorise and trigger deleter functions
          + 
          +  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/del-stash.hpp"
          +
          +#include 
          +#include 
          +
          +
          +
          +namespace lib {
          +namespace test{
          +  
          +  using std::tr1::function;
          +  using std::rand;
          +  
          +  
          +  
          +  namespace { // probe victims
          +    
          +    ulong MAX_MASS = 200;  // number of victims for mass kill
          +    
          +    ulong checksum = 0;
          +    
          +    
          +    template
          +    class Probe
          +      {
          +        uint mySiz_;
          +        char myCrap_[siz];
          +        
          +      public:
          +        Probe()
          +          : mySiz_(siz)
          +          {
          +            REQUIRE (siz);
          +            for (uint i=0; i
          +    Probe*
          +    makeViktim ()
          +    {
          +      return new Probe();
          +    }
          +    
          +  }//(End) test data
          +  
          +  
          +  
          +  
          +  /****************************************************************************
          +   * @test create a bunch of objects with varying type and size, memorising
          +   *       how to kill them properly. Verify everyone is dead after mass-kill.
          +   *       
          +   * @see lib::DelStash
          +   */
          +  class DelStash_test : public Test
          +    {
          +      
          +      virtual void
          +      run (Arg)
          +        {
          +          checksum = 0;
          +          checkSingleKill();
          +          checkMassKill();
          +          checkAutoKill();
          +        }
          +      
          +      
          +      void
          +      checkSingleKill ()
          +        {
          +          DelStash killer;
          +          CHECK (0 == killer.size());
          +          
          +          killer.manage (NULL);
          +          CHECK (0 == killer.size());
          +          
          +          Probe<5> *p =  makeViktim<5>();
          +          Probe<7> &r = *makeViktim<7>();
          +          void     *v =  makeViktim<9>();
          +          CHECK (0 < checksum);
          +          
          +          killer.manage (p);
          +          killer.manage (r);
          +          killer.manage > (v);
          +          
          +          CHECK (3 == killer.size());
          +          
          +          killer.kill (r);
          +          CHECK (2 == killer.size());
          +          
          +          killer.kill (p);
          +          CHECK (1 == killer.size());
          +          
          +          killer.kill (p);            // ignores spurious kill requests
          +          CHECK (1 == killer.size());
          +          
          +          killer.kill (v);
          +          CHECK (0 == killer.size());
          +          CHECK (0 == checksum);
          +        }
          +      
          +      
          +      void
          +      feedViktims (DelStash& killer)
          +        {
          +          function builder[5];
          +          builder[0] = makeViktim<12>;
          +          builder[1] = makeViktim<23>;
          +          builder[2] = makeViktim<34>;
          +          builder[3] = makeViktim<45>;
          +          builder[4] = makeViktim<56>;
          +          
          +          for (uint i=1; i <= MAX_MASS; ++i)
          +            killer.manage (builder[i % 5]());
          +        }
          +      
          +      
          +      void
          +      checkMassKill ()
          +        {
          +          DelStash killer;
          +          CHECK (0 == killer.size());
          +          
          +          CHECK (0 == checksum);
          +          CHECK (0 == killer.size());
          +          
          +          feedViktims (killer);
          +          CHECK (MAX_MASS == killer.size());
          +          
          +          killer.killAll();
          +          CHECK (0 == killer.size());
          +          CHECK (0 == checksum);
          +        }
          +      
          +      
          +      void
          +      checkAutoKill()
          +        {
          +          {
          +            DelStash killer;
          +            CHECK (0 == killer.size());
          +            CHECK (0 == checksum);
          +            
          +            feedViktims (killer);
          +            void * individuum = makeViktim<444>();
          +            killer.manage (individuum);
          +            feedViktims (killer);
          +            killer.manage (makeViktim<5555>());
          +            feedViktims (killer);
          +            
          +            CHECK (3*MAX_MASS + 2 == killer.size());
          +            
          +            killer.kill(individuum);
          +            CHECK (3*MAX_MASS + 1 == killer.size());
          +            
          +            CHECK (0 < checksum);
          +          }// killer going out of scope...
          +          
          +          CHECK (0 == checksum);
          +        }
          +    };
          +  
          +  
          +  /** Register this test class... */
          +  LAUNCHER (DelStash_test, "unit common");
          +  
          +  
          +}} // namespace lib::test
          
          From 9aca3488709715f2ae8f778ef425f0074e61cc47 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Mon, 7 Jun 2010 02:14:10 +0200
          Subject: [PATCH 44/52] code up implementation of this killer-stash
          
          ---
           src/lib/del-stash.hpp | 114 +++++++++++++++++++++++++++++++++++-------
           1 file changed, 96 insertions(+), 18 deletions(-)
          
          diff --git a/src/lib/del-stash.hpp b/src/lib/del-stash.hpp
          index da26c13f0..468e9d1c9 100644
          --- a/src/lib/del-stash.hpp
          +++ b/src/lib/del-stash.hpp
          @@ -46,35 +46,68 @@
           
           #include "lib/error.hpp"
           
          -//#include 
          -//#include       /////TODO better push the hash implementation into a cpp file (and btw, do it more seriously!)
          -
          -//#include 
          -//#include 
          +#include 
          +#include 
           #include 
          +#include 
          +#include 
           
           
           namespace lib {
          -
          -//  using boost::hash_value;
             
             
          -  /** 
          +  /**
              * Manage a collection of deleter functions.
              * This component can memorise addresses and deleter functions
              * and trigger deletion of single objects, or delete all objects
              * on demand or automatically on shutdown.
          +   * @warning clients must not add a given object more than once
              */
             class DelStash
               : boost::noncopyable
               {
          +      /**
          +       * @internal entry to store target object
          +       * and the actual deleter function to use
          +       */
          +      class Killer
          +        {
          +          typedef void KillFun(void*);
          +          void* target_;
          +          KillFun* killIt_;
          +          
          +        public:
          +          Killer(KillFun* f, void* t)
          +            : target_(t)
          +            , killIt_(f)
          +            {
          +              REQUIRE(f);
          +            }
          +          
          +          void
          +          trigger ()
          +            {
          +              if (target_)
          +                killIt_(target_);
          +              target_ = NULL; // remember kill
          +            }
          +          
          +          bool operator== (const void* target)  const { return target_ == target; }
          +          bool operator!= (const void* target)  const { return target_ != target; }
          +        };
          +      
          +      
          +      typedef std::vector Killers;
          +      Killers killers_;
          +      
                 
               public:
                 DelStash (size_t elms_to_reserve =0)
          +        : killers_()
                   { 
                     if (elms_to_reserve)
                       {
          -              //
          +              killers_.reserve (elms_to_reserve);
                       }
                   }
                 
          @@ -92,29 +125,35 @@ namespace lib {
                 size_t
                 size ()  const
                   {
          -          UNIMPLEMENTED ("killer size");
          +          return killers_.size();
                   }
                 
                 
          +#define __DONT_USE_THIS_OVERLOAD_FOR_VOID_POINTER_ typename boost::disable_if >::type* =0
          +      
          +      
                 template
                 void
          -      manage (TY* obj)
          +      manage (TY* obj,  __DONT_USE_THIS_OVERLOAD_FOR_VOID_POINTER_)
                   {
          -          UNIMPLEMENTED ("accept typed ptr for later killing");      
          +          REQUIRE (!isRegistered (obj));
          +          killers_.push_back (Killer (how_to_kill, obj));
                   }
                 
                 template
                 void
                 manage (TY& obj)
                   {
          -          UNIMPLEMENTED ("accept typed obj ref for later killing");      
          +          REQUIRE (!isRegistered (&obj));
          +          killers_.push_back (Killer (how_to_kill, &obj));
                   }
                 
                 template
                 void
                 manage (void *obj)
                   {
          -          UNIMPLEMENTED ("accept object by void* and type information");      
          +          REQUIRE (!isRegistered (obj));
          +          killers_.push_back (Killer (how_to_kill, obj));
                   }
                 
                 
          @@ -122,20 +161,59 @@ namespace lib {
                 void
                 kill (TY* obj)
                   {
          -          UNIMPLEMENTED ("pick and kill object denoted by address");      
          -        }
          +          triggerKill (obj);
          +        } // note: entry remains in the killer vector,
          +         //  but is now disabled and can't be found anymore
                 
                 template
                 void
                 kill (TY& obj)
                   {
          -          UNIMPLEMENTED ("pick and kill object denoted by reference");      
          +          triggerKill (&obj);
                   }
                 
                 void
                 killAll ()
                   {
          -          UNIMPLEMENTED ("mass kill");
          +          size_t i = size();
          +          while (i)
          +            {
          +              killers_[i].trigger();
          +            }
          +        }
          +      
          +      
          +    private:
          +      /** trampoline function to invoke destructor
          +       *  of the specific target type */
          +      template
          +      static void
          +      how_to_kill (void* subject)
          +        {
          +          TY* victim = static_cast (subject);
          +          ENSURE (victim);
          +          delete victim;
          +        };
          +      
          +      bool
          +      isRegistered (const void* objAddress)
          +        {
          +          return killers_.end() != findEntry (objAddress);
          +        }
          +      
          +      Killers::iterator
          +      findEntry (const void* obj)
          +        {
          +          return std::find(killers_.begin(),killers_.end(), obj);
          +        }
          +      
          +      void
          +      triggerKill (void* objAddress)
          +        {
          +          Killers::iterator pos = findEntry (objAddress);
          +          if (killers_.end() != pos)
          +            pos->trigger();
          +          ENSURE (!isRegistered (objAddress), "duplicate deleter registration");
                   }
               };
             
          
          From eb19f59ba0637a398992de23a685e75722c7adcf Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Mon, 7 Jun 2010 03:32:41 +0200
          Subject: [PATCH 45/52] deleter memorising component passes unit test (#629)
          
          ---
           src/lib/del-stash.hpp        | 29 +++++++++++++++++------
           tests/40components.tests     |  2 +-
           tests/lib/del-stash-test.cpp | 46 +++++++++++++++++++++---------------
           3 files changed, 50 insertions(+), 27 deletions(-)
          
          diff --git a/src/lib/del-stash.hpp b/src/lib/del-stash.hpp
          index 468e9d1c9..fa3c87eb5 100644
          --- a/src/lib/del-stash.hpp
          +++ b/src/lib/del-stash.hpp
          @@ -55,6 +55,8 @@
           
           namespace lib {
             
          +  using boost::disable_if_c;
          +  using boost::is_same;
             
             /**
              * Manage a collection of deleter functions.
          @@ -94,6 +96,12 @@ namespace lib {
                     
                     bool operator== (const void* target)  const { return target_ == target; }
                     bool operator!= (const void* target)  const { return target_ != target; }
          +          
          +          bool
          +          isActive()  const
          +            {
          +              return bool(target_);
          +            }
                   };
                 
                 
          @@ -125,24 +133,32 @@ namespace lib {
                 size_t
                 size ()  const
                   {
          -          return killers_.size();
          +          size_t activeEntries = 0;
          +          size_t i = killers_.size();
          +          while (i)
          +            if (killers_[--i].isActive())
          +              ++activeEntries;
          +          return activeEntries;
                   }
                 
                 
          -#define __DONT_USE_THIS_OVERLOAD_FOR_VOID_POINTER_ typename boost::disable_if >::type* =0
          +#define __DONT_USE_THIS_OVERLOAD_FOR_VOID_POINTER_      \
          +          typename disable_if_c< is_same::value \
          +                               ||is_same::value>::type* =0
                 
                 
                 template
                 void
                 manage (TY* obj,  __DONT_USE_THIS_OVERLOAD_FOR_VOID_POINTER_)
                   {
          +          if (!obj) return;
                     REQUIRE (!isRegistered (obj));
                     killers_.push_back (Killer (how_to_kill, obj));
                   }
                 
                 template
                 void
          -      manage (TY& obj)
          +      manage (TY& obj,  __DONT_USE_THIS_OVERLOAD_FOR_VOID_POINTER_)
                   {
                     REQUIRE (!isRegistered (&obj));
                     killers_.push_back (Killer (how_to_kill, &obj));
          @@ -152,6 +168,7 @@ namespace lib {
                 void
                 manage (void *obj)
                   {
          +          if (!obj) return;
                     REQUIRE (!isRegistered (obj));
                     killers_.push_back (Killer (how_to_kill, obj));
                   }
          @@ -175,11 +192,9 @@ namespace lib {
                 void
                 killAll ()
                   {
          -          size_t i = size();
          +          size_t i = killers_.size();
                     while (i)
          -            {
          -              killers_[i].trigger();
          -            }
          +            killers_[--i].trigger();
                   }
                 
                 
          diff --git a/tests/40components.tests b/tests/40components.tests
          index d729cc964..241606571 100644
          --- a/tests/40components.tests
          +++ b/tests/40components.tests
          @@ -226,7 +226,7 @@ return: 0
           END
           
           
          -PLANNED "Deleter function collection" DelStash_test <
           #include 
           
           
          @@ -33,14 +31,13 @@
           namespace lib {
           namespace test{
             
          -  using std::tr1::function;
             using std::rand;
             
             
             
             namespace { // probe victims
               
          -    ulong MAX_MASS = 200;  // number of victims for mass kill
          +    ulong MAX_MASS = 200;  // number of victims to kill at once
               
               ulong checksum = 0;
               
          @@ -73,13 +70,21 @@ namespace test{
                 };
               
               
          -    template
          -    Probe*
          +    template
          +    inline Probe*
               makeViktim ()
               {
          -      return new Probe();
          +      return new Probe();
               }
               
          +    template
          +    inline void
          +    feedViktim (DelStash& killer)
          +      {
          +        killer.manage (new Probe());
          +      }
          +    
          +    
             }//(End) test data
             
             
          @@ -88,7 +93,11 @@ namespace test{
             /****************************************************************************
              * @test create a bunch of objects with varying type and size, memorising
              *       how to kill them properly. Verify everyone is dead after mass-kill.
          -   *       
          +   *       Use a checksum not only to verify the number of objects created and
          +   *       destroyed, but also the individual (random) contents of the data
          +   *       within the objects, to ensure that the correct destructor
          +   *       actually is invoked for each type.
          +   * 
              * @see lib::DelStash
              */
             class DelStash_test : public Test
          @@ -130,8 +139,8 @@ namespace test{
                     killer.kill (p);
                     CHECK (1 == killer.size());
                     
          -          killer.kill (p);            // ignores spurious kill requests
          -          CHECK (1 == killer.size());
          +          killer.kill (p);
          +          CHECK (1 == killer.size()); // spurious kill requests ignored
                     
                     killer.kill (v);
                     CHECK (0 == killer.size());
          @@ -142,15 +151,14 @@ namespace test{
                 void
                 feedViktims (DelStash& killer)
                   {
          -          function builder[5];
          -          builder[0] = makeViktim<12>;
          -          builder[1] = makeViktim<23>;
          -          builder[2] = makeViktim<34>;
          -          builder[3] = makeViktim<45>;
          -          builder[4] = makeViktim<56>;
          -          
                     for (uint i=1; i <= MAX_MASS; ++i)
          -            killer.manage (builder[i % 5]());
          +            switch (i% 5) {
          +              case 0: feedViktim<12> (killer); break;
          +              case 1: feedViktim<23> (killer); break;
          +              case 2: feedViktim<34> (killer); break;
          +              case 3: feedViktim<45> (killer); break;
          +              case 4: feedViktim<56> (killer); break;
          +            }
                   }
                 
                 
          @@ -181,7 +189,7 @@ namespace test{
                       CHECK (0 == checksum);
                       
                       feedViktims (killer);
          -            void * individuum = makeViktim<444>();
          +            Probe<444> * individuum = makeViktim<444>();
                       killer.manage (individuum);
                       feedViktims (killer);
                       killer.manage (makeViktim<5555>());
          
          From 4fb884669b6d33599099ac4318331d6dabf76355 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Tue, 8 Jun 2010 04:26:28 +0200
          Subject: [PATCH 46/52] ooops... didn't invoke the dtor when releasing an
           Advice holer
          
          ---
           src/lib/advice.hpp | 6 +++++-
           1 file changed, 5 insertions(+), 1 deletion(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index 78f44b4b0..063584533 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -331,7 +331,11 @@ namespace advice {
             {
               typedef ActiveProvision Holder;
               if (existingEntry)
          -      releaseBuffer (existingEntry, sizeof(Holder));
          +      {
          +        Holder* obj = (Holder*)existingEntry;
          +        obj->~Holder();
          +        releaseBuffer (existingEntry, sizeof(Holder));
          +      }
             }
             
             
          
          From 59145e0f149639866ea6044b0201e148167088bf Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Fri, 11 Jun 2010 04:12:11 +0200
          Subject: [PATCH 47/52] Refactor storing of advice to prepare for actually
           managing the storage
          
          ---
           src/lib/advice.hpp        | 57 +++++++++++++++++++++++----------------
           src/lib/advice/advice.cpp | 47 +++++++++++++++++++++++++++-----
           2 files changed, 74 insertions(+), 30 deletions(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index 063584533..d76193a22 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -91,12 +91,14 @@
           
           #include 
           
          -using util::isSameObject;
          -
           
           namespace lib    {
           namespace advice {
             
          +  using lib::Symbol;
          +  using util::isSameObject;
          +  
          +  
             /**
              * TODO type comment
              */
          @@ -167,15 +169,18 @@ namespace advice {
               : public PointOfAdvice
               {
               protected:
          -      const PointOfAdvice* publishProvision (PointOfAdvice*);
          -      const PointOfAdvice* discardSolutions ();
          +      void publishProvision (PointOfAdvice*);
          +      void discardSolutions ();
                 void publishRequestBindingChange(HashVal);
                 
                 void registerRequest();
                 void deregisterRequest();
                 
          -      void* getBuffer(size_t);
          -      void  releaseBuffer (const void*, size_t);
          +      static void* getBuffer(size_t);
          +      static void  releaseBuffer (const void*, size_t);
          +      
          +      typedef void (DeleterFunc)(void*);
          +      static void manageAdviceData (PointOfAdvice*, DeleterFunc*);
                 
               public:
                 explicit
          @@ -241,15 +246,13 @@ namespace advice {
                 
                 void setAdvice (AD const& pieceOfAdvice)
                   {
          -          maybe_deallocateOld (
          -              publishProvision(
          -                  storeCopy (pieceOfAdvice)));
          +          publishProvision(
          +            storeCopy (pieceOfAdvice));
                   }
                 
                 void retractAdvice()
                   {
          -          maybe_deallocateOld(
          -              discardSolutions());
          +          discardSolutions();
                   }
                 
                 void
          @@ -261,7 +264,7 @@ namespace advice {
                 
               private:
                 PointOfAdvice* storeCopy (AD const& advice_given);
          -      void maybe_deallocateOld(const PointOfAdvice*);
          +      static void releaseAdviceData (void*);
                 void maybe_rePublish ();
               };
             
          @@ -314,27 +317,36 @@ namespace advice {
             Provision::storeCopy (AD const& advice_given)
             {
               typedef ActiveProvision Holder;
          -    return new(getBuffer(sizeof(Holder))) Holder (*this, advice_given);
          +    void* storage = getBuffer(sizeof(Holder));
          +    try
          +      {
          +        Holder* storedProvision = new(storage) Holder (*this, advice_given);
          +        manageAdviceData (storedProvision, &releaseAdviceData);
          +        return storedProvision;
          +      }
          +    catch(...)
          +      {
          +        Symbol errID = lumiera_error();
          +        releaseBuffer (storage, sizeof(Holder));
          +        throw lumiera::error::Fatal ("Failure to store advice data", errID);
          +      }
             }
             
             
             /** @internal assist the AdviceSystem with deallocating buffer storage.
              *  Problem is we need to know the exact size of the advice value holder,
              *  which information is available only here, in the fully typed context.
          -   *  @note the assumption is that \em any binding created will automatically
          -   *        contain a type guard, which ensures the existingEntry passed in here
          -   *        originally was allocated by #storeCopy within the same typed context.
              */
             template
             inline void
          -  Provision::maybe_deallocateOld (const PointOfAdvice* existingEntry)
          +  Provision::releaseAdviceData (void* entry)
             {
               typedef ActiveProvision Holder;
          -    if (existingEntry)
          +    if (entry)
                 {
          -        Holder* obj = (Holder*)existingEntry;
          +        Holder* obj = static_cast (entry);
                   obj->~Holder();
          -        releaseBuffer (existingEntry, sizeof(Holder));
          +        releaseBuffer (entry, sizeof(Holder));
                 }
             }
             
          @@ -351,9 +363,8 @@ namespace advice {
               AdviceProvision* solution = static_cast (getSolution());
               
               if (solution)    // create copy of the data holder, using the new binding 
          -      maybe_deallocateOld (
          -          publishProvision(
          -              storeCopy (solution->getAdvice())));
          +      publishProvision(
          +        storeCopy (solution->getAdvice()));
             }
             
             
          diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
          index 6d0e32b06..660ff9ef8 100644
          --- a/src/lib/advice/advice.cpp
          +++ b/src/lib/advice/advice.cpp
          @@ -61,10 +61,18 @@
            ** re-discover the specifically typed context; the type guards can only be checked for a match.
            ** Thus we need the help of the frontend objects, which need to provide a deleter function
            ** when providing concrete advice data; this deleter function will be saved as function pointer
          - ** so to be able to deallocate all advice data when the AdviceSystem is shut down
          - **
          + ** so to be able to deallocate all advice data when the AdviceSystem is shut down.
          + ** 
          + ** @todo This approach is closely related to the decision to use a single global index table
          + ** for managing all advice collaborations. An alternative would be to use either a separate
          + ** table for each type, or to store an additional type descriptor with this memory management
          + ** information into each "bucket", which can be assumed to manage entries dealing with the
          + ** same kind of advice data, because each binding automatically includes a type guard.
          + ** If we ever happen to get a significant amount of advice data, but only a small
          + ** number of different advice types, we should reconsider this optimisation.
          + ** 
            ** @todo currently this is unimplemented and we happily leak memory....
          - ** @todo rewrite the allocation to use Lumiera's mpool instead of heap allocations
          + ** @todo rewrite the allocation to use Lumiera's MPool instead of heap allocations
            ** 
            ** \par synchronisation
            ** While the frontend objects are deliberately \em not threadsafe, the lookup implementation
          @@ -112,6 +120,15 @@ namespace advice {
                     {
                       INFO (library, "Shutting down Advice system.");
                     }
          +       
          +       
          +       void discardEntry (const PointOfAdvice* storedProvision)
          +         {
          +           if (storedProvision)
          +             {
          +               UNIMPLEMENTED ("use stored management information to trigger deletion");
          +             }
          +         }
                 };
               
               
          @@ -155,6 +172,21 @@ namespace advice {
             }
             
             
          +  /** Store a descriptor record to take ownership of the given allocation.
          +   *  Problem is we need to know the exact size of the advice value holder,
          +   *  which information is available initially, when the advice data is
          +   *  copied into the system. The knowledge about the size of the allocation
          +   *  is embodied into the deleter function. This allows later to discard
          +   *  entries without needing to know their exact type. 
          +   */
          +  void
          +  AdviceLink::manageAdviceData (PointOfAdvice* entry, DeleterFunc* how_to_delete)
          +  {
          +    UNIMPLEMENTED ("store memory management information");
          +  }
          +
          +  
          +  
             
             /** when the Provision actually sets advice data, this is copied
              *  into an internal buffer within the AdviceSystem. We then use the
          @@ -168,7 +200,7 @@ namespace advice {
              *          and thus the size of the entry to deallocate.
              *          Returning \c NULL in case no old entry exists.
              */
          -  const PointOfAdvice*
          +  void
             AdviceLink::publishProvision (PointOfAdvice* newProvision)
             {
               const PointOfAdvice* previousProvision (getSolution());
          @@ -183,7 +215,7 @@ namespace advice {
               if (previousProvision && !newProvision)
                 aSys().removeProvision (*previousProvision);
               
          -    return previousProvision;  // to be deallocated by caller if non-NULL
          +    aSys().discardEntry (previousProvision);
             }
             
             
          @@ -195,14 +227,15 @@ namespace advice {
              *          to be deallocated by the caller, which
              *          is assumed to know it's exact type.
              */
          -  const PointOfAdvice*
          +  void
             AdviceLink::discardSolutions ()
             {
               const PointOfAdvice* existingProvision (getSolution());
               this->setSolution ( NULL );
               if (existingProvision)
                 aSys().removeProvision (*existingProvision);
          -    return existingProvision;
          +    
          +    aSys().discardEntry (existingProvision);
             }
             
             
          
          From cb838ba5b6bbbcbe1339aad9f02593220d05cf9b Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Sat, 12 Jun 2010 03:12:02 +0200
          Subject: [PATCH 48/52] extend killer-stash to allow registration of custom
           deleter functions
          
          ---
           src/lib/del-stash.hpp        | 23 ++++++++++++-----
           tests/lib/del-stash-test.cpp | 50 ++++++++++++++++++++++++++++++++++++
           2 files changed, 67 insertions(+), 6 deletions(-)
          
          diff --git a/src/lib/del-stash.hpp b/src/lib/del-stash.hpp
          index fa3c87eb5..b05725c94 100644
          --- a/src/lib/del-stash.hpp
          +++ b/src/lib/del-stash.hpp
          @@ -68,13 +68,15 @@ namespace lib {
             class DelStash
               : boost::noncopyable
               {
          +      
          +      typedef void KillFun(void*);
          +      
                 /**
          -       * @internal entry to store target object
          +       * @internal entry to store target pointer
                  * and the actual deleter function to use
                  */
                 class Killer
                   {
          -          typedef void KillFun(void*);
                     void* target_;
                     KillFun* killIt_;
                     
          @@ -106,6 +108,7 @@ namespace lib {
                 
                 
                 typedef std::vector Killers;
          +      
                 Killers killers_;
                 
                 
          @@ -166,13 +169,21 @@ namespace lib {
                 
                 template
                 void
          -      manage (void *obj)
          +      manage (void* obj)
                   {
                     if (!obj) return;
                     REQUIRE (!isRegistered (obj));
                     killers_.push_back (Killer (how_to_kill, obj));
                   }
                 
          +      void
          +      manage (void* obj, KillFun* customDeleter)
          +        {
          +          if (!obj) return;
          +          REQUIRE (!isRegistered (obj));
          +          killers_.push_back (Killer (customDeleter, obj));
          +        }
          +      
                 
                 template
                 void
          @@ -180,7 +191,7 @@ namespace lib {
                   {
                     triggerKill (obj);
                   } // note: entry remains in the killer vector,
          -         //  but is now disabled and can't be found anymore
          +         //  but is disabled and can't be found anymore
                 
                 template
                 void
          @@ -201,11 +212,11 @@ namespace lib {
               private:
                 /** trampoline function to invoke destructor
                  *  of the specific target type */
          -      template
          +      template
                 static void
                 how_to_kill (void* subject)
                   {
          -          TY* victim = static_cast (subject);
          +          X* victim = static_cast (subject);
                     ENSURE (victim);
                     delete victim;
                   };
          diff --git a/tests/lib/del-stash-test.cpp b/tests/lib/del-stash-test.cpp
          index 052604823..f09500b98 100644
          --- a/tests/lib/del-stash-test.cpp
          +++ b/tests/lib/del-stash-test.cpp
          @@ -108,6 +108,7 @@ namespace test{
                   {
                     checksum = 0;
                     checkSingleKill();
          +          checkCustomKill();
                     checkMassKill();
                     checkAutoKill();
                   }
          @@ -205,6 +206,55 @@ namespace test{
                     
                     CHECK (0 == checksum);
                   }
          +      
          +      
          +      /** @test use a custom-provided
          +       *        deleter function 
          +       */
          +      void
          +      checkCustomKill ()
          +        {
          +          DelStash killer;
          +          CHECK (0 == killer.size());
          +          
          +          /** a very specific setup,
          +           *  bound to mess up the checksum,
          +           *  unless the random bias is removed
          +           *  by the custom deleter function
          +           */ 
          +          class Special
          +            : Probe<555>
          +            {
          +              char secret_;
          +              
          +            public:
          +              Special()
          +                : Probe<555>()
          +                , secret_('a' + (rand() % (1+'z'-'a')))
          +                {
          +                  checksum += secret_;
          +                }
          +              
          +              static void
          +              selfKill (void *it)
          +                {
          +                  Special *self = static_cast (it);
          +                  checksum -= self->secret_;
          +                  delete self;
          +                }
          +            };
          +          
          +          
          +          void * type_erased = new Special();
          +          CHECK (0 < checksum);
          +          
          +          killer.manage (type_erased, &Special::selfKill);
          +          CHECK (1 == killer.size());
          +          
          +          killer.kill(type_erased);
          +          CHECK (0 == killer.size());
          +          CHECK (0 == checksum);
          +        }
               };
             
             
          
          From a93d8a42e4eb5fcdd33eafc100eb27d6473fa476 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Sat, 12 Jun 2010 03:33:40 +0200
          Subject: [PATCH 49/52] use killer-stash to resolve the AdviceSystem memory
           leak
          
          ---
           src/lib/advice/advice.cpp | 24 ++++++++++++++++++------
           src/lib/del-stash.hpp     |  2 ++
           2 files changed, 20 insertions(+), 6 deletions(-)
          
          diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
          index 660ff9ef8..a0e6e33ed 100644
          --- a/src/lib/advice/advice.cpp
          +++ b/src/lib/advice/advice.cpp
          @@ -92,17 +92,21 @@
           
           #include "lib/advice.hpp"
           #include "lib/advice/index.hpp"
          +#include "lib/del-stash.hpp"
           #include "lib/singleton.hpp"
          +#include "lib/util.hpp"
           #include "include/logging.h"
           
           #include 
           
           using lib::Singleton;
          +using util::unConst;
          +
          +typedef void (DeleterFunc)(void*);
           
           namespace lib {
           namespace advice {
             
          -  
             namespace { // ======= implementation of the AdviceSystem ============
               
               class AdviceSystem
          @@ -110,6 +114,8 @@ namespace advice {
                 , boost::noncopyable
                 {
                   
          +        DelStash adviceDataRegistry_;
          +        
                 public:
                   AdviceSystem()
                     {
          @@ -121,12 +127,18 @@ namespace advice {
                       INFO (library, "Shutting down Advice system.");
                     }
                  
          +       void
          +       manageAdviceData (PointOfAdvice* entry, DeleterFunc* how_to_delete)
          +         {
          +           adviceDataRegistry_.manage (entry, how_to_delete);
          +         }
                  
          -       void discardEntry (const PointOfAdvice* storedProvision)
          +       void
          +       discardEntry (PointOfAdvice* storedProvision)
                    {
                      if (storedProvision)
                        {
          -               UNIMPLEMENTED ("use stored management information to trigger deletion");
          +               adviceDataRegistry_.kill (storedProvision);
                        }
                    }
                 };
          @@ -182,7 +194,7 @@ namespace advice {
             void
             AdviceLink::manageAdviceData (PointOfAdvice* entry, DeleterFunc* how_to_delete)
             {
          -    UNIMPLEMENTED ("store memory management information");
          +    aSys().manageAdviceData (entry,how_to_delete);
             }
           
             
          @@ -215,7 +227,7 @@ namespace advice {
               if (previousProvision && !newProvision)
                 aSys().removeProvision (*previousProvision);
               
          -    aSys().discardEntry (previousProvision);
          +    aSys().discardEntry (unConst(previousProvision));
             }
             
             
          @@ -235,7 +247,7 @@ namespace advice {
               if (existingProvision)
                 aSys().removeProvision (*existingProvision);
               
          -    aSys().discardEntry (existingProvision);
          +    aSys().discardEntry (unConst(existingProvision));
             }
             
             
          diff --git a/src/lib/del-stash.hpp b/src/lib/del-stash.hpp
          index b05725c94..11dd537c6 100644
          --- a/src/lib/del-stash.hpp
          +++ b/src/lib/del-stash.hpp
          @@ -224,12 +224,14 @@ namespace lib {
                 bool
                 isRegistered (const void* objAddress)
                   {
          +          REQUIRE (objAddress);
                     return killers_.end() != findEntry (objAddress);
                   }
                 
                 Killers::iterator
                 findEntry (const void* obj)
                   {
          +          REQUIRE (obj);
                     return std::find(killers_.begin(),killers_.end(), obj);
                   }
                 
          
          From 7b8f02ef2033e188c46fad6e5b06681e0b5bee96 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Sat, 12 Jun 2010 17:51:55 +0200
          Subject: [PATCH 50/52] change index/solution interface into protected not to
           be used by client code, only by the index
          
          ---
           src/lib/advice.hpp | 14 ++++++++++++--
           1 file changed, 12 insertions(+), 2 deletions(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index d76193a22..f25d95a2e 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -64,6 +64,16 @@
            ** form of advice available, thereby completely decoupling the advised entity from the timings related
            ** to this collaboration.
            ** 
          + ** \par interfaces and implementation
          + ** Client code is assumed to interface solely through the advice::Request and advice::Provision classes,
          + ** which both can be instantiated and copied freely, may be used as member or mixed in as baseclass.
          + ** The AdviceSystem on the other hand is an implementation facility (actually a singleton) and lives
          + ** in the advice.cpp translation unit. The interface entities inherit protected from AdviceLink,
          + ** which is implemented in the same scope as the AdviceSystem and thus allowed to talk to it
          + ** directly. The AdviceSystem in turn uses advice::Index to keep track of the collaboration
          + ** partners, which, for this purpose, are handled as type-erased PointOfAdvice elements.
          + ** The latter class contains 4 API functions used by the index to manage solutions. 
          + ** 
            ** @note as of 6/2010 this is an experimental setup and implemented just enough to work out
            **       the interfaces and gain practical usage experiences. Ichthyo expects this collaboration
            **       service to play a central role at various places within proc-layer.
          @@ -203,7 +213,7 @@ namespace advice {
              */
             template
             class Provision
          -    : public AdviceLink
          +    : protected AdviceLink
               {
                 
                 
          @@ -379,7 +389,7 @@ namespace advice {
              */
             template
             class Request
          -    : public AdviceLink
          +    : protected AdviceLink
               {
                 typedef const ActiveProvision AdviceProvision;
                 
          
          From e020601ebd03415ec8511f23cf0f19b5104beaf6 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Sat, 12 Jun 2010 19:06:56 +0200
          Subject: [PATCH 51/52] refactor AdviceSystem access
          
          ---
           src/lib/advice.hpp        |  62 ++++++++++----
           src/lib/advice/advice.cpp | 164 ++++++++++++++++++++++++++------------
           2 files changed, 161 insertions(+), 65 deletions(-)
          
          diff --git a/src/lib/advice.hpp b/src/lib/advice.hpp
          index f25d95a2e..dd6e749eb 100644
          --- a/src/lib/advice.hpp
          +++ b/src/lib/advice.hpp
          @@ -82,9 +82,10 @@
            ** @todo consider to provide variations of the basic behaviour by policy classes
            ** @todo the implementation is generic/defensive, and could be improved and optimised
            ** 
          - ** @see configrules.hpp
          - ** @see typed-lookup.cpp corresponding implementation
          - ** @see typed-id-test.cpp
          + ** @see AdviceBasics_test usage example
          + ** @see advice.cpp implementation
          + ** @see advice::Index index datastructure
          + ** @see binding.hpp
            ** 
            */
           
          @@ -110,7 +111,17 @@ namespace advice {
             
             
             /**
          -   * TODO type comment
          +   * Basic (abstracted) view of an advice collaboration partner,
          +   * as used internally by the AdviceSystem to manage the participants.
          +   * Each PointOfAdvice is characterised by a binding pattern, used to
          +   * pair up advice::Request and advice::Provision entries. Moreover,
          +   * each PointOfAdvice can refer to an existing advice solution 
          +   * provided elsewhere in the system. The specific type of advice
          +   * (and thus the storage requirements) are abstracted away,
          +   * as is the distinction between Request and Provision.
          +   * 
          +   * @see AdviceSystem
          +   * @see AdviceIndex_test
              */
             class PointOfAdvice
               {
          @@ -187,7 +198,7 @@ namespace advice {
                 void deregisterRequest();
                 
                 static void* getBuffer(size_t);
          -      static void  releaseBuffer (const void*, size_t);
          +      static void  releaseBuffer (void*, size_t);
                 
                 typedef void (DeleterFunc)(void*);
                 static void manageAdviceData (PointOfAdvice*, DeleterFunc*);
          @@ -207,9 +218,22 @@ namespace advice {
             
             /**
              * Access point for the advising entity (server).
          -   * TODO type comment
          +   * This is the interface intended for client code to set and provide
          +   * concrete advice information of a specific type AD. Instantiating 
          +   * automatically creates a \em type-guard binding pattern, but client code
          +   * can (and typically should) provide additional predicates to define the
          +   * "topic" this advice belongs to. This allows advice::Request entries
          +   * to attach to the suitable advice "channels" and get the specific
          +   * piece of advice they're looking for.
              * 
          -   * @todo currently leaking buffer storage for all the advice data which isn't explicitly retracted.
          +   * Any advice::Provision remains inactive and thus invisible, until
          +   * \link #setAdvice setting the concrete advice data \endlink. After that,
          +   * the provided data is \em copied into the AdviceSystem and remains available
          +   * even after the original Provision goes out of scope. Consequently, it isn't
          +   * possible to \em modify advice data once set. But client code may retract
          +   * the provision or change the binding pattern.
          +   * 
          +   * @see AdviceBasics_test usage example
              */
             template
             class Provision
          @@ -219,11 +243,7 @@ namespace advice {
                 
                 /* == policy definitions == */    ////TODO: extract into policy classes
                 
          -      void
          -      deregistrate()
          -        {
          -          TODO ("hand-over deallocation information to the AdviceSystem");
          -        }
          +      void deregistrate() { /* NOP */ }
                 
                 
               public:
          @@ -318,7 +338,7 @@ namespace advice {
             
             /*  ==== memory management for Provision data ===== */
             
          -  /** function to copy advice into an internal buffer.
          +  /** @internal function to copy advice into an internal buffer.
                 @return type erased pointer to the data holder created
                 @throw  error::Fatal on allocation problems, plus anything
                         the advice data may throw during copy construction. */
          @@ -385,7 +405,21 @@ namespace advice {
             
             /**
              * Access point for the advised entity (client).
          -   * TODO type comment
          +   * This is the interface intended for client code to request advice
          +   * of a specific type and optionally limited to a special topic (binding).
          +   * Instantiating an \c Request object automatically entails a registration
          +   * with the AdviceSystem behind the scenes, and deleting it causes deregistration.
          +   * Request objects may be instantiated and copied freely, and the binding pattern
          +   * may be changed. The actual advice is accessed through the member function
          +   * #getAdvice, which might return a default-constructed piece of advice data
          +   * in case no specific advice has been provided yet. Accessing advice can be
          +   * considered a lightweight operation, while creating/destroying advice
          +   * causes an index operation and thus requires a lock.
          +   * 
          +   * Creating an Request and changing the binding might fail, while the dtor
          +   * is protected against failure (as you'd expect). Accessing advice can also
          +   * be considered safe, given the concrete advice type can be default constructed
          +   * without failure in case there isn't any advice data provided yet.
              */
             template
             class Request
          diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
          index a0e6e33ed..2caff7121 100644
          --- a/src/lib/advice/advice.cpp
          +++ b/src/lib/advice/advice.cpp
          @@ -71,8 +71,7 @@
            ** If we ever happen to get a significant amount of advice data, but only a small
            ** number of different advice types, we should reconsider this optimisation.
            ** 
          - ** @todo currently this is unimplemented and we happily leak memory....
          - ** @todo rewrite the allocation to use Lumiera's MPool instead of heap allocations
          + ** @todo rewrite the allocation to use Lumiera's MPool instead of heap allocations    //////TICKET #609
            ** 
            ** \par synchronisation
            ** While the frontend objects are deliberately \em not threadsafe, the lookup implementation
          @@ -104,20 +103,28 @@ using util::unConst;
           
           typedef void (DeleterFunc)(void*);
           
          +
           namespace lib {
           namespace advice {
             
             namespace { // ======= implementation of the AdviceSystem ============
               
          +    /** 
          +     * the system-wide service to support the implementation
          +     * of \em advice collaborations. Manages storage for 
          +     * provided advice data and maintains an index table
          +     * to determine the advice solutions on request. 
          +     */
               class AdviceSystem
          -      : public Index
          -      , boost::noncopyable
          +      : boost::noncopyable
                 {
                   
                   DelStash adviceDataRegistry_;
          +        Index index_;
                   
                 public:
                   AdviceSystem()
          +          : index_()
                     {
                       INFO (library, "Initialising Advice Index tables.");
                     }
          @@ -126,21 +133,92 @@ namespace advice {
                     {
                       INFO (library, "Shutting down Advice system.");
                     }
          -       
          -       void
          -       manageAdviceData (PointOfAdvice* entry, DeleterFunc* how_to_delete)
          -         {
          -           adviceDataRegistry_.manage (entry, how_to_delete);
          -         }
          -       
          -       void
          -       discardEntry (PointOfAdvice* storedProvision)
          -         {
          -           if (storedProvision)
          -             {
          -               adviceDataRegistry_.kill (storedProvision);
          -             }
          -         }
          +        
          +        
          +        
          +        /* == Advice data storage management == */
          +        
          +        /** low-level allocation of storage to hold advice data
          +         *  @todo rewrite to use Lumiera's block allocator / memory pool      /////////////////////////////////TICKET #609
          +         */ 
          +        void*
          +        allocateBuffer(size_t siz)
          +          {
          +            try { return new char[siz]; }
          +            
          +            catch(std::bad_alloc&)
          +              {
          +                throw error::Fatal("Unable to store Advice due to memory exhaustion");
          +              }
          +          }
          +        
          +        void
          +        releaseBuffer (void* buff, size_t)                                   /////////////////////////////////TICKET #609
          +          { 
          +            delete[] (char*)buff; 
          +          }
          +        
          +        void
          +        manageAdviceData (PointOfAdvice* entry, DeleterFunc* how_to_delete)
          +          {
          +            adviceDataRegistry_.manage (entry, how_to_delete);
          +          }
          +        
          +        void
          +        discardEntry (PointOfAdvice* storedProvision)
          +          {
          +            if (storedProvision)
          +              {
          +                adviceDataRegistry_.kill (storedProvision);
          +          }   }
          +        
          +        
          +        
          +        /* == forward additions and retractions to the index == */
          +        
          +        void
          +        publishRequestBindingChange(PointOfAdvice & req,
          +                                    HashVal previous_bindingKey)
          +          {
          +            index_.modifyRequest(previous_bindingKey, req);
          +          }
          +        
          +        void
          +        registerRequest(PointOfAdvice & req)
          +          {
          +            index_.addRequest (req);
          +          }
          +        
          +        void
          +        deregisterRequest(PointOfAdvice const& req)
          +          {
          +            index_.removeRequest (req);
          +          }
          +        
          +        
          +        void
          +        publishProvision (PointOfAdvice* newProvision, const PointOfAdvice* previousProvision)
          +          {
          +            if (!previousProvision && newProvision)
          +              index_.addProvision (*newProvision);
          +            else
          +            if (previousProvision && newProvision)
          +              index_.modifyProvision (*previousProvision, *newProvision);
          +            else
          +            if (previousProvision && !newProvision)
          +              index_.removeProvision (*previousProvision);
          +            
          +            discardEntry (unConst(previousProvision));
          +          }
          +        
          +        void
          +        discardSolutions (const PointOfAdvice* existingProvision)
          +          {
          +            if (existingProvision)
          +              index_.removeProvision (*existingProvision);
          +            
          +            discardEntry (unConst(existingProvision));
          +          }
                 };
               
               
          @@ -159,28 +237,24 @@ namespace advice {
             
             
             /** allocate raw storage for a buffer holding the actual piece of advice.
          -      We need to manage this internally, as the original advice::Provision
          -      may go out of scope, while the advice information as such remains valid.
          -      @note the special twist is the size of the buffer depending on the actual
          -            advice type, which type information we need to erase for tracking all
          -            advice provisions and requests through an generic index datastructure.
          -      @todo rewrite to use Lumiera's block allocator / memory pool */
          +   *  We need to manage this internally, as the original advice::Provision
          +   *  may go out of scope, while the advice information as such remains valid.
          +   *  @note the special twist is the size of the buffer depending on the actual
          +   *        advice type, which type information we need to erase for tracking all
          +   *        advice provisions and requests through an generic index datastructure.
          +   *  @throws error::Fatal on allocation failure
          +   */
             void*
             AdviceLink::getBuffer(size_t siz)
             {
          -    try { return new char[siz]; }
          -    
          -    catch(std::bad_alloc&)
          -      {
          -        throw error::Fatal("Unable to store Advice due to memory exhaustion");
          -      }
          +    return aSys().allocateBuffer(siz);
             }
             
             
             void
          -  AdviceLink::releaseBuffer (const void* buff, size_t)
          +  AdviceLink::releaseBuffer (void* buff, size_t siz)
             { 
          -    delete[] (char*)buff; 
          +    aSys().releaseBuffer(buff, siz);
             }
             
             
          @@ -196,7 +270,7 @@ namespace advice {
             {
               aSys().manageAdviceData (entry,how_to_delete);
             }
          -
          +  
             
             
             
          @@ -218,16 +292,7 @@ namespace advice {
               const PointOfAdvice* previousProvision (getSolution());
               this->setSolution (newProvision);
               
          -    if (!previousProvision && newProvision)
          -      aSys().addProvision (*newProvision);
          -    else
          -    if (previousProvision && newProvision)
          -      aSys().modifyProvision (*previousProvision, *newProvision);
          -    else
          -    if (previousProvision && !newProvision)
          -      aSys().removeProvision (*previousProvision);
          -    
          -    aSys().discardEntry (unConst(previousProvision));
          +    aSys().publishProvision (newProvision, previousProvision);
             }
             
             
          @@ -244,31 +309,28 @@ namespace advice {
             {
               const PointOfAdvice* existingProvision (getSolution());
               this->setSolution ( NULL );
          -    if (existingProvision)
          -      aSys().removeProvision (*existingProvision);
          -    
          -    aSys().discardEntry (unConst(existingProvision));
          +    aSys().discardSolutions (existingProvision);
             }
             
             
             void
             AdviceLink::publishRequestBindingChange(HashVal previous_bindingKey)
             {
          -    aSys().modifyRequest(previous_bindingKey, *this);
          +    aSys().publishRequestBindingChange (*this, previous_bindingKey);
             }
             
             
             void
             AdviceLink::registerRequest()
             {
          -    aSys().addRequest (*this);
          +    aSys().registerRequest (*this);
             }
             
             
             void
             AdviceLink::deregisterRequest()
             {
          -    aSys().removeRequest (*this);
          +    aSys().deregisterRequest (*this);
             }
             
             
          
          From 2debae62e0d1dfc47e08a141106f6075a08658d0 Mon Sep 17 00:00:00 2001
          From: Ichthyostega 
          Date: Sat, 12 Jun 2010 19:32:25 +0200
          Subject: [PATCH 52/52] add locking to protect the advice index table mutations
           clearly, this locking is quite global, and this couldb be improved by using a
           more elaborate index structure
          
          ---
           src/lib/advice/advice.cpp | 34 +++++++++++++++++++++++++++++++---
           1 file changed, 31 insertions(+), 3 deletions(-)
          
          diff --git a/src/lib/advice/advice.cpp b/src/lib/advice/advice.cpp
          index 2caff7121..cbd70e764 100644
          --- a/src/lib/advice/advice.cpp
          +++ b/src/lib/advice/advice.cpp
          @@ -89,15 +89,19 @@
            */
           
           
          +#include "lib/error.hpp"
           #include "lib/advice.hpp"
           #include "lib/advice/index.hpp"
           #include "lib/del-stash.hpp"
           #include "lib/singleton.hpp"
          +#include "lib/symbol.hpp"
          +#include "lib/sync.hpp"
           #include "lib/util.hpp"
           #include "include/logging.h"
           
           #include 
           
          +using lib::Symbol;
           using lib::Singleton;
           using util::unConst;
           
          @@ -116,7 +120,8 @@ namespace advice {
                * to determine the advice solutions on request. 
                */
               class AdviceSystem
          -      : boost::noncopyable
          +      : public lib::Sync<>
          +      , boost::noncopyable
                 {
                   
                   DelStash adviceDataRegistry_;
          @@ -140,6 +145,10 @@ namespace advice {
                   
                   /** low-level allocation of storage to hold advice data
                    *  @todo rewrite to use Lumiera's block allocator / memory pool      /////////////////////////////////TICKET #609
          +         *  @warning the raw allocation and deallocation is \em not protected
          +         *           by the  AdviceSystem monitor. Currently we don't need
          +         *           locking (heap allocation), but any custom allocator
          +         *           will have to care for its own locking!
                    */ 
                   void*
                   allocateBuffer(size_t siz)
          @@ -161,11 +170,13 @@ namespace advice {
                   void
                   manageAdviceData (PointOfAdvice* entry, DeleterFunc* how_to_delete)
                     {
          +            Lock sync (this);
                       adviceDataRegistry_.manage (entry, how_to_delete);
                     }
                   
          +      private:
                   void
          -        discardEntry (PointOfAdvice* storedProvision)
          +        discardEntry (PointOfAdvice* storedProvision)  ///< @note to be invoked from a locked scope
                     {
                       if (storedProvision)
                         {
          @@ -174,31 +185,46 @@ namespace advice {
                   
                   
                   
          +      public:
                   /* == forward additions and retractions to the index == */
                   
                   void
                   publishRequestBindingChange(PointOfAdvice & req,
                                               HashVal previous_bindingKey)
                     {
          +            Lock sync (this);
                       index_.modifyRequest(previous_bindingKey, req);
                     }
                   
                   void
                   registerRequest(PointOfAdvice & req)
                     {
          +            Lock sync (this);
                       index_.addRequest (req);
                     }
                   
                   void
                   deregisterRequest(PointOfAdvice const& req)
                     {
          -            index_.removeRequest (req);
          +            try
          +              {
          +                Lock sync (this);
          +                index_.removeRequest (req);
          +              }
          +            
          +            catch(...)
          +              {
          +                Symbol errID = lumiera_error();
          +                WARN (library, "Problems on deregistration of advice request: %s", errID.c());
          +              }
                     }
                   
                   
                   void
                   publishProvision (PointOfAdvice* newProvision, const PointOfAdvice* previousProvision)
                     {
          +            Lock sync (this);
          +            
                       if (!previousProvision && newProvision)
                         index_.addProvision (*newProvision);
                       else
          @@ -214,6 +240,8 @@ namespace advice {
                   void
                   discardSolutions (const PointOfAdvice* existingProvision)
                     {
          +            Lock sync (this);
          +            
                       if (existingProvision)
                         index_.removeProvision (*existingProvision);