Invocation: provide access to a deduplicated ProcID

...as follow-up to yesterday's decisions
 - each Port will just feature a (stable) reference to a ProcID record
 - which is deduplicated and likewise refers to deduplicated symbolic tags
 - and further spec and hash values are computed on-demand by this entity

__Note__: all functionality belonging to the ''Builder'' can be assumed to run **non-concurrent**
This commit is contained in:
Fischlurch 2024-11-03 21:03:34 +01:00
parent f8642b3459
commit 4b6d812578
6 changed files with 122 additions and 104 deletions

View file

@ -109,7 +109,7 @@ namespace lib {
* This function is intended to be picked up by ADL, and should be usable
* both with `std::hash` and `<boost/functional/hash.hpp>`. It is implemented
* similar as the boost::hash specialisation for std::string */
size_t
HashVal
hash_value (Literal literal)
{
size_t hash=0;
@ -125,7 +125,7 @@ namespace lib {
}
/** hash value for Symbols is directly based on the symbol table entry */
size_t
HashVal
hash_value (Symbol sym)
{
return sym? boost::hash_value (sym.c())

View file

@ -60,7 +60,7 @@
namespace lib {
using std::string;
using std::forward;
using std::move;
/**
@ -81,7 +81,7 @@ namespace lib {
internedString (string && symbolString)
{
Lock sync{this};
auto res = table_.insert (forward<string> (symbolString));
auto res = table_.insert (move (symbolString));
return res.first->c_str();
}
};

View file

@ -179,8 +179,8 @@ namespace lib {
/* ===== to be picked up by ADL ===== */
size_t hash_value (Literal);
size_t hash_value (Symbol);
HashVal hash_value (Literal);
HashVal hash_value (Symbol);
/* === equality comparisons === */

View file

@ -33,30 +33,47 @@
**
** @see turnout.hpp
** @see engine::ProcNodeDiagnostic
** @see proc-node.cpp for the implementation backend
*/
#ifndef ENGINE_PROC_ID_H
#define ENGINE_PROC_ID_H
#include "lib/hash-standard.hpp"
#include "lib/error.hpp"
#include "lib/hash-value.h"
//#include "steam/streamtype.hpp"
#include <string>
namespace steam {
namespace engine {
namespace err = lumiera::error;
using lib::HashVal;
using std::string;
class ProcID
{
public:
/** build and register a processing ID descriptor */
static ProcID& describe();
/* === symbolic descriptors === */
string
genProcSpec()
{
return "Lalü";
}
friend bool operator== (ProcID const& l, ProcID const& r) { return true; }
};
HashVal hash_value (ProcID const&);
}} // namespace steam::engine
#endif /*ENGINE_PROC_ID_H*/

View file

@ -30,13 +30,19 @@
#include "steam/engine/proc-id.hpp"
#include "steam/engine/proc-node.hpp"
#include "lib/format-string.hpp"
#include "lib/util.hpp"
#include <unordered_set>
namespace steam {
namespace engine {
using util::unConst;
namespace { // Details...
std::unordered_set<ProcID> procRegistry;
} // (END) Details...
@ -46,14 +52,31 @@ namespace engine {
Port::~Port() { } ///< @remark VTables for the Port-Turnout hierarchy emitted from \ref proc-node.cpp
/**
* @remark this is the only public access point to ProcID entries,
* which are automatically deduplicated and managed in a common registry
* and retained until end of the Lumiera process (never deleted).
*/
ProcID&
ProcID::describe()
{
UNIMPLEMENTED ("establish and possibly enrol new processing descriptor");
auto res = procRegistry.emplace ();
return unConst (*res.first);
}
/** @internal */
/** generate registry hash value based on the distinct data in ProcID.
* This function is intended to be picked up by ADL, and should be usable
* both with `std::hash` and `<boost/functional/hash.hpp>`.
*/
HashVal
hash_value (ProcID const& procID)
{
return 47; //UNIMPLEMENTED ("ProcID hash");
}
string
ProcNodeDiagnostic::getNodeSpec()
{
@ -66,10 +89,16 @@ namespace engine {
UNIMPLEMENTED ("calculate an unique hash-key to designate this node");
}
/**
* @return symbolic string with format `NodeSymb[.portQualifier](inType[/#][,inType[/#]])(outType[/#][,outType[/#]][ >N])`
* @remark information presented here is passed-through from builder Level-3, based on semantic markup present there
*/
string
ProcNodeDiagnostic::getPortSpec (uint portIdx)
{
UNIMPLEMENTED ("generate a descriptive diagnostic Spec for the designated Turnout");
auto& p{n_.wiring_.ports};
return p.size() < portIdx? util::FAILURE_INDICATOR
: p[portIdx].procID.genProcSpec();
}
HashVal

View file

@ -13507,9 +13507,7 @@
<node CREATED="1519437341366" FOLDED="true" ID="ID_1400629217" MODIFIED="1561827469154" TEXT="Alternativen">
<node CREATED="1519437362523" ID="ID_1967120024" MODIFIED="1519440122737" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
auto locate = matchView(
@ -13526,9 +13524,7 @@
</node>
<node CREATED="1519437509655" ID="ID_241024117" MODIFIED="1519442360056" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
LocatorSpec&lt;UIC_VIEW&gt; locate = panel(&quot;blah&quot;)
@ -13542,9 +13538,7 @@
</node>
<node CREATED="1519437756333" ID="ID_565391583" MODIFIED="1519440134474" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
ViewSpec locate = panel(&quot;blah&quot;)
@ -14149,9 +14143,7 @@
<node CREATED="1515803834302" ID="ID_1965813896" MODIFIED="1518487921070" TEXT="&#xfc;berhaupt nicht auf DSL-Ebene"/>
<node CREATED="1515803844276" ID="ID_512581752" MODIFIED="1518487921070">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
nur &quot;hinten herum&quot; &#252;ber die verwendete <b>LocationQuery</b>
@ -14339,9 +14331,7 @@
<node CREATED="1515725719930" ID="ID_746038986" MODIFIED="1515725729012" TEXT="Aber man bekommt komplexere AlocSpec-Typen"/>
<node CREATED="1515726089841" ID="ID_527144420" MODIFIED="1576282358115" TEXT="der harte (technische) Teil ist bereits implementiert...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
n&#228;mlich in lib::meta::func::PApply::bindBack
@ -14409,9 +14399,7 @@
</node>
<node CREATED="1515732383331" ID="ID_1688687565" MODIFIED="1515797049652">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
Vermutung: mu&#223; Lambda <b>instantiieren</b>...
@ -15546,9 +15534,7 @@
<node CREATED="1504832179925" ID="ID_878950103" MODIFIED="1518487921073" TEXT="w&#xe4;re akzeptabel"/>
<node CREATED="1504831934790" ID="ID_1800843653" MODIFIED="1576282358110" TEXT="aber etwas &#xfc;bertrieben...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...es ist im Rahmen;
@ -15579,9 +15565,7 @@
<icon BUILTIN="button_ok"/>
<node CREATED="1504832394952" ID="ID_85672659" MODIFIED="1518487921073">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
wir brauchen keine <i>Token</i>
@ -15654,9 +15638,7 @@
<node CREATED="1504886051389" ID="ID_1177567162" MODIFIED="1518487921073" TEXT="Tupel {Fenster, Perspektive, Panel, Gruppe, Pfad}"/>
<node CREATED="1504886084393" ID="ID_28488269" MODIFIED="1576282358109" TEXT="optionale Komponenten">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...wir brauchen eine Repr&#228;sentation,
@ -15776,9 +15758,7 @@
<node CREATED="1504833174961" ID="ID_1294462811" MODIFIED="1518487921074" TEXT="im Timeline-Panel der Gruppe hinzuf&#xfc;gen"/>
<node CREATED="1504882791007" ID="ID_1520721786" MODIFIED="1518487921074">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
alloc = unlimited
@ -15794,9 +15774,7 @@
<node CREATED="1504834559240" ID="ID_423545167" MODIFIED="1518487921074" TEXT="nur ein einziger(global)"/>
<node CREATED="1504883102734" ID="ID_81147050" MODIFIED="1518487921074">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
alloc = onlyOne
@ -15948,9 +15926,7 @@
<node CREATED="1504882560202" ID="ID_1190541919" MODIFIED="1518487921075" TEXT="egal, wenn beide Seiten der Zuweisung DSL sind"/>
<node CREATED="1504882584218" ID="ID_790570102" MODIFIED="1518487921075">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
was hier <i>vielleicht</i>&#160;der Fall sein k&#246;nnte
@ -15986,9 +15962,7 @@
<node CREATED="1517970403323" ID="ID_676104700" MODIFIED="1518487921075" TEXT="...wofern &#xfc;berhaupt m&#xf6;glich"/>
<node CREATED="1517970410690" ID="ID_1716625175" MODIFIED="1576282358109" TEXT="Problem sind die LocationClauses">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
wir haben nicht einfach UI-Coordinaten als DSl-Elemente,
@ -16045,9 +16019,7 @@
</node>
<node CREATED="1523023241752" ID="ID_1541233512" MODIFIED="1523023254890">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
Schicht <i>unter</i>&#160;dem ViewLocator
@ -18297,9 +18269,7 @@
<icon BUILTIN="button_ok"/>
<node CREATED="1662051084085" ID="ID_906734828" MODIFIED="1664668205361">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<font face="Monospaced">ElementBoxWidget::Config::<b>buildLayoutStrategy</b>(</font><font color="#2d40af" face="Monospaced">ElementBoxWidget</font><font face="Monospaced">&amp;)</font>
@ -18412,9 +18382,7 @@
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#210f69" CREATED="1664548449268" ID="ID_303509395" MODIFIED="1664548735480" TEXT="Design-Prinzipien">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -18460,9 +18428,7 @@
</node>
<node CREATED="1666367000884" ID="ID_1552390941" MODIFIED="1666367099475" TEXT="sieht mehr wie ein &quot;play&quot;-Button aus...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...und das ist vielleicht sogar eine gute Idee: Lumiera k&#246;nnte die M&#246;glichkeit bieten, jedwedes Element eigens f&#252;r sich darzustellen oder zu inspizieren, transient und ohne Seiteneffekte
@ -18482,9 +18448,7 @@
<node CREATED="1663945651910" ID="ID_897434501" MODIFIED="1663945668859" TEXT="Kind-Elemente ggfs verbergen"/>
<node CREATED="1663945669814" ID="ID_1057659827" MODIFIED="1663945692748">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
ver&#228;nderte Men&#252;-Steuerung bei derartiger <i>Degradierung</i>
@ -18494,9 +18458,7 @@
</node>
<node CREATED="1663945712608" ID="ID_1162263503" MODIFIED="1663945819361" TEXT="minimal-Ausdehung per API bereitstellen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
das bedeutet: es ist Aufgabe eines &#252;bergeordneten Layout-Managers, dann auch ein <i>reduziertes Display</i>&#160;zu schalten; das ElementBoxWidget kann davon ausgehen, den minimal ben&#246;tigten Platz auch zu bekommen (size request)
@ -18517,9 +18479,7 @@
</node>
<node CREATED="1664486499547" ID="ID_1517909946" MODIFIED="1664486599158" TEXT="CSS mu&#xdf; daf&#xfc;r sorgen, da&#xdf; dem nichts hinzugef&#xfc;gt wird">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
im Besonderen keine Border!
@ -18581,9 +18541,7 @@
<node CREATED="1664494602946" ID="ID_1093994466" MODIFIED="1664494618443" TEXT="zum &quot;mapping&quot; des Widgets wird die size-Allocation ermittelt"/>
<node CREATED="1664494619248" ID="ID_1432947442" MODIFIED="1664494782463" TEXT="hierf&#xfc;r gibt es nur wenige Standard-Implementierungen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -18622,9 +18580,7 @@
<node CREATED="1664027980946" ID="ID_1814840612" MODIFIED="1664028017505" TEXT="diese sind aber nur notwendig, falls constrained extension gew&#xfc;nscht"/>
<node CREATED="1664028024900" ID="ID_1409117153" MODIFIED="1664028235700" TEXT="dieses komplexe API k&#xf6;nnte durch die ctor-DSL verst&#xe4;ndlich gemacht werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...insofern dann die Beschr&#228;nkung der Ausdehnung einzig dadurch aktiviert werden kann, da&#223; man ein geeignetes Verb angibt, welches diese beiden Lambda als Argument nimmt
@ -18634,9 +18590,7 @@
</node>
<node CREATED="1664028265740" ID="ID_414167652" MODIFIED="1664028312456" TEXT="der Zugriff erfolgt nat&#xfc;rlich, transparent und on-demand">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...und ich mu&#223; die Frage, wann genau diese Info bezogen wird, &#252;berhaupt nicht kl&#228;ren
@ -18646,9 +18600,7 @@
</node>
<node CREATED="1664028318861" ID="ID_1910143460" MODIFIED="1664028491553" TEXT="jede Metrik-&#xc4;nderung mu&#xdf; dem Widget &#xfc;ber ein separates API eigens gePUSHt werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
wobei letztlich nur ein queue_resize erfolgen mu&#223;; es k&#246;nnte also sein, da&#223; daf&#252;r der Aufruf einer bestehenden GTK-Funktion gen&#252;gt
@ -47548,9 +47500,7 @@
</node>
<node CREATED="1455842653928" ID="ID_1996966445" MODIFIED="1561827465435">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
Diff kennt keine <i>Zuweisung</i>
@ -48134,9 +48084,7 @@
<node CREATED="1455930997303" ID="ID_1710972681" MODIFIED="1455931003962" TEXT="kann erhebliche Gr&#xf6;&#xdf;e haben"/>
<node CREATED="1455931025595" ID="ID_1695885971" MODIFIED="1575133327404" TEXT="ist a priori nicht bekannt">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
stellt sich u.U erst w&#228;hrend der Verarbeitung heraus:
@ -48491,9 +48439,7 @@
</node>
<node CREATED="1456426052973" ID="ID_239653128" MODIFIED="1456437520772" TEXT="Binde-Daten">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
noch zus&#228;tzlich zur genannten Duplikation mu&#223;
@ -48821,9 +48767,7 @@
</node>
<node CREATED="1475439429055" ID="ID_1383518557" MODIFIED="1575133340899" TEXT="also: embeded Buffer">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...und diesen mit VTable best&#252;cken.
@ -49117,9 +49061,7 @@
<node CREATED="1448691355340" ID="ID_724965495" MODIFIED="1448691465633" TEXT="liefert Record&lt;GenNode&gt;"/>
<node CREATED="1452560897720" ID="ID_1869468443" MODIFIED="1576282358007" TEXT="vorerst noch nicht impl...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
hier geht es darum, eine Regel zu generieren,
@ -78272,8 +78214,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1714778001228" ID="ID_1999491710" MODIFIED="1730598037898" TEXT="wir brauchen einen Cache-Key">
<arrowlink COLOR="#79214c" DESTINATION="ID_968805110" ENDARROW="Default" ENDINCLINATION="271;-5;" ID="Arrow_ID_617691253" STARTARROW="None" STARTINCLINATION="-191;250;"/>
<arrowlink COLOR="#ff461d" DESTINATION="ID_518441567" ENDARROW="Default" ENDINCLINATION="475;-655;" ID="Arrow_ID_743151366" STARTARROW="None" STARTINCLINATION="197;254;"/>
<linktarget COLOR="#5c536b" DESTINATION="ID_1999491710" ENDARROW="Default" ENDINCLINATION="-1732;155;" ID="Arrow_ID_1638495806" SOURCE="ID_631143493" STARTARROW="None" STARTINCLINATION="944;56;"/>
<linktarget COLOR="#553750" DESTINATION="ID_1999491710" ENDARROW="Default" ENDINCLINATION="-708;70;" ID="Arrow_ID_338052928" SOURCE="ID_701755621" STARTARROW="None" STARTINCLINATION="842;41;"/>
<linktarget COLOR="#5c536b" DESTINATION="ID_1999491710" ENDARROW="Default" ENDINCLINATION="-1732;155;" ID="Arrow_ID_1638495806" SOURCE="ID_631143493" STARTARROW="None" STARTINCLINATION="944;56;"/>
<icon BUILTIN="yes"/>
<node CREATED="1714778021562" ID="ID_540563860" MODIFIED="1714778064872" TEXT="dieser ergibt sich systematisch aus den 3 Freiheitsgraden"/>
<node CREATED="1714778069039" ID="ID_532019059" MODIFIED="1714778139405" TEXT="er mu&#xdf; zuverl&#xe4;ssig die Reproduzierbarkeit garantieren"/>
@ -91821,10 +91763,41 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1730598253584" ID="ID_763084379" MODIFIED="1730598384398" TEXT="wird in einer Registry abgelegt">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1730598263877" ID="ID_973341461" MODIFIED="1730598270871" TEXT="vorerst einfach statisch implementieren">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1730598263877" ID="ID_973341461" MODIFIED="1730670933336" TEXT="vorerst einfach statisch implementieren">
<icon BUILTIN="pencil"/>
<node CREATED="1730669112939" ID="ID_887683968" MODIFIED="1730669137232" TEXT="Annahme: keine Concurrency">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1730598272422" ID="ID_74408441" MODIFIED="1730598369786" TEXT="keine Bereinigung vorsehen">
<node CREATED="1730669151003" ID="ID_407516299" MODIFIED="1730669164832" TEXT="das gilt f&#xfc;r Alles im Umfeld des Builders">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1730669183016" ID="ID_551692655" MODIFIED="1730669235308" TEXT="au&#xdf;erdem bleibt es damit ein komplett separates System">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...das nicht die allgemeine Symbol-Tabelle flutet; auch kann man damit sp&#228;ter den tats&#228;chlichen Speicherbedarf besser beurteilen
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1730669238465" ID="ID_645344682" MODIFIED="1730669259203" TEXT="sinnvollerweise auch die Teil-Strings ebenfalls in so eine Symboltabelle legen"/>
<node CREATED="1730669278148" ID="ID_98610288" MODIFIED="1730669343276" TEXT="Implementierung: unordered_set + hash_value(Elm const&amp;)">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
#include &quot;lib/hash-standard.hpp&quot;
</p>
<p>
und auch ansonsten &#228;quivalent zur Implementierung von lib::Symbol
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1730598272422" ID="ID_74408441" MODIFIED="1730669177907" TEXT="keine Bereinigung vorsehen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -93376,8 +93349,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1730596470751" ID="ID_1288148978" LINK="https://issues.lumiera.org/ticket/1377" MODIFIED="1730597727524" TEXT="#1377 processing identification">
<linktarget COLOR="#832b91" DESTINATION="ID_1288148978" ENDARROW="Default" ENDINCLINATION="-2377;191;" ID="Arrow_ID_1024856417" SOURCE="ID_125486682" STARTARROW="None" STARTINCLINATION="-1447;-79;"/>
<linktarget COLOR="#484589" DESTINATION="ID_1288148978" ENDARROW="Default" ENDINCLINATION="-451;-260;" ID="Arrow_ID_79666749" SOURCE="ID_701755621" STARTARROW="None" STARTINCLINATION="-1086;55;"/>
<linktarget COLOR="#832b91" DESTINATION="ID_1288148978" ENDARROW="Default" ENDINCLINATION="-2377;191;" ID="Arrow_ID_1024856417" SOURCE="ID_125486682" STARTARROW="None" STARTINCLINATION="-1447;-79;"/>
<icon BUILTIN="hourglass"/>
<node CREATED="1730597099323" ID="ID_968805110" MODIFIED="1730597155681" TEXT="darauf aufbauend: systematische Cache-Keys">
<linktarget COLOR="#79214c" DESTINATION="ID_968805110" ENDARROW="Default" ENDINCLINATION="271;-5;" ID="Arrow_ID_617691253" SOURCE="ID_1999491710" STARTARROW="None" STARTINCLINATION="-191;250;"/>
@ -133253,8 +133226,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<b>Frame-Cache</b>&#160;(Service)
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1730596329922" ID="ID_1539887198" MODIFIED="1730596340330" TEXT="Schema f&#xfc;r Cache-Keys aufbauen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1730596368051" ID="ID_384763125" LINK="https://issues.lumiera.org/ticket/1223" MODIFIED="1730596382793" TEXT="#1223 Create foundation for precise frame-caching">