From aacafd49b34177d037e6b6a7958780850995d733 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 11 Oct 2009 07:36:02 +0200 Subject: [PATCH 001/377] SCons: switch to combined timestamp/MD5 change detection this setting speeds up "sparse" builds (when e.g. just one file changed). --- SConstruct | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SConstruct b/SConstruct index c2e703031..1f1673f6c 100644 --- a/SConstruct +++ b/SConstruct @@ -60,6 +60,8 @@ def setupBasicEnvironment(): EnsurePythonVersion(2,3) EnsureSConsVersion(0,96,90) + Decider('MD5-timestamp') # detect changed files by timestamp, then do a MD5 + opts = defineCmdlineOptions() env = LumieraEnvironment(options=opts ,toolpath = [TOOLDIR] From 4695f41b7c9c767cb21d83fe17c12abeaa401024 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 12 Oct 2009 08:10:00 +0200 Subject: [PATCH 002/377] Documentation of PlacementScope concept --- doc/devel/draw/Session.ScopeStructure-1.svg | 1621 +++++++++++++++++++ wiki/draw/ScopeStructure1.png | Bin 0 -> 47162 bytes wiki/renderengine.html | 82 +- 3 files changed, 1685 insertions(+), 18 deletions(-) create mode 100644 doc/devel/draw/Session.ScopeStructure-1.svg create mode 100644 wiki/draw/ScopeStructure1.png diff --git a/doc/devel/draw/Session.ScopeStructure-1.svg b/doc/devel/draw/Session.ScopeStructure-1.svg new file mode 100644 index 000000000..98e693597 --- /dev/null +++ b/doc/devel/draw/Session.ScopeStructure-1.svg @@ -0,0 +1,1621 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + Structure of Placement Scopes + + + Ichthyostega + + + design sketch: Relation of the nested Placement Scopes within the Lumiera session + 2009 + + + + + + + + + + + + + + + + + + + + + + + + Clip2 + + Sequence + Timeline-1 + + + Timeline-2 + + + + Clip1 + + Effect + + Effect + + Effect + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + root : global rules + + + + + + + + + + + + + + + + + + + + Binding + global Pipes + global Pipes + + + + + Binding + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + diff --git a/wiki/draw/ScopeStructure1.png b/wiki/draw/ScopeStructure1.png new file mode 100644 index 0000000000000000000000000000000000000000..8498ddb1f88bf62dd0b033fb38c978828c54507c GIT binary patch literal 47162 zcmX_n1z6MH_dnespwgfdL8L`G)gjW-Il>_bjFyH0qI5`uq)O+I?jbT#P^r;K3S*2M z4gWWv@ALcfJSy()eeb#Fyw1I^6Yr>(+N!ivY*YjU1hi@|zLLdyw!KLd+TH4@tVNL z$4A(~#mN(Df7s$TG0~<1{h2BTe>8LWMFSX(${>-M7B9Y zLnjyR+kG#@ZKyRv)-U{5Q-@~d)^p|h<^6`6*K_ZoSW@%?Zuh!B4ArlN(ATR3dq9p_ zV8&1R$1jPdszUS}i=}TK6Yf|x2z+_eLcx-VRewqi~(b=B+T z7-Y1;TvMp@IkLd9f&CGJV8>-Idcs@gx_sOS3YOZqLp}9U=OQQ~MbBIXj3p>@WyrNnE)cc3#G3w7P$WD~Jep2bRg$q0ax3weM(CkJf@-o~(@`g`ga~Vrk8?^LU4M=PINN zxs1x_oxy79t7GdQcj>7+SBls8bhOh2GQS})L-cD9{vtRIwIZGi83_>~02iPGI@nAe zfFKCUk(<@Cr0A7(2<-d*ZMRHgxQ;cW8_f8S_h@S3QXR!Y!hL}E`Ix-5m; zh-R2lNw&N3B<->7@=|7CGNQ;nXY_n&ip2a;6q>8dD}+Ellw(mz*%c;Yz}UnsO*kWv zMyM)WQYAwPii{^0-Kl-E-Qjd&7bJaE0 z^jk|U@4spzx1)Pg1K+PaHo^U==rS?0Cf-!u+S981?)o5tk@R zlZ-cD2Hr9C*=lBMmo~G39eSCG-}ki+3?FTNh+SuXwDmPbZ$^truy9OxJ+8;!E=KNQ z;h2khuQjlSo_f7F;4^xFZ%k(b3cmgbt9d;nE0|ak+*cwaL)-CEZL($93*;r_G+E_r z+2m#uBgUJFJ>@Sn;Qe&{&Frx1Q`AmJ(5Y46-|Ext^mLy^MZe~g6A34$iSbEi3)H}^ zegA`hN5@foxlR7x-&4|ldILNLx?Y$wJo5OtY&zU^tRz`PK40gm>a+C&sV(~VflK?W znj>kx=g5{K)bfJgQI4*L(#cliJ=L^!J`g5WY!@~O;V=B-@Si_}!P*zQUJ1D#vueG! z*4KQ5Bf)#0pi#f3r>6-*bOH}H=7pwYIv>F2rG^z@6PKR2tnpjGfS@;ipR;A(ec2IM% zQFDhsf!k=ii2mEJ3H-^1$INB5R=1`FRCnffUjEaz6SU~7^V=_Q(p}F^PLQi{JzjKa zTwi&+X=G-`HiY+kP-qZ+?FSW@#*vP7y3Nku^mi|`EuZj6tsI@~oPBsbK7N4x9hSeK z^9y&6k>cYE-l>;XI>_~8?UR$lFfw{YG>iXpP~wY*k!Spcde_It>(t0&Dr%~unBy?N z=FhVqbx1mOc486=$H(6aKd{!)qBYDLUhXK)<5l8|fYK|FbW$|`%|;TQ(LX4qY~X-t zT530pr~q@lrAgC!SRPKp%GlT6KP9zD{r-EGHInb0&ifV=ndI1{xZi}JT_B$I>~K?U zYUl5{+YpNfNT!Y_DN=c)N`c5vA%>n-$iY_y{DTGhEl3+cB4Ce)57FX)Q{2M#@6Nj@kSfzFEKj zDN9Q;pc+8thyN7q=y)n`*;oTt(*QA8)dl+Pal4+gcP@-1jhAnXwzI22k5yN*+7w?? zMHSq2pjj&y$!Ogf{q)^`AwoumeX}-5Se-xh8d?v_?M8BQOd4UU1@{Gv9veobcK zy@x7*GaDGOLKzjLJ`JcP^J;GyWGsx8YcTJ(M{uvTZ;bl6p7NcaHm^%#`|h#2@7x8{ zY?+kGV?&c%98~AHF-F>%&_gudViB)bcJKF-Z2(W^%^t6FsvG`p`?PAY1)gPS;LYn` zueXy71%ec0ebzo+;Gv6(XTOqOSkv&tVY|%g-l|;`_$&kn|3Mb0=`WNG;$;AA%3iy4 ztA$kAzMPPW_ft>lZzJhvT*n2aWo1fRh|$|3{;q5Ek`q;(`>~@P?&#kUG{gLT{nRHt zd_t71L-~YkSy{_CxU@qLITN1}yXEw8M0kpLA!P&6A)!tU#CQb8bR(EcE5i!Jb^0tuLu+6)wH$7=qLIj&C)FSDV|yn4|V=}((6-ndK{h? z>;e0I`pFeHiun6oSw1b@U-2*fk4>uR?KxkQyjEsJuxHVvPOio82cW^zLw3WtQl`Z7 zwO>QoC|(Db{(Q)K&IXz{NNU^@g(XcA-o@a!OriOLUMMRgOQ_<-sb2k06$TcIm zrDuzA*KD-j^Ubn8|DnY1vVrAL^H9%_gpi1kbpiFkw_>jWrKnGb6{dj93|Yy9yW*?a zh+>JK8>OUONR{6LOf;7QXad{w#V}PNlsyDTKqOCd&q7O)`kim!QgSTJTzXA|PKC1Cv9s3zr`5B_N(uz)y&|=Z`R^e+e)5;7z zbu8(Bs)&@DIn6{5hVT))5-}59RXq?IodB2u76c%qo;=dX@HT<*tAGlB!Ycxo(g#9W zSwH;&x#raY+<8L*eGrC(AnZD4ZxF1%43;cdcB z;!9n?8Xy1n^j%=`F<}7I2ZZ)ergB|mXQ(TY>n02XXxsi55Q9K?%nVHc3$sl#IF5X-SYnp19Itf0sEm{R9K{1T#f$o z&GtWqIu?%tlY0Xw86p(!6>e!$+Ij5etKu-l_n#?CA=l=Zeo|NVjoyvPP3RZRIiYXe zm%0ks|8$ai>w0oxK%@6+e28=D17kUzB&vYn`~Mp@ydI7NhVR~q)~X068X@il%n|gz zJ#UHv{J~KG5WJOel30r1$)ea|8z5NW|5m0`wf8V~q`t;jO}k+_0W~5ILV+4!a!bH>#QtY%^FLgI^^?&?hEy-ZbDS?8Tg!WAk2}fE zv;ct{=V!{aX$&y)K4NfUmgs;qmxQhoFh}bDEC~fLh-U-v+kvhzTp-&797M?om|60F zGxq`kC3Y9sRj&<>OrH5z#9O%h+TWM{w`+woUK7Uzz#KHh%m5C;LaD65fHhSAH`@O0 zdK7@*R#(x~1gY;$x#02W|LxaOrP$#g0Y`75QLf9#x~!uq)(EaO75RDh%Q-TmW z8YSsO+v%ccR*M^oCtdf00s|GQoICOgoF~zR26pTrjFVoC4zt_wmLLu?7>Nt)brxZC zs2n1+qMp8`%kullu-!;uz|E$r)X745igTrEuFBLa{Y6(~I_p3uT?U2@m2T*(OhW z{ov{hE%T-9QA%*!(R8r=gDZAr*F_!H0VPIh)?>r)y#PWbA{U~_!%Z_2CEL#5{j+_q zBUjEaY?p=y!>Zl)6VL6!_qrrWhFuD`#uTfG>|d8Cp*y>|iN{$7uI`J{Wu$#Rp9zsc z20uzsVtYVxnf;lLkLX@Vt9VMM628_uD148)CNFINQ40MIo#?}7C(a7<)9Z{?81IxQ z^MtNT;mek({ZiR6W&yw3nPP&hJboohbCEpf7ly46F&zMx4jRd&k|3$65V09wh7vaYiKR^13oMO+o;vbdf$ ze))i)$^+8)Xf%eicj{luwz)H`+7sdv$Ufr~8dZgvutQtY2ClShx6#au5ZEkP z^npt)F8bkEOsGs1MtB$zM7z_BX%T+}v!WDqhcu4+6>#**kWe&L$?lC3^rH4b28=0@tm!%o3!!Rv4+p=utvqyNm zOuT*`zl-0DQ^-}ru2cUPfoo^C{O8U_zUn&#y{I6`k&RSN5PjXx2F03c?<9 z{-j;nG4FOl6aF~=T-ZvxRD$*Egq%t?T+x}2Xu`E-YH(AM4bE}b;_fSXYv6vzcSO)z zN5E|NnDZ+gJTA2{Qpp8v&u8*_=$uq>pf;|id9S(8SmQ!GfR0*azalY{skOMSQ^2Zn zr>Y&J(((H@cD`U*n7k*%fE|8CB)`ig)+B;cx0&dgrM2DZg^NqYDo{@m0>Cw{q&V#pJ66fsq$!OMAZ^jCT~6?h_e$Q$x#igv!+GxT#6 zCe6N8I1^awE`ED~Q?0>=4Y+m4s@_75PKCDHVz9L76xDXUW;Sv&54SkqaZcsb&BZiA z0C^a;AmA%VYZ_X)xPKoBdK$5^Dta_bY0Ew-pFP(tD0k|7;0rF(^`T(UNMmyZPq-TlG zY1%CSI8B2K&2|3R+v$^aX%4{WP2c6*zv8{aEEjX80${{>&amK`t1$qK2>Z~?&`-3X z(UAth(rVDh^xyD6#r3c*Ff1o%X1LK^rQt2$Ez~L%;t5cPN5YB!J>3rs&j?-9M2Iaw z6QRsZ9iIV450}IMfLDKQ9`OPJ=Aqz;6?6W%)>8TUv}W|>50xL}$8lm<#q`nn2WE!N zN|L25RC3fE)aUiUld5))j2#>Afo!0f=H)yvolL8qXAG1CD3;OR>o4`yo$ZSGOhAu_ zTC)-Yua_2Iq@<#Di<+y*W3PkM)@_oHa_Hg3I< z=%Or^HKDXgUg283GO*9IWo9je_S~F|f9=Bp&@_(4M~kM zE=IZ7VKl@u(&s+2R|VyOcF+!_lS-11ktr9o<(6(&Gn-MD^VTd4xx{@q%uFJl>R9 zGi(Tf5~BJdKzmFK8{5vZ9C8xK2uqz&J|sQ(hX^Q`InjgRr1nU*xAlF-!+muIKYg$z zLt^rbbTwb7Q`_kzA$P;b%(xi9M~|Y63@;hk{|(j*qPNU-&Aj7yjU7eYc_g(t;~?37 z?MJ>=`Fst(kF&+rAPmjw;9Q18?x;R;&>kW(C9)3-+Utm%6#?bwlg9Mbfc8Wf{B*#= zOo@ob4RG}=eFzuQc99SCEsr_bWp`=G9OR*H=I00UXpGdv$16POmXRPnB6=1lmJ@P@ zP@6rP!9w)a30w2Y2ifIb3V;~y#B!R8^3_AY+a&6t!)U)`?OwcpPkZ%pCh%S`H!Oe85fWU0IA9b8E=%2yYh+bb-YebA7{3u0!6 zTE1CrQzTQoofv?4;*{`07J$_~L^`1eL6J>B6$*&XHjX9gjdxK-5;1-5%7mihEc(=U zKt!_{4QDzCDSwMt$k|)z2J#9fNyS(sDkn>2<@w@WoY%WJ<6h|ULLxf1&;j{%9^+3` zY#s43`$L@1PvsAh2fg^`KY!q#-w*v7A^^6vf@=P>TQ?v-m&TUfL)5r*;X8EHODC|= zToozLYSM{}UGV3Z$_k?N(q!y{xhS$!wmaMl6#aQu(> z7)O$#SH#AQGa8Z{St~;1;Wh#Jfk;2lBQ|zq2eQFLUu~WgG?HTz_v;NmnxQM)(dD}uBmZ)I_*i^zJ5FU1w~&suaPk{In4`w z{FYXfq=ZzPIgt=KhtBYkbi2`DzZK}}7Qmd}&!SJu5su}|i_f_vSrp2b+Tm?*mtj1P zIhs`peS&nY>7TvjoRboHPBudT87O+M!#}R=y$X4+`pP`i3WymKwUtRsoMP1?U%0{$ z&0Q?DPr#bf%WNVaSz)65yPLs{N2HQ>H$TwAE?Tv|3aUkCxts;OJ8i+geC;M)mA>wuw!t^>PG zllUH9u>PN1IgTuYc5;qbEpJ5$l)NyA9LnyI2UIp5f}XYYmWMoOP_;zt_k=ndOh9|T zJ`c&XtPmhzixoQrc@RiCoTZ7`eTckivpmX-CVS1%)OSY2zD^eNf>yGMa)%o_^uZEz zB-kJYqjf72v(q|jhp6+T>nSJt(RW1eVw=ZIO0OdO6w!-&AJQ$n_8ThqlFAuf10)($ z(5xA>=TenzV}&ggFR}NX6>5aOi-2vVC8zv_Dz(Lc%8z+X|ELl|&0@fJYxNruZuhN7 zGZDLQ_q-zZyL+|^+MVT$4eHMh^^bayBWA~sm|frhNuc-^;?s(ojWIIh3U8xUhbA#( z9N!!M=%w%Q5|V%PmKo7#@+V@C6T_&i2*XAuOmG4c6qk4-?G1j|yHpQ8yq@`_v!4}5 zFD20=(E{1!W2f=-$y2ho&7}wEM83n#Kb1(_k?J`kMabR67d*@&kUyfU-Sm9C>lMwf zUS0*YtgfxiZ%fD1A17j3Du;8qfZXGEURNooNVy`Ng}!d_y0-lP^#YjTry9l#OWVgp z^FLM}r4S$V;A2IY6ZK%OMrFIcJd(QVS^=UQS#CkGoYbe!wpN>K5$>o62u;v?S^1nwLuoN|bWL72R$e z#T3Vc4aGZ?$o49Xi-UsxqGH>hGh)D4DixO98h6wegh&R>=$w=VYgWtGN-Hz`#;Jih-`Rz6n@NdwE9X6IRnB7(1Kc{KxF`(jJ;E_ok|cwg8= z9CF{JAmQ@jDE{L$XH__m0Gt3Jv?UAQ=S_BQ>|E#YP|l^rzy&~GllS#VGT`#zmX@@2 zfJt<$SZOMa3rPzL)W|P^Grw5Ojxrbg(fI2h>p`^~2LqP8iH5%K%K=NLpN; zU-zj*R3=}puN$$qViwoPmdv!hh-eqCAaZO86IJrv)>rul@)6Ng3lip6N^{>tQM3CrcPaUOF zm=Y^`H9l8izaK?sf>6@jxbe>!jLJl*4uQ>uXEB|Bx)V5`N-BGV1 zEVJji`mf_>b_7%hNNo5OC=3`lIytY(FOYnKF&P z@zr84E&1UUB)?&M*hQzEtK@+Y=3|&qs-B}~{IbP6PIK>iOiK-3aK>w{0MpV)%+TxZ z;xh6r)e)%0v_>vV_n_Thr#Dq)v6Vk*CISY`GiD3Ixjkow@4IF}ma7@d#v5#(aWOae3T4%n< z4NCIvCk$PD?-uw3OD%tXxh2rF(G}6O#oW1=Tb#QxAU?eKUH9vb-`VPiXEnddHv8Ex z52~dWT9($p(={%H!af|ugThK0Kwe++2%wUi-fK_Va%%)a$lF@0Q>RP4SLICtgnHdi zZHjY_=O-Iu)3V!UUEqnW?@}S)V_x#8e<|7K zresA7m}hv>KCib`$S*@mH&0L93#>#2Z-_}a(O8tk_UOrFU4~+9_U+s-s-cFknDYr{Axh&z(Ym+W8-rB$S;VS!7REvV=gn zQcSPbv+$Fa+#kaGK)VQMv=sBA+p6~ju9X}W07ys3})v|2;`X`3`_9aoqQf;GuzI7-*JE?w^zM!lA zIx`XsUSY44UjQgJ(213!vT|J4+YI`n1CDO*CHJLP$GHqcM}PcjosL1P6{b!*d`q(S z8yqV*CvD{+0)gg_M7@phG1Il8C_xys7TMX$Eo>SeQa9+JW5^yIM4n@nZcwc)|i?bJR<%o2rKwBK7Osh1G{w3u-53Bw5(jAuyXSGE8b`6*aJYBaV&Ak(M>NXHi@ zH~yFOG)#$w%E^)Pe4w-FzToy{`G=r;;1&J+9%=)*Zsj}6R5NHNgqs@L#RllQ6 zMz-Z|NYK&ixzod&tLx$g!NHdYVcZDU1g;;+YPi8)EKX`22dMJ>to5o6p9}xsdNJO4 z)b2WT^13DMDab<+L1)4Xim6F{BTO)SE71_N_aQPn9D>`qlWzpBVo1ya7Z7GCtJLg2 z`}sn^UwTLIWmKG3Sjbg$pB{rLwrAp*%8F&aCD<;eFBG&#^y?02P=&{5vW?pL;lPA! zXcb11P_ftDHbzdMKF9kI^4|DW>xV1)V+C)OV|i;)H_08yqRpbG>y;crpu;K_;_5~# z$pZQ7tRqwC1FcF7cyxa){SB^)u^)0U^iC~7n z&tOe2*V)M|z2aphMI-zyYyAM1Vtk{YHi8)Rj-rkynT1#lTH;iZ(7Cr3te7MBdab=k zdrc?jRK2|2*ddLuJv0;R2b7zJz&zYDa#uu>ew$&=ns6#0F%s^~0_T=yIhJbZI#a-T z3Di)F2hRjtEVOyF619gs%4azi@D@ALMvt6~AQUWD(I%~At@D_Xwq7P6Jk@ZA7JG2? zCO`<}vdTgkw*m?bT4%=7DH3`wzgk7MdsVS!5gc~Gck~-Kw}}HoA&992=M&C>q8>vz zVxX1c_58BU{AK44vaj>#TN@FC%ZMjGt&N+l-eE1T2-xe^pv?Bz@ojsjC`?OKgLlSb z2fb%-=TVLQ`HUs`-Gk9(rOUV8*s?<>c1H~6l~-KcZVL+K>wJM);}=)5JnPH5+N<`f zHh^%N-mBKmIh{b!gw2c!^>lEnmqONW!2aw@;m+Q|bPR+VYyw0Y+$nE#N$!0LjYF@z zA(nhz)rIOlKowYvu)@Q%pcx(^WQ$K+1DIjY_Qhei$yT&ROfS(oOl1~5 zsQ|QRcze-LJci*$J8Km5n$foF3R?zbujdu-qYJEWOS-F*W?iC3B~%7E zA=s9sf%<}G(QM04@tt!&?UCianB;Ng!RDUBS>E=97>Wm6uvYT5W7qwa_s=7%%%cN_ z%k2-U>2EjwH0GD&>(8CWIZaelS!P?*?#|7wEe@GH^Bo^6t$yqsa;G%Kan2&2a>ng| z(AByZddbcL7(E;TRZ}Gl?!|jAkjcM~^FoyBW=8uwtBD#tiWL)MIH7D%g)70n;4>R9 zT#@c*)Ekj4-w8rxYG)eLm+JL-oLY#6L+(J9EYZUrZ+)eA*uqalL&VWQK**ph1p^&E zmbBLFZP=EyCRTrD)=Zb>-$~%|z2RRVQej>!kC3W{I@p`Y@_WNt3t=iM!*s@1*nChr zetAJpBu$K$5+;4T_(ng0>(I$8?Xfn@qTz9y*!IyAL9WMtZYHR1&S&l6WL+03>**!? z1PUdmrs9%wk$mXg0>+%)4TA!Yl&Ie=4x^03ln+Tm*9Nq_oC`sLkZM-+v1oa>`PGtAU>r-9lxw>W{>{ zs1#enIkXDTw^jU%pW-U3iCX$5gryL5GE$*25ddKb{@N?;i+RHs14jSi$I6c;xXer2 zBV(K^u!3S+N;tmIPFCpcTK@T=MNHU4o?7r{u{Ev5pLNB#S~Cq4GnhR8HUg77AVXwz zoEUeJa~5)v-FTz@(sZ@O<$KmW(X19Cr&UoQnzbI*qb7g+XLTixhnp+o;5UKQST0Nt&cYD)g)o=x%bEyOs&v;?>; z>hHAK_MEv_#BwQ^3=9swKH1CtQ$A__Ezob*IQXB0goMWce{sew0i%qmTKlXwj|ZCE zmtzU<-LVsBInwV>6ua|i!ahMt-O>~u!r}gd;lLjwWNHaZ$b`26{b!;sv(n=B!`TP# zom7)5jS;n_oy~=u=A)(Fho*0_?GVbeW$E@1pt9s+rvWK#M@^tY@tc$jX&&C)(2i)% zbo{Y*2V6D#T|2mZOuKfJslp&#*UzsR{8e{jw%PN@}bq|M%~bME7U0Vyk3k zSJp9+De38h=o;v1j*m74Y1mQr!F+(qddF2qbudV*xc6JSl?!8DMWlp8Fb4&hRnv0( zAhWOuB9xY0v^$(uoQY3cv&zEsRaNV@EK}U`D)-5;eeHfx-b=^oopJkl)FTE~fmklVuc`^qKJK#DL~hG*ke}Hyw~E^2 zABws}u-RwfbvSiMo@@B|ePETBei(fGtbP_OU(TDU2M;ofr| z{FHs3ubP^g$KmGq<$aBGvUyge`L?|Qfya*}hqo5W7k={Pdb`w%)vG~e`I7rLZGoOp z)bg&ar>Ez)q9R_IVQRrF$kQLZM!5HD!#O^A6zREc-zj%%M-*o!tF1asaP#d(H6xS$Tvf|2$jiCdWg%0p@<2&xzQx(!W;JuD z_SZ+GAg%LnP;puNhQx23l5(}y9jXOsSRbjTiQxDR4HMS9mDUD|F35%RZKt0TngsZU znl^7si`(Kk(wIf0_ScUdL0q$)Q9oH}xIC z4YQ&JW0F%2ltyLD4*0FEJ^ak%0%H{Ta)Fp$-uihQ+c*c+2S&v_k<6Cqqxw)?P)E8I zT;^>rr%#6Roww^5Vhfi(cW$V|& z#lV%OKipa$^paa`EF8mlDRC0@@{QkjF4xGe6!zNGD8R)p5I$$I=uh-@Qmt<3q^g|m z9uLranwn1&XtPbc=n=DCb8D6IYoti`D$IO~#F;>0#R1qJzx8`>v%H$i?Bz>0Ry^HG zo163&@f#NxN#ygLb~cJ*6vTV#b?xS+hn9;=&J@BXEUL%8GdRp3%`%)zLk#F5Y$JD=|j#u(PoR?)u7e(Wxp{E&ST~5jm;@w?}r7ORY_e zXVS9oX;m=yzpHoB0`To|d46K|y+l_n>mX2~sCFDWfUfy-akB0?@iWWEvC(C&%EiS+ zaTa$(?&0Z~tfi&Zk(QPQ7G*J;9s6})koV-Q(@55FtmOryD$3_xW+S{ks&~0RRlxYu zCU6Q>LF}{Kmr<;^5cAlC_~mRmi^Z1hdh`9(UET-S_;x=&i5Eev2q526`Kf8lJ^L(l z3TRVscETGw24GW21X3;LJVzATsi>$dWw#LBco7kigrk4I@8xD?Wzmp@QRa=L-(;u` z@EbMpWY|5qP%N#gqO{FGuQ-S{TIrsI~e_zfSt$O7RsIMydqrSSJ*%Uhg=dRG$}Mr zCdxN^#g6vra-lqL5Jk^cSJ)~Rq@%Gn~pBwIfSh~+}IyA-x z27Tm|{z`}IXyda#0#vm?Psnz5zd zYlA0Gx|oV{{T)Tw;yx|M%T@iB4C$mw8p@KBI{r>ALXzvh$*;!3)w1;m!==F~o_L3q zZt_0h{~ivyx?k9mAoc-K6GpQaThhb9A-I+*Ik|59CD7%WMMf36idK7S4COPxVuK`X zCW9{0F)cuA(Kxf*c+c-j32&8xWU(SieTWJVz1&?G-29B6RPJt7o9* zCH!P{ZbW{6$i&^<{YySVG;{sF38-UbAXOl+zP`SLOTnK<&SyLOz!JBA0=$JGf4;;0 zlpbg-o~0IP{rjj>3CJ8r@zJA@C1|TC3>C$8FbQ%v7U=dHx0q(ZJ*h9f9)B#PBg7d@R-Igzx_`4wsQ>V zz;PJy>DB(`e{)A?Q3YsgA!Wh$w?gH{jjrm%8r>!$x(DfY@gv0A-DFu^NRvq~tEnxM z1ncBxrO3Wp$dMYRI&GA2dksg^PnLaf_`=_0^vb66;yUn}RRjL0dTe{3^>yYRz$GR- zFAtmlx~%ROLJ2^3(d({8)XFs8X0&aD6b#F0@9#8q(n%A~D$a}W#X*Iz2^! zp*A2FrphU`J7O-gH;7kxy@ph|{1nMc;Y|ge>z=_!tqVQ$vj6haUOq_KIk`})Nfrsl z%Bz6c*x88}F1CFxTstrDNgZe0$2rh=d2c`cJ1INlSxhJWwt>s2Y_OMa(7P{Rz=tGB zOwSV^udaqmzA6Ax;Kad1+Fp=GVeCm4vKqmpr$pa2J5dO(PV|?QWThtb0kA9N96-?u zUrvBb=J0r5O#Md7+!8?OI}Q=kNucUvS<54bdQcnOM5?UNqWXqByk~*xM}A*_3Q0o>R>O+gFoqJOPAmWQ#W1lJ0i`+ba~uw(SfgqF-^?9z&zlaEaND0>sN9A+Qr zU>o-2Shrie0Ynzd7uvbqysk_kt~N}yd^Ob2U?w@I%bSZXi^WKaE!gi7Yx}v*iJ599 z@1-AkuhRFV*|JI$wtqH$9di-5)v7JO3%<&h@kDuHCN5U2&X=lwAVZ0lPfkvvUhpIx zgtPL{P?X;Nmuo=mygHED1)y%W(YF6j|GJgOxKQ(@vWDPo4IU3oc}u6IpQQcAsI)X` zjdWhct8-8NmoKgDhBDmYcWxXnV;dK^9ta4;0B=w6czEt7eSRs*526&o?K5&Nk58gh zV|V9#7J@#jatGCYKI*s-QSuv;Vnz||f`4E(5_+Sg(r?gLL$V(5^Q)z#k4S!1?Z#Ah z!j+{N{m!y$M}(XHhO>W?^V&@58yV5@@0NRTSWY{aLOZtQ{LgSxe2$ zq)G~y?;2J|q-Kn2&?R^1l2E^Gn`mNWwP`Ic1J#Fyvb&qK4oyTeVR_W&Y^{5!oGOg= z{KP`>vUCJA{hk@|>{iRRS+6@6Id5y#86U3g_N(=WPT#A{1IQ#L=cC&P5q#creUm`T zg!ob(;WR_fyW?m+EUas> zzBmu=@6TL8@QNmIw`XY)(8kSED<#@pJ4=u$Q6gUo#rpx(F`g{%<4lYK*4YN1t6KUrSH1$_48rRrekyzSg{~=52&~VNO&i16$6zIikWwFv2btIz0xrkp>fe{38#r1ATE-gNG`u@d(>|~0F z`$~+%yJydOKEHgxxWUfhcD@^0T6=qoo$3QuJHVHTyCdjzT5r1cMpu~|FXu@(8M$rG z%5<65+J!Ie`fmDKCaouPU;I;zTF(paus)0~47OZox-0VU-k&ADS03+d-q5X2Fsk#Y zzpJ%(rI6K5KqlSSczR92JFpYx)FSN%f0{^v5)dTd&xQ3V}NfvIvH~N^uOl zZ9VCIPAr-D5DynqsA;!Mw_&gFLq|D5w#Gkz78zmLh54QVd;Qp_^K33oF)sn&V8s~t8Ftd6r?F%F2Hgj9teP-Czu3{7kCiW~ zj(+==7-6y|$+Ir-%TG%-Oi>>exUM!i!^r8k=YTkJ?Dg~AvU>zICYp5eJIFMgMR3rC zbL0H<$!faQz{#O2ycYiN*Jq*qwVxVUWlQC1I)48?M-c6rjQ-rW)4}~set9Q_h9pSw z=@ahH)-RvV5s^?$kQ3LKhy)*gyj!ZK(TEDJ8QkZH#MVc@p4O#lo@duU6v~KoGgmb)T< zavk|Hj`=sOCBkHPt(()%Q3DGq@-JL$ftZvxn_Cu^%=W&IBRz2B&yCZt5 zfh%ZudBOLxA?@~4-VOR*XdHvbcbjB(>a6cY)+P2fi00-WoxZzER`D!iUj{GFaCwdd z#hW4k>AOs~^cSi-@uq`)?l;Z(gEh=SU0 zDUr6yn+?3&y6PlH3|6cXML?IQL}B#PH(~T>QnbzOYAAbJQ2PZPIXodJx|l7%VNVKq zrhL!TV!_CZ2Ac-FH-8=1<_TN)23}oWX!sv(=dit`vqTc0fpD?fbA9+Zc%>j&$K}(t z;|^sEvWdPlG0B*1vVoR!BV&YH9_U(F1TJQ0j<%2!DR%y#h9^siYlIq;Ll%e*VN{^*5c+nU1_H9l z2ThlCM8=!GbZnHg`A%Y`tv#%fZsDOOdV@mQEUZ7|`W`{rL~u?62?bYGxckwZ%8}9z z^2#1JwEVTK`ts^z9@p-Z2IIM_{JrBLie_xUYKxlp=ZXlWaA%S zq~0%y&aRf+Ae;<{v1)My-VR@;Q#yB()8@KIB(4?q;pvn9Rgd2Q`pv(s)sBp1xwMrY zm)uKu)OoVTKHuRH&Fa-S=gqEf=r^xAxFBOuBcx(ztCE)Qv1V9#!-qcYbH^TPS#{vs z`KXNN+K<>iv?j^cY;!WV*O>09Nbt!ZA$Raz6b86$g>-F6&+rmzMGh$2=Q0}w$y@r` znF>pX>C8E*(S_2dy6$2#Zv0gG-46}KU)kPbX4WXF(k|t@w?P*in*3!)g8=vcXnPB; zs=hB=_z(h0OLv!agG#qFlG5ER9Rd>40@95?Ksu!x>E_Vg-QB#4|9kI8xDFjd8N+k- z-fOP8=6qsqs}$FuJj=y9-cL}jJj=Nthp+43A+&IH8qn%aO0hg~Uxg4T{e5Szx%R4f zVNSy-C!gfxrUT`*ej9r+Pg|%-SG08?6!Cf)#yjQ+BPQ$l=eg)_y+rG+lhsZfzFX10 zcoa=7t>os$(x}wDK3u_Dlch-w{YBU9bmTB_pz~hWR98y_$dL!rYv(mQE))X#&%%qn zeS39v634I2eLvXoW@?74k(>4GRT*fAJ6BA%1iri`1}F$-(s4_%Uqes~Z}gNL3vIF)`{!MDzZWW1$Ad4g%H26Dx zpZ4CR&;|6C>P_ccvO@gp2gn&T17`o2LS^+VFI%6qBx_vmLA5{w^CLbwv~Xat(d}IM zw7HS4<=*v5v@V0cFLI?S4*W8eQKn6IH3k&gue4AVj|4!HFI^J&5K=T#R z^*wiU{cCD?u0YY;zupu5duBS~WK;~DL5jp>Vx+ZHtM%ZduQ%5a`zDVQi+k4&foSu$q|s{*MVG+vjdq&zx)jGH~nN zQ2l1d)IX-=>B6p9%0m^tLmloV_+s+%S8Zsv+Q&l2nkL*<`4UGu`H5BG=wzM(dv9PI za@0a3O8>U^Q8-hTe)})$Io27Dk(Kp$f2vpK<;izS6 z>V|OaLcR{yzbmjR;WC7ssWhFmoG!JTyM>@+j^GuM63_N~i9@UNArIJXYtre7*AVZ| zTwaBV4Dfx`C(YA|#APMV>oJh1S0@4xM##g`_IXKI;`;e*3RTAZ=V|?Kk8+tKZX)9< zN1+c9!7J-jN(Fbx5{mS`uOSf?*Q*=2O>gK{b;9|WeDw*IQEM%BwrUuoV4)w>RHzJ#9KeqM6pRrf^W%ov-tMO7tF?H|* zvB`}}-K~P|_6`8fas28=(O_cU3=iePbm0>qMGq3CP}kElgz+2L3^2rZY}RJDNG0{2Ds4Jx}*k`{)2;p}8)fQh*^k~z|`dSdt; z0riui!QcI&*C8ZkI*wg9H93E-YHa6kxTkg2=_ut=xEM+*;2=_p{ByMP8I+EpFz_;! z7#Fp~AKW|e3C6Hou@9Fk-j#fHvD_B03Y6cDPqnEnKvJ zN03S7EoCL;yegMWwlQ;*HHwf$`PoJuw8(<{3t4Mt-kZl>4^>u;pWo@@jfTU=A~f+R zS|RxS++lLQz67c;w*wZX?;j6*kY3qtbT48!9gWm^7sOM_o21)53`dYB%a2S)0J8wIf+i2`hDmyDE_*Ca zjZ0V(^x2of)FY_w_6Zz`AVg9R&Tm@=xoQ|Olo^TF707?YK#`{Ik6Saho$7UBJ~PPt zv#Mho=8xhts%*#qji=|nrPf1C3gS;->&7yHP@tJ*j|-fYk(j zod0ZD^Hs`rHBx1MAliZ_ceBtv(+f$~V&&$$AzcOVeDo z%6a0R{#mVWnTJmH=Ix^i3GiMik|OwZN0C^!G@FDl?2m5Q=)qAu7O!V+> z75y8&Xt4JbI9^r<6ranC&SH8dzThU-A!DP3M1zMO-JP)(p1}#(ICZxe$q+dBjl($c z;aF$X`>e036O`%?1^F3g8Q-36+vS$6_a@eL%9_sRuKBjf_8@Tq!5drTZ1;fx7L##M zK_HHm>xYq$xC&=&*=auOFM4aG<=+-!@?J zCuimtkeHd8N@zzuxH$z7$4w;f5+8Yss;H50sEd0FLEOa7ag8ab?zAj8F=98UH}q(b z^vbguPGY2~EB22!62v7jO+4hw&v0#+G9UBfAqx^K&FDHdXrC0WI)uHzD zHIe#mizD+nlF|>KQyzMUli0-;uZFrmNhq(l$}$n7N!Qq-Iy4G6HWWOkR{PZ4U+YZ(jfk{v#D>EGhEu&V;->Zmv$FltJqBrG4tHc>mt7m=idgR-U{t9d zv~2YOMCFyDuT#u(-Fn`h^|UWdG(LMr6MzQi-!U?#r+q>EG&KZ=fI<#|vza%lvE`hv zOg42i>r2xL>qAj9Tq+N_4G*J?-}f&nZ79TOGZf4`Zoc?-y8zB4L6|Jb9CKKa=$P~O znzIw%!zw+_Y3u*|>0PR}{47^bv#n^VjKFQ}vFebtxxF2?d>s9}6q=6|2k-ji^MzAy zlFODUO;F3005PwfiQp{{Hg^${{u{mTabFoQkj9ljU-U^!ORE7%9YrgF9UL^q`&0HC zCEBeqbcz`^;5;kj9x7bzqM?y#(GRKOL2;lw2BbL`AQ}3a z`r_z_;1DIPohdxLBVwqeVoA}^L;K+%cG}=^qqDqw*Z)W5_3+gOCTI;Zyqye}{)J)< zfo4gHO3#t5`h)9N(hsgEK4+(4hGW;2HXK?tNjCj*+$gxNA@~q3Zng516v8d1dWDd6 z_^VfCZI<%17#H~byyXoYeRLye=)`=ZQ5$->DLEJ89c4tA` zYd-EbqvN~GLILM&ZpjH9v8?@K{y$^%7fS9|Cl=l-K&#Wp%rKD9aQL=!SrQrdPXYB| z(EgGiM{lJ=0y;#c6%1t|e#^^SE(KOzD@|B{Wfi#otjIhF5E88qabqR#=WCK}=TX9- z!A$cYy$gBm6$IUaES>RT-V2N~YJ;`4^?+pk^RZ(vvsrAfsku3JKzke4;}xf|x?|>_ z)wA;%uE@EeR$vOtVHk_cklx6wpfKDoA`}L?f}OL^;e~*D&x+82G4DQ>sc~VeaU8wD zZR7VD`iUH4!_PR1UtMS`$r$U5P-~9&eguHKB^Aa!gv`v$hj;HgaSf-XZCCz+M!~oz ziW>oq*diBy!7!XHnTyn!Bc$j0&4D~9L_%(EH0uQ@EXTq21%Z2&QaGJ3q&@=G2X0c^Xk;|hUhI(2;y zRTsgBdlAuCFIxZDP4No8TImE+QExNVJFLJXn>QPmp@APJ zkxxctqHfP&m~B&FHfC7Q`E2DwaPuQly{KxU$9Rif;wXInS~*BGj`X>N6c9<4@LZG4 zFN76|Q92q{GJ3)n%_MYq3LRFxyUm+U^{*je;o+e_5ZcD%ePpoGx(C62by$%ocY+=8 zkZxGag2Of4leWDX37>X-Jj&Z>dHD;();9Z)5>_xLvnl^UpNz+Fg z=lq7^$3}t)YOHDx{{BAkpLT~7E@XHC(Pcu-Q`=-J)~Qt^^j_Imf@ccZPaATQu_j@( zP51tF<-AI2YVn_9xUEyvo1Vjuc{*1DJ6^$x2nET0?2%N*h3-NyT%FV&$CyIDK-!$q zaS&Ik7xrX>MfoxVNH-u+1};yK55Wpf5=j}_-{a16rG76dVF#^sE=?BD&4#uJbn(9J zXnTuvM=Ygp>d{i#v(xN-z9HY|Hy|$)^v6~nszPmjNk}@jDLNWQ+=ig;wrlxnjXJ!) zGFe5*iA)qC89Dk3CFgm$)&Lan;@vSs*OR>pvRYe(z4^ljTiM63kkkHK&5GoMJ2~fHftTh5Z9AAi0V^8 zskulZx@!Jo#$tXB5&3l2y-;7OD*Wy9TlI@P9sd=jkcz0Xx*{1wQ;y+Z@d=^BndF>$dJVd* z@Ybc)1(FP=MZ(q!K2E5riVsj`-g*mSDG*gKHdfa?nhW}=fdgHibpYpr6YPo{ z3)CR@X!=OH9~;q?l%3x*Jj2;aXPxI5l82aaTg7@!>B1%_*vqouz{$i7F{ZqKYVJCQ zJmleRzJ`B<&50@t+-HEI_*uXxOiBDDN*59_3)^3$`a37fz-i5|`_9T!$j{oVD5oLM z@}1v2glPxWBj8DXS+cxxhEneGCWKOVt-79B^jII-(=Lw>*Bap|eO)f3?B_(YXAN7=((#_Ir5gKMtfsjjgouv>%3~ z?~%=0tQ9e8h*}%b3{>M1*V`Tdt z4icSb$!p$x!jfe<#|9aJ)b(zkb6*6a_-6@?&l02!diLMSDMKV)K^VKF_t*rrJuElf zc-1r1q=mFJYFa<5Zo_9ghq0kRl+@xsW(aS{vdD6;;y_pcaDcd|>6mYk!h@sG|1Ss- zsCza|!atGkxB}v>GKG$;@`u$DQw4e=qvDcR;&T%xPm`+l!rV>gRb-?GCLt~PmMMx* zF8=USt!&G=3dj<~p?PE*>rxj!;3#IcNm?0>v7SiWGe`dCI@(YL-({SPUgbftc#XE^ zE|h_zS3ZG2ACZxfN-l(e-?3!>{XBA3Ru)BW)Wxm02xJ?!P7GRYU6m}L%_aYVtSu8V zh!c7kutaT+fIHy*k9tVnQRo9R^yiOXHJ4%tM0B7l-GCtpWhh|FqUXr|TczguZ~Ht5 z?9U*F!lKq(%ekb|k@2WJ%h)_i4LEnCw&;HaBK|7||IzI$%Mk1txP-b!F6Pb#Xhojg zdN;xhBCzQ~t9!WQ=gVj>Q}Q;gQ?9%qc#x#S^V^!E5pP%#jlN|6$qGLY)}QCJh_l~9 zAeC>t^1HUr7vWayAgmTCS6O+Mxw}}NH+}M(Du2{{3Jg-YW1@QpTQtI4=znseok82JcnF-iwyy|Tpdpym&q z+vm)n8YJ{XhH3h3Ip+q^Lp%XM(f+6qTaHDP|7YrBE=VRE-}Lsm?QxVh2=tH(3*A;h zaVZ--)dbT3J2(rND{@0OE-a7&WaOcG@D5adlPP&6!Jj#;3r4oBWk|~`zrdso)NHJyu;$UJ^9+;xrsR zv8*a7DrQrqL`^b|F~JQ_A#JD0K~1c9c|TF!9lE9DEuwB;EJs5gM4{E9eBa8+A&MsM zL}?aJqLAqy;;!xf!r(+jqjApBHlqJZmXuWSf$a9SyAxBbJrcwrLwux#1CiM zlQxy^gG5g_wmj?jI5YH}T4JQl6yca!nl|_!KWBE3DtY(! z<1d|G0+EC8=GC0pjtT$e&{v}mVKiI9KSs8ce0Ra1a8yu8O%p#mf22<1@XyM`(7@(z zr0spZo!dxP85b}ppiDt0U$xCL*}kSjt7XZ1@R9izej=-|@DtyE0lp&3Q|)_9wdB*( ziI%+_-zZ7roH^Boz; zH6ufv*LSFhIyBcd=6yQCWpP*NG8|QPRd8WOqk_VL&7g3CwZw@-+wrthICq)+B*XgG z{D4GC4<8BE7s8ULjjtZyE0rl({{HY++yzY66CD01Mea=Hz?A6Tm)OSdpWiSF9xS3L zw*2opf)x}o^Ar_1Ab$$qv>k~e;HpU8X%+4>IE)j1?X8^UewR zIXApGrKamce!5rQ*e$eAmgjRU-GKsGhbo5_UW$Nhtej2)!&3Rc0OMERvM9N6y2nZQ zfTiDx16&7q@9+L|B~6@<1c(2bQD!;GMwNaB>Ju@!L`SYfBf!P%I=gdNe+`B1ZZ`tKYo8J_lNC z-u&|p{-L41s9l7C1dqtFOZCaGO2UG3>a^)A-d|1E&dWOCZ`Jbh-n7<=hLBOiuHC-i z3>Dfnd$C z8RqXZ_%AO0Q6AP`7=y-4-=zw&>3l=R2Lq&tkQ?i1s;BaD#nbZ97`-lMsn2)OwfEm8tANKrXx~9gki$@YkyPk=(`vHS2KKfD`U(({Z1KNzRbQlm8_x)5`ZYz7FklCeUIl?_?aLt#kz{O#y07E!V<* z%(pI@POZp$Y?Ri?v)&_onY`GjhA=a6T_qq?yJ7I!_ued8!i?#DCHYA$OaWPV?bX^I{V;SnIOXlr|q9Mz7Cd&BxRArLL~KLpGtHJi#}?u`zTuO7p`^Y#fqpA67HcBeV7 zrNuEgJH0dHH#`mqfL)Dw4IhBNJE782$6M$RRmyq3bCG+@$0(f##{# zouk)-R{ZV+42k5GjOMQkP8qX~QPs28p+mWF!o8cc2QZ&xWebXn<>=pnW3r8s@pKov z8Bh8R#34urp0A;D8Xg%Q5rU`#&sZ@g=P5xhla|vAH)V@s_{;5HVgM zC)VSJ@LtA2(UC?wGJ)lrD58Orf>U*doO1%!8?dG!kNgt&CFqm!AFsJ$p3scP4L+sS z^}Wt^$T$8xJR5o3#~hm0;Lp*1?46LAso2r+_JS9!2}wQJ?e$JnOTRxOe*P!T{4+76 zP9+?t`n2-eQ36rqcN4U&Kfvc2?f{%Bx5MN$M&8 zkne;LJLDr_IcKGHWbO_!X${Ma(}&A-Kwy=vEJ?6bQ)4oZakT@%2gXF0V)4x;haA*K zxHAnHy=8JZ+QZT9!l#<&A*ibomQbe83NEPN4FnGpw1@DFF&EwOVhv2!rMs~TE@}&3 z6=ps_vU+cY1IyuIMTmFN_WtF_@b|X&@3ASR4JzHI-!s0q-lz*0^au)4)zOg!%AXDf zoC_i}2RKIVw~6#tUp9G6ITvl-Qp?Z|&*Mn;9_G!Z_2Ysp_)fQ<#FEwS8H_uiCl-Cj!h&mP53*QX zBkGxsnF6r(T8`Fv<8h$b;QM79P5JX zl_H;J$fJ9pNAYUrt=OQj7IIXebl&^IaDB8ce#Z<8>16X{__dWr^~*F4qImoR8wpJb zZH2jmDMx12VPVBC4!`|VV-k``7HWyb47xwKn^DRE+(OG;Cp2?B69>E49PEEXt;>j| z4A8eZ{F2AppBJN>v&yDiCN|H>59M{K#OL$d(-ibm9!n~CCx_!6`? zO#H5DI=22F&TB)78F&K%zommoDvS$uAHw$jgCrL@K1FvTg{wix*VR?|Rc}{Mdk}<6 zS)5#uS1$?r0-57D&2*cu#w~NFDb`B^TE`LXCZZgfM#PiMSRay2{{{!U?aK3e$Dg+s zvS|IxqM-vOP6{mBwj)AK@N}A6M@0IdP$wo=O3_&Gi|AI6Ml5E@Bl_3q7o)*b;sGI9 zWm^&Dv#Vv1bx9UAQ?KQaOw+C)o^{|O*0SsXW?=Ad(qLeRANB9tE=xNe3#Ee5n3ociP?LP6w)N50nGl&#AVxUW#-+lY6h`QA zH~tC0@S3_YG7hT0Ve$Zx93^xNerOK^T$K*8A%B!|X0=bI^4+%pBBLRe4zo zCf3QNF})EH)mzxzE|x3ac!(^vw~PEi0#6t+tE$FLUea>!tshj$t2NKs)S z$8Xfs#y5%leKq1y1vD5)cT|g&y!bx`(gy7&@Q0Y9T~fZ$47?{Olo7tlzT&!4yU!CN z%w{?hpwXhm0u*)Fg~O#egBCg8*BvZ4Yhe330|MlOS#A9hT^2m3OL{OWk(rLeYS2?Q z4vyAUOz#p4GQ#(R+(fj-T+bB!Zz-GZIx{$cHPo@}mksthJVTe?1~uKBF& zSKOPadHZ7kr>f+AHo4q z0Wlc~6xMy{LKmZcKzMYc$iMlknu4-B3A(|L5~%9uLg@?yxZbNBK_1&_&S<(`L)-~D z^gMvy;I04~9Lnc)ML~9ZAYxWmQ;T`GJHRDx6fp}SAHZdw%&GYqekPavleGzSN%e-M@}#<27ioELeib`5=B z9>!(QkXf5nnm1x)I|?2eU%Z7%D(_FUS)BLOz4c#OjETufnP{OW_ZCyFaiI2vft0nJ zy`h$=EN#A;O9%@Ko0<8lOiAL`$L#dLouQmzs&%uBr+4Cg*GG56ZrnZklR~WAsOt?7 zgJA*rj_Z6MU1qUVuBnw4RUfXS7HyDu;`Lu(IlPQ-eO~0WnPH0{=6?%Z-|Y#^+B0A< z01@Bw!#P~6v4tt$I~f$iwoTW0omy$NMR@mux~88gR)NVhJNg?FZH0w}m3w=8UqrK& zWPm|41o19jL+^CK=X#N6yC6P1hyF#(e$Yee#dJLU;n+sD1&Dj!_ieh`J1*`1#8Jrp z`Sf(O*r-@sSQr)=E_e@28a39#Y5er8tcs0Wz$-R=x5->vXKigAnJpILqInLak25m) z8MoXRr~MDY%0vcRrZ-|BlYB>*uhEu=%6a)f^W?pORl;Lh*DYNQY~vNv5+G=LQKp8K z)vbk10r=@x_Jsi(QfluAKV2uhY9gaauxMxlZ7E*1Wy(z_*^?5R@s`}xj&XFdj#XJ6 zbZ+iV=7>hQ$NAO?&}d*u*GgE-*Kq37i->n027zZgWsDzu7J^7x{^so5c)!Ay2HEzaT@Uxz z?0tNix!g|-uyJs@NQZcry+1cxPHEqUMGJ;Sk_mWLA70;kybG%JytKj(zGY8j1|lL8 zvAh77AZyp-rF17*M__Y2drg;y5m)On&*OT3SbGlG++R|)I5aXHgUOs=a!QF5t z5Hbj9+OPTWHqG%z!~0 z29g#fEC@-9<(92lx5K%~)w`?1`CM>1bT1*o!d&$il~op%wlwVa(Pc<$_5kH!h0pyJ znqevMi{G4|A-9fq`h6;w@A{7{&2y^({Q6Jj8=7ycewgGqzF${3u1u98f9~Jx?DiXw zxs5q`A_&ChYweFQhVH??X=;0_+Bx_gKhu6zm!3v_b9kYm=get%X{D;B_L_zggZN*a zPU$3A=}#Urrd?q;{l!{UGeAXcG*TZ|I7-?}$Yp_%?zvas4z%TQ;W{wnO!^g+Tt*v7 zE`Df%oxLNh<&f&Y&TKT(0?}*??N;CByWeDw^b~X0Xmq&zQ(Qw|sx4x8DJlIYi!@}z za(vNt%1soI;Ij)69FxlmOG@M?ZZU74Z+e6lfbz>nGTHoj$7cV0M92;Cdpnxs7i(+A zDx0D%W)G%77|>Rr`c5<~PUvV#`;Ep2JV_0s6wjQ#4UXoqUs|BZ0i~okFpgGSd+4!l zZf{oPT3M?TXNXk(D43)R-R>w z$$SlHaflmF7Mw>;_qijVr%BxY5i5qu{wXZX0XjlA2jA&pEvkB*(!aR1Kb*r+Bq(T# zRZe*!t_K(b+OHmC)9f*qJoihi=jY}GHLJ|zJB)#8nVwOP0-&_li{^Tsv!>%fe zb{iUkl!}cbAdHYc3Yu1};MfOG^gu|DhCQR$#xZj;*7+MWlb6b(*KpRzrP9#<6h@ z@Xx>nWCVld7PErtYObpc7|n*S42|1IUWBQHsl{7cW>PFLKt4Ou?By2njaTr=J>E3= z>K%)7C6hv!;m@P-&~BbNWnDd8<}_uIXUY)mK=Dbp1rhG}co5@XZ-Ko97Dx-22MKrmGQ+R_Oyn~%9X}_-P8&xH-%QCNL09P z-X8if8UX8e*Rz$SA!jkvVHAgR9RpF@Ev~4?h5~-(ZfB zxT!+dy29I&s@;cDxP`~hKU$2Ed-X(-FnJnoo%YN#sxyr|uY5PXtujl;4);8s`x~yN zs+!cdw_+dtJml24c>HC762kM!uoJy8$7lvo-{(?|Pp|_GA{P8h8)UiYW->Mdh&-Q7 zz{P<6lFECxqlG|vFCQNPFoomLJ=G5Ezwxc1)JscF^P`OfiD1K+Y(jYK8BqRp)iiq% z!GeS__5lh0*RNkQmzS5X_me)jmHG@Y^Cm_S2`Pl}H=@k6_jxd(!yLr<3w*+fn0wB;O`1|0ih%R}M}hiEuoPn3G;m zsNi*{Ax({D<4nF7FU7zq8(>GsZWM?a+06;r6bl~hL>ICVd^qVe^ETOsDhio~khmsc zlC{q@c~o8WWpYdBd2C#kCpAB9p-Ez zi(XURqOcKpH~vS`=w@I!Ns3D2G>>}xhozX*3Tn9-O(@&R<+Q%>U=sUlgem)P_u8_& zgLu)&o*fFXHaX>}t;=XZI@P(%(XNR+u@(%pJJFy@q@*k?ZTX&(qVV_IX}ErqmWIZ4 z%gASq%J??&Av|M zoH#B>9R7GNr^zGmt-qL`=tq*J!vOi430F5An)I3tS~V95o)Ffr%5z%b+%S7?UFF0)oCedtk@KZ4(xE2Og~d zUOa@6`5C@PWK08ee0^+Y>93Q+vq4v;6hsTrVa`Yes*DxeM5Nq1`W`HI^mnqr!{81gp zAROLJJ1fFia;9 z%&w@no@TMWIazIgId_C??=IN3)7ZODu3KA+fyUEAUAh)G?S4I6zZ{1nxgRz6@6e1j zrx*hZ2gXUtvX4|k{T^!JeC>$fSpag4y-v&7;pTwQ$D)#wp%1omTmwM;RtId5K*Gr0 z#y{P9fAm3HZSthr5(+CMc&+nISs9bPdnSrxxlibBOl!Q-l+4> zX0YM5Oao&t%KRWFvSncXU1Z6{R%-Ocrwc2`!vuX8cT2slnIQpY0B_ib-!ZF`O7}0-4YQ3rn)S~0 zpYKd&r}fL4-N6CFBqX$a<^J*O&A-qsp+uH=Fr#MV<*T(F`s%__ad?zP05EatTJ2O3+Zw>RDpur{w$iedEJXO-RoYO>I>VJ|BYV2D) zt^o|uwCA;apHWm?JP5w%YNcK5K$u(@xK34ou#-V0I|D|6qztri5z~{C1YqlUD8*8< zg~}vYR)U?|NvOlVcGuahdRRfjkt{)LoRGbLi-3GsqpJ276om&;q`M?Opgx!W%GVWJ zr%YFQRJbZ~woA6$E10{s@W zeLQ4d2d{afiVCe9+D+$bO!_M=G1#k01pvtE0v6 zsVVg|$8LhB&x!)v|M1sisVn|+bMMh4>WD_jd=s>P!a?pd$fKT@)T~8OALB>op97r*>p{UgvqMMVWeYKrWeFB2ri6BB>^!hV?`aRu6h`0;TSbqx)3AbuXw zsdvf+%JOUau=`MtbCz#GKW5WXabu>d {*wzLo|e9Nh+J@wB}uPaa-h5k5jr+F=G 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 -
+
MObjects are attached into the [[Session]] by adding a [[Placement]]. Because this especially includes the case of //grouping or container objects,// e.g. tracks or [[meta-clips|VirtualClip]], any placement may optionally define and root a scope, and every placement is at least contained in one encompassing scope &mdash; of course with the exception of the absolute top level, which can be thought off as being contained in a scope of handling rules.
 
-Thus, while the [[sequences (former called EDL)|EDL]] act as generic container holding a pile of placments, actually there is a more fine grained structure based on the nesting of the tracks, which especially in Lumiera's HighLevelModel belong to the sequence (they aren't a property of the top level timeline as one might expect). Building upon these observations, we actually require each addition of a placement to specify a scope. The implementation of this tie-to-scope is provided by the same mechanism as utilized for relative placements, i.e. an directional placement relation.
+Thus, while the [[sequences (former called EDL)|EDL]] act as generic container holding a pile of placments, actually there is a more fine grained structure based on the nesting of the tracks, which especially in Lumiera's HighLevelModel belong to the sequence (they aren't a property of the top level timeline as one might expect). Building upon these observations, we actually require each addition of a placement to specify a scope. The implementation of this tie-to-scope is provided by the same mechanism as utilised for relative placements, i.e. an directional placement relation. This relation actually is implemented by the PlacementIndex
 
+
+[>img[Structure of Placment Scopes|draw/ScopeStructure1.png]]
 !Kinds of scopes
 There is only a limited number of situations constituting a scope
-* conceptually, the very top level is a scope of general rules. It is implemented as {{{Placement<Binding>}}}, where [[the binding|BindingMO]] is a meta-object representing the relation.
-* similarily, the link binding a [[Sequence|EDL]] into either a (top-level) timeline or as virtual media into a VirtualClip is rather special.
+* conceptually, the very top level is a scope of general rules.
+* the next level is the link of [[binding|BindingMO]] of a [[Sequence|EDL]] into either a (top-level) [[Timeline]] or as virtual media into a VirtualClip. It is implemented through a {{{Placement<Binding>}}}.
 * each sequence has at least one (manadtory) top-level placement holding its root track
 * tracks may contain nested sub tracks.
 * clips and (track-level) effects likewise are associated with an enclosing track.
 * an important special case of relative placement is when an object is [[attached|AttachedPlacementProblem]] to another leading object, like e.g. an effect modifying a clip
 
-In any case, adding a placement to a scope is to be implemented such as to ensure the presence of a suitable LocatingPin, serving to tie the placement into the scope. This LocatingPin in turn will manage a relation to the scope-defining placement, and by doing so, it will insert the relation information into the [[index|PlacementIndex]]. The remaining problem for the implementation is to find a suitable factory function to set up the mentioned pin.
+!Purpose of Placement scoping
+Similar to the common mechanisms of object visibility in programming languages, placement scopes guide the search for and resolution of properties of placement. Any such property //not defined locally// within the placement is queried ascending through the sequence of nested scopes. Thus, global definitions can be shadowed by local ones.
 
@@ -3161,7 +3164,7 @@ We need a way of addressing existing [[pipes|Pipe]]. Besides, as the Pipes and T <<tasksum end>>
-
+
//This page is a scrapbook for working out the implementation of the [[Session Datastructure in Memory|SessionDataMem]]//
 This is a difficult untertaking, because there are several dependencies (most of which aren't fully designed yet as of 5/09)
 * the GUI uses an adapted version of the HighLevelModel; these datastructures are intended to be backed by the Session
@@ -3181,13 +3184,11 @@ This is a difficult untertaking, because there are several dependencies (most of
 
 <<tasksum start>>
 <<taskadder below>>
-<<task 3 3 3>> how to deal with UNDO
-<<task 2 2 2>> how to deal with CommandDefinition
-<<task >> outline the CommandLifecycle
-<<task 5 15 15>> implement a system for defining parameters and targets
-<<task >> implement a system for generating operations
-<<task 2 2 1>> define the general structure of operations
-<<task >> specify the editing operations
+<<task >> standard implementation of a query, including use of lumiera forward iterators
+<<task >> identify and plan the possible queries
+<<task >> BindingMO
+<<task >> scope concept
+<<task >> outline the general style of the [[(query) interface|SessionQueryStructure]]
 
 !Interface
 <<task 1 1 1>> evaluate models for the [[reference problem|MObjectRef]]
@@ -3195,9 +3196,18 @@ This is a difficult untertaking, because there are several dependencies (most of
 <<task 1 2 2>> incorporate this ID into class Placement
 <<task 2 2>> define PlacementRef and MObjectRef behaviour
 <<task 1 0>> wire up [[Session]] interface as a LayerSeparationInterface
-<<task 1 1 0>> implement PlacementRef
+<<task 1 1 1>> implement PlacementRef
 <<task 2 2 0>> implement MObjectRef
 
+!Mutations
+<<task 3 3 3>> how to deal with UNDO
+<<task 2 2 2>> how to deal with CommandDefinition
+<<task 1 1>> outline the CommandLifecycle
+<<task 14 45 45>> design and implement CommandHandling framework
+<<task 2 2 1>> define the general structure of operations
+<<task >> implement a system for generating operations
+<<task >> specify the editing operations
+
 !Datastructure
 <<task>>investigate the best granularity for object collections
 <<task >> define a record to be used within the index
@@ -3759,21 +3769,22 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl
 
 {{red{TODO...}}}
-
+
"Session Interface", when used in a more general sense, denotes a compound of several interfaces and facilities, together forming the primary access point to the user visible contents and state of the editing project.
 * the API of the session class
 * the accompanying management interface (SessionManager API)
 * an LayerSeparationInterfaces allowing to access these interfaces from outside the Proc-Layer
-* the primary public ~APIs exposed on the objects to be queried and retrieved via the session class API
+* the primary public ~APIs exposed on the objects to be [[queried and retrieved|SessionQueryStructure]] via the session class API
+** Timeline
 ** Sequence
 ** Placement
 ** Clip
 ** Track
 ** Effect
 ** Automation
-* the [[command|CommandHandling]] interface, including the [[undo|UndoManager]] facility
+* the [[command|CommandHandling]] interface, including the [[UNDO|UndoManager]] facility
 
-{{red{WIP}}}
+{{red{WIP ... just emerging}}}
The Session contains all informations, state and objects to be edited by the User (&rarr;[[def|Session]]).
@@ -3820,6 +3831,41 @@ It will contain a global video and audio out pipe, just one EDL with a single tr
 &rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
 
+
+
The frontside interface of the session allows to query for contained objects; it is used to discover the structure and contents of the currently opened session/project. Access point is the public API of the Session class, which, besides exposing those queries, also provides functionality for adding and removing session contents.
+
+!discovering structure
+The session can be seen as an agglomeration of nested and typed containers.
+Thus, at any point, we can explore the structure by asking for //contained objects of a specific type.// For example, at top level, it may be of interest to enumerate the [[timelines within this session|Timeline]] and to ennumerate the [[sequences|EDL]]. And in turn, on a given Sequence, it would be of interest to explore the tracks, and also maybe to iterate over all clips within this sequence.
+So, clearly, there are two flavours of such an contents exploration query: it could either be issued as an dedicated member function on the public API of the respective container object, e.g. {{{Track::getClips()}}} &mdash; or it could be exposed as generic query function, relying on the implicit knowledge of the //current location//&nbsp; rather.
+
+!problem of context and access path
+The (planned) session structure of Lumiera allows for quite some flexibility, which, of course comes at a price tag. Especially, as there can be multiple independent top level timelines, and as a given sequence can be used simultaneously within multiple timelines and even as virtual media within a [[meta-clip|VirtualClip]], and &mdash; moreover &mdash; properties of any Placement are rather queried and discovered within the PlacementScope of this object, as a consequence, the discovered values may depend on //how you look at this object.// More specifically, it depends on the ''access path'' used to discover this object, because this path constitutes the actual scope visible to this object.
+
+To give an example, let's assume a clip within a sequence, and this sequence is both linked to the top-level timeline, but also used within a meta-clip. (see the drawing &rarr; [[here|PlacementScope]])
+In this case, the sequence has an 1:n [[binding|BindingMO]]. A binding is (by definition) also a PlacementScope, and in the case of the sequence, the binding also translates //logical// output designations into global pipes of the top-level timeline, while in the other case they get mapped onto "channels" of the virtual media used by the virtual clip. Thus, the absolute time position as well as the output connection of a given clip within this sequence //depends on how we look at this clip.// Does this clip apear as part of the global timeline, or did we discover it as contained within the meta-clip?
+
+!!solution requirements
+The baseline of any solution to this problem is clear: at the point where the query is issued, a context information is necessary; this context yields an access path from top level down to the object to be queried, and this access path constitutes the effective scope this object utilises for resolving the query.
+
+!!introducing a QueryFocus
+A secondary goal of the design here is to ease the use of the session query interface. Thus the proposal is to treat this context and access path as part of the current state. To do so, we can introduce a QueryFocus following the queries and remembering the access path; this focus should be maintained mostly automatically. It allows for stack-like organisation, to allow sub-queries without affecting the current focus, where the handling of such a temporary sub-focus is handled automatically by a scoped local (RAII) object. The focus follows the issued queries and re-binds as necessary.
+
+!!using QueryFocus as generic query interface
+Solving the problem this way has the nice side effect, that we get a quite natural location where to put an unspecific query interface: Just let the current QueryFocus expose the basic set of query API functions. Such an generic query interface can be seen as a complement to the query functions exposed on specific objects ("get me the clips within this track") according to the structure. Because a generic interface especially allows for writing simple diagnostics and discovery code, with only a weak link to the actual session structure.
+
+!Implementation strategy
+The solution is being built starting from the generic part, as the actual session structure isn't hard coded into the session implementation, but rather created by convention.
+The query API on specific objects (i.e. Session, Timeline, Sequence, Track and Clip) is then easily coded up on top, mostly with inlined one-liners of the kind
+{{{
+ITER getClips() { return QueryFocus::push(this).query<Clip>(); } 
+}}}
+To make this work, QueryFocus exposes an static API (and especially the focus stack is a singleton). The //current// QueryFocus object can easily re-bound to another point of interest (and ajusts the contained path info automatically), and the {{{push()}}}-function creates a local scoped object (which pops automatically).
+
+And last but not least: the difficult part of this whole concept is encapsulated and ''can be left out for now''. Because, according to Lumiera's [[roadmap|http://issues.lumiera.org/roadmap]], meta-clips are to be postponed until well into beta! Thus, we can start with a trivial (no-op) implementation, but immediately gain the benefit of making the relevant parts of the session implementation aware of the problem.
+
+{{red{WIP ... draft}}}
+
<<search>><<closeAll>><<permaview>><<newTiddler>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>
From 193fd2d66bb663eda7ebff1f44df60a79b7525b9 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 14 Oct 2009 05:39:49 +0200 Subject: [PATCH 003/377] Start the new Session structure with Timeline and Sequences --- src/proc/mobject/session/sequence.cpp | 48 +++++++++++++++++++++++ src/proc/mobject/session/sequence.hpp | 55 +++++++++++++++++++++++++++ src/proc/mobject/session/timeline.cpp | 48 +++++++++++++++++++++++ src/proc/mobject/session/timeline.hpp | 55 +++++++++++++++++++++++++++ 4 files changed, 206 insertions(+) create mode 100644 src/proc/mobject/session/sequence.cpp create mode 100644 src/proc/mobject/session/sequence.hpp create mode 100644 src/proc/mobject/session/timeline.cpp create mode 100644 src/proc/mobject/session/timeline.hpp diff --git a/src/proc/mobject/session/sequence.cpp b/src/proc/mobject/session/sequence.cpp new file mode 100644 index 000000000..8717c5bf9 --- /dev/null +++ b/src/proc/mobject/session/sequence.cpp @@ -0,0 +1,48 @@ +/* + Sequence - Compound of MObjects placed on a track tree. Building block of the Session + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/mobject/session/sequence.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "proc/mobject/placement.hpp" +//#include "proc/mobject/session/mobjectfactory.hpp" +//#include "proc/asset/track.hpp" + +namespace mobject { +namespace session { + + + + /** create an empty default configured Sequence */ + Sequence::Sequence () +// : track (makeDefaultTrack ()) +// , clips (0) + { + + } + + + + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/sequence.hpp b/src/proc/mobject/session/sequence.hpp new file mode 100644 index 000000000..038bbcb60 --- /dev/null +++ b/src/proc/mobject/session/sequence.hpp @@ -0,0 +1,55 @@ +/* + SEQUENCE.hpp - Compound of MObjects placed on a track tree. Building block of the Session + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef MOBJECT_SESSION_SEQUENCE_H +#define MOBJECT_SESSION_SEQUENCE_H + +//#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/placement.hpp" + +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + + + /** + * TODO type comment + */ + class Sequence + { + + public: + Sequence(); + + }; +///////////////////////////TODO currently just fleshing the API + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/timeline.cpp b/src/proc/mobject/session/timeline.cpp new file mode 100644 index 000000000..458220993 --- /dev/null +++ b/src/proc/mobject/session/timeline.cpp @@ -0,0 +1,48 @@ +/* + Timeline - independent top-level element of the Session + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/mobject/session/timeline.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "proc/mobject/placement.hpp" +//#include "proc/mobject/session/mobjectfactory.hpp" +//#include "proc/asset/track.hpp" + +namespace mobject { +namespace session { + + + + /** TODO??? */ + Timeline::Timeline () +// : track (makeDefaultTrack ()) +// , clips (0) + { + + } + + + + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/timeline.hpp b/src/proc/mobject/session/timeline.hpp new file mode 100644 index 000000000..03f666a25 --- /dev/null +++ b/src/proc/mobject/session/timeline.hpp @@ -0,0 +1,55 @@ +/* + TIMELINE.hpp - independent top-level element of the Session + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef MOBJECT_SESSION_TIMELINE_H +#define MOBJECT_SESSION_TIMELINE_H + +//#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/placement.hpp" + +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + + + /** + * TODO type comment + */ + class Timeline + { + + public: + Timeline(); + + }; +///////////////////////////TODO currently just fleshing the API + + +}} // namespace mobject::session +#endif From edbd54b0628ad48fefa1e101269e991a6762e095 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 14 Oct 2009 05:48:24 +0200 Subject: [PATCH 004/377] Initial planning regaring the QueryFocus --- src/proc/mobject/placement-ref.hpp | 3 + .../mobject/session/query-focus-stack.hpp | 54 ++++++++++++++++++ src/proc/mobject/session/query-focus.cpp | 44 ++++++++++++++ src/proc/mobject/session/query-focus.hpp | 57 +++++++++++++++++++ src/proc/mobject/session/query-resolver.hpp | 56 ++++++++++++++++++ src/proc/mobject/session/scope-path.cpp | 48 ++++++++++++++++ src/proc/mobject/session/scope-path.hpp | 56 ++++++++++++++++++ wiki/renderengine.html | 25 +++++++- 8 files changed, 340 insertions(+), 3 deletions(-) create mode 100644 src/proc/mobject/session/query-focus-stack.hpp create mode 100644 src/proc/mobject/session/query-focus.cpp create mode 100644 src/proc/mobject/session/query-focus.hpp create mode 100644 src/proc/mobject/session/query-resolver.hpp create mode 100644 src/proc/mobject/session/scope-path.cpp create mode 100644 src/proc/mobject/session/scope-path.hpp diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp index 9b8d8843a..86171e914 100644 --- a/src/proc/mobject/placement-ref.hpp +++ b/src/proc/mobject/placement-ref.hpp @@ -235,6 +235,9 @@ namespace mobject { }; + /** frequently-used shorthand */ + typedef PlacementRef RefPlacement; + } // namespace mobject diff --git a/src/proc/mobject/session/query-focus-stack.hpp b/src/proc/mobject/session/query-focus-stack.hpp new file mode 100644 index 000000000..499bf22d7 --- /dev/null +++ b/src/proc/mobject/session/query-focus-stack.hpp @@ -0,0 +1,54 @@ +/* + QUERY-FOCUS-STACK.hpp - management of current scope within the Session + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef MOBJECT_SESSION_QUERY_FOCUS_STACK_H +#define MOBJECT_SESSION_QUERY_FOCUS_STACK_H + +//#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/placement.hpp" + +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + + + /** + * TODO type comment + */ + class QueryFocusStack + { + + public: + + }; +///////////////////////////TODO currently just fleshing the API + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/query-focus.cpp b/src/proc/mobject/session/query-focus.cpp new file mode 100644 index 000000000..5169d46ab --- /dev/null +++ b/src/proc/mobject/session/query-focus.cpp @@ -0,0 +1,44 @@ +/* + QueryFocus - management of current scope within the Session + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/mobject/session/query-focus.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "proc/mobject/placement.hpp" +//#include "proc/mobject/session/mobjectfactory.hpp" +//#include "proc/asset/track.hpp" + +namespace mobject { +namespace session { + + + + /** TODO??? */ + QueryFocus::QueryFocus() + { } + + + + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp new file mode 100644 index 000000000..9d2cd9b61 --- /dev/null +++ b/src/proc/mobject/session/query-focus.hpp @@ -0,0 +1,57 @@ +/* + QUERY-FOCUS.hpp - management of current scope within the Session + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef MOBJECT_SESSION_QUERY_FOCUS_H +#define MOBJECT_SESSION_QUERY_FOCUS_H + +//#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/placement.hpp" +#include "proc/mobject/session/scope-path.hpp" + +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + + + /** + * TODO type comment + */ + class QueryFocus + { + ScopePath scopes_; + + public: + QueryFocus(); + + }; +///////////////////////////TODO currently just fleshing the API + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp new file mode 100644 index 000000000..da2b3a813 --- /dev/null +++ b/src/proc/mobject/session/query-resolver.hpp @@ -0,0 +1,56 @@ +/* + QUERY-RESOLVER.hpp - interface for discovering contents of a scope + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef MOBJECT_SESSION_QUERY_RESOLVER_H +#define MOBJECT_SESSION_QUERY_RESOLVER_H + +//#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/placement.hpp" + +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + + + /** + * TODO type comment + */ + class QueryResolver + { + + public: + + virtual ~QueryResolver() {} + + }; +///////////////////////////TODO currently just fleshing the API + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp new file mode 100644 index 000000000..e135467c4 --- /dev/null +++ b/src/proc/mobject/session/scope-path.cpp @@ -0,0 +1,48 @@ +/* + ScopePath - logical access path down from Session root + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/mobject/session/scope-path.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "proc/mobject/placement.hpp" +//#include "proc/mobject/session/mobjectfactory.hpp" +//#include "proc/asset/track.hpp" + +namespace mobject { +namespace session { + + + + /** TODO??? */ + ScopePath::ScopePath () +// : track (makeDefaultTrack ()) +// , clips (0) + { + + } + + + + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp new file mode 100644 index 000000000..f5366a457 --- /dev/null +++ b/src/proc/mobject/session/scope-path.hpp @@ -0,0 +1,56 @@ +/* + SCOPE-PATH.hpp - logical access path down from Session root + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef MOBJECT_SESSION_SCOPE_PATH_H +#define MOBJECT_SESSION_SCOPE_PATH_H + +//#include "proc/mobject/mobject.hpp" +#include "proc/mobject/placement-ref.hpp" + +#include +//#include + +using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + + + /** + * TODO type comment + */ + class ScopePath + { + vector path_; + + public: + ScopePath(); + + }; +///////////////////////////TODO currently just fleshing the API + + +}} // namespace mobject::session +#endif diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 59537d71a..67ff846c8 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3381,6 +3381,25 @@ Viewed as a micro program, the processing patterns are ''weak typed'' &mdash
a given Render Engine configuration is a list of Processors. Each Processor in turn contains a Graph of ProcNode.s to do the acutal data processing. In order to cary out any calculations, the Processor needs to be called with a StateProxy containing the state information for this RenderProcess
 
+
+
When querying contents of the session or sub-containers within the session, the QueryFocus follows the current point-of-query. As such queries can be issued to explore the content of container-like objects holding other MObjects, the focus is always attached to a container, which also acts as [[scope|PlacementScope]] for the contained objects. QueryFocus is an implicit state (the current point of interrest). This sate especially remembers the path down from the root of the HighLevelModel, which was used to access the current scope. Because this path constitutes a hierarchy of scopes, it can be relevant for querying and resolving placement properties. (&rarr; SessionStructureQuery)
+
+!provided operations
+* attach to a given scope-like object. Causes the current focus to //navigate//
+* open a new focus, thereby pushing the existing focus onto a ''focus stack''
+* return (pop) to the previous focus
+* get the current scope, which is implemented as Placement
+* get the current ScopePath from root (session globals) down to the current scope
+
+!implementation notes
+we provide a static access API, meaning that there is a singleton behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. This link works by the current session grabbing the query focus and attaching to it. This attachment is shallow, i.e. the QueryFocus doesn't have knowledge about the session, which allows the focus to be unit tested.
+
+The stack of scopes must not be confused with the ScopePath. Each single frame on the stack is a QueryFocus and as such contains a current ScopePath. The purpose of the stack is to make the scope handling mostly transparent; especially this stack allows to write dedicated query functions directed at a given object: they work by pushing and then navigating to the object to use as new starting point. Not every placement is a scope, but every placement has an immediately enclosing scope, which is used as //current scope.//
+
+!!!simplifications
+The full implementation of this scope navigation is tricky, especially when it comes to determining the relation of two positions. It should be ''postponed'' and replaced by a ''dummy'' (no-op) implementation for the first integration round.
+
+
//obviously, getting this one to work requires quite a lot of technical details to be planned and implemented.// This said...
 The intention is to get much more readable ("declarative") and changeable configuration as by programming the decision logic literately within the implementation of some object.
@@ -3831,7 +3850,7 @@ It will contain a global video and audio out pipe, just one EDL with a single tr
 &rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
 
-
+
The frontside interface of the session allows to query for contained objects; it is used to discover the structure and contents of the currently opened session/project. Access point is the public API of the Session class, which, besides exposing those queries, also provides functionality for adding and removing session contents.
 
 !discovering structure
@@ -3840,10 +3859,10 @@ Thus, at any point, we can explore the structure by asking for //contained objec
 So, clearly, there are two flavours of such an contents exploration query: it could either be issued as an dedicated member function on the public API of the respective container object, e.g. {{{Track::getClips()}}} &mdash; or it could be exposed as generic query function, relying on the implicit knowledge of the //current location//&nbsp; rather.
 
 !problem of context and access path
-The (planned) session structure of Lumiera allows for quite some flexibility, which, of course comes at a price tag. Especially, as there can be multiple independent top level timelines, and as a given sequence can be used simultaneously within multiple timelines and even as virtual media within a [[meta-clip|VirtualClip]], and &mdash; moreover &mdash; properties of any Placement are rather queried and discovered within the PlacementScope of this object, as a consequence, the discovered values may depend on //how you look at this object.// More specifically, it depends on the ''access path'' used to discover this object, because this path constitutes the actual scope visible to this object.
+The (planned) session structure of Lumiera allows for quite some flexibility, which, of course comes at a price tag. Especially, as there can be multiple independent top level timelines, where a given sequence can be used simultaneously within multiple timelines and even as virtual media within a [[meta-clip|VirtualClip]], and moreover, as properties of any Placement are rather queried and discovered within the PlacementScope of this object &mdash; consequently the discovered values may depend on //how you look at this object.// More specifically, it depends on the ''access path'' used to discover this object, because this path constitutes the actual scope visible to this object.
 
 To give an example, let's assume a clip within a sequence, and this sequence is both linked to the top-level timeline, but also used within a meta-clip. (see the drawing &rarr; [[here|PlacementScope]])
-In this case, the sequence has an 1:n [[binding|BindingMO]]. A binding is (by definition) also a PlacementScope, and in the case of the sequence, the binding also translates //logical// output designations into global pipes of the top-level timeline, while in the other case they get mapped onto "channels" of the virtual media used by the virtual clip. Thus, the absolute time position as well as the output connection of a given clip within this sequence //depends on how we look at this clip.// Does this clip apear as part of the global timeline, or did we discover it as contained within the meta-clip?
+In this case, the sequence has an 1:n [[binding|BindingMO]]. A binding is (by definition) also a PlacementScope, and, incidentally, in the case of binding the sequence into a timeline, the binding also translates //logical// output designations into global pipes found within the timeline, while otherwise they get mapped onto "channels" of the virtual media used by the virtual clip. Thus, the absolute time position as well as the output connection of a given clip within this sequence //depends on how we look at this clip.// Does this clip apear as part of the global timeline, or did we discover it as contained within the meta-clip?
 
 !!solution requirements
 The baseline of any solution to this problem is clear: at the point where the query is issued, a context information is necessary; this context yields an access path from top level down to the object to be queried, and this access path constitutes the effective scope this object utilises for resolving the query.

From 65f100c1a22b7468478ab3ab7af0ed3dc9046092 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Wed, 14 Oct 2009 06:18:25 +0200
Subject: [PATCH 005/377] start 2 unit tests for scope handling

---
 tests/43session.tests                         |  8 ++
 .../proc/mobject/query-focus-test.cpp         | 95 +++++++++++++++++++
 .../proc/mobject/scope-path-test.cpp          | 73 ++++++++++++++
 3 files changed, 176 insertions(+)
 create mode 100644 tests/components/proc/mobject/query-focus-test.cpp
 create mode 100644 tests/components/proc/mobject/scope-path-test.cpp

diff --git a/tests/43session.tests b/tests/43session.tests
index 083df1c4e..2999d6d68 100644
--- a/tests/43session.tests
+++ b/tests/43session.tests
@@ -55,6 +55,14 @@ PLANNED "PlacementRef_test" PlacementRef_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/lumitime.hpp"
+//#include "proc/mobject/placement-ref.hpp"
+#include "proc/mobject/placement-index.hpp"
+#include "proc/mobject/test-dummy-mobject.hpp"
+//#include "lib/util.hpp"
+
+//#include 
+//#include 
+
+//using util::isSameObject;
+//using lumiera::Time;
+//using std::string;
+//using std::cout;
+//using std::endl;
+
+
+namespace mobject {
+namespace session {
+namespace test    {
+  
+  using namespace mobject::test;
+  typedef TestPlacement PSub;
+  
+  
+  /**********************************************************************************
+   * @test handling of current query focus when navigating a system of nested scopes.
+   *       Using a pseudo-session (actually just a PlacementIndex), this test
+   *       creates some nested scopes and then checks moving the "current scope".
+   *       
+   * @see  mobject::PlacementIndex
+   * @see  mobject::session::ScopePath
+   * @see  mobject::session::QueryFocus
+   */
+  class QueryFocus_test : public Test
+    {
+      
+      virtual void
+      run (Arg) 
+        {
+          PSub p1(*new TestSubMO21);
+          PSub p2(*new TestSubMO21);
+          PSub p3(*new TestSubMO21);
+          PSub p4(*new TestSubMO21);
+          PSub p5(*new TestSubMO21);
+          
+          // Prepare an (test)Index backing the PlacementRefs
+          typedef shared_ptr PIdx;
+          PIdx index (PlacementIndex::create());
+          PMO& root = index->getRoot();
+          reset_PlacementIndex(index);
+
+          index->insert (p1, root);
+          index->insert (p2,  p1 );
+          index->insert (p3,  p2 );
+          index->insert (p4,  p3 );
+          index->insert (p5,  p4 );
+          
+          UNIMPLEMENTED ("unit test to cover query focus management");
+          
+//??      ASSERT (0 == index->size());
+          reset_PlacementIndex();
+        }
+          
+    };
+  
+  
+  /** Register this test class... */
+  LAUNCHER (QueryFocus_test, "unit session");
+  
+  
+}}} // namespace mobject::session::test
diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp
new file mode 100644
index 000000000..3f96612ed
--- /dev/null
+++ b/tests/components/proc/mobject/scope-path-test.cpp
@@ -0,0 +1,73 @@
+/*
+  ScopePath(Test)  -  verify handling of logical access path down from Session root
+ 
+  Copyright (C)         Lumiera.org
+    2009,               Hermann Vosseler 
+ 
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ 
+* *****************************************************/
+
+
+#include "lib/test/run.hpp"
+//#include "lib/lumitime.hpp"
+//#include "proc/mobject/placement-ref.hpp"
+//#include "proc/mobject/placement-index.hpp"
+//#include "proc/mobject/test-dummy-mobject.hpp"
+//#include "lib/util.hpp"
+
+//#include 
+//#include 
+
+//using util::isSameObject;
+//using lumiera::Time;
+//using std::string;
+//using std::cout;
+//using std::endl;
+
+
+namespace mobject {
+namespace session {
+namespace test    {
+  
+//  using namespace mobject::test;
+//  typedef TestPlacement PSub;
+  
+  
+  /***************************************************************************
+   * @test properties and behaviour of the path of nested scopes.
+   *       Using a pseudo-session (actually just a PlacementIndex), this test
+   *       creates some nested scopes and executes navigation moves on them.
+   * @see  mobject::Placement
+   * @see  mobject::session::ScopePath
+   * @see  mobject::session::QueryFocus
+   */
+  class ScopePath_test : public Test
+    {
+      
+      virtual void
+      run (Arg) 
+        {
+          UNIMPLEMENTED ("unit test regarding placement scope handling");
+        }
+          
+    };
+  
+  
+  /** Register this test class... */
+  LAUNCHER (ScopePath_test, "unit session");
+  
+  
+}}} // namespace mobject::session::test

From d193fbf920419ac8b641765159a97c90912f249a Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Fri, 16 Oct 2009 01:54:38 +0200
Subject: [PATCH 006/377] Planning the QueryFocus in more detail

---
 doc/devel/uml/class128645.html   |    4 +-
 doc/devel/uml/class152069.html   |   22 +
 doc/devel/uml/class152197.html   |   20 +
 doc/devel/uml/class152325.html   |   20 +
 doc/devel/uml/class152453.html   |   24 +
 doc/devel/uml/class152581.html   |   22 +
 doc/devel/uml/class152709.html   |   21 +
 doc/devel/uml/class152837.html   |   24 +
 doc/devel/uml/class152965.html   |   21 +
 doc/devel/uml/class153093.html   |   20 +
 doc/devel/uml/class153221.html   |   20 +
 doc/devel/uml/class153349.html   |   24 +
 doc/devel/uml/class153477.html   |   24 +
 doc/devel/uml/class153605.html   |   24 +
 doc/devel/uml/class153733.html   |   24 +
 doc/devel/uml/class153861.html   |   26 +
 doc/devel/uml/class153989.html   |   22 +
 doc/devel/uml/classdiagrams.html |    3 +
 doc/devel/uml/classes.html       |   16 +
 doc/devel/uml/classes_list.html  |   16 +
 doc/devel/uml/fig134021.png      |  Bin 24839 -> 24951 bytes
 doc/devel/uml/fig136325.png      |  Bin 0 -> 21713 bytes
 doc/devel/uml/fig136453.png      |  Bin 0 -> 4250 bytes
 doc/devel/uml/fig136581.png      |  Bin 0 -> 15517 bytes
 doc/devel/uml/index.html         |   77 +-
 doc/devel/uml/index_60.html      |   20 +-
 doc/devel/uml/index_65.html      |    2 +-
 doc/devel/uml/index_66.html      |    1 +
 doc/devel/uml/index_67.html      |   40 +-
 doc/devel/uml/index_68.html      |    1 +
 doc/devel/uml/index_69.html      |    2 +-
 doc/devel/uml/index_70.html      |    3 +-
 doc/devel/uml/index_72.html      |    3 +-
 doc/devel/uml/index_73.html      |    6 +-
 doc/devel/uml/index_76.html      |    1 +
 doc/devel/uml/index_77.html      |    4 +-
 doc/devel/uml/index_79.html      |    3 +-
 doc/devel/uml/index_80.html      |    6 +
 doc/devel/uml/index_81.html      |    3 +
 doc/devel/uml/index_83.html      |   19 +-
 doc/devel/uml/index_84.html      |   10 +-
 doc/devel/uml/index_86.html      |    8 +-
 doc/devel/uml/packages.html      |    5 +-
 uml/lumiera/128261               | 1410 +------------------------
 uml/lumiera/128517               |   19 +-
 uml/lumiera/132229               | 1668 ++++++++++++++++++++++++++++++
 uml/lumiera/132357               |  209 ++++
 uml/lumiera/132485               |   75 ++
 uml/lumiera/136325.diagram       |  100 ++
 uml/lumiera/136453.diagram       |   19 +
 uml/lumiera/136581.diagram       |   76 ++
 uml/lumiera/5.session            |   20 +-
 uml/lumiera/lumiera.prj          |    2 +-
 wiki/renderengine.html           |    6 +-
 54 files changed, 2732 insertions(+), 1483 deletions(-)
 create mode 100644 doc/devel/uml/class152069.html
 create mode 100644 doc/devel/uml/class152197.html
 create mode 100644 doc/devel/uml/class152325.html
 create mode 100644 doc/devel/uml/class152453.html
 create mode 100644 doc/devel/uml/class152581.html
 create mode 100644 doc/devel/uml/class152709.html
 create mode 100644 doc/devel/uml/class152837.html
 create mode 100644 doc/devel/uml/class152965.html
 create mode 100644 doc/devel/uml/class153093.html
 create mode 100644 doc/devel/uml/class153221.html
 create mode 100644 doc/devel/uml/class153349.html
 create mode 100644 doc/devel/uml/class153477.html
 create mode 100644 doc/devel/uml/class153605.html
 create mode 100644 doc/devel/uml/class153733.html
 create mode 100644 doc/devel/uml/class153861.html
 create mode 100644 doc/devel/uml/class153989.html
 create mode 100644 doc/devel/uml/fig136325.png
 create mode 100644 doc/devel/uml/fig136453.png
 create mode 100644 doc/devel/uml/fig136581.png
 create mode 100644 uml/lumiera/132229
 create mode 100644 uml/lumiera/132357
 create mode 100644 uml/lumiera/132485
 create mode 100644 uml/lumiera/136325.diagram
 create mode 100644 uml/lumiera/136453.diagram
 create mode 100644 uml/lumiera/136581.diagram

diff --git a/doc/devel/uml/class128645.html b/doc/devel/uml/class128645.html
index 27413648f..5f94489fb 100644
--- a/doc/devel/uml/class128645.html
+++ b/doc/devel/uml/class128645.html
@@ -23,7 +23,9 @@
 
Operation resolve

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

Declaration :

  • Uml : + resolve() : ExplicitPlacement [ProcessingLayer::MObject]&
  • C++ : public: ExplicitPlacement [ProcessingLayer::MObject]& resolve ()
Relation subject (<unidirectional association>)

Placement acts as smart pointer

Declaration :

  • Uml : # subject : MObject, multiplicity : 1
  • C++ : protected: MObject* subject
Operation chain

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

Declaration :

  • Uml : + chain(in style : ) :
  • C++ : public: chain (const & style)
-
Relation chain (<unidirectional association>)

Chain of additional Placements further constraining the position of this MObject

Declaration :

+
Relation chain (<unidirectional association>)

Chain of additional Placements further constraining the position of this MObject

Declaration :

+
Relation <unidirectional association>

Declaration :

  • Uml : # : Id
  • C++ : protected: Id*

Stereotype: has_a

+

All public operations : chain , resolve

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

+ + + + +

Declaration :

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

+ + + + +

Declaration :

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

+ + + + +

Declaration :

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

+ + + + +

Declaration :

  • C++ : template<class MO> class PlacementRef
+ +
Relation id_ (<unidirectional association>)

Declaration :

  • Uml : - id_ : Id, multiplicity : 1
  • C++ : private: Id* id_

Stereotype: holds

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

+ + + + +

Declaration :

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

+ + + + +

Declaration :

  • C++ : class LuidH

Directly inherited by : Id

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

+ + + + +

Declaration :

  • C++ : template<class MO> class MObjectRef : public Handle
+ +
Relation pRef_ (<unidirectional association>)

Declaration :

Stereotype: holds

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

+ + + + +

Declaration :

  • C++ : class Handle

Directly inherited by : MObjectRef

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

+ + + + +

Declaration :

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

+ + + + +

Declaration :

  • C++ : class P
+ diff --git a/doc/devel/uml/class153349.html b/doc/devel/uml/class153349.html new file mode 100644 index 000000000..48617516d --- /dev/null +++ b/doc/devel/uml/class153349.html @@ -0,0 +1,24 @@ + + + + + + +Class Scope + + + + + +
Class Scope
+

+ + + + +

Declaration :

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

Declaration :

Stereotype: holds

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

+ + + + +

Declaration :

  • C++ : class ScopePath
+ +
Relation path_ (<directional composition>)

Declaration :

Stereotype: vector

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

+ + + + +

Declaration :

  • C++ : class QueryFocus
+ +
Relation scopes (<unidirectional association>)

Declaration :

Stereotype: has_a

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

+ + + + +

Declaration :

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

Declaration :

Stereotype: vector

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

+ + + + +

Declaration :

  • C++ : class ScopeLocator

Stereotype: singleton

+
+ +
Relation <unidirectional association>

Declaration :

+
Relation <unidirectional association>

Declaration :

Stereotype: use

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

+ + + + +

Declaration :

  • C++ : class QueryResolver
  • Java : package interface QueryResolver
  • Php : interface QueryResolver

Directly inherited by : PlacementIndex

+

Stereotype: interface

+ + diff --git a/doc/devel/uml/classdiagrams.html b/doc/devel/uml/classdiagrams.html index bfd20dbab..522259723 100644 --- a/doc/devel/uml/classdiagrams.html +++ b/doc/devel/uml/classdiagrams.html @@ -23,15 +23,18 @@ Command structure Controller Entities File MappingShows whats used to access Frames +Focus of Query HierarchyLumiera Exception hierarchy In Memory Database interface components Layer Separation Interface Media-Asset Relations +MObjectRef Proc-Asset Relations Render Entities Render Mechanics Rules access +Session backbone Session structure StateAdapter composition Stream Type Framework diff --git a/doc/devel/uml/classes.html b/doc/devel/uml/classes.html index ebec4c117..a6a2fe704 100644 --- a/doc/devel/uml/classes.html +++ b/doc/devel/uml/classes.html @@ -27,6 +27,7 @@ AssetManagerboundaryFacade for the Asset subsystem AutoAutomation data for some parameter (i.e. a time varying function) BackendCache +Binding BuffHandle BuffTable Buildableinterface @@ -83,7 +84,9 @@ FrameDescriptorinterfaceA FrameDescriptor implements the higher level interfaces for frames. Further refinements are made by subclassing and policy classes FrameReference GLBuf +Handle HandlingPatterninterface +Id ImplFacade InstanceHandle InterpolatorProvides the implementation for getting the acutal value of a time varying or automated effect/plugin parameter @@ -95,6 +98,7 @@ Lock Lock Logic +LuidH Mask Mediakey abstraction: media-like assets MediaAccessFacadeboundaryprovides functions for querying (opening) a media file, detecting the channels or streams found within this file, etc. Delegating to the actual backend functions @@ -103,18 +107,22 @@ Metakey abstraction: metadata and organisational asset Meta MObjectinterface +MObjectRef Monitor Mutationfunc MutexI provided a reworked Mutex class in my Cinelerra2 repository NodeCreatorToolThis Tool implementation plays the central role in the buld process: given a MObject from Session, it is able to attach ProcNodes to the render engine under construction such as to reflect the properties of the MObject in the actual render. NodeWiring OperationBase +P ParamAccessor ParameterDescriptor and access object for a plugin parameter. Parameters may be provided with values from the session, and this values may be automated. ParamProviderinterfaceA facility to get the actual value of a plugin/effect parameter PathManagerWhile building a render engine, this Strategy class decides on the actual render strategy in accordance to the current controller settings (system state) Pipestructural asset representing a basic building block within the high level model: a port for building a processing chain and generating media output Placementinterfaceused to specify the position of a MObject in the EDL. This can be done in various ways (absolute, relative).
Placement at the same time acts as (refcounting) smart pointer for accessing the MObject. +PlacementIndex +PlacementRef PlayControl PlayheadCursor Plug @@ -132,8 +140,11 @@ Proxy PullInput QueryCache +QueryFocus +QueryFocusStack QueryHandlerinterface QueryHandlerImpl +QueryResolverinterface ReadSource RedoLast RelativeLocation @@ -144,16 +155,21 @@ RenderTask ResolverBase Scheduler +Scope +ScopeLocatorsingleton +ScopePath Segment Segmentation SegmentationToolTool implementation for deriving a partitioning of the current timeline such, that each segement has a constant configuration. "Constant" means here, that any remaining changes over time can be represented by automation solely, without the need to change the node connections. Seq +Sequence Sequence Serializeractor ServiceImpl SessionPrimary Interface for all editing tasks.
The session contains defaults, all the assets being edited, and a set of EDL with the individual MObjects to be manipulated and rendered. SessionImplImplementation class for the Session interface SessManager +shared_ptr SimpleClipElementary clip consisting of only one media stream SmartPointerauxiliary SourceSource Node: represents a media source to pull data from. diff --git a/doc/devel/uml/classes_list.html b/doc/devel/uml/classes_list.html index 173ec52e4..2378c288f 100644 --- a/doc/devel/uml/classes_list.html +++ b/doc/devel/uml/classes_list.html @@ -28,6 +28,7 @@ AssetManager
Auto
BackendCache
+Binding
BuffHandle
BuffTable
Buildable
@@ -84,7 +85,9 @@ FrameDescriptor
FrameReference
GLBuf
+Handle
HandlingPattern
+Id
ImplFacade
InstanceHandle
Interpolator
@@ -96,6 +99,7 @@ Lock
Lock
Logic
+LuidH
Mask
Media
MediaAccessFacade
@@ -104,18 +108,22 @@ Meta
Meta
MObject
+MObjectRef
Monitor
Mutation
Mutex
NodeCreatorTool
NodeWiring
OperationBase
+P
ParamAccessor
Parameter
ParamProvider
PathManager
Pipe
Placement
+PlacementIndex
+PlacementRef
PlayControl
PlayheadCursor
Plug
@@ -133,8 +141,11 @@ Proxy
PullInput
QueryCache
+QueryFocus
+QueryFocusStack
QueryHandler
QueryHandlerImpl
+QueryResolver
ReadSource
RedoLast
RelativeLocation
@@ -145,16 +156,21 @@ RenderTask
ResolverBase
Scheduler
+Scope
+ScopeLocator
+ScopePath
Segment
Segmentation
SegmentationTool
Seq
+Sequence
Sequence
Serializer
ServiceImpl
Session
SessionImpl
SessManager
+shared_ptr
SimpleClip
SmartPointer
Source
diff --git a/doc/devel/uml/fig134021.png b/doc/devel/uml/fig134021.png index edd5445309c667b0a405a52bc64987340ca07910..5405d20102a94b5be2e2786bca2b7ad0754f2ace 100644 GIT binary patch literal 24951 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

1()nGz?NGQkDgbk{gCK0>fK^6&c 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

xbqeMZyI-;Q=GC~nJ+FbUn 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 j-?`*RR{1}l9>0YwjWk=(68Uq%dQw!! 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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 : allocation, vframe, toolfactory, hub, buildable, abstractmo, exitnode, pathmanager, track, meta, fixedlocation, relativelocation, controllerfacade, rendergraph, pluginadapter, explicitplacement, auto, glrender, arender, renderstate, label, nodecreatertool, projector, interpolator, paramprovider, mask, mobject, source, frame, effect, buildertool, segmentationtool, link, parameter, renderengine, glbuf, procnode, stateproxy, edl, fixture, glpipe, main, conmanager, clip, vrender, placement, sessionimpl, builderfacade, aframe, assembler, trafo

+

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

Artifact main

Stereotype: source

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

2.3 Package MObject

+ +

2.3.1 Package Session

+
-

2.3.1 Class View Session

+

2.3.1.1 Class View Session parts

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

2.3.1.2 Class View Object ref

+
+ +

+

MObjectRef



+
+
Class Id
+
Class LuidH
+
+
+ +

2.3.1.3 Class View Datastructure

+
+ +

+

Session backbone



+
+
Class Sequence
+
Class Binding
+
+
+ +

2.3.2 Package Placement

+
+ +

2.3.2.1 Class View Scopes

+
+ +

+

Focus of Query



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

2.3.2 Package Builder

+

2.3.3 Package Builder

-

2.3.2.1 Class View Builder Workings

+

2.3.3.1 Class View Builder Workings

build process



This figure shows the process of building and starting a RenderEngine

-

2.3.2.1.1 Activity building the Engine

+

2.3.3.1.1 Activity building the Engine

Pre Condition :

    Post Condition :

      @@ -1011,7 +1053,7 @@ undo

      Defined in building the Engine

      Pre Condition :

        Post Condition :

          Behavior :

            Flow <flow>

            From configure Tools To fork activity node

            Weight :

              Guard :

                Selection :

                  Transformation :

                    -

                    2.3.2.1.1.1 Expansion region establish partitioning

                    +

                    2.3.3.1.1.1 Expansion region establish partitioning

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

                    Defined in building the Engine

                    Flow <flow>

                    From fork activity node To segment Tool

                    Weight :

                      Guard :

                        Selection :

                          Transformation :

                            Flow <flow>

                            From fork activity node To build Tool

                            Weight :

                              Guard :

                                Selection :

                                  Transformation :

                                    -

                                    2.3.2.1.1.2 Expansion region build Processors

                                    +

                                    2.3.3.1.1.2 Expansion region build Processors

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

                                    2.3.3 Use Case View config examples

                                    +

                                    2.3.4 Use Case View config examples

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

                                    type :TypeHandler

                                    + +

                                    5.4 Package Containers

                                    +
                                    + +

                                    5.4.1 Class View Custom holders

                                    +
                                    +
                                    Class Handle
                                    +
                                    Class P
                                    +
                                    +
                                    -

                                    5.4 Class View error

                                    +

                                    5.5 Class View error

                                    @@ -1518,7 +1570,7 @@ undo -

                                    5.5 Class View Service Components

                                    +

                                    5.6 Class View Service Components

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

                                    5.6 Class View Posix Threads Abstraction

                                    +

                                    5.7 Class View Posix Threads Abstraction

                                    C++ wrapers for pthreads

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

                                    5.7 Class View SmartPointers

                                    +

                                    5.8 Class View SmartPointers

                                    +
                                    diff --git a/doc/devel/uml/index_60.html b/doc/devel/uml/index_60.html index ab6befaf1..d00995e12 100644 --- a/doc/devel/uml/index_60.html +++ b/doc/devel/uml/index_60.html @@ -17,8 +17,8 @@ - + @@ -28,8 +28,8 @@ - + @@ -45,20 +45,20 @@ + - - - - - - + - - + + + + + +
                                    NameKindDescription
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <flow>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    <transition>transition
                                    diff --git a/doc/devel/uml/index_65.html b/doc/devel/uml/index_65.html index 38dfaced6..25d659f38 100644 --- a/doc/devel/uml/index_65.html +++ b/doc/devel/uml/index_65.html @@ -60,9 +60,9 @@ 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 2788567d7..36ad84a5e 100644 --- a/doc/devel/uml/index_66.html +++ b/doc/devel/uml/index_66.html @@ -23,6 +23,7 @@ backend-componentscomponent diagram BackendCacheclass BackendLayerpackage +Bindingclass BuffHandleclass BuffTableclass buildoperation diff --git a/doc/devel/uml/index_67.html b/doc/devel/uml/index_67.html index a8a98a5d6..693346ea5 100644 --- a/doc/devel/uml/index_67.html +++ b/doc/devel/uml/index_67.html @@ -29,44 +29,44 @@ Categoryclasstree like classification of Assets categoryartifacttree like classification of Assets causeattributea copy of the first exception encountered in this exception chain -chainoperationcreate and add another Placement for this media object, thus increasingly constraining the (possible) position of this object. chainrelationChain of additional Placements further constraining the position of this MObject +chainoperationcreate and add another Placement for this media object, thus increasingly constraining the (possible) position of this object. 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 clearoperationclear current session contents
                                    without resetting overall session config.
                                    Afterwards, the session will contain only one
                                    empty EDL, while all Assets are retained.
                                    client codecomponent Clipclassbookkeeping (asset) view of a media clip. -clipartifactbookkeeping (asset) view of a media clip. clipartifacta Media Clip +clipartifactbookkeeping (asset) view of a media clip. Clipclass clipsrelation closureattribute @@ -109,6 +109,7 @@ connectopaque activity action constraintartifactLocatingPin representing an directive by the user that
                                    must not be violated Constraintclass +Containerspackage controlpackagesourcecode package

                                    The Processing and Render Controller,
                                    and the Proc-Layer dispatcher ControlpackageCommand handling, Proc-Layer dispatcher, controller and administrative facilities Controllercomponent @@ -124,6 +125,7 @@ currentclass instance currentrelationStandard access path to get at the current session via the Session Manager, which acts as a "PImpl" smart pointer currFramerelation +Custom holdersclass view diff --git a/doc/devel/uml/index_68.html b/doc/devel/uml/index_68.html index 580695e3a..9866cde59 100644 --- a/doc/devel/uml/index_68.html +++ b/doc/devel/uml/index_68.html @@ -20,6 +20,7 @@ Datasetclassmeta asset describing a collection of control data datasetartifactmeta asset describing a collection of control data datasrcrelationThe predecessor in a processing pipeline, i.e. a source to get data to be processed +Datastructureclass view DBclassImplementation of the registry holding all Asset instances known to the Asset Manager subsystem. As of 8/2007 implemented by a hashtable. dbartifactregistry holding known Asset instances. defaultsrelation diff --git a/doc/devel/uml/index_69.html b/doc/devel/uml/index_69.html index 3c4e4f7af..0c6f365e7 100644 --- a/doc/devel/uml/index_69.html +++ b/doc/devel/uml/index_69.html @@ -23,8 +23,8 @@ 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 edlsrelation EffectclassEffect or media processing component -effectartifactEDL representation of a pluggable and automatable effect. effectartifactEffect or media processing component +effectartifactEDL representation of a pluggable and automatable effect. Effectclass effective timeline (Fixture)node effectiveTimelinerelation diff --git a/doc/devel/uml/index_70.html b/doc/devel/uml/index_70.html index 93fe59aa1..e177ed876 100644 --- a/doc/devel/uml/index_70.html +++ b/doc/devel/uml/index_70.html @@ -39,9 +39,10 @@ fixtureartifactthe (low level) representation of the EDL with concrete placement data Fixturecomponent Fixtureclass +Focus of Queryclass diagram fork activity nodefork activity node -fork pseudo statefork pseudo state fork pseudo statefork pseudo state +fork pseudo statefork pseudo state FrameclassFrames are just a low level lump of continous memory, most parts are opaque. Frames are memory sensitive, they will be small constant sized structures which can be efficently managed in a pool. Framenode FrameclassTODO: how to relate to Cehteh's Frame entity in the Backend?
                                    The latter is the fundamental Frame entity, wheras this Object rather represents a buffer set containing frame date diff --git a/doc/devel/uml/index_72.html b/doc/devel/uml/index_72.html index 7356cb17f..2d011b5a4 100644 --- a/doc/devel/uml/index_72.html +++ b/doc/devel/uml/index_72.html @@ -17,6 +17,7 @@ + @@ -24,8 +25,8 @@ - +
                                    NameKindDescription
                                    Handleclass
                                    handlerelationweak pointer
                                    handlesrelation
                                    handles_availableattributeinitialized to the maximum number of filehandles the backend may use for mapped files. When no handles are available, the handle which is last in the handles list is closed and (re-)used.
                                    Else this number is decremented for each new filehandle used and incremented for any one explicitly freed.
                                    Hierarchyclass diagramLumiera Exception hierarchy
                                    howtoProcoperation@return descriptor how to build a render pipeline corresponding to this media
                                    hubartifactspecial ProcNode used to build data distributing connections
                                    HUEclass instance
                                    HUEclass instance
                                    HUEclass instance
                                    diff --git a/doc/devel/uml/index_73.html b/doc/devel/uml/index_73.html index 1e264158e..6fa319735 100644 --- a/doc/devel/uml/index_73.html +++ b/doc/devel/uml/index_73.html @@ -20,12 +20,14 @@ idattributeAsset primary key. IDattribute IDentry point pseudo state +Idclass +id_relation ImplFacadeclass In Memory Databaseclass diagram inFixtureactivity action pin -inputclass instance -inputclass instance inputclass instance +inputclass instance +inputclass instance instanceoperation InstanceHandleclass instructionsrelation diff --git a/doc/devel/uml/index_76.html b/doc/devel/uml/index_76.html index bdd59ab29..3eaed2f2b 100644 --- a/doc/devel/uml/index_76.html +++ b/doc/devel/uml/index_76.html @@ -34,6 +34,7 @@ Lockclass Logicclass longDescattributeuser visible qualification of the thing, unit or concept represented by this asset. perferably "in one line". To be localized. +LuidHclass Lumieraartifactthe main executable to be built lumierapackage diff --git a/doc/devel/uml/index_77.html b/doc/devel/uml/index_77.html index bef78819f..908bede9a 100644 --- a/doc/devel/uml/index_77.html +++ b/doc/devel/uml/index_77.html @@ -34,13 +34,15 @@ 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 mobjectartifactKey Abstraction: A Media Object in the Session mobjectpackagesourcecode package

                                    MObject Subsystem
                                    including the Session (EDL), Builder and Processing Controller MObjectpackage MObjectclass +MObjectRefclass diagram +MObjectRefclass Monitorclass multichannel clipobject diagram Mutationclass diff --git a/doc/devel/uml/index_79.html b/doc/devel/uml/index_79.html index 0f0da521d..c557cd0be 100644 --- a/doc/devel/uml/index_79.html +++ b/doc/devel/uml/index_79.html @@ -17,11 +17,12 @@ + - + diff --git a/doc/devel/uml/index_80.html b/doc/devel/uml/index_80.html index fc2fcf572..738c03906 100644 --- a/doc/devel/uml/index_80.html +++ b/doc/devel/uml/index_80.html @@ -17,6 +17,7 @@
                                    NameKindDescription
                                    Object refclass view
                                    offsetattributeOffset the actual position by this (time) value relative to the anchor point. TODO: Representation?
                                    OperationBaseclass
                                    orgattributeorigin or authorship id. Can be a project abbreviation, a package id or just the authors nickname or UID. This allows for the compnent name to be more generic (e.g. "blur"). Default for all assets provided by the core Lumiera codebase is "lumi".
                                    ouputclass instance
                                    ouputclass instance
                                    ouputclass instance
                                    ouputclass instance
                                    outPortrelationthe Port this MObject wants to be conected to
                                    Overviewcomponent diagramThis drawing shows the top level compoents and relations
                                    + @@ -25,6 +26,7 @@ + @@ -32,7 +34,10 @@ + + + @@ -47,6 +52,7 @@ + diff --git a/doc/devel/uml/index_81.html b/doc/devel/uml/index_81.html index 6367201fd..7668e971e 100644 --- a/doc/devel/uml/index_81.html +++ b/doc/devel/uml/index_81.html @@ -21,8 +21,11 @@ + + +
                                    NameKindDescription
                                    Pclass
                                    paramrelation
                                    ParamAccessorclass
                                    parameterartifactrepresentation of an automatable effect/plugin parameter
                                    ParamProviderclassA facility to get the actual value of a plugin/effect parameter
                                    paramsrelation
                                    paramsrelation
                                    path_relation
                                    PathManagerclassWhile building a render engine, this Strategy class decides on the actual render strategy in accordance to the current controller settings (system state)
                                    pathmanagerartifactManager for deciding the actual render strategy
                                    Pipeclassstructural asset representing a basic building block within the high level model: a port for building a processing chain and generating media output
                                    pipesrelation
                                    pipesrelationthe global ports (busses) of the session
                                    placementartifactKey Abstraction: a way to place and locate a Media Object
                                    Placementpackage
                                    Placementclassused to specify the position of a MObject in the EDL. This can be done in various ways (absolute, relative).
                                    Placement at the same time acts as (refcounting) smart pointer for accessing the MObject.
                                    PlacementIndexclass
                                    PlacementRefclass
                                    playoperationTODO: will probably be handled differently (see Cehteh)
                                    PlayControlclass
                                    PlayheadCursorclass
                                    Posix Threads Abstractionclass viewC++ wrapers for pthreads
                                    predecessorsrelation
                                    predicate implclass instance
                                    pRef_relation
                                    Prefetchclass
                                    Previewclassalternative version of the media data, probably with lower resolution
                                    previewartifactalternative version of the media data, probably with lower resolution
                                    Query System overviewcomponent view
                                    query useuse case view
                                    QueryCacheclass
                                    QueryFocusclass
                                    QueryFocusStackclass
                                    QueryHandlerclass
                                    QueryHandlerImplclass
                                    QueryResolverclass
                                    diff --git a/doc/devel/uml/index_83.html b/doc/devel/uml/index_83.html index fa8dc7579..93f76635f 100644 --- a/doc/devel/uml/index_83.html +++ b/doc/devel/uml/index_83.html @@ -20,6 +20,11 @@ SAMETIMEattributeplace subject at the sime time as the anchor saveoperationcreate a complete, serialized representation
                                    of the current session config and contents.
                                    @todo how to serialize, prameters, return value? Schedulerclass +Scopeclass +ScopeLocatorclass +ScopePathclass +Scopesclass view +scopesrelation scratchstate segmentartifactSegment of the Timeline.
                                    Used at the moment (7/07) for partitioning the timeline/fixture into segments
                                    to be rendered by a specialized render node network for each, without the need
                                    to change any connections within a given segment.
                                    Note this concept may be superfluos alltogether; is a draft and the real
                                    use still needs to be worked out... Segmentclass @@ -31,15 +36,18 @@ segmentsactivity object segmentsrelationthe partitioning of the Timeline to be created by this tool. Seqclass +Sequenceclass Sequenceclass Serializerclass Service Componentsclass view ServiceImplclass Sessioncomponent sessionartifactInterface: the session edited by the user -Sessionclass view sessionpackagesourcecode package

                                    Everything concerning the EDL and Session, within the MObject Subsystem +Sessionpackage SessionclassPrimary Interface for all editing tasks.
                                    The session contains defaults, all the assets being edited, and a set of EDL with the individual MObjects to be manipulated and rendered. +Session backboneclass diagram +Session partsclass view Session structureclass diagram sessionimplartifactholds the complete session data to be edited by the user SessionImplclassImplementation class for the Session interface @@ -47,6 +55,7 @@ SessManagerclass setup Build Paramsopaque activity action setup StateProxyopaque activity action +shared_ptrclass shortDescattributeuser visible Name-ID. To be localized. simpleclipartifactElementary clip (single media stream only) SimpleClipclassElementary clip consisting of only one media stream @@ -63,15 +72,15 @@ Statenode Stateclass staterelation -state actionstate action -state actionstate action +state actionstate action state actionstate action state actionstate action +state actionstate action +state actionstate action +state actionstate action state actionstate actiontry to fetch existing definition -state actionstate action state actionstate action state actionstate action -state actionstate action StateAdapterclass StateAdapter compositionclass diagram StateProxyclass diff --git a/doc/devel/uml/index_84.html b/doc/devel/uml/index_84.html index ea6b9d69e..33624b8dd 100644 --- a/doc/devel/uml/index_84.html +++ b/doc/devel/uml/index_84.html @@ -34,8 +34,8 @@ Trackclassstructural asset holding the configuration of a track in the EDL trackattribute trackrelation -trackartifactA grouping device within the EDL. The corresponding Placement
                                    by which this Track object is refered defines fallback placing
                                    properties to be used by all objects placed on this track in
                                    case they don't specify more concrete placements.
                                    Typically, tracks are used do make default Port connections,
                                    define a layer or pan for sound and for for disabling groups
                                    of clips. Note tracks are grouped in a tree like fashion.
                                    trackartifactstructural asset holding the configuration of a track in the EDL +trackartifactA grouping device within the EDL. The corresponding Placement
                                    by which this Track object is refered defines fallback placing
                                    properties to be used by all objects placed on this track in
                                    case they don't specify more concrete placements.
                                    Typically, tracks are used do make default Port connections,
                                    define a layer or pan for sound and for for disabling groups
                                    of clips. Note tracks are grouped in a tree like fashion.
                                    trackrelation Trackclass tracksrelationelementary media assets comprising this compound @@ -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 +treatoperation TypeHandlerclass TypeHandler<Pipe>class diff --git a/doc/devel/uml/index_86.html b/doc/devel/uml/index_86.html index 85cc3a896..3c3999692 100644 --- a/doc/devel/uml/index_86.html +++ b/doc/devel/uml/index_86.html @@ -22,10 +22,10 @@ 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 @@ -33,9 +33,9 @@ video1class instance video1class instance video1class instance -video1class instance video1class instance video1class instance +video1class instance Visitableclass visitorpackagesub-namespace for visitor library implementation visitorartifactAcyclic Visitor library diff --git a/doc/devel/uml/packages.html b/doc/devel/uml/packages.html index 7b039a400..8b63a59fb 100644 --- a/doc/devel/uml/packages.html +++ b/doc/devel/uml/packages.html @@ -20,12 +20,13 @@ Asset backendsrcsourcecode package

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

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

                                    Common library and helper classes CommonLib ConfigQuery +Containers controlsrcsourcecode package

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

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

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

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

                                    Tools and Utilities
                                    (separate from the main cinelrra binary) visitorsub-namespace for visitor library implementation diff --git a/uml/lumiera/128261 b/uml/lumiera/128261 index 87b5544e9..699fc9f00 100644 --- a/uml/lumiera/128261 +++ b/uml/lumiera/128261 @@ -1,6 +1,6 @@ format 58 "MObject" // ProcessingLayer::MObject - revision 37 + revision 38 modified_by 5 "hiv" // class settings //class diagram settings @@ -26,1413 +26,9 @@ format 58 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 - classview 128005 "Session" - //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 128133 "Session structure" - draw_all_relations no 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 + package_ref 132229 // Session - class 139653 "Session" - abstract visibility public - cpp_decl "${comment}${template}class ${name}${inherit} - { -${members} }; -${inlines} -" - java_decl "" - php_decl "" - python_2_2 python_decl "" - idl_decl "" - explicit_switch_type "" - - comment "Primary 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." - operation 133509 "currEDL" - public return_type class_ref 128133 // Seq - 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} -} - -" - - - - - comment "The EDL currently in focus. In most cases, Session and EDL are almost the same, just EDL emphasizes the collection aspect. But generally (for larger editing projects) one Session can contain several EDLs, which may even be nested. At any given time, only one of these EDLs has focus and recieves the editing commands." - end - - operation 133637 "getFixture" - public explicit_return_type "Fixture&" - 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} -} - -" - - - - - comment "While the session can be comprised of several EDLs, -there is only one Fixture, which represents the actual -configuration of all Objects to be rendered" - end - - classrelation 144773 // current () - relation 142853 ---> - a role_name "current" multiplicity "1" class_relation public - comment "Standard access path to get at the current session via the Session Manager, which acts as a \"PImpl\" smart pointer" - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}& ${name}${value}; -" - classrelation_ref 144773 // current () - b parent class_ref 139781 // SessManager - end - - classrelation 150917 // defaults () - relation 148101 ---> - a role_name "defaults" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 150917 // defaults () - b parent class_ref 141445 // DefaultsManager - end - end - - class 128005 "SessionImpl" - 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 "" - - comment "Implementation class for the Session interface" - classrelation 128005 // edls () - relation 128005 *--> - a role_name "edls" multiplicity "1..*" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${stereotype}<${type}> ${name}${value}; -" - classrelation_ref 128005 // edls () - b parent class_ref 128133 // Seq - end - - classrelation 128261 // theFixture () - relation 128133 ---> - a role_name "theFixture" multiplicity "1" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type} * ${name}${value}; -" - classrelation_ref 128261 // theFixture () - b parent class_ref 128261 // Fixture - end - - classrelation 144645 // - relation 142725 -_-|> - stereotype "PImpl" - a public - cpp default "${type}" - classrelation_ref 144645 // - b parent class_ref 139653 // Session - end - - classrelation 147717 // pipes () - relation 145541 o--> - stereotype "vector" - a role_name "pipes" multiplicity "*" protected - comment "the global ports (busses) of the session" - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 147717 // pipes () - b parent class_ref 138117 // Pipe - end - end - - class 139781 "SessManager" - 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 "" - - operation 133765 "clear" - public explicit_return_type "void" - 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} -} - -" - - - - - comment "clear current session contents -without resetting overall session config. -Afterwards, the session will contain only one -empty EDL, while all Assets are retained. -" - end - - operation 133893 "reset" - public explicit_return_type "void" - 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} -} - -" - - - - - comment "reset all session config and -start with a pristine default session." - end - - operation 134021 "load" - public explicit_return_type "void" - 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} -} - -" - - - - - comment "replace the current session by a new -session loaded from serialized state." - end - - operation 134149 "save" - public explicit_return_type "void" - 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} -} - -" - - - - - comment "create a complete, serialized representation -of the current session config and contents. -@todo how to serialize, prameters, return value?" - end - end - - class 145541 "Timeline" - abstract visibility public - cpp_decl "${comment}${template}class ${name}${inherit} - { -${members} }; -${inlines} -" - java_decl "" - php_decl "" - python_2_2 python_decl "" - idl_decl "" - explicit_switch_type "" - - classrelation 159109 // - relation_ref 154885 // - end - - classrelation 159237 // - relation 155013 ---> - stereotype "own" - a role_name "" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 159237 // - b parent class_ref 145925 // PlayControl - end - - classrelation 159621 // - relation 155269 ---> - a role_name "" multiplicity "1" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 159621 // - b parent class_ref 146309 // Sequence - end - - classrelation 160005 // globalBusses () - relation 155653 *--> - stereotype "list" - a role_name "globalBusses" multiplicity "*" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - classrelation_ref 160005 // globalBusses () - b multiplicity "1" parent class_ref 138117 // Pipe - end - end - - class 145797 "TimelineView" - 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 158853 // - relation 154757 -_-|> - a public - cpp default "${type}" - classrelation_ref 158853 // - b parent class_ref 145541 // Timeline - end - - classrelation 159749 // - relation 155397 ---> - a role_name "" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 159749 // - b parent class_ref 146309 // Sequence - end - - classrelation 160773 // - relation 156293 ---- - a role_name "" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 160773 // - b role_name "" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 160901 // - end - end - - class 128133 "Seq" - 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 128901 // clips () - relation 128517 o--> - stereotype "list" - a role_name "clips" multiplicity "*" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${stereotype}<${type} *> ${name}${value}; -" - classrelation_ref 128901 // clips () - b parent class_ref 128517 // MObject - end - - classrelation 147333 // track () - relation 145157 ---> - a role_name "track" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 147333 // track () - b parent class_ref 128389 // Track - association_type class_ref 128645 // Placement - end - end - - class 128261 "Fixture" - 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 128517 // - relation 128261 ---|> - a public - cpp default "${type}" - classrelation_ref 128517 // - b parent class_ref 128133 // Seq - end - - classrelation 131717 // effectiveTimeline () - relation 131077 *--> - stereotype "list" - a role_name "effectiveTimeline" multiplicity "*" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - classrelation_ref 131717 // effectiveTimeline () - b parent class_ref 129797 // ExplicitPlacement - end - - operation 128645 "getPlaylistForRender" - public explicit_return_type "list" - 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 - - operation 129157 "getAutomation" - public explicit_return_type "Auto [ProcessingLayer::MObject]*" - 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 - - classrelation 147589 // track () - relation 145413 ---> - a role_name "track" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 147589 // track () - b parent class_ref 128389 // Track - association_type class_ref 128645 // Placement - end - - classrelation 163333 // - relation_ref 158213 // - end - end - - class 147333 "Segmentation" - 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 163205 // - relation 158213 ---- - stereotype "partitioning" - a role_name "" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 163205 // - b role_name "" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 163333 // - end - end - - class 135173 "Segment" - 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 "" - - attribute 129925 "start" - protected type class_ref 134917 // Time - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - end - - attribute 130053 "length" - protected type class_ref 134917 // Time - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - comment "duration (span) of this timeline segment." - end - - classrelation 138885 // elements () - relation 137093 o--> - stereotype "list" - a role_name "elements" multiplicity "*" protected - comment "relevant MObjects comprising this segment. TODO: actually necessary??" - cpp default " ${comment}${static}${mutable}${volatile}${const}${stereotype}<${type} *> ${name}${value}; -" - classrelation_ref 138885 // elements () - b parent class_ref 129797 // ExplicitPlacement - end - - classrelation 163589 // - relation 158469 ---> - stereotype "correspondance" - a role_name "" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 163589 // - b parent class_ref 131461 // RenderGraph - end - end - - class 128389 "Track" - 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 "" - - associated_diagram classdiagram_ref 128133 // Session structure - classrelation 147077 // - relation 144901 ---|> - a public - cpp default "${type}" - classrelation_ref 147077 // - b parent class_ref 129157 // Meta - end - - classrelation 147205 // subTracks () - relation 145029 *--> - stereotype "vector" - a role_name "subTracks" multiplicity "*" public - comment "Child tracks in a tree structure" - cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - classrelation_ref 147205 // subTracks () - b parent class_ref 128389 // Track - association_type class_ref 128645 // Placement - end - - classrelation 161413 // - relation 156805 -_-|> - a public - cpp default "${type}" - classrelation_ref 161413 // - b parent class_ref 128517 // MObject - end - end - - class 128517 "MObject" - abstract visibility public stereotype "interface" - cpp_decl "${comment}${template}class ${name}${inherit} - { -${members} }; -${inlines} -" - java_decl "${comment}${@}${visibility}interface ${name}${extends} { -${members}} -" - php_decl "" - python_2_2 python_decl "" - idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { -${members}}; -" - explicit_switch_type "" - - attribute 128517 "length" - protected type class_ref 134917 // Time - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - comment "TODO: how to represent time intervals?" - end - - classrelation 137093 // - relation 135557 ---|> - a public - cpp default "${type}" - classrelation_ref 137093 // - b parent class_ref 134021 // Buildable - end - end - - class 128645 "Placement" - abstract visibility public stereotype "interface" - cpp_decl "${comment}${template}class ${name}${inherit} - { -${members} }; -${inlines} -" - java_decl "${comment}${@}${visibility}interface ${name}${extends} { -${members}} -" - php_decl "" - python_2_2 python_decl "" - idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { -${members}}; -" - explicit_switch_type "" - - comment "used to specify the position of a MObject in the EDL. This can be done in various ways (absolute, relative). -Placement at the same time acts as (refcounting) smart pointer for accessing the MObject." - operation 128005 "resolve" - public explicit_return_type "ExplicitPlacement [ProcessingLayer::MObject]&" - 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} -} - -" - - - - - comment "create an actual (explicit) placement while trying to satisfy the network of adjacent objects and placements." - end - - classrelation 144901 // subject () - relation 142981 ---> - a role_name "subject" multiplicity "1" protected - comment "Placement acts as smart pointer" - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 144901 // subject () - b multiplicity "1..*" parent class_ref 128517 // MObject - end - - operation 134277 "chain" - public explicit_return_type "" - nparams 1 - param in name "style" explicit_type "" - cpp_decl " ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}const ${t0}& ${p0}${)}${const}${volatile} ${throw}${abstract};" - cpp_def "${comment}${inline}${type} -${class}::${name} ${(}const ${t0}& ${p0}${)}${const}${volatile} ${throw}${staticnl} -{ - ${body} -} - -" - - - - - comment "create and add another Placement for this media object, thus increasingly constraining the (possible) position of this object." - end - - classrelation 145413 // chain () - relation 143237 ---> - a role_name "chain" multiplicity "1" protected - comment "Chain of additional Placements further constraining the position of this MObject" - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 145413 // chain () - b parent class_ref 139909 // LocatingPin - end - end - - class 129797 "ExplicitPlacement" - abstract visibility public stereotype "interface" - cpp_decl "${comment}${template}class ${name}${inherit} - { -${members} }; -${inlines} -" - java_decl "${comment}${@}${visibility}interface ${name}${extends} { -${members}} -" - php_decl "" - python_2_2 python_decl "" - idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { -${members}}; -" - explicit_switch_type "" - - classrelation 131589 // - relation 130949 ---|> - a public - cpp default "${type}" - classrelation_ref 131589 // - b parent class_ref 128645 // Placement - end - - attribute 128261 "time" - protected type class_ref 134917 // Time - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - end - - attribute 128389 "track" - protected explicit_type "Track [ProcessingLayer::MObject] *" - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - end - - classrelation 131845 // - relation 131205 ---> - a role_name "" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 131845 // - b parent class_ref 128389 // Track - association_type class_ref 128389 // Track - end - end - - class 128773 "AbstractMO" - abstract 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 129925 // - relation 129285 ---|> - a public - cpp default "${type}" - classrelation_ref 129925 // - b parent class_ref 128517 // MObject - end - end - - class 128901 "Clip" - 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 130053 // - relation 129413 ---|> - a public - cpp default "${type}" - classrelation_ref 130053 // - b parent class_ref 128773 // AbstractMO - end - - classrelation 142469 // source () - relation 140677 ---> - a role_name "source" multiplicity "1" protected - comment "the media source this clip referes to" - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 142469 // source () - b multiplicity "*" parent class_ref 136709 // Media - end - - classrelation 161029 // - relation 156421 -_-|> - a public - cpp default "${type}" - classrelation_ref 161029 // - b parent class_ref 128517 // MObject - end - end - - class 138885 "SimpleClip" - 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 "" - - comment "Elementary clip consisting of only one media stream" - classrelation 143365 // - relation 141445 ---|> - a public - cpp default "${type}" - classrelation_ref 143365 // - b parent class_ref 128901 // Clip - end - end - - class 138629 "CompoundClip" - 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 "" - - associated_diagram classdiagram_ref 128133 // Session structure - comment "Clip MObject which is actually a compound of several elementary clips, -e.g. the several streams found within multichannels media." - classrelation 142597 // - relation 140805 ---|> - a public - cpp default "${type}" - classrelation_ref 142597 // - b parent class_ref 128901 // Clip - end - - classrelation 143493 // components () - relation 141573 o--> - a role_name "components" multiplicity "1..*" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 143493 // components () - b multiplicity "*" parent class_ref 128901 // Clip - end - end - - class 129029 "Effect" - 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 130181 // - relation 129541 ---|> - a public - cpp default "${type}" - classrelation_ref 130181 // - b parent class_ref 128773 // AbstractMO - end - - attribute 128901 "plugin" - protected explicit_type "string" - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - comment "Identifier of the Plugin to be used" - end - - classrelation 161157 // - relation 156549 -_-|> - a public - cpp default "${type}" - classrelation_ref 161157 // - b parent class_ref 128517 // MObject - end - end - - class 129157 "Meta" - 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 130309 // - relation 129669 ---|> - a public - cpp default "${type}" - classrelation_ref 130309 // - b parent class_ref 128773 // AbstractMO - end - end - - class 129285 "FixedLocation" - 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 145797 // - relation 143621 ---|> - a public - cpp default "${type}" - classrelation_ref 145797 // - b parent class_ref 139909 // LocatingPin - end - end - - class 129413 "RelativeLocation" - 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 130565 // anchor () - relation 129925 ---> - a role_name "anchor" multiplicity "1" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 130565 // anchor () - b multiplicity "1" parent class_ref 128517 // MObject - association_type class_ref 128517 // MObject - end - - attribute 128133 "relType" - protected type class_ref 133893 // RelType - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - comment "the kind of relation denoted by this Placement" - end - - attribute 129029 "offset" - protected type class_ref 134917 // Time - init_value "0" - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - comment "Offset the actual position by this (time) value relative to the anchor point. TODO: Representation?" - end - - class 133893 "RelType" - visibility public stereotype "enum" - cpp_decl "${comment}enum ${name} - { -${items} - }; -" - java_decl "${comment}${@}${visibility}${final}${abstract}enum ${name}${implements} { -${items}; -${members}} -" - php_decl "" - python_2_2 python_decl "" - idl_decl "${comment}enum ${name} { -${items}}; -" - explicit_switch_type "" - - comment "the possible kinds of RelativePlacements" - attribute 129157 "SAMETIME" - public explicit_type "" - cpp_decl " ${name}${value}, ${comment}" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - comment "place subject at the sime time as the anchor" - end - - attribute 129285 "ATTACH" - public explicit_type "" - cpp_decl " ${name}${value}, ${comment}" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - comment "attach subject to anchor (e.g. an effect to a clip)" - end - end - - classrelation 145669 // - relation 143493 ---|> - a public - cpp default "${type}" - classrelation_ref 145669 // - b parent class_ref 139909 // LocatingPin - end - end - - class 129541 "Allocation" - abstract 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 "" - - comment "a directive to place a MObject in a specific way" - attribute 128773 "repr" - protected explicit_type "string" - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - php_decl "" - python_decl "" - idl_decl "" - get_oper operation_ref 131205 // get_repr - comment "human readable representation of the condition characterizing this allocaton, e.g. \"t >= 10\"" - end - - operation 131205 "get_repr" - const cpp_inline public explicit_return_type "string" - nparams 0 - cpp_decl " ${comment}${friend}${static}${inline}${virtual}const ${type} ${name} ${(}${)}${const}${volatile} ${throw};" - cpp_def "${comment}${inline}const ${type} ${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl} -{ - return repr; -} - -" - cpp_name_spec "get${Name}" - final - java_name_spec "get${Name}" - - - - idl_name_spec "get_${name}" - get_of_attribute attribute_ref 128773 // repr - end - - classrelation 145925 // - relation 143749 ---|> - a public - cpp default "${type}" - classrelation_ref 145925 // - b parent class_ref 139909 // LocatingPin - end - end - - class 129669 "Label" - 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 130949 // - relation 130309 ---|> - a public - cpp default "${type}" - classrelation_ref 130949 // - b parent class_ref 129157 // Meta - end - - classrelation 161285 // - relation 156677 -_-|> - a public - cpp default "${type}" - classrelation_ref 161285 // - b parent class_ref 128517 // MObject - end - end - - class 129925 "Auto" - visibility package - nformals 1 - formal name "VAL" type "class" explicit_default_value "" - explicit_extends "" - nactuals 1 - actual class class_ref 134661 // ParamProvider - rank 0 explicit_value "VAL" - cpp_decl "${comment}${template}class ${name}${inherit} - { -${members} }; -${inlines} -" - java_decl "" - php_decl "" - python_2_2 python_decl "" - idl_decl "" - explicit_switch_type "" - - comment "Automation data for some parameter (i.e. a time varying function)" - classrelation 131973 // - relation 131333 ---|> - a public - cpp default "${type}" - classrelation_ref 131973 // - b parent class_ref 129157 // Meta - end - - classrelation 138501 // - relation 136837 -_-|> - a public - cpp default "${type}" - classrelation_ref 138501 // - b parent class_ref 134661 // ParamProvider - end - - operation 131077 "getValue" - const public explicit_return_type "VAL" - 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 130053 "Wish" - 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 132101 // - relation 131461 ---|> - a public - cpp default "${type}" - classrelation_ref 132101 // - b parent class_ref 129541 // Allocation - end - end - - class 130181 "Constraint" - 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 132357 // - relation 131717 ---|> - a public - cpp default "${type}" - classrelation_ref 132357 // - b parent class_ref 129541 // Allocation - end - end - - class 140421 "Plug" - 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 147845 // - relation 145669 ---|> - a public - cpp default "${type}" - classrelation_ref 147845 // - b parent class_ref 130053 // Wish - end - - classrelation 147973 // outPort () - relation 145797 ---> - a role_name "outPort" protected - comment "the Port this MObject wants to be conected to" - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 147973 // outPort () - b parent class_ref 138117 // Pipe - end - end - - class 134533 "Parameter" - visibility public - nformals 1 - formal name "VAL" 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 "" - - comment "Descriptor and access object for a plugin parameter. Parameters may be provided with values from the session, and this values may be automated." - operation 130821 "getValue" - const public explicit_return_type "VAL" - 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 - - classrelation 138245 // - relation 136581 -_-> - stereotype "implemented_by" - a package - cpp default "#include in source" - classrelation_ref 138245 // - b parent class_ref 134661 // ParamProvider - end - - classrelation 138629 // - relation_ref 136325 // - end - end - - class 134661 "ParamProvider" - abstract visibility public stereotype "interface" - nformals 1 - formal name "VAL" type "class" explicit_default_value "" - explicit_extends "" - cpp_decl "${comment}${template}class ${name}${inherit} - { -${members} }; -${inlines} -" - java_decl "${comment}${@}${visibility}interface ${name}${extends} { -${members}} -" - php_decl "" - python_2_2 python_decl "" - idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { -${members}}; -" - explicit_switch_type "" - - comment "A facility to get the actual value of a plugin/effect parameter" - classrelation 137989 // param () - relation 136325 ---- - a role_name "param" multiplicity "1" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 137989 // param () - b role_name "provider" multiplicity "1" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 138629 // - end - - classrelation 138373 // ipo () - relation 136709 ---> - a role_name "ipo" multiplicity "0..1" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 138373 // ipo () - b parent class_ref 134789 // Interpolator - end - - operation 130949 "getValue" - const public explicit_return_type "VAL" - 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 134789 "Interpolator" - visibility package - nformals 1 - formal name "VAL" 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 "" - - comment "Provides the implementation for getting the acutal value of a time varying or automated effect/plugin parameter" - end - - class 139909 "LocatingPin" - 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 "" - - comment "An element with value semantics, which actually implements the placement of some MObject by positioning it in some way." - classrelation 146053 // next () - relation 143877 ---> - a role_name "next" protected - comment "next additional LocatingPin, if any" - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 146053 // next () - b parent class_ref 139909 // LocatingPin - end - end - end + package_ref 132357 // Placement package_ref 128901 // Builder diff --git a/uml/lumiera/128517 b/uml/lumiera/128517 index d88352c6d..057be77a3 100644 --- a/uml/lumiera/128517 +++ b/uml/lumiera/128517 @@ -1,6 +1,6 @@ format 58 "CommonLib" // CommonLib - revision 15 + revision 16 modified_by 5 "hiv" // class settings //class diagram settings @@ -352,6 +352,8 @@ ${items}}; package_ref 131077 // ConfigQuery + package_ref 132485 // Containers + classview 128773 "error" //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 @@ -936,5 +938,20 @@ ${members}}; explicit_switch_type "" end + + class 153093 "shared_ptr" + 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 "" + + end end end diff --git a/uml/lumiera/132229 b/uml/lumiera/132229 new file mode 100644 index 000000000..e3e0d4b38 --- /dev/null +++ b/uml/lumiera/132229 @@ -0,0 +1,1668 @@ +format 58 +"Session" // ProcessingLayer::MObject::Session + revision 1 + modified_by 5 "hiv" + // class settings + //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 + //use case diagram settings + package_name_in_tab default show_context default auto_label_position default draw_all_relations default class_drawing_mode 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 + //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 + //component diagram settings + package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default + draw_component_as_icon default show_component_req_prov default show_component_rea default show_stereotype_properties default + //deployment diagram settings + package_name_in_tab default show_context default write_horizontally default auto_label_position default draw_all_relations default shadow default + draw_component_as_icon default show_component_req_prov default show_component_rea 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 + //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 + + classview 128005 "Session parts" + //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 128133 "Session structure" + draw_all_relations no 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 139653 "Session" + abstract visibility public + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + php_decl "" + python_2_2 python_decl "" + idl_decl "" + explicit_switch_type "" + + comment "Primary 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." + operation 133509 "currEDL" + public return_type class_ref 128133 // Seq + 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} +} + +" + + + + + comment "The EDL currently in focus. In most cases, Session and EDL are almost the same, just EDL emphasizes the collection aspect. But generally (for larger editing projects) one Session can contain several EDLs, which may even be nested. At any given time, only one of these EDLs has focus and recieves the editing commands." + end + + operation 133637 "getFixture" + public explicit_return_type "Fixture&" + 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} +} + +" + + + + + comment "While the session can be comprised of several EDLs, +there is only one Fixture, which represents the actual +configuration of all Objects to be rendered" + end + + classrelation 144773 // current () + relation 142853 ---> + a role_name "current" multiplicity "1" class_relation public + comment "Standard access path to get at the current session via the Session Manager, which acts as a \"PImpl\" smart pointer" + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}& ${name}${value}; +" + classrelation_ref 144773 // current () + b parent class_ref 139781 // SessManager + end + + classrelation 150917 // defaults () + relation 148101 ---> + a role_name "defaults" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 150917 // defaults () + b parent class_ref 141445 // DefaultsManager + end + end + + class 128005 "SessionImpl" + 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 "" + + comment "Implementation class for the Session interface" + classrelation 128005 // edls () + relation 128005 *--> + a role_name "edls" multiplicity "1..*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${stereotype}<${type}> ${name}${value}; +" + classrelation_ref 128005 // edls () + b parent class_ref 128133 // Seq + end + + classrelation 128261 // theFixture () + relation 128133 ---> + a role_name "theFixture" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} * ${name}${value}; +" + classrelation_ref 128261 // theFixture () + b parent class_ref 128261 // Fixture + end + + classrelation 144645 // + relation 142725 -_-|> + stereotype "PImpl" + a public + cpp default "${type}" + classrelation_ref 144645 // + b parent class_ref 139653 // Session + end + + classrelation 147717 // pipes () + relation 145541 o--> + stereotype "vector" + a role_name "pipes" multiplicity "*" protected + comment "the global ports (busses) of the session" + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 147717 // pipes () + b parent class_ref 138117 // Pipe + end + end + + class 139781 "SessManager" + 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 "" + + operation 133765 "clear" + public explicit_return_type "void" + 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} +} + +" + + + + + comment "clear current session contents +without resetting overall session config. +Afterwards, the session will contain only one +empty EDL, while all Assets are retained. +" + end + + operation 133893 "reset" + public explicit_return_type "void" + 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} +} + +" + + + + + comment "reset all session config and +start with a pristine default session." + end + + operation 134021 "load" + public explicit_return_type "void" + 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} +} + +" + + + + + comment "replace the current session by a new +session loaded from serialized state." + end + + operation 134149 "save" + public explicit_return_type "void" + 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} +} + +" + + + + + comment "create a complete, serialized representation +of the current session config and contents. +@todo how to serialize, prameters, return value?" + end + end + + class 145541 "Timeline" + abstract visibility public + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + php_decl "" + python_2_2 python_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 159109 // + relation_ref 154885 // + end + + classrelation 159237 // + relation 155013 ---> + stereotype "own" + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 159237 // + b parent class_ref 145925 // PlayControl + end + + classrelation 159621 // + relation 155269 ---> + a role_name "" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 159621 // + b parent class_ref 146309 // Sequence + end + + classrelation 160005 // globalBusses () + relation 155653 *--> + stereotype "list" + a role_name "globalBusses" multiplicity "*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 160005 // globalBusses () + b multiplicity "1" parent class_ref 138117 // Pipe + end + end + + class 145797 "TimelineView" + 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 158853 // + relation 154757 -_-|> + a public + cpp default "${type}" + classrelation_ref 158853 // + b parent class_ref 145541 // Timeline + end + + classrelation 159749 // + relation 155397 ---> + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 159749 // + b parent class_ref 146309 // Sequence + end + + classrelation 160773 // + relation 156293 ---- + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 160773 // + b role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 160901 // + end + end + + class 128133 "Seq" + 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 128901 // clips () + relation 128517 o--> + stereotype "list" + a role_name "clips" multiplicity "*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${stereotype}<${type} *> ${name}${value}; +" + classrelation_ref 128901 // clips () + b parent class_ref 128517 // MObject + end + + classrelation 147333 // track () + relation 145157 ---> + a role_name "track" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 147333 // track () + b parent class_ref 128389 // Track + association_type class_ref 128645 // Placement + end + end + + class 128261 "Fixture" + 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 128517 // + relation 128261 ---|> + a public + cpp default "${type}" + classrelation_ref 128517 // + b parent class_ref 128133 // Seq + end + + classrelation 131717 // effectiveTimeline () + relation 131077 *--> + stereotype "list" + a role_name "effectiveTimeline" multiplicity "*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 131717 // effectiveTimeline () + b parent class_ref 129797 // ExplicitPlacement + end + + operation 128645 "getPlaylistForRender" + public explicit_return_type "list" + 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 + + operation 129157 "getAutomation" + public explicit_return_type "Auto [ProcessingLayer::MObject]*" + 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 + + classrelation 147589 // track () + relation 145413 ---> + a role_name "track" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 147589 // track () + b parent class_ref 128389 // Track + association_type class_ref 128645 // Placement + end + + classrelation 163333 // + relation_ref 158213 // + end + end + + class 147333 "Segmentation" + 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 163205 // + relation 158213 ---- + stereotype "partitioning" + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 163205 // + b role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 163333 // + end + end + + class 135173 "Segment" + 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 "" + + attribute 129925 "start" + protected type class_ref 134917 // Time + cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + end + + attribute 130053 "length" + protected type class_ref 134917 // Time + cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + comment "duration (span) of this timeline segment." + end + + classrelation 138885 // elements () + relation 137093 o--> + stereotype "list" + a role_name "elements" multiplicity "*" protected + comment "relevant MObjects comprising this segment. TODO: actually necessary??" + cpp default " ${comment}${static}${mutable}${volatile}${const}${stereotype}<${type} *> ${name}${value}; +" + classrelation_ref 138885 // elements () + b parent class_ref 129797 // ExplicitPlacement + end + + classrelation 163589 // + relation 158469 ---> + stereotype "correspondance" + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 163589 // + b parent class_ref 131461 // RenderGraph + end + end + + class 128389 "Track" + 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 "" + + associated_diagram classdiagram_ref 128133 // Session structure + classrelation 147077 // + relation 144901 ---|> + a public + cpp default "${type}" + classrelation_ref 147077 // + b parent class_ref 129157 // Meta + end + + classrelation 147205 // subTracks () + relation 145029 *--> + stereotype "vector" + a role_name "subTracks" multiplicity "*" public + comment "Child tracks in a tree structure" + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 147205 // subTracks () + b parent class_ref 128389 // Track + association_type class_ref 128645 // Placement + end + + classrelation 161413 // + relation 156805 -_-|> + a public + cpp default "${type}" + classrelation_ref 161413 // + b parent class_ref 128517 // MObject + end + end + + class 128517 "MObject" + abstract visibility public stereotype "interface" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "${comment}${@}${visibility}interface ${name}${extends} { +${members}} +" + php_decl "" + python_2_2 python_decl "" + idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { +${members}}; +" + explicit_switch_type "" + + attribute 128517 "length" + protected type class_ref 134917 // Time + cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + comment "TODO: how to represent time intervals?" + end + + classrelation 137093 // + relation 135557 ---|> + a public + cpp default "${type}" + classrelation_ref 137093 // + b parent class_ref 134021 // Buildable + end + end + + class 128645 "Placement" + abstract visibility public stereotype "interface" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "${comment}${@}${visibility}interface ${name}${extends} { +${members}} +" + php_decl "" + python_2_2 python_decl "" + idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { +${members}}; +" + explicit_switch_type "" + + comment "used to specify the position of a MObject in the EDL. This can be done in various ways (absolute, relative). +Placement at the same time acts as (refcounting) smart pointer for accessing the MObject." + operation 128005 "resolve" + public explicit_return_type "ExplicitPlacement [ProcessingLayer::MObject]&" + 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} +} + +" + + + + + comment "create an actual (explicit) placement while trying to satisfy the network of adjacent objects and placements." + end + + classrelation 144901 // subject () + relation 142981 ---> + a role_name "subject" multiplicity "1" protected + comment "Placement acts as smart pointer" + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 144901 // subject () + b multiplicity "1..*" parent class_ref 128517 // MObject + end + + operation 134277 "chain" + public explicit_return_type "" + nparams 1 + param in name "style" explicit_type "" + cpp_decl " ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}const ${t0}& ${p0}${)}${const}${volatile} ${throw}${abstract};" + cpp_def "${comment}${inline}${type} +${class}::${name} ${(}const ${t0}& ${p0}${)}${const}${volatile} ${throw}${staticnl} +{ + ${body} +} + +" + + + + + comment "create and add another Placement for this media object, thus increasingly constraining the (possible) position of this object." + end + + classrelation 145413 // chain () + relation 143237 ---> + a role_name "chain" multiplicity "1" protected + comment "Chain of additional Placements further constraining the position of this MObject" + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 145413 // chain () + b parent class_ref 139909 // LocatingPin + end + + classrelation 176773 // + relation 166789 ---> + stereotype "has_a" + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 176773 // + b parent class_ref 152581 // Id + end + + classrelation 178053 // + relation 168069 -_-> + stereotype "belongs_into" + a package + cpp default "#include in source" + classrelation_ref 178053 // + b parent class_ref 153349 // Scope + end + end + + class 129797 "ExplicitPlacement" + abstract visibility public stereotype "interface" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "${comment}${@}${visibility}interface ${name}${extends} { +${members}} +" + php_decl "" + python_2_2 python_decl "" + idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { +${members}}; +" + explicit_switch_type "" + + classrelation 131589 // + relation 130949 ---|> + a public + cpp default "${type}" + classrelation_ref 131589 // + b parent class_ref 128645 // Placement + end + + attribute 128261 "time" + protected type class_ref 134917 // Time + cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + end + + attribute 128389 "track" + protected explicit_type "Track [ProcessingLayer::MObject] *" + cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + end + + classrelation 131845 // + relation 131205 ---> + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 131845 // + b parent class_ref 128389 // Track + association_type class_ref 128389 // Track + end + end + + class 128773 "AbstractMO" + abstract 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 129925 // + relation 129285 ---|> + a public + cpp default "${type}" + classrelation_ref 129925 // + b parent class_ref 128517 // MObject + end + end + + class 128901 "Clip" + 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 130053 // + relation 129413 ---|> + a public + cpp default "${type}" + classrelation_ref 130053 // + b parent class_ref 128773 // AbstractMO + end + + classrelation 142469 // source () + relation 140677 ---> + a role_name "source" multiplicity "1" protected + comment "the media source this clip referes to" + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 142469 // source () + b multiplicity "*" parent class_ref 136709 // Media + end + + classrelation 161029 // + relation 156421 -_-|> + a public + cpp default "${type}" + classrelation_ref 161029 // + b parent class_ref 128517 // MObject + end + end + + class 138885 "SimpleClip" + 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 "" + + comment "Elementary clip consisting of only one media stream" + classrelation 143365 // + relation 141445 ---|> + a public + cpp default "${type}" + classrelation_ref 143365 // + b parent class_ref 128901 // Clip + end + end + + class 138629 "CompoundClip" + 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 "" + + associated_diagram classdiagram_ref 128133 // Session structure + comment "Clip MObject which is actually a compound of several elementary clips, +e.g. the several streams found within multichannels media." + classrelation 142597 // + relation 140805 ---|> + a public + cpp default "${type}" + classrelation_ref 142597 // + b parent class_ref 128901 // Clip + end + + classrelation 143493 // components () + relation 141573 o--> + a role_name "components" multiplicity "1..*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 143493 // components () + b multiplicity "*" parent class_ref 128901 // Clip + end + end + + class 129029 "Effect" + 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 130181 // + relation 129541 ---|> + a public + cpp default "${type}" + classrelation_ref 130181 // + b parent class_ref 128773 // AbstractMO + end + + attribute 128901 "plugin" + protected explicit_type "string" + cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + comment "Identifier of the Plugin to be used" + end + + classrelation 161157 // + relation 156549 -_-|> + a public + cpp default "${type}" + classrelation_ref 161157 // + b parent class_ref 128517 // MObject + end + end + + class 129157 "Meta" + 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 130309 // + relation 129669 ---|> + a public + cpp default "${type}" + classrelation_ref 130309 // + b parent class_ref 128773 // AbstractMO + end + end + + class 129285 "FixedLocation" + 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 145797 // + relation 143621 ---|> + a public + cpp default "${type}" + classrelation_ref 145797 // + b parent class_ref 139909 // LocatingPin + end + end + + class 129413 "RelativeLocation" + 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 130565 // anchor () + relation 129925 ---> + a role_name "anchor" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 130565 // anchor () + b multiplicity "1" parent class_ref 128517 // MObject + association_type class_ref 128517 // MObject + end + + attribute 128133 "relType" + protected type class_ref 133893 // RelType + cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + comment "the kind of relation denoted by this Placement" + end + + attribute 129029 "offset" + protected type class_ref 134917 // Time + init_value "0" + cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + comment "Offset the actual position by this (time) value relative to the anchor point. TODO: Representation?" + end + + class 133893 "RelType" + visibility public stereotype "enum" + cpp_decl "${comment}enum ${name} + { +${items} + }; +" + java_decl "${comment}${@}${visibility}${final}${abstract}enum ${name}${implements} { +${items}; +${members}} +" + php_decl "" + python_2_2 python_decl "" + idl_decl "${comment}enum ${name} { +${items}}; +" + explicit_switch_type "" + + comment "the possible kinds of RelativePlacements" + attribute 129157 "SAMETIME" + public explicit_type "" + cpp_decl " ${name}${value}, ${comment}" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + comment "place subject at the sime time as the anchor" + end + + attribute 129285 "ATTACH" + public explicit_type "" + cpp_decl " ${name}${value}, ${comment}" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + comment "attach subject to anchor (e.g. an effect to a clip)" + end + end + + classrelation 145669 // + relation 143493 ---|> + a public + cpp default "${type}" + classrelation_ref 145669 // + b parent class_ref 139909 // LocatingPin + end + end + + class 129541 "Allocation" + abstract 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 "" + + comment "a directive to place a MObject in a specific way" + attribute 128773 "repr" + protected explicit_type "string" + cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + java_decl "" + php_decl "" + python_decl "" + idl_decl "" + get_oper operation_ref 131205 // get_repr + comment "human readable representation of the condition characterizing this allocaton, e.g. \"t >= 10\"" + end + + operation 131205 "get_repr" + const cpp_inline public explicit_return_type "string" + nparams 0 + cpp_decl " ${comment}${friend}${static}${inline}${virtual}const ${type} ${name} ${(}${)}${const}${volatile} ${throw};" + cpp_def "${comment}${inline}const ${type} ${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl} +{ + return repr; +} + +" + cpp_name_spec "get${Name}" + final + java_name_spec "get${Name}" + + + + idl_name_spec "get_${name}" + get_of_attribute attribute_ref 128773 // repr + end + + classrelation 145925 // + relation 143749 ---|> + a public + cpp default "${type}" + classrelation_ref 145925 // + b parent class_ref 139909 // LocatingPin + end + end + + class 129669 "Label" + 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 130949 // + relation 130309 ---|> + a public + cpp default "${type}" + classrelation_ref 130949 // + b parent class_ref 129157 // Meta + end + + classrelation 161285 // + relation 156677 -_-|> + a public + cpp default "${type}" + classrelation_ref 161285 // + b parent class_ref 128517 // MObject + end + end + + class 129925 "Auto" + visibility package + nformals 1 + formal name "VAL" type "class" explicit_default_value "" + explicit_extends "" + nactuals 1 + actual class class_ref 134661 // ParamProvider + rank 0 explicit_value "VAL" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + php_decl "" + python_2_2 python_decl "" + idl_decl "" + explicit_switch_type "" + + comment "Automation data for some parameter (i.e. a time varying function)" + classrelation 131973 // + relation 131333 ---|> + a public + cpp default "${type}" + classrelation_ref 131973 // + b parent class_ref 129157 // Meta + end + + classrelation 138501 // + relation 136837 -_-|> + a public + cpp default "${type}" + classrelation_ref 138501 // + b parent class_ref 134661 // ParamProvider + end + + operation 131077 "getValue" + const public explicit_return_type "VAL" + 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 130053 "Wish" + 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 132101 // + relation 131461 ---|> + a public + cpp default "${type}" + classrelation_ref 132101 // + b parent class_ref 129541 // Allocation + end + end + + class 130181 "Constraint" + 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 132357 // + relation 131717 ---|> + a public + cpp default "${type}" + classrelation_ref 132357 // + b parent class_ref 129541 // Allocation + end + end + + class 140421 "Plug" + 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 147845 // + relation 145669 ---|> + a public + cpp default "${type}" + classrelation_ref 147845 // + b parent class_ref 130053 // Wish + end + + classrelation 147973 // outPort () + relation 145797 ---> + a role_name "outPort" protected + comment "the Port this MObject wants to be conected to" + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 147973 // outPort () + b parent class_ref 138117 // Pipe + end + end + + class 134533 "Parameter" + visibility public + nformals 1 + formal name "VAL" 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 "" + + comment "Descriptor and access object for a plugin parameter. Parameters may be provided with values from the session, and this values may be automated." + operation 130821 "getValue" + const public explicit_return_type "VAL" + 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 + + classrelation 138245 // + relation 136581 -_-> + stereotype "implemented_by" + a package + cpp default "#include in source" + classrelation_ref 138245 // + b parent class_ref 134661 // ParamProvider + end + + classrelation 138629 // + relation_ref 136325 // + end + end + + class 134661 "ParamProvider" + abstract visibility public stereotype "interface" + nformals 1 + formal name "VAL" type "class" explicit_default_value "" + explicit_extends "" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "${comment}${@}${visibility}interface ${name}${extends} { +${members}} +" + php_decl "" + python_2_2 python_decl "" + idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { +${members}}; +" + explicit_switch_type "" + + comment "A facility to get the actual value of a plugin/effect parameter" + classrelation 137989 // param () + relation 136325 ---- + a role_name "param" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 137989 // param () + b role_name "provider" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 138629 // + end + + classrelation 138373 // ipo () + relation 136709 ---> + a role_name "ipo" multiplicity "0..1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 138373 // ipo () + b parent class_ref 134789 // Interpolator + end + + operation 130949 "getValue" + const public explicit_return_type "VAL" + 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 134789 "Interpolator" + visibility package + nformals 1 + formal name "VAL" 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 "" + + comment "Provides the implementation for getting the acutal value of a time varying or automated effect/plugin parameter" + end + + class 139909 "LocatingPin" + 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 "" + + comment "An element with value semantics, which actually implements the placement of some MObject by positioning it in some way." + classrelation 146053 // next () + relation 143877 ---> + a role_name "next" protected + comment "next additional LocatingPin, if any" + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 146053 // next () + b parent class_ref 139909 // LocatingPin + end + end + end + + classview 131973 "Object ref" + //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 136581 "MObjectRef" + 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 152453 "PlacementRef" + visibility package + nformals 1 + formal name "MO" 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 176901 // id_ () + relation 166917 ---> + stereotype "holds" + a role_name "id_" multiplicity "1" private + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 176901 // id_ () + b multiplicity "*" parent class_ref 152581 // Id + end + + classrelation 177029 // + relation 167045 -_-> + stereotype "uses" + a package + cpp default "#include in source" + classrelation_ref 177029 // + b parent class_ref 152069 // PlacementIndex + end + end + + class 152581 "Id" + 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 176645 // + relation 166661 ---|> + a public + cpp default "${type}" + classrelation_ref 176645 // + b parent class_ref 152709 // LuidH + end + end + + class 152709 "LuidH" + 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 "" + + end + + class 152837 "MObjectRef" + visibility package + nformals 1 + formal name "MO" 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 177157 // + relation 167173 ---|> + a public + cpp default "${type}" + classrelation_ref 177157 // + b parent class_ref 152965 // Handle + end + + classrelation 177285 // pRef_ () + relation 167301 ---> + stereotype "holds" + a role_name "pRef_" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 177285 // pRef_ () + b multiplicity "*" parent class_ref 152453 // PlacementRef + end + + classrelation 177413 // + relation 167429 -_-> + stereotype "denotes" + a package + cpp default "#include in source" + classrelation_ref 177413 // + b parent class_ref 128517 // MObject + end + end + end + + classview 132101 "Datastructure" + //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 136453 "Session backbone" + 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 152069 "PlacementIndex" + 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 178437 // + relation 168453 -_-|> + a public + cpp default "${type}" + classrelation_ref 178437 // + b parent class_ref 153989 // QueryResolver + end + end + + class 152197 "Sequence" + 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 "" + + end + + class 152325 "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 "" + + end + end +end diff --git a/uml/lumiera/132357 b/uml/lumiera/132357 new file mode 100644 index 000000000..ef09856d3 --- /dev/null +++ b/uml/lumiera/132357 @@ -0,0 +1,209 @@ +format 58 +"Placement" // ProcessingLayer::MObject::Placement + revision 1 + modified_by 5 "hiv" + // class settings + //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 + //use case diagram settings + package_name_in_tab default show_context default auto_label_position default draw_all_relations default class_drawing_mode 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 + //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 + //component diagram settings + package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default + draw_component_as_icon default show_component_req_prov default show_component_rea default show_stereotype_properties default + //deployment diagram settings + package_name_in_tab default show_context default write_horizontally default auto_label_position default draw_all_relations default shadow default + draw_component_as_icon default show_component_req_prov default show_component_rea 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 + //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 + + classview 131845 "Scopes" + //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 136325 "Focus of Query" + draw_all_relations no 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 153349 "Scope" + 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 177541 // + relation 167557 ---> + stereotype "holds" + a role_name "" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 177541 // + b multiplicity "1" parent class_ref 152453 // PlacementRef + end + end + + class 153477 "ScopePath" + 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 177669 // path_ () + relation 167685 *--> + stereotype "vector" + a role_name "path_" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 177669 // path_ () + b parent class_ref 153349 // Scope + end + end + + class 153605 "QueryFocus" + 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 177797 // scopes () + relation 167813 ---> + stereotype "has_a" + a role_name "scopes" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 177797 // scopes () + b parent class_ref 153477 // ScopePath + end + end + + class 153733 "QueryFocusStack" + 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 177925 // + relation 167941 *--> + stereotype "vector" + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 177925 // + b parent class_ref 153605 // QueryFocus + end + end + + class 153861 "ScopeLocator" + visibility package stereotype "singleton" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + php_decl "" + python_2_2 python_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 178181 // + relation 168197 ---> + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 178181 // + b parent class_ref 153733 // QueryFocusStack + end + + classrelation 178309 // + relation 168325 -_-> + stereotype "resolves" + a package + cpp default "#include in source" + classrelation_ref 178309 // + b parent class_ref 153349 // Scope + end + + classrelation 178565 // + relation 168581 ---> + stereotype "use" + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 178565 // + b parent class_ref 153989 // QueryResolver + end + end + + class 153989 "QueryResolver" + visibility package stereotype "interface" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "${comment}${@}${visibility}interface ${name}${extends} { +${members}} +" + php_decl "${comment}${visibility}interface ${name} { +${members}} +" + python_2_2 python_decl "" + idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { +${members}}; +" + explicit_switch_type "" + + end + end +end diff --git a/uml/lumiera/132485 b/uml/lumiera/132485 new file mode 100644 index 000000000..099d2b342 --- /dev/null +++ b/uml/lumiera/132485 @@ -0,0 +1,75 @@ +format 58 +"Containers" // CommonLib::Containers + revision 1 + modified_by 5 "hiv" + // class settings + //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 + //use case diagram settings + package_name_in_tab default show_context default auto_label_position default draw_all_relations default class_drawing_mode 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 + //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 + //component diagram settings + package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default + draw_component_as_icon default show_component_req_prov default show_component_rea default show_stereotype_properties default + //deployment diagram settings + package_name_in_tab default show_context default write_horizontally default auto_label_position default draw_all_relations default shadow default + draw_component_as_icon default show_component_req_prov default show_component_rea 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 + //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 + + classview 132229 "Custom holders" + //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 + class 152965 "Handle" + 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 "" + + end + + class 153221 "P" + 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 "" + + end + end +end diff --git a/uml/lumiera/136325.diagram b/uml/lumiera/136325.diagram new file mode 100644 index 000000000..5b265342a --- /dev/null +++ b/uml/lumiera/136325.diagram @@ -0,0 +1,100 @@ +format 58 + +classcanvas 128005 class_ref 128645 // Placement + 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 197 345 2005 +end +classcanvas 128133 class_ref 152453 // PlacementRef + 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 345 205 2005 +end +classcanvas 128261 class_ref 153349 // Scope + 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 214 212 2000 +end +classcanvas 128517 class_ref 153477 // ScopePath + 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 46 212 2000 +end +classcanvas 128773 class_ref 153605 // QueryFocus + 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 42 140 2000 +end +classcanvas 129029 class_ref 153733 // QueryFocusStack + 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 114 77 2000 +end +classcanvas 129413 class_ref 152069 // PlacementIndex + 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 340 345 2004 +end +note 129669 "actually +implemented through" + xyzwh 250 303 2000 131 50 +classcanvas 129797 class_ref 153861 // ScopeLocator + 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 196 17 2000 +end +classcanvas 130437 class_ref 153989 // QueryResolver + 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 452 107 2000 +end +note 131333 "this connection is established by the current session" + xyzwh 361 39 2000 158 47 +relationcanvas 128389 relation_ref 167557 // + from ref 128261 z 1999 stereotype "<>" xyz 277 231 3000 to ref 128133 + no_role_a no_role_b + multiplicity_a_pos 328 237 3000 multiplicity_b_pos 268 237 3000 +end +relationcanvas 128645 relation_ref 167685 // + from ref 128517 z 1999 stereotype "<>" xyz 135 231 3000 to ref 128261 + role_a_pos 176 214 3000 no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 128901 relation_ref 167813 // + from ref 128773 z 1999 stereotype "<>" xyz 49 181 3000 to ref 128517 + role_a_pos 86 195 3000 no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 129157 relation_ref 167941 // + geometry VHr + from ref 129029 z 1999 stereotype "<>" xyz 51 80 3000 to point 76 94 + line 129925 z 1999 to ref 128773 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 129285 relation_ref 168069 // + from ref 128005 z 1999 stereotype "<>" xyz 193 286 3000 to ref 128261 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 129541 relation_ref 167045 // + from ref 128133 z 1999 stereotype "<>" xyz 361 289 3000 to ref 129413 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 130053 relation_ref 168197 // + geometry VHr + from ref 129797 z 1999 to point 162 43 + line 130181 z 1999 to ref 129029 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 130309 relation_ref 168325 // + from ref 129797 z 1999 stereotype "<>" xyz 237 141 3000 to ref 128261 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 130949 relation_ref 168453 // + from ref 129413 z 1999 to point 493 261 + line 131077 z 1999 to ref 130437 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 131205 relation_ref 168581 // + from ref 129797 z 1999 stereotype "<>" xyz 339 91 3000 to ref 130437 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +preferred_whz 582 515 1 +end diff --git a/uml/lumiera/136453.diagram b/uml/lumiera/136453.diagram new file mode 100644 index 000000000..a1452d45b --- /dev/null +++ b/uml/lumiera/136453.diagram @@ -0,0 +1,19 @@ +format 58 + +classcanvas 128005 class_ref 152069 // PlacementIndex + 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 484 147 2000 +end +classcanvas 128261 class_ref 145541 // Timeline + 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 84 95 2000 +end +classcanvas 129029 class_ref 152197 // Sequence + 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 161 252 2000 +end +classcanvas 129157 class_ref 152325 // 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 124 175 2000 +end +end diff --git a/uml/lumiera/136581.diagram b/uml/lumiera/136581.diagram new file mode 100644 index 000000000..4fb73ba2c --- /dev/null +++ b/uml/lumiera/136581.diagram @@ -0,0 +1,76 @@ +format 58 + +classcanvas 128005 class_ref 152069 // PlacementIndex + 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 573 402 2000 +end +classcanvas 128133 class_ref 152453 // PlacementRef + 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 382 396 2000 +end +classcanvas 128389 class_ref 128645 // Placement + 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 286 209 2000 +end +classcanvas 128517 class_ref 152581 // Id + 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 464 231 2000 +end +classcanvas 128645 class_ref 152709 // LuidH + 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 464 169 2000 +end +classcanvas 129413 class_ref 128517 // MObject + 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 119 73 3005 +end +classcanvas 129669 class_ref 152837 // MObjectRef + 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 195 395 2000 +end +classcanvas 129797 class_ref 152965 // Handle + 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 205 327 2000 +end +relationcanvas 128773 relation_ref 166661 // + from ref 128517 z 1999 to ref 128645 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 128901 relation_ref 166789 // + from ref 128389 z 1999 stereotype "<>" xyz 386 250 3000 to ref 128517 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 129157 relation_ref 166917 // + from ref 128133 z 1999 stereotype "<>" xyz 430 332 3000 to ref 128517 + role_a_pos 486 275 3000 no_role_b + multiplicity_a_pos 460 275 3000 multiplicity_b_pos 419 378 3000 +end +relationcanvas 129285 relation_ref 167045 // + from ref 128133 z 1999 stereotype "<>" xyz 493 420 3000 to ref 128005 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 129541 relation_ref 142981 // + from ref 128389 z 1999 to ref 129413 + role_a_pos 205 129 3000 no_role_b + multiplicity_a_pos 205 152 3000 multiplicity_b_pos 259 231 3000 +end +relationcanvas 129925 relation_ref 167173 // + from ref 129669 z 1999 to ref 129797 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 130309 relation_ref 167301 // + from ref 129669 z 1999 stereotype "<>" xyz 298 420 3000 to ref 128133 + role_a_pos 343 404 3000 no_role_b + multiplicity_a_pos 365 427 3000 multiplicity_b_pos 273 425 3000 +end +relationcanvas 130437 relation_ref 167429 // + from ref 129669 z 1999 stereotype "<>" xyz 89 273 3000 to point 154 346 + line 130565 z 1999 to ref 129413 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +end diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session index 9d1a80e06..02e012c28 100644 --- a/uml/lumiera/5.session +++ b/uml/lumiera/5.session @@ -1,9 +1,11 @@ window_sizes 1302 1004 270 1022 856 71 diagrams - active classdiagram_ref 134021 // Command structure + classdiagram_ref 134021 // Command structure 575 622 100 4 0 0 - statediagram_ref 135173 // Command lifecycle - 349 682 100 4 0 0 + active classdiagram_ref 136325 // Focus of Query + 582 515 100 4 0 0 + classdiagram_ref 136581 // MObjectRef + 651 533 100 4 0 38 end show_stereotypes selected @@ -15,13 +17,17 @@ open package_ref 128133 // Asset classview_ref 128389 // Controller Workings - class_ref 148997 // CmdClosure - class_ref 150789 // Closure - pseudostate_ref 128133 // choice + classview_ref 128005 // Session parts + classview_ref 131973 // Object ref + class_ref 152069 // PlacementIndex + classview_ref 131845 // Scopes - package_ref 128261 // MObject + package_ref 128901 // Builder + usecaseview_ref 128261 // config examples classview_ref 128133 // Engine Workings classview_ref 129541 // InterfaceSystem classview_ref 129285 // StreamType + classview_ref 132229 // Custom holders + classview_ref 128266 // SmartPointers end end diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj index 66d76596f..98d69abad 100644 --- a/uml/lumiera/lumiera.prj +++ b/uml/lumiera/lumiera.prj @@ -1,6 +1,6 @@ format 58 "lumiera" - revision 53 + revision 54 modified_by 5 "hiv" cpp_root_dir "../../src/" diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 67ff846c8..6663337cb 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -2092,7 +2092,7 @@ The general idea is, that each facade interface actually provides access to a sp &rarr; [[overview of the MObject hierarchy|MObjects]]
                                    -
                                    +
                                    ''The Problem of referring to an [[MObject]]'' stems from the object //as a concept// encompassing a wider scope then just the current implementation instance. If the object was just a runtime entity in memory, we could use a simple (language) reference or pointer. Actually, this isn't sufficient, as the object reference will pass LayerSeparationInterfaces, will be handed over to code not written in the same implementation language, will be included in an ''UNDO'' record for the UndoManager, and thus will need to be serialized and stored permanently within the SessionStorage.
                                     Moreover [[MObject instances|MObject]] have a 2-level structure: the core object holds just the properties in a strict sense, i.e. the properties which the object //owns.// Any properties due to putting the object into a specific context, i.e. all relation properties are represented as [[Placement]] of the object. Thus, when viewed from the client side, a reference to a specific ~MObject //instance,// actually denotes a //specific//&nbsp; Placement of this object into the Session.
                                     
                                    @@ -2116,6 +2116,7 @@ Obviously, the second approach has quite some appeal &mdash; but, in order t
                                     
                                     !Implementation concept
                                     Presumably, none of the both models is usable as-is; rather we try to reconstruct the viable properties of both, starting out with the more elegant second model. Thus, basically the ''reference is a smart-ptr'' referring to the core object. Additionally, it incorporates a ''systematic ID denoting the location of the placement''. This ID without the smart-ptr part is used for the C-implementation, making the full handle implementation a shortcut for an access sequence, which first querries the placement from the Session, followed by dereferencing the placement to get at the core object. Thus, the implementation builds upon another abstraction, the &rarr; PlacementRef, which in turn assumes for an index within the implementation of the [[session datastructure|SessionDataMem]] to track and retrieve the actual Placement.
                                    +[img[Structure of MObjectRef and PlacementRef|uml/fig136581.png]]
                                     
                                     
                                     !using ~MObject references
                                    @@ -3381,7 +3382,7 @@ Viewed as a micro program, the processing patterns are ''weak typed'' &mdash
                                     
                                    a given Render Engine configuration is a list of Processors. Each Processor in turn contains a Graph of ProcNode.s to do the acutal data processing. In order to cary out any calculations, the Processor needs to be called with a StateProxy containing the state information for this RenderProcess
                                     
                                    -
                                    +
                                    When querying contents of the session or sub-containers within the session, the QueryFocus follows the current point-of-query. As such queries can be issued to explore the content of container-like objects holding other MObjects, the focus is always attached to a container, which also acts as [[scope|PlacementScope]] for the contained objects. QueryFocus is an implicit state (the current point of interrest). This sate especially remembers the path down from the root of the HighLevelModel, which was used to access the current scope. Because this path constitutes a hierarchy of scopes, it can be relevant for querying and resolving placement properties. (&rarr; SessionStructureQuery)
                                     
                                     !provided operations
                                    @@ -3390,6 +3391,7 @@ Viewed as a micro program, the processing patterns are ''weak typed'' &mdash
                                     * return (pop) to the previous focus
                                     * get the current scope, which is implemented as Placement
                                     * get the current ScopePath from root (session globals) down to the current scope
                                    +[>img[Scope Locating|uml/fig136325.png]]
                                     
                                     !implementation notes
                                     we provide a static access API, meaning that there is a singleton behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. This link works by the current session grabbing the query focus and attaching to it. This attachment is shallow, i.e. the QueryFocus doesn't have knowledge about the session, which allows the focus to be unit tested.
                                    
                                    From 9451a6888f6fcf9de8bea8010dde309f5b18fef1 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 16 Oct 2009 03:13:57 +0200
                                    Subject: [PATCH 007/377] start definition of new session::Scope interface
                                    
                                    ---
                                     src/proc/mobject/placement-index.cpp          |  7 ++
                                     src/proc/mobject/placement-index.hpp          |  2 +
                                     src/proc/mobject/placement-ref.hpp            |  3 +-
                                     src/proc/mobject/session/scope.cpp            | 54 ++++++++++++
                                     src/proc/mobject/session/scope.hpp            | 70 ++++++++++++++++
                                     tests/43session.tests                         |  4 +
                                     .../proc/mobject/placement-scope-test.cpp     | 81 ++++++++++++++++++
                                     .../proc/mobject/query-focus-test.cpp         | 22 +----
                                     .../proc/mobject/scope-path-test.cpp          |  4 +
                                     .../proc/mobject/session/test-scopes.cpp      | 84 +++++++++++++++++++
                                     .../proc/mobject/session/test-scopes.hpp      | 72 ++++++++++++++++
                                     11 files changed, 383 insertions(+), 20 deletions(-)
                                     create mode 100644 src/proc/mobject/session/scope.cpp
                                     create mode 100644 src/proc/mobject/session/scope.hpp
                                     create mode 100644 tests/components/proc/mobject/placement-scope-test.cpp
                                     create mode 100644 tests/components/proc/mobject/session/test-scopes.cpp
                                     create mode 100644 tests/components/proc/mobject/session/test-scopes.hpp
                                    
                                    diff --git a/src/proc/mobject/placement-index.cpp b/src/proc/mobject/placement-index.cpp
                                    index 7fc5d9be0..38758d80e 100644
                                    --- a/src/proc/mobject/placement-index.cpp
                                    +++ b/src/proc/mobject/placement-index.cpp
                                    @@ -135,6 +135,13 @@ namespace mobject {
                                       }
                                       
                                       
                                    +  void
                                    +  PlacementIndex::clear()
                                    +  {
                                    +    UNIMPLEMENTED  ("purge the PlacementIndex, discarding any contained placements");
                                    +  }
                                    +  
                                    +  
                                       
                                       
                                       namespace { // implementation detail: default global placement index access
                                    diff --git a/src/proc/mobject/placement-index.hpp b/src/proc/mobject/placement-index.hpp
                                    index bd8950ef4..5d9da5ff7 100644
                                    --- a/src/proc/mobject/placement-index.hpp
                                    +++ b/src/proc/mobject/placement-index.hpp
                                    @@ -107,6 +107,8 @@ namespace mobject {
                                           
                                           ~PlacementIndex();
                                           
                                    +      void clear();
                                    +      
                                         protected:
                                           PlacementIndex() ;
                                           
                                    diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp
                                    index 86171e914..c70e4cf1e 100644
                                    --- a/src/proc/mobject/placement-ref.hpp
                                    +++ b/src/proc/mobject/placement-ref.hpp
                                    @@ -31,7 +31,7 @@
                                      **       these cases will just be a subclass or Placement
                                      **       (which in the mentioned example would mean it couldn't be
                                      **       passed to a API function expecting a Placement).
                                    - **       This is uggly, but doesn't seem to bear any danger.
                                    + **       This is ugly, but doesn't seem to bear any danger.
                                      **
                                      ** @see Placement
                                      ** @see PlacementRef_test
                                    @@ -71,6 +71,7 @@ namespace mobject {
                                       LUMIERA_ERROR_DECLARE (INVALID_PLACEMENTREF);  ///< unresolvable placement reference, or of incompatible type
                                       
                                       /**
                                    +   * TODO type comment
                                        */
                                       template
                                       class PlacementRef
                                    diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp
                                    new file mode 100644
                                    index 000000000..570fe90ff
                                    --- /dev/null
                                    +++ b/src/proc/mobject/session/scope.cpp
                                    @@ -0,0 +1,54 @@
                                    +/*
                                    +  Scope  -  nested search scope for properties of placement
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2009,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +#include "proc/mobject/session/scope.hpp"
                                    +#include "proc/mobject/mobject.hpp"
                                    +//#include "proc/mobject/session/track.hpp"
                                    +//#include "proc/mobject/placement.hpp"
                                    +//#include "proc/mobject/session/mobjectfactory.hpp"
                                    +//#include "proc/asset/track.hpp"
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +  
                                    +  
                                    +  
                                    +  /** TODO??? */
                                    +  Scope::Scope (PlacementMO const& constitutingPlacement)
                                    +    : anchor_(constitutingPlacement)
                                    +  {
                                    +    
                                    +  }
                                    +  
                                    +  
                                    +  ScopeLocator::ScopeLocator()
                                    +  {
                                    +    
                                    +  }
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +}} // namespace mobject::session
                                    diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp
                                    new file mode 100644
                                    index 000000000..05ff245fd
                                    --- /dev/null
                                    +++ b/src/proc/mobject/session/scope.hpp
                                    @@ -0,0 +1,70 @@
                                    +/*
                                    +  SCOPE.hpp  -  nested search scope for properties of placement
                                    +
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2009,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +*/
                                    +
                                    +
                                    +#ifndef MOBJECT_SESSION_SCOPE_H
                                    +#define MOBJECT_SESSION_SCOPE_H
                                    +
                                    +//#include "proc/mobject/mobject.hpp"
                                    +#include "proc/mobject/placement.hpp"
                                    +#include "proc/mobject/placement-ref.hpp"
                                    +#include "lib/singleton.hpp"
                                    +
                                    +//#include 
                                    +//#include 
                                    +
                                    +//using std::vector;
                                    +//using std::string;
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +  
                                    +  
                                    +  class ScopeLocator;
                                    +  
                                    +
                                    +  /**
                                    +   * TODO type comment
                                    +   */
                                    +  class Scope
                                    +    {
                                    +      RefPlacement anchor_;
                                    +      
                                    +    public:
                                    +      Scope (PlacementMO const& constitutingPlacement);
                                    +      
                                    +    };
                                    +  
                                    +  
                                    +  class ScopeLocator
                                    +    {
                                    +      
                                    +    public:
                                    +      ScopeLocator();
                                    +      
                                    +    };
                                    +///////////////////////////TODO currently just fleshing the API
                                    +  
                                    +  
                                    +}} // namespace mobject::session
                                    +#endif
                                    diff --git a/tests/43session.tests b/tests/43session.tests
                                    index 2999d6d68..d5218096c 100644
                                    --- a/tests/43session.tests
                                    +++ b/tests/43session.tests
                                    @@ -55,6 +55,10 @@ PLANNED "PlacementRef_test" PlacementRef_test <
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +#include "lib/test/run.hpp"
                                    +#include "proc/mobject/session/test-scopes.hpp"
                                    +//#include "lib/lumitime.hpp"
                                    +//#include "proc/mobject/placement-ref.hpp"
                                    +//#include "proc/mobject/placement-index.hpp"
                                    +//#include "proc/mobject/test-dummy-mobject.hpp"
                                    +//#include "lib/util.hpp"
                                    +
                                    +//#include 
                                    +//#include 
                                    +
                                    +//using util::isSameObject;
                                    +//using lumiera::Time;
                                    +//using std::string;
                                    +//using std::cout;
                                    +//using std::endl;
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +namespace test    {
                                    +  
                                    +//  using namespace mobject::test;
                                    +//  typedef TestPlacement PSub;
                                    +  
                                    +  
                                    +  /***************************************************************************
                                    +   * @test basic behaviour of the nested placement search scopes.
                                    +   *       Using a pseudo-session (actually just a PlacementIndex), this test
                                    +   *       creates some nested scopes and then...
                                    +   *       - discovers the scope of a placement
                                    +   *       - finds the parent scope
                                    +   *       - enumerates a scope path up to root
                                    +   * 
                                    +   * @see  mobject::Placement
                                    +   * @see  mobject::session::ScopePath
                                    +   * @see  mobject::session::QueryFocus
                                    +   */
                                    +  class PlacementScope_test : public Test
                                    +    {
                                    +      
                                    +      virtual void
                                    +      run (Arg) 
                                    +        {
                                    +          // Prepare an (test)Index backing the PlacementRefs
                                    +          PIdx index = build_testScopes();
                                    +          
                                    +          UNIMPLEMENTED ("function test of placement scope interface");
                                    +        }
                                    +      
                                    +    };
                                    +  
                                    +  
                                    +  /** Register this test class... */
                                    +  LAUNCHER (PlacementScope_test, "function session");
                                    +  
                                    +  
                                    +}}} // namespace mobject::session::test
                                    diff --git a/tests/components/proc/mobject/query-focus-test.cpp b/tests/components/proc/mobject/query-focus-test.cpp
                                    index 27ee07380..4500c0db6 100644
                                    --- a/tests/components/proc/mobject/query-focus-test.cpp
                                    +++ b/tests/components/proc/mobject/query-focus-test.cpp
                                    @@ -24,8 +24,8 @@
                                     #include "lib/test/run.hpp"
                                     //#include "lib/lumitime.hpp"
                                     //#include "proc/mobject/placement-ref.hpp"
                                    +#include "proc/mobject/session/test-scopes.hpp"
                                     #include "proc/mobject/placement-index.hpp"
                                    -#include "proc/mobject/test-dummy-mobject.hpp"
                                     //#include "lib/util.hpp"
                                     
                                     //#include 
                                    @@ -42,8 +42,6 @@ namespace mobject {
                                     namespace session {
                                     namespace test    {
                                       
                                    -  using namespace mobject::test;
                                    -  typedef TestPlacement PSub;
                                       
                                       
                                       /**********************************************************************************
                                    @@ -61,28 +59,14 @@ namespace test    {
                                           virtual void
                                           run (Arg) 
                                             {
                                    -          PSub p1(*new TestSubMO21);
                                    -          PSub p2(*new TestSubMO21);
                                    -          PSub p3(*new TestSubMO21);
                                    -          PSub p4(*new TestSubMO21);
                                    -          PSub p5(*new TestSubMO21);
                                               
                                               // Prepare an (test)Index backing the PlacementRefs
                                    -          typedef shared_ptr PIdx;
                                    -          PIdx index (PlacementIndex::create());
                                    -          PMO& root = index->getRoot();
                                    -          reset_PlacementIndex(index);
                                    -
                                    -          index->insert (p1, root);
                                    -          index->insert (p2,  p1 );
                                    -          index->insert (p3,  p2 );
                                    -          index->insert (p4,  p3 );
                                    -          index->insert (p5,  p4 );
                                    +          PIdx index = build_testScopes();
                                    +//          PMO& root = index->getRoot();
                                               
                                               UNIMPLEMENTED ("unit test to cover query focus management");
                                               
                                     //??      ASSERT (0 == index->size());
                                    -          reset_PlacementIndex();
                                             }
                                               
                                         };
                                    diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp
                                    index 3f96612ed..817883c4b 100644
                                    --- a/tests/components/proc/mobject/scope-path-test.cpp
                                    +++ b/tests/components/proc/mobject/scope-path-test.cpp
                                    @@ -22,6 +22,7 @@
                                     
                                     
                                     #include "lib/test/run.hpp"
                                    +#include "proc/mobject/session/test-scopes.hpp"
                                     //#include "lib/lumitime.hpp"
                                     //#include "proc/mobject/placement-ref.hpp"
                                     //#include "proc/mobject/placement-index.hpp"
                                    @@ -60,6 +61,9 @@ namespace test    {
                                           virtual void
                                           run (Arg) 
                                             {
                                    +          // Prepare an (test)Index backing the PlacementRefs
                                    +          PIdx index = build_testScopes();
                                    +          
                                               UNIMPLEMENTED ("unit test regarding placement scope handling");
                                             }
                                               
                                    diff --git a/tests/components/proc/mobject/session/test-scopes.cpp b/tests/components/proc/mobject/session/test-scopes.cpp
                                    new file mode 100644
                                    index 000000000..0b58081d5
                                    --- /dev/null
                                    +++ b/tests/components/proc/mobject/session/test-scopes.cpp
                                    @@ -0,0 +1,84 @@
                                    +/*
                                    +  TEST-SCOPES.cpp  -  builds a test PlacementIndex containing dummy Placements as nested scopes
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2009,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +#include "proc/mobject/session/test-scopes.hpp"
                                    +//#include "lib/util.hpp"
                                    +
                                    +//#include 
                                    +//#include 
                                    +
                                    +//using util::isSameObject;
                                    +//using lumiera::Time;
                                    +//using std::string;
                                    +//using std::cout;
                                    +//using std::endl;
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +namespace test    {
                                    +  
                                    +  
                                    +  namespace { // deleter function to clean up Test fixture
                                    +    void
                                    +    remove_testIndex (PlacementIndex* testIdx)
                                    +    {
                                    +      REQUIRE (testIdx);
                                    +      testIdx->clear();
                                    +      ASSERT (0 == testIdx->size());
                                    +      reset_PlacementIndex();  // restore default Index from Session
                                    +      
                                    +      delete testIdx;
                                    +    }
                                    +  }
                                    +  
                                    +  
                                    +  /** @note when this object goes out of scope, the activation of this
                                    +   *        test PlacementIndex will be cleared automatically, and the
                                    +   *        default Index within the session will be re-activated. 
                                    +   */
                                    +  PIdx
                                    +  build_testScopes()
                                    +  {
                                    +    PSub p1(*new TestSubMO21);
                                    +    PSub p2(*new TestSubMO21);
                                    +    PSub p3(*new TestSubMO21);
                                    +    PSub p4(*new TestSubMO21);
                                    +    PSub p5(*new TestSubMO21);
                                    +    
                                    +    // Prepare an (test)Index backing the PlacementRefs
                                    +    PIdx index (PlacementIndex::create().get(), &remove_testIndex); // taking ownership
                                    +    reset_PlacementIndex(index);
                                    +    PMO& root = index->getRoot();
                                    +
                                    +    index->insert (p1, root);
                                    +    index->insert (p2,  p1 );
                                    +    index->insert (p3,  p2 );
                                    +    index->insert (p4,  p3 );
                                    +    index->insert (p5,  p4 );
                                    +    
                                    +    return index;
                                    +  }
                                    +  
                                    +  
                                    +}}} // namespace mobject::session::test
                                    diff --git a/tests/components/proc/mobject/session/test-scopes.hpp b/tests/components/proc/mobject/session/test-scopes.hpp
                                    new file mode 100644
                                    index 000000000..760ab0d75
                                    --- /dev/null
                                    +++ b/tests/components/proc/mobject/session/test-scopes.hpp
                                    @@ -0,0 +1,72 @@
                                    +/*
                                    +  TEST-SCOPES.hpp  -  builds a test PlacementIndex containing dummy Placements as nested scopes
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2009,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +*/
                                    +
                                    +
                                    +#ifndef MOBJECT_SESSION_TEST_TEST_SCOPES_H
                                    +#define MOBJECT_SESSION_TEST_TEST_SCOPES_H
                                    +
                                    +
                                    +//#include "lib/lumitime.hpp"
                                    +//#include "proc/mobject/placement-ref.hpp"
                                    +#include "proc/mobject/session/test-scopes.hpp"
                                    +#include "proc/mobject/test-dummy-mobject.hpp"
                                    +#include "proc/mobject/placement-index.hpp"
                                    +//#include "lib/util.hpp"
                                    +
                                    +#include 
                                    +//#include 
                                    +//#include 
                                    +
                                    +//using util::isSameObject;
                                    +//using lumiera::Time;
                                    +//using std::string;
                                    +//using std::cout;
                                    +//using std::endl;
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +namespace test    {
                                    +  
                                    +  using std::tr1::shared_ptr;
                                    +
                                    +  using namespace mobject::test;
                                    +  typedef TestPlacement PSub;
                                    +  typedef shared_ptr PIdx;
                                    +  
                                    +  
                                    +  
                                    +  /** helper for tests: create a pseudo-session (actually just a PlacementIndex),
                                    +   *  which contains some nested placement scopes.
                                    +   *  @return new PlacementIndex, which has already been activated to be used
                                    +   *          by all Placements from now on. This activation will be cleared
                                    +   *          automatically, when this object goes out of scope.
                                    +   * 
                                    +   * @see mobject::PlacementIndex
                                    +   * @see session::SessManagerImpl::getCurrentIndex()
                                    +   * @see mobject::reset_PlacementIndex
                                    +   */
                                    +  PIdx build_testScopes();
                                    +  
                                    +  
                                    +}}} // namespace mobject::session::test
                                    +#endif
                                    
                                    From cfc17e75ba9dc6783a903d3f965f55617747591c Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 16 Oct 2009 21:20:30 +0200
                                    Subject: [PATCH 008/377] refined and clarified planning of Scope and
                                     QueryFocus
                                    
                                    ---
                                     doc/devel/uml/class153349.html       |   4 +++-
                                     doc/devel/uml/class153605.html       |   2 +-
                                     doc/devel/uml/class153861.html       |   2 +-
                                     doc/devel/uml/fig136325.png          | Bin 21713 -> 23017 bytes
                                     doc/devel/uml/index_71.html          |   1 +
                                     doc/devel/uml/public_operations.html |   1 +
                                     src/proc/mobject/session/scope.cpp   |   2 ++
                                     src/proc/mobject/session/scope.hpp   |   8 ++++++++
                                     uml/lumiera/132357                   |  23 ++++++++++++++++++++---
                                     uml/lumiera/136325.diagram           |  24 ++++++++++++------------
                                     uml/lumiera/lumiera.prj              |   2 +-
                                     wiki/renderengine.html               |   8 +++++---
                                     12 files changed, 55 insertions(+), 22 deletions(-)
                                    
                                    diff --git a/doc/devel/uml/class153349.html b/doc/devel/uml/class153349.html
                                    index 48617516d..845e35a8d 100644
                                    --- a/doc/devel/uml/class153349.html
                                    +++ b/doc/devel/uml/class153349.html
                                    @@ -19,6 +19,8 @@
                                     

                                    Declaration :

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

                                    Declaration :

                                    Stereotype: holds

                                    -
                                    + +
                                    Operation getParent

                                    Declaration :

                                    • Uml : + getParent() : Scope
                                    • C++ : public: Scope getParent ()
                                    +

                                    All public operations : getParent

                                    diff --git a/doc/devel/uml/class153605.html b/doc/devel/uml/class153605.html index 3978922a5..abd092454 100644 --- a/doc/devel/uml/class153605.html +++ b/doc/devel/uml/class153605.html @@ -18,7 +18,7 @@

                                    Declaration :

                                    • C++ : class QueryFocus
                                    -
                                    Relation scopes (<unidirectional association>)

                                    Declaration :

                                    Stereotype: has_a

                                    +
                                    Relation scopes (<unidirectional association>)

                                    Declaration :

                                    Stereotype: owns

                                    diff --git a/doc/devel/uml/class153861.html b/doc/devel/uml/class153861.html index 1ef4ad515..70c14570f 100644 --- a/doc/devel/uml/class153861.html +++ b/doc/devel/uml/class153861.html @@ -20,7 +20,7 @@
                                    Relation <unidirectional association>

                                    Declaration :

                                    -
                                    Relation <unidirectional association>

                                    Declaration :

                                    Stereotype: use

                                    +
                                    Relation <unidirectional association>

                                    Declaration :

                                    Stereotype: uses

                                    diff --git a/doc/devel/uml/fig136325.png b/doc/devel/uml/fig136325.png index 32668374dbb1f9ba3c7570c8617e463b2eb4f81b..7aa5b52890c63f554d7a00ddc8078b462693409a 100644 GIT binary patch literal 23017 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 literal 21713 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 the session can be comprised of several EDLs,
                                    there is only one Fixture, which represents the actual
                                    configuration of all Objects to be rendered getFrameoperationmode = READ, WRITE, ... getIDoperation +getParentoperation getParentsoperationList of entities this asset depends on or requires to be functional. May be empty. The head of this list can be considered the primary prerequisite getPlaylistForRenderoperation getStateProxyoperation diff --git a/doc/devel/uml/public_operations.html b/doc/devel/uml/public_operations.html index 717b3562d..4e6395642 100644 --- a/doc/devel/uml/public_operations.html +++ b/doc/devel/uml/public_operations.html @@ -44,6 +44,7 @@ getFixtureSessionWhile the session can be comprised of several EDLs,
                                    there is only one Fixture, which represents the actual
                                    configuration of all Objects to be rendered getFrameFilemode = READ, WRITE, ... getIDAssetManager +getParentScope getParentsAssetList of entities this asset depends on or requires to be functional. May be empty. The head of this list can be considered the primary prerequisite getPlaylistForRenderFixture getStateProxyRenderState diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp index 570fe90ff..fe5f60bcb 100644 --- a/src/proc/mobject/session/scope.cpp +++ b/src/proc/mobject/session/scope.cpp @@ -22,6 +22,7 @@ #include "proc/mobject/session/scope.hpp" +#include "proc/mobject/session/query-focus-stack.hpp" #include "proc/mobject/mobject.hpp" //#include "proc/mobject/session/track.hpp" //#include "proc/mobject/placement.hpp" @@ -42,6 +43,7 @@ namespace session { ScopeLocator::ScopeLocator() + : focusStack_(new QueryFocusStack) { } diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp index 05ff245fd..fa7a0a0a7 100644 --- a/src/proc/mobject/session/scope.hpp +++ b/src/proc/mobject/session/scope.hpp @@ -30,6 +30,7 @@ #include "proc/mobject/placement-ref.hpp" #include "lib/singleton.hpp" +#include //#include //#include @@ -39,8 +40,10 @@ namespace mobject { namespace session { + using boost::scoped_ptr; class ScopeLocator; + class QueryFocusStack; /** @@ -53,11 +56,16 @@ namespace session { public: Scope (PlacementMO const& constitutingPlacement); + static Scope const& containing (PlacementMO const& aPlacement); + static Scope const& containing (RefPlacement const& refPlacement); + + Scope const& getParent() const; }; class ScopeLocator { + scoped_ptr focusStack_; public: ScopeLocator(); diff --git a/uml/lumiera/132357 b/uml/lumiera/132357 index ef09856d3..fa75cd0cd 100644 --- a/uml/lumiera/132357 +++ b/uml/lumiera/132357 @@ -1,6 +1,6 @@ format 58 "Placement" // ProcessingLayer::MObject::Placement - revision 1 + revision 2 modified_by 5 "hiv" // class settings //class diagram settings @@ -68,6 +68,23 @@ ${inlines} " classrelation_ref 177541 // b multiplicity "1" parent class_ref 152453 // PlacementRef + end + + operation 138885 "getParent" + public return_type class_ref 153349 // Scope + 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 @@ -110,7 +127,7 @@ ${inlines} classrelation 177797 // scopes () relation 167813 ---> - stereotype "has_a" + stereotype "owns" a role_name "scopes" protected cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; " @@ -176,7 +193,7 @@ ${inlines} classrelation 178565 // relation 168581 ---> - stereotype "use" + stereotype "uses" a role_name "" protected cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; " diff --git a/uml/lumiera/136325.diagram b/uml/lumiera/136325.diagram index 5b265342a..80ebfe88a 100644 --- a/uml/lumiera/136325.diagram +++ b/uml/lumiera/136325.diagram @@ -10,7 +10,7 @@ classcanvas 128133 class_ref 152453 // PlacementRef end classcanvas 128261 class_ref 153349 // Scope 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 214 212 2000 + xyz 204 208 2000 end classcanvas 128517 class_ref 153477 // ScopePath 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 @@ -29,8 +29,8 @@ classcanvas 129413 class_ref 152069 // PlacementIndex xyz 340 345 2004 end note 129669 "actually -implemented through" - xyzwh 250 303 2000 131 50 +implemented through the:" + xyzwh 241 308 2000 140 45 classcanvas 129797 class_ref 153861 // ScopeLocator 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 196 17 2000 @@ -42,18 +42,18 @@ end note 131333 "this connection is established by the current session" xyzwh 361 39 2000 158 47 relationcanvas 128389 relation_ref 167557 // - from ref 128261 z 1999 stereotype "<>" xyz 277 231 3000 to ref 128133 + from ref 128261 z 1999 stereotype "<>" xyz 281 219 3000 to ref 128133 no_role_a no_role_b - multiplicity_a_pos 328 237 3000 multiplicity_b_pos 268 237 3000 + multiplicity_a_pos 328 237 3000 multiplicity_b_pos 278 237 3000 end relationcanvas 128645 relation_ref 167685 // - from ref 128517 z 1999 stereotype "<>" xyz 135 231 3000 to ref 128261 - role_a_pos 176 214 3000 no_role_b + from ref 128517 z 1999 stereotype "<>" xyz 130 231 3000 to ref 128261 + role_a_pos 166 214 3000 no_role_b no_multiplicity_a no_multiplicity_b end relationcanvas 128901 relation_ref 167813 // - from ref 128773 z 1999 stereotype "<>" xyz 49 181 3000 to ref 128517 - role_a_pos 86 195 3000 no_role_b + from ref 128773 z 1999 stereotype "<>" xyz 54 182 3000 to ref 128517 + role_a_pos 88 194 3000 no_role_b no_multiplicity_a no_multiplicity_b end relationcanvas 129157 relation_ref 167941 // @@ -64,7 +64,7 @@ relationcanvas 129157 relation_ref 167941 // no_multiplicity_a no_multiplicity_b end relationcanvas 129285 relation_ref 168069 // - from ref 128005 z 1999 stereotype "<>" xyz 193 286 3000 to ref 128261 + from ref 128005 z 1999 stereotype "<>" xyz 193 289 3000 to ref 128261 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end @@ -81,7 +81,7 @@ relationcanvas 130053 relation_ref 168197 // no_multiplicity_a no_multiplicity_b end relationcanvas 130309 relation_ref 168325 // - from ref 129797 z 1999 stereotype "<>" xyz 237 141 3000 to ref 128261 + from ref 129797 z 1999 stereotype "<>" xyz 237 139 3000 to ref 128261 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end @@ -92,7 +92,7 @@ relationcanvas 130949 relation_ref 168453 // no_multiplicity_a no_multiplicity_b end relationcanvas 131205 relation_ref 168581 // - from ref 129797 z 1999 stereotype "<>" xyz 339 91 3000 to ref 130437 + from ref 129797 z 1999 stereotype "<>" xyz 338 92 3000 to ref 130437 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj index 98d69abad..890574f20 100644 --- a/uml/lumiera/lumiera.prj +++ b/uml/lumiera/lumiera.prj @@ -1,6 +1,6 @@ format 58 "lumiera" - revision 54 + revision 55 modified_by 5 "hiv" cpp_root_dir "../../src/" diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 6663337cb..2c9abe508 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3051,10 +3051,10 @@ Placement references mimic the behaviour of a real placement, i.e. they proxy th {{red{WIP}}}
                                    -
                                    +
                                    MObjects are attached into the [[Session]] by adding a [[Placement]]. Because this especially includes the case of //grouping or container objects,// e.g. tracks or [[meta-clips|VirtualClip]], any placement may optionally define and root a scope, and every placement is at least contained in one encompassing scope &mdash; of course with the exception of the absolute top level, which can be thought off as being contained in a scope of handling rules.
                                     
                                    -Thus, while the [[sequences (former called EDL)|EDL]] act as generic container holding a pile of placments, actually there is a more fine grained structure based on the nesting of the tracks, which especially in Lumiera's HighLevelModel belong to the sequence (they aren't a property of the top level timeline as one might expect). Building upon these observations, we actually require each addition of a placement to specify a scope. The implementation of this tie-to-scope is provided by the same mechanism as utilised for relative placements, i.e. an directional placement relation. This relation actually is implemented by the PlacementIndex
                                    +Thus, while the [[sequences (former called EDL)|EDL]] act as generic container holding a pile of placments, actually there is a more fine grained structure based on the nesting of the tracks, which especially in Lumiera's HighLevelModel belong to the sequence (they aren't a property of the top level timeline as one might expect). Building upon these observations, we actually require each addition of a placement to specify a scope. Consequently, for each Placement at hand it is possible to determine an //containing scope,// which in turn is associated with some Placement of a top-level ~MObject for this scope. An example would be the {{{Placement<Track>}}} acting as scope of all the clips placed onto this track. The //implementation//&nbsp; of this tie-to-scope is provided by the same mechanism as utilised for relative placements, i.e. an directional placement relation. Actually, this relation is implemented by the PlacementIndex within the current [[Session]].
                                     
                                     
                                     [>img[Structure of Placment Scopes|draw/ScopeStructure1.png]]
                                    @@ -3382,7 +3382,7 @@ Viewed as a micro program, the processing patterns are ''weak typed'' &mdash
                                     
                                    a given Render Engine configuration is a list of Processors. Each Processor in turn contains a Graph of ProcNode.s to do the acutal data processing. In order to cary out any calculations, the Processor needs to be called with a StateProxy containing the state information for this RenderProcess
                                     
                                    -
                                    +
                                    When querying contents of the session or sub-containers within the session, the QueryFocus follows the current point-of-query. As such queries can be issued to explore the content of container-like objects holding other MObjects, the focus is always attached to a container, which also acts as [[scope|PlacementScope]] for the contained objects. QueryFocus is an implicit state (the current point of interrest). This sate especially remembers the path down from the root of the HighLevelModel, which was used to access the current scope. Because this path constitutes a hierarchy of scopes, it can be relevant for querying and resolving placement properties. (&rarr; SessionStructureQuery)
                                     
                                     !provided operations
                                    @@ -3392,6 +3392,8 @@ Viewed as a micro program, the processing patterns are ''weak typed'' &mdash
                                     * get the current scope, which is implemented as Placement
                                     * get the current ScopePath from root (session globals) down to the current scope
                                     [>img[Scope Locating|uml/fig136325.png]]
                                    +!!!relation to Scope
                                    +There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current scope.// But QueryFocus is more of a //binding// &mdash; it links or focusses the current state and into a specific scope with a ScopePath depending on the current state. Thus, while Scope is just a passive container allowing locate and navigate, QueryFocus by virtue of this binding allows to query this current location.
                                     
                                     !implementation notes
                                     we provide a static access API, meaning that there is a singleton behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. This link works by the current session grabbing the query focus and attaching to it. This attachment is shallow, i.e. the QueryFocus doesn't have knowledge about the session, which allows the focus to be unit tested.
                                    
                                    From a662b176bb035359c590792d692beb782ca8232f Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 17 Oct 2009 02:15:28 +0200
                                    Subject: [PATCH 009/377] WIP test-driven brainstorming: what is a Scope?
                                    
                                    ---
                                     doc/devel/uml/fig136325.png                   | Bin 23017 -> 23252 bytes
                                     doc/devel/uml/index.html                      |   2 +-
                                     .../proc/mobject/placement-scope-test.cpp     |  71 ++++++++++++++++--
                                     uml/lumiera/136325.diagram                    |   2 +
                                     4 files changed, 69 insertions(+), 6 deletions(-)
                                    
                                    diff --git a/doc/devel/uml/fig136325.png b/doc/devel/uml/fig136325.png
                                    index 7aa5b52890c63f554d7a00ddc8078b462693409a..4df084bb6b83584293637c283b1dd680203ab1d1 100644
                                    GIT binary patch
                                    literal 23252
                                    zcmcG$bySsW*EhNVm6Y!84(XDR?hp`=5=6Q~I#jy58|m(llul`+ySp3C#eSdfeV^|+
                                    z-}&Q=an2fh$Yw3>x?;}xi@5@o6eM3G;3GgFkk`^uV(%dkXle)qstyhsyo2HiZw7&o
                                    zLZrpssXC|ZFSux6OwU4&*?qi!T~C$-1&E^>Mh;L{;t6w=$Y9~Tz{JF|rKA1MH1+*^
                                    zEopFnVez5HIk`a*Edq9sjFz;H@XG@2`BHv^FS46=pLaR9;mL$+r5Bgh*4R^0c(>%J
                                    z6S=nr2l0@4Y+ry&2c$<;6M&z>%EG-+;2y|O?Z9tRa6W|K2RbwvECk~1^Z(sPS&Rp-
                                    zAUEIi6RML*;g3~CA+E1QkWr}!Sz^CpbRu@(j#)uNFkiu#gNswX5J3h%;JlqRU8Fj-$8tMekIl-G!48(k?oEb();J=7ZLvlRaMHNG|R5Uo+Tlpr4|+j`Y1d5
                                    zR^0|RY%*0P)KJv->LeBJH&?&DmJ}At1qOYrFc3#tGC0@|DJHi+-{*CADX@eI
                                    z@rKj4(IY^`Lh9f-8VC#?7#M!sS#B?rmvd;8;q_|S9m!nX+`OWv?-vwgw%_{r85gEU
                                    zmNlf^NU!@%$aS=W)BRrAnM0$Uo11@OA%-%dA8SmkX=*BC7A?MfLDd<0WY}6xe?Kyb
                                    zASOl;65;mjsIo{?rzT^Cfu!VC#b+vg{T*Ll{-Ghqn_L?U3JP-a?;3ssu#j!KdV|*i
                                    z1C?J&OG*yf+xrd=xja3s%*=i`s~{jUu(5Gn?d6>=w|^Gx*f?5Br%>NY84y-i&n^z(
                                    z{p@Gzaw9)X&%r5)gXO_(I#!>jsE386X4mqwsK|DspCl}d`pXwNf#wtUU~#y~X(0t!
                                    zeviEmq89r}bSl-?xe$ohOR(VLS33Ot{O^4HTsODkU7Rg~!}ZJ!e|E)Ym6TZNqrEZg
                                    z^`4r#{QK9tG^l@gvC`F1yVa8(8@sW;pMy<+W{ZI&-Goo4Av>F$Z#G?OV(Npng?n5q
                                    z7B+5za2`XI#(r_}o0hKJJe;^#*6Ffz91IL$AM(ZLsc3J*N5w1s#>vcxoh+e(o-!6|
                                    zIaishkh;HWkQVP`x;0EuXT5b^lGALBj#Laaf-^Dzh5p-(7Kd$-)JI!~>HfZ@)vHxn
                                    zQc^%bKny$S1!Vgr9IrQYaWT^2q5$Q=2MFXA!E+q!;s{hY-hbag5inqbi+~;SfB)zX
                                    zZ1-j;3~1$eOq$eh5ip$_ZQrsE=Iqnox)c-@RX82Jf`!FUj@8zh%g?J*ZCmFPalNVJ
                                    z<-f~|h!D>*i6N)=-KnGv_@<9bT~jdp>C@|gu7UU=D5w*yx?Amr%IT>olbx~DF)K8Z
                                    zKk2PAO}uKeB@p2;8^ZVxG+1CBf@^EPawQKLR7i&2w$|4RulAXO*<&i9DlAk;_iFKV
                                    zhRlW%T*=F;kM4x=@hu8HIJ_oP)tU>?51FZI#pmedP{S5NT*gpscJ_PW1Cijky!52o#iUT3Xn2S)PFN@p^A0A{?3C(osl=;4c^U
                                    zxdC&(ysgXHT4V!98k(w9esw>epN|*n=7xsDRmNom_+fvNjkk6hQr)QuXr6C~&#jh?
                                    z(V}nRmw&C54nA6BC~E(or7%=_7RB8{JnN+vz1l%>a%)^j6m@Jq3<`@9=DM-0yIacH
                                    z%1f_@$=d;zIwB%@K7P%+t8_4s2W73p<0i5)aW4E*=Ed!C=y0!aj`U*j&n
                                    zS9hw;&Q?*hHr1MYNhtYn%e&C()j92?F5bmt7c2BMcz2u`x~Gk7%?pNA+c75(Cyhs$
                                    z?~^xu*qZSl-L8}OrzuM6L)+W5EADSmzWd|Yw7o$Z-cUkY^HN-wx^6-~x5GrH=1Qq?
                                    z_*!W+G+X((r+vxu*Yw1>`??gTPej~Q0)-?qTjGVEpC`E8cX0A)#SO-ao|cxMrw+CMvY2nj}I~z3A8DfpD-!m*z00pEj!g8`=DI~+AFr`x
                                    z^Wj86Iy-v@sz^ZrK{yEuE4N-r4rllHI2u_@bX87c<8WKs)$s~qPq^1ySvo?+?akSA
                                    zM+f`mzUESE>+W#sBTra3K^-ZrNqX9%^Jyg4<>kB1R
                                    zp)*XeC;n0|>waUg96>f0M&hNa9*>GErSie3N~4{QE_!efRRjr1tI6f;!hQ>>xR@(9
                                    z=OmY7YO1?Tb9`no>I|>P)K_xX4j*@=$8(baxMhkAZq=u`%16mKJwT-kxIelx1j&HKX-pjhb2ogZh}7
                                    zD#yh|S5t@Y%VxrtB7t{yhJ^F+qPxm0GvKfJKUdyXD{}WZf{FK@|mr(
                                    z?u%pU{8%I>4`c9Io{(^OV?95VFp(I$mYJ;Gp*y5-b+vjZnLSa?;6jf2Y#biL2pLZV
                                    zyEn0NxZ6nOT0%F=DhaQ#%I*HxNs_nTe*&to{NP#u*mEE(yFPI
                                    zrsE-0vJP_c$$HI6XMHp|Ji~3}f9db^hJ0_Pr
                                    zjCswcCP}>J+03!eK_EwXr=pi`KJVC5pd$J8z;$W9xHxNdbxkyPnl(|Pwib>|T~E(v
                                    zWZHgHE>Vz(%y972y~`GI;sLv;Xel(Widm`789N7MT&xMlqCvyk;sUhFIIFooT8`?x
                                    zp%#{kojoYTTp<#9(Sc8PHo|b4_4O9XLV5}Kyh|F3g(OoG3B3FiK5|4vH&(vu??5dX
                                    zKy>u&S5~==y@a1kt7kaLTMa7{=fej#avf3itKrEaa6@1=VUdW7GmGweVi~Bz!UiiV
                                    zPh4H05!U7KN(ydtlt=5Oqjd#5K5D9VY86Mmfcq=Ow*bE%(D!uqGRhxM!D5jQ#_{l~7{1)l0Qu2vYs^~sch8C)wH!a=owvTl#^#&*}
                                    zh#^v-a!17>|0|pa3qc3vdne+nc?c;u1Z4h82!vf4hSc<0@~`BWRpj=C$>M5@+%BV?
                                    zj{MoYd1bkBB@7sx_t|h2lDN|C?PFHIg~S#UR#8aAv`BM6)dCr#iT`Y+9Zl}l>fVr?
                                    zo*r3pkoa(?C+M
                                    zi|iUd9p~0p+aZ_-S>?#(z$}!*zwP`>_KL=Zapbmt1R-RSRwu7;_1}w8v9Y};?CQsa
                                    zf7>J+$1kwpmlAw%047#aD|s*D9TgFg1(#b+U>}%pP_duju-JW}M!AZgu|Vnwz?9@m
                                    zot%+gSI!z`_RyAqPQ|v9^
                                    z^J=*sA+vkjv?M0h_OlveDSZ5B(Q0)ETVWXWWV@Y~sgaqp1f6O=kjE2DxS~FMEh?
                                    zBqeYbU*3=!CsR-s^rWQ?Qw|wb1z#SO6_tKSQQ1&^0b`y~R)5PE
                                    z2XzC;`CtFY&b)3L$M7Ef9znru_q3kSqO?xaAdUW30IC-s6vC(Lj%`Y+pW0scB7^dm
                                    z79l`Dco)>XJEX>)k!{ti-iV#Vq)f-h&=noFZ^>3*<%h&&WG<7Eg3-}EQ75N=)z+eQ
                                    z;I6kuM5sn$%JSG`n9SF|1kmQytCo1?hcHx7_PSghHWAmz`y8M_kmH+QDJnwHb8VVa
                                    zIy*ZvGDxMT5>m8LiPKId)pb>JO;{5zR#xx|3(wnxos?s}ZcdjJWAM4He&+YPgZi12
                                    zRFI0QcjUNA)ITVmd0}QE=IQ<>c_>*$R0R7XKYy<7skpeQ*(CB|xgADq@-3;|$PrXj
                                    zCb-t8Kp`Z0))W8EPRAwpDu-dhJ?j=te3Di!@IdFS4-ll!0I#;V&+Knv7iO`EYRwh>
                                    zTz6tqG%=a2{PJslUgTh(i_~X0tyw0U_pQrml!nv!_7laUsYyta?OIF04n5z3vSiO)
                                    zUV15+Pk(>H$B(kAYN>)x?gMjmM>kW!YtElOi99_HQ%DRh)E!}pABf+^S7SI&N9
                                    zVP-DRAjKzJU#WOaX85^^nPROtcat1{NdNknS6SKrdP>CkeA_pAJU2IY3)MOw`c^==
                                    z$tH1nem*58#^LVLauJh;CU1AwjIihI^mM9BPftaq>p0EG5=IrQrF;Sqx
                                    z#Ke@EnyT0A%IS2d?K9%_c$U65U6!1fsQK|@QgX7oni^Ucxeu4sJkQttzwE}t4qv}U
                                    zO>S&$+2=SQlKHIVbP9o8NzER8AKf>o`u_dzld+_vABJ2$O7cVP7kgU|dwR3-@;8~8
                                    zX%rIqjt()XE+0ygbl#(Tt%|+y(^pJO`B-CCTUEuY30;u6QXd%^S5{^YjtqcX0(EU|
                                    zt?tO=Bpk|BLFw?sI6-;}VQ1ZCW&XjTenMo78aV-oWVgQL_`5KwOg8WBx#x3
                                    zD0^`yr{tKJ<-4nJO3LEw(HNVi>Y|Tw@{UGBm4;O;(aDNa1SiT%LS!-5xGL)Eun5wG
                                    zY2F+G7i*N`Fy@Yqj(vT7H8nMhi;EaE3hVMGmzTo>1IcV(`T@wz&dz>#co-iWLqbB@
                                    z-P^-q(bZN{t8u?M{rgt~7S=x{C8fW=|ND1nq>hQn$%XlObaZs1!31S(?IwdR1nOw%
                                    ziS5gg=}xIP=r#_1HXvx}%?D=8`Y{I|S4PeF&*elz~4Rd1-mm9D}4
                                    z?yIQPp?YH@J{Wj3G+uf6KSvAZAFF#8!6xB%vTMMXm?|n2TpeH$`2HjMuf_b57q-ZD
                                    zS?fnm4hfy+q_LU4+197Q%^_3s=|}dvvZA7{K#UxrM`x@aTkPOa)ZM~3$#C7b?$`SV
                                    zb60?8a6Qk3n)&8rYmXvEG=f;kUyhA~vvqiQxVCmSt|;W<;!=>Gf1Ep*%zd;!Q^lg&
                                    zb%HWi{BFD#2ma#^tg|C@r;8Q^T^B3Fo4u?WN%1;pMwka=94_#_^h~W!ej7
                                    zu|N}XXk-(~&&YVouqR2Lm%Eu)TPqPxlFmpQ5EgQ-qE7PeCj-Mcsz_m>gSB;DDnClA
                                    z%lPV{RYzTEUon{3y4J>j)nw786q&EG$c
                                    z<@m@aV|RBFio!Ym9}rw+5I|Q}f6M=jkFzo}E9rSbNA_wVe(M`FtoS=uXD`Vw%)4Hu
                                    zifaSoK|Up@s`u9G@hxDGhKHF21s^Z=rrlL+2(M00pGheRiC1B3U|E7a++};;7fl0;
                                    zOxR|tt*7_YAIrcKmiO}~A)f=>6AxT=S((?#syJa!aB%SJ*RKP!dY!UMOPMJtJ0~YE
                                    zMlwY$EiK(uUWgLHm|I+KEc}{A-MW+vBdq-d)zK*i+as%4EX!{Ek)B~3o4HyNZgPUq
                                    z{rb(H?(PT)m9Ysz53qHoNpZvC7waRxp?<71e04%IUBsh%J7;|t8cH)}B7;E__OO$O
                                    zOUTmf%<6f6t?bZvI^QrgG$eFd5U2%k4itH`PQ~1_#0`eaHnjg}Ky*AAv9<
                                    zh9?wz{5MqO%d{1?C4kn!}R0T>%#neIArA9@f{)}qS4V&
                                    z1qFraQXMV8_yq;^N05nzkqDK7P@0`>f3n(@rV@M!_
                                    zKL(zcExPsasNqXs3=kjUjA0aRxQyodtJN!rA>rCEqg`^padve&!bozPNd
                                    za_@W!tmCu+99$?~4&zOhQBWjxpIF^}_p5LFjf;==Ht_YuAni^$c0e0X+!F
                                    z2I0To*GEts>LM$@oKI$wev>w1eze%k?|hum-2AZK7ww|L)3}ctwpLJ3psA@@SXcr3V6BqUlrABf*Ne=;%22P3Ge
                                    z%3(V86D&$>EUXhF(kXda*+MVjbzz9qY@qx+;Ru7P>;fMBw@Umt_l
                                    z$jHe3y*mmDib12uBBqzulj(RaAgIvIP0h``gd1Z~a^BsgynKGMm!P1N
                                    z*tglEM)HUWz$@?hsN*341m{4W}L%
                                    z7m`R7^%rKrT*T0jvVwHbaskz@^ZVHksY4V}>f;*NW@?oOVx-T<0t7J$2_%^7WS_*H
                                    zu8sk(y|HDju1-Q$+8r2>^|lF+w=cH4#xcYm4U17of^KqQVQJuXPtJFO^gN~G9-M#t
                                    z!|&2m2sUgj{A!Jge)8BFPIp(iy>gO()5oRY;27#PaS;}NE7H3lKu9(*ao$v0JGv;?
                                    zJL{SXIMLl*J_ARj&la;W-%*pekCH)==603F@#eUu@}v2u1?xMO{{?#jt-8~W(T|!N@ScN8sNB833
                                    z0VDFQTzNX#xWPA^lP(v9H_?il%gzM_JB5G$LSSK|Q&Q|HBnuDbT@s2Sw*D;r%u8=@
                                    zKAC1|DZjXIB;a!(wGL|I&NEgyryp^`LY6y4xMYm*E>*aM!?0UjJ*}+r;&VPW$G}J}
                                    zeLvDO@?9T^>yFJ&f4zXn;G2Te{=Oj^uPH~)@UU#BEaMav{?NBxO(mtr4wRe@zt_3r
                                    zra*t<(Jd_AKVA`KO?|vFb!+h@_2J{=3nyZLN0en@oHw;99pKIhuFEkdgJmWGYTBWr
                                    zVqr_leWqLJ~|*JJZ7
                                    zB<3IP^xtL6jdm<^;i+Yww20#$0F+QsxdHSC4=)t3tMc(#PCzs
                                    zt5w#&V*&Rl#`yn;&xjEJ-{Q0Q_BXY4Pw~;wiBVDSpB@XFe3yBMaT7*bTh9W}?5_^^
                                    zeNh|#1G(AOeto>RMCy)*%gmN!p=aO+xZ|Tu(e3GQuVpXVCOviin6zM<=ZnhR%$0(i
                                    z4Z~AK28IV%l(gd^JiNrS{h2+0SI#zPTwJYa($g<55AMDUXveXnYwCKQ?ToAY`eLyg
                                    zC3xQM&~z4c<|pNDW??ZH0sSwgF2WxrJtsF!(1G?X_f?Vkv>B>MOUn`-p2ycSquTgs
                                    zB*i}mmX<_@1aZucH#b|!EP7l|*K3?OIKj%haS4bpFLC?UdfK;Z)z
                                    zucudPZ>DNmtIo*8Bm|%TE06K3)8(_fqbsZV`m)l)clS5jqlgA%yu4DHiBnTktQLQl
                                    zRq{$xc+Uo|mddEr%L;e{)|^57X|V5bI{4V770`Gaz|wjSBw~XqTdyZgxXiga0-&sp
                                    z0o3;TA|#;K)XY^OZgbNJoGD{GZ{Sbruecb@3Cn*C-#h4R4|Y?>|6ad(&EaLHN(4o&i_
                                    znp$IB-S}{-|5B5wty3M@!1UxK>0^)W{l>tS69Lix@&eQ~`8Ihzls4Qv&u>=GQTF`v)TW<;`MkFLn|-t+hW)kLd1_;Tjw;K_<0iCwulw%
                                    z6r9+^ij0plh4CkAXw53C1)RCMyPUlAljFaa(|VSO*l+p=tjT?-gqK$f=+H<=?kFTJHuu+c54Qz2*fkCX1L*d9|E
                                    zAZo*!s0J{
                                    z=}5W=f&9$EIeA6qaHJdU*DV4hUj+pta_cD7-m?Zmg^||C&*jG7n#RWP?VlbaPu3(a
                                    z9w>uCBJ6r2k2gwIOOcV?ArQ2z@mLxKLWYA60a52}ywDOt1>&bFk|5L8&~`Quk}gq>
                                    zH~0`JKyCByTmgDrSg=h=vJTV>@Bb^2cYPNoTx@o8I$nO~=5`0F_OskixV5%x-CA{4
                                    zHFeLg&$w|hF@_cvDF7J8#)7hOc5JNDun!&lc^e>=zkK;uy?%MsB{DobTv1V>k}Jn+
                                    zyDA1C=%-K1p!9qZll|ZIX7+=};T0%WwdsV@dWTG*S1vgE`$yW6I&<%k;ia*pD}*Ib
                                    zMRfro(B9sTh{LR^q5^;_`4Xm2L~!uH-PO_6!JN9Xa%6JyFS`vHA0;U%DF7T(|aj?BzZ~P~%
                                    z&U%U5$5{oUM9VfY5ZUIi)CuiNefvrz2wZM>SP&G~fq~NMbUpwD4<>OAjEqEFM{irE
                                    z@Hv_RBr`NLL{Co-DmhM0&hb1&NjO&A5Pqk_h`r%t?mx4$u4~<)){9N792`ww50aMc
                                    zBtmd29QUTm%gaCagzfC^Vq;?ivga%};OPKL_(QJ}i{$*cM>z3=SEtbH(8#7U=lEFG
                                    zn(DaxLOzejn>cW%XC?7Yf;OZSaZFm9J3DxUgeegb$D2b0Ep#scA0#h7G&}o|um{NA
                                    zQE_p8sPv4CgT1}9jEo_Hftr1_GWFhVc
                                    zYGGN~)9qeaI1#@@NbiX}l&~$hD}SfPqZ;#HiHB}Si_vLmb0k87(mydU%v;@OnoN`_
                                    zw;Yzl;6}%_ZY#3ZK(I_qFd^ZsZNK9|UOV)wcpfIEhaWh=cP5N#x$UR|&k5FOCS5{UsGc#{)ZitDAL8%W4@+La5$CMO85)u-=)Wy+J
                                    zG$Nu<)Um0l+VXN-HbW^;&s$g&1J3NzC(={};|dLcdQu#3uCJY)ohhlQ5mXewV`^&7
                                    z++OT~3Ois_2>2H;gJP`bHdA7yWX+{D61ED}s`_?XPzY(wEZ!>rg9b5sWS_A|C5XD)
                                    zMuhRpTwe_)a>96yu
                                    zKZ+&HtNMvaqRG*d($e8K9QPrE9a=}7fuBW1-YcdtQf$J6hn(LnS?ID59^9&`U+Ah>L)VX=%`m+=d?d#e=78Ja|G%v=e)Z#?muC@4fc7h
                                    z@#+)xwus#T?_yxIfq89qQ)Jd;`{C4REut_Shs9t30v;%5V-kA!IUU!6u$Fpy(i3>?
                                    z3-j_QmR$R8+G1ng7=RUs2=Ff{#d1rERo_S(K8uMi<<#`2+zZ^ONR2!YC0{~6!kgqn;MH3HA%{}@?DC)iiqA&7KrHz19Cm8CQUn4~
                                    zLLEclwX@eG>r{YX5)!^>qz^rZVq
                                    zVz=A^4%sGZ85NJqMh3MoJ%=^BoHY9d0kXkI5;$vC!cJjuYa;v
                                    z)=KX425GKb|A()yZ$$-bBzXpTrOWS_jv4wJ(mRmxd~AF(l?V{M6C#!{|>O4fG+~%
                                    zMB6_!0SFgjOk2aL9k%!9JLBEm-3uSYI3yD6yj7JlC?s634j0;gz#beN&?u%2#-2Vt
                                    z{O`%jh|6(z0)+6o>S_~nb0PO@R5A|FduPHPR-`$g@;BIT0Syd0s+ta>tp$%VCbz`i*+G@j39s&k5sm$>m!1ap}DmUpxLOaPj~pE)Ya6Sf#$f@IrmbyZVj_j<`FQUFIMARV
                                    zz}GjH1ek=p+2|#aaYv&a=>+`y-rn95@IXSpH{tl`=Efhk29_D%?|H(W-vy~uS63Iz
                                    z>G9>|<>@K8C^8sBp~E!$tznSkhtdSx9`A2nzI-WW3T6^4#%#&(7QhXv(+Pi7T1}?r
                                    z4$y~5p;?cKk55ic*3#5WOisqZ!Evf_6%qLkQVS3m3JOf^>`o_()aB*n`|No^4rk}&
                                    ztf{UB%n|THk|XHVS|oz={ufXFeDi7lbMsq&(j~>k0a4Y}(*vlYBx{7DaD1+0OE8Sv
                                    z+r36rfqyvg>;en|UzRRu17I~d>FeWD-`GgZ=Mb>1d;)BHl%lHs$})sucLC^gQi<=5
                                    z!@|Pu@9zf(2SLiBpr9y?0o6Y!slZ}L8+Zp-^07unTAGfDX{e`1QeK{kjt;)Zwp8{l
                                    z1_lOLf__MNW3#i3?l*S$p&$N-A^rYve(q2T0!$|oK1V>k$UBLCC=ap32vLIy4Q=C7
                                    z7nN)DO-lPRL=Zhkn09?rbbst6tplzDk`Hb5@+Ab~A{-d$^~IDML?j;(!uNf|OfEjL
                                    z!U(8X{{q4Jh%K!PS)E!y76k=9ilNXV=`*?=!IDWK%EX4_^}^_RQK$Vy#szT$hY$x7
                                    zipul%k3;Fx7L^_Jri#^s<+vg_TkDM9@AJc1BPh*0s%b|*BBWTMW3_Khb+WcIsV9P&
                                    zj_v%~&%gLUD~ABF3&$sMGwtT@``6J<(A=cx-<@(qJPNV=-~7TNtNwcM@$?VSG{}Aa
                                    zT3mwlaei?T8WI9l-sQoZq})D(7wt)(|DD}qZb^xyzWzJ8T5JLWb2GC>a2ys^ESabu
                                    zp^&Gxq@;gJN2oJ0w8-}MXf~*P!I~Tz92A4wSYN-sz8={*2UE4ZZL-Lg)8KOYaw~x$
                                    z9Ffy=8>*rJkf{6nsvkZa0#;I?@(^&L85zr4>0ZQK7JrM>%QlCS{q=FtLf4U~1aA<|
                                    zA21Kv;gBug!>*Ykh$o~5>uYFeBmj9UI$A|qy3ZF8r{(GK?vLQzK8Ro-wuz+)JzjSJ
                                    zG947?S%sMA0rR>Q)Prhr9t~rr%WdD9b#Ve-j84BJxuPH>x`m6j6gkvZRQv;KOERC+
                                    z(^G5~-4IkWP`7iKq9?vnSFg*=d?$BAwjDQ*TnvxvMh5ppwuwkB68|zq8Fp2EX~nsq
                                    zI(bALgi%n;f@llM%`~HFk=Z98
                                    zMY>uV;z%4(h1;ejgO9kK#P1rgZ9b7(lRzChL4{gRP57bdMw?3(BCjumu1~G
                                    zc%S0G24f=n>BkUMw7>Do@=!2z=cZdGj+8xpTQ2b(%?l#TB9-x@)C7}!ofP*3)_Zk%
                                    zfPuttTN^p#8YU4P4^NuW{qCS{%n}~*JEM~}49S;JtlgZ0HH7Sdx;GgHHmKJ6kH_hH
                                    zPHAcPVlx3Dq1?{}@{D@JCpZP(AU05EtZWQydV61&XnB-s&wvuN+F?h*v<|Kpfv1F=
                                    z1f*m%Ji0+jcqif4Re5x9nE}r)xKl*gVVgl^
                                    zG$#a9GQ8Kku*jI91a-oiGwr~XI7X%XC`RRpjPc}$k{%sxA7)((Jg!bh!xU%1UIV$;~N1^8p1eq003l1^AqM!u1{>@0tm?4~vT2Iy(tLo)`km5oIkF#JjZD
                                    zpf|G3`M<4Ec_Ua`;0LMHQh`?i+M
                                    z$HHO??dIX(vzl7!=HN}zkdf@|0V*d_2iQ)ZfLLK+A@^3v5U4*ON`UAO{w3hH5`$~_
                                    z^^3v>!1Mq$@F<@xESg*|%xvo{dn3L9Hp9+t7<2&eJMMzci8nqMJ+gyC>Of#U
                                    zId^!DbruDsrR;Bx1>CQHpR6ri?&XOTgIs=bd>kU+2D~|CjrMs$VQXvMOmGOZd3oGv
                                    z6471Ze2^fCTIMKfRG8bH9b+ylIbx1{FTOQu5YMXl&$*^g5WW`Q>y(%weMB>e^U8
                                    z2e7qNCstH;c3-;JrfqIQ!uEW9Wcx2GbgxC4TnT81t0cB4GH=GxzX|uA
                                    z?~t|$@IAk7DKJMKTpsw%&zA*2Jp=?04nuhmO6qwwgxd?JI|mYuJhOVJ?^OsmT+g4#
                                    zo{jMeDYOqKJw-fWRT}QMtVQa7sIfuO*VV9tzPh~ZjcR9Wn<(TZDAGGM#U&`{`L|r(
                                    zfiKnC)5F6<=6nW9$uOpV{T;R>0a#qXIFMOX^sbY@XTE>h~vz3~yxyE2x8;2^+|g*T`UC
                                    zk@p97n^1DLTx+aLvTGX~8<&@tL5?phD3DL#iL^!#F#+oi3kwUdT9R-~dM)mt8jX#O
                                    zRaRDJ_)tt5{ISK|#lhhmcoA?IHH3fq`1q`^KbN-Zs;cEP7X19bfX_%$vPZz}vdQBP
                                    zo2)Z=42#T3rS1w{3VqrGF`k7+w=o7liA~VUbNZG!uek^25?o3$IN^0J{LinuY2_`_ui_4Zw-tzhhf0?5cd|)^54K1InF(Lat<(J3BCe
                                    zfV9!voGl~cNh0K_`f-+8QW7J}sqzz4c1DJKUld+w=pWC=n{Ytk=j2%K(^r8uB;Ca?
                                    z+;s&nUn;MAAmZU=ip`;l05^k#v~+=&m)asaZU_sS2r_c}4DY{XApHeYlz`8fB*g+5)$J1a0@yv+D1l>|4U{zH8riXS_ldaO?|Gb0=RP+
                                    zev1*6y1`2|abq1Xc8p9uzytq>Lb~9Wg+_sy8LiDfbpSx?eVpwsWt*FkPvoCAYX5Fc
                                    zfS+cwP$yh#xzYc}ABCh*zeBeaT}Jk5dxuFa-&r(p4atXabd9LSJ3kxF4}}D9X~g*W
                                    zN$KfFD=TOuB-Vz8oyoszK+gE^Z>*W2tAvDKYpa)-n2)dT%Sg~c1Zrhg!`=u0NdEr)
                                    z3-(!MWhGdMJ)NDXB)p55?Tria+E?fi&ertH&Hljpj1k9V-{5v7v<_|CuArXy@L-IF
                                    zcyKV!O*1h;*lF8TdN?}YumWr!yM-@E%>ntWp|0mB&i{hJXyP5*=#GQpKQHXyE^c3U
                                    z#ekPU%r`)WQ|OeHqmI62=jFvC!~EwZwy6(L%-Or^ySpm~Ke+Z^((39ztZzY-i;DiS
                                    zzaPTJ?gexr`dep|A9;D%bxsqv7iYlu25i{>Ck=y84|N#WNfM>OA`zPdBBTu=usB+(
                                    zQ$aK-w8;E-DIULjeWafy)6maG{&rPav8W?OeR%3tksOeWz`-Fglx!S~YG&dbmDFh4
                                    z6?C+=rZ||w8(Z(Mzop>CQkD-yhY$j8Hfn0&V;|AqhSWz|QqniZmqM!qJw|H+g$jVC
                                    z+M^bg|9P8Jy$-$n(k%|1wl3KffjKIUZ)SHx3ID{rV(x8}X-EiZ3yf;3-N(bLB=>!4
                                    zVfdiG518pzETnN7vW5U%*+c!6xBG#9hvv#lJ~de;Uf_<8j)B3e$RmqB{VinIcxN4}
                                    zlYmqo)lMv&dsk{ti-?erF*YJQ;c7z(l;5N-Z_25$wZq@zcy>7*EmG0Y*f07jZI5_d3G>;C~1k?{3H+MRhCH~e$
                                    zJ+7bSY_+tGPIG>KKvN11nZvWaBqr@U3?5aRRg_Q+4*_g5q3zC2P2Rt|{?^a6Q|N&E
                                    z59Fd}^}zkw#=)T)tVm#o{Pyh~U>H`rg283tSoDYq2=;e5e}9}ZF{=Gb8P^7z=HxR{cLjx=nDv`3P=0*cX1Z@p;I$61;xepfT|hpDMpjT
                                    zW@~P4_5c_RxKDtljx8%K4No>PI%*5TUU~T&yARBZF)bOl8%L*3oJ@ME^YQ{zOTS{#
                                    zg{}>Y;zb)2oAN!e5ZDE#0kH$Tcy$&tl@>E>J`uUOMj&PVl#T|1`A1b%A5@^|HM?FE
                                    zg6(K#whNqC;G%)Qe9{
                                    zlqzR3pRw`r)|<^_m$S`>>$Pw&n?M|Cq8oD-QnEP~`ojbKq=szl0F}w|_LL&U
                                    zRK8gA+ETZxLoy!@4vt1J9!?)hbqB{MDY&f#H5%CBB(gzKIQ#30GAtgf+fq%8rNzZS
                                    zeOfxY-oMUSzub64@(Xr&Z+6h
                                    z-#RN!z^B__i#JufoUPh#m1=3?{mijkXM779_dwSt92s!F{`~2cmuJ1(g-s;n>3(;4
                                    z0Cp4BC_g2B@1?5~R)K}%hg
                                    z=3F0_y0A2Ut@rE0XOruzHI3`x?p{Z~KT}h*f{&db8Sk7w1%?5Qd^oAb*IF5L=bb!&
                                    z?f>Z13CHO(lCRu>Pmq3L72HYm(@hf06$G>%Dg)c=moI~O>~aGG*64IeN!h_cEy*0F
                                    z^W%ACK|%DtnA-ot_Yu7#BO{}OH91+<+WzCt>w1LCMCl2IWcC#b@kkvL48#FN1UVvq
                                    zf1jyHz2{;t&p?2@L^)VzqBOK^Myw@XXJ<`~*|D}wd2
                                    z-`-9r_nQP%ocKD^aq?BF7V#5uL~izEhpR&`U`RGIBSxpNKtMhm$mEdGuAtT;gB3in
                                    zD=RNIxVzk7X5MshiFa`5Ci5vSd0ncfxYqymXi?wb+g0ODem)i`&FawuE!>02Wl3>*
                                    ze|xy61P6nzDo1AR>&c#;hPpXQAzG(+5yf^iiCsh5bsN9!-d-uX+7|)gMMb{pOIKG%
                                    z+&kO(d3pX)b*#V&q*1;+2f!C<{XJ5sgS7!c%BJ+#ry?h|vfNuW=HfSa@r_14;vN?_)lG)C`zv
                                    zcAFej2n6`P&>_?0?_b`tK~`S@2Z}f9JzIt#c=T6WKpFvk^5=HmV(m2n5Lz|_hfc^g
                                    z0+g^KCC7{|>*hQvU0J_-xyyzXj4eGTx(
                                    z^}Q$ytWt>g5!SgQB*GS`F0l@G{K#4U=JG!w5d0s{-wS}OB-h!adnt7P{ONHw!QxTE
                                    zemE0Eq0%en1^GYb7;hiYNC;GF7uB746`*2(`#XhtH3gn6>J3u%eBzsDwozC>tUPo6
                                    z4VDj~uw~3$ENp!n@jek@4;_v*>VLKT|KpvZ{jr-W0(!I|ko<4xRr&A|H{gFE!dU;)
                                    zhG>?3JHq8HK#PlI-GcVqsRDuEQNhw!*9$*;U<_kYx(Hsxqkw}VaJM(WEm%b6MRRK}
                                    zYXiNe7a?dkh59Xc+bnu*=?4PzB`M86?>yh%zuNw#5>po3DIj2+A&@ajFYYC{4B=$(
                                    zMn*=@hYNLbw2tzT5hd{V-rkUZL>rJWL519Ue=18Z`XBPp(&hzdJ*=a3a&q!f
                                    zQc=OMZU)K=BRxGJq7C7j=pc@DOMSys6>T+nfGj~1Ng;tLMJmTxe~m1h4%&Q$XlZ+a
                                    zY5I7j15mL|fN%o5@CuLT?YSvHyo5dAqCi*=1hyER)Wk$QWn__Fpm6>6MdS$sQFF1k
                                    zH$cvqEfLfPoitMu6V>(gxIHJpO@K=GA9~X2oYeV=4B2p2ufwA2)7{e3A%HEn=R1Lc
                                    zf#Ccr$yv*d3rE*Ib@AHEvnrr85aYXHUG5j&X@>M@=pKLdZkcU%t7~a_v~GQ%CVfdZ
                                    zvA7tv=4@_W1YkkfT7UnOc7|g1Xs-o8nY}YpQxfZxV>1?9k0<3hK2|q)bGC(piFs^EgJ;JROpbH?+^6E^=4NGe2ngviz1BswAOm!x)-{qPUC?XpqV!=$pgRFoLWE#nEVn+uDL$<`{X;drvkeHYV
                                    z`cs~6AFh^c30YWJxVgFOz<6%_yQ`~F@$p*+2TZwt%3pAa
                                    zrJdg%pu2bBZ(Krad(+^`Im3vBT-lJG!uS*w6{V*y0cZ!F?%HU%`DGrCBow?wz+1HO
                                    zIq{Na$Vsl&@hd2^A1u6+?Zm3ISFYHyL-dbwA{%tSp1cT*y7{j?
                                    zKfNc)xgxb)DXZ3cNA;{*|LaRkw((@H27e-!YQUVnLWZpr4ntwIQFGF3bAw%f?Wdn}
                                    zTo6b9Dn%7m#~Uco-rFlY%*G4yymN%6|C|;11)FSdzG$F;RG`Fr=x5h&eXpb*tW^sd
                                    z_+}3Xgf;3%J`DF#00^DJmNtwL9^bQ(_uu(Gha%Fis{4CNrR_10=U?C_g7|FCLK8p=
                                    zn2^ZK#$6_GG_*$%X+pzrrl*AnpTBs4u6ZcjYd5zJ^L&v2__T*_WYG)wltm9ryf854
                                    z-m}Zxbd!C(#6HQ^l+Uf2^QRaXzJKKIjpAqY4uz$_xedX&y|v!klvgK1yxoD)onMl-
                                    zc0_Y^c)|Hb!~DyJ`KO2`TMCi`#i-jZ@n
                                    zb+)f)D-0j>_iulPe&rXcq>f{xGpwH4)XYN6YhY;Z#!R!7oGnRJ^Dg6R`Ie*a2T0Vx
                                    zpp!K4`ntWtZ*<#%JSVJ=qq0UEuHp9fRLA!%{YmLSUqZXoVtqwv<44CfZ_xRyWNWQXZbp8JFt>*0qas(4)QH)#dxeh`LxuR$Unn
                                    zd?!d6
                                    zDI763QtO`=q-I>nI@MlYI*u3J)f|1(3S>w-j%*oT6pr8vJ|?L7VI%K5JDV1MVaUqn
                                    zET9HOt`o;Zh6j;H$CfcbnmgRuqCT*|!UYz^Q}7Gnd%tM&04t9dcFWoj_IcSI!zAu@
                                    zHp6D(P^o~2fUM(n5+we!0R2C`k>>&h%*0eMg{-2n2X+tR=x@0XLs~2ialOfu8Nw%O
                                    zGN_Uk-t8QTFUeqOQ&v$(elGavDtusyr7NZ5F5~JX(0p~Z0r6d%Z}p-JV}CQaHo)S=
                                    zK$mD}G_^Q;ySyncfEb)!S+!N7=e4yv8Fu-9)p6$WP^fJmpHd`bq;M?BP_!t8VJul1
                                    zMApiZeTlKlI>I0ng&f(9eamC)dqyaXeM@#`EMe^XG9=I4d7tMz=e+Op{&RmmQ71lLkye;lDW7mFD+scom@@@wWew82
                                    z_Kt2p_};y16l=_p#u|}{P6jT{S-PVEh0M>!)?`$z`F5sc
                                    zzQ+zAJ%!qDXC!iR@S&j(ouyX4oIY{d!{8c8P^1
                                    z!iA@Udh0nkq4F%ZZjH_L@H5-}2g*Nj#VuwFu=>O(mfD0rfqNPC<-v<;7);?wHB_gk
                                    z-eY0Q1Gk{x?*wklCrc(3O>_Gl4hbg^=&9vfTf5btzYMrBi_boyK6k-TzRFANCUrz)
                                    z&ROv|s)l0#(BG9OSB0{Qy1BPCft?1%4h+G!D1PiI_4Gk)^*SY2Vkh(Vj-TMIt5_b0
                                    z(@PM8u-DZ18Ga0an#ab35B2k!*kX=TLo2x%s$qssKmo<2pwhJ1z%O3P++igbX-#n6|4
                                    zobe;3G@J^>aY5zrW3%qrNpba6apEguf6x0DpWD!+!TY*P2%7$skAfwLYQ&?|@(OXN>4b@N0ufBi{_fZ1~j1bXKWgDWKCFN3Q9z1G?8^C`8f
                                    zI#2(v(N)kRc2Hy$syouD5j+9AKyj|}rNe8(!0R(BAGfjH)a3K|Mh!mLK)(m!D$-j(|6M3ljn;`WuCoVdlg7T4DO+Y`rPgxSNel>G9*hJtHv9Ak21cDK@;q>B
                                    zzFp6U!$m;vXI|+0YjN)ZUXV=L62pppP{Ci6-3CWW2}l+c0e*w@af_c6{qrc93FJ)9
                                    zFsKRN)xQLVM*PPQtH7bWim|lP7-dmbSX1*(kE@Xl3(vkBG}m>Q12po)Py7t@J_Y%M
                                    z>}>mvl{WoHRp`zlH5MRsoP`)2bfwQ045vw_P@nm@SrJnn>n
                                    zIJud87iD{F#`TzY9HigTMfIxYB8BC8QUuXg}JNJQ$XI
                                    zS}i0Gior!|Xpp;htKlti#kVidFc)OpwOAboxeV!l6%Hf2Cc9i`2pA)yRNtc{A51;(
                                    z=6YALYLHcr>HKM2!dx#=&y|3Y}kA@I3Mw4W!X{$NAA8`Zlcd#qP5E
                                    z{l<+KTgy_?RcMdW5O-8}x#|NwEY{m`;ZYnw%Rw=kw$&abHcRev0)|}d>?z;pos`bR
                                    z#JTRdA-2Fj^AkYQv$M*XiVVEQvw{e5&tCyI$Zfe(Hp3f(t3de^woXOYbPfP7)8|>^
                                    z;*yX0KL?s%F@U)p-tg^7~NMMk(gBHO&NHsyZ4JYDf-D!0Z)*_&HZ0VOL0K$;5&
                                    zs#eJb1x)g-LqivNM9_}nx;y~Lc9>XXW|@1jtOpdi8fH`KuC7MJ3tF`d(OQpPp*&f@
                                    zU=0B6GpcC!3UTL*?H2B$X>s-KlYc{r-$>OT`>qkf4}mXRQ!3DyUuO9;1CQ-u`F#YS
                                    z#U;H&;)pgcV(Z6-62{6Zw`2o}!F0vPTlhS@1PUq0prXM0>t9~&5(vzP+teqtfTpp@
                                    za^xx
                                    zoE!)jJ)dfXaE~rf(D!+K;celqW7<41
                                    z`{B4G&Sxl8bOL2&q)eAdUSHn=%rALifxN<10T3K*oE500=VfI@$L*~gSE1MBw31Ok
                                    z-+bCbo7!IaVmQ@@wB$Ecz=K1Gq$j1WeF{g
                                    zC>74AZx5ADu?Vrsoer1FYfBq^Sj$A;{#B;3QPYu!)?3G;KD9m;O?2Ir_NMl&MUh;A
                                    zxQ#A5nW`X0{Uvb&_hPqy4%;WqBE8^7A>}B4TUX
                                    z8#)HH^^K<+Umq@kN?^ZjPi}79(UERXd4Yil-<39CD2E}NYm3(7KvO8yiskI5@Q<$fDlN<4D58Oew@
                                    zkzk8yM+5Eq!O&G#DkVw&4%PVYHkkH19WUkef69sJ5X%n+6*=im@9m3HK?H&Tm-yEP
                                    zxVdd9gx?hiYdz7)8k!X@eX6YS6^Lu(LqJsV??%A3H_a6DktLkqbaa45B0uzxjCB1N
                                    zVNavp+~0^QFxb=8HWF^fQ_a0@ed*#ztOa7gPrjJeH_SF1@S6{m5tm^kpRJ<_JY)Dy
                                    z2Z`grX9|u|OIbeSP(F^kHiQ
                                    zOW8d4<>B`Gc0DP=S2f<*R+Q;@8)t7aob&A`Sb51dNHA^e7+rzkbh0_7W+0u6p;_rk
                                    z85vu!yQU3NOwP~A$ylraOhI8bB_*&1J@kE!Wq4Gdm32+Zc^W519KHd27;6uJjT<*Q
                                    z0M7*s{)C;@%)p;^wm4#9E5}<<3O+whDk&X;RV|V1_%$oC|AV)nang7JRzlL-;X$j_
                                    z(Oj1VD@#gQadEt82mj>;$(uKokuaE5@;!{4Nzga?5*4Y;Un7Pg>Ik~9S@sG!C{I78$;
                                    z623ohO-*|W$ody%QwVQwd}}KZRVw8d;9CfF@398r_VKP9$vuY$ULZe0>DLG~GUQbF
                                    z-kESbz$mIQ9%r%46VC;sIScBBSFT(vDJc?{+;g!1vC*PrX&H0pj@-aN)m#tBXYq-b
                                    znwrD&b!>Y2Pf^hbc6Rn#hSgrn!*L}gl3SaVOBVNWUHN%6I=XxNBdFucF#Q$E#>|BF
                                    zb!}tggsMHEiqY#b^_`6tlYul9T@qloSXayg50$8pBnj=DqC?8gP@K7WK-ktB$XxK6
                                    zOWNIZJ@$uj05HAMuD2(24*c;~K_laH&W8T#vWH*U|-P(u<>>u6vMW*@|N!3cWN%MRgQm#8wGLTap`SSb(s)EoOL@3qk*8aWqI=T
                                    z{>u*iW5ZswBR|XMr|xBe(Ikg~JzM^Y4oE`((j64xsp9@)DQb8)KOHcLGLbGS}@Ycdh3-?Q$6~JPiAIdcQP&y=WVFFhs=H-7N!jr
                                    zd}--9OBDCQpxV*8nZxs9QkF8%%l7Bz-&|U9Pe{u>+kQrx>~g82Q>50$cTGh
                                    zt{t)U6ZIyUeR{86tK)L3H^0zbf=w?iJvIKhMsS$#Od!vc!6YQes}sSit5k18Z~W?@
                                    z(D+xtSI-)G53>xA+4RZC6Z_2}paUSYD03w>29tnH2+(%jQ;qseZC!$%dlSQ}6QXgq
                                    zb@BLM2Cl{EI9<49J2%L~y1TECstdx^7}0wtmIhahi%ksr7xH_Ib6{C(zcwz!svR6f3-&{lAL^~lucqcoP3A{O6A#f4v5IsaQi
                                    zj*h{=&{ApH5PSkI@=Zoa$ak#rV!^5sQZd2<0L^&7Nj`aE*k@u!wf^mqsE7!gH@y(o
                                    z^%#{Y8shTA;ZygWmFj8=E$tctu|vzSBi4k^eNqRcZQts1{I9O#N_-$j2G5I4oSi9|
                                    zO74Izj|aC|NibEKH1b>x9BkQZHcu6rW3sX=b#!70m(Ka`t{a`JspYxP32qSx*O!|B
                                    zYKMZA{a>2)g$J}r9tWDNG~~q)PAMZ>yWa9Ur;rT9X#z4vtFn9Yo9}vI=+-YDiu*Zk-XpGs^yV}|n
                                    z8yi2T$`=n>zXb$@8R1=aWFE272%V6^Kwdx6KUfK(p4s>J^e9!ViMARZdsHCfn
                                    zF?Dj%1(&45Sa28IY4mY!C{_F^7|rWaRL|&aN52TWdr!*X;cmrd!}0&TPxipsKTuJR
                                    z9do^Q?a;z}uChXGaT;>f-wQ!jeT|FDR5ePf)VxhYzHpOUc1RZdgi}xinf=$-Lh3r?
                                    z;^d4t({L8CR1nQGk-r+&!QM8B&1H3PmbJ>EY-{Fx`*YM3IcfbrKv_Zg=PVD%hMt{T
                                    q09ec`p^m>l82;D$;s5*iy&la~HflaD@EYV*A<7Es$U=G3fPVtH$O!xZ
                                    
                                    literal 23017
                                    zcmb@ubzD{Jw?4W63CTq$2#YR}l5T-TDkTC^(jeX4C`hLuNOzZXm&Bq31f)Ys8l*$w
                                    zzPQi#obNg3-p}X$?&q#QHhVAjob#P?j(3b_JkK)-d8sIagGq`Bfk1Gc%Syh2K#&b(AT^7+n2B%j3Fd
                                    zOj0||d2~ZTnQr%Mb(Jo$FWK>9iaviNEx5MWp{lVC68M*XWH>JP!SpT~1$_I0Y8CuP
                                    zGy#SH_>pt(|G!_UX{tjW<6?Ij>!6zZ)sZ5PSVJBB_?O&5N{Xp8NqXX)A3!oVHZ;H*
                                    zsOX^%;Nr6Pol1~Kcw%B=y1MEXeVAvHAYwuz{YZzoN5pb71Bubm%w_!$NEa3yH=2Ea
                                    zF@4+MJ~efSVc~s<*bcaf5YMAu`#Cwji;XA5JoNNyIiG$w2sNp_eJhuh9Yqu1apoe9
                                    zVL&3p!t!H$T=eNvTxzH5OA)f<2eq}ut(O*fzAJfoc?O58`r5NRzaC&z#ICHxz1pptmGpUMcy!42;Nfe#2H{FE3rvVuI9S2`qEc@t!AE}E
                                    zg@-s1J{}&l1x%TlOq!Zx1N{U81F>$+x9$twv$GA&!W^un5bD+SvuoEyRwj0(6b>T-
                                    z-!wnJ4H3`QC+tdtLpL6qqa*<@eSC=EvT~MR+HUcLTv&<=WEX0!`##cthle@aJuNLN
                                    za(2L+u3;7iKp=(z9gfywZ=PbW__8tb@|xb>q~pQPXXfTITH>lqneixuC&!N!
                                    z6%>9T5Y7`U+So=bZubK#+?&Hl0`Yx06BT`Lz2o~-t-B|Hx8
                                    zcxi6gB$l({7E)BS^5<+lSo88Ub!J9O-m6QGg~Q0wa`t<6_tKI%D(Y-$i3VKdd?KdB
                                    zWZQChC&MMgvyrpq+3ViU;N7QAf7ZIgL^zij>-!4OQy~gAG*jRUS
                                    zCd7zc+=wAQ+}RmVMMY_$UYU}x%J9lfCzA;Ru?G=OC#B-3FBzbu@!8bIrZ5QctG@nI
                                    zUS1%8h2ZnCMomwrV2pD|jS644iNx_<}qil8ODmLZW_4$-xgyWay_Zl~vU@NmZ
                                    z_5h8V+qtMFeG$)fpO=)xEI0QxiFpi4_jM9dR`Up
                                    z+>mB!EL~Yy;yDr((a;t|Z@o~dRaM6P40axI@t$t;@i1*JVq~rlC(q4&9Usrz*!Fxt
                                    zd`s)SxquT-QrWFSy=lN@8
                                    zbdWrPmpXa4IKNg_4U;}%otQ{-UF&BJc&V>nlAk~Jqqy*FPejn`To~RvdFH7y#xYsG
                                    ze|DI(yxDNl8T8uF#ng0QcQzp~Fz@Qx)zR2^B9@VTdpqh|+V0QIhEHCMWTF-V<0h%k
                                    zbnq!!f1mF9C-bt-RGNswAM?2~!wX7SDq1X>eXeZ|4Al#*oQEe7v_7ebY^z!itMV736!Os|tz)Z%$`*xwu-+_C=33
                                    zSG2S}b82e7jo5t;!dth8oouano$VRuEt0RT@%3unTr#g;|G`6^bSPLOA#uZEVP-A;
                                    zd4BNmnfJIoOw{|5GcqB1GGL}y+R~EacH14=-0X)JXkf=06ghS4NiEYq>74N?+v#b@
                                    zlHLn#GS|yvoJDWfpJ$8v+`P}oIVDl3bBcwoelOAB<_~ps+3qi>U}V~_IJxZhmlm1_
                                    zM?Mp@(_h4=NnLsV
                                    z{`sf|wpBS%GQG07Nkm3wY|Ne1Ry3T}VpC3ve1Hb&rd_MW4S?nP%VFQXLc`uj{!~NF
                                    zyd7S;TSUm{)7Oh3gOQt4BH~gq)o;;Iwr8iL#2E1M^+aG%k(QCsqD0UTrO>H$xvoXm
                                    zj_I&&M6m2)jivMc!q#jZ`cM964y$uNe~JVKX7{Sk$fv>Nul}61`DVsT=)4wdKYqZx
                                    z4C2mRm;zqVdJ_{rp>MsLdGyQLyqpyB7{y$gd_zNp=A(^xm=CiVW5_m|+5LBsJOoZ9
                                    z--()1SNxnjrZPVLt+m$VZbU@A#1G}PZIbyRkNpT@GNneX$?s}!#v94w;7ah9L*n1rOxso-!i!FlXA_|pi%CUNu|S^g>{fyzL3InEqPvM
                                    zcY)+uf-l%?6miXglKinMw?VU1oxN|OoYuIsQ8|%fBE3;uGKVk(o-m~=priGehwRM&
                                    zQg!BU^&5_G*6k-F5&=y@@C|dL6@6B)8|FeE@G(E>QTY6YjTMJ_b+pM<*5OboF;U+6
                                    zb4&DpBUKoxlNt4@OC{!E5o8etT0M12b{LCwqI0%+I-U+x#ifh_6D5%IX38lOM~jux
                                    z$BWgS!^4w6^{Fr&{)$5u+z_v+aj&QAvyfm~U;iixCmpM>mzq~|cO28F^`YD{z4VSH
                                    zXqBlQe|jW^h;=)pQtT!UAcpN%Dl%kbq9w&)Z@y5KR=NH!lkFXo$>s^^kh(yKY$
                                    zQqnmdZ}moXAP7^`t+VO>`T_0XLj`u-!K>9+0+^|h#$Y1X>$0*nRMbDMH-g(eI1XHx
                                    zI$7<3xok7TUB(w@i?j0SJ{S4vyz=R|r7(!!s}T-Pf(_T}y{?c>A(v)Li&ttYjwc7y
                                    zW0nFi6;IEA5mi0CfRRZq)5zN^$AIWZ$=8#m+QzjU3=GJqhxw{{4a=s6aQWh=B;$st
                                    zbLC}wtFHu0M4i9yu5s7YiBb?x`i@Yc#Xe{7`Lz)Yt#omo7dBNijqhzUC=6@W)3M%M
                                    zeh;m*b0BDZIEsE3srKV2uI}O;m&Z;ux-Aq7P3yLX4!`DwXmpah8=WsI3tO)H;^LlN
                                    z|FNvn@YQWJ-dpWrVkI{*dz=NHo`Im?BJsmWn9ynW3gW?s595ZZEiD)8yI22O(cG^!
                                    z=jv9Uk!WhX?X6xi%rc#3v$f^J*^8sbyu4J+tc@B9YvbeD21nkpe7z>Oik1g4oM2Bm
                                    z5gu3um2IAyZElO2n~@Zi&M)M@o0#xM!!|Rw!3__g9_!@dTvjhLE-E~E^z`Sf5uzF!
                                    zd)fcJYN9+v0$Ez(bf1*%V1MZ0fwBqbtd=%PR#rhbrYgHIS5>i`dHKyafEEN{X=DTh
                                    zTgzDjUgwV`I=}by2vk&HWXid_Z{p(%v+=ReX2;4ARcxGWZgLW
                                    zV#0vp-4x0@bO=EJ3_|w-gLh;D$?qO`0e$ar`5>|YM@JI`i$L0CMPu~1x`~eai(z$QTK*vY7%Nf#
                                    znY)K3b<6rH?0FC)TTKL0B)qn}S~l9+
                                    z3w!fN6J@1s_SrSLQW@OumaYQWo=;QGQ3ez_{qV1I+07|?
                                    z89QYvK1M^;PF4KqzO%U{J1R_3ZnwWMQ}kr5K~+%(AVQB98Kv1N=w{s#O)g3{aQM(r
                                    z>V10p$})^-dj8ADSdFmHjY#hwi}yE?EF@${gPPct-Pv@1LylU#h|Fwq59tL4JW{fE
                                    zH{$W33I{*w3*2TAq+V7Gfsa|gZ6i1DoA|^gb9c-V`ZWVwZ>FRygx!rQIOq2_m@ECJ
                                    zP>gW_w!?9dgfU^0q1+SOL8?S%XOHHGAy!s=$G<0*XK`xEnEH5KMJ->tPmXizlO$ge
                                    zlP1x`8{YqO`XCY}psx1g`_$Cg*AJpl_#N_{OB~B>45@fV)4o(W`*ZicSbtpEr`YId
                                    zC=AB(jh=yiO-3@uc5Z{mrce1lJ;@
                                    zIY|(wr@Q(b{beiJ_Tje_^FQDC!j_j`_aJVAZ|cYaHcmdaq+
                                    zvGW3es<`1`55vO@-JhQ|`TbMV^E5>a!~1;X>&ij>n}w0g+t3J{{^2M%hP#`UG{*FF
                                    z>HkFFnR3*^Zodbo-F1vsRD$`Okaj7kH0$RqEi7Kh%Qw3pG4OOxPd5}5VImGvQc`{t
                                    ztAkI~^v?5GhUu9Z-6j_t#6eL}(S1UOsi~>@`ub+K1H*|DO^nRjt94QJa^0Hh>gtM$
                                    zipt8Ok`lU5DU4E`CYP>Y{Cve!3rkB{;)LX6=IBxC0BB?a^j1|>l|KdhPzje&LP`o1
                                    zAy-t47d;Jy|M-Fax;*WA+Vm2<4+DcVe{{?0+J}Vh@vO<8q^MA2*JaT_1Cq(l#zvxNlh@I-IS6@cfCMGE*Fs{#y
                                    zRyW5MJ>3NeDNT$6G_}c!in&BDjKvI>)vvf3n`Y@5gXUU1`Jeeb@Xvg|Lchz}{q?K<
                                    zr4t#&K25{rszaUE_>nCJYirN(kA-(|(jZ1EEP`vnK4*lMwYBxDSFaQlBI@eu($Xk+
                                    z0G}Yl$Y^?Xeh`F99vT{oiGd-jpuoe+TUK1G{Y78g#3Z+^%~xJNJUiRy_3PJCQc^xX
                                    z&jJm!w6tt&Yz__%RPy8nT=(Wa(#!F~a4RI$)hBVtcyn@dcjp?82H4wRT^tgM*zIP;EHZr5WT5)+?~;3WyM<_M#oFTCw%_A
                                    zqo^nxk5UUAXUliFD_14o=Xxn<&8sRQdW_F@!qn8(xT3oAt8krFpM{l|$GYOm)kQ4W
                                    zC3B6RSYL8DG-zr0w_Wzr($U2rI#H1GXahiNq^a$>u{O|WZ4Dlt66i4-9oBqhZc_z+
                                    zT!NM+-KQ~pg+F0H0;8rb4lH55?RFJVBc!C)jn&`%uG(ka>(R4tH_$G2HNqkyoLybd
                                    z4h}9Z*3(;>o5#n;3z$HEHqSZ+HE*)__5>@ZcYhp{KRVt*wfWe^(KY%>v-@?&8A%jR1cv+Q!0l#7L7LIh22TnukaEYi(UdO8U~=
                                    z9EV|4P3;i|wX<_xUER^?ZV*`6_MQ!+ljcg#=FZF~ZIv-7xwq5L_EuVHv#l*$QLp;o
                                    z&O$DZgW0CDxRJG1kCWQM&G`>l2ip_h!XlrALM<#;6w_Omn)Y$8ZvLbKYD*%}EIQ2X
                                    zbmt_A$5U7&)zHX4JY1SEWIPuNHVs=sopZ5%HA=NaS}r_@Yy&@}Hq&Eyb1Z+h*4oj|
                                    zE;uaA^Wrdfgb0QJ&oG`v^J7|Ca3U$2h?$w0k&%%?m3#`2IXZ*z;3|?5UgVa-3*D(g
                                    z>d?v4AnZrnu57b&a}b1F{T$X<-gH3`=dW+c;n1S8XLh$fk*TTo{WG(&xpvMESdmlp
                                    z`E?z3wFKd2OJA9~(vj1b-TL<1_IbF*jGn3BZ%7od4v>6Erm1u+U|@=GAY>=`}S$ifLDxFQc1^
                                    zo)`^&Ug|2nceY2K%l4r}+sP@T=t*|trQa$bf#iE{IqvmRyZc%-)zt9t@$u2p(z3A)
                                    zjgQAAIh^ij;^9TfL{Xe=6Bio
                                    z92gk*?wz=@^7j=)l>htppXC`61{4$(YpbgzDJcz={`yKwK*)r_>&K5z*vjJs8Z0b+L|Do#A1~P@}`*57nnuA~j
                                    z2?HiiNwQRoE2%QGOM`I*=2cY2^v&vfr`(QfEH@?9$-KpTm1UuxVnM5yr$|2I{;hP&
                                    z3hKm?S3NmgJqcxdznfg~qQGZe
                                    z7|Blqql*GV7(m$kjkj`-F!dwL!{xia)igG
                                    zF0;vewzx3$0315+>2_&z%N-ay09
                                    zFbn)n3{6Kz$JyB#ytu=(VepRL5e19%OZ%WVcyy`AZ*d~gOKAq{PZa1#7-e{AzM$0ZORiHxQu=BLE-2R>|
                                    z)7jaHg^3B46_AI4x=ZmP$BEo>8NMsxPZ?O!9=~7I9YzdpHYgyVzNzWY#f7<<*-Mq+
                                    zl>LR4;^Jc3JaFjf*qG_VK@SOBSka2Ku
                                    zfH;-GP*#~i!8?0Q2i_-w()s5Z#7t5}g^PxUhJ}TNk8iTG)1Ra)I*9-ZeQLif$;ilP
                                    z$mZ?s4VH?8g2v6qM~KvkKm@@?!HHohPXz_F^y}fAxm-V&D5SC^ML_4}6Ej0%8G5fr
                                    zBbJ$fwEZQ#8@`jtW43mz>bdAykEdY)dMv!>W)O+{53u+ezLN&Pp1*q?i2;og9~R%q
                                    zq`f0vJp895XhGw&+i`#jr8?~uz57y%Hg+nzI;z~od=}n|1bNKDBs!NJpl;XXq4N-q
                                    zn;}wfgyV!ku@^&lr(EW><^m{SB-#)%^(w9Q^%7BnLP4C=SjK!sg~mLB*q26W~yePauXs{4nO-Jl{_(
                                    zhM(MA3uJBrr6bE!*uC;@Ca{41ub){
                                    zohBD+0ywB6RTY{X_J+~L+m{LKi!ZVI2AWhgG&Ef`UINSaS_lJUk3MA2u{PpYjI9a)307f+kOkNjJK?^Ex-L
                                    zjEk2-NBzvM<9%;`KlgHWm8sDiok>CgurA$tyU-6GI>Lw*(!Dqd5ppan@!ehb1O<~!
                                    zO;R6mN*et+l|cR=?0xx!byrpSyRDv&`Tq7cubsZ0MQCrtSPiwur;R#HbOtF@&xf+&
                                    zp2VJlgbs#Aj;HwzxLzkS1*krSts!1@pMBPPKm_&&o}VQGZis_|3RnHe@HrF{c2
                                    z3APN4sgKWelxRFQ>3DjdF&*9N^1n2Y&x5{fvskS6sK;k!T#n7`-Q2XqJ6xEV<459L
                                    zc;zPHxO2|{i$`v`FO8CgrFi^&c)438IawPH|2Q|ldv!I(&3y^7&=J<|x3TY!UTd6R
                                    zPgT%Tiux#PXo%+(7hIiP1}99`US4KP1Y#Ezdw!0N4ucw2RI}@~n%LSVeRQbwy?qA9
                                    zDg?ht@;K~?xcvP2!3tsQ2%~wX2K`y?!@lGShH*+rl
                                    zgtd6#S+%`w$-^z&*FUqdLfCCw1d0y8#u(oo5pYg+(>tBpDM)lG_w-~N898!tepN3E
                                    zS64B@B^g3!DuC9JR`f6zFM^$z62)sY!3m%=lHT)}5?rLppcpZEU>m@umG$YakHecO7wgaAk}ZJ0ztbaA
                                    zQ9JU2?j%VuQ}HjG)Fj@J5egV8Bm?U%;Qw8pG*dEP6u^V*ih=F
                                    zUXd<8SaB9eX$%f_a&~?Ts(XEZn;Qob;-IlHNG_r0j`apbto}tjx7ixlqo4nuyEB7#
                                    z|EJwq<@DQFM&DmMR)twvqfK>!HBcDB|NXM(nad+#w}~_nMksu;Y`*4;Mvt-JBNDgU
                                    ztD^@uGee10iQjH8shw73V}Lpb)Cj4`B1Ua#0|`abJ;V1xsYEC{GE}x(+my3Y;k36Y
                                    z+yYth1;9f6|
                                    zi#9g~^(u{%@_va~Py^-R`EvpH-};g+r#;N-MfmX6*2Uzc$Oa$pwuDI{rQuS_XVo8_
                                    zHL81067bUOTP)+i
                                    zP)ftc&m?mOr5=?gM7*n1G0N!6I1n+1_x>Va*QP!5?lz2g^5pWmyp5t7LEva?3qQ_f5v|U|=D!m@c
                                    zC7)9w4%XM$f@c5a1sK*-!E(PiR8Sdf!XjQ)O1?HoR`i6x6
                                    z%RUfKe6LSFKL-6@gWXcxeyh;P=qRt_uN+*gP;iqUkDp`v&a_9m+px6U>G
                                    zU}xQp1G;D1?afnHwk9B{!p)913;=u{O#QRl;Mj&QP-lzRZtu0)+tAVBiH#$pyr{Oa
                                    zzJB_%ql&$)dLM8S?J`{*5s1#h4_=3T5Htyst8@BfK2w|dtte=J|IAA@HA|}<&yA4_
                                    zBSh=&54ni80;#Y!x0l-$L5OwGPi@JUHYzaTwn~OC-Re#7AVVILVs}b5KRBMQnoLSU
                                    zY0_edLIB}sdgD8mV(QG&FWyXogKk6Ooc8efp#Z`hQ*Bp_PNH>ucAYDP?8l3hUWgdb#*$ti#jOp}szG
                                    z401syGXPGJkdU$l?CtCdz^WY_fG#@;8Weo^I1wZ+6jtMq^K_1nLp=Lkt2kqKPY+(ABvQk!!{c=|bxsVGt4^LrX;l=s6>VI#T9TujmOlN0i
                                    zzy?1B6c7UggL>H;e4QcCBl20#5K&P09B(K;3{!jgQs2ZxN+IUz7m}E6uQIdDXs0*c
                                    ze^6P_E&hdn*O8a*%n%83vd6`tD?TdPqoLAP(6>cHMC3))!d7
                                    zOC6p0Nj+b0u(~W6MKerDzeJ>#!1z+DdfASC{XT$F!XkA*-jvB9M6m?PkK5OW?$&Nm
                                    z5`%;L&9S{W!ppl2AYV~0HxegXlM{%VCWeg<$U}&xX%~_;ozYBjR|-eZfkh6oSD<{6u@us2z
                                    zfp~?c*{kQf*6e%RF=D3-q-2h{v)@aOt$&7mXKVdIex5@hKCrw?ky86{P`7xRl(^aA
                                    zdz-05IXN>!3&egkwM_;Fqh8_hwXMwv3><~N0cQFhl&J9IKa0+rGa3?N4)t%!+E3gq
                                    zLJw6@WP>(1CWzG3qdXnP`(uvn7Ox6c+_wL6AH8E^eY2jk0G1@MCX4Ir6|38#_MjwO
                                    zy+)cB7bzK76=P@o0TJ`*RqoZS*&2wCpU`PKyg5q0CF3-PI@j+{SCI#&05RCj-I`3m
                                    zVXrqvA}br^1MXRir|ZJk4=M$n-h`Evyeygo)>b=00LymqFEBA#Ca_#kv+bQ%n-c>5
                                    zB!DdehWADam9_^3{SeZlf#QIiHn15Db1qT-Zdq@;p%ME4LqLo|3_-f9rwi%yMuGUz
                                    z#DINmuiU)U`p#^m3(1d-=;`X?1-nHc36rcg8sPw#LGu?Vr4`=uV>4c?K&yLz4DtII
                                    z?cJ;Vc@~q}1vz8&C)Eh`bPx>Ufw8B7a_D#KDcdTDh2dxU-!M}okC^AvpE%KcoR1De
                                    zABx_)LokqC`~&G5N)jLlfmA46Yr87C)!S->W5aw;gzh%=K14QB%$F43dG%C=`cE{<
                                    zFgQf)3?qW=5atYgD-ej;bICU`vlP73bqIRWa6fuY3U>d=)-X$fJJ1^M?9#4F)
                                    zfnVnP|5UX{(yr2{ksug%os$^;$nu=r>7>KY1w#nrB>^X{0LU#H0$Oi)P$5)*&0*bC
                                    z>3GW+f7d7W;$IjOGyGu?|6c?~6MgIEe}@+#(WH0K*UbJ05ybEA3qQk*?gnBYll>#6
                                    zk5I6dB_TtAkOnS?7jBBZ*dTIPXm*c{i*o`Lp2Z8mmwx*6qbr24w6xUs&n{oU
                                    zNWgtU3Q?ao+S*|T8WMLO6b`IFumugk)_eEv9Y$tc91$}!vyhMw7gyEB#zu2<^VhF%
                                    zwgfr0_esdBIR9K#2d)U1TUps&z9_^^G>SvCMIiZYr+)69UYlPMg4t!=96VQ
                                    z<$7(>pw|YE6!-he99Dv-kn0{dC+Fq$*`id=Q<88{p*3O*r!WV(Q3&%l6XPxvFpUxR(a!;CL1&CUCUhA4Qgra+dM
                                    zl|wr8f2d~!p^E@PG~LFYFA+w}4%lSe`}geusd{uYHZqct_eG;bE`d!zK;Tn+JSizD
                                    zO~A81J5_fq3@LXnSaN3|4q-(9UEqoSg2Zf>@CoHV-br-4-48y)n3;wNjMz-_U$h}B$TA&C}N7&Nl=9^nT
                                    zimk1zf_vlQ;~AoXS2M%YjL<>$4O>Eoey}2b5m#r4OOqXlCGsr2-c4Su@Ex2+q*E4%
                                    zlX#R6Xl}r&!qR+6|2BOaE7YH?zJHX_V9J5mD`!#M-|#{5YyEjPORZ%^^EalYsBRC?
                                    z#6jcYcRI4Xh0!9`dlA&GZwbRi^z^(1HM6X&40L)qkxPLFQ%O9QC8ebRSOmuELc}m)NqP`<3gM7urX(d
                                    z5?EY_sJ52Y<>@Y1ZK#2UoE%ncAMgoDwE0|XX=^9Sztz?zi%IX$udb=NA17cr!D3#L
                                    zpOw9b7|MZU{N6aINib=SW&6%dMnrUcbL|O3Yy((xylG@??6f&b4@1Pp#sWK|nXxet
                                    zcLG+<8ywf=<>iA%htfpCR@@8>GAk;;{d#zK@bK{PM~ZqJn*lI3&Pm_$zF*?FOtr|i
                                    z=5S-s2FONl8a`e*0+JPjnj)&sa*_>@vnnboMn)?DKS5FcJfYC?I$CN-@!j}aP6_=>
                                    zySutHG&D-yGyn<4y4?>65lPPV^eGj>ZeVbb?yZ2sYHyxGG6*X!PEIHs?A2$_p2;&*
                                    z0p|C~lTfWZ7ImeHpI%05_cIV76w#mi`}=EadDYZ@fPXI2Y^RBM9v&U}UaTdE`=hl0
                                    z#p`ru8dx*G%XW+`CzngMDIHLR{~Td(97)ep6|8dPz{bMEa|QU!#f6QH?V0b*6`ttT
                                    z)3<}4V;Pl5$;b%ZZ?2A%0KW_pL9k_Jh8)ppWX;fA_js&O>fL+Ub$_P;wI)Bd7ybG@
                                    zGwA8XL|^Lm=B7KqGyyLa6^GuVVnN|JI5;CAo*3j{Wg%mjt>X>
                                    zf$nC<*!*`3fzSu*HE2MsGu48ursq4oAz~ywf`-xDRvr`-f9*OOd|v{jo`nTnDXHAj
                                    zQdTM|{gbU91SOB5&p{8;mGJ4-7g!V<^huJ
                                    ztG6^!It`Q$(~4@>echD}Gq!C~q&50m8M_(fcu;|{fU=B=)?+=h>bN;-mp--@g1;_Lu61=)0LJw>A9*pjw`0}d{bzJ!B(Ck&CNg}`
                                    z<8al)`?>;vDe!;P*4Udg7-k^sn(raxpik&;@O@o)P^qg;2I5(@YokRq90H75QSawL
                                    zI6jU=-#xwF7)LcV@`wm;_BYUVrYH7-@>gTyDT$w)rOj%A((ST0NPQGmf$S6$9W5p=
                                    zd*rmg-4;t%iOwdsqXaj5(N^ZB9@qk>*
                                    zGI#`fgop^GkZBYYQ#QS4RSgYmOP%Y!SN7{OHBDMt6yLwgq(AdM0dzxQDWIN24oMtx
                                    zMlyX54B__nb6HYlnVEfXEw{yh+yjXRm#~ZPDDyOVBtN
                                    z4Gs|W`BJA8OffYiWO1P-9}54!5$*`8@^e#PD2PnwE0qH|)!FG;O&y>2`BQdL(I=dv
                                    zO27bqtd0&b&yq6D5DtVfIc-!;zqP7Otf`^?&KR5Kqa|bd%zvq%P{0vjZ47F>sBak5
                                    z!1ykCr*{LbFQD7?W>9L$FlLBOM6D=T%$wD+i
                                    zJ8JOuZLQaZ!}Cdy=URb@y|Qv>YNkxkemNmL+%Dkdi~boSL}+PAJb>P3$4+nz6BBFD
                                    zFY@r7ia2dtRTwRvZskf3`ke0k2o65hX?lIOSK8|B2`Cy`nIRn91tT;5(2i(Cxgexp
                                    zy4B_*1C$)do%s`G3R{!quEsg(xoa9(625zHYV+48I)jG6JNyHJ&!)`x{C6HOPy@y)
                                    zUAT|&t*c9|lS?f&j>5r_BdyS}>;BNu@!aKa1B#fS9pFSXF|>`cAqSsL(zIIs1yhv0e>
                                    z#&UqDC7cE!J3O=?>$G7z{jqy7Giqg{xcv0D>joiZ4EZH6Awc1zq}PEse~95`TdLbD
                                    z2sxk2P0q-bH)YW-gNJKe!66e9ywA%T)0>Y~EJ$hgg*v3*2I
                                    zi@m+U53OAwagSJS+@lc-Xm`P-F~btii*E~sTTbj896JH42PY@#H@#S(ixU!Zx0qLo
                                    z5VPw_Vmx^8phANsAUYvI9q3JlhRa22#R0z(Zk<8u+dPEXoATy~QCuwEK%72;sNHnk
                                    zK))xiS3xuMjWwlSRYmXiZmq#7z1w*8;AJ$kri?0ly1c?LBcV*
                                    z;m0H8gAZGMY2HV_zP&?1XHZHLwwdF%zzj41kR7a?kU?HnP7bJZ*qE5F)YR4-8v6SB
                                    z0F8q|jon$M+tTQ?`3hhMpi-BVu)q+&oc!;c4*b7p8h>#XdUkdts@$;RtHpWAtGM7z
                                    zrDu=6IGRS6@2hU!ww{alE>!#84rgW_U2F$JFPFnYz?4KGP6x=9yc`F&$78;qKGA;+
                                    zak}bop%f
                                    z+&~;DJdsXs_2BfKO>8l)cZ0XYFevMuoJ|`)%=hWt`hW8S483y$4CgR@eH)tvUCej4
                                    zF5v*p4~yQysJq@)^$}|lYy!A~LCu)&ySFF=7@|mWApju%Q7zH%D4Kz_;`i_0*)ma;
                                    z8YS=FBZJn;B6Ot4mn6N9@+MrN^
                                    zVHuFzQ&U-SDR15aX9Os??w+>HY&S;Z1(}6~+bJo7ArpOb4Les?l^?M3xw(Y_;u1|@
                                    zNlZ&>tZf-wSQruzAfBINSY5ZJP1lxH!lT^^gpzW-tq08nFpG~9Ozo6I;gONlz?qRc
                                    z`%a9M=*em?-aG2#Rn{%pxRK7ps}xM9SA2%6%iUqg$;m(#o|~V)zPbW!UjY*(*6seJ
                                    zf48AdqZ0_Y!s_brk&$S5K2AM!vxUOtT`#3KxWWtrU?zk+ORz}wN%&;Whc!O>AfSa^APSzbY*kO|q*
                                    z0V;h#j_;#1=XP-C6C@bI(vos8
                                    z=>gD~D^FiQ4$%RiLV_w=CM4bqem6u|NPeY%IWgh
                                    z!vF$z_N0fn)9O(N?TOrEDY1Uqg_cw+2Z^;#ML?F`yTKY7rL&{T{-Y)+
                                    zg?fM{`zQc*kS$HFd0hlz*_gl~?x+Da^Ue(=2TyQ<4*pYZD>eP#TQVPb(pO5Eu}olh
                                    zcj;6iqA2yM-YO_4d|T~{1=Ppx&JHm2LE-q{~b9&1^TIJ3;FMvr~-e>1}I2?!JWhSt@&g1+VaUI&jknmvC|W$!?e@?STNMoP5_9wD%YfqWHI)Tlam82DWGUWq5!oC76UJ+
                                    zsX5vBp1riRv|8|HJT5Kc&+dMxD_`kLr#S_k+^MEd4;j7g-t9b}?iO@7?mqTC$p
                                    zHWq8&NXJM`&Bs55LLFeR12j*2Sc~_cXEa}D7k!gRuw*cRxsKCxXq{2CM#zMkc73l$4ZUWDf8Ok)%AB
                                    z)NwH}_yh!;=A${FGxa&>Cf-=FoB;I{I8hiCQ%LafJ48c?;g4Bacav>f6G7*#BznEN
                                    zyIY!QuBL_-6sxRC1k4E^-LTf}wg3_{GUD0;D$->6;@a(((
                                    zsI7&1O<+D2xUg7z+<+Uj?%?bUAOOxmOlj#ZsD&4%=}!&bx0~sJY%7joZfRM^7fS4`
                                    zT4obI_JbarM!S(autQ%%D{{U?2oE7=VL|%3Bp9$?oloOFlUTjYTi>I22L*1$7p?p-
                                    z#KGmIOi>Ybz{uXbI{e+
                                    zHEPV&RqO3u6aCs+2-jPAnpeokS!X*JMPQgz=+AbpoDmd$*D6wTF6fhJOPL&|2qc3B
                                    z)F0aDd;8qwbh7Ox2~a0{KnL&p2;lBQizoX_qKL>Yq*@3^>!B5qm-??j`1_rx%)N>2GX@s%9x(FI4Zs~W-Uck9%
                                    zZ;t?_c-Z(x$ti`i+Yn5P!NWK?9?>38PL2Hb1rA%PfIwXG@sZy-o|bf*RP!Q-n#>Tu
                                    z)fNJ4gPfdzN}fjCCmqID|8wHgN#p(hFhj@zk3>PWx~iwCFW6K*w>N-TY5_XbNSkkZ
                                    zTInN5h7lN^P~BZ@Gq^aM(rp@Lx+S8X7
                                    zV3OET=M6jvZ<3oEW@05Q2&s^#Y6%W%6jv
                                    zRWRsLqqiPlmS<#mZNK*YXSNf#1o7duwLR+Pd6>pcj_Xhk@fKSjAhgZavf|6qRo-U}
                                    z1xg4N*4cr*fNR<4*RMaXE*8DK-ZVBThWfiGF*!Ye85k=@!f}0rBg4bv3>5rU_+WK>6XJn^@9HVCAL8$hFheRNLPQB*6KzfJ*3}$BZ
                                    z`mCAJACuIpVEkp$nfyHQH<5?1{c`RoOR9UOXvZ>PLK8o={+S{NldDhaiSZ#O(*A)Y
                                    zkX>rTc0f6Y_xCIzj9@G<(A`Lbr^X*SwyZ!6fdGO&{+?n4^%g`7Ya|EtcuZFv+vz(v
                                    zGHhS8+5z${_*_R^8yzA5CW=O$2d&#fo&6kWT2Bve*Mg!^HUda(3)(m?_O&5btGAEu
                                    zcVYa;th$W&9g(^*TA$xRezznd6mVGxgcVF~G%*|8$qarz!TJ(SHc!Cy7tCDa(eJfW
                                    z>`=fE=ESytRyKMLjzsnNM<*Xm`)kPPNZ+D1pHF;hdM?ly
                                    zfz{qn^D&fm>gENimVlVme<>xIOrSHa0bL0XPiaAc7{-tBaiEM(gBEURs0?TfDIhLK
                                    z`}-{bn+?8eyFMk02{r)K>F2^ibA5d(_{QbQHZLzPV4L;4Paecj)6;hYI&^4gXmF4P
                                    z*!;{+JkItMSo`Pa$*ISuret+&baizBCP)~dm&?e5jDPoGBunTDXiqCDEELB$@Wr{u
                                    z*{=JNn;#|F2Wrrn(2f1kM?z%J{)vfrS;jUrT1{fIG5OH{)0XGPlHn^pLtO^5Nrxl;N7}SftHp2
                                    z2+CwSlyY!*n8ab!lOo^jN#&P3hFdyXlHao9kvF25TZ7^
                                    z6j6*$O3H0$a94WrGvqF^O#LvwG!MY80~HDeg8`JU+v>#xtOQQLpA17Nr3#wZ*!*u>
                                    zw=xmDx3?FlR~U!`fRqwHe~#X~A~X)msjvSmdmj_i4|
                                    z2NM(e#34~-05NTBo&f{`+JG!60!m6-LqkKb76XHrxH!7%z}*ipZ*NdZ_Ei#qgLZ3k
                                    z^J2Taji8h!lS%B@2VpNvMb+NbMaR$odFm&!XXqslv=`zj-qGGdBQ{w7hRweNnmQ^0
                                    zw5>D%E{cmS6%`}FbVfjH=PM0-snOkU^p}x5GrOquNJ`u!ztMspo!C*GqI8WHs(`L=
                                    zZ=uB!><4a?6Z{k#7;4TJnovo2a+t0s(y~I3J_?eDKc&EY2ZidBFI6Dh$lm|Ev*+`x
                                    zZCf`f?ksU53jJ5VlK1Yi0gmF+&BzJQ==uZoiJA<;e>2QE;go8>tweP#L6SlVLUGS%
                                    zM}Jsf+{CCqizMZ5pmE=;*d!E(_=mXAouo_U!yn14;i%H_TITg#%JWBgH@9Uxp4m;2
                                    zBSmkH1d@!{E28XD6uiY?e2}R8?lFmtzYDUx%f=ae{11CYzbm7kX1oFmf<*HR);gQ1
                                    z8))6Bx6x=GQsi#u((u1|^t&=PMugyD13LABEJpJKB5+w6_tlsk|{Kf
                                    zgn(xI2_)n5-G#O-Zau+NVrx$iGo!*G53izD(?e=i#8SzZiu+0Y_ASNR$qDSVbMyFc
                                    zB{DL6z1a_+GlmBC(S2`4eJ{Wcu-IQH>FuQ`PppjIeLz(2Lu+F92lA2)OlsW<3eC2E
                                    z&D!h^OHB8w8!(}X%b!yxni!PL*K2PT^*x(m+?Q;5r>BUOrkv2h#!=|>}abaVqtZ3D5#|;YStSa;;`D5?sP7T5FxO;z8yk^F48ai=xL|?iUTnBO>D{@g-UU8L{`Y
                                    z1P&cXAvut=0pQ8z2k%4lZ-^2aH^v@Q1iX%Wa~F0mjiI)yn0K*>{Cy7c&{FKjaJJ?}!>kdM^{*=AJW?53rpc;s70kqKuP&u-6;
                                    zKsVZ9@OLvZoZfhxv31z<2D*El{MhgAHezMfPDfjy##uKzQLYh$
                                    zglA=XQQ+VX{qUOV!P%DN=FB%4?YP8GoRZJKXrNnK(A6IaA}vR}=|p3eiY^G-Lv9O@=!RIg?iu>s{-WTif_N}pxk@oEMWO>5R^O%{LiuibA!J2?m
                                    zhqre8l4v)AFS(+4dH=6o&NL9pwr}G^RAh-P84XjnElXj>9x--<3??MoWKD#~*h)gy
                                    zxQpx}+f7DUvxMx#sIjkQ-(`syX5O=&-lyle-}l4w>G?XY3v-?4`M=Kd_#eN6{H~;g
                                    zwyj<{Ah{ZLP`VBpyB|g?4}>o{5MmIB7^R?hv~6}h>HTncPLE0OG(g=I2x%7@H-@(6
                                    z)!B!>s6HxQOsaHKck|CmW!la3dMBc?4|ve0gI_P%(F(ArX2=1}x(FP_2}x=KroUNr
                                    zn2w{wJQo|=k~)L)9I3xQ;fItM8B0@BuG!YEm8lXbj9$ZFV*iDBKggJZ5)PMTAyNn)
                                    ze(cg`zG{_^45zDe>-Kj}TdIat4~o&@<8m3Q5@;GIRo)vg)rH+Gm@7x59way0vm`f{
                                    zw#`5hSEfJ1;=DS`j+4%_|Am@k;mAym{H(03ZrelOMc|i5o6C3hJ~_zW8?W&j#Iq4c
                                    zL^<-x*!jKciuAl5WP!mzrA*c>m$0yQEp^=F3YRIP`Z4ou>rJow&uF#gqQttpZMeCy
                                    zQ>{fsLQtrQK14^GezWZAMd6ckN{*B>_HbN`hGEz`$xZ+}NU~&bCQPYWg>@
                                    zu6_PQR9Kx2g$yXYe%v=(GYctWh090EDh*$_RQJ8lk{a}IhY0#W?q>1uP4pfe8=+o6
                                    z)!G%kerD}o@u54V4fWi5b_vHXI1iFb%w*hj-X2+@L|;0f_>>D($whlxhk@6TjgnJX
                                    z&^3cMVJD}e0}@HJ9&gBx1Gvxn`c^;BmTU?FX9NS8Egg4AEfAiK(U^9TPkmG)u&ML2XFo>?t<$6Q(%muN;5jet*uv5e`s0(r?zF^
                                    zyHgp+P-7wjrU$mDj=UWba{VJfC^d(MiX3nGi;(4ofdhn&(T>j>e05En5DmhO-wnQFpX}J^0
                                    z@isJ6psQMZVUdUdoy7KP4wVB?V*Vvt>c2`^j5G;Y&`MJTt8UzqLX3VG83ACNDH*7p
                                    zM0xowZbnU1chYDDFY?&41P`yfoPQN61Z}j00v&@tBwg9f!;=AxPRYWrn_NGj-yf1s
                                    zl5vYn9$~kdT<7Igd#)#FI}e26HbEVfYiE%et89$lFP0Zpc%}OX%E{4{hmmjqmp@kQ
                                    zi}zXkU?Z8fHntaAxQqi~DsyuQOuG_Kgn*kZ*x3ad5^}yLrBYojJ0pGK*bCwFZf^6N
                                    zo6TiqNB$XN<*uT#ovvi{EK$(jA*jyFi7{!ozdxcqHwXTmd?+|PY(?33`IMtu17L0B
                                    zu{{!{1oV_6BCrMqc>s>?Q-whE3jcCWOH~EgGJh~7_dVUwvbpcG$Z}1B(N2mh2J{1g
                                    zYo#G0aNkS)-uL&TmCUzC${f2A4v)QPXt)M`Ng)QkKJMoQtd${#e@pEt2i(U81=nPh
                                    z|3T-Dgo)i~F
                                    zNiA8jB{;RBQYJc5;j*J)kib?3|F&GJxt||8!HI}?xfPNJVmDpR%>ynLOd({A})ANLkTegyO1Fvqu
                                    z2+*Lhx8AG82?_KY^AG6>;lL|v={8AbmTR2eKw_DWJ=fO*Tkmp=Hd!%3ODn#nCM_c)B~(M%
                                    z`9x6Qi*ua7;(tN(AaG?UE*4rZBwEBrG%+Ug1lHD8^bbOLC9!}!SDVVE;m{>*&RPH^
                                    zNmy7A?8eWPJptTBL4ly#SbpqdvrB=s#l7q~?`@AmGjZL?N`NqCV#?*_R!+Md!2Q2T
                                    zME{9)zltWOjoR3MDs{jgHTu5A#l6_v46&&324_qszdu0mlFaQf7h6dI3H)~Fv!&x~
                                    zjI2+D!2vox>nBf>moMZ!R1yTxck&iN-Z>(C_}jPgGiTDVKjXsQlv~0*=LW$uI-M+a
                                    z9$Or#yHMuzrK4jH;53x_Iudh4b0gxAm{^e&dARX(51+6ESfFSvjKq5=L=^wp&$@%efDSmpY{_YK`JW+;SP
                                    z&Jy|Q(-g39jgO^UzJ|4Rxj2$G9394;6tV3pKD$>~Sqm&7f)Wx1wYBmW4JQ$pS6gwF
                                    zw|q%K!owQ{M#ikdYx!4)|(=OS;R+0R+Q>+u4oO;L^DbyU4GJ7
                                    z%`UORm9)GhZZR`XZJ{=!lIAjayKew!x6puc>px
                                    zzMPr#VRfNWifMl!4-{>-xT>nJ!svt4G~R%Ku*X{J>gA@(z?d~H`g
                                    z5{D#ZDOdAP0X#g64)Em9`T2=ysqf!64Mu3We?7r!21evaB29^sUVNzh?5u-2cBn*)
                                    zm0J>Pef4T`_|rrTi4?mqioqBgFRiRxyZU;0=rzF#S73-t5FMTamP-?p5`W*Gi8?49
                                    zUCfO)SPQN8p_P@JSFT9h8Y=1S?*7*N*i$3>&Qjkc8yo744eo$_M}`vvNKH4y>copX
                                    zX2aYH3N^!}58pS@*x3=)k@$>&%^5i~s}WDLsEv>Yc$g6p$!4VjGc%%WkorkhIIb8yw4|YwV!RWkqG2zcgdfk@~ce{$O`wsT^&t}I;B457vGVn1w1FE#|
                                    zYd&HDvmL1`T8Szw)U};T4GwOKi3va(rC$&c;ZYiyrj91i(UX8+v-*%(L{VuRIn!4_
                                    z8DK6)DJI%2iVs0x^buUqt!#qMMn>sdU+-B*b_!_#pyG`&Jyr<%8Z;vl?
                                    za~}utmbVY^G6mRoK2>(O$$N~^Ulkdpk=^Ky5NfwT#z66sbwa{&tMf8hp3{+>c%bZz
                                    zOXprHXJz&CtJ&VJ?6*4EfVg^^U8%#I0cC!3Ps`=7q?#b2JP-!S{^z2C(F0jnYJh6A
                                    z<>xR`A^tk-dx1(pn3V{Y@FJOTTohTFdn_<|r4J(WUyV<&+q9kmOY-O4
                                    zao|)I@`IyQ1;*?jKfrNqJ*HMX7WeRMtEU{**^vLUNSO=Pf&${>sQPir&&0a4S7EJA!(Y2C&j}fAu(Z&
                                    zgQFODU|Hf!3O9GxEHOs$7UtDN$6H`%KttybI<<+pZs3yEcN>+F$F-6V+mJJ_Dr1`4
                                    z2oaIG>+TR%;2b4xOlv-FA9|e*b{x)+(X_pmQ6APe`1$Rcng;j3E4uA}oS4u@P6X`E
                                    zzOta;mQAzu=ULdKN^|F?&<1;twcJaB?tZHu*-2CI(J}00xPZ|Blu}!p!!>nvRM>QQ
                                    zJD7iGWxvY6Bpsi0<>+Egr*q%Wh;D!2J3Kt>druL!(0d_0{Whjp8X}Kni30$l%!JnB
                                    zD8}cDYF(_sO8(WgmKGCY9)F4L~x~|}5JYJ^c)KFzwZ~^pz
                                    zogawxe}Ct|=$E|mX!SW=^CM}ty^&03#Zf3q)w=i66qV`y_6Ki`O$X@cmIU>*Qsty(
                                    zN$YMYh^234WO8JpcsF|-uL5~(wa#&>`R2q#q-pV(lXEZLDnHy&y0H+mzWFU0h$51%
                                    z>xP_dN9JihW6pV4i@$!2&&_G!Vf2lQBc2Q`&5Z_|+=4Q%c^7=01PmCn#6+)KnO2lm
                                    z-P82mnUr5S%d3=KChfDk1|!DywNMvP6*4zm7r9Umw0aDZL+pgh==Wx}vuC1Pw{e@;
                                    z$)X|}5Kdvf8o==vsP6*zZ;?DYdmD^+h$AN(k4k7K;|GAN-
                                    zwl);!M-i9u4D#4Kpy!PS_ngkW!Gw$7Tbj);h}`1q>!QZd66t#t3_0mbj({>l|MP*a
                                    zd-S@1PZm~xkB7V6Nu?qM7oQ^~C~%n(Np3d<;rhnffJ!l>3bbziQFz`j0l-E5_f3D>
                                    hIQ&0V>i1ZaX{2^=sT%p=3E-qkrLC@yELOD+{vX5sL#hA(
                                    
                                    diff --git a/doc/devel/uml/index.html b/doc/devel/uml/index.html
                                    index a45c5e406..89c2dc30a 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 : 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, mobject, source, frame

                                    +

                                    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/tests/components/proc/mobject/placement-scope-test.cpp b/tests/components/proc/mobject/placement-scope-test.cpp index 29e1352f3..f89cc4f4d 100644 --- a/tests/components/proc/mobject/placement-scope-test.cpp +++ b/tests/components/proc/mobject/placement-scope-test.cpp @@ -22,21 +22,23 @@ #include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" +#include "proc/mobject/session/scope.hpp" #include "proc/mobject/session/test-scopes.hpp" //#include "lib/lumitime.hpp" //#include "proc/mobject/placement-ref.hpp" //#include "proc/mobject/placement-index.hpp" //#include "proc/mobject/test-dummy-mobject.hpp" -//#include "lib/util.hpp" +#include "lib/util.hpp" -//#include +#include //#include -//using util::isSameObject; +using util::isSameObject; //using lumiera::Time; //using std::string; -//using std::cout; -//using std::endl; +using std::cout; +using std::endl; namespace mobject { @@ -69,6 +71,65 @@ namespace test { PIdx index = build_testScopes(); UNIMPLEMENTED ("function test of placement scope interface"); + verifyLookup (index); + verifyNavigation (index); + } + + + typedef PlacementIndex::Query::iterator _Iter; + + /** @test for each Placement in our test "session", + * find the scope and verify it's in line with the index + */ + void + verifyLookup (PIdx ref_index) + { + for (_Iter elm = ref_index.query(); elm; ++elm) + { + ASSERT (elm->isValid()); + cout << *elm << endl; + Scope& scope1 = Scope::containing(*elm); + + RefPlacement ref (*elm); + Scope& scope2 = Scope::containing(ref); + + // verify this with the scope registered within the index... + PlacementMO& scopeTop = ref_index->getScope(*elm); + ASSERT (scope1 == scopeTop); + ASSERT (scope2 == scopeTop); + ASSERT (scope1 == scope2); + + ASSERT (isSameObject (scope1,scope2)); + } + } + + + /** @test navigate to root, starting from each Placement */ + void + verifyNavigation (PIdx ref_index) + { + for (_Iter elm = ref_index.query(); elm; ++elm) + { + Scope& scope = Scope::containing(*elm); + ASSERT (scope == *scope.ascend()); + for (Scope::iterator sco = scope.ascend(); sco; ++sco) + if (sco->isRoot()) + { + VERIFY_ERROR (INVALID, sco->getParent() ); + RefPlacement top = sco->getTop(); + RefPlacement root = ref_index->getRoot(); + + ASSERT (isSameObject (top,root)); + } + else + { + Scope& parent = sco->getParent(); + RefPlacement top = sco->getTop(); + Scope& parentsScope = Scope::containing(top); + RefPlacement topsTop = ref_index->getScope(top); ///////////////////TODO impact of Binding a Sequence? see Ticket #311 + ASSERT (topsTop == parentsScope); + ASSERT (isSameObject (topsTop, parentsScope.getTop())); + } } } }; diff --git a/uml/lumiera/136325.diagram b/uml/lumiera/136325.diagram index 80ebfe88a..2111137af 100644 --- a/uml/lumiera/136325.diagram +++ b/uml/lumiera/136325.diagram @@ -41,6 +41,8 @@ classcanvas 130437 class_ref 153989 // QueryResolver end note 131333 "this connection is established by the current session" xyzwh 361 39 2000 158 47 +textcanvas 131461 "the \"scope top\"" + xyzwh 357 180 2010 73 13 relationcanvas 128389 relation_ref 167557 // from ref 128261 z 1999 stereotype "<>" xyz 281 219 3000 to ref 128133 no_role_a no_role_b From 3b1301be146df4daa39d3d97e9287cd923037a55 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Oct 2009 02:16:19 +0200 Subject: [PATCH 010/377] WIP stubbed some of the operations to implement on class Scope --- src/proc/mobject/placement-ref.hpp | 2 +- src/proc/mobject/session/scope.cpp | 38 +++++++++++++++++++ src/proc/mobject/session/scope.hpp | 25 ++++++++++++ .../proc/mobject/placement-scope-test.cpp | 5 ++- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp index c70e4cf1e..37f629472 100644 --- a/src/proc/mobject/placement-ref.hpp +++ b/src/proc/mobject/placement-ref.hpp @@ -167,7 +167,7 @@ namespace mobject { bool operator!= (PlacementRef const& o) const { return id_ != o; } - typedef _Id PlacementRef::*__unspecified_bool_type; + typedef _Id PlacementRef::*__unspecified_bool_type; ////////TICKET #178 : implement by lib::BoolCheckable? /** implicit conversion to "bool" */ operator __unspecified_bool_type() const { return isValid()? &PlacementRef::id_ : 0; } // never throws diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp index fe5f60bcb..6c00a222e 100644 --- a/src/proc/mobject/session/scope.cpp +++ b/src/proc/mobject/session/scope.cpp @@ -50,6 +50,44 @@ namespace session { + /** discover the enclosing scope of a given Placement */ + Scope const& + Scope::containing (PlacementMO const& aPlacement) + { + UNIMPLEMENTED ("scope discovery"); + } + + + /** retrieve the parent scope which encloses this scope. + * @throw error::Invalid if this is the root scope + */ + Scope const& + Scope::getParent() const + { + UNIMPLEMENTED ("retrieve the enclosing parent scope"); + } + + + /** @return true if this is the outmost (root) scope */ + bool + Scope::isRoot() const + { + UNIMPLEMENTED ("detection of root scope"); + } + + + /** enumerate the path of nested scopes up to root scope. + * @return an iterator which starts with this scope and + * successively yields outer scopes, stopping at root. + */ + Scope::IterType_ + Scope::ascend() const + { + UNIMPLEMENTED ("ascend scope hierarchy up to root"); + } + + + diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp index fa7a0a0a7..c4bffae06 100644 --- a/src/proc/mobject/session/scope.hpp +++ b/src/proc/mobject/session/scope.hpp @@ -28,6 +28,7 @@ //#include "proc/mobject/mobject.hpp" #include "proc/mobject/placement.hpp" #include "proc/mobject/placement-ref.hpp" +#include "lib/iter-adapter.hpp" #include "lib/singleton.hpp" #include @@ -41,6 +42,7 @@ namespace mobject { namespace session { using boost::scoped_ptr; + using lib::IterAdapter; class ScopeLocator; class QueryFocusStack; @@ -53,6 +55,8 @@ namespace session { { RefPlacement anchor_; + typedef IterAdapter IterType_; + public: Scope (PlacementMO const& constitutingPlacement); @@ -60,6 +64,11 @@ namespace session { static Scope const& containing (RefPlacement const& refPlacement); Scope const& getParent() const; + PlacementMO& getTop() const; + bool isRoot() const; + + typedef IterType_ iterator; + iterator ascend() const; }; @@ -74,5 +83,21 @@ namespace session { ///////////////////////////TODO currently just fleshing the API + + inline Scope const& + Scope::containing (RefPlacement const& refPlacement) + { + return containing (*refPlacement); + } + + + inline PlacementMO& + Scope::getTop() const + { + ASSERT (anchor_); + return *anchor_; + } + + }} // namespace mobject::session #endif diff --git a/tests/components/proc/mobject/placement-scope-test.cpp b/tests/components/proc/mobject/placement-scope-test.cpp index f89cc4f4d..cac6cc14b 100644 --- a/tests/components/proc/mobject/placement-scope-test.cpp +++ b/tests/components/proc/mobject/placement-scope-test.cpp @@ -47,12 +47,13 @@ namespace test { // using namespace mobject::test; // typedef TestPlacement PSub; + using lumiera::error::LUMIERA_ERROR_INVALID; /*************************************************************************** * @test basic behaviour of the nested placement search scopes. - * Using a pseudo-session (actually just a PlacementIndex), this test - * creates some nested scopes and then... + * Using a pseudo-session (actually just a PlacementIndex), + * this test creates some nested scopes and then... * - discovers the scope of a placement * - finds the parent scope * - enumerates a scope path up to root From b03577ea3f22ea82d2c134925aecf06b389ad28a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Oct 2009 15:40:37 +0200 Subject: [PATCH 011/377] document the stipulations lib::IterAdapter puts on his parameter types --- src/lib/iter-adapter.hpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 6280e60f8..03d2699fe 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -129,6 +129,19 @@ namespace lib { * - we need friendship to access the callbacks on the container * - the end-of-iteration can be detected by bool check * + * \par Stipulations + * - POS refers to the current position within the data source of this iterator. + * -# it should be default constructible + * -# it should be copy constructible + * -# when IterAdapter is supposed to be assignable, then POS should be + * -# it should provide embedded typedefs for pointer, reference and value_type + * -# it should be convertible to the pointer type it declares + * -# dereferencing it should yield type that is convertible to the reference type + * - CON refers to the data source of this iterator (typically a data container type) + * We store a backlink to this object to invoke a special iteration control API: + * -# \c hasNext yields true iff the source has yet more result values to yield + * -# \c iterNext advances the POS to the next element + * * @see scoped-ptrvect.hpp usage example * @see iter-adaptor-test.cpp */ @@ -153,7 +166,7 @@ namespace lib { IterAdapter () : source_(0) - , pos_(0) + , pos_() { } From 2ca89010d1d307feb1db45afa4a27e2e77a20087 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Oct 2009 21:29:16 +0200 Subject: [PATCH 012/377] introduce pointer-to-PlacementIndex typedef --- src/proc/mobject/placement-index.cpp | 7 +++--- src/proc/mobject/placement-index.hpp | 5 ++++- .../proc/mobject/placement-scope-test.cpp | 2 +- .../proc/mobject/query-focus-test.cpp | 2 +- .../proc/mobject/scope-path-test.cpp | 2 +- .../proc/mobject/session/test-scopes.cpp | 22 +++++++++++++------ .../proc/mobject/session/test-scopes.hpp | 5 ++--- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/proc/mobject/placement-index.cpp b/src/proc/mobject/placement-index.cpp index 38758d80e..ac6bbb279 100644 --- a/src/proc/mobject/placement-index.cpp +++ b/src/proc/mobject/placement-index.cpp @@ -59,7 +59,6 @@ namespace mobject { /* some type shorthands */ - typedef shared_ptr PIdx; typedef PlacementIndex::PlacementMO PlacementMO; typedef PlacementIndex::PRef PRef; typedef PlacementIndex::ID ID; @@ -146,9 +145,9 @@ namespace mobject { namespace { // implementation detail: default global placement index access - PIdx globalIndex; + PPIdx globalIndex; - PIdx const& + PPIdx const& getGlobalIndex() { if (globalIndex) @@ -164,7 +163,7 @@ namespace mobject { void - reset_PlacementIndex (PIdx const& alternativeIndex) + reset_PlacementIndex (PPIdx const& alternativeIndex) { globalIndex = alternativeIndex; } diff --git a/src/proc/mobject/placement-index.hpp b/src/proc/mobject/placement-index.hpp index 5d9da5ff7..362ad7c8b 100644 --- a/src/proc/mobject/placement-index.hpp +++ b/src/proc/mobject/placement-index.hpp @@ -116,13 +116,16 @@ namespace mobject { }; ////////////////TODO currently just fleshing out the API; probably have to split off an impl.class; but for now a PImpl is sufficient... + + typedef shared_ptr PPIdx; + /** @internal there is an implicit PlacementIndex available on a global scale, * by default implemented within the current session. This function allows * to re-define this implicit index temporarily, e.g. for unit tests. */ void - reset_PlacementIndex(shared_ptr const&) ; + reset_PlacementIndex(PPIdx const&) ; /** @internal restore the implicit PlacementIndex to its default implementation (=the session) */ void diff --git a/tests/components/proc/mobject/placement-scope-test.cpp b/tests/components/proc/mobject/placement-scope-test.cpp index cac6cc14b..86c51b184 100644 --- a/tests/components/proc/mobject/placement-scope-test.cpp +++ b/tests/components/proc/mobject/placement-scope-test.cpp @@ -69,7 +69,7 @@ namespace test { run (Arg) { // Prepare an (test)Index backing the PlacementRefs - PIdx index = build_testScopes(); + PPIdx index = build_testScopes(); UNIMPLEMENTED ("function test of placement scope interface"); verifyLookup (index); diff --git a/tests/components/proc/mobject/query-focus-test.cpp b/tests/components/proc/mobject/query-focus-test.cpp index 4500c0db6..f3253af4b 100644 --- a/tests/components/proc/mobject/query-focus-test.cpp +++ b/tests/components/proc/mobject/query-focus-test.cpp @@ -61,7 +61,7 @@ namespace test { { // Prepare an (test)Index backing the PlacementRefs - PIdx index = build_testScopes(); + PPIdx index = build_testScopes(); // PMO& root = index->getRoot(); UNIMPLEMENTED ("unit test to cover query focus management"); diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp index 817883c4b..cc05c1d3f 100644 --- a/tests/components/proc/mobject/scope-path-test.cpp +++ b/tests/components/proc/mobject/scope-path-test.cpp @@ -62,7 +62,7 @@ namespace test { run (Arg) { // Prepare an (test)Index backing the PlacementRefs - PIdx index = build_testScopes(); + PPIdx index = build_testScopes(); UNIMPLEMENTED ("unit test regarding placement scope handling"); } diff --git a/tests/components/proc/mobject/session/test-scopes.cpp b/tests/components/proc/mobject/session/test-scopes.cpp index 0b58081d5..b1cab5cf2 100644 --- a/tests/components/proc/mobject/session/test-scopes.cpp +++ b/tests/components/proc/mobject/session/test-scopes.cpp @@ -57,17 +57,21 @@ namespace test { * test PlacementIndex will be cleared automatically, and the * default Index within the session will be re-activated. */ - PIdx + PPIdx build_testScopes() { - PSub p1(*new TestSubMO21); - PSub p2(*new TestSubMO21); - PSub p3(*new TestSubMO21); - PSub p4(*new TestSubMO21); - PSub p5(*new TestSubMO21); + PDum p1(*new TestSubMO21); + PDum p2(*new TestSubMO21); + PDum p3(*new TestSubMO21); + PDum p4(*new TestSubMO21); + PDum p5(*new TestSubMO21); + + PDum ps1(*new DummyMO); + PDum ps2(*new TestSubMO1); + PDum ps2(*new TestSubMO2); // Prepare an (test)Index backing the PlacementRefs - PIdx index (PlacementIndex::create().get(), &remove_testIndex); // taking ownership + PPIdx index (PlacementIndex::create().get(), &remove_testIndex); // taking ownership reset_PlacementIndex(index); PMO& root = index->getRoot(); @@ -77,6 +81,10 @@ namespace test { index->insert (p4, p3 ); index->insert (p5, p4 ); + index->insert (ps1,root); + index->insert (ps2,root); + index->insert (ps3,root); + return index; } diff --git a/tests/components/proc/mobject/session/test-scopes.hpp b/tests/components/proc/mobject/session/test-scopes.hpp index 760ab0d75..bb9690902 100644 --- a/tests/components/proc/mobject/session/test-scopes.hpp +++ b/tests/components/proc/mobject/session/test-scopes.hpp @@ -50,8 +50,7 @@ namespace test { using std::tr1::shared_ptr; using namespace mobject::test; - typedef TestPlacement PSub; - typedef shared_ptr PIdx; + typedef TestPlacement PDum; @@ -65,7 +64,7 @@ namespace test { * @see session::SessManagerImpl::getCurrentIndex() * @see mobject::reset_PlacementIndex */ - PIdx build_testScopes(); + PPIdx build_testScopes(); }}} // namespace mobject::session::test From 2e62a3b01ba5738c8aba979120d1a1fb2924ebf2 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Oct 2009 21:31:03 +0200 Subject: [PATCH 013/377] WIP continue design how to discover session contents --- src/lib/iter-adapter.hpp | 3 +- src/proc/mobject/placement-index.hpp | 18 +++- src/proc/mobject/session/contents-query.hpp | 88 +++++++++++++++++ src/proc/mobject/session/query-resolver.hpp | 48 ++++++++++ src/proc/mobject/session/scope.hpp | 2 +- tests/43session.tests | 4 + .../proc/mobject/placement-scope-test.cpp | 37 ++++--- .../proc/mobject/scope-path-test.cpp | 1 - .../mobject/session/contents-query-test.cpp | 96 +++++++++++++++++++ wiki/renderengine.html | 54 ++++++++--- 10 files changed, 317 insertions(+), 34 deletions(-) create mode 100644 src/proc/mobject/session/contents-query.hpp create mode 100644 tests/components/proc/mobject/session/contents-query-test.cpp diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 03d2699fe..c9d351988 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -134,7 +134,8 @@ namespace lib { * -# it should be default constructible * -# it should be copy constructible * -# when IterAdapter is supposed to be assignable, then POS should be - * -# it should provide embedded typedefs for pointer, reference and value_type + * -# it should provide embedded typedefs for pointer, reference and value_type, + * or alternatively resolve these types through a specialisation if IterTraits. * -# it should be convertible to the pointer type it declares * -# dereferencing it should yield type that is convertible to the reference type * - CON refers to the data source of this iterator (typically a data container type) diff --git a/src/proc/mobject/placement-index.hpp b/src/proc/mobject/placement-index.hpp index 362ad7c8b..98de15581 100644 --- a/src/proc/mobject/placement-index.hpp +++ b/src/proc/mobject/placement-index.hpp @@ -40,6 +40,7 @@ #include "lib/factory.hpp" #include "proc/mobject/placement.hpp" #include "proc/mobject/placement-ref.hpp" +#include "proc/mobject/session/query-resolver.hpp" #include #include @@ -47,7 +48,7 @@ #include -namespace mobject { +namespace mobject { ///////////////////////////////////////////TODO: shouldn't this go into namespace session ? using lib::factory::RefcountFac; using std::tr1::shared_ptr; @@ -60,7 +61,8 @@ namespace mobject { /** */ class PlacementIndex - : boost::noncopyable + : public session::QueryResolver ////////TODO: really inherit here? + , boost::noncopyable { class Table; @@ -88,11 +90,14 @@ namespace mobject { /** retrieve the logical root scope */ PlacementMO& getRoot() const; - /** diagnostic: number of indexed entries */ size_t size() const; bool contains (PlacementMO const&) const; bool contains (ID) const; + template + typename session::Query >::iterator + query (PlacementMO& scope) const; + /* == mutating operations == */ @@ -159,6 +164,13 @@ namespace mobject { } + template + inline typename session::Query >::iterator + PlacementIndex::query (PlacementMO& scope) const + { + UNIMPLEMENTED ("actually run the containment query"); + } + inline Placement& PlacementIndex::getScope (PlacementMO const& p) const { diff --git a/src/proc/mobject/session/contents-query.hpp b/src/proc/mobject/session/contents-query.hpp new file mode 100644 index 000000000..6e6857498 --- /dev/null +++ b/src/proc/mobject/session/contents-query.hpp @@ -0,0 +1,88 @@ +/* + CONTENTS-QUERY.hpp - query to discover the contents of a container-like part of the model + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef MOBJECT_SESSION_CONTENTS_QUERY_H +#define MOBJECT_SESSION_CONTENTS_QUERY_H + +//#include "proc/mobject/mobject.hpp" +#include "proc/mobject/placement.hpp" +#include "proc/mobject/placement-index.hpp" +#include "proc/mobject/session/query-resolver.hpp" +//#include "lib/iter-adapter.hpp" + +#include +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + + + /** + * TODO type comment + */ + template + class ContentsQuery + : public Query > + , boost::noncopyable + { + PPIdx index_; + PlacementMO const& container_; + + iterator + runQuery() + { + UNIMPLEMENTED ("actually query the index"); + } + + + bool + isValid (Cur& pos) + { + UNIMPLEMENTED ("how to manager result set position"); + } + + + Cur const& + nextResult() + { + UNIMPLEMENTED ("how to manager result set position"); + } + + + public: + ContentsQuery (PPIdx index, PlacementMO const& scope) + : index_(index) + , container_(scope) + { } + + }; +///////////////////////////TODO currently just fleshing the API + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index da2b3a813..dc0bd6960 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -26,6 +26,7 @@ //#include "proc/mobject/mobject.hpp" //#include "proc/mobject/placement.hpp" +#include "lib/iter-adapter.hpp" //#include //#include @@ -36,6 +37,38 @@ namespace mobject { namespace session { + class Scope; + + /** + * TODO type comment + */ + template ///////////////////////TODO: can we get rid of that type parameter? in conjunction with the virtual functions, it causes template code bloat + class Query + { + public: + virtual ~Query() {} + + /* results retrieval */ + + typedef MO* Cur; + typedef lib::IterAdapter iterator; + + iterator operator()(){ return this->runQuery(); } + + static bool hasNext (const Query* thisQuery, Cur& pos) { return thisQuery->isValid(pos); } + static void iterNext (const Query* thisQuery, Cur& pos) { pos = thisQuery->nextResult(); } + + /* diagnostics */ + static size_t query_cnt(); + + + protected: + virtual iterator runQuery() =0; + + /* iteration control */ + virtual bool isValid (Cur& pos) const =0; + virtual Cur const& nextResult() const =0; + }; /** @@ -48,6 +81,21 @@ namespace session { virtual ~QueryResolver() {} + + /** issue a query to retrieve contents + * @param scope or container on which to discover contents + * @return an iterator to yield all elements of suitable type + * + * @todo doesn't this create a circular dependency? scope indirectly relies on QueryResolver, right?? + */ + template + typename Query::iterator + query (Scope const& scope) + { + UNIMPLEMENTED ("create a specific contents query to enumerate contents of scope"); + } + + }; ///////////////////////////TODO currently just fleshing the API diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp index c4bffae06..ce3de7d86 100644 --- a/src/proc/mobject/session/scope.hpp +++ b/src/proc/mobject/session/scope.hpp @@ -60,7 +60,7 @@ namespace session { public: Scope (PlacementMO const& constitutingPlacement); - static Scope const& containing (PlacementMO const& aPlacement); + static Scope const& containing (PlacementMO const& aPlacement); //////////////TODO really returning a const& here?? static Scope const& containing (RefPlacement const& refPlacement); Scope const& getParent() const; diff --git a/tests/43session.tests b/tests/43session.tests index d5218096c..170382dee 100644 --- a/tests/43session.tests +++ b/tests/43session.tests @@ -6,6 +6,10 @@ PLANNED "AddClip_test" AddClip_test < //#include -using util::isSameObject; -//using lumiera::Time; -//using std::string; -using std::cout; -using std::endl; namespace mobject { @@ -46,9 +41,15 @@ namespace session { namespace test { // using namespace mobject::test; -// typedef TestPlacement PSub; using lumiera::error::LUMIERA_ERROR_INVALID; + using util::isSameObject; + //using lumiera::Time; + //using std::string; + using std::cout; + using std::endl; + + /*************************************************************************** * @test basic behaviour of the nested placement search scopes. @@ -77,22 +78,28 @@ namespace test { } - typedef PlacementIndex::Query::iterator _Iter; + typedef Query >::iterator _Iter; + + _Iter + getContents(PPIdx index) + { + return index->query(index->getRoot()); + } /** @test for each Placement in our test "session", * find the scope and verify it's in line with the index */ void - verifyLookup (PIdx ref_index) + verifyLookup (PPIdx ref_index) { - for (_Iter elm = ref_index.query(); elm; ++elm) + for (_Iter elm = getContents(ref_index); elm; ++elm) { ASSERT (elm->isValid()); - cout << *elm << endl; - Scope& scope1 = Scope::containing(*elm); + cout << string(*elm) << endl; + Scope const& scope1 = Scope::containing(*elm); RefPlacement ref (*elm); - Scope& scope2 = Scope::containing(ref); + Scope const& scope2 = Scope::containing(ref); // verify this with the scope registered within the index... PlacementMO& scopeTop = ref_index->getScope(*elm); @@ -107,11 +114,11 @@ namespace test { /** @test navigate to root, starting from each Placement */ void - verifyNavigation (PIdx ref_index) + verifyNavigation (PPIdx ref_index) { - for (_Iter elm = ref_index.query(); elm; ++elm) + for (_Iter elm = getContents(ref_index); elm; ++elm) { - Scope& scope = Scope::containing(*elm); + Scope const& scope = Scope::containing(*elm); ASSERT (scope == *scope.ascend()); for (Scope::iterator sco = scope.ascend(); sco; ++sco) if (sco->isRoot()) diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp index cc05c1d3f..ddfb92da2 100644 --- a/tests/components/proc/mobject/scope-path-test.cpp +++ b/tests/components/proc/mobject/scope-path-test.cpp @@ -44,7 +44,6 @@ namespace session { namespace test { // using namespace mobject::test; -// typedef TestPlacement PSub; /*************************************************************************** diff --git a/tests/components/proc/mobject/session/contents-query-test.cpp b/tests/components/proc/mobject/session/contents-query-test.cpp new file mode 100644 index 000000000..a62cf9802 --- /dev/null +++ b/tests/components/proc/mobject/session/contents-query-test.cpp @@ -0,0 +1,96 @@ +/* + ContentsQuery(Test) - running queries to discover container contents, filtering (sub)types + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +//#include "lib/lumitime.hpp" +//#include "proc/mobject/placement-ref.hpp" +#include "proc/mobject/session/query-resolver.hpp" +#include "proc/mobject/session/contents-query.hpp" +#include "proc/mobject/session/test-scopes.hpp" +//#include "proc/mobject/placement-index.hpp" +//#include "lib/util.hpp" + +#include +//#include + + + +namespace mobject { +namespace session { +namespace test { + + using session::ContentsQuery; + using session::Query; + //using util::isSameObject; + //using lumiera::Time; + //using std::string; + using std::cout; + using std::endl; + + + /*************************************************************************************** + * @test how to discover the contents of a container-like part of the high-level model. + * As this container-like object is just a concept and actually implemented + * by the PlacementIndex, this includes enumerating a scope. The discovered + * contents may be additionally filtered by a runtime type check. + * + * @see mobject::PlacementIndex + * @see mobject::session::QueryResolver + * @see mobject::session::ContentsQuery + */ + class ContentsQuery_test : public Test + { + + virtual void + run (Arg) + { + + // Prepare an (test)Index backing the PlacementRefs + PPIdx index = build_testScopes(); + PlacementMO scope (index->getRoot()); + + discover (ContentsQuery (index,scope)); + discover (ContentsQuery (index,scope)); + discover (ContentsQuery (index,scope)); + discover (ContentsQuery (index,scope)); + discover (ContentsQuery(index,scope)); + } + + + template + void + discover (Query const& query) + { + Query::iterator elm = query(); + while (elm) + cout << *elm++ << endl; + } + + }; + + + /** Register this test class... */ + LAUNCHER (ContentsQuery_test, "unit session"); + + +}}} // namespace mobject::session::test diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 2c9abe508..9c5e6f979 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -1151,7 +1151,7 @@ For this to work, we need each of the //participating object types// to implemen @@clear(left):display(block):@@
                                    -
                                    +
                                    Many features can be implemented by specifically configuring and wiring some unspecific components. Rather than tie the client code in need of some given feature to these configuration internals, in Lumiera the client can //query // for some kind of object providing the //needed capabilities. // Right from start (summer 2007), Ichthyo had the intention to implement such a feature using sort of a ''declarative database'', e.g. by embedding a Prolog system. By adding rules to the basic session configuration, users should be able to customize the semi-automatic part of Lumiera's behaviour to great extent.
                                     
                                     [[Configuration Queries|ConfigQuery]] are used at various places, when creating and adding new objects, as well when building or optimizing the render engine node network.
                                    @@ -1632,7 +1632,7 @@ Besides routing to a global pipe, wiring plugs can also connect to the source po
                                     Finally, this example shows an ''automation'' data set controlling some parameter of an effect contained in one of the global pipes. From the effect's POV, the automation is simply a ParamProvider, i.e a function yielding a scalar value over time. The automation data set may be implemented as a bézier curve, or by a mathematical function (e.g. sine or fractal pseudo random) or by some captured and interpolated data values. Interestingly, in this example the automation data set has been placed relatively to the meta clip (albeit on another track), thus it will follow and adjust when the latter is moved.
                                     
                                    -
                                    +
                                    This wiki page is the entry point to detail notes covering some technical decisions, details and problems encountered in the course of the implementation of the Lumiera Renderengine, the Builder and the related parts.
                                     
                                     * [[Packages, Interfaces and Namespaces|InterfaceNamespaces]]
                                    @@ -1656,7 +1656,8 @@ Finally, this example shows an ''automation'' data set controlling some paramete
                                     * how to [[start the GUI|GuiStart]] and how to [[communicate|GuiCommunication]]
                                     * build the first LayerSeparationInterfaces
                                     * decide on SessionInterface and create [[Session datastructure layout|SessionDataMem]]
                                    -* shaping the GUI/~Proc-Interface, based on MObjectRef and the [[Command frontend|CommandHandling]]
                                    +* shaping the GUI/~Proc-Interface, based on MObjectRef and the [[Command frontend|CommandHandling]] +* defining PlacementScope in order to allow for [[discovering session contents|Query]]
                                    !Observations, Ideas, Proposals
                                    @@ -3051,10 +3052,10 @@ Placement references mimic the behaviour of a real placement, i.e. they proxy th
                                     {{red{WIP}}}
                                     
                                    -
                                    +
                                    MObjects are attached into the [[Session]] by adding a [[Placement]]. Because this especially includes the case of //grouping or container objects,// e.g. tracks or [[meta-clips|VirtualClip]], any placement may optionally define and root a scope, and every placement is at least contained in one encompassing scope &mdash; of course with the exception of the absolute top level, which can be thought off as being contained in a scope of handling rules.
                                     
                                    -Thus, while the [[sequences (former called EDL)|EDL]] act as generic container holding a pile of placments, actually there is a more fine grained structure based on the nesting of the tracks, which especially in Lumiera's HighLevelModel belong to the sequence (they aren't a property of the top level timeline as one might expect). Building upon these observations, we actually require each addition of a placement to specify a scope. Consequently, for each Placement at hand it is possible to determine an //containing scope,// which in turn is associated with some Placement of a top-level ~MObject for this scope. An example would be the {{{Placement<Track>}}} acting as scope of all the clips placed onto this track. The //implementation//&nbsp; of this tie-to-scope is provided by the same mechanism as utilised for relative placements, i.e. an directional placement relation. Actually, this relation is implemented by the PlacementIndex within the current [[Session]].
                                    +Thus, while the [[sequences (former called EDL)|EDL]] act as generic container holding a pile of placments, actually there is a more fine grained structure based on the nesting of the tracks, which especially in Lumiera's HighLevelModel belong to the sequence (they aren't a property of the top level timeline as one might expect). Building upon these observations, we actually require each addition of a placement to specify a scope. Consequently, for each Placement at hand it is possible to determine an //containing scope,// which in turn is associated with some Placement of a top-level ~MObject for this scope. The latter is called the ''scope top''. An example would be the {{{Placement<Track>}}} acting as scope of all the clips placed onto this track. The //implementation//&nbsp; of this tie-to-scope is provided by the same mechanism as utilised for relative placements, i.e. an directional placement relation. Actually, this relation is implemented by the PlacementIndex within the current [[Session]].
                                     
                                     
                                     [>img[Structure of Placment Scopes|draw/ScopeStructure1.png]]
                                    @@ -3307,7 +3308,7 @@ Besides, they provide an __inward interface__ for the [[ProcNode]]s, enabling th
                                     
                                     
                                    -
                                    +
                                    The Render Engine is the part of the application doing the actual video calculations. Its operations are guided by the Objects and Parameters edited by the user in [[the EDL|EDL]] and it retrieves the raw audio and video data from the [[Data backend|backend.html]]. Because the inner workings of the Render Engine are closely related to the structures used in the EDL, this design covers [[the aspect of objects placed into the EDL|MObjects]] as well.
                                     <<<
                                     ''Status'': started out as design draft in summer '07, Ichthyo is now in the middle of a implementing the foundations and main structures in C++
                                    @@ -3382,7 +3383,23 @@ Viewed as a micro program, the processing patterns are ''weak typed'' &mdash
                                     
                                    a given Render Engine configuration is a list of Processors. Each Processor in turn contains a Graph of ProcNode.s to do the acutal data processing. In order to cary out any calculations, the Processor needs to be called with a StateProxy containing the state information for this RenderProcess
                                     
                                    -
                                    +
                                    +
                                    {{red{WIP as of 10/09}}}...//brainstorming about the first ideas towards a query subsystem//
                                    +
                                    +!use case: discovering the contents of a container in the HighLevelModel
                                    +In the course of shaping the session API, __joel__ and __ichthyo__ realised that we're moving towards some sort of discovery or introspection. This gives rise to the quest for a //generic// pattern how to issue and run these discovery operations. The idea is to understand such a discovery as running a query &mdash; using this specific problem to shape the foundation of a query subsystem to come.
                                    +* a ''query'' is a polymorphic, noncopyable, non-singleton type; a query instance corresponds to one distinctly issued query
                                    +* issuing a query yields a result set, which is hidden within the concrete query implementation.
                                    +* the transactional behaviour needs still to be defined: how to deal with concurrent modifications? COW?
                                    +* the query instance remains property of the entity exposing the query capability.
                                    +* client code gets a result iterator, which can be explored //only once until exhaustion.//
                                    +* the handed out result iterator is used to manage the allocation for the query result set by sideeffect (smart handle). &rarr; Ticket #353
                                    +
                                    +----
                                    +See also the notes on &rarr; QueryImplProlog
                                    +
                                    +
                                    +
                                    When querying contents of the session or sub-containers within the session, the QueryFocus follows the current point-of-query. As such queries can be issued to explore the content of container-like objects holding other MObjects, the focus is always attached to a container, which also acts as [[scope|PlacementScope]] for the contained objects. QueryFocus is an implicit state (the current point of interrest). This sate especially remembers the path down from the root of the HighLevelModel, which was used to access the current scope. Because this path constitutes a hierarchy of scopes, it can be relevant for querying and resolving placement properties. (&rarr; SessionStructureQuery)
                                     
                                     !provided operations
                                    @@ -3393,7 +3410,7 @@ Viewed as a micro program, the processing patterns are ''weak typed'' &mdash
                                     * get the current ScopePath from root (session globals) down to the current scope
                                     [>img[Scope Locating|uml/fig136325.png]]
                                     !!!relation to Scope
                                    -There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current scope.// But QueryFocus is more of a //binding// &mdash; it links or focusses the current state and into a specific scope with a ScopePath depending on the current state. Thus, while Scope is just a passive container allowing locate and navigate, QueryFocus by virtue of this binding allows to query this current location.
                                    +There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current scope.// But QueryFocus is more of a //binding// &mdash; it links or focusses the current state and into a specific scope with a ScopePath depending on the current state. Thus, while Scope is just a passive container allowing to locate and navigate, QueryFocus by virtue of this binding allows to [[Query]] at this current location.
                                     
                                     !implementation notes
                                     we provide a static access API, meaning that there is a singleton behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. This link works by the current session grabbing the query focus and attaching to it. This attachment is shallow, i.e. the QueryFocus doesn't have knowledge about the session, which allows the focus to be unit tested.
                                    @@ -3404,7 +3421,7 @@ The stack of scopes must not be confused with the ScopePath. Each single frame o
                                     The full implementation of this scope navigation is tricky, especially when it comes to determining the relation of two positions. It should be ''postponed'' and replaced by a ''dummy'' (no-op) implementation for the first integration round.
                                     
                                    -
                                    +
                                    //obviously, getting this one to work requires quite a lot of technical details to be planned and implemented.// This said...
                                     The intention is to get much more readable ("declarative") and changeable configuration as by programming the decision logic literately within the implementation of some object.
                                     
                                    @@ -3773,6 +3790,17 @@ __see also__
                                     
                                     Rendering can be seen as a passive service available to the Backend, which remains in charge what to render and when. Render processes may be running in parallel without any limitations. All of the storage and data management falls into the realm of the Backend. The render nodes themselves are ''completely stateless'' &mdash; if some state is necessary for carrying out the calculations, the backend will provide a //state frame// in addition to the data frames.
                                    +
                                    +
                                    A distinct property of the Lumiera application is to rely on a rules based approach rather then on hard wired logic. When it comes to deciding and branching, a [[Query]] is issued, resulting either immediately in a {{{bool}}} result, or creating a //binding// for the variables used within the query. Commonly, there is more than one solution for a given query, allowing the result set to be enumerated.
                                    +
                                    +
                                    +
                                    +
                                    +!current state {{red{WIP as of 10/09}}}
                                    +We are still fighting to get the outline of the application settled down.
                                    +For now, the above remains in the status of a general concept and typical solution pattern: ''create query points instead of hard wiring things''.
                                    +Later on we expect a distinct __query subsystem__ to emerge, presumably embedding a YAP Prolog interpreter.
                                    +
                                    A facility allowing the Proc-Layer to work with abstracted [[media stream types|StreamType]], linking (abstract or opaque) [[type tags|StreamTypeDescriptor]] to an [[library|MediaImplLib]], which provides functionality for acutally dealing with data of this media stream type. Thus, the stream type manager is a kind of registry of all the external libraries which can be bridged and accessed by Lumiera (for working with media data, that is). The most basic set of libraries is instelled here automatically at application start, most notably the [[GAVL]] library for working with uncompressed video and audio data. //Later on, when plugins will introduce further external libraries, these need to be registered here too.//
                                    @@ -3792,12 +3820,12 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl {{red{TODO...}}}
                                    -
                                    +
                                    "Session Interface", when used in a more general sense, denotes a compound of several interfaces and facilities, together forming the primary access point to the user visible contents and state of the editing project.
                                     * the API of the session class
                                     * the accompanying management interface (SessionManager API)
                                     * an LayerSeparationInterfaces allowing to access these interfaces from outside the Proc-Layer
                                    -* the primary public ~APIs exposed on the objects to be [[queried and retrieved|SessionQueryStructure]] via the session class API
                                    +* the primary public ~APIs exposed on the objects to be [[queried and retrieved|SessionStructureQuery]] via the session class API
                                     ** Timeline
                                     ** Sequence
                                     ** Placement
                                    @@ -3854,7 +3882,7 @@ It will contain a global video and audio out pipe, just one EDL with a single tr
                                     &rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
                                     
                                    -
                                    +
                                    The frontside interface of the session allows to query for contained objects; it is used to discover the structure and contents of the currently opened session/project. Access point is the public API of the Session class, which, besides exposing those queries, also provides functionality for adding and removing session contents.
                                     
                                     !discovering structure
                                    @@ -3869,7 +3897,7 @@ To give an example, let's assume a clip within a sequence, and this sequence is
                                     In this case, the sequence has an 1:n [[binding|BindingMO]]. A binding is (by definition) also a PlacementScope, and, incidentally, in the case of binding the sequence into a timeline, the binding also translates //logical// output designations into global pipes found within the timeline, while otherwise they get mapped onto "channels" of the virtual media used by the virtual clip. Thus, the absolute time position as well as the output connection of a given clip within this sequence //depends on how we look at this clip.// Does this clip apear as part of the global timeline, or did we discover it as contained within the meta-clip?
                                     
                                     !!solution requirements
                                    -The baseline of any solution to this problem is clear: at the point where the query is issued, a context information is necessary; this context yields an access path from top level down to the object to be queried, and this access path constitutes the effective scope this object utilises for resolving the query.
                                    +The baseline of any solution to this problem is clear: at the point where the query is issued, a context information is necessary; this context yields an access path from top level down to the object to be queried, and this access path constitutes the effective scope this object can utilise for resolving the query.
                                     
                                     !!introducing a QueryFocus
                                     A secondary goal of the design here is to ease the use of the session query interface. Thus the proposal is to treat this context and access path as part of the current state. To do so, we can introduce a QueryFocus following the queries and remembering the access path; this focus should be maintained mostly automatically. It allows for stack-like organisation, to allow sub-queries without affecting the current focus, where the handling of such a temporary sub-focus is handled automatically by a scoped local (RAII) object. The focus follows the issued queries and re-binds as necessary.
                                    
                                    From 474c29319717fe72698ea74e1a2eb944066fb7b3 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 18 Oct 2009 01:30:43 +0200
                                    Subject: [PATCH 014/377] first shot at Ticket #355: use a default-constructed
                                     "invalid" PlacementRef
                                    
                                    Making PlacementRef default constructible this way
                                    would resolve the immediate problems; as any access
                                    goes through an index lookup and thus will throw.
                                    The bool check on this special ref yields false,
                                    so this solution seems to fill the bill.
                                    ---
                                     src/proc/mobject/placement-ref.hpp      | 7 +++++++
                                     src/proc/mobject/session/scope-path.hpp | 2 +-
                                     src/proc/mobject/session/scope.cpp      | 7 +++++++
                                     src/proc/mobject/session/scope.hpp      | 1 +
                                     4 files changed, 16 insertions(+), 1 deletion(-)
                                    
                                    diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp
                                    index 37f629472..5677aeac4 100644
                                    --- a/src/proc/mobject/placement-ref.hpp
                                    +++ b/src/proc/mobject/placement-ref.hpp
                                    @@ -106,6 +106,13 @@ namespace mobject {
                                               validate(id_); 
                                             }
                                           
                                    +      /** Default is an NIL Placement ref. It throws on any access. */
                                    +      PlacementRef ()
                                    +        : id_()
                                    +        {
                                    +          REQUIRE (!isValid(), "hash-ID clash with existing ID");
                                    +        }
                                    +      
                                           PlacementRef (PlacementRef const& r)    ///< copy ctor
                                             : id_(r.id_)
                                             { 
                                    diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp
                                    index f5366a457..5835e6a8d 100644
                                    --- a/src/proc/mobject/session/scope-path.hpp
                                    +++ b/src/proc/mobject/session/scope-path.hpp
                                    @@ -43,7 +43,7 @@ namespace session {
                                        */
                                       class ScopePath
                                         {
                                    -      vector path_;
                                    +      vector path_;
                                           
                                         public:
                                           ScopePath();
                                    diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp
                                    index 6c00a222e..abd0293ff 100644
                                    --- a/src/proc/mobject/session/scope.cpp
                                    +++ b/src/proc/mobject/session/scope.cpp
                                    @@ -42,6 +42,13 @@ namespace session {
                                       }
                                       
                                       
                                    +  Scope::Scope ()
                                    +    : anchor_()
                                    +  {
                                    +    REQUIRE (!anchor_.isValid());
                                    +  }
                                    +  
                                    +  
                                       ScopeLocator::ScopeLocator()
                                         : focusStack_(new QueryFocusStack)
                                       {
                                    diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp
                                    index ce3de7d86..bc192bbb5 100644
                                    --- a/src/proc/mobject/session/scope.hpp
                                    +++ b/src/proc/mobject/session/scope.hpp
                                    @@ -59,6 +59,7 @@ namespace session {
                                           
                                         public:
                                           Scope (PlacementMO const& constitutingPlacement);
                                    +      Scope (); ///< unlocated NIL scope
                                           
                                           static Scope const& containing (PlacementMO const& aPlacement);              //////////////TODO really returning a const& here??
                                           static Scope const& containing (RefPlacement const& refPlacement);
                                    
                                    From f0c9beb5c66d327cf7446a162a7dae0833b652c6 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 18 Oct 2009 19:08:21 +0200
                                    Subject: [PATCH 015/377] WIP design the ScopePath API by unit test
                                    
                                    ---
                                     src/proc/mobject/session/scope-path.hpp       |   3 +-
                                     src/proc/mobject/session/scope.cpp            |  15 ++
                                     src/proc/mobject/session/scope.hpp            |  19 +-
                                     .../proc/mobject/scope-path-test.cpp          | 217 +++++++++++++++++-
                                     .../proc/mobject/session/test-scopes.cpp      |   4 +-
                                     wiki/renderengine.html                        |  23 +-
                                     6 files changed, 253 insertions(+), 28 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp
                                    index 5835e6a8d..5eb43f44a 100644
                                    --- a/src/proc/mobject/session/scope-path.hpp
                                    +++ b/src/proc/mobject/session/scope-path.hpp
                                    @@ -25,7 +25,8 @@
                                     #define MOBJECT_SESSION_SCOPE_PATH_H
                                     
                                     //#include "proc/mobject/mobject.hpp"
                                    -#include "proc/mobject/placement-ref.hpp"
                                    +//#include "proc/mobject/placement-ref.hpp"
                                    +#include "proc/mobject/session/scope.hpp"
                                     
                                     #include 
                                     //#include 
                                    diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp
                                    index abd0293ff..930690a05 100644
                                    --- a/src/proc/mobject/session/scope.cpp
                                    +++ b/src/proc/mobject/session/scope.cpp
                                    @@ -65,6 +65,21 @@ namespace session {
                                       }
                                       
                                       
                                    +  Scope const&
                                    +  Scope::containing (RefPlacement const& refPlacement)
                                    +  {
                                    +    return containing (*refPlacement);
                                    +  }
                                    +  
                                    +  
                                    +  PlacementMO&
                                    +  Scope::getTop()  const
                                    +  {
                                    +    ASSERT (anchor_);
                                    +    return *anchor_;
                                    +  }
                                    +  
                                    +  
                                       /** retrieve the parent scope which encloses this scope.
                                        *  @throw error::Invalid if this is the root scope
                                        */
                                    diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp
                                    index bc192bbb5..241d33b73 100644
                                    --- a/src/proc/mobject/session/scope.hpp
                                    +++ b/src/proc/mobject/session/scope.hpp
                                    @@ -50,6 +50,10 @@ namespace session {
                                     
                                       /**
                                        * TODO type comment
                                    +   * @note Scope is a passive entity,
                                    +   *       basically just wrapping up a Scope-top Placement.
                                    +   *       Contrast this to QueryFocus, which actively
                                    +   *       maintains the current focus location.
                                        */
                                       class Scope
                                         {
                                    @@ -85,20 +89,5 @@ namespace session {
                                       
                                       
                                       
                                    -  inline Scope const&
                                    -  Scope::containing (RefPlacement const& refPlacement)
                                    -  {
                                    -    return containing (*refPlacement);
                                    -  }
                                    -  
                                    -  
                                    -  inline PlacementMO&
                                    -  Scope::getTop()  const
                                    -  {
                                    -    ASSERT (anchor_);
                                    -    return *anchor_;
                                    -  }
                                    -  
                                    -  
                                     }} // namespace mobject::session
                                     #endif
                                    diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp
                                    index ddfb92da2..344e0f215 100644
                                    --- a/tests/components/proc/mobject/scope-path-test.cpp
                                    +++ b/tests/components/proc/mobject/scope-path-test.cpp
                                    @@ -22,28 +22,30 @@
                                     
                                     
                                     #include "lib/test/run.hpp"
                                    +#include "lib/test/test-helper.hpp"
                                     #include "proc/mobject/session/test-scopes.hpp"
                                     //#include "lib/lumitime.hpp"
                                     //#include "proc/mobject/placement-ref.hpp"
                                     //#include "proc/mobject/placement-index.hpp"
                                     //#include "proc/mobject/test-dummy-mobject.hpp"
                                    -//#include "lib/util.hpp"
                                    +#include "lib/util.hpp"
                                     
                                     //#include 
                                     //#include 
                                     
                                    -//using util::isSameObject;
                                    -//using lumiera::Time;
                                    -//using std::string;
                                    -//using std::cout;
                                    -//using std::endl;
                                     
                                     
                                     namespace mobject {
                                     namespace session {
                                     namespace test    {
                                       
                                    +  using util::isSameObject;
                                    +//using lumiera::Time;
                                    +//using std::string;
                                    +//using std::cout;
                                    +//using std::endl;
                                     //  using namespace mobject::test;
                                    +  using lumiera::error::LUMIERA_ERROR_LOGIC;
                                       
                                       
                                       /***************************************************************************
                                    @@ -62,8 +64,209 @@ namespace test    {
                                             {
                                               // Prepare an (test)Index backing the PlacementRefs
                                               PPIdx index = build_testScopes();
                                    +          PMO& startPlacement = *(index->query(index->getRoot()));
                                    +          ASSERT (startPlacement);
                                               
                                    -          UNIMPLEMENTED ("unit test regarding placement scope handling");
                                    +          ScopePath testPath = buildPath (startPlacement);
                                    +          checkRelations (testPath,startPlacement);
                                    +          invalildPath (testPath,startPlacement);
                                    +          check_Identity_and_Copy (startPlacement);
                                    +          navigate (testPath, index);
                                    +        }
                                    +      
                                    +      
                                    +      ScopePath
                                    +      buildPath (PMO& startPla)
                                    +        {
                                    +          Scope startScope (startPla);
                                    +          ScopePath path (startScope);
                                    +          ASSERT (path);
                                    +          ASSERT (path.contains (startScope));
                                    +          return path;
                                    +          ScopePath path (startScope);
                                    +          
                                    +          ScopePath path2 (startScope);
                                    +          ScopePath path3 (path2);
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      checkRelations (ScopePath path1, PMO& refPla)
                                    +        {
                                    +          ASSERT (path1.contains (refPla));
                                    +          
                                    +          Scope refScope (refPla);
                                    +          ASSERT (path1.contains (refScope));
                                    +          ASSERT (path1.endsAt (refScope));
                                    +          
                                    +          ScopePath path2 (refScope);
                                    +          ASSERT (path2.contains (refScope));
                                    +          ASSERT (path2.endsAt (refScope));
                                    +          
                                    +          ASSERT (path1 == path2);
                                    +          ASSERT (!isSameObject (path,path2));
                                    +          
                                    +          Scope parent = path2.moveUp();
                                    +          ASSERT (path2.endsAt (parent));
                                    +          ASSERT (path1.endsAt (refScope));
                                    +          ASSERT (parent == refScope.getParent());
                                    +          ASSERT (path1 != path2);
                                    +          ASSERT (path2 != path1);
                                    +          ASSERT (path1.contains (path2)); ////////////////////TODO: not clear if we really need to implement those relations
                                    +          ASSERT (!disjoint(path1,path2));
                                    +          ASSERT (path2 == commonPrefix(path1,path2));
                                    +          ASSERT (path2 == commonPrefix(path2,path1));
                                    +          ASSERT (path1 != commonPrefix(path1,path2));
                                    +          ASSERT (path1 != commonPrefix(path2,path1));
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      invalidPath (ScopePath refPath, PMO& refPla)
                                    +        {
                                    +          ASSERT (refPath);
                                    +          ASSERT (!ScopePath::INVALID);
                                    +          
                                    +          ScopePath invalidP (ScopePath::INVALID);
                                    +          ASSERT (!invalildP);
                                    +          ASSERT (invalildP == ScopePath::INVALID);
                                    +          ASSERT (!isSameObject (invalidP, ScopePath::INVALID));
                                    +          
                                    +          ASSERT (refPath.contains (refPla));
                                    +          ASSERT (!invalidP.contains (refPla));
                                    +          
                                    +          Scope refScope (refPla);
                                    +          ASSERT (!invalidP.contains (refScope));
                                    +          ASSERT (!invalidP.endsAt (refScope));
                                    +          
                                    +          ASSERT (refPath.contains (invalidP));      // If the moon consists of green cheese, I'll eat my hat!
                                    +          ASSERT (!invalidP.contains (refPath));
                                    +          ASSERT (invalidP == commonPrefix(refPath,invalidP));
                                    +          ASSERT (invalidP == commonPrefix(invalidP,refPath));
                                    +          
                                    +          VERIFY_ERROR (LOGIC, invalidP.moveUp());
                                    +          Scope root = refPath.goRoot();
                                    +          ASSERT (1 == refPath.length());
                                    +          
                                    +          Scope nil = refPath.moveUp();
                                    +          ASSERT (!refPath);
                                    +          ASSERT (!nil.isValid());
                                    +          ASSERT (refPath == invalidP);
                                    +          ASSERT (invalidP.contains (nil));
                                    +          
                                    +          refPath.navigate(root);
                                    +          ASSERT (refPath != invalidP);
                                    +          ASSERT (refPath);
                                    +          
                                    +        //ScopePath::INVALID.navigate(root);  // doesn't compile
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      check_Identity_and_Copy (PMO& refPla)
                                    +        {
                                    +          Scope startScope (startPla);
                                    +          ScopePath path1 (startScope);
                                    +          ScopePath path2 (startScope);
                                    +          ScopePath path3 (path2);
                                    +          
                                    +          ASSERT (path1.contains (startScope));
                                    +          ASSERT (path2.contains (startScope));
                                    +          ASSERT (path3.contains (startScope));
                                    +          
                                    +          ASSERT (path1 == path2);
                                    +          ASSERT (path2 == path3);
                                    +          ASSERT (path1 == path3);
                                    +          ASSERT (!isSameObject (path1,path2));
                                    +          ASSERT (!isSameObject (path2,path3));
                                    +          ASSERT (!isSameObject (path1,path3));
                                    +          
                                    +          Scope parent = path3.moveUp();
                                    +          ASSERT (path1 == path2);
                                    +          ASSERT (path2 != path3);
                                    +          ASSERT (path1 != path3);
                                    +          
                                    +          path2 = path3;
                                    +          ASSERT (path1 != path2);
                                    +          ASSERT (path2 == path3);
                                    +          ASSERT (path1 != path3);
                                    +          
                                    +          path1 = ScopePath::INVALID;
                                    +          ASSERT (path1 != path2);
                                    +          ASSERT (path2 != path3);
                                    +          ASSERT (path1 != path3);
                                    +        }
                                    +      
                                    +      
                                    +      /** @test modify a path by \em navigating it.
                                    +       *  - move one step above the current leaf
                                    +       *  - move up to the root element
                                    +       *  - move back to the parent and verify we're just above the leaf
                                    +       *  - attach a new sibling node and move the path down to there
                                    +       *  - extract the common prefix, which should again point to the parent
                                    +       *  - find a placement in a completely separate branch (only sharing the
                                    +       *    root node). Navigate to there and verify root is the common prefix. 
                                    +       */
                                    +      void
                                    +      navigate (const ScopePath refPath, PPIdx index)
                                    +        {
                                    +          ScopePath path (refPath);
                                    +          ASSERT (path == refPath);
                                    +          
                                    +          Scope leaf = path.getLeaf();
                                    +          Scope parent = path.moveUp();
                                    +          ASSERT (path != refPath);
                                    +          ASSERT (refPath.contains (path));
                                    +          ASSERT (refPath.endsAt (leaf));
                                    +          ASSERT (path.endsAt (parent));
                                    +          ASSERT (parent == leaf.getParent());
                                    +          ASSERT (parent == path.getLeaf());
                                    +          
                                    +          Scope root = path.goRoot();
                                    +          ASSERT (path != refPath);
                                    +          ASSERT (path.endsAt (root));
                                    +          ASSERT (refPath.contains (path));
                                    +          ASSERT (!path.endsAt (parent));
                                    +          ASSERT (!path.endsAt (leaf));
                                    +          
                                    +          path.navigate (parent);
                                    +          ASSERT (path.endsAt (parent));
                                    +          ASSERT (!path.endsAt (root));
                                    +          ASSERT (!path.endsAt (leaf));
                                    +          
                                    +          PMO newNode (*new DummyMO);
                                    +          index->insert (newNode, parent); // place as sibling of "leaf"
                                    +          path.navigate (newNode);
                                    +          Scope sibling = path.getLeaf();
                                    +          ASSERT (parent == sibling.getParent());
                                    +          ASSERT (path.endsAt (sibling));
                                    +          ASSERT (path.contains (parent));
                                    +          ASSERT (path.contains (root));
                                    +          ASSERT (!refPath.contains (path));
                                    +          ASSERT (!path.contains (refPath));
                                    +          ASSERT (!disjoint (path,refPath));
                                    +          ASSERT (!disjoint (refPath,path));
                                    +          
                                    +          Path prefix = commonPrefix (path,refPath);
                                    +          ASSERT (prefix == commonPrefix (refPath,path));
                                    +          ASSERT (prefix.endsAt (parent));
                                    +          ASSERT (!prefix.contains (leaf));
                                    +          ASSERT (!prefix.contains (sibling));
                                    +          path.navigate (prefix.getLeaf());
                                    +          ASSERT (path == prefix);
                                    +          
                                    +          // now explore a completely separate branch....
                                    +          PMO& separatePlacement = *index->query (
                                    +                                     *index->query (
                                    +                                       *index->query (root)));
                                    +          path.navigate (separatePlacement);
                                    +          ASSERT (path);
                                    +          ASSERT (disjoint (path,refPath));
                                    +          ASSERT (path.contains(separatePlacement));
                                    +          Scope other = path.getLeaf();
                                    +          ASSERT (other.getTop() == separatePlacement);
                                    +          ScopePath rootPrefix = commonPrefix (path,refPath);
                                    +          ASSERT (rootPrefix.endsAt (root));
                                             }
                                               
                                         };
                                    diff --git a/tests/components/proc/mobject/session/test-scopes.cpp b/tests/components/proc/mobject/session/test-scopes.cpp
                                    index b1cab5cf2..2c46354fe 100644
                                    --- a/tests/components/proc/mobject/session/test-scopes.cpp
                                    +++ b/tests/components/proc/mobject/session/test-scopes.cpp
                                    @@ -67,8 +67,8 @@ namespace test    {
                                         PDum p5(*new TestSubMO21);
                                         
                                         PDum ps1(*new DummyMO);
                                    -    PDum ps2(*new TestSubMO1);
                                         PDum ps2(*new TestSubMO2);
                                    +    PDum ps3(*new TestSubMO1);
                                         
                                         // Prepare an (test)Index backing the PlacementRefs
                                         PPIdx index (PlacementIndex::create().get(), &remove_testIndex); // taking ownership
                                    @@ -83,7 +83,7 @@ namespace test    {
                                         
                                         index->insert (ps1,root);
                                         index->insert (ps2,root);
                                    -    index->insert (ps3,root);
                                    +    index->insert (ps3, ps2);
                                         
                                         return index;
                                       }
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 9c5e6f979..94f29b7bd 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -767,6 +767,22 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS
                                     On the implementation side, we use a special kind of MObject, acting as an anchor and providing an unique identity. Like any ~MObject, actually a placement establishes the connection and the scope, and typically constitutes a nested scope (e.g. the scope of all objects //within// the sequence to be bound into a timeline)
                                     
                                    +
                                    +
                                    There is some flexibility in the HighLevelModel, allowing to attach the same [[Sequence|EDL]] onto multiple [[timelines|Timeline]] or even into a [[meta-clip|VirtualClip]]. Thus, while there is always an containment relation which can be used to define the current PlacementScope, we can't always establish an unique path from any given location up to the model root. In the most general case, we have to deal with a DAG, not a tree.
                                    +
                                    +!solution idea
                                    +Transform the DAG into a tree by //focussing//&nbsp; on the current situation and context. Have a state containing the //current path.//  &rarr; QueryFocus
                                    +
                                    +!!detail decisions
                                    +!!!!how to represent scoping
                                    +We us a 2-layer approach: initially, containment is implemented through a registration in the PlacementIndex. Building on that, scope is layered on top as an abstraction, which uses the registered containment relation, but takes the current access path into account at the  critical points (where a [[binding|BindingMO]] comes into play)
                                    +
                                    +!!!!the basic containment tree
                                    +each Placement (with the exception of the root) gets registered as contained in yet another Placement. This registration is entirely a tree, and thus differs from the real scope nesting at the Sequence level: The scopes constituting Sequences and Timelines are registered as siblings, immediately below the root. This has some consequences
                                    +# Sequences as well as Timelines can be discovered as contents of the model root
                                    +# ScopePath digresses at Sequence level from the basic containment tree
                                    +
                                    +
                                    All decisions on //how // the RenderProcess has to be carried out are concentrated in this rather complicated Builder Subsystem. The benefit of this approach is, besides decoupling of subsystems, to keep the actual performance-intensive video processing code as simple and transparent as possible. The price, in terms of increased complexity &mdash; to pay in the Builder &mdash; can be handled by making the Build Process generic to a large degree. Using a Design By Contract approach we can decompose the various decisions into small decision modules without having to trace the actual workings of the Build Process as a whole.
                                     
                                    @@ -3052,7 +3068,7 @@ Placement references mimic the behaviour of a real placement, i.e. they proxy th
                                     {{red{WIP}}}
                                     
                                    -
                                    +
                                    MObjects are attached into the [[Session]] by adding a [[Placement]]. Because this especially includes the case of //grouping or container objects,// e.g. tracks or [[meta-clips|VirtualClip]], any placement may optionally define and root a scope, and every placement is at least contained in one encompassing scope &mdash; of course with the exception of the absolute top level, which can be thought off as being contained in a scope of handling rules.
                                     
                                     Thus, while the [[sequences (former called EDL)|EDL]] act as generic container holding a pile of placments, actually there is a more fine grained structure based on the nesting of the tracks, which especially in Lumiera's HighLevelModel belong to the sequence (they aren't a property of the top level timeline as one might expect). Building upon these observations, we actually require each addition of a placement to specify a scope. Consequently, for each Placement at hand it is possible to determine an //containing scope,// which in turn is associated with some Placement of a top-level ~MObject for this scope. The latter is called the ''scope top''. An example would be the {{{Placement<Track>}}} acting as scope of all the clips placed onto this track. The //implementation//&nbsp; of this tie-to-scope is provided by the same mechanism as utilised for relative placements, i.e. an directional placement relation. Actually, this relation is implemented by the PlacementIndex within the current [[Session]].
                                    @@ -3067,6 +3083,7 @@ There is only a limited number of situations constituting a scope
                                     * tracks may contain nested sub tracks.
                                     * clips and (track-level) effects likewise are associated with an enclosing track.
                                     * an important special case of relative placement is when an object is [[attached|AttachedPlacementProblem]] to another leading object, like e.g. an effect modifying a clip
                                    +__note__: attaching a Sequence in multiple ways &rarr; [[causes scoping problems|BindingScopeProblem]]
                                     
                                     !Purpose of Placement scoping
                                     Similar to the common mechanisms of object visibility in programming languages, placement scopes guide the search for and resolution of properties of placement. Any such property //not defined locally// within the placement is queried ascending through the sequence of nested scopes. Thus, global definitions can be shadowed by local ones.
                                    @@ -3882,7 +3899,7 @@ It will contain a global video and audio out pipe, just one EDL with a single tr
                                     &rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
                                     
                                    -
                                    +
                                    The frontside interface of the session allows to query for contained objects; it is used to discover the structure and contents of the currently opened session/project. Access point is the public API of the Session class, which, besides exposing those queries, also provides functionality for adding and removing session contents.
                                     
                                     !discovering structure
                                    @@ -3894,7 +3911,7 @@ So, clearly, there are two flavours of such an contents exploration query: it co
                                     The (planned) session structure of Lumiera allows for quite some flexibility, which, of course comes at a price tag. Especially, as there can be multiple independent top level timelines, where a given sequence can be used simultaneously within multiple timelines and even as virtual media within a [[meta-clip|VirtualClip]], and moreover, as properties of any Placement are rather queried and discovered within the PlacementScope of this object &mdash; consequently the discovered values may depend on //how you look at this object.// More specifically, it depends on the ''access path'' used to discover this object, because this path constitutes the actual scope visible to this object.
                                     
                                     To give an example, let's assume a clip within a sequence, and this sequence is both linked to the top-level timeline, but also used within a meta-clip. (see the drawing &rarr; [[here|PlacementScope]])
                                    -In this case, the sequence has an 1:n [[binding|BindingMO]]. A binding is (by definition) also a PlacementScope, and, incidentally, in the case of binding the sequence into a timeline, the binding also translates //logical// output designations into global pipes found within the timeline, while otherwise they get mapped onto "channels" of the virtual media used by the virtual clip. Thus, the absolute time position as well as the output connection of a given clip within this sequence //depends on how we look at this clip.// Does this clip apear as part of the global timeline, or did we discover it as contained within the meta-clip?
                                    +In this case, the sequence has an 1:n [[binding|BindingMO]]. A binding is (by definition) also a PlacementScope, and, incidentally, in the case of binding the sequence into a timeline, the binding also translates //logical// output designations into global pipes found within the timeline, while otherwise they get mapped onto "channels" of the virtual media used by the virtual clip. Thus, the absolute time position as well as the output connection of a given clip within this sequence //depends on how we look at this clip.// Does this clip apear as part of the global timeline, or did we discover it as contained within the meta-clip? &rarr; see [[discussion of this scope-binding problem|BindingScopeProblem]]
                                     
                                     !!solution requirements
                                     The baseline of any solution to this problem is clear: at the point where the query is issued, a context information is necessary; this context yields an access path from top level down to the object to be queried, and this access path constitutes the effective scope this object can utilise for resolving the query.
                                    
                                    From f01da499554db4c57d4a4b910fffc8b46be81e0c Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Tue, 20 Oct 2009 04:31:50 +0200
                                    Subject: [PATCH 016/377] WIP planning the operations needed on QueryFocus
                                    
                                    ---
                                     src/proc/mobject/session/query-focus.cpp | 35 ++++++++++++++++++++++++
                                     src/proc/mobject/session/query-focus.hpp | 17 ++++++++++++
                                     wiki/renderengine.html                   | 20 ++++++++++++--
                                     3 files changed, 69 insertions(+), 3 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/query-focus.cpp b/src/proc/mobject/session/query-focus.cpp
                                    index 5169d46ab..424c137c6 100644
                                    --- a/src/proc/mobject/session/query-focus.cpp
                                    +++ b/src/proc/mobject/session/query-focus.cpp
                                    @@ -37,8 +37,43 @@ namespace session {
                                       { }
                                       
                                       
                                    +  /** attach this QueryFocus to a container-like scope,
                                    +      causing it to \em navigate, changing the
                                    +      current ScopePath as a side-effect 
                                    +  */
                                    +  QueryFocus&
                                    +  QueryFocus::attach (Scope const& container)
                                    +  {
                                    +    UNIMPLEMENTED ("navigate this focus to attach to the given container scop");
                                    +    return *this;
                                    +  }
                                       
                                       
                                    +  /** push the "current QueryFocus" aside and open a new focus frame.
                                    +      This new QueryFocus will act as "current" until going out of scope
                                    +   */
                                    +  QueryFocus
                                    +  QueryFocus::push (Scope const& otherContainer)
                                    +  {
                                    +    UNIMPLEMENTED ("push current, open a new QueryFocus frame");
                                    +    QueryFocus newFocus; // = do push and open new frame
                                    +    newFocus.attach (otherContainer);
                                    +    return newFocus;
                                    +  }
                                    +  
                                    +  
                                    +  /** cease to use \em this specific reference to the current frame.
                                    +      This operation immediately tries to re-access what is "current"
                                    +      and returns a new handle. But when the previously released reference
                                    +      was the last one, releasing it will cause the QueryFocusStack to pop,
                                    +      in which case we'll re-attach to the now uncovered previous stack top.
                                    +  */
                                    +  QueryFocus
                                    +  QueryFocus::pop()
                                    +  {
                                    +    
                                    +  }
                                    +  
                                       
                                       
                                     }} // namespace mobject::session
                                    diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp
                                    index 9d2cd9b61..2649cf53b 100644
                                    --- a/src/proc/mobject/session/query-focus.hpp
                                    +++ b/src/proc/mobject/session/query-focus.hpp
                                    @@ -49,8 +49,25 @@ namespace session {
                                         public:
                                           QueryFocus();
                                           
                                    +      QueryFocus& attach (Scope const&);
                                    +      static QueryFocus push (Scope const&);
                                    +      QueryFocus pop();
                                    +      
                                    +      operator Scope()        const { return scopes_.getLeaf(); }      
                                    +      ScopePath currentPath() const { return scopes_; }
                                    +      
                                    +      template
                                    +      void query(); ////////////////////////////////////////////////////////////////TODO obviously needs to return an Iterator
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                    +
                                    +  
                                    +  template
                                    +  void
                                    +  QueryFocus::query()
                                    +  {
                                    +    UNIMPLEMENTED ("how the hell do we issue typed queries?????");
                                    +  }
                                       
                                       
                                     }} // namespace mobject::session
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 94f29b7bd..1d3b91584 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3416,15 +3416,16 @@ In the course of shaping the session API, __joel__ and __ichthyo__ realised that
                                     See also the notes on &rarr; QueryImplProlog
                                     
                                    -
                                    +
                                    When querying contents of the session or sub-containers within the session, the QueryFocus follows the current point-of-query. As such queries can be issued to explore the content of container-like objects holding other MObjects, the focus is always attached to a container, which also acts as [[scope|PlacementScope]] for the contained objects. QueryFocus is an implicit state (the current point of interrest). This sate especially remembers the path down from the root of the HighLevelModel, which was used to access the current scope. Because this path constitutes a hierarchy of scopes, it can be relevant for querying and resolving placement properties. (&rarr; SessionStructureQuery)
                                     
                                     !provided operations
                                     * attach to a given scope-like object. Causes the current focus to //navigate//
                                    -* open a new focus, thereby pushing the existing focus onto a ''focus stack''
                                    +* open a new focus, thereby pushing the existing focus onto a [[focus stack|QueryFocusStack]]
                                     * return (pop) to the previous focus
                                    -* get the current scope, which is implemented as Placement
                                    +* get the current scope, represented by the "top" Placement of this scope
                                     * get the current ScopePath from root (session globals) down to the current scope
                                    +* (typed) content discovery query on the current scope
                                     [>img[Scope Locating|uml/fig136325.png]]
                                     !!!relation to Scope
                                     There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current scope.// But QueryFocus is more of a //binding// &mdash; it links or focusses the current state and into a specific scope with a ScopePath depending on the current state. Thus, while Scope is just a passive container allowing to locate and navigate, QueryFocus by virtue of this binding allows to [[Query]] at this current location.
                                    @@ -3438,6 +3439,19 @@ The stack of scopes must not be confused with the ScopePath. Each single frame o
                                     The full implementation of this scope navigation is tricky, especially when it comes to determining the relation of two positions. It should be ''postponed'' and replaced by a ''dummy'' (no-op) implementation for the first integration round.
                                     
                                    +
                                    +
                                    What is the ''current'' QueryFocus? There is a state-dependent part involved, inasmuch the effective ScopePath depends on how the invoking client has navigated the //current location// down into the HighLevelModel structures. Especially, when a VirtualClip is involved, there can be discrepancies between the paths resulting when descending down through different paths. (See &rarr; BindingScopeProblem).
                                    +
                                    +Thus, doing something with the current location, and especially descending or querying adjacent scopes can modify this current path state. Thus we need a means of invoking a query in a way not interfering with the current path state, otherwise we wouldn't be able to provide side-effect free specific query operations.
                                    +
                                    +!maintaining the current QueryFocus
                                    +As long as client code is just interested to use the current query location, we can provide a handle referring to it. But when a query needs to be run without side effect on the current location, we //push//&nbsp; it aside and start using a new QueryFocus on top, which starts out as a clone copy of the current QueryFocus. Client code again gets a handle (smart-ptr) to this location, and additionally may access the new "current location". When all references are out of scope and gone, we'll drop back to the focus put aside previously.
                                    +
                                    +!concurrency
                                    +This concept deliberately ignores parallelism. But, as the current path state is already encapsulated (and ref-counting is in place), the only central access point is to reach the current scope. Instead of using a plain-flat singleton here, this access can easily be routed through thread local storage.
                                    +{{red{As of 10/09 it is not clear if there will be any concurrent access to this discovery API}}} &mdash; but it seems not unlikely to happen...
                                    +
                                    +
                                    //obviously, getting this one to work requires quite a lot of technical details to be planned and implemented.// This said...
                                     The intention is to get much more readable ("declarative") and changeable configuration as by programming the decision logic literately within the implementation of some object.
                                    
                                    From 452e1bb727d3f9d0ab7e01ad02276bccd5f9f487 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Tue, 20 Oct 2009 05:34:58 +0200
                                    Subject: [PATCH 017/377] WIP draft an unit test detailing QueryFocus operation
                                    
                                    ---
                                     src/proc/mobject/session/query-focus.cpp      |  10 ++
                                     src/proc/mobject/session/query-focus.hpp      |   8 +-
                                     .../proc/mobject/query-focus-test.cpp         | 103 ++++++++++++++++--
                                     .../proc/mobject/scope-path-test.cpp          |  14 +++
                                     4 files changed, 123 insertions(+), 12 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/query-focus.cpp b/src/proc/mobject/session/query-focus.cpp
                                    index 424c137c6..5bbbf9a73 100644
                                    --- a/src/proc/mobject/session/query-focus.cpp
                                    +++ b/src/proc/mobject/session/query-focus.cpp
                                    @@ -37,6 +37,16 @@ namespace session {
                                       { }
                                       
                                       
                                    +  /** discard any state and clear
                                    +      the current focus path */
                                    +  QueryFocus&
                                    +  QueryFocus::reset ()
                                    +  {
                                    +    scopes_.clear();
                                    +    return *this;
                                    +  }
                                    +  
                                    +  
                                       /** attach this QueryFocus to a container-like scope,
                                           causing it to \em navigate, changing the
                                           current ScopePath as a side-effect 
                                    diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp
                                    index 2649cf53b..fa8d6343e 100644
                                    --- a/src/proc/mobject/session/query-focus.hpp
                                    +++ b/src/proc/mobject/session/query-focus.hpp
                                    @@ -45,10 +45,12 @@ namespace session {
                                       class QueryFocus
                                         {
                                           ScopePath scopes_;
                                    +      /////////////////////////////////////////////////////////////////////////////////////TODO how to integrate the ref-counting handle?
                                           
                                         public:
                                           QueryFocus();
                                           
                                    +      QueryFocus& reset ();
                                           QueryFocus& attach (Scope const&);
                                           static QueryFocus push (Scope const&);
                                           QueryFocus pop();
                                    @@ -57,16 +59,16 @@ namespace session {
                                           ScopePath currentPath() const { return scopes_; }
                                           
                                           template
                                    -      void query(); ////////////////////////////////////////////////////////////////TODO obviously needs to return an Iterator
                                    +      void query()  const; ////////////////////////////////////////////////////////////////TODO obviously needs to return an Iterator
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                     
                                       
                                       template
                                       void
                                    -  QueryFocus::query()
                                    +  QueryFocus::query()  const
                                       {
                                    -    UNIMPLEMENTED ("how the hell do we issue typed queries?????");
                                    +    UNIMPLEMENTED ("how the hell do we issue typed queries?????");  ///////////////////////TICKET #352
                                       }
                                       
                                       
                                    diff --git a/tests/components/proc/mobject/query-focus-test.cpp b/tests/components/proc/mobject/query-focus-test.cpp
                                    index f3253af4b..d1e621c2d 100644
                                    --- a/tests/components/proc/mobject/query-focus-test.cpp
                                    +++ b/tests/components/proc/mobject/query-focus-test.cpp
                                    @@ -26,22 +26,24 @@
                                     //#include "proc/mobject/placement-ref.hpp"
                                     #include "proc/mobject/session/test-scopes.hpp"
                                     #include "proc/mobject/placement-index.hpp"
                                    +#include "proc/mobject/session/query-focus.hpp"
                                    +#include "proc/mobject/session/scope.hpp"
                                     //#include "lib/util.hpp"
                                     
                                    -//#include 
                                    -//#include 
                                    +#include 
                                    +#include 
                                     
                                    -//using util::isSameObject;
                                    -//using lumiera::Time;
                                    -//using std::string;
                                    -//using std::cout;
                                    -//using std::endl;
                                     
                                     
                                     namespace mobject {
                                     namespace session {
                                     namespace test    {
                                       
                                    +  //using util::isSameObject;
                                    +  //using lumiera::Time;
                                    +  using std::string;
                                    +  using std::cout;
                                    +  using std::endl;
                                       
                                       
                                       /**********************************************************************************
                                    @@ -62,11 +64,94 @@ namespace test    {
                                               
                                               // Prepare an (test)Index backing the PlacementRefs
                                               PPIdx index = build_testScopes();
                                    -//          PMO& root = index->getRoot();
                                    +          PMO& root = index->getRoot();
                                               
                                               UNIMPLEMENTED ("unit test to cover query focus management");
                                               
                                    -//??      ASSERT (0 == index->size());
                                    +          QueryFocus theFocus;
                                    +          theFocus.reset();
                                    +          ASSERT (Scope(root) == Scope(theFocus));
                                    +          
                                    +          checkNavigation (theFocus);
                                    +          
                                    +          Scope scopePosition = Scope(theFocus);
                                    +          manipulate_subFocus();
                                    +          
                                    +          QueryFocus currentFocus;
                                    +          ASSERT (scopePosition == Scope(currentFocus));
                                    +          ASSERT (currentFocus == theFocus);
                                    +        }
                                    +      
                                    +      
                                    +      /** @test move the current focus to various locations
                                    +       *        and discover contents there. */
                                    +      void
                                    +      checkNavigation (QueryFocus& focus)
                                    +        {
                                    +          focus.reset();
                                    +          ASSERT (Scope(focus).isRoot());
                                    +          
                                    +          PMO& someObj = focus.query();
                                    +                         // by construction of the test fixture,
                                    +                         // we know this object is root -> ps2 -> ps3
                                    +          
                                    +          ASSERT (Scope(focus).isRoot());
                                    +          focus.attach (someObj);
                                    +          ASSERT (!Scope(focus).isRoot());
                                    +          ScopePath path = focus.currentPath();
                                    +          ASSERT (someObj == path.getLeaf());
                                    +          ASSERT (path.getParent().getParent().isRoot());
                                    +          
                                    +          focus.attach (path.getParent());
                                    +          ASSERT (Scope(focus) == path.getParent());
                                    +          ASSERT (someObj != Scope(focus));
                                    +          ASSERT (path.contains (focus.currentPath()));
                                    +          ASSERT (focus.currentPath().getParent().isRoot());
                                    +        }
                                    +      
                                    +      
                                    +      /** @test side-effect free manipulation of a sub-focus */
                                    +      void
                                    +      manipulate_subFocus()
                                    +        {
                                    +          QueryFocus original;
                                    +          uint num_refs = original.ref_count();
                                    +          ASSERT (num_refs > 1);
                                    +          
                                    +          QueryFocus subF = QueryFocus::push();
                                    +          cout << string(subF) << endl;
                                    +          ASSERT (subF == original);
                                    +          
                                    +          ASSERT (       1 == subF.ref_count());
                                    +          ASSERT (num_refs == original.ref_count());
                                    +          
                                    +          {
                                    +            QueryFocus subF2 = QueryFocus::push(Scope(subF).getParent());
                                    +            ASSERT (subF2 != subF);
                                    +            ASSERT (subF == original);
                                    +            cout << string(subF2) << endl;
                                    +            
                                    +            Iterator ii = subF2.query();
                                    +            while (ii)
                                    +              {
                                    +                subF2.attach(*ii);
                                    +                cout << string(subF2) << endl;
                                    +                ii = subF2.query();
                                    +              }
                                    +            cout << string(subF2) << "<<<--discovery exhausted" << endl;
                                    +            
                                    +            subF2.pop();
                                    +            cout << string(subF2) << "<<<--after pop()" << endl;
                                    +            ASSERT (subF2 == subF);
                                    +            ASSERT (2 == subF2.ref_count());
                                    +            ASSERT (2 == subF.ref_count());
                                    +          }
                                    +          // subF2 went out of scope, but no auto-pop happens
                                    +          cout << string(subF) << endl;
                                    +          
                                    +          ASSERT (       1 == subF.ref_count());
                                    +          ASSERT (num_refs == original.ref_count());
                                    +         // when subF goes out of scope now, auto-pop will happen...
                                             }
                                               
                                         };
                                    diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp
                                    index 344e0f215..343104089 100644
                                    --- a/tests/components/proc/mobject/scope-path-test.cpp
                                    +++ b/tests/components/proc/mobject/scope-path-test.cpp
                                    @@ -72,6 +72,7 @@ namespace test    {
                                               invalildPath (testPath,startPlacement);
                                               check_Identity_and_Copy (startPlacement);
                                               navigate (testPath, index);
                                    +          clear (testPath, index);
                                             }
                                           
                                           
                                    @@ -268,6 +269,19 @@ namespace test    {
                                               ScopePath rootPrefix = commonPrefix (path,refPath);
                                               ASSERT (rootPrefix.endsAt (root));
                                             }
                                    +      
                                    +      
                                    +      void
                                    +      clear (ScopePath& testPath, PPIdx index)
                                    +        {
                                    +          ASSERT (path);
                                    +          PMO rootNode = index->getRoot();
                                    +          ASSERT (path.getLeaf() != rootNode);
                                    +          
                                    +          path.clear();
                                    +          ASSERT (path);
                                    +          ASSERT (path.getLeaf() == rootNode);
                                    +        }
                                               
                                         };
                                       
                                    
                                    From 007a6e1855a6fcbe778f0ba8bf44b40334400ee2 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Wed, 21 Oct 2009 05:35:32 +0200
                                    Subject: [PATCH 018/377] Consideration how to issue content discovery queries
                                    
                                    ---
                                     doc/devel/uml/fig137733.png | Bin 0 -> 11049 bytes
                                     uml/lumiera/131077          | 169 +++++++++++++++++++++++++++++++++++-
                                     uml/lumiera/132357          |  23 +----
                                     uml/lumiera/137733.diagram  |  50 +++++++++++
                                     uml/lumiera/5.session       |  12 +--
                                     uml/lumiera/lumiera.prj     |   2 +-
                                     wiki/renderengine.html      |  14 ++-
                                     7 files changed, 240 insertions(+), 30 deletions(-)
                                     create mode 100644 doc/devel/uml/fig137733.png
                                     create mode 100644 uml/lumiera/137733.diagram
                                    
                                    diff --git a/doc/devel/uml/fig137733.png b/doc/devel/uml/fig137733.png
                                    new file mode 100644
                                    index 0000000000000000000000000000000000000000..5fcfafd28c5154ac7f6629b691045243613ce25b
                                    GIT binary patch
                                    literal 11049
                                    zcmdUVbyQW|*8WCbr9%)9DG><;1VN<3gQ9|za_E+j?v8_c=FF3m0U^l--nFOaQC9orichmE
                                    zI1^n2X@nec6XVZ1^ou84HWxV)qh;mbBoNfn@@)_gf|AM!Eg{I@`u~}NccdK64Svr@
                                    zdzE3>1BEI!y`qVZq+AO?Z4}rLXG+RCn@s#x`}k(|Z_o?hAaqbni`PDQDkf%#W3|{-
                                    zWFi3>B{O1#byo$LH8vPCoq407O~><9#ROZVu8jTmgBp`J$@%>7t-kmCo3sb4XWlBs
                                    zlsxwAgPmEXT#v9tTEV|dW4Xt<3sRYKdYvmE%xqVv|
                                    zGdS3So@?)QAoVA;@>gr4HZxnZ`bBBXKAXGCiI}t=xY6;!7W1=#+>TCx>*Gf@W}A8a
                                    zUmCG#U%&3MS=n9bm#!Hs+4M6SGF6t(x0pR&A49M(F+JjL&Hv4f9)^DySfJ0DCZ%><
                                    zhjX1k_*Aq13!XU3Lkh08&D!^=%<{%0Fyl!94b15UdG5P9-$Ll$;8QBzB0CtAU}Jrh
                                    zGhSkbVZy~-QclLE*W6fT^HX!}{EX)Lb4G01CjXP$_g7MB5T|$9bB6+j&$X3a9&BU<
                                    z(g=@b41Et28V!nd%4i^hB5p`scUP0WF|WSZ%Bmce>$o>$G*ms1t+wM7j!Ao?Q2~B%
                                    z&&Nz_+Ri8W9U`V(@{9V>(bdtIfB^iXBc~!yZ0vnLzWwim_?PhS25(?R381VQ20AuJpfA-xW#^K-3<3TaZotcX%Yc1V
                                    zjj3Wm$J2rC?&fdbK8fLxwTsKaUDk`1ZgCxd&pH_op^rrpHV32@nO)?!e$Q~&k<~!B
                                    zl)f`cM7RdzY~G-4Ak$d0wOomgcgfn7S6YStX6+yJ@l0I0d*%CA_oMEvc$EZUL|FqD
                                    z9o>+QzJ`RfhOo|ygW6h$1^$?Yg~?l-UpB#3g@#J&=$;kZtiGSD8XL;F@Y+v*EWbSc
                                    z(E0T6JUhFHmATCRq0>k{>*}C;b7Lo;^I;gF_S*1)N{Q=CgZBX4^L>2WIJ?CzH7kk_
                                    zACAv|)_cdrQSjSRZj6<@t#Y&xH-p<$YP(Idt74tZPj3x_^Qlr|8WQiazFwkGUNL0U
                                    zQ(Lrzy?|~YeBrz>ocD;kiofMF-)1A-EmmQ7aaQM^
                                    z*&3Qi28((n1@r2R4YjhgEaDOrSmEd4xqG)m(DE)9{d^{vxUdkH78ybR;K3K!l+)y7
                                    zp&Hk-12?zqg=0a%iJ}V>Dke14NU62Rh}&$uw8+kEx7Y-uzFt90>{`jY>8;-96nb5h
                                    z!9lqtw(B*I-u-Z#hDFH778DpXcuj6r7CdHSL-Ztd9hi_n-^}UPMjE_7E_ULm=V_1i
                                    ze6li~s^&C~GPB&qqJ28s6u7rJWiXsu#&1VGFzDxlEekKws@MATNusjymeOQ9E6=bn
                                    z=g!KHZxeh*dCHF(R`H_^2gA$NNkNvPkYQ(95;V}78eyF0Bd_O~Ps9tI3K`A~+y
                                    zwA4m!L%G0@T5gksmLj^*ucRbnALrUILt$>y;*eV*CNC&%W+Nx29h=?GZqI4jiSxRP
                                    z$j|Yuk=BR*PsZN@8*L4LXBq9}Nz1nl^8`vw;eXiGU&i(SE8bvg+C@nd3=_cc_n*Px
                                    zJC-^+pYc?#)MEeLPvRb*BYIN#J!~4jTF0eUw80emxMZecQ%p@ZOx{}Y4i_Fv{M=hG
                                    z{9F(1l(0EUO)4a%%(}P${_`$0d65>hfsC+dhB-=^iKwNkaw!~oH)%wZVhAnW;9#wq
                                    zlDG<2pwG`*(4fzaEm)9<^6nf2_1*cS$e3y1sg3z1j9*2R8WvEIf|tViqp=nR+7yZZ
                                    zR-FaRXiy)(3xBIpMH0|v^yiRJpSCUizs&>MG$oOgp#4_?j1+(&34i@YQfk6MTc-El
                                    z!W+5VhThOixbjD1rq4*Y8`s~k>|q5Fbeq-jA27`g4%%`VVECZ@SE2XoD>vyTu44~V?+m%K>A!ot26n~Z_K`##C6yPH$Ow{MF$
                                    z$-&_W#6@XoX&-Z5iG#E+_m46)k;gIWyn^)KgVfd-ENGOVY>&0(>
                                    zTmlu283Ix0S{;eB%q?bBQUW*Gn_DY*O-6ZVJ@q8g_r+wL>F(SqoG-Il94%ypP=41%
                                    z1OC)GBGEUqDHtzjX!v6q2sCZ25dM8NkZ}TXaQ^_Q-Jdr%e)QDWzqJQI
                                    zLcKIm;c|8ysF<<`S$BICFq3D8d3rX#^~8@io+y85yI)i?rM|qOp7R8KD498`xgT+U
                                    z)RFhrz|>TF$e<*{>z3P?cvO5g
                                    zhHK%>LxO@7>yu{(z`ig@yQ*Vqaqwc%J~or;YHb}D-2Iup`Qt}W5c@$(@b|E=0#j3)
                                    z{yq*QAs8BlNk-P6F6$~Qo2XH9?j$0jFt$zz$pM3~9mQkuv(n)ka3m=Bth?67>^$&x
                                    zB&CFCk?+P2^Ulxs@hBbx(2_D5BP&abLOnL-VR>Zj9jQR~ym`j#Bf#Gs9T^`n>@wgP
                                    zUyAI|-PFk~Y*V*3Vl{>DBQoMM6s*+Lj3N(|+}+&)RH5K@wHPZtI6X^5)!LQ~;6w3A
                                    zjEn`?cjE|WI-+sy4#3=N9uyfja1~bKjx1FnH|*PU)>$EGgu~b)xFU>~_9)Ez
                                    zdXC!5zm(&phHPs9n}zk4Mc{E48H(~H5D_l5rAOUdY(*2%1z_xVW57gQ?+?emRJ;#i
                                    zUF<9b)>V6hX*gur+!rG#_|N733#R$9Mnk6KML+U(d@4S2(&9?-7;K2|Neg)s@Nrn=
                                    zIUKDM4-eHwx4*t2Q&W8?`|8;tr_zrE=qhe9X6xJ>K>Xq36n7+WUr7ji;F#A5du*2bax%*mAenefUOI{pehFlwiS!OGPF2nu(F2}plg?Zw%
                                    z4K2Z&U(ygqODQ&8@h4midZKx^l#7iktrmOH(D_^rCLUU8Whrx=AI^4tBp5uL4dgE}
                                    z94MSTheWvO=KMY@ah3#7F$(O;bP8W|sFa$2kiU83yWL!i-C#~)${DZCO0JO0r2VOd
                                    z0$YyQ6=xq}R9PUXFczS*k=H_Nj`&6un#0n31lE+2?
                                    zz(pWRRA1AxNp8ui_nj22d{;E?h40pN-BOIhFl_2Qx`aaJ@O>mEmQt=xYZy94L{nqc
                                    zUY`VxJK=28o-pEk`}@~C0EO)rq94a{cay>11v3D$MgzFHRD6{j`cg99(j}EjYTiEb
                                    zD*F_@_b#%0)CnMY-39_S1%Zbl@>vP&HLdtGLIWsxZt>dE(rwV0UcmV~pl1@oi(0qK
                                    zMvD>xsRhs03d{m1m-UaV+hYgLPP`9rD>){;x}0Sd+OINz4qs3xYD+06!Ol+hn#%e6Xi56WIN2;EPNUtWBZkoaiHf70MNdpxQkKJfjhcWr
                                    zUvQ}&&cp-m$a#MxEtbow!usCWL{-9(l25Y0p{74kqNzhcc~B6VwD6g7j{3Tf$*8J{
                                    zlIc^s9QIs?E+x~d2KH(*EKOm*!}F4}9D{M+fel6lt%LIG6II}WMPZlJ5}K=TAeK`F
                                    zofM3#y&v^U`%SvmO0lbY`!KirFNrUgk342vYC@aWZP)@HL3o}260}5KAD*s$u#!!_
                                    z#i%9gVJe_0jL9psufzfmX#nW5(~nY?HOLSLm1VE`dalt8+pBdKBJGcFkHhG#KVH*#H{h2S}#hv6_O0
                                    z3zz-RAK)m=&(B}IdUd2c8fxd#4@Iu8yGer)`5etF-x%*n#qTD8n_zVb(uyZf|u_vBD2QoNutqO2`%^2hojJW
                                    z70`~&XrU)9BcEQI{?rTI4{O0*|KxiuEHb;AzRfGBfGw4hySP3M{kC9NXaU_q>_k{~
                                    zfNMFAV;ApPr8p!GItDv+bPerA+U(88ogYy3P|&&RfUnI-=G71AvkZrNcwIY2xkPvM
                                    zQ0qEBPfUln@7#f@JeajnftK)yr6EW+dF<_6>g|8}TA=Mh^f2O2-1p1F5{YK7AWB!i
                                    zI9)7SOu)&JO$p3cP3q}M1t_P;#ur+;r6BM=_%{rM`SR=il>syLGD|@g<1)Z3eI!uN
                                    zvq^!L$OL(BiUG7m#gFfDel*5bJ#5wYnbzAoSXyvC{CBWN@(b*R$PcW+_pP~jlk&X#VkLtn;=$R<
                                    zfC8Dm?wQ^nSnzzUfa;mTAkpga-qasV%I-27i{j5z!sKT-ftSQ?jHAJ~4{Sz5=Mo>U
                                    zWj`CjxJ~Y8$sW=z6wB*+`hiR%P9a0yUqPMxk&|su>)db+B2BA)0iV2Y!t(4nwL?p9
                                    z?^ykksZ`qf=e#oIxV-NW~jYT&;=QjV5iG3l!%12waMlezG(yTHsQ&puzwWYOe
                                    zYuXb_cieG=+^MuLsm7ws>BkKSNjT*~mV#OVd~Nk^U!9*HGaiMIa?zeJu+_nIXKiD5
                                    zO+NYg=Zz!F=GwwnIrUhaX8ot<4QpMFYaH&|MuJ>m-4xHHnNa(^=}_g?VMGF&>|I+H49bVFrg;xAf*M&bRZ1JM@B!
                                    z#eU61v#0*;;o;U9fYi^$vRk{VBND1zTY@&;zu(#3!6_sb9m>K9^o_MS{CSVIVK{HI
                                    z#PqDen>gcnz#7#}o}8udpZ|$=^fAeHI(V$%{LpE25Pf+$Qp5GA9-m6!VBPmuekJW-#f7(#hnXSyz21D8gB$n?LbSEm_{L|B;_Qw3qKHxbZ30qqw
                                    zn*CQ3ua;z~5bSPDRJ)!%zrT}wxr?QD=;(^B>OF#(Qh=+2LOJdmFIaWE*Bnf?
                                    z|AW^|0nWn2_)5f9gA6UQ2GPuCLp`2Pe-vwm&!%?Eu#7kB8tqecbyxAW5qL)3XtBv?
                                    zeroe`8WZ-MH@i`?HLg?_`z0=bS$z#JN=lN!v{-o6^mAHJxyW&5uC+9Ob0O)88sL44
                                    z4EoPa#_;9O%Uwc{s)j4{Y&o~#6Oo}-Z}(Pm+IdhFhVa)fTIwP-s7tjQceM%b`D_Ay
                                    zwJ0<|LLr+qS)0cP3zN3c?5?!59UKlQ&;LMpf{2bGqlf93ExUlTu8vNwt@ct!G#wGq
                                    zK4?`h4N4tYSTnx$F!_LgGqbb3o#s(`!Tf@cRIt%#;S+0Xu-0y%W2zK(7^KySC@4m&
                                    zoL1o(wty5Tf;}?Wws$_=sI65`5v$@i=nDdiw4ZXRbmSTuDBAz0pEtB!E#CNo$Wm{f
                                    z&$`TZy~}ZL4dL^UBwX1t-`8sdRa}k{}1Yy;^^X+LESD(=X4TxR7IIszWU8_7^(Y8Bq6!ows
                                    zhJ8-cP%kzfJ=~%Jk&=@0vqWs%HTW^Z`1lH-v7M&fy{ep2K7KqCKDVFsx?W`jSk|V<
                                    zd37Cr27MuG1BVyI!#4J8sx6~6!t@U|vZfFhvtwomA{Zrq#KJP~@q3I@po29sI=6XH
                                    z@~yS+3#grQHH_C3=11>9a(-!PPQ8haAhguqKQU1?Ng&M9+C3EuuE{XF1}!p~3E-~T
                                    z{dF_M#aS#lr}_<8q0!Lka9%hFRQ31Gob0VCX5ObsWQ5yH=_huw6a)SHZtNH++2myP
                                    za)+JO_vrk9(+2Sd^E?JDTJ5)@o0Ah(8{=d+WYs9t$t~{esSJe*95SNqZCf)ClJjM5
                                    zmy99<>uYNC#d10jBO@g>G!QhDJNn`n@uE10lcu~-;BH2iW;MQ<^J#VjtKjkO7Wt!e
                                    zE9X;F+Na>;)tnb8S#H1HK~rp>O}`~9oS2>-IcfiP1Yo=f7hgzI#$@cV%T6cBg9om}
                                    zjIO)F7o2Co(>Ch@$X(;Md>fRhe7wGAL@`qZX8HyeOC{28;OGS5y>-Zfj1>LYRf`Kut3wqxRwB8Q8O|f-D9}
                                    zYH0~yv+wEZ;m%fV`RBq|ge^Y(!I
                                    zS?9i*Ch4R#+q7Ba$P$=hD4#hjuc)Y4uz-$tt5m%*N-cu*3e;AoV`&JEKYZYF(MLVH
                                    za&lfM6dnaW4xZW!;KF;iYWA%s%Hx5`A1zqa0D%LQBFE%6X{1|Q6@Zsp0YMXf8^;0X
                                    zgcMuKfhmNZmewc2JA!BV^5^R%&+FSZ#H28u0-b2K{VM3VyVRE|
                                    zF_f(aLiwiIj4UjfHmifg46m4UI8s`b3$PzM0vkLH`#l+ACMCAPLFI$s@W)
                                    zOD%wQ9K*rJ?!YTx>E$PZ);uPwcaemjK7Ben-a9$n>E0YKOFF{xS-QMptA$Z5&-2+!EG8=-BmK>%5O4SnDRXESB&qiE7!(eCgOZ2
                                    zakFx#i?dsRn3&iK3{NCsEj9Y!KBU+;Pzqv1tSZH-6}Bc7w(Er<&wNR<)T_$hdAI76
                                    zyPOoa>a_iGuw>x_Ivn$hi$;Nbe0+xOKFK#oNddjT{-bK}9uw1Wxs4GJW;~zGD~30(
                                    zUis}ChHbOZHcV95)tqj(M|0|%PLvmkdg9YZEJd;slR}vi!Wxb+FJ^`8%9D)>@R~-Y
                                    z{Z^6DkQ}^-Wov(bvdAbBg>u?o>%BEqXwd)tI|v@IX;hysrzOT1F_+7<@o@n%t*c8O
                                    zzPC0~pzAO=QlLL&KkM&$cATYBBDHFy9I+IwevUwQBU!pT=ku73jcwDHtr~D$3gY5E
                                    zx~;%3|DLT@(G}0{>EXf0%lj1-6BjrBNz@ax*e&%up=gz3g=L4?)YaF6K>Y0Hrm)HA
                                    zBd~`cB}4{3pw}6rR%ze6t<)aLMu3YeVEE3$&>df
                                    zDR1*aT3TAt5*$%xQ`J~lShBLRKqS6JF%I1fB+R|Mj4Iq9TM0=RF+IJsG@PSR^W(>l
                                    z!otFZ&e$BqJQ#swz9q%|)_q|^sMgSUGPJ+}eGLz=rEcLt=7ZomxN!xUKL*$2SJX+Q
                                    zD1}0w860#uHli*MaM07m?#7w?8R(KxTWT7i1eb5%1F|0-TniL6R@$XLk$Xra1(<^0
                                    z?_IjM^{h2ev2OQ8>z47r+whObep>MMFX9&kP4KvY`<0acf@k8ge*J<+5NLs4k-(&x
                                    zrKaV}2}qvSEz?}qPwL38fcn>MpBLlqVgj=;(GYcsT-F#wU5b}AGf|iMpR*r=0F1bU
                                    zmucKI&~N65yKzsz>dk5H##w;+Ck+Y}!J&;+PYWh~WIc=P50>e4XWB0S)FHvhdQL
                                    ze#P|G1f*CL&g!60V$T^J?Q!kQm!_v53h?m-li%5Q3qnrEr(g9t+HKOLGFCj&sxY)ML16VwvoqyBRh=I5a;aJ=5%aoe|^~E
                                    z1$^MchdSVM*$db%^|TIV#e!rMu(I%tjlEls%vtk75)ndHYl<0XAAn-B@Gd4~S
                                    z4V?uVV)ZYF#`WhnW_aOh`U4=4Djvt(T@alZu5z*fu0BYxIytP&*KL0fP+VZ(6xGdP
                                    zqwnc_q#h%1P0pJFzQYXt}
                                    z3dEipNm$pJl?_O8GIg(i4NWQI0schY#U`)jqNA=3M*Gz97;)_`qZFlpnfgy3k}(hb
                                    zc&n5Bc&&P8kimmV%fjsauSp-ge54l%xcK|s9hH3c<|QBy<_bFah@9+?2fpACCdm?7+*x(dWVX-udr-
                                    sAa_Fsg4|yHO9sK;xdi|1Y3~9p+--zn&E29Gq`*QipGiH
                                           end
                                         end
                                    +
                                    +    classdiagram 137733 "Query Interface"
                                    +      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 153989 "QueryResolver"
                                    +      visibility package stereotype "interface"
                                    +      cpp_decl "${comment}${template}class ${name}${inherit}
                                    +  {
                                    +${members}  };
                                    +${inlines}
                                    +"
                                    +      java_decl "${comment}${@}${visibility}interface ${name}${extends} {
                                    +${members}}
                                    +"
                                    +      php_decl "${comment}${visibility}interface ${name} {
                                    +${members}}
                                    +"
                                    +      python_2_2 python_decl ""
                                    +      idl_decl "${comment}${abstract}${local}interface ${name}${inherit} {
                                    +${members}};
                                    +"
                                    +      explicit_switch_type ""
                                    +      
                                    +    end
                                    +
                                    +    class 155141 "Query"
                                    +      visibility package 
                                    +      nformals 1
                                    +      formal name "TY" 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 ""
                                    +      
                                    +      class 155269 "Cursor"
                                    +	visibility package 
                                    +	nformals 1
                                    +	formal name "TY" 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 ""
                                    +	
                                    +      end
                                    +
                                    +      operation 140037 "isValid"
                                    +	public explicit_return_type "bool"
                                    +	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
                                    +
                                    +      operation 140165 "nextResult"
                                    +	public return_type class_ref 155269 // Cursor
                                    +	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 155397 "IterAdapter"
                                    +      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 ""
                                    +      
                                    +    end
                                    +
                                    +    class 155525 "ResolvingFacility"
                                    +      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 179717 // 
                                    +	relation 169733 -_-|>
                                    +	  a public
                                    +	    cpp default "${type}"
                                    +	    classrelation_ref 179717 // 
                                    +	  b parent class_ref 153989 // QueryResolver
                                    +      end
                                    +
                                    +      classrelation 179973 // 
                                    +	relation 169989 --->
                                    +	  stereotype "generate"
                                    +	  a role_name "" protected
                                    +	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
                                    +"
                                    +	    classrelation_ref 179973 // 
                                    +	  b parent class_ref 155653 // ActualQuery
                                    +      end
                                    +    end
                                    +
                                    +    class 155653 "ActualQuery"
                                    +      visibility package 
                                    +      nactuals 1
                                    +      actual class class_ref 155141 // Query
                                    +        rank 0 explicit_value ""
                                    +      cpp_decl "${comment}${template}class ${name}${inherit}
                                    +  {
                                    +${members}  };
                                    +${inlines}
                                    +"
                                    +      java_decl ""
                                    +      php_decl ""
                                    +      python_2_2 python_decl ""
                                    +      idl_decl ""
                                    +      explicit_switch_type ""
                                    +      
                                    +      classrelation 179845 // 
                                    +	relation 169861 ---|>
                                    +	  a public
                                    +	    cpp default "${type}"
                                    +	    classrelation_ref 179845 // 
                                    +	  b parent class_ref 155141 // Query
                                    +      end
                                    +    end
                                       end
                                     
                                       usecaseview 128389 "query use"
                                    diff --git a/uml/lumiera/132357 b/uml/lumiera/132357
                                    index fa75cd0cd..8faaadd1a 100644
                                    --- a/uml/lumiera/132357
                                    +++ b/uml/lumiera/132357
                                    @@ -1,6 +1,6 @@
                                     format 58
                                     "Placement" // ProcessingLayer::MObject::Placement
                                    -  revision 2
                                    +  revision 3
                                       modified_by 5 "hiv"
                                       // class settings
                                       //class diagram settings
                                    @@ -201,26 +201,5 @@ ${inlines}
                                     	  b parent class_ref 153989 // QueryResolver
                                           end
                                         end
                                    -
                                    -    class 153989 "QueryResolver"
                                    -      visibility package stereotype "interface"
                                    -      cpp_decl "${comment}${template}class ${name}${inherit}
                                    -  {
                                    -${members}  };
                                    -${inlines}
                                    -"
                                    -      java_decl "${comment}${@}${visibility}interface ${name}${extends} {
                                    -${members}}
                                    -"
                                    -      php_decl "${comment}${visibility}interface ${name} {
                                    -${members}}
                                    -"
                                    -      python_2_2 python_decl ""
                                    -      idl_decl "${comment}${abstract}${local}interface ${name}${inherit} {
                                    -${members}};
                                    -"
                                    -      explicit_switch_type ""
                                    -      
                                    -    end
                                       end
                                     end
                                    diff --git a/uml/lumiera/137733.diagram b/uml/lumiera/137733.diagram
                                    new file mode 100644
                                    index 000000000..f1e7265ed
                                    --- /dev/null
                                    +++ b/uml/lumiera/137733.diagram
                                    @@ -0,0 +1,50 @@
                                    +format 58
                                    +
                                    +classcanvas 128005 class_ref 153989 // QueryResolver
                                    +  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 251 37 2000
                                    +end
                                    +classcanvas 128133 class_ref 155141 // Query
                                    +  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 137 195 2000
                                    +end
                                    +classcanvas 128261 class_ref 155269 // Cursor
                                    +  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 225 271 2004
                                    +end
                                    +classcanvas 128517 class_ref 155397 // IterAdapter
                                    +  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 62 298 2000
                                    +end
                                    +classcanvas 128645 class_ref 155525 // ResolvingFacility
                                    +  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 480 293 2000
                                    +end
                                    +classcanvas 129157 class_ref 155653 // ActualQuery
                                    +  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 386 431 2000
                                    +end
                                    +line 128389 ---+
                                    +  from ref 128261 z 1999 to ref 128133
                                    +relationcanvas 128773 relation_ref 169733 // 
                                    +  geometry VHV
                                    +  from ref 128645 z 1999 to point 526 191
                                    +  line 128901 z 1999 to point 292 191
                                    +  line 129029 z 1999 to ref 128005
                                    +  no_role_a no_role_b
                                    +  no_multiplicity_a no_multiplicity_b
                                    +end
                                    +relationcanvas 129285 relation_ref 169861 // 
                                    +  geometry VHV
                                    +  from ref 129157 z 1999 to point 420 350
                                    +  line 129413 z 1999 to point 168 350
                                    +  line 129541 z 1999 to ref 128133
                                    +  no_role_a no_role_b
                                    +  no_multiplicity_a no_multiplicity_b
                                    +end
                                    +relationcanvas 129669 relation_ref 169989 // 
                                    +  from ref 128645 z 1999 stereotype "<>" xyz 469 379 3000 to ref 129157
                                    +  no_role_a no_role_b
                                    +  no_multiplicity_a no_multiplicity_b
                                    +end
                                    +end
                                    diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session
                                    index 02e012c28..761455ae6 100644
                                    --- a/uml/lumiera/5.session
                                    +++ b/uml/lumiera/5.session
                                    @@ -2,10 +2,12 @@ window_sizes 1302 1004 270 1022 856 71
                                     diagrams
                                       classdiagram_ref 134021 // Command structure
                                         575 622 100 4 0 0
                                    -  active  classdiagram_ref 136325 // Focus of Query
                                    +  classdiagram_ref 136325 // Focus of Query
                                         582 515 100 4 0 0
                                       classdiagram_ref 136581 // MObjectRef
                                         651 533 100 4 0 38
                                    +  active  classdiagram_ref 137733 // Query Interface
                                    +    688 570 100 4 0 0
                                     end
                                     show_stereotypes
                                     selected 
                                    @@ -17,16 +19,16 @@ open
                                       
                                       package_ref 128133 // Asset
                                       classview_ref 128389 // Controller Workings
                                    -  classview_ref 128005 // Session parts
                                       classview_ref 131973 // Object ref
                                       class_ref 152069 // PlacementIndex
                                       classview_ref 131845 // Scopes
                                    -  
                                    -  package_ref 128901 // Builder
                                    +  classview_ref 128261 // Builder Workings
                                       usecaseview_ref 128261 // config examples
                                    -  classview_ref 128133 // Engine Workings
                                    +  class_ref 133253 // Frame
                                       classview_ref 129541 // InterfaceSystem
                                       classview_ref 129285 // StreamType
                                    +  class_ref 153989 // QueryResolver
                                    +  class_ref 155141 // Query
                                       classview_ref 132229 // Custom holders
                                       classview_ref 128266 // SmartPointers
                                     end
                                    diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj
                                    index 890574f20..2293af356 100644
                                    --- a/uml/lumiera/lumiera.prj
                                    +++ b/uml/lumiera/lumiera.prj
                                    @@ -1,6 +1,6 @@
                                     format 58
                                     "lumiera"
                                    -  revision 55
                                    +  revision 56
                                       modified_by 5 "hiv"
                                       cpp_root_dir "../../src/"
                                     
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 1d3b91584..1135ba33c 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3400,7 +3400,7 @@ Viewed as a micro program, the processing patterns are ''weak typed'' &mdash
                                     
                                    a given Render Engine configuration is a list of Processors. Each Processor in turn contains a Graph of ProcNode.s to do the acutal data processing. In order to cary out any calculations, the Processor needs to be called with a StateProxy containing the state information for this RenderProcess
                                     
                                    -
                                    +
                                    {{red{WIP as of 10/09}}}...//brainstorming about the first ideas towards a query subsystem//
                                     
                                     !use case: discovering the contents of a container in the HighLevelModel
                                    @@ -3412,6 +3412,8 @@ In the course of shaping the session API, __joel__ and __ichthyo__ realised that
                                     * client code gets a result iterator, which can be explored //only once until exhaustion.//
                                     * the handed out result iterator is used to manage the allocation for the query result set by sideeffect (smart handle). &rarr; Ticket #353
                                     
                                    +For decoupling the query invocation from the facility actually processing the query, we need to come up with common pattern. In 10/09, there is an immediate demand for such a solution pattern for implementing the QueryFocus and PlacementScope framework, which is crucial for contents discovery in general on the session interface. &rarr; QueryResolver was shaped to deal with this situation, but has the potential to evolve into a general solution for issuing queries.
                                    +
                                     ----
                                     See also the notes on &rarr; QueryImplProlog
                                     
                                    @@ -3474,6 +3476,16 @@ Then, running the goal {{{:-resolve(T, stream(T,mpeg)).}}} would search a Track In the design of the Lumiera Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Pipe, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered "condiguration data" (including the actual plugin implementation to be loaded)
                                    +
                                    +
                                    Within the Lumiera Proc-Layer, there is a general preference for issuing [[queries|Query]] over hard wired configuration (or even mere table based configuration). This leads to the demand of exposing a //possibility to issue queries// &mdash; without actually disclosing much details of the facility implementing this service. For example, for shaping the general session interface (in 10/09), we need a means of exposing a hook to discover HighLevelModel contents, without disclosing how the model is actually organised internally (namely by using an PlacementIndex).
                                    +
                                    +!Analysis of the problem
                                    +The situation can be decomposed as follows.[>img[QueryResolver|uml/fig137733.png]]
                                    +* first off, we need a way to state //what kind of query we want to run.// This includes stipulations on the type of the result set contents expected
                                    +* as the requirement is to keep the facility actually implementing the query service hidden behind an interface, we're forced to erase specific type information and pass on an encapsulated version of the query
                                    +* providing an iterator for exploring the results poses the additional constraint of having an fairly generic iterator type, while still being able to communicate with the actual query implementation behind the interface.
                                    +
                                    +
                                    /***
                                     |''Name:''|RSSReaderPlugin|
                                    
                                    From 90e09b9fa074453c6b6f7788e45c0154c33df7e8 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Thu, 22 Oct 2009 17:24:57 +0200
                                    Subject: [PATCH 019/377] WIP trying to get ahed with the problem of issuing
                                     queries
                                    
                                    ---
                                     doc/devel/uml/fig137733.png                   | Bin 11049 -> 13015 bytes
                                     tests/43session.tests                         |   4 +
                                     .../mobject/session/query-resolver-test.cpp   |  93 +++++++++
                                     uml/lumiera/131077                            | 189 ++++++++++++------
                                     uml/lumiera/137733.diagram                    |  55 +++--
                                     uml/lumiera/5.session                         |   5 +-
                                     6 files changed, 259 insertions(+), 87 deletions(-)
                                     create mode 100644 tests/components/proc/mobject/session/query-resolver-test.cpp
                                    
                                    diff --git a/doc/devel/uml/fig137733.png b/doc/devel/uml/fig137733.png
                                    index 5fcfafd28c5154ac7f6629b691045243613ce25b..23b1a0f442ddbe1be289b6bd8be9495d52ab745d 100644
                                    GIT binary patch
                                    literal 13015
                                    zcmd6uWmwhg*6t?=N=cU@u;}h?orKZ?(hY(jEhUYT(jC%LN_VG}!UUwdySrg>9^7m1
                                    zwf26`b>8=!Plpe1UGtj%cw#)`9=~z(>7~N+hiH${AP~qy=@$~p5C|d>1cFe9f(Sn0
                                    z9ylt4K>mP8OFVn^K6z)xMF;<6sq3I0f^PKr5>FTx=Lk_UL->pEccBUld6jl_Nv>X>
                                    zSHkoNvRp6{;mfxlO*hA=uqv8n6RTsRvJ)1cnMHm164}kuES9s^8P7x5Fsza@ev?j
                                    zp9eu8!&H(G$YvxZ1ak8K!Pin#zL7wPW2vQctUsFnD6`z8ZQ+chEDQEtU;p?-lgZxhd|3*OH2s5h`XmT9pFask{%_X{VA_R&HvKWtXk
                                    zzSdTyV4`rLchrKc)|2}S_Q&YXJCn+qu#S$4$;#oH8uRDjolgWS%;49d(7+6Fu~Z(5
                                    z^HO73L_|R{p;P--naN5Er&U;X7^yfR>vT+Ns*)M10WR(uWozDxs8_=ml=f@Z8kL**
                                    zBl)=^x9)9UWPGusmYI4U(EQ}%JM*TN?pE=rRT$$C5_+yVI66uzJr^}~=UlV=%Lx6IZUVHpW!eDty!@ZyZXgJIzb$G*}codC*)=4<~A70v2i_16}6dNH|^adU}o4{
                                    zdHA@7nl87qQ-PG!2d~B?Uy{T=6tiSK^#-Pa}S3keY`{9G*0wL#J|5zrva59m(
                                    zS-rF4p_Q>>tYYnI(oOl|C_koqUkxjz95;IzMLGdaJJtP@`6i=
                                    z>tfS$aA-!kpWHT{PQDu9VN!jRrTSEJ{%uH!9tVeZ+jlj&l*j8Us%#V#49u2(K0emN
                                    z^j_j4Uh^%8nsL!l))?fXbTlh!JCh?As$2%5{DdD)v`P$?J|gcm+``kzM6{a0AD1I3
                                    zrn8Xl`YSf+rca-Knwy{9Ttjzugm}!bYi#DQE={1~@ej$aBh&QF>Ya@Ju!Wq-sw;Q)
                                    zr)eb*?AHi+d3nRaFp-%eOZ8tgvjgLt-O$c0x+$d%hUl2)3EB${yhyqj6(!iBlFz!B{L4pNIS7t+b|N<>;Px
                                    zFD8edKYol457(;~73_`V>ppG4xM9f}9OAlywqLC!4B4HmaHp#!sIeo3*;u){gLdUh9;bo`5%QI-5mP
                                    zAKR>aE3l&bR4n134XZg>)MKC{yZZ3>@?@&pCn4d$$*C%w{Eg~2WxJj@aUrKCH|I;$
                                    z$82I=o|Vi!;Lz~8IVlMjeXLZ1OGLD0x8xe&E3vlP-P$_ihb?yNPQz-QS6^>oX7*G<
                                    z!cwN2#ly5lEdLv$0r~X8E@lF1Xx%a4QQPAL~FdnjBnu=U>Fb4wQ(Lj8m=jw`tFxRtGL^2
                                    z*anx0P0ds7+1MOOlCe5Ht%KhPdF;1t!eHBEB6^oyY6zXr!U+q;g!Yb;IjGDo4oMr`
                                    z6mO6EyF4z>$wb}NP?V~zL#=1rFON~@8n1**erlF~G|?>5t?xfS2o@3E#BZp6{xV|j
                                    zWUJck)Ka_D=)&Dg*;*nYiHWEn>+MLcm6cUPgTH(ld?MtLxF2?DsY+jR?J_vUkNVFF
                                    z^vU&#l09bg?myggJ=yG?ZPaJgZ_<(0LMBEy6ZCatfa?WR+vExfs4`lm)YjIH70(rE
                                    zSI>o!l3!dj?n~@2kxXx4n*^i~&D$_iN}wF{urU-B*|@$R-k7fSYfVB*5a^Wjrc*7R
                                    z!lWenmr&
                                    z|3lJX1f1Vi5w5tnQM=PF^GieLr#r{xZ`eq(6rSQGWFqIUu8*7ijEd+Nom!bszgh|p
                                    zxVdu914r&`Zbk+|)N;PumNFSNEp7A7X#)&qDUCZYu+-SNg-&5))O37iL*=`FW`jq1
                                    zvvRnCCs(iQJrF@z;)F-XD&q1^Gn&@=(W7uew%MpX^VSs~pUgOxr1=d^K86jcX3xl6
                                    z1r{Rc_QcW5@73x};(IJ6IypWCxy$wz)h0a;$UQ1f;Wrp=ZuKAT)vvnc>C45Lth9c@
                                    zTT9}7s7y9B2_KP1X05KXBtrA*~?9BjFhZD&0nx#g{weL>j+2+h99o8c#
                                    zikCe;M;=sSQ&KG{DGxfDxbRg!J~${R;mPwjT1`1WHF0fQpN&{794liuAzQ>!3r4R7kX#nVdw(alR!{
                                    zFhy5Q?G%>SDq|Q-7|N=1Ug>h=zt*pBF)=vvn&cjFN|uc;c(!A4hA&l9Hhn<>fq%_K+n*9VGS;|A!Vyb*SE`w#@&Mjd%O5+7j_@
                                    z-#Pvisubbm9Q0*DV7@1!^-mRTAI^Q9O6SE385Mw_rs9pza=XfOUu{w
                                    z?;riZP5xA@#6&>Fc9s53*%A}jR~Q)nrDRvl5Fo=#8h?|$AwdFKCG3BxVfzYjH@m+E
                                    z7X*>&c*3GV{FhV~xEmHf;ok&vCJ-phKrsFph+R)ufWUqd{Fj>cR^oV$PU!zHk!>7C
                                    z2-J7jzh3+WPRmyiHR$61Qs5lVd$crcpQEK2w)k$#%|M95naQ~w@h}vl+~sGGTJi?|
                                    z4EvDokM)FxDL_1|N=ivFVtsFGlb^zEL9=82NJ+r6Tw>6gv#7tmN4~mr86|W(ZV_Nq16?b7@zisucyTBc
                                    zt|zWyG%KTDB$Gr$0ve77%@q47_L@kjd|$kHad_Zz)j{;!aYt}tcjf^y(?r9?OZV$i
                                    zAbmWd(c&QN4R9MU{05gRiZf
                                    z9VTX&R>S-0NU8xlyCHw9v`qaPi?O(FBcO`Min2R9a^fyzP>u=)fm2&1Ss`iT;SoZIqL^$Ybx
                                    zb}rUP2vsS4BdGN?Md_uRYHJ@*ODm^t_BhssO-u-MM^#nvPE1_Iimfbf0~wRfTKJqVjRRDMLRn?ivWQ!Rn;5EI->^C9Fz&D
                                    z;!?|rsx;3!&NqEidU_{lEC>d)FK{fDmtO(RXJBU5k|RHNyer}{+c41kd4x$rdANs!
                                    z+g4gZAv82a&~{!frH_?~$!!%j4~@q_-5AR5X@8Sycewv`X+zU_clsfdx&oPqYg1$6
                                    z?nZ7;F-Vrx*1hhr%=%3?NjA8hAsYk)Jj&9=A88=42M@+ZDQ&{lLE
                                    zWY&TZ|IS{AskF~G`3gsQJx_j|7;+o9NB6sQWoPtv`d4fl2zP%#3812nIo8jyezCzm
                                    zM8y8+X3x(vkD5kJ?~5cjT{w}~CRB`iX&(3DDuXjfp&!b@eR*J@^VeDMOnRoyk&WKW
                                    zX(Uf%dq=3!Mog4p!#_yIdQPFbd@Ft0V)<}|gn+Su(`vFAV@CODeg!`_G$>tScjhWn
                                    zK8ZuUcs3-AjEIPjM?{2*-mEIf6-dO!>$0;Z53%Ld)%(aE(-j-#k&(~t+ps_~K@d`s
                                    zd)9RJ7Iw}y9)UXSK9WPor$=7b=K>V%+BUtU!sk>J?T0H-|3W
                                    z9YX_&zq~quaVhkRUde$B54787OE(BH3d2X-g9CG6*W>G7zr3lQd)`&jDJeVIvidsp
                                    zPDdc4f_*mEbn`-{yD(nw?csc@I7K_CYm0O)Sh%?IO?&gs_TF3{55;~{xp$%}@_v79
                                    zB%iMjjihM`bn6y$+L1_fM2SfkXpY)}mv!`&1%=65>tw
                                    z?9U7UKC%lVTnpB~`3*TB8jqFRgNSW&iZA|nj4*Vk(qPDUscO{k&!pmA`)lzD%U@Y4
                                    zu}RHWy3{*y=y6g0F`9HFrXzzu^3OrO?DdZ#9V_H=e0138p_MiUy?(t=g2qp4n~6`Pes0`N(h${caWfd&Ty|9b_A_B^#h;bT7*E$%wog)uNS
                                    zsbXI88EK-Par=p~c=~`G=
                                    zFsWmOAam4V-rJgM9s)v}Or%@bk&)w%^vrKb_tGsRDcRXU9$|dDd~r1P<%`th1OX>4
                                    zR!bB+D`K0)cuCC=0Rp}x2&aEjTp&D(gk=97F)x)bnbKcG6<43JvlScmi;}QA@7^CF
                                    zV63M8>1Ie^Er-a|)re{M6AJxu65gMznHW)WxWCXblv~XCs&YC3=@+GPyNvX|Nu0?4
                                    zls2doYDLom=7Y+baaX6I*Q-fLUbpNN5_k3U!!qW%n#k3~MVfX&cPFt%@!z1GgstuHV#iY0lTTs6NxbgoPbk`dWz4YZ!&#`QbAZlaYu>JO+>)d4
                                    zje2xP94kxB=gL;JhjOtPk5`aw^pw9gjJz|(eR?-1&NHq&R+j}$c&C6pfbeAq2lXmo
                                    zbJTu*58oej4Di`lGn{L!d=H!Ra9$Wu&qccL#Cm@Ck&o?S4?Xxg%J%LyFL1VEouBmg
                                    z7D~BaZ%c)~oojHR6NM*WQ_|7#F_Q4%9i=}z;K^T-`t79?Q{1g)vf%MPHJz$;>_$uLUGc}8GQ*JM?TsGIAsa7mK=`M
                                    zm?3Ko2WmP<>@Z|LS_E$AKPZWbK4>n0YgR$A$bC^nkaAxr6(8|8BuW4x9@7}RcP>)
                                    z;FDnd=Np;BxAmL#%)M3Z-78xvqeetr=>ktyi9U%&(7j&fW1rg$@Tv|$V+pQ(id%sY-mO54bMlmCHZFyNPO?0NM
                                    zt!-$iTr!xDPBE3aNkKYlv`|~U#Bf#IJoXj0;bt7yBvuUSBgr3EtLx-IcGN0o%ak#*
                                    z>C}{XT%Ce!8+nIqc2?r`)jW?)G@YEB6l7$gOfHT$hWdq%>SX+U6Laru<`Jye8<7Mq=|Z1&(x`wRB2Vd)dkaS*yi6obT;e8
                                    z#?N1qAn1pUiHQj&UboydG@}|;m#}Paa-go_pJB!dMataD3ndkD+8!@;-kT+WPB*%#
                                    zyX0M)UmkDFxgUj6OIKQqRaIB3qj7O^9yYnR2jWE2%3mJ!i}_*CdEMRsv{9+B6B(p=24ANuJ)I~|Few~qhcr{yPrADDDWAyc;8%|k+^F2
                                    z_!5TqBE-ZcdiK*ubGn4bQC~dX@2z#%P`t-GqaK)4c?mI7@sG
                                    zEkpmg&t4MYagj0Rz6ouwk$R=&KM;z!m_j%D-T~Ndsli8=D-#)6`t6%DNaS<*>h<2<
                                    zk3hW$ic?nII;-B#B{enQ0EJ;|s*+DKMWMhX595`YLMU%}Qb=iTm(WvSw)jx^Ke+DS
                                    zk?`2om`!~Re>lmQ5H+uQa)oUQu{ySsVU`f)22
                                    z6%KsWp8-`T;q^@uPE3ff{R!GcpbiIGd3#RGt1B$i(2$9e%Ev)a=&r+b2YAs7k4|?S
                                    zz(AyCFf`EQx7}96gYY++RiMombGf%KzrZ#^LPGGNz5xM5*H2?~QD3Q03h=3?@-XqU
                                    z@3&1>UJV!NvM|2QDlC*A$y1z~oP6){u)H+V6h_SG`&GMIs@huA@#XnZ~(fQmyV#MXG&JW
                                    z(zpi%FwBqetnoMUfgMX~a`f9lt%;F|qdR5!nGbUM
                                    zqbI^|+5^Yp*wP~Q6r+~i;MZ?g9Lg7C--iA|+I2($hsl**$B=Tk+BepOI@gok&5?Y|
                                    z>G$khTs{02ND!v1Z2SRz_R4ub_1K;Qe}7hz-=!NUG_Xiz0)vxIyU4L_kJ412fkU}$
                                    zb@f=x>P1Hp6y>p#Y6asPtD|G1RX))w;h?z6EMBf0%TfEfFCzzw&(@+s8(ie4@E#mg
                                    z4q9hR(Axi=-;KDj@yO?aGXbv;WOaI(_P54*M1KGm(Lb)jtlWCkU|
                                    z+1jJ=<)1ffIvPi_Za$QhY8zvNwf4c9<^GDvHOKv8^^xmtw
                                    zVB>Mkf}$*Lg~!54zh*x_RNjrkH#4)%=Ybde+<34%He+`7B#GNDI7o}m_x(z&+AaL7
                                    zRkuE@rz{yXEsNcke~^_icZO=aFG*>kj%l1~V?a!0+!)?nIZ+VlHNNMNM9H{L_d1*L
                                    zLnrc_sdv^Z)KUPQKNhWqN~@_zTKVZ!nC9(ny^Zzk^;j%kSD5Y-Jgz3)dQ&F#-O1Xc
                                    znkM*4k25Hwu={oK8G0Yx-!Zyx1e1vX94lMhe4i7c}>Z$k6z={5w
                                    zvEI+zqG$R%m5rE=2=L>bR?!39B$;pZsj-Chg&#OON>RFl2#Z%<3e!NDZR)-048hqB
                                    z%l@DVs4M-m?>MO49|^^@!1I#X5RW4F>g6LKuAnL|(13+oW_)-yMwtGGr1v7eJ?vRT
                                    z%lzHwn?$s{e=<-gxxe~ViOlpoD7`?VrQf3URJ%nA!Cx|*5R!n-avB+R=O2JoKM!Uo
                                    z*LvQMW$+NjEm?EQ2toyn!1a!>MuLFVdP0ZvQfpMmDv}||q?dBeFnF3i0gJ`6rQld2
                                    zi~3D80t6n(lk=h}xcqaS0HLgX{VT|;k~(~bOw_`
                                    zA^hhg{>g()B!BO&U{GV*XZ)W0yZZTK*_RGGC?s1l2y$0-H~j-g<3H0J_#Lm5zYBW1
                                    zxx1@?ry{+;%q|)GsX6de7_fpV1Xta;EMBTr@GGFC-|Y)_BCY8&a1~^8BC!skL?eot
                                    zpwc)SgJSbGk6eja6%}ItG^k}9El0N1fL$E$)v2*vsA{}*@u3c>nhr_$|O*BuB
                                    zj)H@Oxs+rPjE5FW(oRid9|aM<88(+y+Oy4Ax%{4-oLpr!rSO^i+nfH>Bt9Fxve!Rn
                                    z8{K->@;kcjo5%!{v+q=nzpOYfHhC1Jh(pm{Yrm%Fwo_>X8azNM&Vm5+x&IJ;up-s=
                                    z=hyoLB_ic`N(O4|mVo@IFdHy}C2(9&B9&Nv4#sXR4g98UI7%%IyaFaK4|*gEw)VWj
                                    zU@*A{4+6k%AS|wVi2%b!Cva~lD_f5g>GqbKh=J0*rKK<13M`gyC_@dJ$In9TGg^5qK|7;4
                                    zWuAHRyH17I!O4mB9K5zKMSFaFoL^8dD|_bb2)(j;Z#ezgJiu)z6t6YOc-}T;8WX))
                                    z8zW+y1?(&%WF%AqdoAqnRBWmLV
                                    zEdkGn=M~G2^ei_xBjI0;No#9QNO=pAqE)j0qgNlYy`2oQ0MP1Hrt%s()5CaledrYa
                                    z7>P3lcjZG78pbw0Hv7`S60?UDV2n4XQ{}*c;JhO^P-&45a`>{gZoQM9zWV_jP#8cA
                                    ztpEoF<`c2^wyl}Z6J6pD_KCBuoo_C8QiQ_gQ>Smg`|<2G^3hWo#bO&R|ENVkAXQA&
                                    zak@CPx%i%${!i&fCRj1G(Due=wxQhPDpDckGay7KU@*Vec&)!U&g5b+d#kva>~!Ec
                                    zmFM|F{GBMMIaY(a-dtM!zxC>y<~L&=`(h_1PN1U3s}*6KoEFVxeY$I)ANMSiUVHsV
                                    zqGs|vUx|-t@|fbYy4Q$beN**<>)z%CL#UYi*~kc55!;W*nUwma89-s}bUMYWNVEX0FyTW?o^R!V#O
                                    z^4G79v5X?B`Ek)ryl!r~x9}9va|1_HQ>Sn;HUga#YUxYO?USvs&thInXLGl>I5^s`
                                    zjygf&$NpuvJFO)Dd016ubHvSbXR;CSMZh;aE;quWESGksHZU>k08;7yd~(s~=5>Bm
                                    z&2TWKa+g)%0f#-QNlg9!sRTxI{@7yvnHKkj7Od
                                    z$h0wfF7f;}{7^nS-o&N#qdYp1wTuFM1_V!yU1L}Ho-QHX7yBlZkWTkLqDOqzz~iy&
                                    zaaDDDxfKnE@7=(!M)OqDSTh}0R#)|!J?pJ!JcXRxm)FjqP0ewq=s#*uWEg2pEi}f1
                                    z0QPQd*rcHbJgCst_E+fR6`M^bgt(TedUy;&&x41bRqLH96~$6sI^j^>Z3}#?@Mo#1
                                    zjzZ4X2g{WpM}I>`=VjH{?+e5!Mx_ACU}sy$1vGXtr7q}bY2DsqC_AlF|2(_C80qVa
                                    zeSmRpJJ&?MIsC23a>6%^G)+A&k^7rII7a5Ynv)_A)*Z782Pe(gf!BI$Pimo`+4ku>#znXPE9#O>}f(~7)PyJ)3xI1mUvAsD~
                                    zoIUhtmHwkKPE1UacIZ-9KaYhP8_&tE+g_oqV_~YZV9*cyZ|!&2KH%V3+S#@w7whAk
                                    zXBLO#NCu^6b%yVe;^NwGjfyy*3A&wmdI2Lxsqq{(l-`XStU1{9>TwSC`R2yP<%Z$_
                                    z7=HpmrlXV0rYDC3r4Q)$PccDhsVLx&RZoVDl4la=j8jy7c5#8wV*ApDB6Sl9-7_AfOl9rh(E9t
                                    zCQU;pJqYkDo!t4AvNf=kpi@{{S~~3}7sgnQ?~gUK*fi@VpH=Se7F}M%0JBMV))m4%
                                    z8D~wwbmoMga{5O~lNyz$_zN0Y#J9wy3JS5WURjK5`a|S;WK?|j*(uukIFSsrV8=WS
                                    z$moQ`B~@QAQLb-pJlx%tm6b7SSeMwh|1n|2dM{oC;*6GAO;u$+53j4KAvV;7yu??Q
                                    z2z`J>*52NpEaY5d@Ts}E8Jm)Z#ssYSoaa>`_TrGDSZGK{47E9c6@^-rho`6T-TFOW
                                    z>`$LQ?MzkMfW})AuT@{NKy)=6paej;s^5+<($l|SU~pK_Yjn-d$^xiCKvYzej_&#G
                                    zA!r%Clv-D%PXVB&qrDv%Nid1o(>-r4k!7o_X8=L7|}p
                                    zQ2e@m0Lgx{n4WmH+vR9Q*VAo**FPd;Vi^HsVb%Y%xnqJ$?Y(ICU4j7yI6B}e`Rc`<
                                    z0ICEt;@pZnqyaX`i?y_H&^P6`TLi+1M!FjY8{TjTCl@PvnE?ghNg=lf)Lwc<78XgM
                                    zv5=6kzOaxX>;WiRnJpkzuQgd~Y@4EW%gV~YoA9|DE`w>Swwx&Y6*b5?vZ7F%!xrLS
                                    z3-??6++*WhiIs%2WMwkXlQvlweMPSZ@z0tiA
                                    zFddzpiJ&#LwH;kud~b)>S9_BV4i2Cwpk=&5)ZNo#ake`H$~7_DdGEu?kLYW$F)}Ak
                                    zUsFgld)`DvN4uSFe`~l7W@|DV$r}M!Oua~l0RZGs;Hos(8ZC4?URTOhNNHfwDmCh;
                                    zFdx#YvaB`k(&uAiGF@2di3j$=D}bT^#2N!Dy}h%89!I>;i(rt#FRac+N7pqvTJ<$*
                                    zdU{$>?B*Dj$kh|af@d;;r|iy^iX@_iOmMXK^*D6>HgAuSK@~Lw=Dw?JB3dIGdw_qP
                                    z-KSk<(E3qP^kR9w)u($XH`TS9y4TwdUoQS*>&qzIr}pauj7)o=;TKB6_n6o6tMJWI
                                    zIOSe;NK^zo9&|M3*|Jc$pH2*^pH9aHp&
                                    zc1~ra4vvv^*VHaaDZg4|RPOF4PO;pf_y}_0%-pdJd+x7aXQ66;(G3Z1nO-4z#n;bq
                                    z+7LQXYoA;F`vORAkw&Fz}stUL_|byzQiHk?<_@u>CQHGxa(?|5>UH>r2|V*
                                    zj}48YUKvaj5D);Ndvgd{z^B`_COvU580?wP{lvONZ^H=6r-|j2mAYWUEs7gYzoWCs
                                    zC32dK73p3ah9i*K8(8PoyhUa}ELVeJ*VWyNq!V*zsPOlKd3OSn!z0ctfRv3pLjdn>
                                    z#j8SKC*MZMc(H1ajPDVFfB7`V)S(W>ySYL+dg9#1$;AaCFGf~~sF^yQ;z@8izbPjw
                                    z=bpL$g%Oqh*95MWvIJx*3HImcT2evjFHCt*%g*OCJzxo&YZ`bQ_hXQOYYm#P5UW&k
                                    zO<91zfEfG*>6503w6s}Kt2bG|LWx`lY@2g(-Sy`H#r>T{4WziA)2`JJS;?RlBlEA$
                                    z!S`_P3`DY~6%@|$uL)ifCTyVhyh(Oxap~f%*$^yvVC-5#dD|Q1lcV7X$2&ymc?$eZ
                                    zC|7dct^bWHzQq+J=9w{lEPIFT#pPk+>+|)l@N&5s%BODp&ZMJE^y^E@%fqVqIRHSi
                                    zaXTdX`0Or)&v80tLP9}_p~fg8Vmwx~l;#BoDV-F!BP#8Tm(khYgTrmh1{YKkz(6Y_
                                    z4J#a_XebF8dw42wY)4iQ7(_&?L>VM{KWtzy
                                    z1&0H`P+BLdQk|JVdUOhK4$A0EzXJFLH1Pui
                                    z$75o&UE=vRPa(A5OHm45Wy>f6KP0>DJdCaRnpg0$r+O~c`Dm3irB4B+6j*40i7?jL
                                    zkOmj{ESBImAvafRiV6FspodH$vD9gOC!OTv!h*EazYVJVw#<^1+;tHAw%Z6=V
                                    zE>Dt_O1~^=+nl_=y?G{>V)YN!NHkfmTDds{%qDtzZI+f>`E6O+E#5D1G>A0gPQt0EsN~0STR8u+
                                    sg3_&sv^;>MzxubH>HqlOI&Q>1EF66iWl7ox|F8m)mQ;`^f*O4MUjqAbSpWb4
                                    
                                    literal 11049
                                    zcmdUVbyQW|*8WCbr9%)9DG><;1VN<3gQ9|za_E+j?v8_c=FF3m0U^l--nFOaQC9orichmE
                                    zI1^n2X@nec6XVZ1^ou84HWxV)qh;mbBoNfn@@)_gf|AM!Eg{I@`u~}NccdK64Svr@
                                    zdzE3>1BEI!y`qVZq+AO?Z4}rLXG+RCn@s#x`}k(|Z_o?hAaqbni`PDQDkf%#W3|{-
                                    zWFi3>B{O1#byo$LH8vPCoq407O~><9#ROZVu8jTmgBp`J$@%>7t-kmCo3sb4XWlBs
                                    zlsxwAgPmEXT#v9tTEV|dW4Xt<3sRYKdYvmE%xqVv|
                                    zGdS3So@?)QAoVA;@>gr4HZxnZ`bBBXKAXGCiI}t=xY6;!7W1=#+>TCx>*Gf@W}A8a
                                    zUmCG#U%&3MS=n9bm#!Hs+4M6SGF6t(x0pR&A49M(F+JjL&Hv4f9)^DySfJ0DCZ%><
                                    zhjX1k_*Aq13!XU3Lkh08&D!^=%<{%0Fyl!94b15UdG5P9-$Ll$;8QBzB0CtAU}Jrh
                                    zGhSkbVZy~-QclLE*W6fT^HX!}{EX)Lb4G01CjXP$_g7MB5T|$9bB6+j&$X3a9&BU<
                                    z(g=@b41Et28V!nd%4i^hB5p`scUP0WF|WSZ%Bmce>$o>$G*ms1t+wM7j!Ao?Q2~B%
                                    z&&Nz_+Ri8W9U`V(@{9V>(bdtIfB^iXBc~!yZ0vnLzWwim_?PhS25(?R381VQ20AuJpfA-xW#^K-3<3TaZotcX%Yc1V
                                    zjj3Wm$J2rC?&fdbK8fLxwTsKaUDk`1ZgCxd&pH_op^rrpHV32@nO)?!e$Q~&k<~!B
                                    zl)f`cM7RdzY~G-4Ak$d0wOomgcgfn7S6YStX6+yJ@l0I0d*%CA_oMEvc$EZUL|FqD
                                    z9o>+QzJ`RfhOo|ygW6h$1^$?Yg~?l-UpB#3g@#J&=$;kZtiGSD8XL;F@Y+v*EWbSc
                                    z(E0T6JUhFHmATCRq0>k{>*}C;b7Lo;^I;gF_S*1)N{Q=CgZBX4^L>2WIJ?CzH7kk_
                                    zACAv|)_cdrQSjSRZj6<@t#Y&xH-p<$YP(Idt74tZPj3x_^Qlr|8WQiazFwkGUNL0U
                                    zQ(Lrzy?|~YeBrz>ocD;kiofMF-)1A-EmmQ7aaQM^
                                    z*&3Qi28((n1@r2R4YjhgEaDOrSmEd4xqG)m(DE)9{d^{vxUdkH78ybR;K3K!l+)y7
                                    zp&Hk-12?zqg=0a%iJ}V>Dke14NU62Rh}&$uw8+kEx7Y-uzFt90>{`jY>8;-96nb5h
                                    z!9lqtw(B*I-u-Z#hDFH778DpXcuj6r7CdHSL-Ztd9hi_n-^}UPMjE_7E_ULm=V_1i
                                    ze6li~s^&C~GPB&qqJ28s6u7rJWiXsu#&1VGFzDxlEekKws@MATNusjymeOQ9E6=bn
                                    z=g!KHZxeh*dCHF(R`H_^2gA$NNkNvPkYQ(95;V}78eyF0Bd_O~Ps9tI3K`A~+y
                                    zwA4m!L%G0@T5gksmLj^*ucRbnALrUILt$>y;*eV*CNC&%W+Nx29h=?GZqI4jiSxRP
                                    z$j|Yuk=BR*PsZN@8*L4LXBq9}Nz1nl^8`vw;eXiGU&i(SE8bvg+C@nd3=_cc_n*Px
                                    zJC-^+pYc?#)MEeLPvRb*BYIN#J!~4jTF0eUw80emxMZecQ%p@ZOx{}Y4i_Fv{M=hG
                                    z{9F(1l(0EUO)4a%%(}P${_`$0d65>hfsC+dhB-=^iKwNkaw!~oH)%wZVhAnW;9#wq
                                    zlDG<2pwG`*(4fzaEm)9<^6nf2_1*cS$e3y1sg3z1j9*2R8WvEIf|tViqp=nR+7yZZ
                                    zR-FaRXiy)(3xBIpMH0|v^yiRJpSCUizs&>MG$oOgp#4_?j1+(&34i@YQfk6MTc-El
                                    z!W+5VhThOixbjD1rq4*Y8`s~k>|q5Fbeq-jA27`g4%%`VVECZ@SE2XoD>vyTu44~V?+m%K>A!ot26n~Z_K`##C6yPH$Ow{MF$
                                    z$-&_W#6@XoX&-Z5iG#E+_m46)k;gIWyn^)KgVfd-ENGOVY>&0(>
                                    zTmlu283Ix0S{;eB%q?bBQUW*Gn_DY*O-6ZVJ@q8g_r+wL>F(SqoG-Il94%ypP=41%
                                    z1OC)GBGEUqDHtzjX!v6q2sCZ25dM8NkZ}TXaQ^_Q-Jdr%e)QDWzqJQI
                                    zLcKIm;c|8ysF<<`S$BICFq3D8d3rX#^~8@io+y85yI)i?rM|qOp7R8KD498`xgT+U
                                    z)RFhrz|>TF$e<*{>z3P?cvO5g
                                    zhHK%>LxO@7>yu{(z`ig@yQ*Vqaqwc%J~or;YHb}D-2Iup`Qt}W5c@$(@b|E=0#j3)
                                    z{yq*QAs8BlNk-P6F6$~Qo2XH9?j$0jFt$zz$pM3~9mQkuv(n)ka3m=Bth?67>^$&x
                                    zB&CFCk?+P2^Ulxs@hBbx(2_D5BP&abLOnL-VR>Zj9jQR~ym`j#Bf#Gs9T^`n>@wgP
                                    zUyAI|-PFk~Y*V*3Vl{>DBQoMM6s*+Lj3N(|+}+&)RH5K@wHPZtI6X^5)!LQ~;6w3A
                                    zjEn`?cjE|WI-+sy4#3=N9uyfja1~bKjx1FnH|*PU)>$EGgu~b)xFU>~_9)Ez
                                    zdXC!5zm(&phHPs9n}zk4Mc{E48H(~H5D_l5rAOUdY(*2%1z_xVW57gQ?+?emRJ;#i
                                    zUF<9b)>V6hX*gur+!rG#_|N733#R$9Mnk6KML+U(d@4S2(&9?-7;K2|Neg)s@Nrn=
                                    zIUKDM4-eHwx4*t2Q&W8?`|8;tr_zrE=qhe9X6xJ>K>Xq36n7+WUr7ji;F#A5du*2bax%*mAenefUOI{pehFlwiS!OGPF2nu(F2}plg?Zw%
                                    z4K2Z&U(ygqODQ&8@h4midZKx^l#7iktrmOH(D_^rCLUU8Whrx=AI^4tBp5uL4dgE}
                                    z94MSTheWvO=KMY@ah3#7F$(O;bP8W|sFa$2kiU83yWL!i-C#~)${DZCO0JO0r2VOd
                                    z0$YyQ6=xq}R9PUXFczS*k=H_Nj`&6un#0n31lE+2?
                                    zz(pWRRA1AxNp8ui_nj22d{;E?h40pN-BOIhFl_2Qx`aaJ@O>mEmQt=xYZy94L{nqc
                                    zUY`VxJK=28o-pEk`}@~C0EO)rq94a{cay>11v3D$MgzFHRD6{j`cg99(j}EjYTiEb
                                    zD*F_@_b#%0)CnMY-39_S1%Zbl@>vP&HLdtGLIWsxZt>dE(rwV0UcmV~pl1@oi(0qK
                                    zMvD>xsRhs03d{m1m-UaV+hYgLPP`9rD>){;x}0Sd+OINz4qs3xYD+06!Ol+hn#%e6Xi56WIN2;EPNUtWBZkoaiHf70MNdpxQkKJfjhcWr
                                    zUvQ}&&cp-m$a#MxEtbow!usCWL{-9(l25Y0p{74kqNzhcc~B6VwD6g7j{3Tf$*8J{
                                    zlIc^s9QIs?E+x~d2KH(*EKOm*!}F4}9D{M+fel6lt%LIG6II}WMPZlJ5}K=TAeK`F
                                    zofM3#y&v^U`%SvmO0lbY`!KirFNrUgk342vYC@aWZP)@HL3o}260}5KAD*s$u#!!_
                                    z#i%9gVJe_0jL9psufzfmX#nW5(~nY?HOLSLm1VE`dalt8+pBdKBJGcFkHhG#KVH*#H{h2S}#hv6_O0
                                    z3zz-RAK)m=&(B}IdUd2c8fxd#4@Iu8yGer)`5etF-x%*n#qTD8n_zVb(uyZf|u_vBD2QoNutqO2`%^2hojJW
                                    z70`~&XrU)9BcEQI{?rTI4{O0*|KxiuEHb;AzRfGBfGw4hySP3M{kC9NXaU_q>_k{~
                                    zfNMFAV;ApPr8p!GItDv+bPerA+U(88ogYy3P|&&RfUnI-=G71AvkZrNcwIY2xkPvM
                                    zQ0qEBPfUln@7#f@JeajnftK)yr6EW+dF<_6>g|8}TA=Mh^f2O2-1p1F5{YK7AWB!i
                                    zI9)7SOu)&JO$p3cP3q}M1t_P;#ur+;r6BM=_%{rM`SR=il>syLGD|@g<1)Z3eI!uN
                                    zvq^!L$OL(BiUG7m#gFfDel*5bJ#5wYnbzAoSXyvC{CBWN@(b*R$PcW+_pP~jlk&X#VkLtn;=$R<
                                    zfC8Dm?wQ^nSnzzUfa;mTAkpga-qasV%I-27i{j5z!sKT-ftSQ?jHAJ~4{Sz5=Mo>U
                                    zWj`CjxJ~Y8$sW=z6wB*+`hiR%P9a0yUqPMxk&|su>)db+B2BA)0iV2Y!t(4nwL?p9
                                    z?^ykksZ`qf=e#oIxV-NW~jYT&;=QjV5iG3l!%12waMlezG(yTHsQ&puzwWYOe
                                    zYuXb_cieG=+^MuLsm7ws>BkKSNjT*~mV#OVd~Nk^U!9*HGaiMIa?zeJu+_nIXKiD5
                                    zO+NYg=Zz!F=GwwnIrUhaX8ot<4QpMFYaH&|MuJ>m-4xHHnNa(^=}_g?VMGF&>|I+H49bVFrg;xAf*M&bRZ1JM@B!
                                    z#eU61v#0*;;o;U9fYi^$vRk{VBND1zTY@&;zu(#3!6_sb9m>K9^o_MS{CSVIVK{HI
                                    z#PqDen>gcnz#7#}o}8udpZ|$=^fAeHI(V$%{LpE25Pf+$Qp5GA9-m6!VBPmuekJW-#f7(#hnXSyz21D8gB$n?LbSEm_{L|B;_Qw3qKHxbZ30qqw
                                    zn*CQ3ua;z~5bSPDRJ)!%zrT}wxr?QD=;(^B>OF#(Qh=+2LOJdmFIaWE*Bnf?
                                    z|AW^|0nWn2_)5f9gA6UQ2GPuCLp`2Pe-vwm&!%?Eu#7kB8tqecbyxAW5qL)3XtBv?
                                    zeroe`8WZ-MH@i`?HLg?_`z0=bS$z#JN=lN!v{-o6^mAHJxyW&5uC+9Ob0O)88sL44
                                    z4EoPa#_;9O%Uwc{s)j4{Y&o~#6Oo}-Z}(Pm+IdhFhVa)fTIwP-s7tjQceM%b`D_Ay
                                    zwJ0<|LLr+qS)0cP3zN3c?5?!59UKlQ&;LMpf{2bGqlf93ExUlTu8vNwt@ct!G#wGq
                                    zK4?`h4N4tYSTnx$F!_LgGqbb3o#s(`!Tf@cRIt%#;S+0Xu-0y%W2zK(7^KySC@4m&
                                    zoL1o(wty5Tf;}?Wws$_=sI65`5v$@i=nDdiw4ZXRbmSTuDBAz0pEtB!E#CNo$Wm{f
                                    z&$`TZy~}ZL4dL^UBwX1t-`8sdRa}k{}1Yy;^^X+LESD(=X4TxR7IIszWU8_7^(Y8Bq6!ows
                                    zhJ8-cP%kzfJ=~%Jk&=@0vqWs%HTW^Z`1lH-v7M&fy{ep2K7KqCKDVFsx?W`jSk|V<
                                    zd37Cr27MuG1BVyI!#4J8sx6~6!t@U|vZfFhvtwomA{Zrq#KJP~@q3I@po29sI=6XH
                                    z@~yS+3#grQHH_C3=11>9a(-!PPQ8haAhguqKQU1?Ng&M9+C3EuuE{XF1}!p~3E-~T
                                    z{dF_M#aS#lr}_<8q0!Lka9%hFRQ31Gob0VCX5ObsWQ5yH=_huw6a)SHZtNH++2myP
                                    za)+JO_vrk9(+2Sd^E?JDTJ5)@o0Ah(8{=d+WYs9t$t~{esSJe*95SNqZCf)ClJjM5
                                    zmy99<>uYNC#d10jBO@g>G!QhDJNn`n@uE10lcu~-;BH2iW;MQ<^J#VjtKjkO7Wt!e
                                    zE9X;F+Na>;)tnb8S#H1HK~rp>O}`~9oS2>-IcfiP1Yo=f7hgzI#$@cV%T6cBg9om}
                                    zjIO)F7o2Co(>Ch@$X(;Md>fRhe7wGAL@`qZX8HyeOC{28;OGS5y>-Zfj1>LYRf`Kut3wqxRwB8Q8O|f-D9}
                                    zYH0~yv+wEZ;m%fV`RBq|ge^Y(!I
                                    zS?9i*Ch4R#+q7Ba$P$=hD4#hjuc)Y4uz-$tt5m%*N-cu*3e;AoV`&JEKYZYF(MLVH
                                    za&lfM6dnaW4xZW!;KF;iYWA%s%Hx5`A1zqa0D%LQBFE%6X{1|Q6@Zsp0YMXf8^;0X
                                    zgcMuKfhmNZmewc2JA!BV^5^R%&+FSZ#H28u0-b2K{VM3VyVRE|
                                    zF_f(aLiwiIj4UjfHmifg46m4UI8s`b3$PzM0vkLH`#l+ACMCAPLFI$s@W)
                                    zOD%wQ9K*rJ?!YTx>E$PZ);uPwcaemjK7Ben-a9$n>E0YKOFF{xS-QMptA$Z5&-2+!EG8=-BmK>%5O4SnDRXESB&qiE7!(eCgOZ2
                                    zakFx#i?dsRn3&iK3{NCsEj9Y!KBU+;Pzqv1tSZH-6}Bc7w(Er<&wNR<)T_$hdAI76
                                    zyPOoa>a_iGuw>x_Ivn$hi$;Nbe0+xOKFK#oNddjT{-bK}9uw1Wxs4GJW;~zGD~30(
                                    zUis}ChHbOZHcV95)tqj(M|0|%PLvmkdg9YZEJd;slR}vi!Wxb+FJ^`8%9D)>@R~-Y
                                    z{Z^6DkQ}^-Wov(bvdAbBg>u?o>%BEqXwd)tI|v@IX;hysrzOT1F_+7<@o@n%t*c8O
                                    zzPC0~pzAO=QlLL&KkM&$cATYBBDHFy9I+IwevUwQBU!pT=ku73jcwDHtr~D$3gY5E
                                    zx~;%3|DLT@(G}0{>EXf0%lj1-6BjrBNz@ax*e&%up=gz3g=L4?)YaF6K>Y0Hrm)HA
                                    zBd~`cB}4{3pw}6rR%ze6t<)aLMu3YeVEE3$&>df
                                    zDR1*aT3TAt5*$%xQ`J~lShBLRKqS6JF%I1fB+R|Mj4Iq9TM0=RF+IJsG@PSR^W(>l
                                    z!otFZ&e$BqJQ#swz9q%|)_q|^sMgSUGPJ+}eGLz=rEcLt=7ZomxN!xUKL*$2SJX+Q
                                    zD1}0w860#uHli*MaM07m?#7w?8R(KxTWT7i1eb5%1F|0-TniL6R@$XLk$Xra1(<^0
                                    z?_IjM^{h2ev2OQ8>z47r+whObep>MMFX9&kP4KvY`<0acf@k8ge*J<+5NLs4k-(&x
                                    zrKaV}2}qvSEz?}qPwL38fcn>MpBLlqVgj=;(GYcsT-F#wU5b}AGf|iMpR*r=0F1bU
                                    zmucKI&~N65yKzsz>dk5H##w;+Ck+Y}!J&;+PYWh~WIc=P50>e4XWB0S)FHvhdQL
                                    ze#P|G1f*CL&g!60V$T^J?Q!kQm!_v53h?m-li%5Q3qnrEr(g9t+HKOLGFCj&sxY)ML16VwvoqyBRh=I5a;aJ=5%aoe|^~E
                                    z1$^MchdSVM*$db%^|TIV#e!rMu(I%tjlEls%vtk75)ndHYl<0XAAn-B@Gd4~S
                                    z4V?uVV)ZYF#`WhnW_aOh`U4=4Djvt(T@alZu5z*fu0BYxIytP&*KL0fP+VZ(6xGdP
                                    zqwnc_q#h%1P0pJFzQYXt}
                                    z3dEipNm$pJl?_O8GIg(i4NWQI0schY#U`)jqNA=3M*Gz97;)_`qZFlpnfgy3k}(hb
                                    zc&n5Bc&&P8kimmV%fjsauSp-ge54l%xcK|s9hH3c<|QBy<_bFah@9+?2fpACCdm?7+*x(dWVX-udr-
                                    sAa_Fsg4|yHO9sK;xdi|1Y3~9p+--zn&E29Gq`*QipGiH
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +#include "lib/test/run.hpp"
                                    +//#include "lib/lumitime.hpp"
                                    +//#include "proc/mobject/placement-ref.hpp"
                                    +//#include "proc/mobject/session/test-scopes.hpp"
                                    +//#include "proc/mobject/placement-index.hpp"
                                    +#include "proc/mobject/session/query-resolver.hpp"
                                    +//#include "lib/access-casted.hpp"
                                    +//#include "lib/variant.hpp"
                                    +//#include "lib/meta/typelist.hpp"
                                    +//#include "lib/util.hpp"
                                    +
                                    +#include 
                                    +#include 
                                    +
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +namespace test    {
                                    +  
                                    +  //using util::isSameObject;
                                    +  //using lumiera::Time;
                                    +  using std::string;
                                    +  using std::cout;
                                    +  using std::endl;
                                    +  
                                    +  namespace { // a test query resolving facility
                                    +    
                                    +  
                                    +    struct TypeMatchFilter
                                    +      {
                                    +        
                                    +      };
                                    +  
                                    +  }
                                    +  
                                    +  
                                    +  /***********************************************************************************
                                    +   * @test verify the mechanism for issuing typed queries through a generic interface,
                                    +   *       without disclosing the facility actually answering those queries. 
                                    +   *       Results are to be retrieved through a Lumiera Forward Iterator.
                                    +   *       
                                    +   * @see  mobject::session::QueryResolver
                                    +   * @see  mobject::session::ScopeLocate usage example
                                    +   * @see  mobject::session::ContentsQuery typed query example
                                    +   * @see  contents-query-test.cpp
                                    +   */
                                    +  class QueryResolver_test : public Test
                                    +    {
                                    +      
                                    +      virtual void
                                    +      run (Arg) 
                                    +        {
                                    +          Iterator ii = subF2.query();
                                    +          while (ii)
                                    +            {
                                    +              subF2.attach(*ii);
                                    +              cout << string(subF2) << endl;
                                    +              ii = subF2.query();
                                    +            }
                                    +        }
                                    +          
                                    +    };
                                    +  
                                    +  
                                    +  /** Register this test class... */
                                    +  LAUNCHER (QueryResolver_test, "unit session");
                                    +  
                                    +  
                                    +}}} // namespace mobject::session::test
                                    diff --git a/uml/lumiera/131077 b/uml/lumiera/131077
                                    index 9fd8e46ec..e64895446 100644
                                    --- a/uml/lumiera/131077
                                    +++ b/uml/lumiera/131077
                                    @@ -1,6 +1,6 @@
                                     format 58
                                     "ConfigQuery" // CommonLib::ConfigQuery
                                    -  revision 4
                                    +  revision 12
                                       modified_by 5 "hiv"
                                       // class settings
                                       //class diagram settings
                                    @@ -450,7 +450,7 @@ ${inlines}
                                         end
                                     
                                         classdiagram 137733 "Query Interface"
                                    -      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
                                    +      draw_all_relations no 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
                                     
                                    @@ -473,6 +473,104 @@ ${members}};
                                     "
                                           explicit_switch_type ""
                                           
                                    +      operation 141317 "issue"
                                    +	public explicit_return_type ""
                                    +	nparams 1
                                    +	  param in name "query" type class_ref 156805 // QuerY
                                    +	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 156805 "QuerY"
                                    +      abstract visibility public stereotype "interface"
                                    +      cpp_decl "${comment}${template}class ${name}${inherit}
                                    +  {
                                    +${members}  };
                                    +${inlines}
                                    +"
                                    +      java_decl ""
                                    +      php_decl ""
                                    +      python_2_2 python_decl ""
                                    +      idl_decl ""
                                    +      explicit_switch_type ""
                                    +      
                                    +      class 156933 "Result"
                                    +	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 ""
                                    +	
                                    +      end
                                    +
                                    +      operation 140037 "isValid"
                                    +	public explicit_return_type "bool"
                                    +	nparams 1
                                    +	  param in name "pos" type class_ref 156933 // Result
                                    +	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
                                    +
                                    +      operation 140165 "nextResult"
                                    +	public return_type class_ref 156933 // Result
                                    +	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
                                    +
                                    +      classrelation 181765 // 
                                    +	relation 171653 -_->
                                    +	  a default
                                    +	    cpp default "#include in source"
                                    +	    classrelation_ref 181765 // 
                                    +	  b parent class_ref 156933 // Result
                                    +      end
                                    +
                                    +      classrelation 182533 // 
                                    +	relation 172165 --->
                                    +	  a role_name "" protected
                                    +	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
                                    +"
                                    +	    classrelation_ref 182533 // 
                                    +	  b parent class_ref 156933 // Result
                                    +      end
                                         end
                                     
                                         class 155141 "Query"
                                    @@ -507,45 +605,41 @@ ${inlines}
                                     	idl_decl ""
                                     	explicit_switch_type ""
                                     	
                                    +	classrelation 183685 // 
                                    +	  relation 173317 ---|>
                                    +	    a public
                                    +	      cpp default "${type}"
                                    +	      classrelation_ref 183685 // 
                                    +	    b parent class_ref 156933 // Result
                                    +	end
                                           end
                                     
                                    -      operation 140037 "isValid"
                                    -	public explicit_return_type "bool"
                                    -	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}
                                    -}
                                    -
                                    -"
                                    -	
                                    -	
                                    -	
                                    -	
                                    +      classrelation 181125 // 
                                    +	relation 171141 -_-|>
                                    +	  a public
                                    +	    cpp default "${type}"
                                    +	    classrelation_ref 181125 // 
                                    +	  b parent class_ref 156805 // QuerY
                                           end
                                     
                                    -      operation 140165 "nextResult"
                                    -	public return_type class_ref 155269 // Cursor
                                    -	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}
                                    -}
                                    -
                                    +      classrelation 184837 // 
                                    +	relation 174469 --->
                                    +	  stereotype "type-def"
                                    +	  a role_name "" protected
                                    +	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
                                     "
                                    -	
                                    -	
                                    -	
                                    -	
                                    +	    classrelation_ref 184837 // 
                                    +	  b parent class_ref 155397 // IterAdapter
                                           end
                                         end
                                     
                                         class 155397 "IterAdapter"
                                           visibility package 
                                    +      nformals 2
                                    +      formal name "POS" type "class" explicit_default_value ""
                                    +        explicit_extends ""
                                    +      formal name "CON" type "class" explicit_default_value ""
                                    +        explicit_extends ""
                                           cpp_decl "${comment}${template}class ${name}${inherit}
                                       {
                                     ${members}  };
                                    @@ -580,41 +674,8 @@ ${inlines}
                                     	  b parent class_ref 153989 // QueryResolver
                                           end
                                     
                                    -      classrelation 179973 // 
                                    -	relation 169989 --->
                                    -	  stereotype "generate"
                                    -	  a role_name "" protected
                                    -	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
                                    -"
                                    -	    classrelation_ref 179973 // 
                                    -	  b parent class_ref 155653 // ActualQuery
                                    -      end
                                         end
                                     
                                    -    class 155653 "ActualQuery"
                                    -      visibility package 
                                    -      nactuals 1
                                    -      actual class class_ref 155141 // Query
                                    -        rank 0 explicit_value ""
                                    -      cpp_decl "${comment}${template}class ${name}${inherit}
                                    -  {
                                    -${members}  };
                                    -${inlines}
                                    -"
                                    -      java_decl ""
                                    -      php_decl ""
                                    -      python_2_2 python_decl ""
                                    -      idl_decl ""
                                    -      explicit_switch_type ""
                                    -      
                                    -      classrelation 179845 // 
                                    -	relation 169861 ---|>
                                    -	  a public
                                    -	    cpp default "${type}"
                                    -	    classrelation_ref 179845 // 
                                    -	  b parent class_ref 155141 // Query
                                    -      end
                                    -    end
                                       end
                                     
                                       usecaseview 128389 "query use"
                                    diff --git a/uml/lumiera/137733.diagram b/uml/lumiera/137733.diagram
                                    index f1e7265ed..89c4838d1 100644
                                    --- a/uml/lumiera/137733.diagram
                                    +++ b/uml/lumiera/137733.diagram
                                    @@ -6,45 +6,56 @@ classcanvas 128005 class_ref 153989 // QueryResolver
                                     end
                                     classcanvas 128133 class_ref 155141 // Query
                                       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 137 195 2000
                                    -end
                                    -classcanvas 128261 class_ref 155269 // Cursor
                                    -  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 225 271 2004
                                    +  xyz 180 332 2000
                                     end
                                     classcanvas 128517 class_ref 155397 // IterAdapter
                                       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 62 298 2000
                                    +  xyz 50 241 2000
                                     end
                                     classcanvas 128645 class_ref 155525 // ResolvingFacility
                                       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 480 293 2000
                                    +  xyz 427 339 2000
                                     end
                                    -classcanvas 129157 class_ref 155653 // ActualQuery
                                    +classcanvas 129797 class_ref 156805 // QuerY
                                       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 386 431 2000
                                    +  xyz 163 150 2000
                                    +end
                                    +classcanvas 131077 class_ref 156933 // Result
                                    +  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 250 241 2000
                                    +end
                                    +classcanvas 131205 class_ref 155269 // Cursor
                                    +  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 251 378 2005
                                     end
                                     line 128389 ---+
                                    -  from ref 128261 z 1999 to ref 128133
                                    -relationcanvas 128773 relation_ref 169733 // 
                                    -  geometry VHV
                                    -  from ref 128645 z 1999 to point 526 191
                                    -  line 128901 z 1999 to point 292 191
                                    -  line 129029 z 1999 to ref 128005
                                    +  from ref 131077 z 1999 to ref 129797
                                    +line 131845 ---+
                                    +  from ref 131205 z 1999 to ref 128133
                                    +relationcanvas 132101 relation_ref 173317 // 
                                    +  from ref 131205 z 1999 to ref 131077
                                       no_role_a no_role_b
                                       no_multiplicity_a no_multiplicity_b
                                     end
                                    -relationcanvas 129285 relation_ref 169861 // 
                                    -  geometry VHV
                                    -  from ref 129157 z 1999 to point 420 350
                                    -  line 129413 z 1999 to point 168 350
                                    -  line 129541 z 1999 to ref 128133
                                    +relationcanvas 132229 relation_ref 171141 // 
                                    +  from ref 128133 z 1999 to ref 129797
                                       no_role_a no_role_b
                                       no_multiplicity_a no_multiplicity_b
                                     end
                                    -relationcanvas 129669 relation_ref 169989 // 
                                    -  from ref 128645 z 1999 stereotype "<>" xyz 469 379 3000 to ref 129157
                                    +relationcanvas 132357 relation_ref 169733 // 
                                    +  geometry VHV unfixed
                                    +  from ref 128645 z 1999 to point 473 166
                                    +  line 132485 z 1999 to point 292 166
                                    +  line 132613 z 1999 to ref 128005
                                       no_role_a no_role_b
                                       no_multiplicity_a no_multiplicity_b
                                     end
                                    +relationcanvas 133125 relation_ref 174469 // 
                                    +  geometry VHr
                                    +  from ref 128133 z 1999 stereotype "<>" xyz 100 358 3000 to point 81 356
                                    +  line 133381 z 1999 to ref 128517
                                    +  no_role_a no_role_b
                                    +  no_multiplicity_a no_multiplicity_b
                                    +end
                                    +preferred_whz 629 529 1
                                     end
                                    diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session
                                    index 761455ae6..c9ca3b9b5 100644
                                    --- a/uml/lumiera/5.session
                                    +++ b/uml/lumiera/5.session
                                    @@ -7,7 +7,7 @@ diagrams
                                       classdiagram_ref 136581 // MObjectRef
                                         651 533 100 4 0 38
                                       active  classdiagram_ref 137733 // Query Interface
                                    -    688 570 100 4 0 0
                                    +    629 529 100 4 0 0
                                     end
                                     show_stereotypes
                                     selected 
                                    @@ -28,7 +28,10 @@ open
                                       classview_ref 129541 // InterfaceSystem
                                       classview_ref 129285 // StreamType
                                       class_ref 153989 // QueryResolver
                                    +  class_ref 156933 // Result
                                    +  classrelation_ref 181765 // 
                                       class_ref 155141 // Query
                                    +  class_ref 155525 // ResolvingFacility
                                       classview_ref 132229 // Custom holders
                                       classview_ref 128266 // SmartPointers
                                     end
                                    
                                    From 8345df394d5ad64f729e00a17574b3a562b2f0ed Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 23 Oct 2009 03:10:55 +0200
                                    Subject: [PATCH 020/377] WIP continued turning over the problem....
                                    
                                    ---
                                     doc/devel/uml/fig137733.png | Bin 13015 -> 14443 bytes
                                     uml/lumiera/131077          |  43 ++++++++++++++++++++++++++++++++----
                                     uml/lumiera/137733.diagram  |  38 ++++++++++++++++++++++---------
                                     wiki/renderengine.html      |  13 +++++++++--
                                     4 files changed, 78 insertions(+), 16 deletions(-)
                                    
                                    diff --git a/doc/devel/uml/fig137733.png b/doc/devel/uml/fig137733.png
                                    index 23b1a0f442ddbe1be289b6bd8be9495d52ab745d..5e81df28533b417b549890fd8be080d926d15aab 100644
                                    GIT binary patch
                                    literal 14443
                                    zcmcJ01yt1AzwdyEgc3?9=@3dI(v9?hw2~6i-60I6fFMYBqm+o0bPkPlcL_+x&>e5%
                                    zIp?19|KEGxy6>&`ST2_i@Qb~_dw)N*KPbve-N7Qkf?K8Wh*bG{#rMq-gnRrWgmjcVeDt-B7jJ7iL
                                    zvoO^)%~)tF_WKE9OA2IJOqcTKbm%FCDO+yJH8Imlh=p%nURHQKGDP=fY?|WVa}#nu
                                    zj^mwzZ#{^sMDi}Dzzb+Pze6A*gtsiXA&@kK3=D{fpfVaHje;H(q8Lhm0{J2p2!RYy
                                    zOF$rN;ZzXFfiynE+wK3^k0pJZhKOjI)_{^vArKJ9wn&Lx83&j_C8WpwvKX7
                                    zgakps_nfaTxr!I(=GgoSDqc5T-ngYdJ@tyYkFH)>8b57pYo?Z%^z5QN5)sdAXSe#$
                                    zH!Pz*AmBtu=*BJF6nb9_oRo*Y(y+?#D90SRL?vd;+ZN;YV>=7WQNy(Kw)-oUq5=8Z
                                    z!ZNVRonbYL+S*$+$McFdNE9T3lF?WC`EwkMHwCVHP;&l|TBr4VGg^z$t)NihxX4Hg
                                    z%Lp?}J^oOz)&MwXjh?vIceAN-2fq0GG-JDF8
                                    z6G^<(N663*L1){W<=LdfTVwqS8eQGp2lFlKc6O8$Jb2YMvuef0c|@YO$&OEka%?CC
                                    zc(`dYHXD4dIP)@`EK(QRdP}WHFBfAi1_lPYV<0gP?Y`oN#nQlTCbK>@Xmtr9zAAKF
                                    z_3ss)O-s8A^`*Jlu}cBN>gt|mhDGcSsaroO>F()Kig9#w{LwR$c~1A(BsP7avm;`C
                                    z^zk>H+HCXTKy;sljd2S@*U-qp&LgA^`~Axl9D}mEP;ph&!;WbFwqUJ7yM-6R!V1N-
                                    zH*41FzkH!vWRn_IV(RKg4gBhLCI8?-{M=koLj$vzn9tW2IeMBAF0RGd4e&QZ0ijnL
                                    z<0cl`)rThT=g$l(eVT-C+^B_n+0Qk0JWlbcU_uA1k*)IF(Kq|aL%
                                    zP4iecUf8S2>(b%%>HbjyM~+1q8l4>&`4_`qU#2|yWFs#ABY_iM?Ucyju%t+tT9rk6
                                    zGfxLmH<>9r8q4%xwj4>|(?HM22=9n`QY`!4-v!zCx@%BDZEyGM=BBnu>qjIJGYPlj
                                    z3X_S6SftX
                                    z{9>aL+AMEVYbpk(uY1d6otaul1dPjR6|ogE*7W|LEI5(3h8iiH7N!1D3b*{ZC@2I?
                                    zx;3?x)o#nkRMEiRwt5xR@##2q%eP--+r?C_e+iL6)pV}`c-A~wdAxk43lN&gY~1C%00D(r}+4LXGd2YbabDc*6~FH
                                    zx)X7E`Rd#c%)frO)=RTV;3HQO%&X!D{-1T*brEm8{$@rbi
                                    z%m!U4=Qc6V3wigW#)mFZ!oolH>!4pE%U>)
                                    zPdlqYtXzCvmtV(e)6-*LAw1U`{a$KUm*HT>Th{o!(A0Fhx+K4avyl{LJ3mn>%xyh2
                                    zo3A~Xo#G~XlJhiaajxH?FRcd@30K}Pu)_A1tklaaMPE%FH~A}ILeXy@ceO3Y-+N4S
                                    zv^C8_W4P;cOQV%*e|>Z(J5@d-Yi9iWqHSBq<#4VVbIr?`Sel(@GeiD1^
                                    z;l8GW@U)n3_S@PTwix*qYord~;fY!FdUL?$x&`#Ir@o*yBI
                                    z=jU7DZdFp^zTy(hFj(d5Z_IQ*5az>Jq+B$X({4PEjEAVTUJf9b$LN*8%zjatZfr8J
                                    znX1@a)quB!=z5-QP6XiFU_qn!NAq=4!x9p*m{#X@qI`UsTxKOGcq5|X-t>U&XJecI
                                    z>ifNzMWwY5Y+N}iv9om-YPPnr1{WzQTOC*5nX%8a1>WLau7ZMOWKNTW*CysdP}
                                    z?w#GQR&F+-eSK+QVC!}ya{~!G7tg}&sT-$Wjh93`PWkd{Wu-5pJq;FF7cbzNhNs^i
                                    zfg3_8yu2x>ce1;gt11!0yq;A4)$@Yy@^G@$dRm7;E#Fc}^QM5%mJ^0R#x|UMrY2rB
                                    zPjhj8Bt9__ezM!m=QJ}>vO1WSMof|G5z|nM^ND0u&Rbs*A1WHaZlXLj4S(Z0Y&~12
                                    z@qrt&kR>DtLZnu{HE7bC|3$l+?-q?7TpGWA{x*8H+kv@eHKDfzc=taWa$5jV7$q?`
                                    zT3`qP$}Xc}RzV&W&nFUU&HqhvZhNl#P&lg=RRT2g6T3PLMaPe(DF52k)1J`2sn^>W
                                    zbM?nb{umIat4xThDG~_rtMu~H`Y;q37k9p#>T&~>1iYv7eDlfOoO^w!OQtA(pld#H
                                    zu|DRWwWL>R-5%9Ff*+Wx73o*jC{R<0($Fi$k7No+%T(>pz}eZ^i)mra%^!CU@*evJ
                                    z1YZd8RAk~&@l+T+?>fRJ`dGHLjw*vik1Eg@$F>(j7C-wXT*}R@HHmk9SCCU%2sFU+
                                    zll0o!b+DtmuIH_!OA%v0%WSS(cYnPV4aky9CFf+wD$%{6$CiPyjj=xBalV?(xHScH
                                    zaduvtEH|jjZf!BtP^BOfa{p?#ptx9+zA)?48q0Dqx27q9p;YTOEE}62yTu4$3LrqC
                                    zc)ieiflVC3tTl3Se!>_`ic9t+O=Tu~bydp`Z*}!SdwXp3qM(3zbDP)UMsaDr_8Gg-
                                    zWty^j(dW*KGhBujwv}F2&sqW(za8p(M@R-jLKP8piHNJ8GSMAIhKBN~LOks3{74n3
                                    zxVn1mQn!DJ)mhE=^9b67v%_TlCp<<*MhfwFvk15>4mVZ@5!_Z2KZkOHJUvrX;cOzX
                                    z$dA*u00hAznCxywRaE4u(vx!3~6dxY$x^Jp1Ev;q2eTxo^l_CkKGP6PSR6ZxWiIN6+`H&H797TN|7SyN+
                                    z^gHGn)tDmf>8yXD!QaJKZi#wbd=wEbTX09m5<)H171Y1$FR2>GG>B#=$2X;q7==Up
                                    z10F2m+caL<7ioME#*ejl@6h-}10e}vHV=ayzSRk%@;-S+kwvjOd1iSwaKr5mZmwwX&`X8Tw|AD1e_YWv+itSL6#`-tvb+~?(e&T@V=s2C`T2oo7*N<-(6Bw+
                                    z(QzmQR50+#1fF4pN7z$?&YsAXu32(_)mRo{8hN?&D1C(n_B7@H9|G=p{a+*CR!K<-3HngpDjaoU
                                    zhmsA6tIOo4PoILh^6}An{~rBij&ef@4RY7G&E!9AHAPbmbE)!H$eGkv6@|O)k8>YA
                                    z)>R5=2i=~M&++?9##Glmt{30bdn{=Ij9coR-A=uF6(@92`$%prff*(3Sw=wZ7uCF7
                                    zUrZ0MOOJdTpUj)gh-dddJs#p@rZ+t}J(yv!-PGD1!
                                    zaf^?E^gWU+vDBEs&vUo8w$*-9r6cTfa<$60LhkPjpB`WW
                                    zG!F*o4*991rsiqdvs9aDHyU>KY8Rw)5V4o-@ixq-VYPC3P3wRVQiyR1?jKBgbcCFR
                                    zVX!%G2*9wusTGWdQ)m0)U7UF(B)C0>LYJCw&pwiti(u?5gi0}}GPxXYpFd!KPgjo1
                                    z>$s9pU{m|uC^_%!E<_#G1D^l}+GH*KfoMRH!7OO5quIR#!ot0Y+=E9fdG&xFVnPlQ@QDCj`8
                                    zNS#*1RkDDaBd!Gk6+-kZFio0>>Hc(fZ(7f0}#169XL
                                    zd!t*oR|v?-6A~HWuESdcMz2CCtdv!dHQVphL>oVV=O)%MHQiK$)Kl%d=rR*%Ly!1|
                                    zI05|9YN^FRfgJwce8G0_t-4~(BO68q@osx|T_grs1;LRSB0yRYQChVNA)?n`uyo2Q
                                    z0K&pgo4-)de_drYqtM@7BfgF+1XcuL3M449OJYS`!MNW3|8c)3QrHQ`Zai~MxL2GW
                                    zrwj{&t-)dnsh723PJ6>)N2_B+dpP8L5AfL#;t5zHtkU@W_E(o>?zA3f&gw<_)w{=_
                                    zxf^xdPw^;IEizZ6dGzS&WO>@#`#rZ!Rx*!Wowz3Ub#LScoAc|LnmeAJ$TCabu2Gl1
                                    z5;Mly8gqVrQu&l~IgBE=gOr)tNo;7{sd--ckvFj}+1jSy&x<32yKN+ZgLly6HtwpSm2G`Y)4VZDnV85Jgs7(G_r+Tu
                                    z*@Um>#rok9v+9Hb@uB|hn8#UN0;h#j9m(}J+YwbB3eZ|DJgvy~>@fA>T)+=cE>Wo3
                                    zo^rz8o|b>$EO(xj#tgvX#Nl&wsEvsf4jJqQzQn$y=k4dYGU8GR18TK=@o$
                                    zA$F5X-QllB*j+XH8Fa=t33*-0
                                    zEVSMj94xP@Qr+2iq!e_^f0{(=y8r4QpvhS>0MUXN3~%tBp62v8ns
                                    z%!g?f&EC8@!Xa-JxNziTEtr^@aWd{Yw%%V!X(b_IAtNQ?5@awhLLg#`3N?yNu4@7S
                                    zt!#Pi7w^j;W0)6<6oK*)83UE5GOwma7}b;k9Tzm}cFV2?K+SE7^kw
                                    zX8l$unXpg~{E+-~wEeZ=t?ju;pp{64KJxP|DRp*$)DCF-Vko20HtN|Xa9M5Vs1Rq%
                                    zk#77lT#6HbXtmhkM}0)UgT=3n@16GR-?2FQ=IJ6%@yqbL+
                                    zFf70ykPGa#+dtz)12QsXttLL2_v@>7#xwy+_1IUv#B>j=2}6yoadtN#k^KCLDH;$J
                                    zMcPVYs8MH6JKWtpys>s-twXgtb(;;TjlZYb84QEeQcG;erV4EW1x%w*FCCBS-vzPj
                                    zp1-S-FWb
                                    zHNU(ViQ?$4-&!`*p+p-0EW%}IxG7!I{oJHiNNXJ^3JVLkSWwXG9zR#-akV!UZ$9_B
                                    zu=qAk0w&1z;*`1g`YPfW;VCKMN$!>;YypdS@#$UA_^_Of&RwFBOdvU0O$w#j47QqAvSFsVoL0vO
                                    z2IdcKv3^ddB8{~5!XIPUVnrpu<$i>+A42e!)9(7l0Piy{w9tgMGfZS95YzfS}ZZv)5f^{}9e65(H&HLo!
                                    zRxL5=^3N!F-=Wcw|K4BIStC-PW>}x&SdhIQwfvCW>4M=)P1VOK=$XH|E9}b_*7l+U
                                    zQSY9}cuo(I)f302l^nMiB!z5X(SKIcoYWvi9LE}m5qxLnqw1s1^T-c+N8pNaM((t`
                                    z`8|(<#_gOAm9M4WNq{9cwJ4lhdRIOqjUP1%Rmk`alOHlCua2_Z?FJ;VEnq}!H^f&u
                                    z;@A56WCkp<%4ywmubW#GLn8)py2fZ@gM1{Hz+pYb^XO4)g@0gZsMl8Ivd)`1KOm7?
                                    zgO+B@*xTM7&tVo38yj0*?ow>r9YV&d{3bbqCht|{K*{TgPbD%8afQyEyc4+UNgoAv
                                    zFGW9w_NEH!g0=>3alYHhWd-Q#a_Vn2q;7vewnJVw#z;+V^w%##jhIk!{=@x2g~Yt`
                                    z;$9&*crfHFg0*vZXQ6F-JyQbjshG{AXt0x-ixi~E5=vlM!~?o|}}2~?GpmHaMS
                                    z?(-iW8)|qi#hb_{@w|TZkd3X#^WwB)VQo0KH<_QCnVFfJ`{-!ai(AWebE332iPymW
                                    z6zO%v4;XnEpC6tB5TUCab1bcef20(tA3HrG-anQc?)y?iBuVkhzgI(r;zf=!Ef-gr
                                    zT7eF_&)iHc9Np&`eQ#G6lWv{6s%i}0eDjBUdq8q6wNMKt;r#shGwO{Sa*Qsvwm-VM
                                    z9PQmqCB>jlG7(YX;r*Giv3XkMB)8wYd(lgt2mJ^{GG2<%v4C1A<&=`O;KuAdT6T1C
                                    z5%xGODK9VI-QQmwEVUR_rFaY`rnMCd5dK+k`y&8h;zm@#H0&++a+~&vxboS}Hy0Kb
                                    zimnleM$xNene?V~#xOIksu|NyoZnVo^f1~}Q$Z&n(`J2-Pc8ZJKHL0Ao|b5UR=G93
                                    zLNq0qdNbrqZ3GQa`#Q(RHRzu!DD+mJ@*`{5oj1ndM_ZUs&y&SiLPpi0ZyI342ydX@
                                    zRP6{R5~n!iB(fBeMW9kTkv<2&^WyVk-0^!No3fM(cfr@
                                    zHVylS{Cg0Kp2+|e2kI?y!U^!a42_i@(p%~$~BggQhuUsy1d7|8A>F3X%^U9An59AdUeTyBcPY>Y8
                                    zsgqnh(U?W3m~mx=qpg#NM^BOyl|rxBHKl~XVn3ETt#iRJ`oAweVXV0;azh%w_VZ*$
                                    z!at?fkPsdFi_<*NtDV5MOJiv7?A+55G`ie9S!g-#TT!v&kDJO+Q^slW2pf9$uD(p>
                                    zW}%(i`73s*b?Ah^Gz#tdP)_D|rc{2HlY`O6?x(B#h)cJnv7%yY>*=UeojUiy?rx`F
                                    zKdb?Ct*o>M+Dpy)?jd9sDzV#1N~2lbQgvukl|TM|adCAu|D3hc-rPLFzfA=P2WQrU
                                    z*!7pRvi>|TH}@z&{WF!3brz%Fwr#Wpg>}C(x
                                    z5+D-_0!r=u{hwfw&v0-Cezo85!*g02TAAWagCG6K*VbCjZ3A6$y4Ed}LaExh`+H-j
                                    zw^jdwZNPiYZ+?3cLvvja<^^~Bl>iDA-}H4lSQSt-($Ii?_lJf6{Jm`+Y5XV}LC;9k
                                    z>wiJ|ummYI46|4*DY-wQGD)S=M?^Wccjl%tAz^a0#cy_S4O;h^Iy8fbtZ=XsFMIe4
                                    zSk#~J&4$v@Z-W8vST*)z93cu1
                                    zBA5d|V+*AQ+yd{j#+kd#y=X7q4V_9MWT1&FPy;{_#XbCH3Gpx{{y
                                    z^Q33JcW=}L5zExZT>oJI&Z7CS&e^X>qgELm4<~m&tYm!y1nUS93Pe)@f8nNz9Ba*2
                                    zrm&cp8HASK_DVejw?ksr^cvqb3(UuW`N6?eZHXCIKg}-EIP~6kn?XSBJxtyaSBh#5W
                                    zJ7cW)Jx*PK>mrIl9Q)J-IdgV|h$LnX+y*@COL!Xq>3(?0d?#14SDU~S2xIC5-cM`C
                                    zEnH8zn3f;m4*9QO%=1LdSAi&F|KOi4n@zn0|KiFE|wToM?cHu}6SPrx3CK#sA2
                                    z-Od~k@$Q7$YG7na1`A{<=pJ0236A7noOOJlmhAcvOg;=Wj?WTWTsA_6-@F>$$$|E;
                                    z*b$wlQ9J>bQP6h@h+P|+o;`zu
                                    zwRQ_8sHi0Q>O~$~Q`=(x^5|$aCN=EZVAUMWBt9VEVBzLg!?2rce3^OPMi~m$!FDIB
                                    ze|1F^{XEg@7z&f>8*j)+)&w;cCvscqTS8SZ)oeHi^t`458(OPT4@D@cHR~6Cy5rZ|
                                    zZ+Jwt4i0K(b944T%5xHjs3+8BV?a#(DMFbd{xF>XD%27u$K)Fkkd1ioEptW*N4K=Z
                                    z?HhXKCDBxU{8pZkR7)tGPzk+-U39HKL`i`N^xjDinvnb(*HVIF1Xu-Qq>?3iQbXFk
                                    zGNC@V`{)Jh23LY0eo9onLPUyqRtFMsvgs~v=Z{`u7_f?C-X(=QiG1i&4YaMpD52K1
                                    z#G|3R>E<2^jGVaFhfQ65M0$Y)&tTt!lP#gMw=nNMq_he)MN!T66`xc3)b{$;$~%f#
                                    zHK0Y~4TiGCqY%8qXO5ydEc31fLZb-d{+l5=Eo#l@@i!qJ{fdFMn=eW0p=k9p*D}B6
                                    zr?%ofm9G%U{YTeX0M^&Pg~u}zFTI+Z4BKTWSg)l#!apa;p+i(N+Q_47GodkD+JUkqgYfon{0s
                                    zz+zKkIa4z}di|vqL9_U5xhL7j$0s_q<2xAv0Rb_wNoEYHYE~Qa`JvMpxiz<;nXy-s
                                    zAMw(!UnS$AQ(j;Q_kor^*W|w(gjb)xvcnj3
                                    zsd>(`e@x6E7eNDJ2-q*ql~E>7muzm?yW@S)w~z>|+decC
                                    z6BDSfnJ%qEqc_T!J$v~BAxrk$sY*bI@z8`)N_SV_3>3b^^OUrD&*mNAcDWT
                                    z!+-A&P5SLfe>6(TM}oI4t3{DG>V6amcDpS;8L=6MoQhRGJ=uMilwS*d3$C9s+x3_8
                                    zh3%`~Dk&*-Ed2QKW57ma?#(2`4}fM!iD+mO;%|i-TpE-Swe7!t(m=*MMxYS`+~G~I
                                    zlQw(`_Lu4fa_PEVACb2NxG5F^X|-pguirx3k@Y}^wZ1-32(de(*ls_#Yq{x+(uW76
                                    ztN+pgUiqex>xT!LJaBw8BqLBGBUm!CW-ze=ZJn*v5T3|nelJdzdq4v5x>E3YN2OU#
                                    z0refLISB*t0kwiGO(Z8uLRQ>$5Sg3Qnsj0QQo&&30-|QE=fz0#2khzT+|h3u%t+K$q})G{L3S+b>z7jzS_!Nu-kCr${O|qI+vty>%|Haq$uaAQprBCT<>7HZ
                                    z(*6}r4g2t685py@DRTItJiNSE(2giJu$cqO87k55qNbTCA+B#PeA
                                    zElJvhx#@i^o2&iGyPJtsPKl1l8K14`8~5(YV?fu2a{4PBM2@z?C(ACrG4VQ?$1!!5
                                    znmbW)nuh>6R;ukBnfosmXY^qwL=Se_DLDKi^fTRg$2O3Z0LZMYZ~~$^fJ4Rd$>m&D
                                    zryO)EHwSN4JQYX-_1sM%RpNLg#lRVQTayr<%9qFCQ42r<}y6+E=wNUpWcayTJ)CK-Y-{nwwdXbX+ReZ4h|M{-OVtA
                                    z+1eK3QPI*G{j7g0e6b&iH@{wh2nh*^p)qR?z`wk_tgEXNzB(_)qoSt=5gjgO%@R}4
                                    zX908C8}Zs-QPS1b_42yv>r>2Z-e}aWc9w&|G^(Ag+}+)Q(PifZJP114r&vyh8{u;uZ4#N4
                                    z+5(YHU#^s<-*nCyyi-nZ<4(LZj*iZHz;4W>Q}bqZAhTEa%KaJbyjSF&y@Nw4zyP$e
                                    zF(1LV+d{}AXpD@F0fD-OOY!21B9xJ_Q}2nPi3wva4XjNvs3}sr_|I2bB%sr%Fm9F
                                    zxVX67_iux1sAN4io2{$0yC)S&aR(dQ!P)un=m-#ie5TGUY*GY1t9qdxpmt6ExVRV?
                                    ziXkoWF<-=Vo0(3jM4-oS2*f}Uq^BD^qXjrg*X!Z{ludNL&!V%SANPV?7?m;Me)bF0
                                    z$zy5*PvYEbokv$Au2J`P7JRLSw%DZiaz2O^6i&JTvu<6@%Y?TBuTRamFSdy@(fas9
                                    zf}-L8;l2WIeusoZG3D}LRCmNGbOwf74Ai#h{U_X#zz??M2SsAu>g8kgDjNnRN(
                                    zArhHZ#T8n#Y}K{Yo#^rVix#F#;kY%WQCXjGP07;I(kd!=7)uEXnSg=F>x#%;CT$#e
                                    z5q94R)EZ!?*LHH0tjQlecI^y_@LCAw1`IhiK7PDFSJ;C4ULg<{>0H6W1M9&3U|3BT
                                    zXd}2n$9jNepX`R-5O^XRio{Yzn^67%b#x*Rzq?u&r@H$?0sb#NcCd%
                                    zSqmgIc84|!mpI%cFbIqDco?|HQa%>smg8-8F<98u)%DbDFEECepC23goLYRv;V0^oAc6+r-K~kw>FIf6cXz&A
                                    zd}A~IR?0sj@ew7{o8YaES)oefBJpd|kGfPr_Q6&?#Bb~9lkZNGQx9wVSm`Ja(891d
                                    zF5w5mJ6{nfbT0{yq(UtRKpG*i)M@ZmPL506@q9Ivb?wSZP`$vNndS6{s;g0b?S(Kv
                                    zpJR-8c~3efZ4?w>l}foIk+fP~AP(ksWPP==NMRkZn-&nvHtk#V3#>nbwjNUUER!OV
                                    zZRvdpJ!(s26@t#=?b|x534zf%5B6KPZUH6%?)L5-RZ{ZgaKS8mxkuLz?|+btvH;o<
                                    z?Co1>KRl44X=-0xTpzWWu5_?z3EZ6by6^#J9uI#x{Ne!fI}`9gkT*#K6$j!jc-(*M>q0%O!31wN`}$Xiv>#Y0w}uD^xZ#itRce-Y^!Ll=>mr=y
                                    z8ovTM>+k!#r>Cd#&CY3!D`^aKA|5gK<@TJ4XaLF$p}if~rREPUweWIm%=q)4&ti(o
                                    zu2VSsgCB;5__fN&KnfB8Smp`WXq8i>4dTKS00Cl_S02mBtmo$fM;r0U;o6Q1NFUn#vw>Yybb^BS>DBp3?nz_QPy%P9A08$q+l^b!
                                    z^3ptZn-i&|+*>xI`Ku}lf;&724nQGPWUL%zRiqA-l;x8(K})D~h}HG-Xv|Kn+gmR%
                                    z2_ffSUmB4+SzYYp25Hm(i(ppN>QWSmFCJKa074M`2b+x5&1YkYJaUYYPd>jwUL9JF
                                    z+e^nRCMCUsHpjEm3&P9HrjFwy9|zfeDjU_YQ2LkH81reMaX<0fI}FM4u$fc20%DD*
                                    zyQaa}+10UXn`$~{EPu%zd73A$D!)5loYDgU!rD3?AQh)&`O|#uV#&}gHmeC4sCd(R
                                    z3SH02NA#-$fZj6xj%{%oSoQS0*QuTGINurQ>e?99f%iK)xX$8&NNW{37v8LpzTU1fdo02&5gt+2@5EA=lhI{J>uN8D;De4Ni?7Bx$&LPpJ)a0b*{+T_-D@+KywDR7|W|D}4$I;+?ozrR%#QWgn
                                    zbmZ)(&rPF_5=yR(&H@C5RV4<#XcBMa{MJlUXRb5QFengQfc$zN_`OF5f1-QJz-XUt
                                    zj1vNx)&)S_^9dmR6teyS%w)fE{Z82Y4tay1s@^Dvy#o0Km4u!Yu+T>)ZM=%CCi{06
                                    zI}cX}=RgXPS*5j$IYUp4B@2}i?(jfu@BH^rNp~fK_cup)(f&h
                                    z)+V9H3NpvQ?<;XXX)d2}b3NY9&sCE`0CRWdOpuOP`K1gM)zT62%1nvnXM&3>V;x_;
                                    zCYbOba3yRg3Foe2O5Lu^9@s31OKks$ZU%Xxs2RBiA<#wO_xs<~+B)R{wCb|;9h5Yl
                                    z{?0t*z#u!IiC@n-W;4D2h*BDxEEDXY=6CF7p1MJ-(pXX9N|p8}Afk7An7n&&B;3;M
                                    zeg$%B1=?qWe+qir-P~HcEZ@XM`&oa=_|{v41w?+blxXLJE(bi(c0$IgnzJnnN{^vl
                                    zJ==}n@|<*Wx>hT81s{(z_#20Wqk9rA0umANI`xEwVy^~?xk4;XKjTepwS3dBy`IQI
                                    zizLleOHh6I3|#ZR_zhwC2!l2@|S^#>xHRN}x=Ps73gtamLFMp`S)2jEdF
                                    zqj7}posCH%c
                                    z2M4ljR|uQ}xQ&5fI#c5cpu5da_EuJv<
                                    zV?7XQIL?UT2|kzE&e8;Msa+x{-bJ{*Q;2har2o-jN
                                    z!)<2kv||Gq!
                                    zf?c?;FPgBh@FHF(cnuKZ7xwa$mj3bf#x2lVqDh|1a=iO60Fg;7mG7tPaE^ZV)t$CO
                                    zF`70}HN*H9V?PE6I~HO~d}J9EECn)`FY}z~QIm?|AmA9qmAfy&BQ-4wG|oZ~
                                    z@qk6J1T4w$^_4({Yf1X5lYpW(#)kr6jG~tq5H
                                    zG(9*0G=@W!alQFiqT%ZkUSC7RR~_UkMUDdS82?&o`@tarPT*%s^24-B??F{TAg7O!
                                    zN*o((3{~R3rodSi@e07(1Y63=ZT!#l;3|2MM&ob1lQH^9{ycXi!o3n;8Wvef3V}%I
                                    ze++Za4h>@*kpS1ZLn|C`NA43G<7Yn>FMLXK%*70BX%Gpj-{DCwVDgtHdL#aI8>|9}
                                    zqQ4FcZIFSVZaFOQY8m}HJl(!(1di%dJ71VP#{=wple|`1u6D15c$Tp4_WnBp6h#35
                                    z!O?M3cZy!awKD^c9fYf;pfQgv@(oF4{
                                    zn4{wg$YS{6U0opk!l|oWe;*gf$jr>nn0lgJ6m}{8EcY7j>~)Wb26S~=>FXJFf0FfPntRVk|p7J$H)x_dvYQuf;-H5w9Yn9L*+5qN5pO3p9!o>|A{sU>HT7
                                    z9*rO*-mcZ#ooLqDb~BF!7J;siD5aBu;XR-8A_v5uDVa3Bmr4Y^ULUytvH%aX8GJ-0
                                    z?AbF3uissqRLcuw(i$1BaR1kw|6O21fWVBPoA`rRdP65uveACjZPN%EvrQ~I01G<|
                                    zdWefyKnMJ9^7m1
                                    zwf26`b>8=!Plpe1UGtj%cw#)`9=~z(>7~N+hiH${AP~qy=@$~p5C|d>1cFe9f(Sn0
                                    z9ylt4K>mP8OFVn^K6z)xMF;<6sq3I0f^PKr5>FTx=Lk_UL->pEccBUld6jl_Nv>X>
                                    zSHkoNvRp6{;mfxlO*hA=uqv8n6RTsRvJ)1cnMHm164}kuES9s^8P7x5Fsza@ev?j
                                    zp9eu8!&H(G$YvxZ1ak8K!Pin#zL7wPW2vQctUsFnD6`z8ZQ+chEDQEtU;p?-lgZxhd|3*OH2s5h`XmT9pFask{%_X{VA_R&HvKWtXk
                                    zzSdTyV4`rLchrKc)|2}S_Q&YXJCn+qu#S$4$;#oH8uRDjolgWS%;49d(7+6Fu~Z(5
                                    z^HO73L_|R{p;P--naN5Er&U;X7^yfR>vT+Ns*)M10WR(uWozDxs8_=ml=f@Z8kL**
                                    zBl)=^x9)9UWPGusmYI4U(EQ}%JM*TN?pE=rRT$$C5_+yVI66uzJr^}~=UlV=%Lx6IZUVHpW!eDty!@ZyZXgJIzb$G*}codC*)=4<~A70v2i_16}6dNH|^adU}o4{
                                    zdHA@7nl87qQ-PG!2d~B?Uy{T=6tiSK^#-Pa}S3keY`{9G*0wL#J|5zrva59m(
                                    zS-rF4p_Q>>tYYnI(oOl|C_koqUkxjz95;IzMLGdaJJtP@`6i=
                                    z>tfS$aA-!kpWHT{PQDu9VN!jRrTSEJ{%uH!9tVeZ+jlj&l*j8Us%#V#49u2(K0emN
                                    z^j_j4Uh^%8nsL!l))?fXbTlh!JCh?As$2%5{DdD)v`P$?J|gcm+``kzM6{a0AD1I3
                                    zrn8Xl`YSf+rca-Knwy{9Ttjzugm}!bYi#DQE={1~@ej$aBh&QF>Ya@Ju!Wq-sw;Q)
                                    zr)eb*?AHi+d3nRaFp-%eOZ8tgvjgLt-O$c0x+$d%hUl2)3EB${yhyqj6(!iBlFz!B{L4pNIS7t+b|N<>;Px
                                    zFD8edKYol457(;~73_`V>ppG4xM9f}9OAlywqLC!4B4HmaHp#!sIeo3*;u){gLdUh9;bo`5%QI-5mP
                                    zAKR>aE3l&bR4n134XZg>)MKC{yZZ3>@?@&pCn4d$$*C%w{Eg~2WxJj@aUrKCH|I;$
                                    z$82I=o|Vi!;Lz~8IVlMjeXLZ1OGLD0x8xe&E3vlP-P$_ihb?yNPQz-QS6^>oX7*G<
                                    z!cwN2#ly5lEdLv$0r~X8E@lF1Xx%a4QQPAL~FdnjBnu=U>Fb4wQ(Lj8m=jw`tFxRtGL^2
                                    z*anx0P0ds7+1MOOlCe5Ht%KhPdF;1t!eHBEB6^oyY6zXr!U+q;g!Yb;IjGDo4oMr`
                                    z6mO6EyF4z>$wb}NP?V~zL#=1rFON~@8n1**erlF~G|?>5t?xfS2o@3E#BZp6{xV|j
                                    zWUJck)Ka_D=)&Dg*;*nYiHWEn>+MLcm6cUPgTH(ld?MtLxF2?DsY+jR?J_vUkNVFF
                                    z^vU&#l09bg?myggJ=yG?ZPaJgZ_<(0LMBEy6ZCatfa?WR+vExfs4`lm)YjIH70(rE
                                    zSI>o!l3!dj?n~@2kxXx4n*^i~&D$_iN}wF{urU-B*|@$R-k7fSYfVB*5a^Wjrc*7R
                                    z!lWenmr&
                                    z|3lJX1f1Vi5w5tnQM=PF^GieLr#r{xZ`eq(6rSQGWFqIUu8*7ijEd+Nom!bszgh|p
                                    zxVdu914r&`Zbk+|)N;PumNFSNEp7A7X#)&qDUCZYu+-SNg-&5))O37iL*=`FW`jq1
                                    zvvRnCCs(iQJrF@z;)F-XD&q1^Gn&@=(W7uew%MpX^VSs~pUgOxr1=d^K86jcX3xl6
                                    z1r{Rc_QcW5@73x};(IJ6IypWCxy$wz)h0a;$UQ1f;Wrp=ZuKAT)vvnc>C45Lth9c@
                                    zTT9}7s7y9B2_KP1X05KXBtrA*~?9BjFhZD&0nx#g{weL>j+2+h99o8c#
                                    zikCe;M;=sSQ&KG{DGxfDxbRg!J~${R;mPwjT1`1WHF0fQpN&{794liuAzQ>!3r4R7kX#nVdw(alR!{
                                    zFhy5Q?G%>SDq|Q-7|N=1Ug>h=zt*pBF)=vvn&cjFN|uc;c(!A4hA&l9Hhn<>fq%_K+n*9VGS;|A!Vyb*SE`w#@&Mjd%O5+7j_@
                                    z-#Pvisubbm9Q0*DV7@1!^-mRTAI^Q9O6SE385Mw_rs9pza=XfOUu{w
                                    z?;riZP5xA@#6&>Fc9s53*%A}jR~Q)nrDRvl5Fo=#8h?|$AwdFKCG3BxVfzYjH@m+E
                                    z7X*>&c*3GV{FhV~xEmHf;ok&vCJ-phKrsFph+R)ufWUqd{Fj>cR^oV$PU!zHk!>7C
                                    z2-J7jzh3+WPRmyiHR$61Qs5lVd$crcpQEK2w)k$#%|M95naQ~w@h}vl+~sGGTJi?|
                                    z4EvDokM)FxDL_1|N=ivFVtsFGlb^zEL9=82NJ+r6Tw>6gv#7tmN4~mr86|W(ZV_Nq16?b7@zisucyTBc
                                    zt|zWyG%KTDB$Gr$0ve77%@q47_L@kjd|$kHad_Zz)j{;!aYt}tcjf^y(?r9?OZV$i
                                    zAbmWd(c&QN4R9MU{05gRiZf
                                    z9VTX&R>S-0NU8xlyCHw9v`qaPi?O(FBcO`Min2R9a^fyzP>u=)fm2&1Ss`iT;SoZIqL^$Ybx
                                    zb}rUP2vsS4BdGN?Md_uRYHJ@*ODm^t_BhssO-u-MM^#nvPE1_Iimfbf0~wRfTKJqVjRRDMLRn?ivWQ!Rn;5EI->^C9Fz&D
                                    z;!?|rsx;3!&NqEidU_{lEC>d)FK{fDmtO(RXJBU5k|RHNyer}{+c41kd4x$rdANs!
                                    z+g4gZAv82a&~{!frH_?~$!!%j4~@q_-5AR5X@8Sycewv`X+zU_clsfdx&oPqYg1$6
                                    z?nZ7;F-Vrx*1hhr%=%3?NjA8hAsYk)Jj&9=A88=42M@+ZDQ&{lLE
                                    zWY&TZ|IS{AskF~G`3gsQJx_j|7;+o9NB6sQWoPtv`d4fl2zP%#3812nIo8jyezCzm
                                    zM8y8+X3x(vkD5kJ?~5cjT{w}~CRB`iX&(3DDuXjfp&!b@eR*J@^VeDMOnRoyk&WKW
                                    zX(Uf%dq=3!Mog4p!#_yIdQPFbd@Ft0V)<}|gn+Su(`vFAV@CODeg!`_G$>tScjhWn
                                    zK8ZuUcs3-AjEIPjM?{2*-mEIf6-dO!>$0;Z53%Ld)%(aE(-j-#k&(~t+ps_~K@d`s
                                    zd)9RJ7Iw}y9)UXSK9WPor$=7b=K>V%+BUtU!sk>J?T0H-|3W
                                    z9YX_&zq~quaVhkRUde$B54787OE(BH3d2X-g9CG6*W>G7zr3lQd)`&jDJeVIvidsp
                                    zPDdc4f_*mEbn`-{yD(nw?csc@I7K_CYm0O)Sh%?IO?&gs_TF3{55;~{xp$%}@_v79
                                    zB%iMjjihM`bn6y$+L1_fM2SfkXpY)}mv!`&1%=65>tw
                                    z?9U7UKC%lVTnpB~`3*TB8jqFRgNSW&iZA|nj4*Vk(qPDUscO{k&!pmA`)lzD%U@Y4
                                    zu}RHWy3{*y=y6g0F`9HFrXzzu^3OrO?DdZ#9V_H=e0138p_MiUy?(t=g2qp4n~6`Pes0`N(h${caWfd&Ty|9b_A_B^#h;bT7*E$%wog)uNS
                                    zsbXI88EK-Par=p~c=~`G=
                                    zFsWmOAam4V-rJgM9s)v}Or%@bk&)w%^vrKb_tGsRDcRXU9$|dDd~r1P<%`th1OX>4
                                    zR!bB+D`K0)cuCC=0Rp}x2&aEjTp&D(gk=97F)x)bnbKcG6<43JvlScmi;}QA@7^CF
                                    zV63M8>1Ie^Er-a|)re{M6AJxu65gMznHW)WxWCXblv~XCs&YC3=@+GPyNvX|Nu0?4
                                    zls2doYDLom=7Y+baaX6I*Q-fLUbpNN5_k3U!!qW%n#k3~MVfX&cPFt%@!z1GgstuHV#iY0lTTs6NxbgoPbk`dWz4YZ!&#`QbAZlaYu>JO+>)d4
                                    zje2xP94kxB=gL;JhjOtPk5`aw^pw9gjJz|(eR?-1&NHq&R+j}$c&C6pfbeAq2lXmo
                                    zbJTu*58oej4Di`lGn{L!d=H!Ra9$Wu&qccL#Cm@Ck&o?S4?Xxg%J%LyFL1VEouBmg
                                    z7D~BaZ%c)~oojHR6NM*WQ_|7#F_Q4%9i=}z;K^T-`t79?Q{1g)vf%MPHJz$;>_$uLUGc}8GQ*JM?TsGIAsa7mK=`M
                                    zm?3Ko2WmP<>@Z|LS_E$AKPZWbK4>n0YgR$A$bC^nkaAxr6(8|8BuW4x9@7}RcP>)
                                    z;FDnd=Np;BxAmL#%)M3Z-78xvqeetr=>ktyi9U%&(7j&fW1rg$@Tv|$V+pQ(id%sY-mO54bMlmCHZFyNPO?0NM
                                    zt!-$iTr!xDPBE3aNkKYlv`|~U#Bf#IJoXj0;bt7yBvuUSBgr3EtLx-IcGN0o%ak#*
                                    z>C}{XT%Ce!8+nIqc2?r`)jW?)G@YEB6l7$gOfHT$hWdq%>SX+U6Laru<`Jye8<7Mq=|Z1&(x`wRB2Vd)dkaS*yi6obT;e8
                                    z#?N1qAn1pUiHQj&UboydG@}|;m#}Paa-go_pJB!dMataD3ndkD+8!@;-kT+WPB*%#
                                    zyX0M)UmkDFxgUj6OIKQqRaIB3qj7O^9yYnR2jWE2%3mJ!i}_*CdEMRsv{9+B6B(p=24ANuJ)I~|Few~qhcr{yPrADDDWAyc;8%|k+^F2
                                    z_!5TqBE-ZcdiK*ubGn4bQC~dX@2z#%P`t-GqaK)4c?mI7@sG
                                    zEkpmg&t4MYagj0Rz6ouwk$R=&KM;z!m_j%D-T~Ndsli8=D-#)6`t6%DNaS<*>h<2<
                                    zk3hW$ic?nII;-B#B{enQ0EJ;|s*+DKMWMhX595`YLMU%}Qb=iTm(WvSw)jx^Ke+DS
                                    zk?`2om`!~Re>lmQ5H+uQa)oUQu{ySsVU`f)22
                                    z6%KsWp8-`T;q^@uPE3ff{R!GcpbiIGd3#RGt1B$i(2$9e%Ev)a=&r+b2YAs7k4|?S
                                    zz(AyCFf`EQx7}96gYY++RiMombGf%KzrZ#^LPGGNz5xM5*H2?~QD3Q03h=3?@-XqU
                                    z@3&1>UJV!NvM|2QDlC*A$y1z~oP6){u)H+V6h_SG`&GMIs@huA@#XnZ~(fQmyV#MXG&JW
                                    z(zpi%FwBqetnoMUfgMX~a`f9lt%;F|qdR5!nGbUM
                                    zqbI^|+5^Yp*wP~Q6r+~i;MZ?g9Lg7C--iA|+I2($hsl**$B=Tk+BepOI@gok&5?Y|
                                    z>G$khTs{02ND!v1Z2SRz_R4ub_1K;Qe}7hz-=!NUG_Xiz0)vxIyU4L_kJ412fkU}$
                                    zb@f=x>P1Hp6y>p#Y6asPtD|G1RX))w;h?z6EMBf0%TfEfFCzzw&(@+s8(ie4@E#mg
                                    z4q9hR(Axi=-;KDj@yO?aGXbv;WOaI(_P54*M1KGm(Lb)jtlWCkU|
                                    z+1jJ=<)1ffIvPi_Za$QhY8zvNwf4c9<^GDvHOKv8^^xmtw
                                    zVB>Mkf}$*Lg~!54zh*x_RNjrkH#4)%=Ybde+<34%He+`7B#GNDI7o}m_x(z&+AaL7
                                    zRkuE@rz{yXEsNcke~^_icZO=aFG*>kj%l1~V?a!0+!)?nIZ+VlHNNMNM9H{L_d1*L
                                    zLnrc_sdv^Z)KUPQKNhWqN~@_zTKVZ!nC9(ny^Zzk^;j%kSD5Y-Jgz3)dQ&F#-O1Xc
                                    znkM*4k25Hwu={oK8G0Yx-!Zyx1e1vX94lMhe4i7c}>Z$k6z={5w
                                    zvEI+zqG$R%m5rE=2=L>bR?!39B$;pZsj-Chg&#OON>RFl2#Z%<3e!NDZR)-048hqB
                                    z%l@DVs4M-m?>MO49|^^@!1I#X5RW4F>g6LKuAnL|(13+oW_)-yMwtGGr1v7eJ?vRT
                                    z%lzHwn?$s{e=<-gxxe~ViOlpoD7`?VrQf3URJ%nA!Cx|*5R!n-avB+R=O2JoKM!Uo
                                    z*LvQMW$+NjEm?EQ2toyn!1a!>MuLFVdP0ZvQfpMmDv}||q?dBeFnF3i0gJ`6rQld2
                                    zi~3D80t6n(lk=h}xcqaS0HLgX{VT|;k~(~bOw_`
                                    zA^hhg{>g()B!BO&U{GV*XZ)W0yZZTK*_RGGC?s1l2y$0-H~j-g<3H0J_#Lm5zYBW1
                                    zxx1@?ry{+;%q|)GsX6de7_fpV1Xta;EMBTr@GGFC-|Y)_BCY8&a1~^8BC!skL?eot
                                    zpwc)SgJSbGk6eja6%}ItG^k}9El0N1fL$E$)v2*vsA{}*@u3c>nhr_$|O*BuB
                                    zj)H@Oxs+rPjE5FW(oRid9|aM<88(+y+Oy4Ax%{4-oLpr!rSO^i+nfH>Bt9Fxve!Rn
                                    z8{K->@;kcjo5%!{v+q=nzpOYfHhC1Jh(pm{Yrm%Fwo_>X8azNM&Vm5+x&IJ;up-s=
                                    z=hyoLB_ic`N(O4|mVo@IFdHy}C2(9&B9&Nv4#sXR4g98UI7%%IyaFaK4|*gEw)VWj
                                    zU@*A{4+6k%AS|wVi2%b!Cva~lD_f5g>GqbKh=J0*rKK<13M`gyC_@dJ$In9TGg^5qK|7;4
                                    zWuAHRyH17I!O4mB9K5zKMSFaFoL^8dD|_bb2)(j;Z#ezgJiu)z6t6YOc-}T;8WX))
                                    z8zW+y1?(&%WF%AqdoAqnRBWmLV
                                    zEdkGn=M~G2^ei_xBjI0;No#9QNO=pAqE)j0qgNlYy`2oQ0MP1Hrt%s()5CaledrYa
                                    z7>P3lcjZG78pbw0Hv7`S60?UDV2n4XQ{}*c;JhO^P-&45a`>{gZoQM9zWV_jP#8cA
                                    ztpEoF<`c2^wyl}Z6J6pD_KCBuoo_C8QiQ_gQ>Smg`|<2G^3hWo#bO&R|ENVkAXQA&
                                    zak@CPx%i%${!i&fCRj1G(Due=wxQhPDpDckGay7KU@*Vec&)!U&g5b+d#kva>~!Ec
                                    zmFM|F{GBMMIaY(a-dtM!zxC>y<~L&=`(h_1PN1U3s}*6KoEFVxeY$I)ANMSiUVHsV
                                    zqGs|vUx|-t@|fbYy4Q$beN**<>)z%CL#UYi*~kc55!;W*nUwma89-s}bUMYWNVEX0FyTW?o^R!V#O
                                    z^4G79v5X?B`Ek)ryl!r~x9}9va|1_HQ>Sn;HUga#YUxYO?USvs&thInXLGl>I5^s`
                                    zjygf&$NpuvJFO)Dd016ubHvSbXR;CSMZh;aE;quWESGksHZU>k08;7yd~(s~=5>Bm
                                    z&2TWKa+g)%0f#-QNlg9!sRTxI{@7yvnHKkj7Od
                                    z$h0wfF7f;}{7^nS-o&N#qdYp1wTuFM1_V!yU1L}Ho-QHX7yBlZkWTkLqDOqzz~iy&
                                    zaaDDDxfKnE@7=(!M)OqDSTh}0R#)|!J?pJ!JcXRxm)FjqP0ewq=s#*uWEg2pEi}f1
                                    z0QPQd*rcHbJgCst_E+fR6`M^bgt(TedUy;&&x41bRqLH96~$6sI^j^>Z3}#?@Mo#1
                                    zjzZ4X2g{WpM}I>`=VjH{?+e5!Mx_ACU}sy$1vGXtr7q}bY2DsqC_AlF|2(_C80qVa
                                    zeSmRpJJ&?MIsC23a>6%^G)+A&k^7rII7a5Ynv)_A)*Z782Pe(gf!BI$Pimo`+4ku>#znXPE9#O>}f(~7)PyJ)3xI1mUvAsD~
                                    zoIUhtmHwkKPE1UacIZ-9KaYhP8_&tE+g_oqV_~YZV9*cyZ|!&2KH%V3+S#@w7whAk
                                    zXBLO#NCu^6b%yVe;^NwGjfyy*3A&wmdI2Lxsqq{(l-`XStU1{9>TwSC`R2yP<%Z$_
                                    z7=HpmrlXV0rYDC3r4Q)$PccDhsVLx&RZoVDl4la=j8jy7c5#8wV*ApDB6Sl9-7_AfOl9rh(E9t
                                    zCQU;pJqYkDo!t4AvNf=kpi@{{S~~3}7sgnQ?~gUK*fi@VpH=Se7F}M%0JBMV))m4%
                                    z8D~wwbmoMga{5O~lNyz$_zN0Y#J9wy3JS5WURjK5`a|S;WK?|j*(uukIFSsrV8=WS
                                    z$moQ`B~@QAQLb-pJlx%tm6b7SSeMwh|1n|2dM{oC;*6GAO;u$+53j4KAvV;7yu??Q
                                    z2z`J>*52NpEaY5d@Ts}E8Jm)Z#ssYSoaa>`_TrGDSZGK{47E9c6@^-rho`6T-TFOW
                                    z>`$LQ?MzkMfW})AuT@{NKy)=6paej;s^5+<($l|SU~pK_Yjn-d$^xiCKvYzej_&#G
                                    zA!r%Clv-D%PXVB&qrDv%Nid1o(>-r4k!7o_X8=L7|}p
                                    zQ2e@m0Lgx{n4WmH+vR9Q*VAo**FPd;Vi^HsVb%Y%xnqJ$?Y(ICU4j7yI6B}e`Rc`<
                                    z0ICEt;@pZnqyaX`i?y_H&^P6`TLi+1M!FjY8{TjTCl@PvnE?ghNg=lf)Lwc<78XgM
                                    zv5=6kzOaxX>;WiRnJpkzuQgd~Y@4EW%gV~YoA9|DE`w>Swwx&Y6*b5?vZ7F%!xrLS
                                    z3-??6++*WhiIs%2WMwkXlQvlweMPSZ@z0tiA
                                    zFddzpiJ&#LwH;kud~b)>S9_BV4i2Cwpk=&5)ZNo#ake`H$~7_DdGEu?kLYW$F)}Ak
                                    zUsFgld)`DvN4uSFe`~l7W@|DV$r}M!Oua~l0RZGs;Hos(8ZC4?URTOhNNHfwDmCh;
                                    zFdx#YvaB`k(&uAiGF@2di3j$=D}bT^#2N!Dy}h%89!I>;i(rt#FRac+N7pqvTJ<$*
                                    zdU{$>?B*Dj$kh|af@d;;r|iy^iX@_iOmMXK^*D6>HgAuSK@~Lw=Dw?JB3dIGdw_qP
                                    z-KSk<(E3qP^kR9w)u($XH`TS9y4TwdUoQS*>&qzIr}pauj7)o=;TKB6_n6o6tMJWI
                                    zIOSe;NK^zo9&|M3*|Jc$pH2*^pH9aHp&
                                    zc1~ra4vvv^*VHaaDZg4|RPOF4PO;pf_y}_0%-pdJd+x7aXQ66;(G3Z1nO-4z#n;bq
                                    z+7LQXYoA;F`vORAkw&Fz}stUL_|byzQiHk?<_@u>CQHGxa(?|5>UH>r2|V*
                                    zj}48YUKvaj5D);Ndvgd{z^B`_COvU580?wP{lvONZ^H=6r-|j2mAYWUEs7gYzoWCs
                                    zC32dK73p3ah9i*K8(8PoyhUa}ELVeJ*VWyNq!V*zsPOlKd3OSn!z0ctfRv3pLjdn>
                                    z#j8SKC*MZMc(H1ajPDVFfB7`V)S(W>ySYL+dg9#1$;AaCFGf~~sF^yQ;z@8izbPjw
                                    z=bpL$g%Oqh*95MWvIJx*3HImcT2evjFHCt*%g*OCJzxo&YZ`bQ_hXQOYYm#P5UW&k
                                    zO<91zfEfG*>6503w6s}Kt2bG|LWx`lY@2g(-Sy`H#r>T{4WziA)2`JJS;?RlBlEA$
                                    z!S`_P3`DY~6%@|$uL)ifCTyVhyh(Oxap~f%*$^yvVC-5#dD|Q1lcV7X$2&ymc?$eZ
                                    zC|7dct^bWHzQq+J=9w{lEPIFT#pPk+>+|)l@N&5s%BODp&ZMJE^y^E@%fqVqIRHSi
                                    zaXTdX`0Or)&v80tLP9}_p~fg8Vmwx~l;#BoDV-F!BP#8Tm(khYgTrmh1{YKkz(6Y_
                                    z4J#a_XebF8dw42wY)4iQ7(_&?L>VM{KWtzy
                                    z1&0H`P+BLdQk|JVdUOhK4$A0EzXJFLH1Pui
                                    z$75o&UE=vRPa(A5OHm45Wy>f6KP0>DJdCaRnpg0$r+O~c`Dm3irB4B+6j*40i7?jL
                                    zkOmj{ESBImAvafRiV6FspodH$vD9gOC!OTv!h*EazYVJVw#<^1+;tHAw%Z6=V
                                    zE>Dt_O1~^=+nl_=y?G{>V)YN!NHkfmTDds{%qDtzZI+f>`E6O+E#5D1G>A0gPQt0EsN~0STR8u+
                                    sg3_&sv^;>MzxubH>HqlOI&Q>1EF66iWl7ox|F8m)mQ;`^f*O4MUjqAbSpWb4
                                    
                                    diff --git a/uml/lumiera/131077 b/uml/lumiera/131077
                                    index e64895446..646250274 100644
                                    --- a/uml/lumiera/131077
                                    +++ b/uml/lumiera/131077
                                    @@ -1,6 +1,6 @@
                                     format 58
                                     "ConfigQuery" // CommonLib::ConfigQuery
                                    -  revision 12
                                    +  revision 13
                                       modified_by 5 "hiv"
                                       // class settings
                                       //class diagram settings
                                    @@ -476,7 +476,7 @@ ${members}};
                                           operation 141317 "issue"
                                     	public explicit_return_type ""
                                     	nparams 1
                                    -	  param in name "query" type class_ref 156805 // QuerY
                                    +	  param in name "query" type class_ref 156805 // Goal
                                     	cpp_decl "    ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}${)}${const}${volatile} ${throw}${abstract};"
                                     	cpp_def "${comment}${inline}${type}
                                     ${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl}
                                    @@ -492,7 +492,7 @@ ${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl}
                                           end
                                         end
                                     
                                    -    class 156805 "QuerY"
                                    +    class 156805 "Goal"
                                           abstract visibility public stereotype "interface"
                                           cpp_decl "${comment}${template}class ${name}${inherit}
                                       {
                                    @@ -619,7 +619,7 @@ ${inlines}
                                     	  a public
                                     	    cpp default "${type}"
                                     	    classrelation_ref 181125 // 
                                    -	  b parent class_ref 156805 // QuerY
                                    +	  b parent class_ref 156805 // Goal
                                           end
                                     
                                           classrelation 184837 // 
                                    @@ -674,8 +674,43 @@ ${inlines}
                                     	  b parent class_ref 153989 // QueryResolver
                                           end
                                     
                                    +      classrelation 186117 // 
                                    +	relation 175749 --->
                                    +	  stereotype "produce"
                                    +	  a role_name "" protected
                                    +	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
                                    +"
                                    +	    classrelation_ref 186117 // 
                                    +	  b parent class_ref 158085 // Solution
                                    +      end
                                         end
                                     
                                    +    class 158085 "Solution"
                                    +      visibility package 
                                    +      nactuals 2
                                    +      actual class class_ref 155141 // Query
                                    +        rank 0 explicit_value ""
                                    +      actual class class_ref 155269 // Cursor
                                    +        rank 0 explicit_value ""
                                    +      cpp_decl "${comment}${template}class ${name}${inherit}
                                    +  {
                                    +${members}  };
                                    +${inlines}
                                    +"
                                    +      java_decl ""
                                    +      php_decl ""
                                    +      python_2_2 python_decl ""
                                    +      idl_decl ""
                                    +      explicit_switch_type ""
                                    +      
                                    +      classrelation 185989 // 
                                    +	relation 175621 ---|>
                                    +	  a public
                                    +	    cpp default "${type}"
                                    +	    classrelation_ref 185989 // 
                                    +	  b parent class_ref 155269 // Cursor
                                    +      end
                                    +    end
                                       end
                                     
                                       usecaseview 128389 "query use"
                                    diff --git a/uml/lumiera/137733.diagram b/uml/lumiera/137733.diagram
                                    index 89c4838d1..5926ed423 100644
                                    --- a/uml/lumiera/137733.diagram
                                    +++ b/uml/lumiera/137733.diagram
                                    @@ -2,31 +2,35 @@ format 58
                                     
                                     classcanvas 128005 class_ref 153989 // QueryResolver
                                       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 251 37 2000
                                    +  xyz 262 25 2000
                                     end
                                     classcanvas 128133 class_ref 155141 // Query
                                       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 180 332 2000
                                    +  xyz 175 293 2000
                                     end
                                     classcanvas 128517 class_ref 155397 // IterAdapter
                                       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 50 241 2000
                                    +  xyz 46 222 2000
                                     end
                                     classcanvas 128645 class_ref 155525 // ResolvingFacility
                                       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 427 339 2000
                                     end
                                    -classcanvas 129797 class_ref 156805 // QuerY
                                    +classcanvas 129797 class_ref 156805 // Goal
                                       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 163 150 2000
                                    +  xyz 159 131 2000
                                     end
                                     classcanvas 131077 class_ref 156933 // Result
                                       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 250 241 2000
                                    +  xyz 246 222 2000
                                     end
                                     classcanvas 131205 class_ref 155269 // Cursor
                                       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 251 378 2005
                                    +  xyz 246 339 2005
                                    +end
                                    +classcanvas 133509 class_ref 158085 // Solution
                                    +  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 355 444 2000
                                     end
                                     line 128389 ---+
                                       from ref 131077 z 1999 to ref 129797
                                    @@ -44,18 +48,32 @@ relationcanvas 132229 relation_ref 171141 // 
                                     end
                                     relationcanvas 132357 relation_ref 169733 // 
                                       geometry VHV unfixed
                                    -  from ref 128645 z 1999 to point 473 166
                                    -  line 132485 z 1999 to point 292 166
                                    +  from ref 128645 z 1999 to point 473 128
                                    +  line 132485 z 1999 to point 303 128
                                       line 132613 z 1999 to ref 128005
                                       no_role_a no_role_b
                                       no_multiplicity_a no_multiplicity_b
                                     end
                                     relationcanvas 133125 relation_ref 174469 // 
                                       geometry VHr
                                    -  from ref 128133 z 1999 stereotype "<>" xyz 100 358 3000 to point 81 356
                                    +  from ref 128133 z 1999 stereotype "<>" xyz 95 319 3000 to point 77 317
                                       line 133381 z 1999 to ref 128517
                                       no_role_a no_role_b
                                       no_multiplicity_a no_multiplicity_b
                                     end
                                    +relationcanvas 133637 relation_ref 175621 // 
                                    +  geometry VHV unfixed
                                    +  from ref 133509 z 1999 to point 379 411
                                    +  line 133765 z 1999 to point 266 411
                                    +  line 133893 z 1999 to ref 131205
                                    +  no_role_a no_role_b
                                    +  no_multiplicity_a no_multiplicity_b
                                    +end
                                    +relationcanvas 134021 relation_ref 175749 // 
                                    +  decenter_end 830
                                    +  from ref 128645 z 1999 stereotype "<>" xyz 428 406 3000 to ref 133509
                                    +  no_role_a no_role_b
                                    +  no_multiplicity_a no_multiplicity_b
                                    +end
                                     preferred_whz 629 529 1
                                     end
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 1135ba33c..b8b4a681c 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3476,14 +3476,23 @@ Then, running the goal {{{:-resolve(T, stream(T,mpeg)).}}} would search a Track
                                     In the design of the Lumiera Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Pipe, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered "condiguration data" (including the actual plugin implementation to be loaded)
                                     
                                    -
                                    +
                                    Within the Lumiera Proc-Layer, there is a general preference for issuing [[queries|Query]] over hard wired configuration (or even mere table based configuration). This leads to the demand of exposing a //possibility to issue queries// &mdash; without actually disclosing much details of the facility implementing this service. For example, for shaping the general session interface (in 10/09), we need a means of exposing a hook to discover HighLevelModel contents, without disclosing how the model is actually organised internally (namely by using an PlacementIndex).
                                     
                                     !Analysis of the problem
                                     The situation can be decomposed as follows.[>img[QueryResolver|uml/fig137733.png]]
                                    -* first off, we need a way to state //what kind of query we want to run.// This includes stipulations on the type of the result set contents expected
                                    +* first off, we need a way to state //what kind of query we want to run.// This includes stipulations on the type of the expected result set contents
                                     * as the requirement is to keep the facility actually implementing the query service hidden behind an interface, we're forced to erase specific type information and pass on an encapsulated version of the query
                                     * providing an iterator for exploring the results poses the additional constraint of having an fairly generic iterator type, while still being able to communicate with the actual query implementation behind the interface.
                                    +
                                    +
                                    +!!!Difficulties
                                    +*it's not clear which usage pattern I'm after
                                    +*# client creates a specific {{{Query<TY>}}} to be resolved by an concealed entity
                                    +*# client creates just a goal, which is then translated into a specific query mechanism behind the invocation interface
                                    +*# client issues a query and expect it just to be handled by //some//&nbsp; suitable resolver
                                    +* thus it's difficult to determine, //what// part of the issued query needs automatic management. More specifically, is it possible for the client to dispose the query after issuing it, but keeping and exploring the iterator obtained as result of the query?
                                    +* and then there is the notorious problem of re-gaining the specifically typed context //behind//&nbsp; the invocation interface. Especially, the facility processing the query needs to know both the expected result type and details about the concrete query and its parametrisation
                                     
                                    From 23c03872989f4269f621b23c0d7eb253eaa661df Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 23 Oct 2009 20:08:58 +0200 Subject: [PATCH 021/377] Updated Entry-Page and overall description of Renderengine TiddlyWiki --- wiki/renderengine.html | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/wiki/renderengine.html b/wiki/renderengine.html index b8b4a681c..40e101913 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3325,8 +3325,8 @@ Besides, they provide an __inward interface__ for the [[ProcNode]]s, enabling th
                                    -
                                    -
                                    The Render Engine is the part of the application doing the actual video calculations. Its operations are guided by the Objects and Parameters edited by the user in [[the EDL|EDL]] and it retrieves the raw audio and video data from the [[Data backend|backend.html]]. Because the inner workings of the Render Engine are closely related to the structures used in the EDL, this design covers [[the aspect of objects placed into the EDL|MObjects]] as well.
                                    +
                                    +
                                    The Render Engine is the part of the application doing the actual video calculations. Utilising system level services and retrieving raw audio and video data through [[Lumiera's Backend|backend.html]], its operations are guided by the objects and parameters edited by the user in [[the session|Session]]. Thus, the Lumiera Proc-Layer covers the (abstract) edit operations available to the user, the representation of [["editable things"|MObjects]] and the translation of those into facilities allowing to [[drive the rendering|Rendering]].
                                     <<<
                                     ''Status'': started out as design draft in summer '07, Ichthyo is now in the middle of a implementing the foundations and main structures in C++
                                     * basic [[AssetManager]] working
                                    @@ -3856,15 +3856,19 @@ Later on we expect a distinct __query subsystem__ to emerge, presumably embeddin
                                     
                                    A facility allowing the Proc-Layer to work with abstracted [[media stream types|StreamType]], linking (abstract or opaque) [[type tags|StreamTypeDescriptor]] to an [[library|MediaImplLib]], which provides functionality for acutally dealing with data of this media stream type. Thus, the stream type manager is a kind of registry of all the external libraries which can be bridged and accessed by Lumiera (for working with media data, that is). The most basic set of libraries is instelled here automatically at application start, most notably the [[GAVL]] library for working with uncompressed video and audio data. //Later on, when plugins will introduce further external libraries, these need to be registered here too.//
                                    -
                                    +
                                    The Session contains all informations, state and objects to be edited by the User. From a users view, the Session is synonymous to the //current Project//. It can be saved and loaded. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]]. &rarr; [[Session design overview|SessionOverview]]
                                     
                                     !Session structure
                                    -The Session object is a singleton &mdash; actually it is a »~PImpl«-Facade object (because the actual implementation object can be swapped for (re)loading Sessions).<br/>The Session is comprised of
                                    -* a collection of ''EDL'' objects
                                    -* a ''current EDL'', which can be switched and accessed {{red{TODO not sure if I keep this design...}}}
                                    -* a collection of ''global Pipes''
                                    -* the ''Fixture'' with a possibility to [[(re)build it|PlanningBuildFixture]]
                                    +The Session object is a singleton &mdash; actually it is a »~PImpl«-Facade object (because the actual implementation object can be swapped for (re)loading Sessions).<br/>The Session is the access point to the HighLevelModel; it is comprised of +* a number of (independent) top-level [[time-lines|Timeline]] +* some [[sequences|EDL]] to be used within these timelines +* a [[scope structure|PlacementScope]] backed by an index, and a current QueryFocus +* a set of ConfigRules to guide default behaviour {{red{planned as of 10/09}}} +* the ''Fixture'' with a possibility to [[(re)build it|PlanningBuildFixture]] {{red{just partially designed as of 10/09}}} + +&rarr; see [[relation of timeline, sequences and objects|TimelineSequences]] +
                                    The Layout of the Session datastructure in memory is bound by several dependencies: GUI, HighLevelModel, SessionStorage, [[Builder]].
                                    
                                    From 455ad14ae5e2f3a31f362e02ee0650622235b437 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 23 Oct 2009 20:09:36 +0200
                                    Subject: [PATCH 022/377] set up some steps which might lead to a solution of
                                     the typed-query-problem
                                    
                                    ---
                                     .../mobject/session/query-resolver-test.cpp   | 32 +++++++++++++++----
                                     wiki/renderengine.html                        | 16 ++++++++--
                                     2 files changed, 39 insertions(+), 9 deletions(-)
                                    
                                    diff --git a/tests/components/proc/mobject/session/query-resolver-test.cpp b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    index 91f0df2fe..e78894b2d 100644
                                    --- a/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    +++ b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    @@ -23,6 +23,7 @@
                                     
                                     #include "lib/test/run.hpp"
                                     //#include "lib/lumitime.hpp"
                                    +#include "lib/test/test-helper.hpp"
                                     //#include "proc/mobject/placement-ref.hpp"
                                     //#include "proc/mobject/session/test-scopes.hpp"
                                     //#include "proc/mobject/placement-index.hpp"
                                    @@ -41,6 +42,7 @@ namespace mobject {
                                     namespace session {
                                     namespace test    {
                                       
                                    +  using lib::test::showSizeof;
                                       //using util::isSameObject;
                                       //using lumiera::Time;
                                       using std::string;
                                    @@ -50,11 +52,17 @@ namespace test    {
                                       namespace { // a test query resolving facility
                                         
                                       
                                    -    struct TypeMatchFilter
                                    +    class TypeMatchFilter
                                    +      : public QueryResolver
                                           {
                                             
                                           };
                                       
                                    +    QueryResolver&
                                    +    buildTestQueryResolver ()
                                    +    {
                                    +      UNIMPLEMENTED("build a special resolver just for this test and register it.");
                                    +    }
                                       }
                                       
                                       
                                    @@ -74,13 +82,23 @@ namespace test    {
                                           virtual void
                                           run (Arg) 
                                             {
                                    -          Iterator ii = subF2.query();
                                    +          QueryResolver& resolver = buildTestQueryResolver();
                                    +          Query firstQuery;
                                    +          Query::iterator ii = resolver.issue (firstQuery);
                                    +          explore (ii);
                                    +          
                                    +          Query secondtQuery;
                                    +          Query::iterator iii = resolver.issue (secondQuery);
                                    +          explore (iii);
                                    +        }
                                    +      
                                    +      template
                                    +      static void
                                    +      explore (typename Query::iterator const& ii)
                                    +        {
                                    +          cout << "Query-Results: " << showSizeof(ii) << endl;;
                                               while (ii)
                                    -            {
                                    -              subF2.attach(*ii);
                                    -              cout << string(subF2) << endl;
                                    -              ii = subF2.query();
                                    -            }
                                    +              cout << *ii << endl;
                                             }
                                               
                                         };
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 40e101913..1aaf3cdd0 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3476,7 +3476,7 @@ Then, running the goal {{{:-resolve(T, stream(T,mpeg)).}}} would search a Track
                                     In the design of the Lumiera Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Pipe, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered "condiguration data" (including the actual plugin implementation to be loaded)
                                     
                                    -
                                    +
                                    Within the Lumiera Proc-Layer, there is a general preference for issuing [[queries|Query]] over hard wired configuration (or even mere table based configuration). This leads to the demand of exposing a //possibility to issue queries// &mdash; without actually disclosing much details of the facility implementing this service. For example, for shaping the general session interface (in 10/09), we need a means of exposing a hook to discover HighLevelModel contents, without disclosing how the model is actually organised internally (namely by using an PlacementIndex).
                                     
                                     !Analysis of the problem
                                    @@ -3492,7 +3492,7 @@ The situation can be decomposed as follows.[>img[QueryResolver|uml/fig137733.
                                     *# client creates just a goal, which is then translated into a specific query mechanism behind the invocation interface
                                     *# client issues a query and expect it just to be handled by //some//&nbsp; suitable resolver
                                     * thus it's difficult to determine, //what// part of the issued query needs automatic management. More specifically, is it possible for the client to dispose the query after issuing it, but keeping and exploring the iterator obtained as result of the query?
                                    -* and then there is the notorious problem of re-gaining the specifically typed context //behind//&nbsp; the invocation interface. Especially, the facility processing the query needs to know both the expected result type and details about the concrete query and its parametrisation
                                    +* and then there is the notorious problem of re-gaining the specifically typed context //behind//&nbsp; the invocation interface. Especially, the facility processing the query needs to know both the expected result type and details about the concrete query and its parametrisation. &rarr; TypedQueryProblem
                                     
                                    @@ -5553,6 +5553,18 @@ Using transitions is a very basic task and thus needs viable support by the GUI. Because of this experience, ichthyo wants to support a more general case of transitions, which have N output connections, behave similar to their "simple" counterpart, but leave out the mixing step. As a plus, such transitions can be inserted at the source ports of N clips or between any intermediary or final output pipes as well. Any transition processor capable of handling this situation should provide some flag, in order to decide if he can be placed in such a manner. (wichin the builder, encountering a inconsistently placed transition is just an [[building error|BuildingError]])
                                    +
                                    +
                                    //the problem of processing specifically typed queries without tying query and QueryResolver.//<br/>This problem can be seen as a instance of the problematic situation encountered with most visitation schemes: we want entities and tools (visitors) to work together, without being forced to commit to a pre-defined table of operations. In the situation at hand here, we want //some entities// &mdash; which we don't know &mdash; to issue //some queries// &mdash; which we don't know either. Obviously, such a problem can be solved only by controlling the scope of this incomplete knowledge, and the sequence in time of building it.
                                    +Thus, to re-state the problem more specifically, we want the //definition//&nbsp; of the entities to be completely separate of those concerning the details of the query resolution mechanism, so to be able to design, reason, verify and extend each one without being forced into concern about the details of the respective other side. So, the buildup of the combined structure has to be postponed &mdash; assuring it //has//&nbsp; happened at the point it's operations are required.
                                    +
                                    +!Solution Stages
                                    +* in ''static scope'' (while compiling), just a {{{Query<TY>}}} gets mentioned.<br/>As this is the only chance for driving a specifically typed context, we need to prepare a registration mechanism, to allow for //remembering//&nbsp; this context later.
                                    +* at the same time, but otherwise independently, compilation needs to drive the generation of possible query resolution mechanisms. As C++ only allows very limited influence on the compilation process, which is always based on a common visibility scope, and on the other hand doesn't allow to re-access the static level after the fact (no language-rooted introspection), we're forced to use an external tool, or to rely on manual specification. As we're building a rather specialised facility, not a general purpose library, the latter seems adequate, if done close to where the actual query resolution mechanism is implemented.
                                    +* during ''initialisation'', a complete list of all specifically typed scopes needs to be collected. This might be a flat list, but may well become structured in multiple dimensions later, when using multiple //kinds of query.// It is important to notice that this buildup of a complete list won't happen, unless triggered explicitly, so we need registration into a system lifecycle hook.
                                    +* on ''first use'' (which me must ensure to be //after//&nbsp; initialisation) the list-of-typed queries will be hooked into the query resolving facility to build a dispatcher table there.
                                    +* the ''actual query'' just picks the respective type-ID for accessing the dispatcher table, making for a total of //two//&nbsp; function-pointer indirections.
                                    +
                                    +
                                    A ''~Meta-Clip'' or ''Virtual Clip'' (both are synonymous) denotes a clip which doesn't just pull media streams out of a source media asset, but rather provides the results of rendering a complete sub-network. In all other respects it behaves exactly like a "real" clip, i.e. it has [[source ports|ClipSourcePort]], can have attached effects (thus forming a local render pipe) and can be placed and combined with other clips. Depending on what is wired to the source ports, we get two flavours:
                                     * a __placeholder clip__ has no "embedded" content. Rather, by virtue of placements and wiring requests, the output of some other pipe somewhere in the session will be wired to the clip's source ports. Thus, pulling data from this clip will effectively pull from these source pipes wired to it.
                                    
                                    From c3441ac26a6d1de7d383e7f98f3507f16b89c1eb Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 24 Oct 2009 00:23:22 +0200
                                    Subject: [PATCH 023/377] WIP Query implementation draft...
                                    
                                    ---
                                     src/lib/multifact.hpp                         |   2 +-
                                     src/proc/mobject/session/query-resolver.cpp   |  53 +++++++
                                     src/proc/mobject/session/query-resolver.hpp   | 139 ++++++++++++++----
                                     .../mobject/session/query-resolver-test.cpp   |  10 +-
                                     4 files changed, 171 insertions(+), 33 deletions(-)
                                     create mode 100644 src/proc/mobject/session/query-resolver.cpp
                                    
                                    diff --git a/src/lib/multifact.hpp b/src/lib/multifact.hpp
                                    index 557e52375..1e15949eb 100644
                                    --- a/src/lib/multifact.hpp
                                    +++ b/src/lib/multifact.hpp
                                    @@ -146,7 +146,7 @@ namespace lib {
                                             /**
                                              * Convenience shortcut for automatically setting up
                                              * a production line, fabricating a singleton instance
                                    -         * of the given target type (TAR)
                                    +         * of the given target type (IMP)
                                              */
                                             template
                                             class Singleton
                                    diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp
                                    new file mode 100644
                                    index 000000000..990aed9fd
                                    --- /dev/null
                                    +++ b/src/proc/mobject/session/query-resolver.cpp
                                    @@ -0,0 +1,53 @@
                                    +/*
                                    +  QueryResolver  -  interface for discovering contents of a scope
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2009,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +#include "proc/mobject/session/query-resolver.hpp"
                                    +//#include "proc/mobject/session/track.hpp"
                                    +//#include "proc/mobject/placement.hpp"
                                    +//#include "proc/mobject/session/mobjectfactory.hpp"
                                    +//#include "proc/asset/track.hpp"
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +  
                                    +  
                                    +  
                                    +  QueryResolver::~QueryResolver() { }
                                    +  
                                    +  
                                    +  
                                    +  /** TODO??? */
                                    +  void
                                    +  QueryResolver::issue (Goal& query)
                                    +  {
                                    +    if (!canHandleQuery (query.getQID()))
                                    +      throw lumiera::error::Invalid ("unable to resolve this kind of query"); ////TICKET #197
                                    +    
                                    +    UNIMPLEMENTED ("dispatch-mechanism for re-discovering specific type-context");
                                    +    
                                    +  }
                                    +  
                                    +  
                                    +  
                                    +  
                                    +}} // namespace mobject::session
                                    diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp
                                    index dc0bd6960..6179f6018 100644
                                    --- a/src/proc/mobject/session/query-resolver.hpp
                                    +++ b/src/proc/mobject/session/query-resolver.hpp
                                    @@ -26,7 +26,9 @@
                                     
                                     //#include "proc/mobject/mobject.hpp"
                                     //#include "proc/mobject/placement.hpp"
                                    +#include "lib/typed-counter.hpp"
                                     #include "lib/iter-adapter.hpp"
                                    +#include "lib/util.hpp"
                                     
                                     //#include 
                                     //#include 
                                    @@ -37,37 +39,104 @@
                                     namespace mobject {
                                     namespace session {
                                       
                                    -  class Scope;
                                    +  using util::unConst;
                                    +  
                                    +  
                                    +//  class Scope;
                                    +  class QueryResolver;
                                    +  
                                       
                                       /**
                                        * TODO type comment
                                    +   * Query ABC
                                        */
                                    -  template        ///////////////////////TODO: can we get rid of that type parameter? in conjunction with the virtual functions, it causes template code bloat
                                    -  class Query
                                    +  class Goal
                                         {
                                         public:
                                    -      virtual ~Query() {}
                                    +      virtual ~Goal() {}
                                           
                                    -      /* results retrieval */
                                    +      enum Kind
                                    +        { GENERIC = 0
                                    +        , DISCOVERY
                                    +        };
                                           
                                    -      typedef MO* Cur;
                                    -      typedef lib::IterAdapter iterator;
                                    +      struct QueryID
                                    +        {
                                    +          Kind kind;
                                    +          size_t type;
                                    +        };
                                           
                                    -      iterator operator()(){ return this->runQuery(); }
                                    +      QueryID getQID() { return id_; }
                                           
                                    -      static bool hasNext  (const Query* thisQuery, Cur& pos) { return thisQuery->isValid(pos); }
                                    -      static void iterNext (const Query* thisQuery, Cur& pos) { pos = thisQuery->nextResult(); }
                                           
                                    -      /* diagnostics */
                                    -      static size_t query_cnt();      
                                    +      class Result
                                    +        {
                                    +          void *cur_;
                                    +          
                                    +        protected:
                                    +          template
                                    +          RES& access()
                                    +            {
                                    +              REQUIRE (cur_);
                                    +              return *reinterpret_cast (cur_);
                                    +            }
                                    +        };
                                           
                                    +      static bool hasNext  (const Goal* thisQuery, Result& pos) { return unConst(thisQuery)->isValid(pos);   }   ////TICKET #375
                                    +      static void iterNext (const Goal* thisQuery, Result& pos) { return unConst(thisQuery)->nextResult(pos);}
                                           
                                         protected:
                                    -      virtual iterator runQuery()            =0;
                                    -    
                                    +      QueryID id_;
                                    +      
                                    +      Goal (QueryID qid)
                                    +        : id_(quid)
                                    +        { }
                                    +      
                                           /* iteration control */
                                    -      virtual bool isValid (Cur& pos)  const =0;
                                    -      virtual Cur const& nextResult()  const =0;
                                    +      virtual bool isValid (Result& pos)             =0;      /////TODO danger of template bloat?
                                    +      virtual Result const& nextResult(Result& pos)  =0;
                                    +    };
                                    +  
                                    +  
                                    +  
                                    +  /** Context used for generating type-IDs to denote
                                    +   *  the specific result types of issued queries  */
                                    +  typedef lib::TypedContext ResultType;
                                    +  
                                    +  
                                    +  /**
                                    +   * TODO type comment
                                    +   * Concrete query to yield specifically typed result elements
                                    +   */
                                    +  template
                                    +  class Query
                                    +    : public Goal
                                    +    {
                                    +      static QueryID
                                    +      defineQueryTypeID ()
                                    +        {
                                    +          QueryID id = {Goal::GENERIC, ResultType::ID::get()};
                                    +          return id;
                                    +        }
                                    +      
                                    +    public:
                                    +      Query()
                                    +        : Goal (defineQueryTypeID())
                                    +        { }
                                    +      
                                    +      /* results retrieval */
                                    +      class Cursor : public Goal::Result
                                    +        {
                                    +        public:
                                    +          RES& operator* () { return   access(); }
                                    +          RES* operator->() { return & access(); }
                                    +        };
                                    +      
                                    +      typedef lib::IterAdapter iterator;
                                    +      
                                    +      operator iterator() ;
                                    +      iterator operator() (QueryResolver const& resolver);
                                    +      
                                         };
                                       
                                       
                                    @@ -79,26 +148,42 @@ namespace session {
                                           
                                         public:
                                           
                                    -      virtual ~QueryResolver() {}
                                    +      virtual ~QueryResolver() ;
                                           
                                           
                                           /** issue a query to retrieve contents
                                    -       *  @param scope or container on which to discover contents
                                    -       *  @return an iterator to yield all elements of suitable type
                                    -       *  
                                    -       *  @todo doesn't this create a circular dependency? scope indirectly relies on QueryResolver, right??
                                    +       *  The query is handed over internally to a suitable resolver implementation.
                                    +       *  After returning, results can be obtained from the query by iteration.
                                    +       *  @throw lumiera::Error subclass if query evaluation flounders.
                                    +       *         This might be broken logic, invalid input, misconfiguration
                                    +       *         or failure of an external facility used for resolution.
                                    +       *  @note a query may yield no results, in which case the iterator is empty.
                                            */
                                    -      template
                                    -      typename Query::iterator
                                    -      query (Scope const& scope)
                                    -        {
                                    -          UNIMPLEMENTED ("create a specific contents query to enumerate contents of scope");
                                    -        }
                                    +      void issue (Goal& query);
                                           
                                           
                                    +    protected:
                                    +      virtual bool canHandleQuery (Goal::QueryID qID)  const =0;
                                    +      
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                       
                                       
                                    +  template
                                    +  inline typename Query::iterator
                                    +  Query::operator() (QueryResolver const& resolver)
                                    +    {
                                    +      resolver.issue (*this);
                                    +      return *this;
                                    +    }
                                    +  
                                    +  
                                    +  template
                                    +  Query::operator iterator()
                                    +    {
                                    +      UNIMPLEMENTED ("how to get the result iterator");
                                    +    }
                                    +  
                                    +  
                                     }} // namespace mobject::session
                                     #endif
                                    diff --git a/tests/components/proc/mobject/session/query-resolver-test.cpp b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    index e78894b2d..389926ba5 100644
                                    --- a/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    +++ b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    @@ -84,12 +84,12 @@ namespace test    {
                                             {
                                               QueryResolver& resolver = buildTestQueryResolver();
                                               Query firstQuery;
                                    -          Query::iterator ii = resolver.issue (firstQuery);
                                    -          explore (ii);
                                    +          resolver.issue (firstQuery);
                                    +          explore (firstQuery);
                                               
                                    -          Query secondtQuery;
                                    -          Query::iterator iii = resolver.issue (secondQuery);
                                    -          explore (iii);
                                    +          Query secondQuery;
                                    +          resolver.issue (secondQuery);
                                    +          explore (secondQuery);
                                             }
                                           
                                           template
                                    
                                    From eb2d3096014d02e3d8ac51d3dc2fc62fe7ba49dc Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 24 Oct 2009 16:03:14 +0200
                                    Subject: [PATCH 024/377] WIP: reworked the design further
                                    
                                    ---
                                     doc/devel/uml/fig137733.png                   | Bin 14443 -> 15785 bytes
                                     .../mobject/session/query-resolver-test.cpp   |   8 ++--
                                     uml/lumiera/131077                            |  35 +++++++++++-----
                                     uml/lumiera/137733.diagram                    |  38 ++++++++++++------
                                     uml/lumiera/5.session                         |   4 +-
                                     uml/lumiera/lumiera.prj                       |   2 +-
                                     wiki/renderengine.html                        |   7 +++-
                                     7 files changed, 62 insertions(+), 32 deletions(-)
                                    
                                    diff --git a/doc/devel/uml/fig137733.png b/doc/devel/uml/fig137733.png
                                    index 5e81df28533b417b549890fd8be080d926d15aab..764c97c51ed0d6763149f40380f6169420d1f74d 100644
                                    GIT binary patch
                                    literal 15785
                                    zcmch;WmJ`Iw*|ZjWed_JEl8(ygKj}eQl(3jl5SyBD&5lEA=2F;Ap+9UB^{fP&JEv%
                                    z&-0x3J?}Yx&NsgCF^0pz-Zyt#_qx`abFR4pRg`3~G08C@5D2!MtdtrAf=UX3pzJ_V
                                    z!6#Y$bT)8u0;geWn3qh1bsUXN%_r8RMU`C~!
                                    zT6$Fyq{v7L>z}*A=YYVV_*7IyjqyCjK~6fTRvBEV@mi0&?ydIEs+@*={ragdsUkBHy#(yxpc1nIG1eZn{9NvYv!qC
                                    zpNS<`7H3F7eC
                                    za%0It&AmMZu2HVfQa5W+-l!ajda!>iADP`a8i#PCvbVR7VM$3zv9~{Fmh9=9UD}$_
                                    zPp}`!%|1e$yv$cq&2vZtJVo{d)l?Wk)ivJ-$#1`Y9!)!lZBK4k3xvBu|qT
                                    zuT2!gtwJZm7cZjs6SEM^B>h9EL2n1sixU#G78dNjel7C5d&g}vAM+c7-$+v9-ML;w
                                    zLPy7d!MlvrBZLs(viE$bb-ZnjWS#CBIi@b=E3E$y%ScNh)g(yH245hH%J)?b~eYU*1
                                    zDl95WtgrS~e&XKK%5-v>ag>;lnxU~Eyr|%6qu0MwPE%3-4|~rWwY!{>uwt&aAUx{1
                                    zC|8LDH#efssVhA?x;K*O^YzJ;1>wu_!WYJ|>L{$Xf=|;Q+1Vx0Js?$1p14_%?(Y0g
                                    zpMra%he9dIEQ`-ic2d}S?ZL7ww43JS%ob`Lm^+N#jV3>*d-Q&_Ur*9y=OWFW=l9XL
                                    zj^}=NtFXgUmVpqS8Dv~`E4bXo#>s~dbh>(?V+G?jCp!j5BT`cAlze7SRaB&s1YY~#
                                    zO;=OdIa_;eYuEGKyuSu#F6YhV-R0%wRrPPR1X{5&VIg)7h^?KgZSk;-4Ck|ryysvEny;_S;y6)83p7|7U&fwx{PMmxgo?Sma`fZVgFFhs
                                    zVuz(~+j3DPa5wc5)vUw?^z)BoEm!9kfrM*fVs5N9CAxJvjRC<}4t92)hs+J~F+m_B
                                    zP1GL^k{UD?q#=JK5SO#3NqVh>3euVWc-K`+0FnT%#5x%@by6IYzn?QH>=I!>N=U%y
                                    z28TbD@{y9}P*!NjFX3QjPM43tOcG?Wn)l=r5ZDSV;yKB?g&`dTxrK>^0Dtasuu5gK
                                    ztKHy?-0z|p?+S5MfM$r*IfMOuc-YVrt*<{IA}m~_Be*hA7QMWDKux`~)}M2SHagTP
                                    zfv5foDXN&(yxE`9^6{h22IA!S_{CM6v9LI@*p8vbX1>LR>-9ite31^W^i$5TFzVs-
                                    z_v4MO6pYW-8?0wjdt!RWKdWwsOBS=Au}IvRzVob%z)82GCz-QQwf6lr%)PUg!+y^3PuN)d7TjAwMV
                                    zAFh-twu=ybH~J;TVqA$uXKb|e%X_qj%e}6nRPpIpHjQfLB2@V>Q!3POmP;-F8td62
                                    zkWK6mKYDu`>{rycr)+FyMIJD(uMkuX@VpzNeerr8o%uE~KAq1g@`O)$U`|4!O2lbj
                                    z5FQ0VEY?B|?VL8nTy|zQwX423JVHJ8CqiLY%5%uqsqw4QLD58ip#4w%4KYJGvvYWo
                                    zzAlS@zXjHRSfzo^^y2luD&+rCw}nPXzlV?Lzt03o@3K}Oomu2*<$u(4m3zF@5AR7z
                                    zTz&sE0_tDiOIkxLS^V^exHLNt6~sY)@IpGZxE|aF&nfP-`9W(F-4bQZ48<4h)JDU{
                                    zr^7k(aV%LE7rXu*7tV#6WyuTE0Reb&m@kwNYWmsPx}LjD!dhCwk@QBd+b=ISF=-bU
                                    zo3U`L8GN8P*2EMSvzgMbiyHL3>muk{2}3AIy|yOW{IHvNczD(Z=HqvZ_6{>Lcu6@a
                                    z5eOYo{-e!l8yOnOW?5*N!`c7{24WbW)j3R4)6%>I&5%1A`Wqc=O_A5%HsL2cx_WxI
                                    z@2*Gg7J2e$#m11zgr}PSGz-|Dnmm*I_$`j>dSmA*8ZXoBh&7IDo_UrZ!X7|`l4{r+
                                    z`!Sd_oJ(iysLi(^lpLE%thQibIwWKp77!Bh-+Owv-PwGg*xPfN
                                    zo!@b&^wn|=n%x(@QAQj^;g+1SwXX!Y(lF_4mzRr^y`-Fl)~)UB}i{CGXy4-eMZ
                                    zbY;mXo0^zVNv0AI41b;KL-_&Vk^D!cH6Dl60A5qhzGUIH&d$j{Uo6o*V#zmX$pz>u
                                    zp2p+9U?13lm+#&XsyKp0zSr(BpOuwWG(qr)5ahPM!Q#@CQ){&>fmh5R!8x5bwkn-e
                                    zB)x?oIy0*pdMWX_KJ+mvHmx)yDZ=J{@csAd5p>>131TF$h)0C7_^myd!pTYzt;co(
                                    zP(wxOyLYaXUR8jPt8H_+Dt!U)^LE=h0(dlw>)+sMweNFy2FJfJDTvAcafCx<`v0Ft
                                    zgcYL+NX_Ff;Ete}AJ*&|ZQq74hwR1r5{PmR(Vf#BKN~UVYnw!zsAs{m9%6-F9d86r
                                    z2y4xmZZpQG(cjW;xD%UM)Q9myA=X%KcrH~O0E0j9+mMZK93MZ#>~U6RR#pt@^W0};
                                    z)(Q{|83Xiimi37CnK}y0G;SfGa@T{C;bH5<7Db5VJ(dq$V(zu=Z(QHKvs~b{o^$^_
                                    zm?4CV>w?9HX-lLnRuV~MCv>ta84!H2bGRY-EVj1Ji3A41N2;UkTd057J#HB&J|!iK
                                    zkE}vNLZp42UPEat$GpwxCKBLCwh9HcUlV0mK6v78?vb(12L&a~M*#Zvuw}V>V0fLr
                                    zO2(rT7On!fqg{D#GN<=+x@MO`V}H8_gMbisZFO}c>5VRGtH38ZoaM_iwuObVCb*3F
                                    z(F@;tCyRLYA;f&k$k&f$!6a7rFv}@EMd-r90yVja!__4&0LF^4r|(XGYn=x+IGX1^
                                    zTU}W21QpuHCmfe5NYwUML45oXEFj}aOT2`~=|Vde3?@P;amlqLKUHb&zQ25iL)Es{
                                    zH*I@j?bl5Jsg{GUF=nmP%MBZF@xYJkje9*c%NCd7^uHLW1meLWQH@=}TUlM%j-i)x
                                    zE#Mm85CKSq^|^?s=*sezs%LakL)TJNR7r^Q!__h2qu|h5v`*VZ5>i?JccjCTUhw6(0
                                    zbzvU+M^aMX{je|K$H`)*{hz;uBJRZz@xhzis6k59{ExJxs6<9RSKzQ_Hz2Oj*OeDr
                                    zVzWJ2G0vgI^Xlj4dm0*gIr1xG#VKkH#}#L+phovzA-l6=PU3|fd?NL~F+eN{A7~%{
                                    zu$5vM`Z;`9_Zrbe$Gow=sI-s9pbp4-4`DtdWqi_c1X{j;jgTvHOa
                                    zX%%`hvIJb}H#aBqnjR>zzP=hsGBP8Zu9xG~ip2v8Dk^l)~
                                    z)3Clni$ilY?lABY8#kPahkku?R0nzPaXg}Yz{^8@ynV6Zjgmqm_Wg3Z=4aV!xDFf}
                                    zqKVG(feyrjCAh8glk39AXeD+_=UcOISS0-oa+Tad9#0Rg^u&NdYvFhp(I__Am8X8P
                                    zL+Ey59hd64yAtOS8L70gy4rMUk7iMV0tp_RbEr~r^c6#>i~w-8MLZya4iO^xN0z9D
                                    zIkani0Pzux{zuE;_1I4SlUgA`^1*9npXi+X^#=~CoCzV982=!vQsP94egaTQ(&_)v
                                    zIVLbUBoGldVb+z<>>L(lgrZ5rVzdSj)F2+gj$7UfKgXlEj>RNaY72yZZoHeb?YIe6%)N;KEu0YW$1bkR4yr
                                    zw9{DT)EmZ*p$?*}b-V`&IxKvCrf{;MNV{owP0(`n2R{Ik
                                    zx_VA|%Gb0$nk}9NEuJYpcm^IvMJ2nxH1x?<5Td8;xJ&z^wwLdM(&kIOz44#;xfgSV
                                    z2VZas)yCk_3Dv%|+;YjOSNEn`pyZgSw_93_<4TKLNbN>^-&X?thksH?Y1L6tP$yap_g5rmXVVB^FG}=R_E#u!DtRE55SB$vz}{-#
                                    z?VXkz>jB0$^?7IzfVG_+Wmh;njH=-gSw8{n5OFfu8Eld2SuYQmZJmSQazVzc_9;LX
                                    zW}4s!O>pIPEH-t=8|dbXX^l%G@kO&tccTc`&;Z1jr5;F!C@2qDU$Vv}B=B2|L33<>
                                    zwQ_=}uXo;lvtsq`T}gjRm-vY;KTVo;b90sHfWDx!C5;C*K#{oEDa6E8?Dtz`4AytA
                                    z+a@cnt*0ul5_sdHGdLhPFnFDRW)ywCra-v
                                    z{`e8&H6einwS;>tp3(ZCH7Tbq7H)WfPR-NlYDEF7L`EMKo+meAmXgwTB0t<^fB8M5
                                    zsi5b(KsmqBeM5prh+5~_GQPKmjm^F8hwBMXL;aXbfWqa27fCPu^w?&|=;slFB6RJg
                                    z_15XZfGOBoU>QZo2COfCM_%`98fN}BBxsHJlQk)W7d{vKXQgKM`QFzT9HJ}cv>6c)
                                    z;Cp@A^)8AZl!|L0Tl{q&cytdQ@bVwYKi*#WO7A`Pi7w3IY(Eg~_Op=<-SP^DTtzHm
                                    z*pKA8T#IpUK=LPRcJl%Q{S7>-r2i_?zYhzG(-b1JF^OlM_21mp;NT92cF5M?LXLaz
                                    zm`3kMIY`mST+^1SW6rTV{^(Efc%QZ4R{cG9{PcJ4{;VprFc2dOqTOYOuSo`8;UV9j
                                    zf;-{wu5tNxPZ@uZ87Ne)Jt%Sv!qKGKjiKo2s)y2B$qPj?Tan!k+R^tjWKjEt7EfY{
                                    z%1r$Xy4Kgt*s441G0&qO$a)Wd4Ilx6F&q)hjJ9|#u7W(R?TbzK*{4EX2!Qe_2J75z
                                    z*xcv+@X9IYlI?pA^i6w=61b?
                                    z8Z2$#-rf%fTN?l!D6qEAt-rnBP(b36?r1O^Mf|Gn?rAZ(8lHVkuaZ~n(I~FCP
                                    zG8ZVpQQH9vo9hM!wYC}dD?R1x14)7P7Qj*Lv5-HS?YTp|EBv(RO^eg{5AoNt-kkRHnyf?EY&Iox@YLPvEU3*3#|$
                                    zC5>bju2i7L*4EZGdt7Wf)??sOuRDt5h_SI1xS#D$PENuCp64lbc6IGeR;(qMrUnKD
                                    zVcxyVS3J|*&BDgk+qqJ9fRCB~JTm*ok00P(fEccqH?ne(Ojg3huYPH=&-T>r=C$@a
                                    zR9bH1&!2gcrKYBu4y1x*ehDZLyjs0Ty9WV)cWtc@ZAX8KDEw&C>0niHY3l9I&vpxK
                                    zzUM~>HXA0zL?Uu>ZP^r90FQCc;l_w5KoqO`ywk=>UTErPCR51SXcS*PDm|{5c<$HV
                                    zLdYC0j;&}rwx?@iYI?#Ml~WtNu07=<-;Nb-Y;JxbGI{gnUjJ3U=xzv&84Qv0yt+KAcS0l<2xtaZH77(8-6JN>X-wrY
                                    zmfsMBFjL|1WxmuU3B}V9BKwMxldT(@{Rr7IuAlVTt>#I-JoFR5Q@vc{2^BH6hT1bc
                                    z6EB0z>}2tCYJA!WPaZPtn^a49jtlRyZKxEoG9_~{JS{pRhR?CD7(9%A4u(#*ZtH-Blab4;8
                                    z?&A{(BpjB;YHW&JOxnmuBZZvpQU~xDLW9EE-k{?BH(hjX+`voHZZX+kMtLPqqj+Zj
                                    zx9#<>kEwuby1Lq%nYpyPo_#<$11k{F^|51&x@-rEt2f^91%L+D>)!I@RL}8VgccK1
                                    zo)aRMQZzO)*?q3P9SH#L$&T^XBw>XUBIEn_&Y__vjv}PA9e@CCY`7?nxgy49fodGL
                                    z`4&?BwODPrg~@Tp>vEe=KAM*Y=q0{*fVp$e;b<45t7rST>8FZ$xS6$hri~U(7MS$q
                                    znf6mIY;6Hf!T{(IqoSX%u-qSo>t`|YS&elc{3vlaOD4(v=-sDV0Q>sPQIgML3+z%gMg5C
                                    zyhp~|doet+%b|1JUTfzO#4{erFb#WR+H}xw5lj-=ck)0EQ_R7{*S<`1A*iYYW@Z--
                                    z`4&C@004CMuJQ-ko%ORDLByh8G)l@nk3&-
                                    z`i*^{15)8|@pe@IdaEMlTwWh;W#o&gx3t*IHb$VxGXr@%Qu*$PBwadI5g)m&6l#<7
                                    zo4yM;2a==#Cg9Qu@YH>AdaLfPV`EYz
                                    zzeim4tR-40#sH~Ihz%PrTdt>1kS8*4wEFw{Ml>Xh
                                    zIuPaT5~qe&qXiq%x|y5ApXkjG*N0@nD7$-lv>V@*wX|ICEp>t4Hx?Holad+?zoL41
                                    zU7wzw<|xF)vOHhiZMoi=uCbAl^4aWse2Wf!DyP%N#ytCbkq)DElG~1MA|7lq{rd7?
                                    z5-^q~i}7S~{x8O+Yo`}24Xy`Yfe;HA&BcO$Qw#D~(nX1q*Thp-S2IZ-kubGrJ$
                                    z`8g@aRAOA5MzQWB_)EQd$1G+A_CS#5y^cmTbgC`MB-~E}37PzGsK^NkN6KDzQHeU=
                                    zr4V2j7IvMfwd)F_vY04+_4Fy|_Z%qH3K0d9TtiV5E4Bh+ublHn^895J){cSRD#4s$5}={RbvB~#c)oqi&@ygo|qq|wsK9HPe(Q~S9QK4@Dp95$|)M*T!(JqZsPOz(Ln
                                    zo)Y)mJ`ux!AdI9GqAUeuElcIvn%%m+i$E$`yZeztL}V(6110slzzGhPOc0TBvnWTk
                                    z#W?4D(LLX?29xkWKVtlUFZmH>H4#1X3dKLkJv4Mes9>i@(
                                    zXP3ixuqgE=LR#LnEr^jJN>;dAaP*{V$Ao)1lSQ5C%ejN63E{R
                                    z?XKDg-c%50vrcF*{Q3q
                                    z$GP|LS5eKJ+v)ENrMw#e1;l%2=ju}%QmI&DCMG5i1A0Nh@zK$j37Yxx0Ol+&|KSry
                                    zCBY;1Nr=lS!zlTFP7Tb5q)#h@OnYNFf=Ri?=FNwur!QLHqfv=CPPBNnENsJhd3e;G
                                    zKgTw8w71_sK9;awmIbI{X=#Z~y>NYHB_=-pv<-_(x5ZPOo4f3%#x3bgDWI+s`5>f&
                                    znC4SRkVxdgY>+AxpPYOuQ#u%jN@O|7r8|-V#Gk#B)61~npT&CcR&NxM6i!i5I8a7&
                                    znpsI+nI>s_yu+h^^!VNo>s&yr;;RM|)o(OhG(zl(!SmctD=lU1cBjANl&{2J8lJVH
                                    zyv`25F8kOQB++uJ(Y~)yb(0e8?AbJEo8u{UtAF
                                    z596rol!tU&lLTNOXNE@;D9Jw4z
                                    z8fZe~I?A75)IJQ3J8H?vd5d?Ytv
                                    z9Ykad?-0Q97BBPl__|m=3obt)k;;YYz-mURHrYOWE!)!mvXB5G5I|H$BXIFhV@W+h
                                    zY#%Xqrl%Ja_;h-)r@?no#p3ol>9uB4}@`}m->=1k
                                    zppXn@$*cwAwPu*v#Yro0j4iHN5HrZ(gO;S6r^Op~#ziyMF
                                    zTs#VD9h>x|Lk$Zddfz$J4GEIHIpUAss6)bhaZnb2C$8UGBKJokziN>
                                    zJ#f5ux-L@8Pn^^G`J3fMAl~qst1$@+^Yhr-fsXj62Os<9WFb@12I#jEMO~0Hb-P}`
                                    zGBIvobJop-w)TUJn6N@0`YF<0D-t!voSx+&!-~Dzc~g2iRAW5sX!B^g=|Tg^2O6>%
                                    z*opW=L_@iK_h>t+tz?o@rVScmt(%-sEfYx^F0!GRj(dwot9=yf^UeG6?O3G63CTPn
                                    zZfBtsHC+0-(*QC?MC1cbD1SEFKnA)DWFnP1YQy=Ul`vJlV%Qa?nC4Oa*1VGXQ9f{}
                                    z+}huFTLpy_SYhhymX5RKg2lxPKySX!78U6^Qqpqex!56$8=l%T4a8s;uEoVRUEO3F
                                    z@t$I}oW*aU7}eI|hn=Lmv8$|*Qa-hgt9%JQ0+KOaF|nQ1KGC_kD(CI<6#(VJ$qr)i
                                    zV0jKV{hjFOR8NhB;r|6~&(!hJ`UD48;AK7|(*v%kTxA2Nwf=eF5BgDO?d>tNSR~2M
                                    zo0*dg$?F{XRf#~J%qNRDeb1EE0qu;-UthEIn^2=7mG02K9rw)Dsab7uQ=BYYGBxhm
                                    z7RjgH^p*i6WG`s%(vlfm2<_{>Y)IjrQFlRjZ9zLvknzCRsTdz~3y|Or#5EtjN
                                    z(o-~5H9uGH^i*ZA_Zy+D>AOcD){~B(R`Q+TPk*5E%
                                    zTrM$kZnZPByU0x-8d~(X5S6zdmF*tQKbWa=D6km)QcTH+VyMjLpquTp+MiwfktWLG%N$-w~t7x#GH1gII=FH(!Ufm3;0Y}WvR1n42>
                                    zlc5TbR_gClz`IaaT3TAH*HElowFxo?qe3+QY!m#XVYeBWiGoQuIQ1KueI}Yc8rXY*
                                    zJ?Hq~Aj-H7Tq{p0CDQl|K)Bg&FMG1&$y
                                    zwL4Syx;#6Yc*Vu4bNAIxub4I&RlrJ2Q56Rl;}qehF)O_A(B$yGbxPKjAxeDCic+i(;X7Vcs1@9ziyv#_v8NJ#Wd
                                    z19-qn7{{Tb9&5Z5ctG_Pe5((9Y(94gt1Tyo3$=Ko7;-iOF(w$~STCO$U@bf|c+|ir
                                    znaOW9m>v-k0p3u2e7va34(MnC9=kbJg#abqABXBo^ww;H2DA*I9UB`PS|0$O<>iCe
                                    zd&i6Qbbw@p*ET(^(>?8nO|dgk_CzwcI}kf3H}?i$T8tF}{aGCd2Ee`NJvP~`r0(o|
                                    z3=WKC*WxklPyQB4K@s<}#J~%j31}!x%Bgqn-feW=PE1NlqL=%48(YNV+!3I}#m-Bl1zRX
                                    zr=B8PQXW42$RQ7e-$Y4HHFf|87l5M*FUY*g)g%QSgVb7%>aiiGkK?xl
                                    z2F5<1dxOMRidl}wXm0m8is*e`w~NZGKzJF2fXRPW=G>VkMIaj5tEi~JU>{<%F*QjZ
                                    zXqO86U2L5Bm0GgO9@e|;&H+V^)`woM$3xh`!9l0S8aeAS-*mQ`1f-20Jw4vWbr3rVK5~QfLb}5XPTzxYFZ;yx
                                    z!ZM+tpa8E;2<9Vz!3l|y#g}<8`1#W-IY&pw4FT4cwwj9b__DE8O+xP5(Wq+Z+QuJK
                                    z2&`M67wPkX>^i`8+4n3
                                    zs~nd|Z!B|{_Imhn`i_UvhKcoS?wUEKhA~QaQtmcXy6oy|#Xf&tfpXWB)iL|I(PPkguY$W(DAEL!acODPtwL)0
                                    z#P0<4Jk@e!qW>~5%E)lFfI1GEU+_aSLINIsCZ?0&9E!cYB#q*bXR`6{4%f+OJAi;9
                                    zXnlE^|GXE7srLwYj)t-
                                    z-rgSB=SyIM8>_bRXL_~{(s7Sm)a|Fz9E7ltd)%V*+3jVo0duL124Nc_Vw<5D5KWi{;3+pY_FXec(XezMv}JUTWuCgHQoNCtdQPbUh2!$d)wkDlc1
                                    zy;}b%%MijYui)Bg65HhbZdZpJMl+wcfge^qU(Igm8=6iH_4#73ORz+i9O%uf`HJCm
                                    zux{h$jIwYS&YyaIl4f~dw0C@bxR-ylS-|l|OG&u}v2tXI7z-`YM*^>-V9ahO{r9R%)KUlSrm8%nTSWW!PF{x;fR8UZCGar`bSr6`h?P%P9
                                    zTR(Z>B*S`^9GHM_0`T+am0SEaKjP15X{k&Gs3%KbS>0T%H2=7$+6
                                    z7q#!D^;zyA>54^E9FuYyHEXYZUt&{R+v>&XPkU$QFWOa+6&25;7~2_@^?^d7Lff&w
                                    zLX#rqItQ%tUtWri1Mf(6VZp1HH(|FFjsVI(heomG0+wE_?bciqlXf+w)0)zI<$WCN
                                    z?W;Ms!-o%y%PT8)XaTe!p}Ag|s%l8$hu4571C}46W?-6kQ6AU?zM?y{z)fBcA~MOQ
                                    zx)}6zKS@M?7-DlVW1x&>SrnM6pXZ*gE5fpj*q%XI`G~tJXt6q*r`)hT9exW#`TSr&
                                    z@nwN}`C$3}{(iA;-OGmKX`PyWD5jh6ymIix=t?d0CvO-AaGz|Ro{b{cv!u~5luEP?
                                    zHcDEkE$X27H*t~}KJW-w#ZyGi;u-~jNuki@dqg_zlMnKyTK}?rHq;8;eA|(+SBT$=
                                    z0xai%);-j)qSV9q+gk@rp59L?KACQsk+Ps-?60NO_~TyNcZDsj^u}$^w;TX(uug7B
                                    zpp5L-jEV0F&DB}8W%5BnBK{(+5^uhf-ne;7FCHw~9D%ROwqW?B43wGT;2*FY|&n`?cU(EMT?qZIp4`WN$n%NN}`cL1+J8}wqQA&}UXFS%
                                    zlH%}}bZ%ttsNjXB!Nerzg*N`G-Q@fnr&#YoYl)&373aIEQvc(HA5Mv}*r_|6;vT9{
                                    znRVZSR&fuM^v|{W^l6LwTy1vv(1nNoPa*MC|4tksKbO`;uG+(FK6fhWp!5Q5>$(u=
                                    z=Nnu^%pQQe`ahkE!(%~hwIjn>cq${KQ^qjWIplPSs}Txe=KNz=0S=V=KAqMsCM9_i
                                    zn?s~Gb2m4|xVPY`&>f61BQGz-ZvX*E7L%f|`~NL3Ks0?G+%>(UhW@SgE&8LOf7t3n
                                    zNep0h_~T&#o?pg^$(Ik39kDcVSWrc~6m?Y3x6GNg0{<~ZXO`cul;uTPi4Ln#DfjVH&)1-ZFZV^;uk*&zM2+o{0SR0%(^)`|su
                                    z0;n(5;097foaAFy4%P+$lItzM1T@U^d?OEhmjXxw`1dR}e(lLa4e3&NHq=n|+Uk10
                                    zmy1Hc@fZ=s3@a?
                                    z4;~OaiD5Tt65u0}C7|I~Q*-hj4Z{ZyXs9Q9d-yOu%L!W`;Gb(90<*RfXgxO`|IsP~
                                    z@aQBYJV8@hUtb?^sd9EO=V1jJwLN_K`T1bE_7eFmz)Ks=mLrT}Ffoi}|L}mhr^eTY
                                    zh*GB62Cl9?COGdtlJUfUdHKx}0fRO;dJJggfP9dT*@D(bu40k^utxziHDIW5#%CZ5
                                    zz?vVQoX`l{XM3__WMqVr^J8LRJ(mxo6dtZLe~z^K1n4ceB8$H!$UUIv-{y<;1O@}T
                                    zXmng$-cLhaBa$%BT;8CSz`Sn`J7Sblv<6Pb5v&G*JTG3dDzX)loyq_B0CwL)rX`N5
                                    ziV6q7B&{;YVm0yLVa&II)%in7JvA^&GgH%b;IVu#im1yV@$UL(UozkJtJnvLL7>Nw
                                    z^oc(6tzj>%23kB$C>6GNIiwW8}W7Lo_>7drj_1*U2!m7MB+gNVkNseS-btmOP~qnd}5Y
                                    z?4wur`dKMiP-BGnP#Zc(8*2aAsbb$sMUBLgrIi_Ib~dme(wWN`U9$UNuYZ)=QpAeKnDqya$m~ZJf?s?7$vcprH`5C8^dchKuH42wM2PAR*7e}@?Ao^-L!kW}
                                    z2xd0y?aXgxF9uQ#6qTZY@i-mr_TL0yVT9;K#?`z?97U~fJqdu%h&EkiwnSZ
                                    z)T!tAn1f|eek0GHRt^0Tx0qXWOk7-CQj$i~`E`;wd^uNf#OHsGA}t*HQQ^p8K9j4P
                                    zsaShMD^;Mr`!^3@G}Txoe`uIkV9^Co>Q5I@R5avN6};>@lNaa^2-fiY=a`f)UO9U>
                                    zCE3#I*yJoS^z1+|(bBuw>O3}Hmu0EvXhdggWR(8Tot@}bF(}Xx5O{)}7m;VW3tatJ
                                    zw6}4u8ts;V_d|QE#Gngkec{x`q-yPc*w20OfRpq*@`H)ZNNzXSR5z~EVA2v6h92A4
                                    zIE}Pd?ezfM2>&lqVI1ddK=^#4z404ZTL|_x~{5{4=|ntL74pjV%V9L3<}wruXCsXZxBe@V2}eCOI;5Hp2ZKk%+`y?
                                    zu*HGlswo;TU5(uF4P76+Bmst;ym|h@wXve>CJr;_r3!(@Ch?eSnB
                                    zDg`+uiCy3-zc@yM8It3zz{&a}6(H}fuhZV*Z!Kj2_Qh}DZqDi)%zF+&k`oxnGbaV{
                                    zt#UVpHO8R%GHa!`rpEFN45mo}Z}ej*7$cMcQq0K_RpZ;y{wj;SXb!}ev}Q0S2=u(U
                                    zg7Ii7QBQSw0QtdMp6pQNq~%6TDyj`La4Dxsh=V2oaIN|J_MPnIul&0=Kryw^ar0*e
                                    zBSm_iO<;EnPw`Cc3LfksCdz@KRBy9fWCxYXv&igL0L)kT$Acl8cB28azfJ;-zyOAr
                                    z9~CMQ77OZq$q(q#V9NL5`}>daKhZs;s1|khGhhz-fB?x#EPLwep1yL=QoJDn;Fqs4
                                    z#`>9CRQeD318o_k4LyMcEO40g)d1wyO=k1)N4|0=Q0^FVg5=`UGGnTtd*6|Q27z&!
                                    z2paqkVDboD6Z*K!){(09HD(Z=lDV&3Hq@JL!3{qOs_{R@k^b9=F|P*-(Ve`?HW2@<
                                    zQDpi-_o%3>I%8YM9%kP9drrB_Y8-Ts{(?^b*O6tU7j{S}u8LB)Fc`sx$Vn?n6~hca
                                    F{6A8r`_=#e
                                    
                                    literal 14443
                                    zcmcJ01yt1AzwdyEgc3?9=@3dI(v9?hw2~6i-60I6fFMYBqm+o0bPkPlcL_+x&>e5%
                                    zIp?19|KEGxy6>&`ST2_i@Qb~_dw)N*KPbve-N7Qkf?K8Wh*bG{#rMq-gnRrWgmjcVeDt-B7jJ7iL
                                    zvoO^)%~)tF_WKE9OA2IJOqcTKbm%FCDO+yJH8Imlh=p%nURHQKGDP=fY?|WVa}#nu
                                    zj^mwzZ#{^sMDi}Dzzb+Pze6A*gtsiXA&@kK3=D{fpfVaHje;H(q8Lhm0{J2p2!RYy
                                    zOF$rN;ZzXFfiynE+wK3^k0pJZhKOjI)_{^vArKJ9wn&Lx83&j_C8WpwvKX7
                                    zgakps_nfaTxr!I(=GgoSDqc5T-ngYdJ@tyYkFH)>8b57pYo?Z%^z5QN5)sdAXSe#$
                                    zH!Pz*AmBtu=*BJF6nb9_oRo*Y(y+?#D90SRL?vd;+ZN;YV>=7WQNy(Kw)-oUq5=8Z
                                    z!ZNVRonbYL+S*$+$McFdNE9T3lF?WC`EwkMHwCVHP;&l|TBr4VGg^z$t)NihxX4Hg
                                    z%Lp?}J^oOz)&MwXjh?vIceAN-2fq0GG-JDF8
                                    z6G^<(N663*L1){W<=LdfTVwqS8eQGp2lFlKc6O8$Jb2YMvuef0c|@YO$&OEka%?CC
                                    zc(`dYHXD4dIP)@`EK(QRdP}WHFBfAi1_lPYV<0gP?Y`oN#nQlTCbK>@Xmtr9zAAKF
                                    z_3ss)O-s8A^`*Jlu}cBN>gt|mhDGcSsaroO>F()Kig9#w{LwR$c~1A(BsP7avm;`C
                                    z^zk>H+HCXTKy;sljd2S@*U-qp&LgA^`~Axl9D}mEP;ph&!;WbFwqUJ7yM-6R!V1N-
                                    zH*41FzkH!vWRn_IV(RKg4gBhLCI8?-{M=koLj$vzn9tW2IeMBAF0RGd4e&QZ0ijnL
                                    z<0cl`)rThT=g$l(eVT-C+^B_n+0Qk0JWlbcU_uA1k*)IF(Kq|aL%
                                    zP4iecUf8S2>(b%%>HbjyM~+1q8l4>&`4_`qU#2|yWFs#ABY_iM?Ucyju%t+tT9rk6
                                    zGfxLmH<>9r8q4%xwj4>|(?HM22=9n`QY`!4-v!zCx@%BDZEyGM=BBnu>qjIJGYPlj
                                    z3X_S6SftX
                                    z{9>aL+AMEVYbpk(uY1d6otaul1dPjR6|ogE*7W|LEI5(3h8iiH7N!1D3b*{ZC@2I?
                                    zx;3?x)o#nkRMEiRwt5xR@##2q%eP--+r?C_e+iL6)pV}`c-A~wdAxk43lN&gY~1C%00D(r}+4LXGd2YbabDc*6~FH
                                    zx)X7E`Rd#c%)frO)=RTV;3HQO%&X!D{-1T*brEm8{$@rbi
                                    z%m!U4=Qc6V3wigW#)mFZ!oolH>!4pE%U>)
                                    zPdlqYtXzCvmtV(e)6-*LAw1U`{a$KUm*HT>Th{o!(A0Fhx+K4avyl{LJ3mn>%xyh2
                                    zo3A~Xo#G~XlJhiaajxH?FRcd@30K}Pu)_A1tklaaMPE%FH~A}ILeXy@ceO3Y-+N4S
                                    zv^C8_W4P;cOQV%*e|>Z(J5@d-Yi9iWqHSBq<#4VVbIr?`Sel(@GeiD1^
                                    z;l8GW@U)n3_S@PTwix*qYord~;fY!FdUL?$x&`#Ir@o*yBI
                                    z=jU7DZdFp^zTy(hFj(d5Z_IQ*5az>Jq+B$X({4PEjEAVTUJf9b$LN*8%zjatZfr8J
                                    znX1@a)quB!=z5-QP6XiFU_qn!NAq=4!x9p*m{#X@qI`UsTxKOGcq5|X-t>U&XJecI
                                    z>ifNzMWwY5Y+N}iv9om-YPPnr1{WzQTOC*5nX%8a1>WLau7ZMOWKNTW*CysdP}
                                    z?w#GQR&F+-eSK+QVC!}ya{~!G7tg}&sT-$Wjh93`PWkd{Wu-5pJq;FF7cbzNhNs^i
                                    zfg3_8yu2x>ce1;gt11!0yq;A4)$@Yy@^G@$dRm7;E#Fc}^QM5%mJ^0R#x|UMrY2rB
                                    zPjhj8Bt9__ezM!m=QJ}>vO1WSMof|G5z|nM^ND0u&Rbs*A1WHaZlXLj4S(Z0Y&~12
                                    z@qrt&kR>DtLZnu{HE7bC|3$l+?-q?7TpGWA{x*8H+kv@eHKDfzc=taWa$5jV7$q?`
                                    zT3`qP$}Xc}RzV&W&nFUU&HqhvZhNl#P&lg=RRT2g6T3PLMaPe(DF52k)1J`2sn^>W
                                    zbM?nb{umIat4xThDG~_rtMu~H`Y;q37k9p#>T&~>1iYv7eDlfOoO^w!OQtA(pld#H
                                    zu|DRWwWL>R-5%9Ff*+Wx73o*jC{R<0($Fi$k7No+%T(>pz}eZ^i)mra%^!CU@*evJ
                                    z1YZd8RAk~&@l+T+?>fRJ`dGHLjw*vik1Eg@$F>(j7C-wXT*}R@HHmk9SCCU%2sFU+
                                    zll0o!b+DtmuIH_!OA%v0%WSS(cYnPV4aky9CFf+wD$%{6$CiPyjj=xBalV?(xHScH
                                    zaduvtEH|jjZf!BtP^BOfa{p?#ptx9+zA)?48q0Dqx27q9p;YTOEE}62yTu4$3LrqC
                                    zc)ieiflVC3tTl3Se!>_`ic9t+O=Tu~bydp`Z*}!SdwXp3qM(3zbDP)UMsaDr_8Gg-
                                    zWty^j(dW*KGhBujwv}F2&sqW(za8p(M@R-jLKP8piHNJ8GSMAIhKBN~LOks3{74n3
                                    zxVn1mQn!DJ)mhE=^9b67v%_TlCp<<*MhfwFvk15>4mVZ@5!_Z2KZkOHJUvrX;cOzX
                                    z$dA*u00hAznCxywRaE4u(vx!3~6dxY$x^Jp1Ev;q2eTxo^l_CkKGP6PSR6ZxWiIN6+`H&H797TN|7SyN+
                                    z^gHGn)tDmf>8yXD!QaJKZi#wbd=wEbTX09m5<)H171Y1$FR2>GG>B#=$2X;q7==Up
                                    z10F2m+caL<7ioME#*ejl@6h-}10e}vHV=ayzSRk%@;-S+kwvjOd1iSwaKr5mZmwwX&`X8Tw|AD1e_YWv+itSL6#`-tvb+~?(e&T@V=s2C`T2oo7*N<-(6Bw+
                                    z(QzmQR50+#1fF4pN7z$?&YsAXu32(_)mRo{8hN?&D1C(n_B7@H9|G=p{a+*CR!K<-3HngpDjaoU
                                    zhmsA6tIOo4PoILh^6}An{~rBij&ef@4RY7G&E!9AHAPbmbE)!H$eGkv6@|O)k8>YA
                                    z)>R5=2i=~M&++?9##Glmt{30bdn{=Ij9coR-A=uF6(@92`$%prff*(3Sw=wZ7uCF7
                                    zUrZ0MOOJdTpUj)gh-dddJs#p@rZ+t}J(yv!-PGD1!
                                    zaf^?E^gWU+vDBEs&vUo8w$*-9r6cTfa<$60LhkPjpB`WW
                                    zG!F*o4*991rsiqdvs9aDHyU>KY8Rw)5V4o-@ixq-VYPC3P3wRVQiyR1?jKBgbcCFR
                                    zVX!%G2*9wusTGWdQ)m0)U7UF(B)C0>LYJCw&pwiti(u?5gi0}}GPxXYpFd!KPgjo1
                                    z>$s9pU{m|uC^_%!E<_#G1D^l}+GH*KfoMRH!7OO5quIR#!ot0Y+=E9fdG&xFVnPlQ@QDCj`8
                                    zNS#*1RkDDaBd!Gk6+-kZFio0>>Hc(fZ(7f0}#169XL
                                    zd!t*oR|v?-6A~HWuESdcMz2CCtdv!dHQVphL>oVV=O)%MHQiK$)Kl%d=rR*%Ly!1|
                                    zI05|9YN^FRfgJwce8G0_t-4~(BO68q@osx|T_grs1;LRSB0yRYQChVNA)?n`uyo2Q
                                    z0K&pgo4-)de_drYqtM@7BfgF+1XcuL3M449OJYS`!MNW3|8c)3QrHQ`Zai~MxL2GW
                                    zrwj{&t-)dnsh723PJ6>)N2_B+dpP8L5AfL#;t5zHtkU@W_E(o>?zA3f&gw<_)w{=_
                                    zxf^xdPw^;IEizZ6dGzS&WO>@#`#rZ!Rx*!Wowz3Ub#LScoAc|LnmeAJ$TCabu2Gl1
                                    z5;Mly8gqVrQu&l~IgBE=gOr)tNo;7{sd--ckvFj}+1jSy&x<32yKN+ZgLly6HtwpSm2G`Y)4VZDnV85Jgs7(G_r+Tu
                                    z*@Um>#rok9v+9Hb@uB|hn8#UN0;h#j9m(}J+YwbB3eZ|DJgvy~>@fA>T)+=cE>Wo3
                                    zo^rz8o|b>$EO(xj#tgvX#Nl&wsEvsf4jJqQzQn$y=k4dYGU8GR18TK=@o$
                                    zA$F5X-QllB*j+XH8Fa=t33*-0
                                    zEVSMj94xP@Qr+2iq!e_^f0{(=y8r4QpvhS>0MUXN3~%tBp62v8ns
                                    z%!g?f&EC8@!Xa-JxNziTEtr^@aWd{Yw%%V!X(b_IAtNQ?5@awhLLg#`3N?yNu4@7S
                                    zt!#Pi7w^j;W0)6<6oK*)83UE5GOwma7}b;k9Tzm}cFV2?K+SE7^kw
                                    zX8l$unXpg~{E+-~wEeZ=t?ju;pp{64KJxP|DRp*$)DCF-Vko20HtN|Xa9M5Vs1Rq%
                                    zk#77lT#6HbXtmhkM}0)UgT=3n@16GR-?2FQ=IJ6%@yqbL+
                                    zFf70ykPGa#+dtz)12QsXttLL2_v@>7#xwy+_1IUv#B>j=2}6yoadtN#k^KCLDH;$J
                                    zMcPVYs8MH6JKWtpys>s-twXgtb(;;TjlZYb84QEeQcG;erV4EW1x%w*FCCBS-vzPj
                                    zp1-S-FWb
                                    zHNU(ViQ?$4-&!`*p+p-0EW%}IxG7!I{oJHiNNXJ^3JVLkSWwXG9zR#-akV!UZ$9_B
                                    zu=qAk0w&1z;*`1g`YPfW;VCKMN$!>;YypdS@#$UA_^_Of&RwFBOdvU0O$w#j47QqAvSFsVoL0vO
                                    z2IdcKv3^ddB8{~5!XIPUVnrpu<$i>+A42e!)9(7l0Piy{w9tgMGfZS95YzfS}ZZv)5f^{}9e65(H&HLo!
                                    zRxL5=^3N!F-=Wcw|K4BIStC-PW>}x&SdhIQwfvCW>4M=)P1VOK=$XH|E9}b_*7l+U
                                    zQSY9}cuo(I)f302l^nMiB!z5X(SKIcoYWvi9LE}m5qxLnqw1s1^T-c+N8pNaM((t`
                                    z`8|(<#_gOAm9M4WNq{9cwJ4lhdRIOqjUP1%Rmk`alOHlCua2_Z?FJ;VEnq}!H^f&u
                                    z;@A56WCkp<%4ywmubW#GLn8)py2fZ@gM1{Hz+pYb^XO4)g@0gZsMl8Ivd)`1KOm7?
                                    zgO+B@*xTM7&tVo38yj0*?ow>r9YV&d{3bbqCht|{K*{TgPbD%8afQyEyc4+UNgoAv
                                    zFGW9w_NEH!g0=>3alYHhWd-Q#a_Vn2q;7vewnJVw#z;+V^w%##jhIk!{=@x2g~Yt`
                                    z;$9&*crfHFg0*vZXQ6F-JyQbjshG{AXt0x-ixi~E5=vlM!~?o|}}2~?GpmHaMS
                                    z?(-iW8)|qi#hb_{@w|TZkd3X#^WwB)VQo0KH<_QCnVFfJ`{-!ai(AWebE332iPymW
                                    z6zO%v4;XnEpC6tB5TUCab1bcef20(tA3HrG-anQc?)y?iBuVkhzgI(r;zf=!Ef-gr
                                    zT7eF_&)iHc9Np&`eQ#G6lWv{6s%i}0eDjBUdq8q6wNMKt;r#shGwO{Sa*Qsvwm-VM
                                    z9PQmqCB>jlG7(YX;r*Giv3XkMB)8wYd(lgt2mJ^{GG2<%v4C1A<&=`O;KuAdT6T1C
                                    z5%xGODK9VI-QQmwEVUR_rFaY`rnMCd5dK+k`y&8h;zm@#H0&++a+~&vxboS}Hy0Kb
                                    zimnleM$xNene?V~#xOIksu|NyoZnVo^f1~}Q$Z&n(`J2-Pc8ZJKHL0Ao|b5UR=G93
                                    zLNq0qdNbrqZ3GQa`#Q(RHRzu!DD+mJ@*`{5oj1ndM_ZUs&y&SiLPpi0ZyI342ydX@
                                    zRP6{R5~n!iB(fBeMW9kTkv<2&^WyVk-0^!No3fM(cfr@
                                    zHVylS{Cg0Kp2+|e2kI?y!U^!a42_i@(p%~$~BggQhuUsy1d7|8A>F3X%^U9An59AdUeTyBcPY>Y8
                                    zsgqnh(U?W3m~mx=qpg#NM^BOyl|rxBHKl~XVn3ETt#iRJ`oAweVXV0;azh%w_VZ*$
                                    z!at?fkPsdFi_<*NtDV5MOJiv7?A+55G`ie9S!g-#TT!v&kDJO+Q^slW2pf9$uD(p>
                                    zW}%(i`73s*b?Ah^Gz#tdP)_D|rc{2HlY`O6?x(B#h)cJnv7%yY>*=UeojUiy?rx`F
                                    zKdb?Ct*o>M+Dpy)?jd9sDzV#1N~2lbQgvukl|TM|adCAu|D3hc-rPLFzfA=P2WQrU
                                    z*!7pRvi>|TH}@z&{WF!3brz%Fwr#Wpg>}C(x
                                    z5+D-_0!r=u{hwfw&v0-Cezo85!*g02TAAWagCG6K*VbCjZ3A6$y4Ed}LaExh`+H-j
                                    zw^jdwZNPiYZ+?3cLvvja<^^~Bl>iDA-}H4lSQSt-($Ii?_lJf6{Jm`+Y5XV}LC;9k
                                    z>wiJ|ummYI46|4*DY-wQGD)S=M?^Wccjl%tAz^a0#cy_S4O;h^Iy8fbtZ=XsFMIe4
                                    zSk#~J&4$v@Z-W8vST*)z93cu1
                                    zBA5d|V+*AQ+yd{j#+kd#y=X7q4V_9MWT1&FPy;{_#XbCH3Gpx{{y
                                    z^Q33JcW=}L5zExZT>oJI&Z7CS&e^X>qgELm4<~m&tYm!y1nUS93Pe)@f8nNz9Ba*2
                                    zrm&cp8HASK_DVejw?ksr^cvqb3(UuW`N6?eZHXCIKg}-EIP~6kn?XSBJxtyaSBh#5W
                                    zJ7cW)Jx*PK>mrIl9Q)J-IdgV|h$LnX+y*@COL!Xq>3(?0d?#14SDU~S2xIC5-cM`C
                                    zEnH8zn3f;m4*9QO%=1LdSAi&F|KOi4n@zn0|KiFE|wToM?cHu}6SPrx3CK#sA2
                                    z-Od~k@$Q7$YG7na1`A{<=pJ0236A7noOOJlmhAcvOg;=Wj?WTWTsA_6-@F>$$$|E;
                                    z*b$wlQ9J>bQP6h@h+P|+o;`zu
                                    zwRQ_8sHi0Q>O~$~Q`=(x^5|$aCN=EZVAUMWBt9VEVBzLg!?2rce3^OPMi~m$!FDIB
                                    ze|1F^{XEg@7z&f>8*j)+)&w;cCvscqTS8SZ)oeHi^t`458(OPT4@D@cHR~6Cy5rZ|
                                    zZ+Jwt4i0K(b944T%5xHjs3+8BV?a#(DMFbd{xF>XD%27u$K)Fkkd1ioEptW*N4K=Z
                                    z?HhXKCDBxU{8pZkR7)tGPzk+-U39HKL`i`N^xjDinvnb(*HVIF1Xu-Qq>?3iQbXFk
                                    zGNC@V`{)Jh23LY0eo9onLPUyqRtFMsvgs~v=Z{`u7_f?C-X(=QiG1i&4YaMpD52K1
                                    z#G|3R>E<2^jGVaFhfQ65M0$Y)&tTt!lP#gMw=nNMq_he)MN!T66`xc3)b{$;$~%f#
                                    zHK0Y~4TiGCqY%8qXO5ydEc31fLZb-d{+l5=Eo#l@@i!qJ{fdFMn=eW0p=k9p*D}B6
                                    zr?%ofm9G%U{YTeX0M^&Pg~u}zFTI+Z4BKTWSg)l#!apa;p+i(N+Q_47GodkD+JUkqgYfon{0s
                                    zz+zKkIa4z}di|vqL9_U5xhL7j$0s_q<2xAv0Rb_wNoEYHYE~Qa`JvMpxiz<;nXy-s
                                    zAMw(!UnS$AQ(j;Q_kor^*W|w(gjb)xvcnj3
                                    zsd>(`e@x6E7eNDJ2-q*ql~E>7muzm?yW@S)w~z>|+decC
                                    z6BDSfnJ%qEqc_T!J$v~BAxrk$sY*bI@z8`)N_SV_3>3b^^OUrD&*mNAcDWT
                                    z!+-A&P5SLfe>6(TM}oI4t3{DG>V6amcDpS;8L=6MoQhRGJ=uMilwS*d3$C9s+x3_8
                                    zh3%`~Dk&*-Ed2QKW57ma?#(2`4}fM!iD+mO;%|i-TpE-Swe7!t(m=*MMxYS`+~G~I
                                    zlQw(`_Lu4fa_PEVACb2NxG5F^X|-pguirx3k@Y}^wZ1-32(de(*ls_#Yq{x+(uW76
                                    ztN+pgUiqex>xT!LJaBw8BqLBGBUm!CW-ze=ZJn*v5T3|nelJdzdq4v5x>E3YN2OU#
                                    z0refLISB*t0kwiGO(Z8uLRQ>$5Sg3Qnsj0QQo&&30-|QE=fz0#2khzT+|h3u%t+K$q})G{L3S+b>z7jzS_!Nu-kCr${O|qI+vty>%|Haq$uaAQprBCT<>7HZ
                                    z(*6}r4g2t685py@DRTItJiNSE(2giJu$cqO87k55qNbTCA+B#PeA
                                    zElJvhx#@i^o2&iGyPJtsPKl1l8K14`8~5(YV?fu2a{4PBM2@z?C(ACrG4VQ?$1!!5
                                    znmbW)nuh>6R;ukBnfosmXY^qwL=Se_DLDKi^fTRg$2O3Z0LZMYZ~~$^fJ4Rd$>m&D
                                    zryO)EHwSN4JQYX-_1sM%RpNLg#lRVQTayr<%9qFCQ42r<}y6+E=wNUpWcayTJ)CK-Y-{nwwdXbX+ReZ4h|M{-OVtA
                                    z+1eK3QPI*G{j7g0e6b&iH@{wh2nh*^p)qR?z`wk_tgEXNzB(_)qoSt=5gjgO%@R}4
                                    zX908C8}Zs-QPS1b_42yv>r>2Z-e}aWc9w&|G^(Ag+}+)Q(PifZJP114r&vyh8{u;uZ4#N4
                                    z+5(YHU#^s<-*nCyyi-nZ<4(LZj*iZHz;4W>Q}bqZAhTEa%KaJbyjSF&y@Nw4zyP$e
                                    zF(1LV+d{}AXpD@F0fD-OOY!21B9xJ_Q}2nPi3wva4XjNvs3}sr_|I2bB%sr%Fm9F
                                    zxVX67_iux1sAN4io2{$0yC)S&aR(dQ!P)un=m-#ie5TGUY*GY1t9qdxpmt6ExVRV?
                                    ziXkoWF<-=Vo0(3jM4-oS2*f}Uq^BD^qXjrg*X!Z{ludNL&!V%SANPV?7?m;Me)bF0
                                    z$zy5*PvYEbokv$Au2J`P7JRLSw%DZiaz2O^6i&JTvu<6@%Y?TBuTRamFSdy@(fas9
                                    zf}-L8;l2WIeusoZG3D}LRCmNGbOwf74Ai#h{U_X#zz??M2SsAu>g8kgDjNnRN(
                                    zArhHZ#T8n#Y}K{Yo#^rVix#F#;kY%WQCXjGP07;I(kd!=7)uEXnSg=F>x#%;CT$#e
                                    z5q94R)EZ!?*LHH0tjQlecI^y_@LCAw1`IhiK7PDFSJ;C4ULg<{>0H6W1M9&3U|3BT
                                    zXd}2n$9jNepX`R-5O^XRio{Yzn^67%b#x*Rzq?u&r@H$?0sb#NcCd%
                                    zSqmgIc84|!mpI%cFbIqDco?|HQa%>smg8-8F<98u)%DbDFEECepC23goLYRv;V0^oAc6+r-K~kw>FIf6cXz&A
                                    zd}A~IR?0sj@ew7{o8YaES)oefBJpd|kGfPr_Q6&?#Bb~9lkZNGQx9wVSm`Ja(891d
                                    zF5w5mJ6{nfbT0{yq(UtRKpG*i)M@ZmPL506@q9Ivb?wSZP`$vNndS6{s;g0b?S(Kv
                                    zpJR-8c~3efZ4?w>l}foIk+fP~AP(ksWPP==NMRkZn-&nvHtk#V3#>nbwjNUUER!OV
                                    zZRvdpJ!(s26@t#=?b|x534zf%5B6KPZUH6%?)L5-RZ{ZgaKS8mxkuLz?|+btvH;o<
                                    z?Co1>KRl44X=-0xTpzWWu5_?z3EZ6by6^#J9uI#x{Ne!fI}`9gkT*#K6$j!jc-(*M>q0%O!31wN`}$Xiv>#Y0w}uD^xZ#itRce-Y^!Ll=>mr=y
                                    z8ovTM>+k!#r>Cd#&CY3!D`^aKA|5gK<@TJ4XaLF$p}if~rREPUweWIm%=q)4&ti(o
                                    zu2VSsgCB;5__fN&KnfB8Smp`WXq8i>4dTKS00Cl_S02mBtmo$fM;r0U;o6Q1NFUn#vw>Yybb^BS>DBp3?nz_QPy%P9A08$q+l^b!
                                    z^3ptZn-i&|+*>xI`Ku}lf;&724nQGPWUL%zRiqA-l;x8(K})D~h}HG-Xv|Kn+gmR%
                                    z2_ffSUmB4+SzYYp25Hm(i(ppN>QWSmFCJKa074M`2b+x5&1YkYJaUYYPd>jwUL9JF
                                    z+e^nRCMCUsHpjEm3&P9HrjFwy9|zfeDjU_YQ2LkH81reMaX<0fI}FM4u$fc20%DD*
                                    zyQaa}+10UXn`$~{EPu%zd73A$D!)5loYDgU!rD3?AQh)&`O|#uV#&}gHmeC4sCd(R
                                    z3SH02NA#-$fZj6xj%{%oSoQS0*QuTGINurQ>e?99f%iK)xX$8&NNW{37v8LpzTU1fdo02&5gt+2@5EA=lhI{J>uN8D;De4Ni?7Bx$&LPpJ)a0b*{+T_-D@+KywDR7|W|D}4$I;+?ozrR%#QWgn
                                    zbmZ)(&rPF_5=yR(&H@C5RV4<#XcBMa{MJlUXRb5QFengQfc$zN_`OF5f1-QJz-XUt
                                    zj1vNx)&)S_^9dmR6teyS%w)fE{Z82Y4tay1s@^Dvy#o0Km4u!Yu+T>)ZM=%CCi{06
                                    zI}cX}=RgXPS*5j$IYUp4B@2}i?(jfu@BH^rNp~fK_cup)(f&h
                                    z)+V9H3NpvQ?<;XXX)d2}b3NY9&sCE`0CRWdOpuOP`K1gM)zT62%1nvnXM&3>V;x_;
                                    zCYbOba3yRg3Foe2O5Lu^9@s31OKks$ZU%Xxs2RBiA<#wO_xs<~+B)R{wCb|;9h5Yl
                                    z{?0t*z#u!IiC@n-W;4D2h*BDxEEDXY=6CF7p1MJ-(pXX9N|p8}Afk7An7n&&B;3;M
                                    zeg$%B1=?qWe+qir-P~HcEZ@XM`&oa=_|{v41w?+blxXLJE(bi(c0$IgnzJnnN{^vl
                                    zJ==}n@|<*Wx>hT81s{(z_#20Wqk9rA0umANI`xEwVy^~?xk4;XKjTepwS3dBy`IQI
                                    zizLleOHh6I3|#ZR_zhwC2!l2@|S^#>xHRN}x=Ps73gtamLFMp`S)2jEdF
                                    zqj7}posCH%c
                                    z2M4ljR|uQ}xQ&5fI#c5cpu5da_EuJv<
                                    zV?7XQIL?UT2|kzE&e8;Msa+x{-bJ{*Q;2har2o-jN
                                    z!)<2kv||Gq!
                                    zf?c?;FPgBh@FHF(cnuKZ7xwa$mj3bf#x2lVqDh|1a=iO60Fg;7mG7tPaE^ZV)t$CO
                                    zF`70}HN*H9V?PE6I~HO~d}J9EECn)`FY}z~QIm?|AmA9qmAfy&BQ-4wG|oZ~
                                    z@qk6J1T4w$^_4({Yf1X5lYpW(#)kr6jG~tq5H
                                    zG(9*0G=@W!alQFiqT%ZkUSC7RR~_UkMUDdS82?&o`@tarPT*%s^24-B??F{TAg7O!
                                    zN*o((3{~R3rodSi@e07(1Y63=ZT!#l;3|2MM&ob1lQH^9{ycXi!o3n;8Wvef3V}%I
                                    ze++Za4h>@*kpS1ZLn|C`NA43G<7Yn>FMLXK%*70BX%Gpj-{DCwVDgtHdL#aI8>|9}
                                    zqQ4FcZIFSVZaFOQY8m}HJl(!(1di%dJ71VP#{=wple|`1u6D15c$Tp4_WnBp6h#35
                                    z!O?M3cZy!awKD^c9fYf;pfQgv@(oF4{
                                    zn4{wg$YS{6U0opk!l|oWe;*gf$jr>nn0lgJ6m}{8EcY7j>~)Wb26S~=>FXJFf0FfPntRVk|p7J$H)x_dvYQuf;-H5w9Yn9L*+5qN5pO3p9!o>|A{sU>HT7
                                    z9*rO*-mcZ#ooLqDb~BF!7J;siD5aBu;XR-8A_v5uDVa3Bmr4Y^ULUytvH%aX8GJ-0
                                    z?AbF3uissqRLcuw(i$1BaR1kw|6O21fWVBPoA`rRdP65uveACjZPN%EvrQ~I01G<|
                                    zdWefyKnMJ firstQuery;
                                    -          resolver.issue (firstQuery);
                                    -          explore (firstQuery);
                                    +          explore (firstQuery (resolver));
                                               
                                               Query secondQuery;
                                    -          resolver.issue (secondQuery);
                                    -          explore (secondQuery);
                                    +          explore (secondQuery(resolver));
                                             }
                                           
                                           template
                                           static void
                                    -      explore (typename Query::iterator const& ii)
                                    +      explore (typename Query::iterator ii)
                                             {
                                               cout << "Query-Results: " << showSizeof(ii) << endl;;
                                               while (ii)
                                    diff --git a/uml/lumiera/131077 b/uml/lumiera/131077
                                    index 646250274..466d94b36 100644
                                    --- a/uml/lumiera/131077
                                    +++ b/uml/lumiera/131077
                                    @@ -1,6 +1,6 @@
                                     format 58
                                     "ConfigQuery" // CommonLib::ConfigQuery
                                    -  revision 13
                                    +  revision 14
                                       modified_by 5 "hiv"
                                       // class settings
                                       //class diagram settings
                                    @@ -651,6 +651,23 @@ ${inlines}
                                           idl_decl ""
                                           explicit_switch_type ""
                                           
                                    +      classrelation 187397 // pos_ ()
                                    +	relation 177029 --->
                                    +	  a role_name "pos_" protected
                                    +	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
                                    +"
                                    +	    classrelation_ref 187397 // pos_ ()
                                    +	  b parent class_ref 156933 // Result
                                    +      end
                                    +
                                    +      classrelation 187525 // source_ ()
                                    +	relation 177157 --->
                                    +	  a role_name "source_" protected
                                    +	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
                                    +"
                                    +	    classrelation_ref 187525 // source_ ()
                                    +	  b parent class_ref 158085 // SolutionResultSet
                                    +      end
                                         end
                                     
                                         class 155525 "ResolvingFacility"
                                    @@ -681,17 +698,15 @@ ${inlines}
                                     	    cpp default "    ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
                                     "
                                     	    classrelation_ref 186117 // 
                                    -	  b parent class_ref 158085 // Solution
                                    +	  b parent class_ref 158085 // SolutionResultSet
                                           end
                                         end
                                     
                                    -    class 158085 "Solution"
                                    +    class 158085 "SolutionResultSet"
                                           visibility package 
                                    -      nactuals 2
                                    +      nactuals 1
                                           actual class class_ref 155141 // Query
                                             rank 0 explicit_value ""
                                    -      actual class class_ref 155269 // Cursor
                                    -        rank 0 explicit_value ""
                                           cpp_decl "${comment}${template}class ${name}${inherit}
                                       {
                                     ${members}  };
                                    @@ -703,12 +718,12 @@ ${inlines}
                                           idl_decl ""
                                           explicit_switch_type ""
                                           
                                    -      classrelation 185989 // 
                                    -	relation 175621 ---|>
                                    +      classrelation 187269 // 
                                    +	relation 176901 ---|>
                                     	  a public
                                     	    cpp default "${type}"
                                    -	    classrelation_ref 185989 // 
                                    -	  b parent class_ref 155269 // Cursor
                                    +	    classrelation_ref 187269 // 
                                    +	  b parent class_ref 155141 // Query
                                           end
                                         end
                                       end
                                    diff --git a/uml/lumiera/137733.diagram b/uml/lumiera/137733.diagram
                                    index 5926ed423..f6a2a9bb3 100644
                                    --- a/uml/lumiera/137733.diagram
                                    +++ b/uml/lumiera/137733.diagram
                                    @@ -10,7 +10,7 @@ classcanvas 128133 class_ref 155141 // Query
                                     end
                                     classcanvas 128517 class_ref 155397 // IterAdapter
                                       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 46 222 2000
                                    +  xyz 24 222 2000
                                     end
                                     classcanvas 128645 class_ref 155525 // ResolvingFacility
                                       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
                                    @@ -28,7 +28,7 @@ classcanvas 131205 class_ref 155269 // Cursor
                                       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 246 339 2005
                                     end
                                    -classcanvas 133509 class_ref 158085 // Solution
                                    +classcanvas 133509 class_ref 158085 // SolutionResultSet
                                       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 355 444 2000
                                     end
                                    @@ -56,24 +56,38 @@ relationcanvas 132357 relation_ref 169733 // 
                                     end
                                     relationcanvas 133125 relation_ref 174469 // 
                                       geometry VHr
                                    -  from ref 128133 z 1999 stereotype "<>" xyz 95 319 3000 to point 77 317
                                    +  from ref 128133 z 1999 stereotype "<>" xyz 64 319 3000 to point 55 317
                                       line 133381 z 1999 to ref 128517
                                       no_role_a no_role_b
                                       no_multiplicity_a no_multiplicity_b
                                     end
                                    -relationcanvas 133637 relation_ref 175621 // 
                                    -  geometry VHV unfixed
                                    -  from ref 133509 z 1999 to point 379 411
                                    -  line 133765 z 1999 to point 266 411
                                    -  line 133893 z 1999 to ref 131205
                                    -  no_role_a no_role_b
                                    -  no_multiplicity_a no_multiplicity_b
                                    -end
                                     relationcanvas 134021 relation_ref 175749 // 
                                       decenter_end 830
                                    -  from ref 128645 z 1999 stereotype "<>" xyz 428 406 3000 to ref 133509
                                    +  from ref 128645 z 1999 stereotype "<>" xyz 450 406 3000 to ref 133509
                                       no_role_a no_role_b
                                       no_multiplicity_a no_multiplicity_b
                                     end
                                    +relationcanvas 134149 relation_ref 176901 // 
                                    +  geometry VHV unfixed
                                    +  from ref 133509 z 1999 to point 402 422
                                    +  line 134277 z 1999 to point 195 422
                                    +  line 134405 z 1999 to ref 128133
                                    +  no_role_a no_role_b
                                    +  no_multiplicity_a no_multiplicity_b
                                    +end
                                    +relationcanvas 134789 relation_ref 177029 // 
                                    +  from ref 128517 z 1999 to point 89 239
                                    +  line 135301 z 1999 to ref 131077
                                    +  role_a_pos 101 240 3000 no_role_b
                                    +  no_multiplicity_a no_multiplicity_b
                                    +end
                                    +relationcanvas 134917 relation_ref 177157 // 
                                    +  from ref 128517 z 1999 to point 89 251
                                    +  line 135557 z 1999 to point 144 251
                                    +  line 135173 z 1999 to point 195 461
                                    +  line 135045 z 1999 to ref 133509
                                    +  role_a_pos 101 253 3000 no_role_b
                                    +  no_multiplicity_a no_multiplicity_b
                                    +end
                                     preferred_whz 629 529 1
                                     end
                                    diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session
                                    index c9ca3b9b5..2cda23c29 100644
                                    --- a/uml/lumiera/5.session
                                    +++ b/uml/lumiera/5.session
                                    @@ -4,10 +4,8 @@ diagrams
                                         575 622 100 4 0 0
                                       classdiagram_ref 136325 // Focus of Query
                                         582 515 100 4 0 0
                                    -  classdiagram_ref 136581 // MObjectRef
                                    -    651 533 100 4 0 38
                                       active  classdiagram_ref 137733 // Query Interface
                                    -    629 529 100 4 0 0
                                    +    629 542 100 4 0 0
                                     end
                                     show_stereotypes
                                     selected 
                                    diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj
                                    index 2293af356..99a17c9aa 100644
                                    --- a/uml/lumiera/lumiera.prj
                                    +++ b/uml/lumiera/lumiera.prj
                                    @@ -1,6 +1,6 @@
                                     format 58
                                     "lumiera"
                                    -  revision 56
                                    +  revision 57
                                       modified_by 5 "hiv"
                                       cpp_root_dir "../../src/"
                                     
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 1aaf3cdd0..faa4b3695 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3476,7 +3476,7 @@ Then, running the goal {{{:-resolve(T, stream(T,mpeg)).}}} would search a Track
                                     In the design of the Lumiera Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Pipe, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered "condiguration data" (including the actual plugin implementation to be loaded)
                                     
                                    -
                                    +
                                    Within the Lumiera Proc-Layer, there is a general preference for issuing [[queries|Query]] over hard wired configuration (or even mere table based configuration). This leads to the demand of exposing a //possibility to issue queries// &mdash; without actually disclosing much details of the facility implementing this service. For example, for shaping the general session interface (in 10/09), we need a means of exposing a hook to discover HighLevelModel contents, without disclosing how the model is actually organised internally (namely by using an PlacementIndex).
                                     
                                     !Analysis of the problem
                                    @@ -3493,6 +3493,11 @@ The situation can be decomposed as follows.[>img[QueryResolver|uml/fig137733.
                                     *# client issues a query and expect it just to be handled by //some//&nbsp; suitable resolver
                                     * thus it's difficult to determine, //what// part of the issued query needs automatic management. More specifically, is it possible for the client to dispose the query after issuing it, but keeping and exploring the iterator obtained as result of the query?
                                     * and then there is the notorious problem of re-gaining the specifically typed context //behind//&nbsp; the invocation interface. Especially, the facility processing the query needs to know both the expected result type and details about the concrete query and its parametrisation. &rarr; TypedQueryProblem
                                    +
                                    +!!!Decisions
                                    +* while, in the use case currently at hand, the query instance is created by the client on the stack, the possibility of managing the queries internally is deliberately kept open. Because otherwise, we had to commit to a specific way of obtaining results, for example by assuming always to use an embedded STL iterator.
                                    +* we endorse that uttermost performance is less important than clean separation an extensibility. Thus we accept accessing the current position pointer through reference and we package a ref-counting mechanism together with this current position ("Cursor")
                                    +* the result set is not tied to the query &mdash; at least not by design. The query can be discarded while further exploring the result set.
                                     
                                    From 5d9671cb2c830f5d389971b9ff93c90236c7f9e6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Oct 2009 16:18:53 +0100 Subject: [PATCH 025/377] WIP place a ref-count into the result iterator --- src/lib/iter-adapter.hpp | 8 +-- src/proc/mobject/session/query-resolver.cpp | 2 +- src/proc/mobject/session/query-resolver.hpp | 57 ++++++++++++++------- tests/lib/iter-adapter-test.cpp | 9 ++-- wiki/renderengine.html | 4 +- 5 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index c9d351988..5883d5512 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -138,8 +138,8 @@ namespace lib { * or alternatively resolve these types through a specialisation if IterTraits. * -# it should be convertible to the pointer type it declares * -# dereferencing it should yield type that is convertible to the reference type - * - CON refers to the data source of this iterator (typically a data container type) - * We store a backlink to this object to invoke a special iteration control API: + * - CON points to the data source of this iterator (typically a data container type) + * We store a pointer-like backlink to invoke a special iteration control API: * -# \c hasNext yields true iff the source has yet more result values to yield * -# \c iterNext advances the POS to the next element * @@ -150,7 +150,7 @@ namespace lib { class IterAdapter : public lib::BoolCheckable > { - const CON* source_; + CON source_; mutable POS pos_; public: @@ -158,7 +158,7 @@ namespace lib { typedef typename IterTraits::reference reference; typedef typename IterTraits::value_type value_type; - IterAdapter (const CON* src, const POS& startpos) + IterAdapter (CON src, POS const& startpos) : source_(src) , pos_(startpos) { diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp index 990aed9fd..9d59f7c3a 100644 --- a/src/proc/mobject/session/query-resolver.cpp +++ b/src/proc/mobject/session/query-resolver.cpp @@ -37,7 +37,7 @@ namespace session { /** TODO??? */ - void + QueryResolver::Invocation QueryResolver::issue (Goal& query) { if (!canHandleQuery (query.getQID())) diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index 6179f6018..1290bd5e8 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -26,10 +26,12 @@ //#include "proc/mobject/mobject.hpp" //#include "proc/mobject/placement.hpp" +#include "lib/bool-checkable.hpp" #include "lib/typed-counter.hpp" #include "lib/iter-adapter.hpp" #include "lib/util.hpp" +#include //#include //#include @@ -43,8 +45,13 @@ namespace session { // class Scope; + class Goal; class QueryResolver; + /** Allow for taking ownership of a result set */ + typedef std::tr1::shared_ptr PGoal; + + /** * TODO type comment @@ -70,20 +77,30 @@ namespace session { class Result + : public lib::BoolCheckable { void *cur_; protected: + void pointAt(void* p) { cur_ = p; } + template - RES& access() + RES& + access() { REQUIRE (cur_); return *reinterpret_cast (cur_); } + + public: + bool isValid() const { return bool(cur_); } + + Result() : cur_(0) { } ///< create an NIL result }; - static bool hasNext (const Goal* thisQuery, Result& pos) { return unConst(thisQuery)->isValid(pos); } ////TICKET #375 - static void iterNext (const Goal* thisQuery, Result& pos) { return unConst(thisQuery)->nextResult(pos);} + + static bool hasNext (PGoal thisQuery, Result& pos) { return thisQuery->isValid(pos); } ////TICKET #375 + static void iterNext (PGoal thisQuery, Result& pos) { thisQuery->nextResult(pos); } protected: QueryID id_; @@ -125,21 +142,25 @@ namespace session { { } /* results retrieval */ - class Cursor : public Goal::Result + class Cursor + : public Goal::Result { public: - RES& operator* () { return access(); } - RES* operator->() { return & access(); } + RES& operator* () { return access(); } + RES* operator->() { return & access(); } + + void pointAt(RES* r){ Goal::Result::pointAt(r);} }; - typedef lib::IterAdapter iterator; - operator iterator() ; + typedef lib::IterAdapter iterator; + iterator operator() (QueryResolver const& resolver); }; + /** * TODO type comment */ @@ -151,15 +172,22 @@ namespace session { virtual ~QueryResolver() ; + struct Invocation + { + PGoal resultSet; + Goal::Result firstResult; + }; + /** issue a query to retrieve contents * The query is handed over internally to a suitable resolver implementation. - * After returning, results can be obtained from the query by iteration. + * @return Invocation data, containing a smart-pointer which \em owns the result set, + * and the first result or NULL result. Usable for building an IterAdapter. * @throw lumiera::Error subclass if query evaluation flounders. * This might be broken logic, invalid input, misconfiguration * or failure of an external facility used for resolution. * @note a query may yield no results, in which case the iterator is empty. */ - void issue (Goal& query); + Invocation issue (Goal& query); protected: @@ -174,14 +202,7 @@ namespace session { Query::operator() (QueryResolver const& resolver) { resolver.issue (*this); - return *this; - } - - - template - Query::operator iterator() - { - UNIMPLEMENTED ("how to get the result iterator"); + return iterator (); } diff --git a/tests/lib/iter-adapter-test.cpp b/tests/lib/iter-adapter-test.cpp index d49878f62..18e567e74 100644 --- a/tests/lib/iter-adapter-test.cpp +++ b/tests/lib/iter-adapter-test.cpp @@ -82,10 +82,11 @@ namespace test{ /* ==== Exposing Iterator interface(s) for the clients ====== */ - typedef IterAdapter<_Vec::iterator, TestContainer> iterator; - typedef IterAdapter<_Vec::const_iterator, TestContainer> const_iterator; - typedef PtrDerefIter ref_iterator; - typedef PtrDerefIter const_ref_iter; + typedef IterAdapter<_Vec::iterator, const TestContainer*> iterator; + typedef IterAdapter<_Vec::const_iterator, const TestContainer*> const_iterator; + + typedef PtrDerefIter ref_iterator; + typedef PtrDerefIter const_ref_iter; iterator begin () { return iterator (this, numberz_.begin()); } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index faa4b3695..18c9131e2 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3476,7 +3476,7 @@ Then, running the goal {{{:-resolve(T, stream(T,mpeg)).}}} would search a Track In the design of the Lumiera Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Pipe, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered "condiguration data" (including the actual plugin implementation to be loaded)
                                    -
                                    +
                                    Within the Lumiera Proc-Layer, there is a general preference for issuing [[queries|Query]] over hard wired configuration (or even mere table based configuration). This leads to the demand of exposing a //possibility to issue queries// &mdash; without actually disclosing much details of the facility implementing this service. For example, for shaping the general session interface (in 10/09), we need a means of exposing a hook to discover HighLevelModel contents, without disclosing how the model is actually organised internally (namely by using an PlacementIndex).
                                     
                                     !Analysis of the problem
                                    @@ -3496,7 +3496,7 @@ The situation can be decomposed as follows.[>img[QueryResolver|uml/fig137733.
                                     
                                     !!!Decisions
                                     * while, in the use case currently at hand, the query instance is created by the client on the stack, the possibility of managing the queries internally is deliberately kept open. Because otherwise, we had to commit to a specific way of obtaining results, for example by assuming always to use an embedded STL iterator.
                                    -* we endorse that uttermost performance is less important than clean separation an extensibility. Thus we accept accessing the current position pointer through reference and we package a ref-counting mechanism together with this current position ("Cursor")
                                    +* we endorse that uttermost performance is less important than clean separation an extensibility. Thus we accept accessing the current position pointer through reference and we use a ref-counting mechanism alongside with the handed out iterator
                                     * the result set is not tied to the query &mdash; at least not by design. The query can be discarded while further exploring the result set.
                                     
                                    From 5968d35cdfb1a8e50a7269265b1df7e7f644594d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Oct 2009 21:39:02 +0100 Subject: [PATCH 026/377] WIP maybe resolved now the knot in my design...? --- doc/devel/uml/fig137733.png | Bin 15785 -> 17651 bytes src/proc/mobject/session/query-resolver.cpp | 9 +- src/proc/mobject/session/query-resolver.hpp | 55 ++++--- uml/lumiera/131077 | 160 +++++++++++++------- uml/lumiera/137733.diagram | 89 +++++++---- uml/lumiera/5.session | 7 +- wiki/renderengine.html | 5 +- 7 files changed, 217 insertions(+), 108 deletions(-) diff --git a/doc/devel/uml/fig137733.png b/doc/devel/uml/fig137733.png index 764c97c51ed0d6763149f40380f6169420d1f74d..61b258961423411b1dcd8827940a13f7a0119512 100644 GIT binary patch literal 17651 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 F{6A8r`_=#e diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp index 9d59f7c3a..323e1e3d7 100644 --- a/src/proc/mobject/session/query-resolver.cpp +++ b/src/proc/mobject/session/query-resolver.cpp @@ -32,12 +32,19 @@ namespace session { + /* generate vtables here */ + + Goal::~Goal() { } + QueryResolver::~QueryResolver() { } + QueryResolver::Resolution::~Resolution() { } + + /** TODO??? */ - QueryResolver::Invocation + QueryResolver::Resolution QueryResolver::issue (Goal& query) { if (!canHandleQuery (query.getQID())) diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index 1290bd5e8..a4e8d3544 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -44,12 +44,12 @@ namespace session { using util::unConst; -// class Scope; class Goal; class QueryResolver; + class QueryResolver::Resolution; /** Allow for taking ownership of a result set */ - typedef std::tr1::shared_ptr PGoal; + typedef std::tr1::shared_ptr PReso; @@ -60,7 +60,7 @@ namespace session { class Goal { public: - virtual ~Goal() {} + virtual ~Goal() ; enum Kind { GENERIC = 0 @@ -99,8 +99,6 @@ namespace session { }; - static bool hasNext (PGoal thisQuery, Result& pos) { return thisQuery->isValid(pos); } ////TICKET #375 - static void iterNext (PGoal thisQuery, Result& pos) { thisQuery->nextResult(pos); } protected: QueryID id_; @@ -109,9 +107,6 @@ namespace session { : id_(quid) { } - /* iteration control */ - virtual bool isValid (Result& pos) =0; /////TODO danger of template bloat? - virtual Result const& nextResult(Result& pos) =0; }; @@ -153,7 +148,7 @@ namespace session { }; - typedef lib::IterAdapter iterator; + typedef lib::IterAdapter iterator; iterator operator() (QueryResolver const& resolver); @@ -171,23 +166,46 @@ namespace session { virtual ~QueryResolver() ; - - struct Invocation + /** + * ABC denoting the result set + * of an individual query resolution + */ + class Resolution { - PGoal resultSet; - Goal::Result firstResult; + typedef Goal::Result Result; + + public: + virtual ~Resolution(); + + static bool + hasNext (PReso&, Result& pos) ////TICKET #375 + { + return bool(pos); + } + + static void + iterNext (PReso& resultSet, Result& pos) + { + resultSet->nextResult(pos); + } + + virtual Result prepareResolution() =0; + + protected: + + virtual Result const& nextResult(Result& pos) =0; }; + /** issue a query to retrieve contents * The query is handed over internally to a suitable resolver implementation. - * @return Invocation data, containing a smart-pointer which \em owns the result set, - * and the first result or NULL result. Usable for building an IterAdapter. + * @return concrete Resolution of the query (ResultSet), \em managed by smart-pointer. * @throw lumiera::Error subclass if query evaluation flounders. * This might be broken logic, invalid input, misconfiguration * or failure of an external facility used for resolution. * @note a query may yield no results, in which case the iterator is empty. */ - Invocation issue (Goal& query); + PReso issue (Goal& query); protected: @@ -201,8 +219,9 @@ namespace session { inline typename Query::iterator Query::operator() (QueryResolver const& resolver) { - resolver.issue (*this); - return iterator (); + PReso resultSet = resolver.issue (*this); + Result first = prepareResolution(); + return iterator (resultSet, first); } diff --git a/uml/lumiera/131077 b/uml/lumiera/131077 index 466d94b36..e6458174f 100644 --- a/uml/lumiera/131077 +++ b/uml/lumiera/131077 @@ -1,6 +1,6 @@ format 58 "ConfigQuery" // CommonLib::ConfigQuery - revision 14 + revision 17 modified_by 5 "hiv" // class settings //class diagram settings @@ -489,6 +489,64 @@ ${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl} + end + + class 159237 "Resolution" + 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 "" + + operation 140037 "isValid" + public explicit_return_type "bool" + nparams 1 + param in name "pos" type class_ref 156933 // Result + 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 + + operation 140165 "nextResult" + public return_type class_ref 156933 // Result + 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 + + classrelation 190469 // + relation 180101 ---> + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 190469 // + b parent class_ref 156933 // Result + end end end @@ -518,41 +576,6 @@ ${inlines} idl_decl "" explicit_switch_type "" - end - - operation 140037 "isValid" - public explicit_return_type "bool" - nparams 1 - param in name "pos" type class_ref 156933 // Result - 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 - - operation 140165 "nextResult" - public return_type class_ref 156933 // Result - 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 classrelation 181765 // @@ -651,22 +674,22 @@ ${inlines} idl_decl "" explicit_switch_type "" - classrelation 187397 // pos_ () - relation 177029 ---> - a role_name "pos_" protected - cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; -" - classrelation_ref 187397 // pos_ () - b parent class_ref 156933 // Result - end - - classrelation 187525 // source_ () - relation 177157 ---> + classrelation 188805 // source_ () + relation 178437 ---> a role_name "source_" protected cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; " - classrelation_ref 187525 // source_ () - b parent class_ref 158085 // SolutionResultSet + classrelation_ref 188805 // source_ () + b parent class_ref 159237 // Resolution + end + + classrelation 188933 // pos_ () + relation 178565 ---> + a role_name "pos_" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 188933 // pos_ () + b parent class_ref 155269 // Cursor end end @@ -698,15 +721,36 @@ ${inlines} cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; " classrelation_ref 186117 // - b parent class_ref 158085 // SolutionResultSet + b parent class_ref 158085 // ResultSet + end + + classrelation 190085 // + relation 179717 -_-> + a default + cpp default "#include in source" + classrelation_ref 190085 // + b parent class_ref 155525 // ResolvingFacility + end + + classrelation 190213 // + relation 179845 -_-> + a default + cpp default "#include in source" + classrelation_ref 190213 // + b parent class_ref 153989 // QueryResolver + end + + classrelation 190341 // + relation 179973 -_-> + a default + cpp default "#include in source" + classrelation_ref 190341 // + b parent class_ref 153989 // QueryResolver end end - class 158085 "SolutionResultSet" + class 158085 "ResultSet" visibility package - nactuals 1 - actual class class_ref 155141 // Query - rank 0 explicit_value "" cpp_decl "${comment}${template}class ${name}${inherit} { ${members} }; @@ -718,12 +762,12 @@ ${inlines} idl_decl "" explicit_switch_type "" - classrelation 187269 // - relation 176901 ---|> + classrelation 188677 // + relation 178309 ---|> a public cpp default "${type}" - classrelation_ref 187269 // - b parent class_ref 155141 // Query + classrelation_ref 188677 // + b parent class_ref 159237 // Resolution end end end diff --git a/uml/lumiera/137733.diagram b/uml/lumiera/137733.diagram index f6a2a9bb3..918a3b519 100644 --- a/uml/lumiera/137733.diagram +++ b/uml/lumiera/137733.diagram @@ -2,7 +2,7 @@ format 58 classcanvas 128005 class_ref 153989 // QueryResolver 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 262 25 2000 + xyz 394 49 2000 end classcanvas 128133 class_ref 155141 // Query 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 @@ -10,11 +10,11 @@ classcanvas 128133 class_ref 155141 // Query end classcanvas 128517 class_ref 155397 // IterAdapter 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 24 222 2000 + xyz 52 373 2000 end classcanvas 128645 class_ref 155525 // ResolvingFacility 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 427 339 2000 + xyz 382 362 2015 end classcanvas 129797 class_ref 156805 // Goal 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 @@ -28,9 +28,23 @@ classcanvas 131205 class_ref 155269 // Cursor 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 246 339 2005 end -classcanvas 133509 class_ref 158085 // SolutionResultSet +classcanvas 133509 class_ref 158085 // ResultSet 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 355 444 2000 + xyz 343 439 2000 +end +classcanvas 135685 class_ref 159237 // Resolution + 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 340 209 2004 +end +note 136965 "Client" + color lightmediumgreen xyzwh 23 431 2000 52 35 +classcanvas 137093 class_ref 155525 // ResolvingFacility + 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 438 344 2010 +end +classcanvas 137221 class_ref 155525 // ResolvingFacility + 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 492 327 1994 end line 128389 ---+ from ref 131077 z 1999 to ref 129797 @@ -48,46 +62,67 @@ relationcanvas 132229 relation_ref 171141 // end relationcanvas 132357 relation_ref 169733 // geometry VHV unfixed - from ref 128645 z 1999 to point 473 128 - line 132485 z 1999 to point 303 128 - line 132613 z 1999 to ref 128005 + from ref 128645 z 1999 to point 428 227 + line 138117 z 1999 to point 435 227 + line 138245 z 1999 to ref 128005 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end relationcanvas 133125 relation_ref 174469 // geometry VHr - from ref 128133 z 1999 stereotype "<>" xyz 64 319 3000 to point 55 317 + from ref 128133 z 1999 stereotype "<>" xyz 91 307 3000 to point 83 317 line 133381 z 1999 to ref 128517 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end relationcanvas 134021 relation_ref 175749 // decenter_end 830 - from ref 128645 z 1999 stereotype "<>" xyz 450 406 3000 to ref 133509 + from ref 128645 z 1999 stereotype "<>" xyz 406 417 3000 to ref 133509 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end -relationcanvas 134149 relation_ref 176901 // +line 135813 ---+ + from ref 135685 z 1999 to ref 128005 +relationcanvas 135941 relation_ref 178309 // + from ref 133509 z 1999 to ref 135685 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 136069 relation_ref 178437 // + decenter_begin 603 + from ref 128517 z 1999 to point 116 405 + line 136197 z 1999 to point 298 405 + line 136325 z 1999 to ref 135685 + role_a_pos 124 406 3000 no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 136581 relation_ref 178565 // + from ref 128517 z 1999 to point 117 392 + line 136837 z 1999 to point 219 392 + line 136709 z 1999 to ref 131205 + role_a_pos 124 393 3000 no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 137733 relation_ref 179845 // + geometry VHV + from ref 137093 z 1999 to point 484 227 + line 137861 z 1999 to point 435 227 + line 137989 z 1999 to ref 128005 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 138373 relation_ref 179973 // geometry VHV unfixed - from ref 133509 z 1999 to point 402 422 - line 134277 z 1999 to point 195 422 - line 134405 z 1999 to ref 128133 + from ref 137221 z 1999 to point 538 227 + line 138501 z 1999 to point 435 227 + line 138629 z 1999 to ref 128005 no_role_a no_role_b no_multiplicity_a no_multiplicity_b end -relationcanvas 134789 relation_ref 177029 // - from ref 128517 z 1999 to point 89 239 - line 135301 z 1999 to ref 131077 - role_a_pos 101 240 3000 no_role_b +relationcanvas 138757 relation_ref 180101 // + from ref 135685 z 1999 to ref 131077 + no_role_a no_role_b no_multiplicity_a no_multiplicity_b end -relationcanvas 134917 relation_ref 177157 // - from ref 128517 z 1999 to point 89 251 - line 135557 z 1999 to point 144 251 - line 135173 z 1999 to point 195 461 - line 135045 z 1999 to ref 133509 - role_a_pos 101 253 3000 no_role_b - no_multiplicity_a no_multiplicity_b -end -preferred_whz 629 529 1 +preferred_whz 612 547 1 end diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session index 2cda23c29..2667b5cd6 100644 --- a/uml/lumiera/5.session +++ b/uml/lumiera/5.session @@ -5,7 +5,7 @@ diagrams classdiagram_ref 136325 // Focus of Query 582 515 100 4 0 0 active classdiagram_ref 137733 // Query Interface - 629 542 100 4 0 0 + 612 547 100 4 0 0 end show_stereotypes selected @@ -25,11 +25,14 @@ open class_ref 133253 // Frame classview_ref 129541 // InterfaceSystem classview_ref 129285 // StreamType - class_ref 153989 // QueryResolver + classdiagram_ref 137733 // Query Interface + operation_ref 140037 // isValid + operation_ref 140165 // nextResult class_ref 156933 // Result classrelation_ref 181765 // class_ref 155141 // Query class_ref 155525 // ResolvingFacility + class_ref 158085 // ResultSet classview_ref 132229 // Custom holders classview_ref 128266 // SmartPointers end diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 18c9131e2..4b3fbe2ac 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3476,7 +3476,7 @@ Then, running the goal {{{:-resolve(T, stream(T,mpeg)).}}} would search a Track In the design of the Lumiera Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Pipe, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered "condiguration data" (including the actual plugin implementation to be loaded)
                                    -
                                    +
                                    Within the Lumiera Proc-Layer, there is a general preference for issuing [[queries|Query]] over hard wired configuration (or even mere table based configuration). This leads to the demand of exposing a //possibility to issue queries// &mdash; without actually disclosing much details of the facility implementing this service. For example, for shaping the general session interface (in 10/09), we need a means of exposing a hook to discover HighLevelModel contents, without disclosing how the model is actually organised internally (namely by using an PlacementIndex).
                                     
                                     !Analysis of the problem
                                    @@ -3496,8 +3496,9 @@ The situation can be decomposed as follows.[>img[QueryResolver|uml/fig137733.
                                     
                                     !!!Decisions
                                     * while, in the use case currently at hand, the query instance is created by the client on the stack, the possibility of managing the queries internally is deliberately kept open. Because otherwise, we had to commit to a specific way of obtaining results, for example by assuming always to use an embedded STL iterator.
                                    -* we endorse that uttermost performance is less important than clean separation an extensibility. Thus we accept accessing the current position pointer through reference and we use a ref-counting mechanism alongside with the handed out iterator
                                    +* we endorse that uttermost performance is less important than clean separation an extensibility. Thus we accept accessing the current position pointer through reference and we use a ref-counting mechanism alongside with the iterator to be handed out to the client
                                     * the result set is not tied to the query &mdash; at least not by design. The query can be discarded while further exploring the result set.
                                    +* for dealing with the TypedQueryProblem, we require the concrete resolving facilities to register with a system startup hook, to build a dispatcher table on the implementation side. This allows us to downcast to the concrete Cursor type on iteration and results retrieval.
                                     
                                    From ec4b2eef00f3e2ec29a349bc57055b9aa6f4a651 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 26 Oct 2009 01:39:25 +0100 Subject: [PATCH 027/377] WIP: test-driven brainstorming: how to build the query dispatcher table? --- src/proc/mobject/session/query-resolver.cpp | 6 +- src/proc/mobject/session/query-resolver.hpp | 15 +- .../mobject/session/query-resolver-test.cpp | 74 +++++++++- tests/lib/multifact-argument-test.cpp | 137 ++++++++++++++++++ 4 files changed, 224 insertions(+), 8 deletions(-) create mode 100644 tests/lib/multifact-argument-test.cpp diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp index 323e1e3d7..3c5974b49 100644 --- a/src/proc/mobject/session/query-resolver.cpp +++ b/src/proc/mobject/session/query-resolver.cpp @@ -41,10 +41,14 @@ namespace session { QueryResolver::Resolution::~Resolution() { } + struct QueryDispatcher + { + + }; /** TODO??? */ - QueryResolver::Resolution + PReso QueryResolver::issue (Goal& query) { if (!canHandleQuery (query.getQID())) diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index a4e8d3544..6d095323b 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -31,6 +31,7 @@ #include "lib/iter-adapter.hpp" #include "lib/util.hpp" +#include #include //#include //#include @@ -46,6 +47,7 @@ namespace session { class Goal; class QueryResolver; + class QueryDispatcher; class QueryResolver::Resolution; /** Allow for taking ownership of a result set */ @@ -82,7 +84,7 @@ namespace session { void *cur_; protected: - void pointAt(void* p) { cur_ = p; } + void point_at(void* p) { cur_ = p; } template RES& @@ -141,10 +143,10 @@ namespace session { : public Goal::Result { public: - RES& operator* () { return access(); } - RES* operator->() { return & access(); } + RES& operator* () { return access(); } + RES* operator->() { return & access(); } - void pointAt(RES* r){ Goal::Result::pointAt(r);} + void point_at(RES* r){ Goal::Result::pointAt(r);} }; @@ -161,6 +163,7 @@ namespace session { */ class QueryResolver { + boost::scoped_ptr dispatcher_; public: @@ -189,11 +192,11 @@ namespace session { resultSet->nextResult(pos); } - virtual Result prepareResolution() =0; + virtual Result prepareResolution() =0; protected: - virtual Result const& nextResult(Result& pos) =0; + virtual void nextResult(Result& pos) =0; }; diff --git a/tests/components/proc/mobject/session/query-resolver-test.cpp b/tests/components/proc/mobject/session/query-resolver-test.cpp index c8301cbe7..9acb18ac6 100644 --- a/tests/components/proc/mobject/session/query-resolver-test.cpp +++ b/tests/components/proc/mobject/session/query-resolver-test.cpp @@ -28,6 +28,7 @@ //#include "proc/mobject/session/test-scopes.hpp" //#include "proc/mobject/placement-index.hpp" #include "proc/mobject/session/query-resolver.hpp" +//#include "lib/symbol.hpp" //#include "lib/access-casted.hpp" //#include "lib/variant.hpp" //#include "lib/meta/typelist.hpp" @@ -51,10 +52,81 @@ namespace test { namespace { // a test query resolving facility - + + template + class DummySolution; + + class DummySolution + { + int resNr_; + + public: + DummySolution() : resNr_(7) {} + + int* next () { --resNr_; return &resNr_; } + bool exhausted() { return bool(resNr_); } + }; + + class DummySolution + : DummySolution + { + string currentText_; + + public: + string* + next () + { + static char* lumi ="Lumiera"; + currentText_ = string (lumi[*DummySolution::next()]); + return ¤tText_; + } + }; + + template + struct DummyResultSet + : QueryResolver::Resolution + { + DummySolution solution_; + + typedef typename Query::Cursor Cursor; + + Result + prepareResolution() + { + Cursor cursor; + cursor.pointAt (solution_.next()); + return cursor; + } + + void + nextResult(Result& pos) + { + Cursor& cursor = static_cast (pos); + + if (solution_.exhausted()) + cursor.point_at (0); + else + cursor.point_at (solution_.next()); + } + }; + class TypeMatchFilter : public QueryResolver { + bool + canHandleQuery (Goal::QueryID qID) const + { + return Goal::GENERIC == qID.kind + && (wantResultType (qID) + ||wantResultType(qID)); + } + + template + bool + wantResultType (Goal::QueryID qID) + { + return qID.type == ResultType::ID::get(); + } }; diff --git a/tests/lib/multifact-argument-test.cpp b/tests/lib/multifact-argument-test.cpp new file mode 100644 index 000000000..d2df7c886 --- /dev/null +++ b/tests/lib/multifact-argument-test.cpp @@ -0,0 +1,137 @@ +/* + MultiFact(Test) - unittest for the configurable object-family creating factory + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" +#include "lib/multifact.hpp" +#include "lib/util.hpp" + +#include +#include +#include + + + +namespace lib { +namespace test{ + + using boost::lexical_cast; + using lib::test::showSizeof; + using util::isSameObject; + using util::isnil; + using std::ostream; + using std::string; + using std::cout; + using std::endl; + + using lumiera::error::LUMIERA_ERROR_INVALID; + + + namespace { // hierarchy of test dummy objects + + struct Interface + { + virtual ~Interface() {}; + virtual operator string () =0; + }; + + inline ostream& operator<< (ostream& os, Interface& ifa) { return os << string(ifa); } + + + enum theID + { ONE = 1 + , TWO + , THR + , FOU + }; + + typedef factory::MultiFact TestFactory; + + + template + class Implementation + : public Interface + { + operator string() + { + return "Impl-"+lexical_cast (ii); + } + + public: + static theID getTypeID() { return ii; } + }; + + /** Factory instance for the tests... */ + TestFactory theFact; + + // Configure the products to be fabricated.... + TestFactory::Singleton > holder1 (theFact,ONE); + TestFactory::Singleton > holder2 (theFact,TWO); + TestFactory::Singleton > holder3 (theFact,THR); + TestFactory::Singleton > holder4 (theFact,FOU); + } + + + + + + /******************************************************************* + * @test verify simple setup of the MultiFact template. + * Define a hierarchy of test dummy objects, such as to + * register them automatically for creation through a suitable + * instantiation of MultiFact. Verify we get the correct product + * when invoking this MultiFac flavour. + * @see lib::MultiFact + */ + class MultiFact_test : public Test + { + void + run (Arg) + { + cout << theFact(ONE) << endl; + cout << theFact(TWO) << endl; + cout << theFact(THR) << endl; + cout << theFact(FOU) << endl; + cout << showSizeof (theFact) << endl; + + Interface & o1 = theFact(ONE); + Interface & o2 = theFact(ONE); + ASSERT (isSameObject(o1,o2)); + + TestFactory anotherFact; + ASSERT (isnil (anotherFact)); + VERIFY_ERROR (INVALID, anotherFact(ONE) ); + + TestFactory::Singleton > anotherSingletonHolder (anotherFact,ONE); + Interface & o3 = anotherFact(ONE); + ASSERT (isSameObject(o2,o3)); + } + }; + + + /** Register this test class... */ + LAUNCHER (MultiFact_test, "unit common"); + + + +}} // namespace lib::test From 6dc09e66dc1ae5a1b69538ed22bddad077c4ed2b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 26 Oct 2009 01:42:35 +0100 Subject: [PATCH 028/377] WIP: test-driven brainstorming: how to pass additional factory arguments? (Ticket #377) --- tests/40components.tests | 5 ++ tests/lib/multifact-argument-test.cpp | 112 +++++++++++--------------- 2 files changed, 54 insertions(+), 63 deletions(-) diff --git a/tests/40components.tests b/tests/40components.tests index 01d959a34..b46711e0c 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -294,6 +294,11 @@ return: 0 END +PLANNED "Factory argument handling" MultiFactArgument_test < @@ -24,71 +24,60 @@ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "lib/multifact.hpp" -#include "lib/util.hpp" +//#include "lib/util.hpp" -#include +//#include #include -#include +//#include +#include namespace lib { namespace test{ - using boost::lexical_cast; +// using boost::lexical_cast; using lib::test::showSizeof; - using util::isSameObject; - using util::isnil; - using std::ostream; - using std::string; +// using util::isSameObject; +// using util::isnil; +// using std::ostream; +// using std::string; using std::cout; using std::endl; + using std::tr1::bind; - using lumiera::error::LUMIERA_ERROR_INVALID; +// using lumiera::error::LUMIERA_ERROR_INVALID; - namespace { // hierarchy of test dummy objects + namespace { // a test-dummy ID type, used to encapsulate additional arguments - struct Interface - { - virtual ~Interface() {}; - virtual operator string () =0; - }; - - inline ostream& operator<< (ostream& os, Interface& ifa) { return os << string(ifa); } - - - enum theID + enum baseType { ONE = 1 , TWO - , THR - , FOU }; - typedef factory::MultiFact TestFactory; - - - template - class Implementation - : public Interface + struct DummyID { - operator string() - { - return "Impl-"+lexical_cast (ii); - } - - public: - static theID getTypeID() { return ii; } + baseType bas; + int additionalInfo; }; - /** Factory instance for the tests... */ - TestFactory theFact; - // Configure the products to be fabricated.... - TestFactory::Singleton > holder1 (theFact,ONE); - TestFactory::Singleton > holder2 (theFact,TWO); - TestFactory::Singleton > holder3 (theFact,THR); - TestFactory::Singleton > holder4 (theFact,FOU); + struct Num { int n_; }; + + /** dummy "factory" function to be invoked */ + Num* + fabricateNumberz (int base, int offset) + { + cout << "fabricate("<n_ = base*offset; + return product; + } + + + typedef factory::MultiFact TestFactory; + } @@ -96,41 +85,38 @@ namespace test{ /******************************************************************* - * @test verify simple setup of the MultiFact template. - * Define a hierarchy of test dummy objects, such as to - * register them automatically for creation through a suitable - * instantiation of MultiFact. Verify we get the correct product - * when invoking this MultiFac flavour. + * @test define a MultiFact (factory with dynamic registration), + * which accepts additional arguments and passes them + * through to the registered factory function(s). * @see lib::MultiFact + * @see query-resolver.cpp */ - class MultiFact_test : public Test + class MultiFactArgument_test : public Test { void run (Arg) { - cout << theFact(ONE) << endl; - cout << theFact(TWO) << endl; - cout << theFact(THR) << endl; - cout << theFact(FOU) << endl; + TestFactory theFact; + theFact.defineProduction (ONE, bind (&fabricateNumberz, 1, _1)); + theFact.defineProduction (TWO, bind (&fabricateNumberz, 2, _1)); + cout << showSizeof (theFact) << endl; - Interface & o1 = theFact(ONE); - Interface & o2 = theFact(ONE); - ASSERT (isSameObject(o1,o2)); + typedef TestFactory::PType PP; - TestFactory anotherFact; - ASSERT (isnil (anotherFact)); - VERIFY_ERROR (INVALID, anotherFact(ONE) ); + DummyID id1 = {ONE, 2}; + DummyID id1 = {TWO, 3}; - TestFactory::Singleton > anotherSingletonHolder (anotherFact,ONE); - Interface & o3 = anotherFact(ONE); - ASSERT (isSameObject(o2,o3)); + PP p1 = theFact(id1); + PP p2 = theFact(id2); + ASSERT (1*2 == p1->n_); + ASSERT (2*3 == p2->n_); } }; /** Register this test class... */ - LAUNCHER (MultiFact_test, "unit common"); + LAUNCHER (MultiFactArgument_test, "unit common"); From 2530e8c1a163ef4be6f3eb5c104b482b2e92cf4e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 27 Oct 2009 05:13:38 +0100 Subject: [PATCH 029/377] WIP try to create an extension point to MultiFact, allowing to accept argument(s) sketch of an idea how to add an extension possibility without messing up the basic MultiFact template --- src/lib/multifact-arg.hpp | 100 ++++++++++++++++++++++++++ src/lib/multifact.hpp | 38 +++++++--- tests/lib/multifact-argument-test.cpp | 2 +- 3 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 src/lib/multifact-arg.hpp diff --git a/src/lib/multifact-arg.hpp b/src/lib/multifact-arg.hpp new file mode 100644 index 000000000..fda2d087a --- /dev/null +++ b/src/lib/multifact-arg.hpp @@ -0,0 +1,100 @@ +/* + MULTIFACT-ARG.hpp - variant of family-of-object factory, accepting fabrication arguments + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file multifact.hpp + ** Extension allowing the MultiFact to pass arguments to the fabrication. + ** This extension is implemented by template specialisations and thus kicks in + ** when specifying a function \em signature as factory "product type". The resulting + ** factory class exposes a function call operator matching this signature, additionally + ** expecting the ID (to select the specific fabrication function) as first parameter. + ** + ** @todo WIP-WIP-WIP ... does this work out as intended?? TICKET #377 + ** + ** @see multifact-argument-test.cpp + ** @see query-resolver.cpp usage example + ** @see multifact.hpp standard case + */ + + +#ifndef LIB_MULTIFACT_ARG_H +#define LIB_MULTIFACT_ARG_H + + +#include "lib/multifact.hpp" + + + +namespace lib { + namespace factory { + + + using std::tr1::function; + + + template + struct FabTraits + { + typedef TY RawProduct; + typedef RawProduct FacSig(ARG); + typedef ARG Argument; + }; + + + + + /** + * Variant of MultiFact, selecting a creator function by ID + * with the ability to pass additional argument(s) to this + * creator function on invocation. + * TODO type comment + */ + template< typename SIG, + , typename ID + , template class Wrapper + > + class MultiFact, ID, Wrapper> + : public MultiFact + { + + typedef typename FabTraits::Argument ArgType; + + public: + Product + operator() (ID const& id, ArgType arg) + { + Creator& func = selectProducer (id); + return wrap (func(arg)); + } + + }; + + + + } // namespace factory + + + + // TODO is there some suitable standard configuration we could provide here?? + + +} // namespace lib +#endif diff --git a/src/lib/multifact.hpp b/src/lib/multifact.hpp index 1e15949eb..37ff84d4f 100644 --- a/src/lib/multifact.hpp +++ b/src/lib/multifact.hpp @@ -25,6 +25,7 @@ ** ** @todo WIP-WIP-WIP ... currently collecting various bits of implementation here. TICKET #277 ** + ** @see multifact-test.cpp ** @see SingletonFactory ** @see lib::factory::Factory */ @@ -60,6 +61,15 @@ namespace lib { }; + template + struct FabTraits + { + typedef TY RawProduct; + typedef RawProduct FacSig(void); + }; + + + /** * Table of registered production functions for MultiFact. * Each stored function can be accessed by ID and is able @@ -68,12 +78,12 @@ namespace lib { template struct Fab { - typedef TY& RawProduct; - typedef std::tr1::function FactoryFunc; + typedef typename FabTraits::FacSig Signature; + typedef std::tr1::function FactoryFunc; FactoryFunc& - select (ID id) + select (ID const& id) { if (!contains (id)) throw lumiera::error::Invalid("unknown factory product requested."); @@ -82,7 +92,7 @@ namespace lib { } void - defineProduction (ID id, FactoryFunc fun) + defineProduction (ID const& id, FactoryFunc fun) { producerTable_[id] = fun; } @@ -114,20 +124,30 @@ namespace lib { , template class Wrapper > class MultiFact - : Wrapper + : Wrapper::RawProduct> { typedef Fab _Fab; - typedef typename _Fab::FactoryFunc Creator; - typedef typename Wrapper::PType Product; _Fab funcTable_; + protected: + typedef typename FabTraits::RawProduct RawType; + typedef typename Wrapper::PType Product; + typedef typename _Fab::FactoryFunc Creator; + + + Creator& + selectProducer (ID const& id) + { + return funcTable_.select(id); + } + public: Product - operator() (ID id) + operator() (ID const& id) { - Creator& func = funcTable_.select(id); + Creator& func = selectProducer (id); return wrap (func()); } diff --git a/tests/lib/multifact-argument-test.cpp b/tests/lib/multifact-argument-test.cpp index 462f76ff1..c83f36061 100644 --- a/tests/lib/multifact-argument-test.cpp +++ b/tests/lib/multifact-argument-test.cpp @@ -102,7 +102,7 @@ namespace test{ cout << showSizeof (theFact) << endl; - typedef TestFactory::PType PP; + typedef TestFactory::Product PP; DummyID id1 = {ONE, 2}; DummyID id1 = {TWO, 3}; From 0cef067c11fbfd885573c8ab22baa58afa6f3285 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 28 Oct 2009 04:45:17 +0100 Subject: [PATCH 030/377] WIP adapt unit test and the argument-accepting MultiFact specialisation --- src/lib/multifact-arg.hpp | 4 ++- src/lib/multifact.hpp | 36 ++++++++++++++++++------ tests/42query.tests | 8 ++++++ tests/43session.tests | 4 --- tests/lib/multifact-argument-test.cpp | 40 +++++++++++++++------------ 5 files changed, 62 insertions(+), 30 deletions(-) diff --git a/src/lib/multifact-arg.hpp b/src/lib/multifact-arg.hpp index fda2d087a..d47ddd6c4 100644 --- a/src/lib/multifact-arg.hpp +++ b/src/lib/multifact-arg.hpp @@ -41,6 +41,8 @@ #include "lib/multifact.hpp" +#include + namespace lib { @@ -54,7 +56,7 @@ namespace lib { struct FabTraits { typedef TY RawProduct; - typedef RawProduct FacSig(ARG); + typedef RawProduct FabSig(ARG); typedef ARG Argument; }; diff --git a/src/lib/multifact.hpp b/src/lib/multifact.hpp index 37ff84d4f..fee171b96 100644 --- a/src/lib/multifact.hpp +++ b/src/lib/multifact.hpp @@ -40,6 +40,7 @@ #include "util.hpp" #include +#include #include @@ -55,17 +56,33 @@ namespace lib { template struct PassReference { + typedef TAR& RType; typedef TAR& PType; - PType wrap (TAR& object) { return object; } + PType wrap (RType object) { return object; } }; + /** + * Wrapper taking ownership, + * by wrapping into smart-ptr + */ + template + struct BuildRefcountPtr + { + typedef TAR* RType; + typedef std::tr1::shared_ptr PType; + + PType wrap (RType ptr) { return PType (ptr); } + }; + + + template struct FabTraits { typedef TY RawProduct; - typedef RawProduct FacSig(void); + typedef RawProduct FabSig(void); }; @@ -78,7 +95,7 @@ namespace lib { template struct Fab { - typedef typename FabTraits::FacSig Signature; + typedef typename FabTraits::FabSig Signature; typedef std::tr1::function FactoryFunc; @@ -126,15 +143,18 @@ namespace lib { class MultiFact : Wrapper::RawProduct> { - typedef Fab _Fab; + typedef Wrapper::RawProduct> _Wrap; + typedef typename FabTraits::RawProduct RawType; + typedef typename _Wrap::PType WrappedProduct; + typedef typename _Wrap::RType FabProduct; + typedef Fab _Fab; _Fab funcTable_; - protected: - typedef typename FabTraits::RawProduct RawType; - typedef typename Wrapper::PType Product; - typedef typename _Fab::FactoryFunc Creator; + protected: + typedef typename _Fab::FactoryFunc Creator; + typedef WrappedProduct Product; Creator& selectProducer (ID const& id) diff --git a/tests/42query.tests b/tests/42query.tests index d05c27fcc..5d437cc41 100644 --- a/tests/42query.tests +++ b/tests/42query.tests @@ -2,6 +2,14 @@ TESTING "Proc Layer config rules Test Suite" ./test-lib --group=query +PLANNED "issuing typed queries" QueryResolver_test < @@ -45,27 +45,27 @@ namespace test{ using std::cout; using std::endl; using std::tr1::bind; + using std::tr1::function; + using std::tr1::placeholders::_1; // using lumiera::error::LUMIERA_ERROR_INVALID; - namespace { // a test-dummy ID type, used to encapsulate additional arguments + namespace { // dummy fabrication function, creating wrapped numbers, controlled by an additional argument - enum baseType + enum prodID { ONE = 1 , TWO }; - struct DummyID - { - baseType bas; - int additionalInfo; - }; - - struct Num { int n_; }; - /** dummy "factory" function to be invoked */ + /** dummy "factory" function to be invoked + * @return pointer to heap allocated product object + * @note this function needs to deliver the product in a form + * which can be accepted by the concrete wrapper, which + * is going to be configured into the factory. + */ Num* fabricateNumberz (int base, int offset) { @@ -76,7 +76,11 @@ namespace test{ } - typedef factory::MultiFact TestFactory; + /** the factory instantiation used for this test */ + typedef factory::MultiFact< function // nominal signature of fabrication + , prodID // select factory function by prodID + , factory::BuildRefcountPtr // wrapper: manage product by smart-ptr + > TestFactory; } @@ -88,6 +92,11 @@ namespace test{ * @test define a MultiFact (factory with dynamic registration), * which accepts additional arguments and passes them * through to the registered factory function(s). + * @note we set up fabrication functions by binding such as to match + * the function signature declared in the factory; thereby one + * argument remains unclosed, which is the argument to be + * supplied on each factory invocation by the client code. + * * @see lib::MultiFact * @see query-resolver.cpp */ @@ -104,11 +113,8 @@ namespace test{ typedef TestFactory::Product PP; - DummyID id1 = {ONE, 2}; - DummyID id1 = {TWO, 3}; - - PP p1 = theFact(id1); - PP p2 = theFact(id2); + PP p1 = theFact(ONE, 2); + PP p2 = theFact(TWO, 3); ASSERT (1*2 == p1->n_); ASSERT (2*3 == p2->n_); } From 3145064a21fbd13c2dc8c8c135c783b0ee04d83c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 29 Oct 2009 04:31:16 +0100 Subject: [PATCH 031/377] change IterAdapter iteration control API to use free functions --- src/lib/iter-adapter.hpp | 8 ++++---- tests/lib/iter-adapter-test.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 5883d5512..e5ad6d15c 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -125,8 +125,8 @@ namespace lib { * - it is not just a disguised pointer (meaning, it's more expensive) * - it checks validity on every operation and may throw * - it has a distinct back-link to the source container - * - the source container needs to implement iterStart() and iterInc() - * - we need friendship to access the callbacks on the container + * - the source container needs to provide hasNext() and iterNext() free functions. + * - we may need friendship to implement those extension points on the container * - the end-of-iteration can be detected by bool check * * \par Stipulations @@ -227,7 +227,7 @@ namespace lib { bool checkPos() const { - return source_ && CON::hasNext (source_,pos_); + return source_ && hasNext (source_,pos_); } /** ask the controlling container to yield the next position. @@ -240,7 +240,7 @@ namespace lib { { if (!checkPos()) return false; - CON::iterNext (source_,pos_); + iterNext (source_,pos_); return checkPos(); } diff --git a/tests/lib/iter-adapter-test.cpp b/tests/lib/iter-adapter-test.cpp index 18e567e74..112a231af 100644 --- a/tests/lib/iter-adapter-test.cpp +++ b/tests/lib/iter-adapter-test.cpp @@ -106,7 +106,7 @@ namespace test{ /** Implementation of Iteration-logic: pull next element. */ template - static void + friend void iterNext (const TestContainer*, ITER& pos) { ++pos; @@ -121,7 +121,7 @@ namespace test{ * immediately transform this into the official "bottom" */ template - static bool + friend bool hasNext (const TestContainer* src, ITER& pos) { REQUIRE (src); From 54aa7b4afebe7951b62f082b08551564e6067dfb Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 29 Oct 2009 04:32:00 +0100 Subject: [PATCH 032/377] WIP fixes and stubbing to get at compiling the MultiFact --- src/lib/multifact-arg.hpp | 7 +- src/proc/mobject/placement-index.cpp | 7 ++ src/proc/mobject/placement-index.hpp | 3 + src/proc/mobject/session/query-resolver.cpp | 7 +- src/proc/mobject/session/query-resolver.hpp | 74 +++++++++++---------- src/proc/mobject/session/scope-path.cpp | 16 +++++ src/proc/mobject/session/scope-path.hpp | 5 ++ src/proc/mobject/session/scope.cpp | 14 ++++ src/proc/mobject/session/scope.hpp | 3 + 9 files changed, 97 insertions(+), 39 deletions(-) diff --git a/src/lib/multifact-arg.hpp b/src/lib/multifact-arg.hpp index d47ddd6c4..c0c779c60 100644 --- a/src/lib/multifact-arg.hpp +++ b/src/lib/multifact-arg.hpp @@ -69,16 +69,19 @@ namespace lib { * creator function on invocation. * TODO type comment */ - template< typename SIG, + template< typename SIG , typename ID , template class Wrapper > class MultiFact, ID, Wrapper> : public MultiFact { - + typedef MultiFact _Base; typedef typename FabTraits::Argument ArgType; + typedef typename _Base::Product Product; + typedef typename _Base::Creator Creator; + public: Product operator() (ID const& id, ArgType arg) diff --git a/src/proc/mobject/placement-index.cpp b/src/proc/mobject/placement-index.cpp index ac6bbb279..dc84d0481 100644 --- a/src/proc/mobject/placement-index.cpp +++ b/src/proc/mobject/placement-index.cpp @@ -76,6 +76,13 @@ namespace mobject { PlacementIndex::~PlacementIndex() { } + bool + PlacementIndex::canHandleQuery (session::Goal::QueryID qID) const + { + UNIMPLEMENTED ("decide by hard-wired check if the given Query can be resolved by PlacementIndex"); + } + + PlacementMO& PlacementIndex::getRoot() const { diff --git a/src/proc/mobject/placement-index.hpp b/src/proc/mobject/placement-index.hpp index 98de15581..553419d32 100644 --- a/src/proc/mobject/placement-index.hpp +++ b/src/proc/mobject/placement-index.hpp @@ -99,6 +99,9 @@ namespace mobject { ///////////////////////////////////////////TODO: shouldn't t query (PlacementMO& scope) const; + bool canHandleQuery(session::Goal::QueryID) const; + + /* == mutating operations == */ ID insert (PlacementMO& newObj, PlacementMO& targetScope); diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp index 3c5974b49..6cdd21894 100644 --- a/src/proc/mobject/session/query-resolver.cpp +++ b/src/proc/mobject/session/query-resolver.cpp @@ -38,7 +38,7 @@ namespace session { QueryResolver::~QueryResolver() { } - QueryResolver::Resolution::~Resolution() { } + Resolution::~Resolution() { } struct QueryDispatcher @@ -47,6 +47,11 @@ namespace session { }; + QueryResolver::QueryResolver () + : dispatcher_(new QueryDispatcher) + { } + + /** TODO??? */ PReso QueryResolver::issue (Goal& query) diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index 6d095323b..fcf13981c 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -46,12 +46,12 @@ namespace session { class Goal; + class Resolution; class QueryResolver; class QueryDispatcher; - class QueryResolver::Resolution; /** Allow for taking ownership of a result set */ - typedef std::tr1::shared_ptr PReso; + typedef std::tr1::shared_ptr PReso; @@ -106,7 +106,7 @@ namespace session { QueryID id_; Goal (QueryID qid) - : id_(quid) + : id_(qid) { } }; @@ -146,18 +146,48 @@ namespace session { RES& operator* () { return access(); } RES* operator->() { return & access(); } - void point_at(RES* r){ Goal::Result::pointAt(r);} + void point_at(RES* r){ Goal::Result::point_at(r);} }; - typedef lib::IterAdapter iterator; + typedef lib::IterAdapter iterator; iterator operator() (QueryResolver const& resolver); }; - + /** + * ABC denoting the result set + * of an individual query resolution + */ + class Resolution + { + typedef Goal::Result Result; + + public: + virtual ~Resolution(); + + static bool + hasNext (PReso&, Result& pos) ////TICKET #375 + { + return bool(pos); + } + + static void + iterNext (PReso& resultSet, Result& pos) + { + resultSet->nextResult(pos); + } + + virtual Result prepareResolution() =0; + + protected: + + virtual void nextResult(Result& pos) =0; + }; + + /** * TODO type comment */ @@ -169,35 +199,6 @@ namespace session { virtual ~QueryResolver() ; - /** - * ABC denoting the result set - * of an individual query resolution - */ - class Resolution - { - typedef Goal::Result Result; - - public: - virtual ~Resolution(); - - static bool - hasNext (PReso&, Result& pos) ////TICKET #375 - { - return bool(pos); - } - - static void - iterNext (PReso& resultSet, Result& pos) - { - resultSet->nextResult(pos); - } - - virtual Result prepareResolution() =0; - - protected: - - virtual void nextResult(Result& pos) =0; - }; /** issue a query to retrieve contents @@ -214,6 +215,7 @@ namespace session { protected: virtual bool canHandleQuery (Goal::QueryID qID) const =0; + QueryResolver(); }; ///////////////////////////TODO currently just fleshing the API @@ -223,7 +225,7 @@ namespace session { Query::operator() (QueryResolver const& resolver) { PReso resultSet = resolver.issue (*this); - Result first = prepareResolution(); + Result first = resultSet->prepareResolution(); return iterator (resultSet, first); } diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp index e135467c4..5ecb64919 100644 --- a/src/proc/mobject/session/scope-path.cpp +++ b/src/proc/mobject/session/scope-path.cpp @@ -41,6 +41,22 @@ namespace session { } + Scope + ScopePath::getLeaf() const + { + UNIMPLEMENTED ("access end node of current path"); + } + + + /* == Mutations == */ + + void + ScopePath::clear() + { + UNIMPLEMENTED ("reset the current path to empty state"); + } + + diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp index 5eb43f44a..054cdfe46 100644 --- a/src/proc/mobject/session/scope-path.hpp +++ b/src/proc/mobject/session/scope-path.hpp @@ -49,6 +49,11 @@ namespace session { public: ScopePath(); + + Scope getLeaf() const; + + void clear(); + }; ///////////////////////////TODO currently just fleshing the API diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp index 930690a05..b73096d36 100644 --- a/src/proc/mobject/session/scope.cpp +++ b/src/proc/mobject/session/scope.cpp @@ -49,6 +49,20 @@ namespace session { } + Scope::Scope (Scope const& o) + : anchor_(o.anchor_) + { } + + + Scope& + Scope::operator= (Scope const& o) + { + anchor_ = o.anchor_; ////////////////////////////TODO verify correctness + return *this; + } + + + ScopeLocator::ScopeLocator() : focusStack_(new QueryFocusStack) { diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp index 241d33b73..88d6300d2 100644 --- a/src/proc/mobject/session/scope.hpp +++ b/src/proc/mobject/session/scope.hpp @@ -65,6 +65,9 @@ namespace session { Scope (PlacementMO const& constitutingPlacement); Scope (); ///< unlocated NIL scope + Scope (Scope const&); + Scope& operator= (Scope const&); + static Scope const& containing (PlacementMO const& aPlacement); //////////////TODO really returning a const& here?? static Scope const& containing (RefPlacement const& refPlacement); From d2721378d552c1c6d5d159fc55b816a43195661b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 29 Oct 2009 21:59:02 +0100 Subject: [PATCH 033/377] get QueryResolver to compile --- src/proc/mobject/session/contents-query.hpp | 22 +++---------------- src/proc/mobject/session/query-resolver.cpp | 2 +- src/proc/mobject/session/query-resolver.hpp | 19 +++++++++++----- .../mobject/session/query-resolver-test.cpp | 14 +++++++----- 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/proc/mobject/session/contents-query.hpp b/src/proc/mobject/session/contents-query.hpp index 6e6857498..d28b0286d 100644 --- a/src/proc/mobject/session/contents-query.hpp +++ b/src/proc/mobject/session/contents-query.hpp @@ -50,28 +50,12 @@ namespace session { : public Query > , boost::noncopyable { + typedef Query > _Query; + typedef typename _Query::iterator iterator; + PPIdx index_; PlacementMO const& container_; - iterator - runQuery() - { - UNIMPLEMENTED ("actually query the index"); - } - - - bool - isValid (Cur& pos) - { - UNIMPLEMENTED ("how to manager result set position"); - } - - - Cur const& - nextResult() - { - UNIMPLEMENTED ("how to manager result set position"); - } public: diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp index 6cdd21894..bd30d4e54 100644 --- a/src/proc/mobject/session/query-resolver.cpp +++ b/src/proc/mobject/session/query-resolver.cpp @@ -54,7 +54,7 @@ namespace session { /** TODO??? */ PReso - QueryResolver::issue (Goal& query) + QueryResolver::issue (Goal& query) const { if (!canHandleQuery (query.getQID())) throw lumiera::error::Invalid ("unable to resolve this kind of query"); ////TICKET #197 diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index fcf13981c..8d3ccf1c2 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -143,6 +143,10 @@ namespace session { : public Goal::Result { public: + typedef RES value_type; + typedef RES& reference; + typedef RES* pointer; + RES& operator* () { return access(); } RES* operator->() { return & access(); } @@ -163,23 +167,25 @@ namespace session { */ class Resolution { + public: typedef Goal::Result Result; - public: virtual ~Resolution(); - static bool - hasNext (PReso&, Result& pos) ////TICKET #375 + + friend bool + hasNext (PReso const&, Result const& pos) ////TICKET #375 { return bool(pos); } - static void + friend void iterNext (PReso& resultSet, Result& pos) { resultSet->nextResult(pos); } + virtual Result prepareResolution() =0; protected: @@ -209,7 +215,7 @@ namespace session { * or failure of an external facility used for resolution. * @note a query may yield no results, in which case the iterator is empty. */ - PReso issue (Goal& query); + PReso issue (Goal& query) const; protected: @@ -226,7 +232,8 @@ namespace session { { PReso resultSet = resolver.issue (*this); Result first = resultSet->prepareResolution(); - return iterator (resultSet, first); + Cursor& start = static_cast (first); + return iterator (resultSet, start); } diff --git a/tests/components/proc/mobject/session/query-resolver-test.cpp b/tests/components/proc/mobject/session/query-resolver-test.cpp index 9acb18ac6..9775caccb 100644 --- a/tests/components/proc/mobject/session/query-resolver-test.cpp +++ b/tests/components/proc/mobject/session/query-resolver-test.cpp @@ -56,6 +56,7 @@ namespace test { template class DummySolution; + template<> class DummySolution { int resNr_; @@ -67,6 +68,7 @@ namespace test { bool exhausted() { return bool(resNr_); } }; + template<> class DummySolution : DummySolution { @@ -76,15 +78,15 @@ namespace test { string* next () { - static char* lumi ="Lumiera"; - currentText_ = string (lumi[*DummySolution::next()]); + static const char* lumi ="Lumiera"; + currentText_ = string (lumi + *DummySolution::next()); return ¤tText_; } }; template struct DummyResultSet - : QueryResolver::Resolution + : Resolution { DummySolution solution_; @@ -123,7 +125,7 @@ namespace test { template bool - wantResultType (Goal::QueryID qID) + wantResultType (Goal::QueryID qID) const { return qID.type == ResultType::ID::get(); } @@ -162,9 +164,9 @@ namespace test { explore (secondQuery(resolver)); } - template + template static void - explore (typename Query::iterator ii) + explore (ITER ii) { cout << "Query-Results: " << showSizeof(ii) << endl;; while (ii) From ee611224b65628910f2fa7ac2e6fbb004b5e1736 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 29 Oct 2009 21:59:25 +0100 Subject: [PATCH 034/377] disable the tests not ready yet (see Ticket 384) --- .../components/proc/mobject/mobject-ref-test.cpp | 8 ++++---- .../proc/mobject/placement-scope-test.cpp | 6 ++++++ .../components/proc/mobject/query-focus-test.cpp | 6 ++++++ tests/components/proc/mobject/scope-path-test.cpp | 15 +++++++++++++++ .../proc/mobject/session/contents-query-test.cpp | 2 ++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/tests/components/proc/mobject/mobject-ref-test.cpp b/tests/components/proc/mobject/mobject-ref-test.cpp index fad045ab4..f851b4b06 100644 --- a/tests/components/proc/mobject/mobject-ref-test.cpp +++ b/tests/components/proc/mobject/mobject-ref-test.cpp @@ -84,7 +84,7 @@ namespace test { ASSERT (2 == pClip2.use_count()); -#if 0 /////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! // Prepare an (test)Index typedef shared_ptr PIdx; PIdx index (PlacementIndex::create()); @@ -136,7 +136,7 @@ namespace test { void checkBuildMObjectRef (REF refObj, void* placementAdr) { -#if 0 /////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! MORef rMO; ASSERT (!rMO); // still empty (not bound) cout << rMO << endl; @@ -177,7 +177,7 @@ namespace test { void checkLifecylce (PMObj const& p1, PMObj const& p2) { -#if 0 /////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! ASSERT (2 == p1.use_count()); ASSERT (2 == p2.use_count()); @@ -215,7 +215,7 @@ namespace test { void checkTypeHandling (LumieraUid luid) { -#if 0 /////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! MObjectRef rMObj; MORef rClip; MORef rSub1; diff --git a/tests/components/proc/mobject/placement-scope-test.cpp b/tests/components/proc/mobject/placement-scope-test.cpp index c5bccb2c4..87ba1a1bf 100644 --- a/tests/components/proc/mobject/placement-scope-test.cpp +++ b/tests/components/proc/mobject/placement-scope-test.cpp @@ -73,6 +73,7 @@ namespace test { PPIdx index = build_testScopes(); UNIMPLEMENTED ("function test of placement scope interface"); +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! verifyLookup (index); verifyNavigation (index); } @@ -84,6 +85,7 @@ namespace test { getContents(PPIdx index) { return index->query(index->getRoot()); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! } /** @test for each Placement in our test "session", @@ -92,6 +94,7 @@ namespace test { void verifyLookup (PPIdx ref_index) { +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! for (_Iter elm = getContents(ref_index); elm; ++elm) { ASSERT (elm->isValid()); @@ -109,6 +112,7 @@ namespace test { ASSERT (isSameObject (scope1,scope2)); } +#endif //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! } @@ -116,6 +120,7 @@ namespace test { void verifyNavigation (PPIdx ref_index) { +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! for (_Iter elm = getContents(ref_index); elm; ++elm) { Scope const& scope = Scope::containing(*elm); @@ -138,6 +143,7 @@ namespace test { ASSERT (topsTop == parentsScope); ASSERT (isSameObject (topsTop, parentsScope.getTop())); } } +#endif //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! } }; diff --git a/tests/components/proc/mobject/query-focus-test.cpp b/tests/components/proc/mobject/query-focus-test.cpp index d1e621c2d..589dec521 100644 --- a/tests/components/proc/mobject/query-focus-test.cpp +++ b/tests/components/proc/mobject/query-focus-test.cpp @@ -70,6 +70,7 @@ namespace test { QueryFocus theFocus; theFocus.reset(); +#ifdef false ////////////////////////////////////////////////////////////////////////////////TICKET 384 ASSERT (Scope(root) == Scope(theFocus)); checkNavigation (theFocus); @@ -80,6 +81,7 @@ namespace test { QueryFocus currentFocus; ASSERT (scopePosition == Scope(currentFocus)); ASSERT (currentFocus == theFocus); +#endif } @@ -91,6 +93,7 @@ namespace test { focus.reset(); ASSERT (Scope(focus).isRoot()); +#ifdef false ////////////////////////////////////////////////////////////////////////////////TICKET 384 PMO& someObj = focus.query(); // by construction of the test fixture, // we know this object is root -> ps2 -> ps3 @@ -107,6 +110,7 @@ namespace test { ASSERT (someObj != Scope(focus)); ASSERT (path.contains (focus.currentPath())); ASSERT (focus.currentPath().getParent().isRoot()); +#endif } @@ -114,6 +118,7 @@ namespace test { void manipulate_subFocus() { +#ifdef false ////////////////////////////////////////////////////////////////////////////////TICKET 384 QueryFocus original; uint num_refs = original.ref_count(); ASSERT (num_refs > 1); @@ -152,6 +157,7 @@ namespace test { ASSERT ( 1 == subF.ref_count()); ASSERT (num_refs == original.ref_count()); // when subF goes out of scope now, auto-pop will happen... +#endif } }; diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp index 343104089..9adcfb03d 100644 --- a/tests/components/proc/mobject/scope-path-test.cpp +++ b/tests/components/proc/mobject/scope-path-test.cpp @@ -24,6 +24,7 @@ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "proc/mobject/session/test-scopes.hpp" +#include "proc/mobject/session/scope-path.hpp" //#include "lib/lumitime.hpp" //#include "proc/mobject/placement-ref.hpp" //#include "proc/mobject/placement-index.hpp" @@ -64,6 +65,7 @@ namespace test { { // Prepare an (test)Index backing the PlacementRefs PPIdx index = build_testScopes(); +#if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 PMO& startPlacement = *(index->query(index->getRoot())); ASSERT (startPlacement); @@ -73,6 +75,7 @@ namespace test { check_Identity_and_Copy (startPlacement); navigate (testPath, index); clear (testPath, index); +#endif } @@ -80,6 +83,7 @@ namespace test { buildPath (PMO& startPla) { Scope startScope (startPla); +#if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 ScopePath path (startScope); ASSERT (path); ASSERT (path.contains (startScope)); @@ -88,12 +92,14 @@ namespace test { ScopePath path2 (startScope); ScopePath path3 (path2); +#endif } void checkRelations (ScopePath path1, PMO& refPla) { +#if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 ASSERT (path1.contains (refPla)); Scope refScope (refPla); @@ -119,12 +125,14 @@ namespace test { ASSERT (path2 == commonPrefix(path2,path1)); ASSERT (path1 != commonPrefix(path1,path2)); ASSERT (path1 != commonPrefix(path2,path1)); +#endif ////////////////////////////////////////////////////////////////////////////////TICKET 384 } void invalidPath (ScopePath refPath, PMO& refPla) { +#if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 ASSERT (refPath); ASSERT (!ScopePath::INVALID); @@ -160,12 +168,14 @@ namespace test { ASSERT (refPath); //ScopePath::INVALID.navigate(root); // doesn't compile +#endif ////////////////////////////////////////////////////////////////////////////////TICKET 384 } void check_Identity_and_Copy (PMO& refPla) { +#if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 Scope startScope (startPla); ScopePath path1 (startScope); ScopePath path2 (startScope); @@ -196,6 +206,7 @@ namespace test { ASSERT (path1 != path2); ASSERT (path2 != path3); ASSERT (path1 != path3); +#endif ////////////////////////////////////////////////////////////////////////////////TICKET 384 } @@ -211,6 +222,7 @@ namespace test { void navigate (const ScopePath refPath, PPIdx index) { +#if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 ScopePath path (refPath); ASSERT (path == refPath); @@ -268,12 +280,14 @@ namespace test { ASSERT (other.getTop() == separatePlacement); ScopePath rootPrefix = commonPrefix (path,refPath); ASSERT (rootPrefix.endsAt (root)); +#endif ////////////////////////////////////////////////////////////////////////////////TICKET 384 } void clear (ScopePath& testPath, PPIdx index) { +#if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 ASSERT (path); PMO rootNode = index->getRoot(); ASSERT (path.getLeaf() != rootNode); @@ -281,6 +295,7 @@ namespace test { path.clear(); ASSERT (path); ASSERT (path.getLeaf() == rootNode); +#endif ////////////////////////////////////////////////////////////////////////////////TICKET 384 } }; diff --git a/tests/components/proc/mobject/session/contents-query-test.cpp b/tests/components/proc/mobject/session/contents-query-test.cpp index a62cf9802..e8619c217 100644 --- a/tests/components/proc/mobject/session/contents-query-test.cpp +++ b/tests/components/proc/mobject/session/contents-query-test.cpp @@ -81,9 +81,11 @@ namespace test { void discover (Query const& query) { +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384 !!!!!!!!! Query::iterator elm = query(); while (elm) cout << *elm++ << endl; +#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! } }; From 1dccd37c7059527462f9fc746b36bffb665be43a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 29 Oct 2009 22:00:17 +0100 Subject: [PATCH 035/377] re-order MultiFact implementation to get it to compile --- src/lib/multifact-arg.hpp | 55 ++++++++++++++++++--------- src/lib/multifact.hpp | 47 +++++++++++++---------- tests/lib/multifact-argument-test.cpp | 2 +- 3 files changed, 66 insertions(+), 38 deletions(-) diff --git a/src/lib/multifact-arg.hpp b/src/lib/multifact-arg.hpp index c0c779c60..999b9542d 100644 --- a/src/lib/multifact-arg.hpp +++ b/src/lib/multifact-arg.hpp @@ -41,7 +41,7 @@ #include "lib/multifact.hpp" -#include +#include "lib/meta/function.hpp" @@ -49,42 +49,63 @@ namespace lib { namespace factory { + using lumiera::typelist::Types; + using lumiera::typelist::FunctionSignature; + using lumiera::typelist::FunctionTypedef; using std::tr1::function; - template - struct FabTraits + /** + * Extended MultiFact configuration for arbitrary fabrication functions. + * Contrary to the (simple) standard case, such fabrication functions + * take additional arguments on each invocation. These arguments need + * to be passed through by MultiFact. Moreover, the actual Wrapper + * used may require these fabrication functions to deliver their + * product in a specific form, e.g. as pointer or reference. + * Thus, we have to re-build the actual signature of the + * fabrication functions to be installed into MultiFact. + */ + template< typename SIG + , template class Wrapper + > + struct FabWiring, Wrapper> + : Wrapper >::Ret> { - typedef TY RawProduct; - typedef RawProduct FabSig(ARG); - typedef ARG Argument; + typedef typename FunctionSignature >::Args Args; + typedef typename FunctionSignature >::Ret Element; + typedef typename Wrapper::PType WrappedProduct; + typedef typename Wrapper::RType FabProduct; + typedef typename FunctionTypedef::Sig SIG_Fab; }; /** - * Variant of MultiFact, selecting a creator function by ID - * with the ability to pass additional argument(s) to this - * creator function on invocation. - * TODO type comment + * Variant of MultiFact, accepting additional invocation argument. + * Similar to the (simple) standard case, this MultiFact specialisation + * allows to install suitable fabrication function(s) at runtime and + * will select the function to use on invocation based on the given ID. + * One additional argument will be passed on to this function. + * @todo with a bit more metaprogramming it would be possible to + * accept multiple arguments; maybe we'll need this later on. */ - template< typename SIG + template< typename ELM, typename ARG , typename ID , template class Wrapper > - class MultiFact, ID, Wrapper> - : public MultiFact + class MultiFact + : public MultiFact,ID,Wrapper> { - typedef MultiFact _Base; - typedef typename FabTraits::Argument ArgType; + typedef MultiFact,ID,Wrapper> _Base; - typedef typename _Base::Product Product; typedef typename _Base::Creator Creator; public: + typedef typename _Base::Product Product; + Product - operator() (ID const& id, ArgType arg) + operator() (ID const& id, ARG arg) { Creator& func = selectProducer (id); return wrap (func(arg)); diff --git a/src/lib/multifact.hpp b/src/lib/multifact.hpp index fee171b96..21656cbd9 100644 --- a/src/lib/multifact.hpp +++ b/src/lib/multifact.hpp @@ -78,25 +78,16 @@ namespace lib { - template - struct FabTraits - { - typedef TY RawProduct; - typedef RawProduct FabSig(void); - }; - - - /** * Table of registered production functions for MultiFact. * Each stored function can be accessed by ID and is able - * to fabricate a specific object, which is assignable to TY + * to fabricate a specific object, which is assignable to + * the nominal target type in the MultiFact definition. */ - template + template struct Fab { - typedef typename FabTraits::FabSig Signature; - typedef std::tr1::function FactoryFunc; + typedef std::tr1::function FactoryFunc; FactoryFunc& @@ -126,6 +117,23 @@ namespace lib { + /** + * @internal configuration of the elements + * to be combined into a MultiFact instance + */ + template< typename TY + , template class Wrapper + > + struct FabWiring + : Wrapper + { + typedef typename Wrapper::PType WrappedProduct; + typedef typename Wrapper::RType FabProduct; + typedef FabProduct SIG_Fab(void); + }; + + + /** * Factory for creating a family of objects by ID. * The actual factory functions are to be installed @@ -141,20 +149,17 @@ namespace lib { , template class Wrapper > class MultiFact - : Wrapper::RawProduct> + : public FabWiring { - typedef Wrapper::RawProduct> _Wrap; - typedef typename FabTraits::RawProduct RawType; - typedef typename _Wrap::PType WrappedProduct; - typedef typename _Wrap::RType FabProduct; - typedef Fab _Fab; + typedef FabWiring _Conf; + typedef typename _Conf::SIG_Fab SIG_Fab; + typedef Fab _Fab; _Fab funcTable_; protected: typedef typename _Fab::FactoryFunc Creator; - typedef WrappedProduct Product; Creator& selectProducer (ID const& id) @@ -164,6 +169,8 @@ namespace lib { public: + typedef typename _Conf::WrappedProduct Product; + Product operator() (ID const& id) { diff --git a/tests/lib/multifact-argument-test.cpp b/tests/lib/multifact-argument-test.cpp index e3e6a7b09..5258696b1 100644 --- a/tests/lib/multifact-argument-test.cpp +++ b/tests/lib/multifact-argument-test.cpp @@ -77,7 +77,7 @@ namespace test{ /** the factory instantiation used for this test */ - typedef factory::MultiFact< function // nominal signature of fabrication + typedef factory::MultiFact< Num(int) // nominal signature of fabrication , prodID // select factory function by prodID , factory::BuildRefcountPtr // wrapper: manage product by smart-ptr > TestFactory; From ceb4d4b5eaadf9162e202fd72320f06f6acf19f6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 30 Oct 2009 00:32:26 +0100 Subject: [PATCH 036/377] reworked MultiFact passes unit test. Closes Ticket #376 --- src/lib/multifact-arg.hpp | 12 +++++++---- src/lib/multifact.hpp | 31 ++++++++++++++++++++++++--- tests/40components.tests | 7 ++++-- tests/lib/multifact-argument-test.cpp | 26 +++++++++------------- tests/lib/multifact-test.cpp | 2 +- 5 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/lib/multifact-arg.hpp b/src/lib/multifact-arg.hpp index 999b9542d..dfb452765 100644 --- a/src/lib/multifact-arg.hpp +++ b/src/lib/multifact-arg.hpp @@ -27,7 +27,12 @@ ** factory class exposes a function call operator matching this signature, additionally ** expecting the ID (to select the specific fabrication function) as first parameter. ** - ** @todo WIP-WIP-WIP ... does this work out as intended?? TICKET #377 + ** @note the function signature used for this variant of MultiFact should specify + ** the raw/base (interface) type of the produced objects as a return type. + ** Depending on the used wrapper, the actual fabrication functions indeed + ** should yield the product in a form suitable to be accepted by the + ** wrapper. E.g., when building smart-ptrs, the fabrication function + ** should actually deliver a raw pointer to a heap allocated object. ** ** @see multifact-argument-test.cpp ** @see query-resolver.cpp usage example @@ -63,7 +68,7 @@ namespace lib { * used may require these fabrication functions to deliver their * product in a specific form, e.g. as pointer or reference. * Thus, we have to re-build the actual signature of the - * fabrication functions to be installed into MultiFact. + * fabrication functions to be installed into MultiFact. */ template< typename SIG , template class Wrapper @@ -82,7 +87,7 @@ namespace lib { /** - * Variant of MultiFact, accepting additional invocation argument. + * Variant of MultiFact, accepting an additional invocation argument. * Similar to the (simple) standard case, this MultiFact specialisation * allows to install suitable fabrication function(s) at runtime and * will select the function to use on invocation based on the given ID. @@ -98,7 +103,6 @@ namespace lib { : public MultiFact,ID,Wrapper> { typedef MultiFact,ID,Wrapper> _Base; - typedef typename _Base::Creator Creator; public: diff --git a/src/lib/multifact.hpp b/src/lib/multifact.hpp index 21656cbd9..6e77b5d6e 100644 --- a/src/lib/multifact.hpp +++ b/src/lib/multifact.hpp @@ -22,8 +22,30 @@ /** @file multifact.hpp ** Building blocks of a configurable factory, generating families of related objects. + ** Serving the "classical" factory situation: obtaining objects of various kinds, which + ** are related somehow (usually through an common interface). The creation of these + ** objects is non-trivial while number and exact parametrisation aren't known beforehand + ** and need to be figured out at runtime. Thus, a number of "fabrication lines" is set up, + ** to be selected on invocation through an ID (which may be symbolic, hashed or structural). ** - ** @todo WIP-WIP-WIP ... currently collecting various bits of implementation here. TICKET #277 + ** Usually, the issue of object and storage management is closely related, while it is + ** desirable to keep the object production logic clean of these rather technical concerns. + ** The implementation built here separates the latter into a policy template invoked as a + ** \em wrapper, accepting the raw product and either registering it, taking ownership, clone + ** it or use it for more involved wiring. Obviously, the product generated by the installed + ** "fabrication lines" needs to be delivered in a form acceptable by the concrete wrapper; + ** mismatch will be spotted by the compiler on registration of the respective fabrication + ** function. + ** + ** \par Singleton generation + ** For the very common situation of needing various singleton objects, accessible by ID, + ** there is a convenience shortcut: The nested MultiFact::Singleton template can be instantiated + ** within the context providing the objects (usually a static context). In itself a lib::Singleton + ** factory, it automatically registers the singleton access function as "fabrication" function + ** into a suitable MultiFact instance passed in as ctor parameter. + ** + ** @note there is an extension header, multifact-arg.hpp, which provides template specialisations + ** for the special case when the fabrication functions need additional invocation arguments. ** ** @see multifact-test.cpp ** @see SingletonFactory @@ -48,6 +70,7 @@ namespace lib { namespace factory { + //////TODO: couldn't these wrappers be extracted into a separate header? /** * Dummy "wrapper", @@ -78,6 +101,8 @@ namespace lib { + + /** * Table of registered production functions for MultiFact. * Each stored function can be accessed by ID and is able @@ -193,7 +218,7 @@ namespace lib { /** * Convenience shortcut for automatically setting up * a production line, fabricating a singleton instance - * of the given target type (IMP) + * of the given implementation target type (IMP) */ template class Singleton @@ -217,7 +242,7 @@ namespace lib { /* === diagnostics === */ - + bool empty () const { return funcTable_.empty(); } bool contains (ID id) const { return funcTable_.contains (id); } }; diff --git a/tests/40components.tests b/tests/40components.tests index b46711e0c..a1013091e 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -284,7 +284,7 @@ return: 0 END -PLANNED "configurable Factory" MultiFact_test < #include -//#include #include @@ -36,19 +33,13 @@ namespace lib { namespace test{ -// using boost::lexical_cast; - using lib::test::showSizeof; -// using util::isSameObject; -// using util::isnil; -// using std::ostream; -// using std::string; using std::cout; using std::endl; using std::tr1::bind; using std::tr1::function; using std::tr1::placeholders::_1; + using lib::test::showSizeof; -// using lumiera::error::LUMIERA_ERROR_INVALID; namespace { // dummy fabrication function, creating wrapped numbers, controlled by an additional argument @@ -61,10 +52,10 @@ namespace test{ struct Num { int n_; }; /** dummy "factory" function to be invoked - * @return pointer to heap allocated product object + * @return pointer to heap allocated product object * @note this function needs to deliver the product in a form * which can be accepted by the concrete wrapper, which - * is going to be configured into the factory. + * is going to be configured into the factory. */ Num* fabricateNumberz (int base, int offset) @@ -82,6 +73,8 @@ namespace test{ , factory::BuildRefcountPtr // wrapper: manage product by smart-ptr > TestFactory; + // for reference: type of an equivalent dispatcher table... + typedef std::map > DispatcherMap; } @@ -103,13 +96,14 @@ namespace test{ class MultiFactArgument_test : public Test { void - run (Arg) + run (Arg) { TestFactory theFact; - theFact.defineProduction (ONE, bind (&fabricateNumberz, 1, _1)); - theFact.defineProduction (TWO, bind (&fabricateNumberz, 2, _1)); + theFact.defineProduction (ONE, bind (&fabricateNumberz, 1, _1 )); + theFact.defineProduction (TWO, bind (&fabricateNumberz, 2, _1 )); cout << showSizeof (theFact) << endl; + ASSERT (sizeof(theFact) == sizeof(DispatcherMap)); typedef TestFactory::Product PP; @@ -117,7 +111,7 @@ namespace test{ PP p2 = theFact(TWO, 3); ASSERT (1*2 == p1->n_); ASSERT (2*3 == p2->n_); - } + } }; diff --git a/tests/lib/multifact-test.cpp b/tests/lib/multifact-test.cpp index d2df7c886..2850c0ea0 100644 --- a/tests/lib/multifact-test.cpp +++ b/tests/lib/multifact-test.cpp @@ -97,7 +97,7 @@ namespace test{ /******************************************************************* * @test verify simple setup of the MultiFact template. - * Define a hierarchy of test dummy objects, such as to + * Define a hierarchy of test dummy objects, in order to * register them automatically for creation through a suitable * instantiation of MultiFact. Verify we get the correct product * when invoking this MultiFac flavour. From 006392f6ea6d6eaf40af9bd45388abf8e2542066 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 30 Oct 2009 03:53:51 +0100 Subject: [PATCH 037/377] yet another random test helper --- src/lib/test/test-helper.cpp | 16 ++++++++++++++ src/lib/test/test-helper.hpp | 5 +++++ tests/40components.tests | 1 + tests/lib/test/test-helper-test.cpp | 33 +++++++++++++++++++++++++++-- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/lib/test/test-helper.cpp b/src/lib/test/test-helper.cpp index 401690788..0c67ca7fd 100644 --- a/src/lib/test/test-helper.cpp +++ b/src/lib/test/test-helper.cpp @@ -41,5 +41,21 @@ namespace test{ } + /** @todo probably this can be done in a more clever way. Anyone...? + */ + string + randStr (size_t len) + { + static const string alpha ("aaaabbccddeeeeffgghiiiijjkkllmmnnooooppqqrrssttuuuuvvwwxxyyyyzz0123456789"); + static const size_t MAXAL (alpha.size()); + + string garbage(len,'\0'); + size_t p = len; + while (p) + garbage[--p] = alpha[rand() % MAXAL]; + return garbage; + } + + }} // namespace lib::test diff --git a/src/lib/test/test-helper.hpp b/src/lib/test/test-helper.hpp index 26d3b5616..afa79c743 100644 --- a/src/lib/test/test-helper.hpp +++ b/src/lib/test/test-helper.hpp @@ -110,6 +110,11 @@ namespace test{ return Time (500 * (rand() % 2), (rand() % 600)); } + /** create garbage string of given length + * @return string containing arbitrary lower case letters and numbers + */ + string randStr (size_t len); + }} // namespace lib::test diff --git a/tests/40components.tests b/tests/40components.tests index a1013091e..f5d4d3d5e 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -489,6 +489,7 @@ END TEST "Test support functions" TestHelper_test < +#include #include +#include -using std::cout; -using std::endl; +using util::for_each; using lumiera::Error; using lumiera::LUMIERA_ERROR_EXCEPTION; using lumiera::error::LUMIERA_ERROR_ASSERTION; +using boost::algorithm::is_lower; +using boost::algorithm::is_digit; +using std::tr1::function; +using std::string; +using std::cout; +using std::endl; + namespace lib { namespace test{ @@ -61,6 +71,7 @@ namespace test{ void run (Arg) { + checkGarbageStr(); checkTypeDisplay(); checkThrowChecker(); } @@ -99,6 +110,24 @@ namespace test{ } + + + void + checkGarbageStr() + { + string garN = randStr(0); + ASSERT (0 == garN.size()); + + typedef function ChPredicate; + ChPredicate is_OK (is_lower() || is_digit()); + + string garM = randStr(1000000); + for_each (garM, is_OK); + + cout << randStr(80) << endl; + } + + /** @test check the VERIFY_ERROR macro, * which ensures a given error is raised. */ From df562a186f0982ddb2478f45d12f1705da7091e8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 30 Oct 2009 05:15:26 +0100 Subject: [PATCH 038/377] oops... fix a bug in Literal's hash function --- src/lib/symbol-impl.cpp | 11 +++-- tests/lib/symbol-hashtable-test.cpp | 63 ++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/lib/symbol-impl.cpp b/src/lib/symbol-impl.cpp index 1345ab795..3d06dcc35 100644 --- a/src/lib/symbol-impl.cpp +++ b/src/lib/symbol-impl.cpp @@ -67,10 +67,13 @@ namespace lib { size_t hash_value (Literal sym) { size_t hash=0; - const char *pos = sym; - size_t maxpos = STRING_MAX_RELEVANT; - for ( ; pos && --maxpos; ++pos) - hash_combine(hash, *pos); + if (sym) + { + const char *pos = sym; + size_t maxpos = STRING_MAX_RELEVANT; + for ( ; *pos && --maxpos; ++pos) + hash_combine(hash, *pos); + } return hash; } diff --git a/tests/lib/symbol-hashtable-test.cpp b/tests/lib/symbol-hashtable-test.cpp index 92fd43a34..2e74f7b3c 100644 --- a/tests/lib/symbol-hashtable-test.cpp +++ b/tests/lib/symbol-hashtable-test.cpp @@ -23,16 +23,18 @@ #include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" #include "lib/util.hpp" #include "lib/symbol.hpp" #include #include +#include #include -using util::isnil; using util::contains; +using util::isnil; @@ -67,6 +69,8 @@ namespace test{ void run (Arg) { + checkHashFunction(); + HTable table; ASSERT (isnil(table)); @@ -95,6 +99,63 @@ namespace test{ ASSERT (isnil (table[KEY5])); // adds a new empty value object as side effect ASSERT (5 == table.size()); } + + + void + checkHashFunction() + { + string random = randStr(STRING_MAX_RELEVANT+1); + + string copy1(random); + copy1[5] = '\0'; // truncate the c-String to 5 chars + + string copy2(random); + copy2[rand() % STRING_MAX_RELEVANT] = '*'; // modify a random position + + string copy3(copy2); + copy3[STRING_MAX_RELEVANT] = '*'; // modify behind observation limit + + Symbol l0; + Literal l51 (copy1.c_str()); + Literal l52 (random.substr(0,5).c_str()); + + Literal l_1 (random.c_str()); + Literal l_2 (copy2.c_str()); + Literal l_3 (copy3.c_str()); + + ASSERT (isnil (l0)); + ASSERT (l0 != l51); + ASSERT (l51 == l52); + + ASSERT (l51 != l_1); + ASSERT (l_1 != l_2); + ASSERT (l_2 == l_3); // difference not detected due to observation limit... + ASSERT (!std::strncmp (l_2, l_3, STRING_MAX_RELEVANT )); + ASSERT ( std::strncmp (l_2, l_3, STRING_MAX_RELEVANT+1)); + + size_t h0 = hash_value (l0); + size_t h51 = hash_value (l51); + size_t h52 = hash_value (l52); + size_t h_1 = hash_value (l_1); + size_t h_2 = hash_value (l_2); + size_t h_3 = hash_value (l_3); + + ASSERT (h0 == 0); + ASSERT (h51 != 0); + ASSERT (h52 != 0); + ASSERT (h_1 != 0); + ASSERT (h_2 != 0); + ASSERT (h_3 != 0); + + ASSERT (h51 == h52); // verify the hash function indeed stops at '\0' + ASSERT (h51 != h_1); // share a common prefix, but the hash differs + ASSERT (h_1 != h_2); // the single random modification is detected + ASSERT (h_2 == h_3); // because l_2 and l_3 differ behind the fixed observation limit + + ASSERT (h_1 == hash_value (l_1)); //reproducible + ASSERT (h_2 == hash_value (l_2)); + ASSERT (h_3 == hash_value (l_3)); + } }; LAUNCHER (SymbolHashtable_test, "function common"); From f35b4223160406ed3e871d5ed134bd0a67fa177d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 30 Oct 2009 06:50:26 +0100 Subject: [PATCH 039/377] SubID: add (preliminary) hash impl; unit test pass --- src/lib/sub-id.hpp | 43 +++++++++++++++++++------- tests/40components.tests | 9 +++++- tests/lib/sub-id-test.cpp | 63 +++++++++++++++++++++++++++++++-------- 3 files changed, 91 insertions(+), 24 deletions(-) diff --git a/src/lib/sub-id.hpp b/src/lib/sub-id.hpp index 257dc2638..98df7c4e7 100644 --- a/src/lib/sub-id.hpp +++ b/src/lib/sub-id.hpp @@ -49,14 +49,19 @@ #include "lib/format.hpp" //#include +#include /////TODO better push the hash implementation into a cpp file (and btw, do it more seriously!) + #include #include namespace lib { - using std::string; + using boost::hash_value; + using std::ostream; + using std::string; + using std::cout; @@ -73,15 +78,32 @@ namespace lib { virtual operator string() const =0; }; - - - ostream& - operator<< (ostream& os, SubID const& sID) - { - return os << string(sID); - } - + + inline ostream& + operator<< (ostream& os, SubID const& sID) + { + return os << string(sID); + } + + inline size_t + hash_value (SubID const& sID) + { + return hash_value (string (sID)); + } + + inline bool + operator== (SubID const& id1, SubID const& id2) + { + return (string (id1) == string (id2)); + } + + ////////TODO a serious implementation should descend recursively, instead of relying on the string representation + + + + + template class SubId @@ -96,7 +118,8 @@ namespace lib { operator string() const { - return util::str (baseID_); + using util::str; + return str (baseID_); // note: extension point } }; diff --git a/tests/40components.tests b/tests/40components.tests index f5d4d3d5e..a88881147 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -872,7 +872,14 @@ return: 0 END -PLANNED "extensible symbolic identifier" SubID_test < (buildIDs() ); -// buildHashtable (buildIDs() ); + checkSubIDHash(); } @@ -87,7 +94,7 @@ namespace test{ CID c2 (G); CID c3 (B); - cout << "..." << c1 << c2 << c3 << endl; + cout << "...." << c1 << c2 << c3 << endl; } @@ -107,6 +114,33 @@ namespace test{ } + void + checkSubIDHash() + { + typedef SubId CID; + typedef SubId UID; + typedef ExtendedSubId CUID; + + vector simpleIDs; + simpleIDs.push_back(CID(R)); + simpleIDs.push_back(CID(R)); + simpleIDs.push_back(CID(G)); + simpleIDs.push_back(CID(B)); + + vector extendedIDs; + extendedIDs.push_back(CUID(R,22)); + extendedIDs.push_back(CUID(R,22)); // note the duplicates get dropped + extendedIDs.push_back(CUID(R,23)); + extendedIDs.push_back(CUID(R,24)); + extendedIDs.push_back(CUID(G,24)); + extendedIDs.push_back(CUID(B,25)); + + buildHashtable (simpleIDs); + buildHashtable (extendedIDs); + } + + + template struct HashTable : std::tr1::unordered_map > @@ -114,13 +148,14 @@ namespace test{ void add (KEY key) { - *this[key] = string(key); + (*this)[key] = string(key); } void verify (KEY key) { - ASSERT (string(key) == *this[key]); + cout << "verify....." << key << endl; + ASSERT (string(key) == (*this)[key]); } }; @@ -133,8 +168,10 @@ namespace test{ typedef HashTable HTab; HTab tab; - for_each (keys, bind (&HTab::add, tab, _1 )); - for_each (keys, bind (&HTab::verify, tab, _1 )); + for_each (keys, bind (&HTab::add, ref(tab), _1 )); + for_each (keys, bind (&HTab::verify, ref(tab), _1 )); + + cout << "Elements in hashtable: " << tab.size() << endl; } From 572f26edc87d4987a5c7446a0af7f7587b877fc5 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 30 Oct 2009 17:16:37 +0100 Subject: [PATCH 040/377] document the QueryResolver design --- doc/devel/uml/class152069.html | 1 + doc/devel/uml/class153989.html | 8 ++++- doc/devel/uml/class155141.html | 25 ++++++++++++++++ doc/devel/uml/class155269.html | 23 ++++++++++++++ doc/devel/uml/class155397.html | 24 +++++++++++++++ doc/devel/uml/class155525.html | 25 ++++++++++++++++ doc/devel/uml/class156805.html | 26 ++++++++++++++++ doc/devel/uml/class156933.html | 22 ++++++++++++++ doc/devel/uml/class158085.html | 23 ++++++++++++++ doc/devel/uml/class159237.html | 28 +++++++++++++++++ doc/devel/uml/classdiagrams.html | 1 + doc/devel/uml/classes.html | 8 +++++ doc/devel/uml/classes_list.html | 8 +++++ doc/devel/uml/fig137733.png | Bin 17651 -> 18488 bytes doc/devel/uml/index.html | 12 ++++++-- doc/devel/uml/index_60.html | 12 ++++---- doc/devel/uml/index_65.html | 4 +-- doc/devel/uml/index_66.html | 2 +- doc/devel/uml/index_67.html | 43 ++++++++++++++------------- doc/devel/uml/index_68.html | 2 +- doc/devel/uml/index_69.html | 2 +- doc/devel/uml/index_71.html | 1 + doc/devel/uml/index_73.html | 7 +++-- doc/devel/uml/index_77.html | 2 +- doc/devel/uml/index_78.html | 1 + doc/devel/uml/index_80.html | 1 + doc/devel/uml/index_81.html | 2 ++ doc/devel/uml/index_82.html | 4 +++ doc/devel/uml/index_83.html | 13 ++++---- doc/devel/uml/index_84.html | 8 ++--- doc/devel/uml/index_86.html | 14 ++++----- doc/devel/uml/public_operations.html | 7 +++-- uml/lumiera/131077 | 19 +++++++++++- uml/lumiera/137733.diagram | 16 ++++++++-- uml/lumiera/5.session | 2 -- uml/lumiera/lumiera.prj | 2 +- wiki/renderengine.html | 13 ++++---- 37 files changed, 343 insertions(+), 68 deletions(-) create mode 100644 doc/devel/uml/class155141.html create mode 100644 doc/devel/uml/class155269.html create mode 100644 doc/devel/uml/class155397.html create mode 100644 doc/devel/uml/class155525.html create mode 100644 doc/devel/uml/class156805.html create mode 100644 doc/devel/uml/class156933.html create mode 100644 doc/devel/uml/class158085.html create mode 100644 doc/devel/uml/class159237.html diff --git a/doc/devel/uml/class152069.html b/doc/devel/uml/class152069.html index 5b8f8eee2..899872f11 100644 --- a/doc/devel/uml/class152069.html +++ b/doc/devel/uml/class152069.html @@ -18,5 +18,6 @@

                                    Declaration :

                                    +

                                    All public operations : issue

                                    diff --git a/doc/devel/uml/class153989.html b/doc/devel/uml/class153989.html index 2330627fd..f41ba6162 100644 --- a/doc/devel/uml/class153989.html +++ b/doc/devel/uml/class153989.html @@ -16,7 +16,13 @@ -

                                    Declaration :

                                    • C++ : class QueryResolver
                                    • Java : package interface QueryResolver
                                    • Php : interface QueryResolver

                                    Directly inherited by : PlacementIndex

                                    +

                                    Declaration :

                                    • C++ : class QueryResolver
                                    • Java : package interface QueryResolver
                                    • Php : interface QueryResolver

                                    Directly inherited by : PlacementIndex ResolvingFacility

                                    Stereotype: interface

                                    +
                                    + +
                                    Operation issue

                                    Declaration :

                                    • Uml : + issue(in query : Goal) :
                                    • C++ : public: issue ()
                                    + +
                                    Relation <unidirectional association>

                                    Declaration :

                                    +

                                    All public operations : issue

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

                                    + + + + +

                                    Declaration :

                                    • C++ : template<class TY> class Query : public Goal
                                    +
                                    Class Cursor
                                    + +
                                    Relation <unidirectional association>

                                    Declaration :

                                    Stereotype: type-def

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

                                    + + + + +

                                    Declaration :

                                    • C++ : template<class TY> class Cursor : public Result

                                    nested in Query

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

                                    + + + + +

                                    Declaration :

                                    • C++ : template<class POS, class CON> class IterAdapter
                                    + +
                                    Relation source_ (<unidirectional association>)

                                    Declaration :

                                    +
                                    Relation pos_ (<unidirectional association>)

                                    Declaration :

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

                                    + + + + +

                                    Declaration :

                                    + +
                                    Relation <unidirectional association>

                                    Declaration :

                                    Stereotype: produce

                                    +
                                    +

                                    All public operations : issue

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

                                    + + + + +

                                    Declaration :

                                    • C++ : class Goal

                                    Directly inherited by : Query

                                    +

                                    Stereotype: interface

                                    +
                                    +
                                    Class Result
                                    + +
                                    Relation <unidirectional association>

                                    Declaration :

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

                                    + + + + +

                                    Declaration :

                                    • C++ : class Result

                                    Directly inherited by : Cursor

                                    +

                                    nested in Goal

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

                                    + + + + +

                                    Declaration :

                                    +
                                    +

                                    All public operations : isValid , nextResult

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

                                    + + + + +

                                    Declaration :

                                    • C++ : class Resolution

                                    Directly inherited by : ResultSet

                                    +

                                    nested in QueryResolver

                                    +
                                    + +
                                    Operation isValid

                                    Declaration :

                                    • Uml : + isValid(in pos : Result) : bool
                                    • C++ : public: bool isValid ()
                                    +
                                    Operation nextResult

                                    Declaration :

                                    • Uml : + nextResult() : Result
                                    • C++ : public: Result nextResult ()
                                    +
                                    Relation <unidirectional association>

                                    Declaration :

                                    +

                                    All public operations : isValid , nextResult

                                    + + diff --git a/doc/devel/uml/classdiagrams.html b/doc/devel/uml/classdiagrams.html index 522259723..73a9e7f73 100644 --- a/doc/devel/uml/classdiagrams.html +++ b/doc/devel/uml/classdiagrams.html @@ -31,6 +31,7 @@ Media-Asset Relations MObjectRef Proc-Asset Relations +Query Interface Render Entities Render Mechanics Rules access diff --git a/doc/devel/uml/classes.html b/doc/devel/uml/classes.html index a6a2fe704..7254ced2b 100644 --- a/doc/devel/uml/classes.html +++ b/doc/devel/uml/classes.html @@ -53,6 +53,7 @@ ConManagerConnection Manager, used to build the connections between render engine nodes, if these nodes need to cooperate besides the normal "data pull" operation. Esp., the Connection Manager knows how to wire up the effect's parameters with the corresponding ParamProviders (autmation) in the Session Constraint ControllerFacadeboundaryProvides unified access to the Proc-Subsystem Controller. Especially, this Facade class provides the functions to get a render engine to carry out actual renderings. +Cursor Datasetmeta asset describing a collection of control data DBImplementation of the registry holding all Asset instances known to the Asset Manager subsystem. As of 8/2007 implemented by a hashtable. DefaultsManager @@ -84,6 +85,7 @@ FrameDescriptorinterfaceA FrameDescriptor implements the higher level interfaces for frames. Further refinements are made by subclassing and policy classes FrameReference GLBuf +Goalinterface Handle HandlingPatterninterface Id @@ -92,6 +94,7 @@ InterpolatorProvides the implementation for getting the acutal value of a time varying or automated effect/plugin parameter Invalid Invocation +IterAdapter Label Link LocatingPinAn element with value semantics, which actually implements the placement of some MObject by positioning it in some way. @@ -139,6 +142,7 @@ Prototype Proxy PullInput +Query QueryCache QueryFocus QueryFocusStack @@ -153,7 +157,11 @@ RenderGraph RenderStateEncapsulates the logic used to get a "current render process" in accordance to the currentyl applicable controller settings. The provided StateProxy serves to hold any mutalbe state used in the render process, so the rest of the render engine can be stateless. RenderTask +Resolution ResolverBase +ResolvingFacility +Result +ResultSet Scheduler Scope ScopeLocatorsingleton diff --git a/doc/devel/uml/classes_list.html b/doc/devel/uml/classes_list.html index 2378c288f..ab8b6e948 100644 --- a/doc/devel/uml/classes_list.html +++ b/doc/devel/uml/classes_list.html @@ -54,6 +54,7 @@ ConManager
                                    Constraint
                                    ControllerFacade
                                    +Cursor
                                    Dataset
                                    DB
                                    DefaultsManager
                                    @@ -85,6 +86,7 @@ FrameDescriptor
                                    FrameReference
                                    GLBuf
                                    +Goal
                                    Handle
                                    HandlingPattern
                                    Id
                                    @@ -93,6 +95,7 @@ Interpolator
                                    Invalid
                                    Invocation
                                    +IterAdapter
                                    Label
                                    Link
                                    LocatingPin
                                    @@ -140,6 +143,7 @@ Prototype
                                    Proxy
                                    PullInput
                                    +Query
                                    QueryCache
                                    QueryFocus
                                    QueryFocusStack
                                    @@ -154,7 +158,11 @@ RenderGraph
                                    RenderState
                                    RenderTask
                                    +Resolution
                                    ResolverBase
                                    +ResolvingFacility
                                    +Result
                                    +ResultSet
                                    Scheduler
                                    Scope
                                    ScopeLocator
                                    diff --git a/doc/devel/uml/fig137733.png b/doc/devel/uml/fig137733.png index 61b258961423411b1dcd8827940a13f7a0119512..df4eb2a81eede408a0a67d81864308c5b9465729 100644 GIT binary patch literal 18488 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 literal 17651 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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 : 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

                                    +

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

                                    Artifact main

                                    Stereotype: source

                                    @@ -1026,7 +1026,6 @@ undo
                                    @@ -1516,6 +1515,15 @@ undo
                                    + +

                                    +

                                    Query Interface



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

                                    5.3.3 Use Case View query use

                                    diff --git a/doc/devel/uml/index_60.html b/doc/devel/uml/index_60.html index d00995e12..5fa958d5f 100644 --- a/doc/devel/uml/index_60.html +++ b/doc/devel/uml/index_60.html @@ -30,8 +30,8 @@ <flow>transition <flow>transition <flow>transition -<flow>transition <flow>transition +<flow>transition <flow>transition <flow>transition <flow>transition @@ -47,18 +47,18 @@ <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 25d659f38..4afe9874b 100644 --- a/doc/devel/uml/index_65.html +++ b/doc/devel/uml/index_65.html @@ -57,12 +57,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 36ad84a5e..bb6bceff8 100644 --- a/doc/devel/uml/index_66.html +++ b/doc/devel/uml/index_66.html @@ -38,8 +38,8 @@ buildableartifactmarker interface denoting any MObject able to be treated by Tools buildEngineoperationMain Operation of the Builder: create a render engine for a given part of the timeline Buildercomponent -builderpackagesourcecode package

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

                                    The Builder creating the Render Engine,
                                    located within the MObject Subsystem Builder Entitiesclass diagram Builder Tool (Visitor)class diagram Builder Workingsclass view diff --git a/doc/devel/uml/index_67.html b/doc/devel/uml/index_67.html index 693346ea5..573a61e0e 100644 --- a/doc/devel/uml/index_67.html +++ b/doc/devel/uml/index_67.html @@ -29,39 +29,39 @@ Categoryclasstree like classification of Assets categoryartifacttree like classification of Assets causeattributea copy of the first exception encountered in this exception chain -chainrelationChain of additional Placements further constraining the position of this MObject chainoperationcreate and add another Placement for this media object, thus increasingly constraining the (possible) position of this object. +chainrelationChain of additional Placements further constraining the position of this MObject 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 clearoperationclear current session contents
                                    without resetting overall session config.
                                    Afterwards, the session will contain only one
                                    empty EDL, while all Assets are retained.
                                    client codecomponent Clipclassbookkeeping (asset) view of a media clip. @@ -125,6 +125,7 @@ currentclass instance currentrelationStandard access path to get at the current session via the Session Manager, which acts as a "PImpl" smart pointer currFramerelation +Cursorclass Custom holdersclass view diff --git a/doc/devel/uml/index_68.html b/doc/devel/uml/index_68.html index 9866cde59..0af5dabf9 100644 --- a/doc/devel/uml/index_68.html +++ b/doc/devel/uml/index_68.html @@ -33,8 +33,8 @@ designpackage designpackageAll things concering the big picture.
                                    Not a real code package, rather a container for design drafts, specifications, decisions. detect Channelsuse case -determine Render Paramsopaque activity action determine Render Paramsexpansion region +determine Render Paramsopaque activity action devnullclass instance Dispatchercomponent dispatchOpoperation diff --git a/doc/devel/uml/index_69.html b/doc/devel/uml/index_69.html index 0c6f365e7..3c4e4f7af 100644 --- a/doc/devel/uml/index_69.html +++ b/doc/devel/uml/index_69.html @@ -23,8 +23,8 @@ 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 edlsrelation 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_71.html b/doc/devel/uml/index_71.html index 8e5db9b8f..93915463a 100644 --- a/doc/devel/uml/index_71.html +++ b/doc/devel/uml/index_71.html @@ -50,6 +50,7 @@ globalBussesrelation glpipeartifactspecialized connection element for handling OpenGL implementation details glrenderartifactRepresentation of a OpenGL accellerated Video render process +Goalclass graphnode groupsattributeadditional classification, selections or departments this asset belongs to. Groups are optional, non-exclusive and may be overlapping. guipackagesourcecode package

                                    User Interface classes go here diff --git a/doc/devel/uml/index_73.html b/doc/devel/uml/index_73.html index 6fa319735..bc3749d4b 100644 --- a/doc/devel/uml/index_73.html +++ b/doc/devel/uml/index_73.html @@ -25,9 +25,9 @@ ImplFacadeclass In Memory Databaseclass diagram inFixtureactivity action pin -inputclass instance -inputclass instance inputclass instance +inputclass instance +inputclass instance instanceoperation InstanceHandleclass instructionsrelation @@ -42,6 +42,9 @@ iporelation isActiveoperationweather this asset is swithced on and consequently included in the fixture and participates in rendering isCalculatedoperation +issueoperation +isValidoperation +IterAdapterclass diff --git a/doc/devel/uml/index_77.html b/doc/devel/uml/index_77.html index 908bede9a..c54b8ea8c 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 -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 mobjectartifactKey Abstraction: A Media Object in the Session mobjectpackagesourcecode package

                                    MObject Subsystem
                                    including the Session (EDL), Builder and Processing Controller diff --git a/doc/devel/uml/index_78.html b/doc/devel/uml/index_78.html index 2671839d3..dd4d80ba8 100644 --- a/doc/devel/uml/index_78.html +++ b/doc/devel/uml/index_78.html @@ -21,6 +21,7 @@ nameattribute need sub objectuse case nextrelationnext additional LocatingPin, if any +nextResultoperation node1class instance node2class instance node3class instance diff --git a/doc/devel/uml/index_80.html b/doc/devel/uml/index_80.html index 738c03906..1c5804224 100644 --- a/doc/devel/uml/index_80.html +++ b/doc/devel/uml/index_80.html @@ -49,6 +49,7 @@ pluginadapterartifactAdapter for integrating various Effect processors in the render pipeline pnodenode pointattributeidentifying the point where the nodes should be attached +pos_relation Posix Threads Abstractionclass viewC++ wrapers for pthreads predecessorsrelation predicate implclass instance diff --git a/doc/devel/uml/index_81.html b/doc/devel/uml/index_81.html index 7668e971e..eb42837b2 100644 --- a/doc/devel/uml/index_81.html +++ b/doc/devel/uml/index_81.html @@ -18,6 +18,8 @@ + + diff --git a/doc/devel/uml/index_82.html b/doc/devel/uml/index_82.html index 3f9b13363..827043e15 100644 --- a/doc/devel/uml/index_82.html +++ b/doc/devel/uml/index_82.html @@ -45,11 +45,15 @@ + + + + diff --git a/doc/devel/uml/index_83.html b/doc/devel/uml/index_83.html index 93f76635f..f519ce594 100644 --- a/doc/devel/uml/index_83.html +++ b/doc/devel/uml/index_83.html @@ -66,21 +66,22 @@ + - - - - - - + + + + + + diff --git a/doc/devel/uml/index_84.html b/doc/devel/uml/index_84.html index 33624b8dd..5ca78a2ce 100644 --- a/doc/devel/uml/index_84.html +++ b/doc/devel/uml/index_84.html @@ -44,13 +44,13 @@ - + - - - + + +
                                    NameKindDescription
                                    queryclass view
                                    Queryclass
                                    Query Interfaceclass diagram
                                    Query System overviewcomponent view
                                    query useuse case view
                                    QueryCacheclass
                                    RenderTaskclass
                                    reprattributehuman readable representation of the condition characterizing this allocaton, e.g. "t >= 10"
                                    resetoperationreset all session config and
                                    start with a pristine default session.
                                    Resolutionclass
                                    resolveoperationcreate an actual (explicit) placement while trying to satisfy the network of adjacent objects and placements.
                                    resolveoperation
                                    resolveoperation
                                    Resolvercomponent
                                    ResolverBaseclass
                                    ResolvingFacilityclass
                                    Resultclass
                                    ResultSetclass
                                    retrieveoperation
                                    rootCauseoperationIf this exception was caused by a chain of further exceptions,
                                    return the first one registered in this throw sequence.
                                    This works only, if every exceptions thrown as a consequence
                                    of another exception is propperly constructed by passing
                                    the original exception to the constructor
                                    Rule Basecomponent
                                    SourceclassSource Node: represents a media source to pull data from.
                                    sourceartifactRepresentation of a Media source
                                    Source Overviewdeployment diagram
                                    source_relation
                                    startattributebegin of the timerange covered by this processor
                                    startattribute
                                    Stateclass
                                    Statenode
                                    Stateclass
                                    staterelation
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    state actionstate actiontry to fetch existing definition
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    state actionstate action
                                    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
                                    TypeHandlerclass
                                    TypeHandler<Pipe>class
                                    diff --git a/doc/devel/uml/index_86.html b/doc/devel/uml/index_86.html index 3c3999692..ada782f0a 100644 --- a/doc/devel/uml/index_86.html +++ b/doc/devel/uml/index_86.html @@ -21,21 +21,21 @@ VFrameclass vframeartifacta buffer and render process holding a Video frame vid1class instance -vid_Aclass instance -vid_Aclass instance vid_aclass instance vid_aclass instance vid_Aclass instance +vid_Aclass instance +vid_Aclass instance +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 Visitableclass visitorpackagesub-namespace for visitor library implementation visitorartifactAcyclic Visitor library diff --git a/doc/devel/uml/public_operations.html b/doc/devel/uml/public_operations.html index 4e6395642..02e32e775 100644 --- a/doc/devel/uml/public_operations.html +++ b/doc/devel/uml/public_operations.html @@ -54,9 +54,12 @@ howtoProcMedia@return descriptor how to build a render pipeline corresponding to this media isActiveAssetweather this asset is swithced on and consequently included in the fixture and participates in rendering isCalculatedState +issueQueryResolver +isValidResolution knownAssetManager@return true if the given id is registered in the internal asset DB loadSessManagerreplace the current session by a new
                                    session loaded from serialized state. makeTypeHandler +nextResultResolution playRenderEngineTODO: will probably be handled differently (see Cehteh) processProcNode pullProcNode @@ -71,13 +74,13 @@ saveSessManagercreate a complete, serialized representation
                                    of the current session config and contents.
                                    @todo how to serialize, prameters, return value? treatApplicable treatBuilderToolThis operation is to be overloaded for the specific MObject subclasses to be treated. +treatNodeCreatorTool treatNodeCreatorTool treatNodeCreatorTool -treatNodeCreatorTool treatNodeCreatorTool treatSegmentationTool -treatSegmentationTool treatSegmentationTool +treatSegmentationTool useFileFileProviderAnnounces that the application intends to use this file with mode (READ|WRITE|READWRITE) useTemporaryStorageFileProviderProvides a pool for interminate frames whatError diff --git a/uml/lumiera/131077 b/uml/lumiera/131077 index e6458174f..a6ef47693 100644 --- a/uml/lumiera/131077 +++ b/uml/lumiera/131077 @@ -1,6 +1,6 @@ format 58 "ConfigQuery" // CommonLib::ConfigQuery - revision 17 + revision 18 modified_by 5 "hiv" // class settings //class diagram settings @@ -548,6 +548,15 @@ ${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl} b parent class_ref 156933 // Result end end + + classrelation 191621 // + relation 181253 ---> + a role_name "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 191621 // + b parent class_ref 159237 // Resolution + end end class 156805 "Goal" @@ -594,6 +603,14 @@ ${inlines} classrelation_ref 182533 // b parent class_ref 156933 // Result end + + classrelation 191749 // + relation 181381 -_-> + a default + cpp default "#include in source" + classrelation_ref 191749 // + b parent class_ref 153989 // QueryResolver + end end class 155141 "Query" diff --git a/uml/lumiera/137733.diagram b/uml/lumiera/137733.diagram index 918a3b519..38b1472ea 100644 --- a/uml/lumiera/137733.diagram +++ b/uml/lumiera/137733.diagram @@ -46,6 +46,8 @@ classcanvas 137221 class_ref 155525 // ResolvingFacility 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 492 327 1994 end +textcanvas 139269 "invoke for resolution" + xyzwh 289 91 2004 100 15 line 128389 ---+ from ref 131077 z 1999 to ref 129797 line 131845 ---+ @@ -81,8 +83,6 @@ relationcanvas 134021 relation_ref 175749 // no_role_a no_role_b no_multiplicity_a no_multiplicity_b end -line 135813 ---+ - from ref 135685 z 1999 to ref 128005 relationcanvas 135941 relation_ref 178309 // from ref 133509 z 1999 to ref 135685 no_role_a no_role_b @@ -124,5 +124,17 @@ relationcanvas 138757 relation_ref 180101 // no_role_a no_role_b no_multiplicity_a no_multiplicity_b end +relationcanvas 138885 relation_ref 181253 // + from ref 128005 z 1999 to ref 135685 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 139013 relation_ref 181381 // + decenter_end 805 + from ref 129797 z 1999 to point 227 100 + line 139141 z 1999 to ref 128005 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end preferred_whz 612 547 1 end diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session index 2667b5cd6..fab2f0520 100644 --- a/uml/lumiera/5.session +++ b/uml/lumiera/5.session @@ -1,7 +1,5 @@ window_sizes 1302 1004 270 1022 856 71 diagrams - classdiagram_ref 134021 // Command structure - 575 622 100 4 0 0 classdiagram_ref 136325 // Focus of Query 582 515 100 4 0 0 active classdiagram_ref 137733 // Query Interface diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj index 99a17c9aa..d39e4f756 100644 --- a/uml/lumiera/lumiera.prj +++ b/uml/lumiera/lumiera.prj @@ -1,6 +1,6 @@ format 58 "lumiera" - revision 57 + revision 58 modified_by 5 "hiv" cpp_root_dir "../../src/" diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 4b3fbe2ac..df0a49d38 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3476,7 +3476,7 @@ Then, running the goal {{{:-resolve(T, stream(T,mpeg)).}}} would search a Track In the design of the Lumiera Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Pipe, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered "condiguration data" (including the actual plugin implementation to be loaded)
                                    -
                                    +
                                    Within the Lumiera Proc-Layer, there is a general preference for issuing [[queries|Query]] over hard wired configuration (or even mere table based configuration). This leads to the demand of exposing a //possibility to issue queries// &mdash; without actually disclosing much details of the facility implementing this service. For example, for shaping the general session interface (in 10/09), we need a means of exposing a hook to discover HighLevelModel contents, without disclosing how the model is actually organised internally (namely by using an PlacementIndex).
                                     
                                     !Analysis of the problem
                                    @@ -3487,12 +3487,15 @@ The situation can be decomposed as follows.[>img[QueryResolver|uml/fig137733.
                                     
                                     
                                     !!!Difficulties
                                    -*it's not clear which usage pattern I'm after
                                    -*# client creates a specific {{{Query<TY>}}} to be resolved by an concealed entity
                                    -*# client creates just a goal, which is then translated into a specific query mechanism behind the invocation interface
                                    +*the usage pattern is not clear &mdash; mostly it's just //planned//
                                    +*# client might create a specific {{{Query<TY>}}} and demand resolution
                                    +*# client might create just a goal, which is then translated into a specific query mechanism behind the invocation interface
                                     *# client issues a query and expect it just to be handled by //some//&nbsp; suitable resolver
                                     * thus it's difficult to determine, //what// part of the issued query needs automatic management. More specifically, is it possible for the client to dispose the query after issuing it, but keeping and exploring the iterator obtained as result of the query?
                                    -* and then there is the notorious problem of re-gaining the specifically typed context //behind//&nbsp; the invocation interface. Especially, the facility processing the query needs to know both the expected result type and details about the concrete query and its parametrisation. &rarr; TypedQueryProblem
                                    +* and then there is the notorious problem of re-gaining the specifically typed context //behind//&nbsp; the invocation interface. Especially, the facility processing the query needs to know both the expected result type and details about the concrete query and its parametrisation. <br/>&rarr; TypedQueryProblem
                                    +
                                    +!!!Entities and Operations
                                    +The //client// &nbsp;(code using query-resolver.hpp) either wants a ''goal'' or ''query'' to be resolved; the former is just implicitly typed and usually given in predicate logic from, while the latter may be a specialised subclass templated to yield objects of a specific type as results. A ''query resolver'' is an (abstracted) entity capable of //resolving//&nbsp; such a goal. Actually, behind the scenes there is somehow a registration of the concrete resolving facilities, which are asumed to decide about their ability of handling a given goal. Issuing a goal or query yields a ''resolution'' &mdash; practically speaking, a set of indivitual solutions. These individual solution ''results'' can be explored by ''iteration'', thereby moving an embedded ''cursor'' through the ''result set''. Any result can be retrieved at most once &mdash; after that, the resolution is ''exhausted'' and will be released automatically when the expolration iterator goes out of scope.
                                     
                                     !!!Decisions
                                     * while, in the use case currently at hand, the query instance is created by the client on the stack, the possibility of managing the queries internally is deliberately kept open. Because otherwise, we had to commit to a specific way of obtaining results, for example by assuming always to use an embedded STL iterator.
                                    
                                    From f70f8c4e4ac2920f36e549a484e362cbca6fdc99 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 30 Oct 2009 18:37:08 +0100
                                    Subject: [PATCH 041/377] implemented the mechanism for dispatch-to-concrete
                                     resolution
                                    
                                    ---
                                     src/proc/mobject/placement-index.hpp          |  2 +-
                                     src/proc/mobject/session/query-resolver.cpp   | 68 ++++++++++++++++---
                                     src/proc/mobject/session/query-resolver.hpp   | 27 +++++++-
                                     .../mobject/session/query-resolver-test.cpp   | 22 +++---
                                     wiki/renderengine.html                        |  4 +-
                                     5 files changed, 96 insertions(+), 27 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/placement-index.hpp b/src/proc/mobject/placement-index.hpp
                                    index 553419d32..55f1f52ec 100644
                                    --- a/src/proc/mobject/placement-index.hpp
                                    +++ b/src/proc/mobject/placement-index.hpp
                                    @@ -62,7 +62,7 @@ namespace mobject { ///////////////////////////////////////////TODO: shouldn't t
                                        */
                                       class PlacementIndex
                                         : public session::QueryResolver        ////////TODO: really inherit here?
                                    -    , boost::noncopyable
                                    +//  , boost::noncopyable                  ////////TODO : where to put the "noncopyable" base
                                         {
                                           class Table;
                                           
                                    diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp
                                    index bd30d4e54..8bfb65eb3 100644
                                    --- a/src/proc/mobject/session/query-resolver.cpp
                                    +++ b/src/proc/mobject/session/query-resolver.cpp
                                    @@ -22,45 +22,91 @@
                                     
                                     
                                     #include "proc/mobject/session/query-resolver.hpp"
                                    -//#include "proc/mobject/session/track.hpp"
                                    -//#include "proc/mobject/placement.hpp"
                                    -//#include "proc/mobject/session/mobjectfactory.hpp"
                                    -//#include "proc/asset/track.hpp"
                                    +#include "lib/multifact-arg.hpp"
                                     
                                     namespace mobject {
                                     namespace session {
                                       
                                    +  using lib::factory::MultiFact;
                                    +  using lib::factory::BuildRefcountPtr;
                                       
                                       
                                    -  /* generate vtables here */  
                                    -
                                    +  /* generate vtables here... */
                                    +  
                                       Goal::~Goal() { }
                                    -
                                    -  QueryResolver::~QueryResolver() { }
                                       
                                       Resolution::~Resolution() { }
                                       
                                    +  QueryResolver::~QueryResolver() { }
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  typedef Goal::QueryID const& QID;
                                    +  
                                    +  /** we're going to use QueryID as Map key... */
                                    +  inline bool
                                    +  operator< (QID q1, QID q2)
                                    +  {
                                    +    return (q1.kind < q2.kind)
                                    +        || (q1.kind == q2.kind
                                    +         && q1.type < q2.type
                                    +           );
                                    +  }
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  /* == dispatch to resolve typed queries == */
                                    +  
                                    +  /** factory used as dispatcher table
                                    +   *  for resolving typed queries  */
                                    +  typedef MultiFact< Resolution(Goal&)   // nominal signature of fabrication
                                    +                   , Goal::QueryID      //  select resolution function by kind-of-Query
                                    +                   , BuildRefcountPtr  //   wrapper: manage result set by smart-ptr
                                    +                   > DispatcherTable; //
                                       
                                       struct QueryDispatcher
                                    +    : DispatcherTable
                                         {
                                           
                                    +      PReso
                                    +      handle (Goal& query)
                                    +        {
                                    +          QID qID = query.getQID();
                                    +          ENSURE (contains (qID));
                                    +          
                                    +          return (*this) (qID, query); 
                                    +        }               //qID picks the resolution function
                                         };
                                       
                                       
                                    +  
                                       QueryResolver::QueryResolver ()
                                         : dispatcher_(new QueryDispatcher)
                                         { }
                                       
                                       
                                    -  /** TODO??? */
                                    +  /** @par implementation
                                    +   *  For actually building a result set, the QueryResolver base implementation
                                    +   *  uses an embedded dispatcher table. The concrete query resolving facilities,
                                    +   *  when implementing the QueryResolver interface, are expected to register
                                    +   *  individual resolution functions into this QueryDispatcher table.
                                    +   *  Whenever issuing a Goal, a suitable resolution function is picked
                                    +   *  based on the Goal::QueryID, which contains an embedded type code.
                                    +   *  Thus, the individual resolution function can (re)establish a
                                    +   *  typed context and downcast the Goal appropriately
                                    +   */
                                       PReso  
                                       QueryResolver::issue (Goal& query)  const
                                       {
                                    +    TODO ("ensure proper initialisation");  
                                    +    
                                         if (!canHandleQuery (query.getQID()))
                                           throw lumiera::error::Invalid ("unable to resolve this kind of query"); ////TICKET #197
                                         
                                    -    UNIMPLEMENTED ("dispatch-mechanism for re-discovering specific type-context");
                                    -    
                                    +    return dispatcher_->handle(query);
                                       }
                                       
                                       
                                    diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp
                                    index 8d3ccf1c2..6c0d295c5 100644
                                    --- a/src/proc/mobject/session/query-resolver.hpp
                                    +++ b/src/proc/mobject/session/query-resolver.hpp
                                    @@ -31,6 +31,7 @@
                                     #include "lib/iter-adapter.hpp"
                                     #include "lib/util.hpp"
                                     
                                    +#include 
                                     #include 
                                     #include 
                                     //#include 
                                    @@ -43,6 +44,7 @@ namespace mobject {
                                     namespace session {
                                       
                                       using util::unConst;
                                    +  using boost::noncopyable;
                                       
                                       
                                       class Goal;
                                    @@ -60,6 +62,7 @@ namespace session {
                                        * Query ABC
                                        */
                                       class Goal
                                    +    : noncopyable
                                         {
                                         public:
                                           virtual ~Goal() ;
                                    @@ -78,6 +81,12 @@ namespace session {
                                           QueryID getQID() { return id_; }
                                           
                                           
                                    +      /** 
                                    +       * Single Solution, possibly part of a result set.
                                    +       * A pointer-like object, usually to be down-casted
                                    +       * to a specifically typed Query::Cursor
                                    +       * @see Resolution
                                    +       */
                                           class Result
                                             : public lib::BoolCheckable
                                             {
                                    @@ -117,6 +126,15 @@ namespace session {
                                        *  the specific result types of issued queries  */
                                       typedef lib::TypedContext ResultType;
                                       
                                    +  template
                                    +  inline size_t
                                    +  getResultTypeID()  ///< @return unique ID denoting result type RES
                                    +  {
                                    +    return ResultType::ID::get();
                                    +  }
                                    +  
                                    +  
                                    +  
                                       
                                       /**
                                        * TODO type comment
                                    @@ -129,7 +147,7 @@ namespace session {
                                           static QueryID
                                           defineQueryTypeID ()
                                             {
                                    -          QueryID id = {Goal::GENERIC, ResultType::ID::get()};
                                    +          QueryID id = {Goal::GENERIC, getResultTypeID() };
                                               return id;
                                             }
                                           
                                    @@ -138,6 +156,7 @@ namespace session {
                                             : Goal (defineQueryTypeID())
                                             { }
                                           
                                    +      
                                           /* results retrieval */
                                           class Cursor
                                             : public Goal::Result
                                    @@ -156,7 +175,8 @@ namespace session {
                                           
                                           typedef lib::IterAdapter iterator;
                                           
                                    -      iterator operator() (QueryResolver const& resolver);
                                    +      iterator
                                    +      operator() (QueryResolver const& resolver);
                                           
                                         };
                                       
                                    @@ -166,6 +186,7 @@ namespace session {
                                        * of an individual query resolution
                                        */
                                       class Resolution
                                    +    : noncopyable
                                         {
                                         public:
                                           typedef Goal::Result Result;
                                    @@ -195,9 +216,11 @@ namespace session {
                                     
                                     
                                       /**
                                    +   * Interface: a facility for resolving (some) queries
                                        * TODO type comment
                                        */
                                       class QueryResolver
                                    +    : noncopyable
                                         {
                                           boost::scoped_ptr dispatcher_;
                                           
                                    diff --git a/tests/components/proc/mobject/session/query-resolver-test.cpp b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    index 9775caccb..9f5f7e186 100644
                                    --- a/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    +++ b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    @@ -54,23 +54,23 @@ namespace test    {
                                         
                                         
                                         template
                                    -    class DummySolution;
                                    +    class DummySolutions;
                                         
                                         template<>
                                    -    class DummySolution
                                    +    class DummySolutions
                                           {
                                             int resNr_;
                                             
                                           public:
                                    -        DummySolution() : resNr_(7) {}
                                    +        DummySolutions() : resNr_(7) {}
                                             
                                             int* next () { --resNr_; return &resNr_; }
                                             bool exhausted() { return bool(resNr_); }
                                           };
                                         
                                         template<>
                                    -    class DummySolution
                                    -      : DummySolution 
                                    +    class DummySolutions
                                    +      : DummySolutions 
                                           {
                                             string currentText_;
                                             
                                    @@ -79,7 +79,7 @@ namespace test    {
                                             next ()
                                               { 
                                                 static const char* lumi ="Lumiera";
                                    -            currentText_ = string (lumi + *DummySolution::next());
                                    +            currentText_ = string (lumi + *DummySolutions::next());
                                                 return ¤tText_;
                                               }
                                           };
                                    @@ -88,7 +88,7 @@ namespace test    {
                                         struct DummyResultSet
                                           : Resolution
                                           {
                                    -        DummySolution solution_;
                                    +        DummySolutions solutions_;
                                     
                                             typedef typename Query::Cursor Cursor;
                                     
                                    @@ -96,7 +96,7 @@ namespace test    {
                                             prepareResolution()
                                               {
                                                 Cursor cursor;
                                    -            cursor.pointAt (solution_.next());
                                    +            cursor.pointAt (solutions_.next());
                                                 return cursor;
                                               }
                                             
                                    @@ -105,10 +105,10 @@ namespace test    {
                                               {
                                                 Cursor& cursor = static_cast (pos);
                                                 
                                    -            if (solution_.exhausted())
                                    +            if (solutions_.exhausted())
                                                   cursor.point_at (0);
                                                 else
                                    -              cursor.point_at (solution_.next());
                                    +              cursor.point_at (solutions_.next());
                                               }
                                           };
                                           
                                    @@ -127,7 +127,7 @@ namespace test    {
                                             bool
                                             wantResultType (Goal::QueryID qID)  const
                                               {
                                    -            return qID.type == ResultType::ID::get();
                                    +            return qID.type == getResultTypeID();
                                               }
                                             
                                           };
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index df0a49d38..423409a94 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -5562,9 +5562,9 @@ Using transitions is a very basic task and thus needs viable support by the GUI.
                                     Because of this experience, ichthyo wants to support a more general case of transitions, which have N output connections, behave similar to their "simple" counterpart, but leave out the mixing step. As a plus, such transitions can be inserted at the source ports of N clips or between any intermediary or final output pipes as well. Any transition processor capable of handling this situation should provide some flag, in order to decide if he can be placed in such a manner. (wichin the builder, encountering a  inconsistently placed transition is just an [[building error|BuildingError]])
                                     
                                    -
                                    +
                                    //the problem of processing specifically typed queries without tying query and QueryResolver.//<br/>This problem can be seen as a instance of the problematic situation encountered with most visitation schemes: we want entities and tools (visitors) to work together, without being forced to commit to a pre-defined table of operations. In the situation at hand here, we want //some entities// &mdash; which we don't know &mdash; to issue //some queries// &mdash; which we don't know either. Obviously, such a problem can be solved only by controlling the scope of this incomplete knowledge, and the sequence in time of building it.
                                    -Thus, to re-state the problem more specifically, we want the //definition//&nbsp; of the entities to be completely separate of those concerning the details of the query resolution mechanism, so to be able to design, reason, verify and extend each one without being forced into concern about the details of the respective other side. So, the buildup of the combined structure has to be postponed &mdash; assuring it //has//&nbsp; happened at the point it's operations are required.
                                    +Thus, to re-state the problem more specifically, we want the //definition//&nbsp; of the entities to be completely separate of those definitions concerning the details of the query resolution mechanism, so to be able to design, reason, verify and extend each one without being forced into concern about the details of the respective other side. So, the buildup of the combined structure has to be postponed &mdash; assuring it //has//&nbsp; happened at the point it's operations are required.
                                     
                                     !Solution Stages
                                     * in ''static scope'' (while compiling), just a {{{Query<TY>}}} gets mentioned.<br/>As this is the only chance for driving a specifically typed context, we need to prepare a registration mechanism, to allow for //remembering//&nbsp; this context later.
                                    
                                    From 9ff7b1eaeb2434bf17f4d13840cf004954902198 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 30 Oct 2009 20:33:44 +0100
                                    Subject: [PATCH 042/377] Implement registration of a resolution function.
                                     QueryResolver_test pass
                                    
                                    ---
                                     src/proc/mobject/session/query-resolver.cpp   | 10 +++
                                     src/proc/mobject/session/query-resolver.hpp   | 20 +++--
                                     tests/42query.tests                           |  4 -
                                     tests/43session.tests                         | 20 +++++
                                     .../mobject/session/query-resolver-test.cpp   | 89 +++++++++++++------
                                     5 files changed, 109 insertions(+), 34 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp
                                    index 8bfb65eb3..db4f86894 100644
                                    --- a/src/proc/mobject/session/query-resolver.cpp
                                    +++ b/src/proc/mobject/session/query-resolver.cpp
                                    @@ -110,6 +110,16 @@ namespace session {
                                       }
                                       
                                       
                                    +  void
                                    +  QueryResolver::installResolutionCase (QID qID, function resolutionFun)
                                    +  {
                                    +    ENSURE (!dispatcher_->contains (qID),
                                    +            "duplicate registration of query resolution function");
                                    +    
                                    +    dispatcher_->defineProduction (qID, resolutionFun);
                                    +  }
                                    +  
                                    +  
                                       
                                       
                                     }} // namespace mobject::session
                                    diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp
                                    index 6c0d295c5..29ab318d3 100644
                                    --- a/src/proc/mobject/session/query-resolver.hpp
                                    +++ b/src/proc/mobject/session/query-resolver.hpp
                                    @@ -33,6 +33,7 @@
                                     
                                     #include 
                                     #include 
                                    +#include 
                                     #include 
                                     //#include 
                                     //#include 
                                    @@ -45,6 +46,8 @@ namespace session {
                                       
                                       using util::unConst;
                                       using boost::noncopyable;
                                    +  using boost::scoped_ptr;
                                    +  using std::tr1::function;
                                       
                                       
                                       class Goal;
                                    @@ -181,6 +184,9 @@ namespace session {
                                         };
                                       
                                       
                                    +  
                                    +  
                                    +  
                                       /** 
                                        * ABC denoting the result set
                                        * of an individual query resolution
                                    @@ -222,14 +228,13 @@ namespace session {
                                       class QueryResolver
                                         : noncopyable
                                         {
                                    -      boost::scoped_ptr dispatcher_;
                                    +      scoped_ptr dispatcher_;
                                    +      
                                           
                                         public:
                                    -      
                                           virtual ~QueryResolver() ;
                                           
                                           
                                    -      
                                           /** issue a query to retrieve contents
                                            *  The query is handed over internally to a suitable resolver implementation.
                                            *  @return concrete Resolution of the query (ResultSet), \em managed by smart-pointer.
                                    @@ -241,8 +246,13 @@ namespace session {
                                           PReso issue (Goal& query)  const;
                                           
                                           
                                    -    protected:
                                    -      virtual bool canHandleQuery (Goal::QueryID qID)  const =0;
                                    +      
                                    +    protected: /* === API for concrete query resolvers === */
                                    +      
                                    +      virtual bool canHandleQuery (Goal::QueryID)  const =0;
                                    +      
                                    +      void installResolutionCase (Goal::QueryID const&,
                                    +                                  function);
                                           
                                           QueryResolver();
                                         };
                                    diff --git a/tests/42query.tests b/tests/42query.tests
                                    index 5d437cc41..664e2912a 100644
                                    --- a/tests/42query.tests
                                    +++ b/tests/42query.tests
                                    @@ -2,10 +2,6 @@ TESTING "Proc Layer config rules Test Suite" ./test-lib --group=query
                                     
                                     
                                     
                                    -PLANNED "issuing typed queries" QueryResolver_test <
                                     #include 
                                    @@ -44,15 +36,17 @@ namespace session {
                                     namespace test    {
                                       
                                       using lib::test::showSizeof;
                                    -  //using util::isSameObject;
                                    -  //using lumiera::Time;
                                       using std::string;
                                       using std::cout;
                                       using std::endl;
                                       
                                    -  namespace { // a test query resolving facility
                                    +  
                                    +  
                                    +  
                                    +  namespace { // providing a test query resolving facility...
                                         
                                         
                                    +    /** an sequence of "solutions" to be "found" */
                                         template
                                         class DummySolutions;
                                         
                                    @@ -65,12 +59,12 @@ namespace test    {
                                             DummySolutions() : resNr_(7) {}
                                             
                                             int* next () { --resNr_; return &resNr_; }
                                    -        bool exhausted() { return bool(resNr_); }
                                    +        bool exhausted() { return !bool(resNr_); }
                                           };
                                         
                                         template<>
                                         class DummySolutions
                                    -      : DummySolutions 
                                    +      : public DummySolutions 
                                           {
                                             string currentText_;
                                             
                                    @@ -84,19 +78,27 @@ namespace test    {
                                               }
                                           };
                                         
                                    +    
                                    +    /**
                                    +     * a concrete "resolution" of the query
                                    +     * is a set of "solutions", which can be 
                                    +     * explored by iteration. Thus, the result set
                                    +     * has to implement the iteration control API
                                    +     * as required by IterAdapter
                                    +     */
                                         template
                                         struct DummyResultSet
                                           : Resolution
                                           {
                                             DummySolutions solutions_;
                                    -
                                    +        
                                             typedef typename Query::Cursor Cursor;
                                    -
                                    +        
                                             Result
                                             prepareResolution()
                                               {
                                                 Cursor cursor;
                                    -            cursor.pointAt (solutions_.next());
                                    +            cursor.point_at (solutions_.next());
                                                 return cursor;
                                               }
                                             
                                    @@ -111,8 +113,15 @@ namespace test    {
                                                   cursor.point_at (solutions_.next());
                                               }
                                           };
                                    -      
                                    -    class TypeMatchFilter
                                    +    
                                    +    
                                    +    
                                    +    /**
                                    +     * a (dummy) concrete query resolution facility.
                                    +     * It is hard-wired to accept queries on int and string,
                                    +     * generating a sequence of results for both cases
                                    +     */
                                    +    class DummyTypedSolutionProducer
                                           : public QueryResolver
                                           {
                                             bool
                                    @@ -130,14 +139,44 @@ namespace test    {
                                                 return qID.type == getResultTypeID();
                                               }
                                             
                                    +        
                                    +        template
                                    +        static Resolution*
                                    +        resolutionFunction (Goal& goal)
                                    +          {
                                    +            Goal::QueryID const& qID = goal.getQID();
                                    +            REQUIRE (qID.kind == Goal::GENERIC
                                    +                  && qID.type == getResultTypeID());
                                    +            
                                    +            return new DummyResultSet(); 
                                    +          }
                                    +        
                                    +      public:
                                    +        DummyTypedSolutionProducer()
                                    +          : QueryResolver()
                                    +          {
                                    +            Goal::QueryID case1 = {Goal::GENERIC, getResultTypeID()};
                                    +            Goal::QueryID case2 = {Goal::GENERIC, getResultTypeID()};
                                    +            
                                    +            installResolutionCase(case1, &resolutionFunction );
                                    +            installResolutionCase(case2, &resolutionFunction );
                                    +          }
                                           };
                                    -  
                                    +    
                                    +    
                                    +    lib::Singleton testResolver;
                                    +    
                                         QueryResolver&
                                         buildTestQueryResolver ()
                                         {
                                    -      UNIMPLEMENTED("build a special resolver just for this test and register it.");
                                    +      return testResolver();
                                         }
                                    -  }
                                    +    
                                    +  } // (END) implementation of a test query resolving facility
                                    +  
                                    +  
                                    +  
                                    +  
                                       
                                       
                                       /***********************************************************************************
                                    @@ -168,11 +207,11 @@ namespace test    {
                                           static void
                                           explore (ITER ii)
                                             {
                                    -          cout << "Query-Results: " << showSizeof(ii) << endl;;
                                    -          while (ii)
                                    +          cout << "Query-Results: " << showSizeof(ii) << endl;
                                    +          for ( ; ii; ++ii )
                                                   cout << *ii << endl;
                                             }
                                    -          
                                    +      
                                         };
                                       
                                       
                                    
                                    From ea52a188fa5b6cef87a38ee1877218a46eead0a1 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 31 Oct 2009 19:50:23 +0100
                                    Subject: [PATCH 043/377] Start a category for documenting concepts,
                                     abstractions and formalities
                                    
                                    ---
                                     wiki/renderengine.html | 25 +++++++++++++++++++++----
                                     1 file changed, 21 insertions(+), 4 deletions(-)
                                    
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 423409a94..5a744b2cc 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -514,6 +514,18 @@ 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.
                                    +!!Collaborators
                                    +* the ''advised'' entity 
                                    +* the ''advisor''
                                    +* ''advice system''
                                    +
                                    +
                                    Memory management facility for the low-level model (render nodes network). The model is organised into temporal segments, which are considered to be structurally constant and uniform. The objects within each segment are strongly interconnected, and thus each segment is being built in a single build process and is replaced or released as a whole. __~AllocationCluster__ implements memory management to support this usage pattern. He owns a number of object families of various types.[>img[draw/AllocationCluster.png]]
                                     * [[processing nodes|ProcNode]] &mdash; probably with several subclasses (?)
                                    @@ -1122,6 +1134,10 @@ Connecting data streams of differing type involves a StreamConversion. Mostly, t
                                     * retrieve a //strategy// for implementing a connection
                                     
                                    +
                                    +
                                    This index refers to the conceptual, more abstract and formally specified aspects of the Proc-Layer and Lumiera in general.
                                    +More often than not, these emerge from immediate solutions, being percieved as especially expressive, when taken on, yielding guidance by themselves. Some others, [[Placements|Placement]] and [[Advice]] to mention here, immediately substantiate the vision.
                                    +
                                    Configuration Queries are requests to the system to "create or retrieve an object with //this and that // capabilities". They are resolved by a rule based system ({{red{planned feature}}}) and the user can extend the used rules for each Session. Syntactically, they are stated in ''prolog'' syntax as a conjunction (=logical and) of ''predicates'', for example {{{stream(mpeg), pipe(myPipe)}}}. Queries are typed to the kind of expected result object: {{{Query<Pipe> ("stream(mpeg)")}}} requests a pipe excepting/delivering mpeg stream data &mdash; and it depends on the current configuration what "mpeg" means. If there is any stream data producing component in the system, which advertises to deliver {{{stream(mpeg)}}}, and a pipe can be configured or connected with this component, then the [[defaults manager|DefaultsManagement]] will create/deliver a [[Pipe|PipeHandling]] object configured accordingly.
                                     &rarr; [[Configuration Rules system|ConfigRules]]
                                    @@ -1675,7 +1691,7 @@ Finally, this example shows an ''automation'' data set controlling some paramete
                                     * shaping the GUI/~Proc-Interface, based on MObjectRef and the [[Command frontend|CommandHandling]]
                                     * defining PlacementScope in order to allow for [[discovering session contents|Query]]
                                    -
                                    +
                                    !Observations, Ideas, Proposals
                                     ''this page is a scrapbook for collecting ideas'' &mdash; please don't take anything noted here too literal. While writing code, I observe that I (ichthyo) follow certain informal guidelines, some of which I'd like to note down because they could evolve into general style guidelines for the Proc-Layer code.
                                     * ''Inversion of Control'' is the leading design principle.
                                    @@ -2970,8 +2986,8 @@ there is not much you can do directly with a pipe asset. It is an point of refer
                                     Pipes are integrated with the [[management of defaults|DefaultsManagement]]. For example, any pipe uses implicitly some [[processing pattern|ProcPatt]] &mdash; it may default to the empty pattern. This feature enables to apply some standard wiring to the pipes (e.g a fader for audio, similar to the classic mixing consoles). This //is // a global property of the pipe, but &mdash; contrary to the stream type &mdash; this pattern may be switched
                                     
                                    -
                                    -
                                    A Placement represents a //relation:// it is always linked to a //Subject// (this being a [[Media Object|MObject]]) and has the meaning to //place// this Subject in some manner, either relatively to other Media Objects, or by some Constraint or simply absolute at (time, output). The latter case is especially important for the build process and thus represented by a special [[Sub-Interface ExplicitPlacement|ExplicitPlacement]]. Besides this simple cases, Placements can also express more specific kinds of "locating" an object, like placing a sound source at a pan position or placing a video clip at a given layer (above or below another video clip)
                                    +
                                    +
                                    A Placement represents a //relation:// it is always linked to a //Subject// (this being a [[Media Object|MObject]]) and has the meaning to //place// this Subject in some manner, either relatively to other Media Objects, by some Constraint or simply absolute at (time, output). The latter case is especially important for the build process and thus represented by a special [[Sub-Interface ExplicitPlacement|ExplicitPlacement]]. Besides this simple cases, Placements can also express more specific kinds of "locating" an object, like placing a sound source at a pan position or placing a video clip at a given layer (above or below another video clip)
                                     
                                     So basically placements represent a query interface: you can allways ask the placement to find out about the position of the related object in terms of (time, output), and &mdash; depending on the specific object and situation &mdash; also about these additional [[placement derived dimensions|PlacementDerivedDimension]] like sound pan or layer order or similar things which also fit into the general concept of "placing" an object.
                                     
                                    @@ -3325,7 +3341,7 @@ Besides, they provide an __inward interface__ for the [[ProcNode]]s, enabling th
                                     
                                     
                                    -
                                    +
                                    The Render Engine is the part of the application doing the actual video calculations. Utilising system level services and retrieving raw audio and video data through [[Lumiera's Backend|backend.html]], its operations are guided by the objects and parameters edited by the user in [[the session|Session]]. Thus, the Lumiera Proc-Layer covers the (abstract) edit operations available to the user, the representation of [["editable things"|MObjects]] and the translation of those into facilities allowing to [[drive the rendering|Rendering]].
                                     <<<
                                     ''Status'': started out as design draft in summer '07, Ichthyo is now in the middle of a implementing the foundations and main structures in C++
                                    @@ -3353,6 +3369,7 @@ The system is ''open'' inasmuch every part mirrors the structure of correspondin
                                     &rarr; [[Two Examples|Examples]] (Object diagrams) 
                                     &rarr; how [[Automation]] works
                                     &rarr; [[Problems|ProblemsTodo]] to be solved and notable [[design decisions|DesignDecisions]]
                                    +&rarr; [[Concepts, Abstractions and Formalities|Concepts]]
                                     &rarr; [[Implementation Details|ImplementationDetails]] {{red{WIP}}}
                                     
                                    From ab524c3b7cb78e7a0e88a985a148f290d2b0ec42 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 31 Oct 2009 23:57:47 +0100 Subject: [PATCH 044/377] Document the Lumiera Forward Iterator concept --- wiki/renderengine.html | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 5a744b2cc..af4d8e0b2 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -1483,6 +1483,34 @@ Some further details As the builder and thus render engine //only consults the fixture,// while all editing operations finally propagate to the fixture as well, we get an isolation layer between the high level part of the Proc layer (editing, object manipulation) and the render engine. Creating the Fixture can be seen as a preprocessing step to simplify the build process. For this reason, the process of [[(re)building the fixture|PlanningBuildFixture]] has been designed together with the [[Builder]]
                                    +
                                    +
                                    The situation focussed by this concept is when an API needs to expose a sequence of results, values or objects, instead of just yielding a function result value. As the naive solution of passing an pointer or array creates coupling to internals, it was superseded by the ~GoF [[Iterator pattern|http://en.wikipedia.org/wiki/Iterator]]. Iteration can be implemented by convention, polymorphically or by generic programming; we use the latter approach.
                                    +
                                    +!Lumiera Forward Iterator concept
                                    +''Definition'': An Iterator is a self-contained token value, representing the promise to pull a sequence of data
                                    +* rather then deriving from an specific interface, anything behaving appropriately //is a Lumiera Forward Iterator.// 
                                    +* the client finds a typedef at a suitable, nearby location. Objects of this type can be created, copied and compared.
                                    +* any Lumiera forward iterator can be in //exhausted// &nbsp;(invalid) state, which can be checked by {{{bool}}} conversion.
                                    +* especially, default constructed iterators are fixed to that state. Non-exhausted iterators may only be obtained by API call.
                                    +* the exhausted state is final and can't be reset, meaning that any iterator is a disposable one-way-off object.
                                    +* when an iterator is //not//&nbsp; in the exhausted state, it may be //dereferenced// ({{{*i}}}), yielding the "current" value
                                    +* moreover, iterators may be incremented ({{{++i}}}) until exhaustion.
                                    +
                                    +!!Discussion
                                    +The Lumiera Forward Iterator concept is a blend of the STL iterators and iterator concepts found in Java, C#, Python and Ruby. The chosen syntax should look familiar to C++ programmers and indeed is compatible to STL containers and ranges. To the contrary, while a STL iterator can be thought off as being just a disguised pointer, the semantics of Lumiera Forward Iterators is deliberately reduced to a single, one-way-off forward iteration, they can't be reset, manipulated by any arithmetic, and the result of assigning to an dereferenced iterator is unspecified, as is the meaning of post-increment and stored copies in general. You //should not think of an iterator as denoting a position// &mdash; just a one-way off promise to yield data.
                                    +
                                    +Another notable difference to the STL iterators is the default ctor and the {{{bool}}} conversion. The latter allows using iterators painlessly within {{{for}}} and {{{while}}} loops; a default constructed iterator is equivalent to the STL container's {{{end()}}} value &mdash; indeed any //container-like// object exposing Lumiera Forward Iteration is encouraged to provide such an {{{end()}}}-function, additionally enabling iteration by {{{std::for_each}}} (or Lumiera's even more convenient {{{util::for_each()}}}).
                                    +
                                    +!!Implementation notes
                                    +''iter-adapter.hpp'' provides some helper templates for building Lumiera Forward Iterators.
                                    +* __~IterAdapter__ is the most flexible variant, intended for use by custom facilities. An ~IterAdapter maintains an internal back-link to a facilitiy exposing an iteration control API, which is accessed through free functions as extension point. This iteration control API is similar to C#, allowing to advance to the next result and to check the current iteration state.
                                    +* __~RangeIter__ wraps two existing iterators &mdash; usually obtained from {{{begin()}}} and {{{end()}}} of an STL container embedded within the implementation. This allows for iterator chaining.
                                    +* __~PtrDerefIter__ works similar, but can be used on an STL container holding //pointers,// to be dereferenced automatically on access
                                    +
                                    +Similar to the STL habits, Lumiera Forward Iterators should expose typedefs for {{{pointer}}}, {{{reference}}} and {{{value_type}}}.
                                    +Additionally, they may be used for resource management purposes by "hiding" a ref-counting facility, e.g. allowing to keep a snapshot or restult set around until it can't be accessed anymore.
                                    +
                                    +
                                    This term has //two meanings, //so care has to be taken for not confusing them.
                                     # in general use, a Frame means one full image of a video clip, i.e an array of rows of pixels. For interlaced footage, one Frame contains two halfimages, commonly called Fields. (Cinelerra2 confuses this terms)
                                    @@ -1664,7 +1692,7 @@ Besides routing to a global pipe, wiring plugs can also connect to the source po
                                     Finally, this example shows an ''automation'' data set controlling some parameter of an effect contained in one of the global pipes. From the effect's POV, the automation is simply a ParamProvider, i.e a function yielding a scalar value over time. The automation data set may be implemented as a bézier curve, or by a mathematical function (e.g. sine or fractal pseudo random) or by some captured and interpolated data values. Interestingly, in this example the automation data set has been placed relatively to the meta clip (albeit on another track), thus it will follow and adjust when the latter is moved.
                                     
                                    -
                                    +
                                    This wiki page is the entry point to detail notes covering some technical decisions, details and problems encountered in the course of the implementation of the Lumiera Renderengine, the Builder and the related parts.
                                     
                                     * [[Packages, Interfaces and Namespaces|InterfaceNamespaces]]
                                    @@ -1687,6 +1715,7 @@ Finally, this example shows an ''automation'' data set controlling some paramete
                                     * the relation of [[Project, Timelines and Sequences|TimelineSequences]]
                                     * how to [[start the GUI|GuiStart]] and how to [[communicate|GuiCommunication]]
                                     * build the first LayerSeparationInterfaces
                                    +* create an uniform pattern for [[passing and accessing object collections|ForwardIterator]]
                                     * decide on SessionInterface and create [[Session datastructure layout|SessionDataMem]]
                                     * shaping the GUI/~Proc-Interface, based on MObjectRef and the [[Command frontend|CommandHandling]]
                                     * defining PlacementScope in order to allow for [[discovering session contents|Query]]
                                    From 2620c38ed9f5648e1d989b70b531fd2016f93a36 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 1 Nov 2009 02:02:21 +0100 Subject: [PATCH 045/377] documentation, close some tickets... --- src/lib/iter-adapter.hpp | 1 + src/proc/assetmanager.hpp | 4 +-- tests/43session.tests | 28 +++++++++---------- .../mobject/session/defsregistryimpltest.cpp | 2 +- tests/lib/iter-adapter-test.cpp | 5 +--- wiki/renderengine.html | 6 ++-- 6 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index e5ad6d15c..5dc9bab54 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -128,6 +128,7 @@ namespace lib { * - the source container needs to provide hasNext() and iterNext() free functions. * - we may need friendship to implement those extension points on the container * - the end-of-iteration can be detected by bool check + * @note it is possible to "hide" a smart-ptr within the CON template parameter. * * \par Stipulations * - POS refers to the current position within the data source of this iterator. diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index 6068a86c4..6e0730b5e 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -73,11 +73,11 @@ namespace asset { /** provide the unique ID for given Asset::Ident tuple */ static ID getID (const Asset::Ident&); - /** retrieve the registerd smart-ptr for any asset */ + /** retrieve the registered smart-ptr for any asset */ template static P wrap (const KIND& asset); - /** find and return corresponging object */ + /** find and return corresponding object */ template P getAsset (const ID& id) throw(lumiera::error::Invalid); diff --git a/tests/43session.tests b/tests/43session.tests index a88cb2b30..7320329bc 100644 --- a/tests/43session.tests +++ b/tests/43session.tests @@ -69,21 +69,21 @@ END TEST "issuing typed queries" QueryResolver_test <candidates(q3); ASSERT ( *i++ == o3); // found by direct match - ASSERT ( *i++ == o1); // followed by the ordered ennumeration + ASSERT ( *i++ == o1); // followed by the ordered enumeration ASSERT ( *i++ == o2); ASSERT ( *i++ == o3); ASSERT ( *i++ == o3); diff --git a/tests/lib/iter-adapter-test.cpp b/tests/lib/iter-adapter-test.cpp index 112a231af..c90df8cd4 100644 --- a/tests/lib/iter-adapter-test.cpp +++ b/tests/lib/iter-adapter-test.cpp @@ -98,12 +98,9 @@ namespace test{ const_iterator end () const { return const_iterator(); } + protected: /* ==== API for the IterAdapter ==== */ - friend class IterAdapter<_Vec::iterator, TestContainer>; - friend class IterAdapter<_Vec::const_iterator,TestContainer>; - - /** Implementation of Iteration-logic: pull next element. */ template friend void diff --git a/wiki/renderengine.html b/wiki/renderengine.html index af4d8e0b2..f17e1f552 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -1134,9 +1134,9 @@ Connecting data streams of differing type involves a StreamConversion. Mostly, t * retrieve a //strategy// for implementing a connection
                                    -
                                    +
                                    This index refers to the conceptual, more abstract and formally specified aspects of the Proc-Layer and Lumiera in general.
                                    -More often than not, these emerge from immediate solutions, being percieved as especially expressive, when taken on, yielding guidance by themselves. Some others, [[Placements|Placement]] and [[Advice]] to mention here, immediately substantiate the vision.
                                    +More often than not, these emerge from immediate solutions, being percieved as especially expressive, when taken on, yielding guidance by themselves. Some others, [[Placements|Placement]] and [[Advice]] to mention here, immediately substantiate the original vision.
                                    Configuration Queries are requests to the system to "create or retrieve an object with //this and that // capabilities". They are resolved by a rule based system ({{red{planned feature}}}) and the user can extend the used rules for each Session. Syntactically, they are stated in ''prolog'' syntax as a conjunction (=logical and) of ''predicates'', for example {{{stream(mpeg), pipe(myPipe)}}}. Queries are typed to the kind of expected result object: {{{Query<Pipe> ("stream(mpeg)")}}} requests a pipe excepting/delivering mpeg stream data &mdash; and it depends on the current configuration what "mpeg" means. If there is any stream data producing component in the system, which advertises to deliver {{{stream(mpeg)}}}, and a pipe can be configured or connected with this component, then the [[defaults manager|DefaultsManagement]] will create/deliver a [[Pipe|PipeHandling]] object configured accordingly.
                                    @@ -1262,7 +1262,7 @@ As we don't have a Prolog interpreter on board yet, we utilize a mock store with
                                     {{{default(Obj)}}} is a predicate expressing that the object {{{Obj}}} can be considered the default setup under the given conditions. Using the //default// can be considered as a shortcut for actually finding a exact and unique solution. The latter would require to specify all sorts of detailed properties up to the point where only one single object can satisfy all conditions. On the other hand, leaving some properties unspecified would yield a set of solutions (and the user code issuing the query had to provide means for selecting one soltution from this set). Just falling back on the //default// means that the user code actually doesn't care for any additional properties (as long as the properties he //does// care for are satisfied). Nothing is said specifically on //how//&nbsp; this default gets configured; actually there can be rules //somewhere,// and, additionally, anything encountered once while asking for a default can be re-used as default under similar circumstances.
                                     &rarr; [[implementing defaults|DefaultsImplementation]]
                                    -
                                    +
                                    Along the way of working out various [[implementation details|ImplementationDetails]], decisions need to be made on how to understand the different facilities and entities and how to tackle some of the problems. This page is mainly a collection of keywords, summaries and links to further the discussion. And the various decisions should allways be read as proposals to solve some problem at hand...
                                     
                                     ''Everything is an object'' &mdash; of course, that's a //no-brainer,// todays. Rather, important is what is not "an object", meaning it can't be arranged arbitrarily
                                    
                                    From 356fe8fd135cc91f51ed571ed8880b5b679c2c72 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 1 Nov 2009 03:47:35 +0100
                                    Subject: [PATCH 046/377] change the ContensQuery stub to fit into the
                                     QueryResolver in its current form
                                    
                                    Actually, the implementation within PlacementIndex is missing.
                                    Moreover, I think now that PlacementIndex shouldn't implement
                                    QueryResolver directly.
                                    ---
                                     src/proc/mobject/placement-index.cpp          |  6 +-
                                     src/proc/mobject/placement-index.hpp          | 13 ++++-
                                     src/proc/mobject/session/contents-query.hpp   | 28 +++++++---
                                     src/proc/mobject/session/query-resolver.cpp   | 14 ++---
                                     src/proc/mobject/session/query-resolver.hpp   | 56 +++++++++++++------
                                     .../mobject/session/contents-query-test.cpp   | 28 +++++-----
                                     .../mobject/session/query-resolver-test.cpp   |  9 +--
                                     7 files changed, 100 insertions(+), 54 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/placement-index.cpp b/src/proc/mobject/placement-index.cpp
                                    index dc84d0481..6b01eeeaa 100644
                                    --- a/src/proc/mobject/placement-index.cpp
                                    +++ b/src/proc/mobject/placement-index.cpp
                                    @@ -63,6 +63,8 @@ namespace mobject {
                                       typedef PlacementIndex::PRef PRef;
                                       typedef PlacementIndex::ID ID;
                                       
                                    +  typedef PlacementIndex::QID QID; //////////TODO
                                    +  
                                       
                                       /** @internal Factory for creating a new placement index.
                                        *            For use by the Session and for unit tests.  
                                    @@ -77,9 +79,11 @@ namespace mobject {
                                      
                                     
                                       bool
                                    -  PlacementIndex::canHandleQuery (session::Goal::QueryID qID) const
                                    +  PlacementIndex::canHandleQuery (QID qID) const
                                       {
                                         UNIMPLEMENTED ("decide by hard-wired check if the given Query can be resolved by PlacementIndex");
                                    +    return session::Goal::GENERIC == qID.kind;
                                    +        // thats not enough! need to check the typeID (match to Placement, with some fixed MOX values)
                                       }
                                       
                                       
                                    diff --git a/src/proc/mobject/placement-index.hpp b/src/proc/mobject/placement-index.hpp
                                    index 55f1f52ec..4fb15d428 100644
                                    --- a/src/proc/mobject/placement-index.hpp
                                    +++ b/src/proc/mobject/placement-index.hpp
                                    @@ -73,13 +73,15 @@ namespace mobject { ///////////////////////////////////////////TODO: shouldn't t
                                           typedef PlacementRef PRef;
                                           typedef PlacementMO::ID const& ID;
                                           
                                    +      typedef session::Goal::QueryID const& QID;
                                    +      
                                           
                                           PlacementMO& find (ID)  const;
                                           
                                           template
                                           Placement&  find (PlacementMO::Id)  const;
                                           template
                                    -      Placement&  find (PlacementRef const&)  const;
                                    +      Placement&  find (PlacementRef const&) const;
                                           
                                           PlacementMO& getScope (PlacementMO const&)  const;
                                           PlacementMO& getScope (ID)                  const;
                                    @@ -99,7 +101,7 @@ namespace mobject { ///////////////////////////////////////////TODO: shouldn't t
                                           query (PlacementMO& scope)                  const;
                                           
                                           
                                    -      bool canHandleQuery(session::Goal::QueryID) const;
                                    +      bool canHandleQuery(QID)                    const;
                                           
                                           
                                           /* == mutating operations == */
                                    @@ -167,11 +169,16 @@ namespace mobject { ///////////////////////////////////////////TODO: shouldn't t
                                       }
                                       
                                       
                                    +  /** @todo use query-resolver-test as an example.....
                                    +   *        return a result set object derived from Resolution
                                    +   *        For the additional type filtering: build a filter iterator,
                                    +   *        using a type-filtering predicate, based on Placement#isCompatible
                                    +   */
                                       template
                                       inline typename session::Query >::iterator
                                       PlacementIndex::query (PlacementMO& scope)  const
                                       {
                                    -    UNIMPLEMENTED ("actually run the containment query"); 
                                    +    UNIMPLEMENTED ("actually run the containment query");
                                       }
                                       
                                       inline Placement&
                                    diff --git a/src/proc/mobject/session/contents-query.hpp b/src/proc/mobject/session/contents-query.hpp
                                    index d28b0286d..9a2e709a2 100644
                                    --- a/src/proc/mobject/session/contents-query.hpp
                                    +++ b/src/proc/mobject/session/contents-query.hpp
                                    @@ -26,11 +26,9 @@
                                     
                                     //#include "proc/mobject/mobject.hpp"
                                     #include "proc/mobject/placement.hpp"
                                    -#include "proc/mobject/placement-index.hpp"
                                     #include "proc/mobject/session/query-resolver.hpp"
                                     //#include "lib/iter-adapter.hpp"
                                     
                                    -#include 
                                     //#include 
                                     //#include 
                                     
                                    @@ -48,22 +46,36 @@ namespace session {
                                       template
                                       class ContentsQuery
                                         : public Query >
                                    -    , boost::noncopyable
                                         {
                                           typedef Query > _Query;
                                    -      typedef typename _Query::iterator iterator;
                                           
                                    -      PPIdx index_;
                                    +      QueryResolver const&  index_;
                                           PlacementMO const& container_;
                                           
                                           
                                    -      
                                         public:
                                    -      ContentsQuery (PPIdx index, PlacementMO const& scope)
                                    -        : index_(index)
                                    +      ContentsQuery (QueryResolver const& resolver, PlacementMO const& scope)
                                    +        : _Query (_Query::defineQueryTypeID (Goal::DISCOVERY))
                                    +        , index_(resolver)
                                             , container_(scope)
                                             { }
                                           
                                    +      typedef typename _Query::iterator iterator;
                                    +      
                                    +      iterator
                                    +      operator() ()  const
                                    +        {
                                    +          return _Query::resolveBy (index_);
                                    +        }
                                    +      
                                    +      PlacementMO const&
                                    +      searchScope ()
                                    +        {
                                    +          return container_;
                                    +        }
                                    +      
                                    +      /////////////////////TODO maybe exposing a content filter predicate from here?
                                    +      
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                       
                                    diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp
                                    index db4f86894..af618310d 100644
                                    --- a/src/proc/mobject/session/query-resolver.cpp
                                    +++ b/src/proc/mobject/session/query-resolver.cpp
                                    @@ -62,17 +62,17 @@ namespace session {
                                       
                                       /** factory used as dispatcher table
                                        *  for resolving typed queries  */
                                    -  typedef MultiFact< Resolution(Goal&)   // nominal signature of fabrication
                                    -                   , Goal::QueryID      //  select resolution function by kind-of-Query
                                    -                   , BuildRefcountPtr  //   wrapper: manage result set by smart-ptr
                                    -                   > DispatcherTable; //
                                    +  typedef MultiFact< Resolution(Goal const&) // nominal signature of fabrication
                                    +                   , Goal::QueryID          //  select resolution function by kind-of-Query
                                    +                   , BuildRefcountPtr      //   wrapper: manage result set by smart-ptr
                                    +                   > DispatcherTable;     //
                                       
                                       struct QueryDispatcher
                                         : DispatcherTable
                                         {
                                           
                                           PReso
                                    -      handle (Goal& query)
                                    +      handle (Goal const& query)
                                             {
                                               QID qID = query.getQID();
                                               ENSURE (contains (qID));
                                    @@ -99,7 +99,7 @@ namespace session {
                                        *  typed context and downcast the Goal appropriately
                                        */
                                       PReso  
                                    -  QueryResolver::issue (Goal& query)  const
                                    +  QueryResolver::issue (Goal const& query)  const
                                       {
                                         TODO ("ensure proper initialisation");  
                                         
                                    @@ -111,7 +111,7 @@ namespace session {
                                       
                                       
                                       void
                                    -  QueryResolver::installResolutionCase (QID qID, function resolutionFun)
                                    +  QueryResolver::installResolutionCase (QID qID, function resolutionFun)
                                       {
                                         ENSURE (!dispatcher_->contains (qID),
                                                 "duplicate registration of query resolution function");
                                    diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp
                                    index 29ab318d3..e389b5c27 100644
                                    --- a/src/proc/mobject/session/query-resolver.hpp
                                    +++ b/src/proc/mobject/session/query-resolver.hpp
                                    @@ -81,7 +81,11 @@ namespace session {
                                               size_t type;
                                             };
                                           
                                    -      QueryID getQID() { return id_; }
                                    +      QueryID const&
                                    +      getQID()  const
                                    +        {
                                    +          return id_;
                                    +        }
                                           
                                           
                                           /** 
                                    @@ -147,10 +151,11 @@ namespace session {
                                       class Query
                                         : public Goal
                                         {
                                    +    protected:
                                           static QueryID
                                    -      defineQueryTypeID ()
                                    +      defineQueryTypeID (Kind queryType = Goal::GENERIC)
                                             {
                                    -          QueryID id = {Goal::GENERIC, getResultTypeID() };
                                    +          QueryID id = {queryType, getResultTypeID() };
                                               return id;
                                             }
                                           
                                    @@ -178,8 +183,14 @@ namespace session {
                                           
                                           typedef lib::IterAdapter iterator;
                                           
                                    -      iterator
                                    -      operator() (QueryResolver const& resolver);
                                    +      iterator operator() (QueryResolver const& resolver)  const;
                                    +      iterator resolveBy  (QueryResolver const& resolver)  const;
                                    +      
                                    +      
                                    +    protected:
                                    +      Query (QueryID qID)
                                    +        : Goal (qID)
                                    +        { }
                                           
                                         };
                                       
                                    @@ -243,31 +254,42 @@ namespace session {
                                            *         or failure of an external facility used for resolution.
                                            *  @note a query may yield no results, in which case the iterator is empty.
                                            */
                                    -      PReso issue (Goal& query)  const;
                                    +      PReso issue (Goal const& query)  const;
                                           
                                           
                                           
                                    -    protected: /* === API for concrete query resolvers === */
                                    +    protected:  /* ===== API for concrete query resolvers ===== */
                                           
                                    -      virtual bool canHandleQuery (Goal::QueryID)  const =0;
                                    +      virtual bool canHandleQuery (Goal::QueryID const&)  const =0;
                                           
                                           void installResolutionCase (Goal::QueryID const&,
                                    -                                  function);
                                    +                                  function);
                                           
                                           QueryResolver();
                                         };
                                    -///////////////////////////TODO currently just fleshing the API
                                    +  
                                    +  
                                       
                                       
                                       template
                                       inline typename Query::iterator
                                    -  Query::operator() (QueryResolver const& resolver)
                                    -    {
                                    -      PReso resultSet = resolver.issue (*this);
                                    -      Result first = resultSet->prepareResolution();
                                    -      Cursor& start = static_cast (first);
                                    -      return iterator (resultSet, start);
                                    -    }
                                    +  Query::resolveBy (QueryResolver const& resolver)  const
                                    +  {
                                    +    PReso resultSet = resolver.issue (*this);
                                    +    Result first = resultSet->prepareResolution();
                                    +    Cursor& start = static_cast (first);
                                    +    return iterator (resultSet, start);
                                    +  }
                                    +  
                                    +  
                                    +  /** notational convenience shortcut,
                                    +   *  synonymous to #resolveBy */
                                    +  template
                                    +  inline typename Query::iterator
                                    +  Query::operator() (QueryResolver const& resolver)  const
                                    +  {
                                    +    return resolveBy (resolver);
                                    +  }
                                       
                                       
                                     }} // namespace mobject::session
                                    diff --git a/tests/components/proc/mobject/session/contents-query-test.cpp b/tests/components/proc/mobject/session/contents-query-test.cpp
                                    index e8619c217..16125e7bd 100644
                                    --- a/tests/components/proc/mobject/session/contents-query-test.cpp
                                    +++ b/tests/components/proc/mobject/session/contents-query-test.cpp
                                    @@ -27,11 +27,11 @@
                                     #include "proc/mobject/session/query-resolver.hpp"
                                     #include "proc/mobject/session/contents-query.hpp"
                                     #include "proc/mobject/session/test-scopes.hpp"
                                    -//#include "proc/mobject/placement-index.hpp"
                                    +//#include "proc/mobject/placement-resolver.hpp"
                                     //#include "lib/util.hpp"
                                     
                                     #include 
                                    -//#include 
                                    +#include 
                                     
                                     
                                     
                                    @@ -43,7 +43,7 @@ namespace test    {
                                       using session::Query;
                                       //using util::isSameObject;
                                       //using lumiera::Time;
                                    -  //using std::string;
                                    +  using std::string;
                                       using std::cout;
                                       using std::endl;
                                     
                                    @@ -68,24 +68,24 @@ namespace test    {
                                               // Prepare an (test)Index backing the PlacementRefs
                                               PPIdx index = build_testScopes();
                                               PlacementMO scope (index->getRoot());
                                    +          QueryResolver const& resolver (*index);
                                               
                                    -          discover (ContentsQuery    (index,scope));
                                    -          discover (ContentsQuery    (index,scope));
                                    -          discover (ContentsQuery (index,scope));
                                    -          discover (ContentsQuery (index,scope));
                                    -          discover (ContentsQuery(index,scope));
                                    +          discover (ContentsQuery    (resolver,scope));
                                    +          discover (ContentsQuery    (resolver,scope));
                                    +          discover (ContentsQuery (resolver,scope));
                                    +          discover (ContentsQuery (resolver,scope));
                                    +          discover (ContentsQuery(resolver,scope));
                                             }
                                           
                                           
                                           template
                                           void
                                    -      discover (Query const& query)
                                    +      discover (ContentsQuery const& query)
                                             {
                                    -#if false  //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384  !!!!!!!!!
                                    -          Query::iterator elm = query();
                                    -          while (elm)
                                    -            cout << *elm++ << endl;
                                    -#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!!
                                    +          for (typename ContentsQuery::iterator elm = query();
                                    +               elm;
                                    +             ++elm)
                                    +            cout << string(*elm) << endl;
                                             }
                                               
                                         };
                                    diff --git a/tests/components/proc/mobject/session/query-resolver-test.cpp b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    index 82231367f..7aeeab60e 100644
                                    --- a/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    +++ b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    @@ -45,6 +45,7 @@ namespace test    {
                                       
                                       namespace { // providing a test query resolving facility...
                                         
                                    +    typedef Goal::QueryID const& QID;
                                         
                                         /** an sequence of "solutions" to be "found" */
                                         template
                                    @@ -125,7 +126,7 @@ namespace test    {
                                           : public QueryResolver
                                           {
                                             bool
                                    -        canHandleQuery (Goal::QueryID qID)  const
                                    +        canHandleQuery (QID qID)  const
                                               {
                                                 return Goal::GENERIC == qID.kind 
                                                     && (wantResultType (qID)
                                    @@ -134,7 +135,7 @@ namespace test    {
                                             
                                             template
                                             bool
                                    -        wantResultType (Goal::QueryID qID)  const
                                    +        wantResultType (QID qID)  const
                                               {
                                                 return qID.type == getResultTypeID();
                                               }
                                    @@ -142,9 +143,9 @@ namespace test    {
                                             
                                             template
                                             static Resolution*
                                    -        resolutionFunction (Goal& goal)
                                    +        resolutionFunction (Goal const& goal)
                                               {
                                    -            Goal::QueryID const& qID = goal.getQID();
                                    +            QID qID = goal.getQID();
                                                 REQUIRE (qID.kind == Goal::GENERIC
                                                       && qID.type == getResultTypeID());
                                                 
                                    
                                    From 1c72cbb5997ea65294f32b3b6c2e2f0ec29530d8 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Mon, 2 Nov 2009 06:06:43 +0100
                                    Subject: [PATCH 047/377] Iterator tools: (1) a filtering iterator
                                    
                                    ---
                                     src/lib/iter-adapter.hpp        |  14 +-
                                     src/lib/itertools.hpp           | 320 ++++++++++++++++++++++++++++++++
                                     tests/40components.tests        |  11 ++
                                     tests/lib/iter-adapter-test.cpp |  54 +++++-
                                     tests/lib/itertools-test.cpp    | 192 +++++++++++++++++++
                                     5 files changed, 582 insertions(+), 9 deletions(-)
                                     create mode 100644 src/lib/itertools.hpp
                                     create mode 100644 tests/lib/itertools-test.cpp
                                    
                                    diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp
                                    index 5dc9bab54..b62bb96c7 100644
                                    --- a/src/lib/iter-adapter.hpp
                                    +++ b/src/lib/iter-adapter.hpp
                                    @@ -113,6 +113,14 @@ namespace lib {
                                             typedef const TY* pointer;
                                           };
                                         
                                    +    
                                    +    void
                                    +    _throwIterExhausted()
                                    +    {
                                    +      throw lumiera::error::Invalid ("Can't iterate further",
                                    +            lumiera::error::LUMIERA_ERROR_ITER_EXHAUST);
                                    +    }
                                    +    
                                       }
                                       
                                       
                                    @@ -252,8 +260,7 @@ namespace lib {
                                           _maybe_throw()  const
                                             {
                                               if (!isValid())
                                    -            throw lumiera::error::Invalid ("Can't iterate further",
                                    -                  lumiera::error::LUMIERA_ERROR_ITER_EXHAUST);
                                    +            _throwIterExhausted();
                                             }
                                           
                                           /// comparison is allowed to access impl iterator
                                    @@ -371,8 +378,7 @@ namespace lib {
                                           _maybe_throw()  const
                                             {
                                               if (!isValid())
                                    -            throw lumiera::error::Invalid ("Can't iterate further",
                                    -                  lumiera::error::LUMIERA_ERROR_ITER_EXHAUST);
                                    +            _throwIterExhausted();
                                             }
                                         };
                                       
                                    diff --git a/src/lib/itertools.hpp b/src/lib/itertools.hpp
                                    new file mode 100644
                                    index 000000000..3c541242a
                                    --- /dev/null
                                    +++ b/src/lib/itertools.hpp
                                    @@ -0,0 +1,320 @@
                                    +/*
                                    +  ITERTOOLS.hpp  -  collection of tools for building and combining iterators 
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2009,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +*/
                                    +
                                    +/** @file itertools.hpp
                                    + ** Helpers for working with iterators based on the pipeline model.
                                    + ** Iterators abstract from the underlying data container and provide
                                    + ** the contained data as a source to pull values from. Based on this
                                    + ** model, we can build pipelines, with filters, valves, junction points
                                    + ** and transforming facilities. The templates in this header enable such,
                                    + ** based on the Lumiera Forward Iterator concept. They build on generic
                                    + ** programming techniques, thus are intended to be combined at compile time
                                    + ** using definitive type information. Contrast this to an iterator model
                                    + ** as in Java's Commons-Collections, where Iterator is an Interface based
                                    + ** on virtual functions. Thus, the basic problem to overcome is the lack
                                    + ** of a single common interface, which could serve as foundation for
                                    + ** type inference. As a solution, we use a "onion" approach, where a
                                    + ** generic base gets configured with an active core, implementing
                                    + ** the filtering or processing functionality, while the base class
                                    + ** (IterTool) exposes the operations necessary to comply to the
                                    + ** Forward Iterator Concept. 
                                    + ** 
                                    + ** \par Filtering Iterator
                                    + ** The FilterIter template can be used to build a filter into a pipeline,
                                    + ** as it forwards only those elements from its source iterator, which pass
                                    + ** the predicate evaluation. Anything acceptable as ctor parameter for a
                                    + ** tr1::function object can be passed in as predicate, but of course the
                                    + ** signature must be sensible. Please note, that -- depending on the
                                    + ** predicate -- already the ctor or even a simple \c bool test might
                                    + ** pull and exhaust the source iterator completely, in an attempt
                                    + ** to find the first element passing the predicate test. 
                                    + **  
                                    + ** @todo WIP WIP WIP
                                    + ** @todo see Ticket #347
                                    + ** 
                                    + ** @see IterAdapter
                                    + ** @see itertools-test.cpp
                                    + ** @see contents-query.hpp
                                    + */
                                    +
                                    +
                                    +#ifndef LIB_ITERTOOLS_H
                                    +#define LIB_ITERTOOLS_H
                                    +
                                    +
                                    +#include "lib/bool-checkable.hpp"
                                    +#include "lib/iter-adapter.hpp"
                                    +#include "lib/util.hpp"
                                    +
                                    +#include 
                                    +
                                    +
                                    +
                                    +namespace lib {
                                    +  
                                    +  using std::tr1::function;
                                    +  using util::unConst;
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  /** 
                                    +   * A neutral \em identity-function core,
                                    +   * also serving as point-of reference how any
                                    +   * core is intended to work. Any core is intended
                                    +   * to serve as inner part of an iterator tool template.
                                    +   * - it provides the trait typedefs
                                    +   * - it abstracts the "source"
                                    +   * - it abstracts the local operation to be performed
                                    +   * - the ctor of the core sets up the configuration.
                                    +   * @note cores should be copyable without much overhead
                                    +   */
                                    +  template
                                    +  struct IdentityCore
                                    +    {
                                    +      mutable IT source_;
                                    +      
                                    +      IdentityCore (IT const& orig)
                                    +        : source_(orig)
                                    +        { }
                                    +      
                                    +      IT&
                                    +      source ()
                                    +        {
                                    +          return source_;
                                    +        }
                                    +      
                                    +      IT const&
                                    +      source ()  const
                                    +        {
                                    +          return source_;
                                    +        }
                                    +      
                                    +      bool
                                    +      evaluate () const
                                    +        {
                                    +          return bool(source_);
                                    +        }
                                    +      
                                    +      typedef typename IT::pointer pointer;
                                    +      typedef typename IT::reference reference;
                                    +      typedef typename IT::value_type value_type;
                                    +    };
                                    +  
                                    +  
                                    +  /**
                                    +   * Standard functionality to build up any iterator tool.
                                    +   * IterTool exposes the frontend functions necessary to
                                    +   * comply to the Lumiera Forward Iterator concept.
                                    +   * The protected part provides the building blocks
                                    +   * to implement the actual processing/filter logic.
                                    +   */
                                    +  template
                                    +  class IterTool
                                    +    : public lib::BoolCheckable >
                                    +    {
                                    +      
                                    +    protected: /* iteration control */
                                    +      CORE core_;
                                    +      
                                    +      bool
                                    +      hasData()  const
                                    +        {
                                    +          return core_.evaluate()
                                    +              || unConst(this)->iterate();
                                    +        }        // skipping irrelevant results doesn't count as "mutation"
                                    +      
                                    +      bool
                                    +      iterate ()
                                    +        {
                                    +          if (!core_.source()) return false;
                                    +          
                                    +          do ++core_.source();
                                    +          while (core_.source() && !core_.evaluate());
                                    +          return core_.source();
                                    +        }
                                    +      
                                    +      void
                                    +      _maybe_throw()  const
                                    +        {
                                    +          if (!isValid())
                                    +            _throwIterExhausted();
                                    +        }
                                    +      
                                    +      
                                    +      
                                    +    public:
                                    +      typedef typename CORE::pointer pointer;
                                    +      typedef typename CORE::reference reference;
                                    +      typedef typename CORE::value_type value_type;
                                    +      
                                    +      
                                    +      IterTool (CORE const& setup)
                                    +        : core_(setup)
                                    +        {
                                    +          hasData();
                                    +        }
                                    +      
                                    +      
                                    +      
                                    +      /* === lumiera forward iterator concept === */
                                    +      
                                    +      reference
                                    +      operator*() const
                                    +        {
                                    +          _maybe_throw();
                                    +          return *core_.source();
                                    +        }
                                    +      
                                    +      pointer
                                    +      operator->() const
                                    +        {
                                    +          _maybe_throw();
                                    +          return core_.source();
                                    +        }
                                    +      
                                    +      IterTool&
                                    +      operator++()
                                    +        {
                                    +          _maybe_throw();
                                    +          iterate();
                                    +          return *this;
                                    +        }
                                    +      
                                    +      bool
                                    +      isValid ()  const
                                    +        {
                                    +          return hasData();
                                    +        }
                                    +      
                                    +      bool
                                    +      empty ()    const
                                    +        {
                                    +          return !isValid();
                                    +        }
                                    +      
                                    +      
                                    +      /// comparison is allowed to access the source iterator
                                    +      template
                                    +      friend bool operator== (IterTool const& it1, IterTool const& it2);
                                    +    };
                                    +  
                                    +  
                                    +  template
                                    +  inline bool
                                    +  operator== (IterTool const& it1, IterTool const& it2)
                                    +  {
                                    +    return it1.isValid()      == it2.isValid()
                                    +        && it1.core_.source() == it2.core_.source()
                                    +        ;
                                    +  }
                                    +  
                                    +  template
                                    +  inline bool
                                    +  operator!= (IterTool const& ito1, IterTool const& ito2)
                                    +  {
                                    +    return !(ito1 == ito2);
                                    +  }
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  /**
                                    +   * Implementation of the filter logic.
                                    +   * This core stores a function object instance,
                                    +   * passing each pulled source element to this
                                    +   * predicate function for evaluation.
                                    +   */
                                    +  template
                                    +  struct FilterCore
                                    +    : IdentityCore
                                    +    {
                                    +      typedef IdentityCore _Par;
                                    +      typedef typename IT::reference Val;
                                    +      
                                    +      
                                    +      function predicate_;
                                    +      
                                    +      bool
                                    +      evaluate () const
                                    +        {
                                    +          return _Par::source()
                                    +              && predicate_(*_Par::source());
                                    +        }
                                    +      
                                    +      
                                    +      template
                                    +      FilterCore (IT const& orig, PRED prediDef)
                                    +        : _Par(orig)
                                    +        , predicate_(prediDef) // induces a signature check
                                    +        { }
                                    +    };
                                    +  
                                    +  
                                    +  /**
                                    +   * Iterator tool filtering pulled data according to a predicate 
                                    +   */
                                    +  template
                                    +  class FilterIter
                                    +    : public IterTool >
                                    +    {
                                    +      typedef FilterCore _Filter;
                                    +      typedef IterTool<_Filter> _Impl;
                                    +      
                                    +      static bool acceptAll(typename _Filter::Val) { return true; }
                                    +      
                                    +      
                                    +    public:
                                    +      FilterIter ()
                                    +        : _Impl(FilterCore(IT(), acceptAll))
                                    +        { }
                                    +      
                                    +      template
                                    +      FilterIter (IT const& src, PRED filterPredicate)
                                    +        : _Impl(_Filter(src,filterPredicate))
                                    +        { }
                                    +      
                                    +    };
                                    +  
                                    +  
                                    +  /** Build a FilterIter: convenience free function shortcut,
                                    +   *  picking up the involved types automatically.
                                    +   *  @param  filterPredicate to be invoked for each source element
                                    +   *  @return Iterator filtering contents of the source
                                    +   */
                                    +  template
                                    +  inline FilterIter
                                    +  filterIterator (IT const& src, PRED filterPredicate)
                                    +  {
                                    +    return FilterIter(src,filterPredicate);
                                    +  }
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +} // namespace lib
                                    +#endif
                                    diff --git a/tests/40components.tests b/tests/40components.tests
                                    index a88881147..ccaa911c8 100644
                                    --- a/tests/40components.tests
                                    +++ b/tests/40components.tests
                                    @@ -322,10 +322,21 @@ END
                                     
                                     
                                     TEST "Lumiera Iterator Concept" IterAdapter_test 20 < data_;
                                    +        
                                    +        WrappedVector(uint num)
                                    +          {
                                    +            while (num)
                                    +              data_.push_back(num--);
                                    +          }
                                    +        
                                    +        typedef vector::iterator sourceIter;
                                    +        typedef RangeIter iterator;
                                    +        
                                    +        typedef vector::const_iterator const_sourceIter;
                                    +        typedef RangeIter const_iterator;
                                    +        
                                    +        iterator       begin()       { return       iterator(data_.begin(),data_.end()); }
                                    +        iterator       end()         { return       iterator();                          }
                                    +        const_iterator begin() const { return const_iterator(data_.begin(),data_.end()); }
                                    +        const_iterator end()   const { return const_iterator();                          }
                                    +        
                                    +      };
                                    +    
                                    +    
                                         /** 
                                          * Example of a more elaborate custom container exposing an iteration API.
                                          * While the demo implementation here is based on pointers within a vector,
                                    @@ -154,10 +181,12 @@ namespace test{
                                             {
                                               if (0 < arg.size()) NUM_ELMS = lexical_cast (arg[0]);
                                               
                                    -          wrapIterRange ();
                                    +          useSimpleWrappedContainer ();
                                               
                                    +          wrapIterRange ();
                                               TestContainer testElms (NUM_ELMS);
                                               simpleUsage (testElms);
                                    +          
                                               iterTypeVariations (testElms);
                                               verifyComparisons (testElms);
                                             }
                                    @@ -192,17 +221,32 @@ namespace test{
                                           
                                           
                                           /** @test use the IterAdapter as if it was a STL iterator */
                                    +      template
                                           void
                                    -      simpleUsage (TestContainer& elms)
                                    +      simpleUsage (CON& elms)
                                             {
                                    -          for_each (elms, showIt);
                                    +          for_each (elms, showIntP);
                                               cout << endl;
                                             }
                                           
                                    -      static void showIt (int* elm) { cout << "::" << *elm; }
                                    +      static void showIntP (int* elm) { cout << "::" << *elm; }
                                    +      static void showInt  (int  elm) { cout << "::" <<  elm; }
                                           
                                           
                                           
                                    +      void
                                    +      useSimpleWrappedContainer ()
                                    +        {
                                    +          WrappedVector testVec (NUM_ELMS);
                                    +          for_each (testVec, showInt);
                                    +          cout << endl;
                                    +          
                                    +          WrappedVector const& ref (testVec);
                                    +          for_each (ref, showInt);  // uses const_iterator
                                    +          cout << endl;
                                    +        }
                                    +      
                                    +      
                                           /** @test verify the const and dereferencing variants,
                                            *        which can be created based on IterAdapter */
                                           void
                                    diff --git a/tests/lib/itertools-test.cpp b/tests/lib/itertools-test.cpp
                                    new file mode 100644
                                    index 000000000..baa74bc11
                                    --- /dev/null
                                    +++ b/tests/lib/itertools-test.cpp
                                    @@ -0,0 +1,192 @@
                                    +/*
                                    +  IterTools(Test)  -  building combined and filtering iterators based on the Iterator tools
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2009,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +
                                    +#include "lib/test/run.hpp"
                                    +#include "lib/util.hpp"
                                    +
                                    +#include "lib/itertools.hpp"
                                    +
                                    +#include 
                                    +#include 
                                    +#include 
                                    +
                                    +
                                    +
                                    +namespace lib {
                                    +namespace test{
                                    +  
                                    +  using ::Test;
                                    +  using boost::lexical_cast;
                                    +  using util::for_each;
                                    +  using util::isnil;
                                    +  using std::vector;
                                    +  using std::cout;
                                    +  using std::endl;
                                    +  
                                    +  
                                    +  
                                    +  namespace { // Test data
                                    +  
                                    +    uint NUM_ELMS = 10;
                                    +    
                                    +    struct TestSource
                                    +      {
                                    +        vector data_;
                                    +        
                                    +        TestSource(uint num)
                                    +          {
                                    +            while (num)
                                    +              data_.push_back(num--);
                                    +          }
                                    +        
                                    +        typedef vector::iterator sourceIter;
                                    +        typedef RangeIter iterator;
                                    +        
                                    +        iterator begin() { return iterator(data_.begin(),data_.end()); }
                                    +        iterator end()   { return iterator();                          }
                                    +        
                                    +      };
                                    +    
                                    +  } // (END) Test data
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  /*******************************************************************************
                                    +   *  @test build combined and filtering iterators with the help of lib::IterTool.
                                    +   *        Check correct behaviour of the resulting iterator and 
                                    +   *        verify they fulfil the Lumiera Forward Iterator concept
                                    +   *        
                                    +   * @todo implement more iterator tools.... see Ticket #347
                                    +   */
                                    +  class IterTools_test : public Test
                                    +    {
                                    +      
                                    +      typedef TestSource::iterator Iter;
                                    +      
                                    +      
                                    +      virtual void
                                    +      run (Arg arg)
                                    +        {
                                    +          if (0 < arg.size()) NUM_ELMS = lexical_cast (arg[0]);
                                    +          
                                    +          TestSource source(NUM_ELMS);
                                    +          
                                    +          pullOut (source.begin());
                                    +          verifyComparisons (source.begin());
                                    +          
                                    +          
                                    +          buildFilterIterator (source.begin());
                                    +          Iter ii (source.begin());
                                    +          ++++++ii;
                                    +          buildFilterIterator (ii);
                                    +        }
                                    +      
                                    +      
                                    +      
                                    +      template
                                    +      void
                                    +      pullOut (IT const& ii)
                                    +        {
                                    +          for (IT iter(ii) ; iter; ++iter )
                                    +            cout << "::" << *iter;
                                    +          cout << endl;
                                    +        }
                                    +      
                                    +      
                                    +      
                                    +      static bool takeAll (int)   { return true; }
                                    +      static bool takeEve (int i) { return 0 == i % 2; }
                                    +      static bool takeOdd (int i) { return 0 != i % 2; }
                                    +      
                                    +      void
                                    +      buildFilterIterator (Iter const& ii)
                                    +        {
                                    +          pullOut (filterIterator (ii, takeAll));  // note: using the convenient builder function 
                                    +          pullOut (filterIterator (ii, takeEve));
                                    +          pullOut (filterIterator (ii, takeOdd));
                                    +          
                                    +          FilterIter all (ii, takeAll);
                                    +          FilterIter odd (ii, takeOdd);
                                    +          verifyComparisons (all);
                                    +          verifyComparisons (odd);
                                    +          
                                    +          while (++all && ++odd)
                                    +            ASSERT (all != odd);
                                    +          
                                    +          while (++all) { }
                                    +          ASSERT (isnil (odd));
                                    +          ASSERT (all == odd);
                                    +        }
                                    +      
                                    +      
                                    +      
                                    +      /** @test verify equality handling and NIL detection
                                    +       *        for the given iterator/wrapper handed in */
                                    +      template
                                    +      void
                                    +      verifyComparisons (IT const& ii)
                                    +        {
                                    +          IT i1(ii);
                                    +          IT i2(ii);
                                    +          IT iN;
                                    +          ASSERT ( isnil (iN));
                                    +          ASSERT (!isnil (i1));
                                    +          ASSERT (!isnil (i2));
                                    +          
                                    +          ASSERT (i1 == i2); ASSERT (i2 == i1);
                                    +          ASSERT (i1 != iN); ASSERT (iN != i1); 
                                    +          ASSERT (i2 != iN); ASSERT (iN != i2);
                                    +          
                                    +          ++i1;
                                    +          ASSERT (i1 != i2);
                                    +          ASSERT (i1 != iN);
                                    +          
                                    +          ++i2;
                                    +          ASSERT (i1 == i2);
                                    +          ASSERT (i1 != iN); 
                                    +          ASSERT (i2 != iN);
                                    +          
                                    +          while (++i1) { }
                                    +          ASSERT (isnil(i1));
                                    +          ASSERT (i1 != i2);
                                    +          ASSERT (i1 == iN);
                                    +          
                                    +          while (++i2) { }
                                    +          ASSERT (isnil(i2));
                                    +          ASSERT (i2 == i1);
                                    +          ASSERT (i2 == iN);
                                    +        }
                                    +      
                                    +      
                                    +    };
                                    +  
                                    +  LAUNCHER (IterTools_test, "unit common");
                                    +  
                                    +  
                                    +}} // namespace lib::test
                                    +
                                    
                                    From 8c7727704c27facbcb95eb6f5de302df48f44070 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Mon, 2 Nov 2009 07:37:15 +0100
                                    Subject: [PATCH 048/377] Finish ContentQuery definition; relying on
                                     PlacementIndex
                                    
                                    ---
                                     src/lib/iter-adapter.hpp                      |  2 +-
                                     src/proc/mobject/session/contents-query.hpp   | 84 ++++++++++++++++---
                                     .../mobject/session/contents-query-test.cpp   | 23 +++--
                                     3 files changed, 82 insertions(+), 27 deletions(-)
                                    
                                    diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp
                                    index b62bb96c7..4d386f86e 100644
                                    --- a/src/lib/iter-adapter.hpp
                                    +++ b/src/lib/iter-adapter.hpp
                                    @@ -175,7 +175,7 @@ namespace lib {
                                             }
                                           
                                           IterAdapter ()
                                    -        : source_(0)
                                    +        : source_()
                                             , pos_()
                                             { }
                                           
                                    diff --git a/src/proc/mobject/session/contents-query.hpp b/src/proc/mobject/session/contents-query.hpp
                                    index 9a2e709a2..07373b79c 100644
                                    --- a/src/proc/mobject/session/contents-query.hpp
                                    +++ b/src/proc/mobject/session/contents-query.hpp
                                    @@ -24,28 +24,51 @@
                                     #ifndef MOBJECT_SESSION_CONTENTS_QUERY_H
                                     #define MOBJECT_SESSION_CONTENTS_QUERY_H
                                     
                                    -//#include "proc/mobject/mobject.hpp"
                                    +
                                     #include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/session/query-resolver.hpp"
                                    -//#include "lib/iter-adapter.hpp"
                                     
                                    -//#include 
                                    -//#include 
                                    +#include 
                                     
                                    -//using std::vector;
                                    -//using std::string;
                                     
                                     namespace mobject {
                                     namespace session {
                                       
                                    +  using std::tr1::bind;
                                    +  using std::tr1::function;
                                    +  using std::tr1::placeholders::_1;
                                    +  
                                       
                                       
                                       /**
                                    -   * TODO type comment
                                    +   * Query a scope to discover it's contents.
                                    +   * This is a special kind of query, wired up such as to
                                    +   * enumerate the contents of a scope, filtered by a subtype-check.
                                    +   * For the actual resolution of the scope's contents, this query
                                    +   * relies on an index like facility (usually Session's PlacementIndex),
                                    +   * which is abstracted as a QueryResolver, but actually is expected to
                                    +   * cooperate especially with this Query subclass to retrieve the scope
                                    +   * to be enumerated and the definition of the actual filter predicate.
                                    +   * Currently (11/09), there is a special, hard-wired Query-kind-ID
                                    +   * \c Goal::DISCOVERY to distinguish this special kind of a Query.
                                    +   * 
                                    +   * Contrary to the usual handling of a generic query, a ContentsQuery
                                    +   * object holds it's own discovery iterator and thus is completely
                                    +   * self contained. The query is issued automatically on construction,
                                    +   * thus the embedded iterator immediately points at the first result.
                                    +   * Moreover, as any Lumiera Forward Iterator is \c bool checkable,
                                    +   * a ContentsQuery not yielding any results will evaluate to \c false
                                    +   * immediately after construction, allowing convenient inline checks.
                                    +   * The query can be re-issued by the function operator, and the
                                    +   * embedded result iterator can of course be copied to a bare
                                    +   * iterator instance, e.g. for passing it on (ContentsQuery
                                    +   * itself is intended to be used polymorphically and thus
                                    +   * defined to be non-copyable)
                                        */
                                       template
                                       class ContentsQuery
                                         : public Query >
                                    +    , public Query >::iterator
                                         {
                                           typedef Query > _Query;
                                           
                                    @@ -53,14 +76,26 @@ namespace session {
                                           PlacementMO const& container_;
                                           
                                           
                                    +      typedef typename _Query::iterator _QIter;
                                    +      typedef typename _QIter::reference Val;
                                    +      
                                    +      
                                         public:
                                    -      ContentsQuery (QueryResolver const& resolver, PlacementMO const& scope)
                                    +      typedef _QIter              iterator;
                                    +      typedef function ContentFilter;
                                    +      
                                    +      
                                    +      ContentsQuery (QueryResolver const& resolver,
                                    +                     PlacementMO  const& scope)
                                             : _Query (_Query::defineQueryTypeID (Goal::DISCOVERY))
                                    +        , _QIter ()
                                             , index_(resolver)
                                             , container_(scope)
                                    -        { }
                                    +        {
                                    +          resetResultIteration (_Query::resolveBy(index_));
                                    +        }
                                    +      
                                           
                                    -      typedef typename _Query::iterator iterator;
                                           
                                           iterator
                                           operator() ()  const
                                    @@ -69,15 +104,38 @@ namespace session {
                                             }
                                           
                                           PlacementMO const&
                                    -      searchScope ()
                                    +      searchScope ()  const
                                             {
                                               return container_;
                                             }
                                           
                                    -      /////////////////////TODO maybe exposing a content filter predicate from here?
                                    +      ContentFilter
                                    +      contentFilter () const
                                    +        {
                                    +          return buildContentFilter();
                                    +        }
                                           
                                    +      
                                    +    protected:
                                    +      /** the default implementation of the content filtering
                                    +       *  builds on the downcast-function available on each 
                                    +       *  Placement instance. By parametrising this function
                                    +       *  with our template parameter MO, we pick out only
                                    +       *  those elements of the scope being subclasses of MO
                                    +       */
                                    +      virtual ContentFilter
                                    +      buildContentFilter()  const
                                    +        {
                                    +          return bind (&PlacementMO::isCompatible, _1 );
                                    +        }
                                    +      
                                    +    private:
                                    +      void
                                    +      resetResultIteration (iterator const& newQueryResults)
                                    +        {
                                    +          static_cast (*this) = newQueryResults;
                                    +        }
                                         };
                                    -///////////////////////////TODO currently just fleshing the API
                                       
                                       
                                     }} // namespace mobject::session
                                    diff --git a/tests/components/proc/mobject/session/contents-query-test.cpp b/tests/components/proc/mobject/session/contents-query-test.cpp
                                    index 16125e7bd..3b200d07c 100644
                                    --- a/tests/components/proc/mobject/session/contents-query-test.cpp
                                    +++ b/tests/components/proc/mobject/session/contents-query-test.cpp
                                    @@ -22,12 +22,9 @@
                                     
                                     
                                     #include "lib/test/run.hpp"
                                    -//#include "lib/lumitime.hpp"
                                    -//#include "proc/mobject/placement-ref.hpp"
                                     #include "proc/mobject/session/query-resolver.hpp"
                                     #include "proc/mobject/session/contents-query.hpp"
                                     #include "proc/mobject/session/test-scopes.hpp"
                                    -//#include "proc/mobject/placement-resolver.hpp"
                                     //#include "lib/util.hpp"
                                     
                                     #include 
                                    @@ -38,21 +35,20 @@
                                     namespace mobject {
                                     namespace session {
                                     namespace test    {
                                    -
                                    +  
                                       using session::ContentsQuery;
                                    -  using session::Query;
                                    -  //using util::isSameObject;
                                    -  //using lumiera::Time;
                                       using std::string;
                                       using std::cout;
                                       using std::endl;
                                    -
                                    +  
                                       
                                       /***************************************************************************************
                                        * @test how to discover the contents of a container-like part of the high-level model.
                                        *       As this container-like object is just a concept and actually implemented
                                        *       by the PlacementIndex, this includes enumerating a scope. The discovered
                                    -   *       contents may be additionally filtered by a runtime type check.
                                    +   *       contents will be filtered by a runtime type check.
                                    +   *       
                                    +   * @todo cover using an additional dynamic filter on the results
                                        *       
                                        * @see  mobject::PlacementIndex
                                        * @see  mobject::session::QueryResolver
                                    @@ -82,12 +78,13 @@ namespace test    {
                                           void
                                           discover (ContentsQuery const& query)
                                             {
                                    -          for (typename ContentsQuery::iterator elm = query();
                                    -               elm;
                                    -             ++elm)
                                    +          typedef typename ContentsQuery::iterator I;
                                    +          
                                    +          for (I elm(query);
                                    +               elm; ++elm)
                                                 cout << string(*elm) << endl;
                                             }
                                    -          
                                    +      
                                         };
                                       
                                       
                                    
                                    From ce4e3608d0a77b298c7332d2e6310e8d55c7c612 Mon Sep 17 00:00:00 2001
                                    From: Michael Ploujnikov 
                                    Date: Mon, 2 Nov 2009 13:51:18 -0500
                                    Subject: [PATCH 049/377] make sure luidgen picks up the nobug cflags
                                    
                                    ---
                                     src/tool/Makefile.am | 2 +-
                                     1 file changed, 1 insertion(+), 1 deletion(-)
                                    
                                    diff --git a/src/tool/Makefile.am b/src/tool/Makefile.am
                                    index 2bf1acf99..bacd925d8 100644
                                    --- a/src/tool/Makefile.am
                                    +++ b/src/tool/Makefile.am
                                    @@ -18,7 +18,7 @@
                                     lumitool_srcdir = $(top_srcdir)/src/tool
                                     
                                     noinst_PROGRAMS += luidgen
                                    -luidgen_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror
                                    +luidgen_CFLAGS = $(CFLAGS) $(NOBUGMT_LUMIERA_CFLAGS) -std=gnu99 -Wall -Werror
                                     luidgen_CPPFLAGS = -I$(top_srcdir)/src/
                                     luidgen_LDADD = liblumiera.la  $(NOBUGMT_LUMIERA_LIBS)    -lboost_regex-mt -lboost_program_options-mt
                                     luidgen_SOURCES = $(lumitool_srcdir)/luidgen.c
                                    
                                    From e0e9b7c2c0442ec7c5daa146bc969b9fdd2662ad Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Wed, 4 Nov 2009 04:56:25 +0100
                                    Subject: [PATCH 050/377] WIP about how to link the QueryFocus system to the
                                     session/PlacementIndex
                                    
                                    ---
                                     src/proc/mobject/session/query-focus.hpp    |   2 +
                                     src/proc/mobject/session/query-resolver.hpp |   5 +-
                                     src/proc/mobject/session/scope-locator.hpp  | 103 ++++++++++++++++++++
                                     src/proc/mobject/session/scope.hpp          |  18 +---
                                     wiki/renderengine.html                      |   4 +-
                                     5 files changed, 115 insertions(+), 17 deletions(-)
                                     create mode 100644 src/proc/mobject/session/scope-locator.hpp
                                    
                                    diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp
                                    index fa8d6343e..522d6e896 100644
                                    --- a/src/proc/mobject/session/query-focus.hpp
                                    +++ b/src/proc/mobject/session/query-focus.hpp
                                    @@ -69,6 +69,8 @@ namespace session {
                                       QueryFocus::query()  const
                                       {
                                         UNIMPLEMENTED ("how the hell do we issue typed queries?????");  ///////////////////////TICKET #352
                                    +    
                                    +    ////////////yeah! we know now ---> ScopeLocator::explore(..)
                                       }
                                       
                                       
                                    diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp
                                    index e389b5c27..4a77648ae 100644
                                    --- a/src/proc/mobject/session/query-resolver.hpp
                                    +++ b/src/proc/mobject/session/query-resolver.hpp
                                    @@ -36,7 +36,7 @@
                                     #include 
                                     #include 
                                     //#include 
                                    -//#include 
                                    +#include 
                                     
                                     //using std::vector;
                                     //using std::string;
                                    @@ -48,6 +48,7 @@ namespace session {
                                       using boost::noncopyable;
                                       using boost::scoped_ptr;
                                       using std::tr1::function;
                                    +  using std::string;
                                       
                                       
                                       class Goal;
                                    @@ -245,6 +246,8 @@ namespace session {
                                         public:
                                           virtual ~QueryResolver() ;
                                           
                                    +      operator string ()     =0; ///< short characterisation of the actual facility
                                    +      
                                           
                                           /** issue a query to retrieve contents
                                            *  The query is handed over internally to a suitable resolver implementation.
                                    diff --git a/src/proc/mobject/session/scope-locator.hpp b/src/proc/mobject/session/scope-locator.hpp
                                    new file mode 100644
                                    index 000000000..f91f64510
                                    --- /dev/null
                                    +++ b/src/proc/mobject/session/scope-locator.hpp
                                    @@ -0,0 +1,103 @@
                                    +/*
                                    +  SCOPE-LOCATOR.hpp  -  management and registration point for the QueryFocus-system
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2009,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +*/
                                    +
                                    +
                                    +#ifndef MOBJECT_SESSION_SCOPE_LOCATOR_H
                                    +#define MOBJECT_SESSION_SCOPE_LOCATOR_H
                                    +
                                    +//#include "proc/mobject/mobject.hpp"
                                    +#include "proc/mobject/session/scope.hpp"
                                    +#include "proc/mobject/placement.hpp"
                                    +#include "proc/mobject/session/contents-query.hpp"
                                    +#include "lib/singleton.hpp"
                                    +#include "lib/util.hpp"
                                    +
                                    +#include 
                                    +#include 
                                    +//#include 
                                    +//#include 
                                    +
                                    +//using std::vector;
                                    +//using std::string;
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +  
                                    +  using std::tr1::shared_ptr;
                                    +  using boost::scoped_ptr;
                                    +  using util::cStr;
                                    +  
                                    +  
                                    +  class QueryFocusStack; //////TODO better include?
                                    +  
                                    +
                                    +  
                                    +  class ScopeLocator
                                    +    {
                                    +     scoped_ptr focusStack_;
                                    +     shared_ptr index_;
                                    +      
                                    +    public:
                                    +      ScopeLocator();
                                    +      
                                    +      void
                                    +      activate (shared_ptr resolvingFacility);
                                    +      
                                    +      template
                                    +      typename ContentsQuery::iterator
                                    +      explore (Scope const&);
                                    +      
                                    +    };
                                    +///////////////////////////TODO currently just fleshing the API
                                    +  
                                    +  
                                    +  
                                    +  /** activate or de-activate the QueryFocus system.
                                    +   *  This is done by a link to a contents-query resolving facility,
                                    +   *  typically the PlacementIndex within the current session.  
                                    +   */
                                    +  void
                                    +  ScopeLocator::activate (shared_ptr resolvingFacility)
                                    +  {
                                    +    index_ = resolvingFacility;
                                    +    
                                    +    if (index_)
                                    +      INFO (config, "Enabling Scope resolution by %s.", cStr(*index_));
                                    +    else
                                    +      INFO (config, "Disabling Scope resolution.");
                                    +  }
                                    +  
                                    +  
                                    +  /** use the currently installed contents-resolving facility
                                    +   *  to enumerate the contents of the given scope
                                    +   */
                                    +  template
                                    +  typename ContentsQuery::iterator
                                    +  ScopeLocator::explore (Scope const& scope)
                                    +  {
                                    +    REQUIRE (index_);
                                    +    return ContentsQuery (*index_, scope.getTop());
                                    +  }
                                    +  
                                    +  
                                    +}} // namespace mobject::session
                                    +#endif
                                    diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp
                                    index 88d6300d2..e12eae402 100644
                                    --- a/src/proc/mobject/session/scope.hpp
                                    +++ b/src/proc/mobject/session/scope.hpp
                                    @@ -1,6 +1,5 @@
                                     /*
                                       SCOPE.hpp  -  nested search scope for properties of placement
                                    -
                                      
                                       Copyright (C)         Lumiera.org
                                         2009,               Hermann Vosseler 
                                    @@ -28,10 +27,12 @@
                                     //#include "proc/mobject/mobject.hpp"
                                     #include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/placement-ref.hpp"
                                    +//#include "proc/mobject/session/query-resolver.hpp"  ///////////TODO: really?
                                     #include "lib/iter-adapter.hpp"
                                    -#include "lib/singleton.hpp"
                                    +//#include "lib/singleton.hpp"
                                     
                                    -#include 
                                    +//#include 
                                    +//#include 
                                     //#include 
                                     //#include 
                                     
                                    @@ -41,11 +42,8 @@
                                     namespace mobject {
                                     namespace session {
                                       
                                    -  using boost::scoped_ptr;
                                       using lib::IterAdapter;
                                       
                                    -  class ScopeLocator;
                                    -  class QueryFocusStack;
                                       
                                     
                                       /**
                                    @@ -80,14 +78,6 @@ namespace session {
                                         };
                                       
                                       
                                    -  class ScopeLocator
                                    -    {
                                    -     scoped_ptr focusStack_; 
                                    -      
                                    -    public:
                                    -      ScopeLocator();
                                    -      
                                    -    };
                                     ///////////////////////////TODO currently just fleshing the API
                                       
                                       
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index f17e1f552..5db23fab1 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3464,7 +3464,7 @@ For decoupling the query invocation from the facility actually processing the qu
                                     See also the notes on &rarr; QueryImplProlog
                                     
                                    -
                                    +
                                    When querying contents of the session or sub-containers within the session, the QueryFocus follows the current point-of-query. As such queries can be issued to explore the content of container-like objects holding other MObjects, the focus is always attached to a container, which also acts as [[scope|PlacementScope]] for the contained objects. QueryFocus is an implicit state (the current point of interrest). This sate especially remembers the path down from the root of the HighLevelModel, which was used to access the current scope. Because this path constitutes a hierarchy of scopes, it can be relevant for querying and resolving placement properties. (&rarr; SessionStructureQuery)
                                     
                                     !provided operations
                                    @@ -3479,7 +3479,7 @@ See also the notes on &rarr; QueryImplProlog
                                     There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current scope.// But QueryFocus is more of a //binding// &mdash; it links or focusses the current state and into a specific scope with a ScopePath depending on the current state. Thus, while Scope is just a passive container allowing to locate and navigate, QueryFocus by virtue of this binding allows to [[Query]] at this current location.
                                     
                                     !implementation notes
                                    -we provide a static access API, meaning that there is a singleton behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. This link works by the current session grabbing the query focus and attaching to it. This attachment is shallow, i.e. the QueryFocus doesn't have knowledge about the session, which allows the focus to be unit tested.
                                    +we provide a static access API, meaning that there is a singleton behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. This link works by the current session contacting the query focus system (~ScopeLocator) and attaching to it. This attachment is shallow, i.e. the QueryFocus doesn't have knowledge about the session, which allows the focus to be unit tested.
                                     
                                     The stack of scopes must not be confused with the ScopePath. Each single frame on the stack is a QueryFocus and as such contains a current ScopePath. The purpose of the stack is to make the scope handling mostly transparent; especially this stack allows to write dedicated query functions directed at a given object: they work by pushing and then navigating to the object to use as new starting point. Not every placement is a scope, but every placement has an immediately enclosing scope, which is used as //current scope.//
                                     
                                    
                                    From bb8c018214a71926cfe9f3a25af3b61aa3aa2f0f Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 6 Nov 2009 18:42:15 +0100
                                    Subject: [PATCH 051/377] integrate QueryFocus with the new ContentsQuery
                                     facility
                                    
                                    ---
                                     src/proc/mobject/placement-index.hpp           |  4 ++++
                                     src/proc/mobject/session/query-focus.hpp       | 15 ++++++---------
                                     src/proc/mobject/session/query-resolver.hpp    |  2 +-
                                     src/proc/mobject/session/scope-locator.hpp     | 18 +++++++++++-------
                                     src/proc/mobject/session/scope.cpp             |  4 ++++
                                     .../mobject/session/query-resolver-test.cpp    |  2 ++
                                     wiki/renderengine.html                         |  4 ++--
                                     7 files changed, 30 insertions(+), 19 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/placement-index.hpp b/src/proc/mobject/placement-index.hpp
                                    index 4fb15d428..1bc193cbe 100644
                                    --- a/src/proc/mobject/placement-index.hpp
                                    +++ b/src/proc/mobject/placement-index.hpp
                                    @@ -96,10 +96,14 @@ namespace mobject { ///////////////////////////////////////////TODO: shouldn't t
                                           bool contains (PlacementMO const&)          const;
                                           bool contains (ID)                          const;
                                           
                                    +////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper      
                                           template
                                           typename session::Query >::iterator
                                           query (PlacementMO& scope)                  const;
                                           
                                    +      operator string()  const { return "PlacementIndex"; }
                                    +////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper      
                                    +      
                                           
                                           bool canHandleQuery(QID)                    const;
                                           
                                    diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp
                                    index 522d6e896..0507eb31b 100644
                                    --- a/src/proc/mobject/session/query-focus.hpp
                                    +++ b/src/proc/mobject/session/query-focus.hpp
                                    @@ -27,6 +27,7 @@
                                     //#include "proc/mobject/mobject.hpp"
                                     //#include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/session/scope-path.hpp"
                                    +#include "proc/mobject/session/scope-locator.hpp"
                                     
                                     //#include 
                                     //#include 
                                    @@ -59,19 +60,15 @@ namespace session {
                                           ScopePath currentPath() const { return scopes_; }
                                           
                                           template
                                    -      void query()  const; ////////////////////////////////////////////////////////////////TODO obviously needs to return an Iterator
                                    +      typename ContentsQuery::iterator
                                    +      query()  const
                                    +        {
                                    +          ScopeLocator::instance().explore (*this);
                                    +        }
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                     
                                       
                                    -  template
                                    -  void
                                    -  QueryFocus::query()  const
                                    -  {
                                    -    UNIMPLEMENTED ("how the hell do we issue typed queries?????");  ///////////////////////TICKET #352
                                    -    
                                    -    ////////////yeah! we know now ---> ScopeLocator::explore(..)
                                    -  }
                                       
                                       
                                     }} // namespace mobject::session
                                    diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp
                                    index 4a77648ae..07808a3bf 100644
                                    --- a/src/proc/mobject/session/query-resolver.hpp
                                    +++ b/src/proc/mobject/session/query-resolver.hpp
                                    @@ -246,7 +246,7 @@ namespace session {
                                         public:
                                           virtual ~QueryResolver() ;
                                           
                                    -      operator string ()     =0; ///< short characterisation of the actual facility
                                    +      virtual operator string ()  const    =0; ///< short characterisation of the actual facility
                                           
                                           
                                           /** issue a query to retrieve contents
                                    diff --git a/src/proc/mobject/session/scope-locator.hpp b/src/proc/mobject/session/scope-locator.hpp
                                    index f91f64510..d75bdf980 100644
                                    --- a/src/proc/mobject/session/scope-locator.hpp
                                    +++ b/src/proc/mobject/session/scope-locator.hpp
                                    @@ -53,19 +53,23 @@ namespace session {
                                       
                                       class ScopeLocator
                                         {
                                    -     scoped_ptr focusStack_;
                                    -     shared_ptr index_;
                                    +      scoped_ptr focusStack_;
                                    +      shared_ptr index_;
                                           
                                         public:
                                    -      ScopeLocator();
                                    +      static lib::Singleton instance;
                                           
                                           void
                                           activate (shared_ptr resolvingFacility);
                                           
                                           template
                                           typename ContentsQuery::iterator
                                    -      explore (Scope const&);
                                    +      explore (Scope);
                                           
                                    +    protected:
                                    +      ScopeLocator();
                                    +      
                                    +      friend class lib::singleton::StaticCreate;
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                       
                                    @@ -75,7 +79,7 @@ namespace session {
                                        *  This is done by a link to a contents-query resolving facility,
                                        *  typically the PlacementIndex within the current session.  
                                        */
                                    -  void
                                    +  inline void
                                       ScopeLocator::activate (shared_ptr resolvingFacility)
                                       {
                                         index_ = resolvingFacility;
                                    @@ -91,8 +95,8 @@ namespace session {
                                        *  to enumerate the contents of the given scope
                                        */
                                       template
                                    -  typename ContentsQuery::iterator
                                    -  ScopeLocator::explore (Scope const& scope)
                                    +  inline typename ContentsQuery::iterator
                                    +  ScopeLocator::explore (Scope scope)
                                       {
                                         REQUIRE (index_);
                                         return ContentsQuery (*index_, scope.getTop());
                                    diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp
                                    index b73096d36..04a99ea24 100644
                                    --- a/src/proc/mobject/session/scope.cpp
                                    +++ b/src/proc/mobject/session/scope.cpp
                                    @@ -22,6 +22,7 @@
                                     
                                     
                                     #include "proc/mobject/session/scope.hpp"
                                    +#include "proc/mobject/session/scope-locator.hpp"
                                     #include "proc/mobject/session/query-focus-stack.hpp"
                                     #include "proc/mobject/mobject.hpp"
                                     //#include "proc/mobject/session/track.hpp"
                                    @@ -69,6 +70,9 @@ namespace session {
                                         
                                       }
                                       
                                    +  /** Storage holding the single ScopeLocator instance */
                                    +  lib::Singleton ScopeLocator::instance;
                                    +  
                                       
                                       
                                       /** discover the enclosing scope of a given Placement */
                                    diff --git a/tests/components/proc/mobject/session/query-resolver-test.cpp b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    index 7aeeab60e..d3a785b0f 100644
                                    --- a/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    +++ b/tests/components/proc/mobject/session/query-resolver-test.cpp
                                    @@ -152,6 +152,8 @@ namespace test    {
                                                 return new DummyResultSet(); 
                                               }
                                             
                                    +        operator string()  const { return "Test-DummyQueryResolver"; }
                                    +        
                                           public:
                                             DummyTypedSolutionProducer()
                                               : QueryResolver()
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 5db23fab1..251817e61 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3464,7 +3464,7 @@ For decoupling the query invocation from the facility actually processing the qu
                                     See also the notes on &rarr; QueryImplProlog
                                     
                                    -
                                    +
                                    When querying contents of the session or sub-containers within the session, the QueryFocus follows the current point-of-query. As such queries can be issued to explore the content of container-like objects holding other MObjects, the focus is always attached to a container, which also acts as [[scope|PlacementScope]] for the contained objects. QueryFocus is an implicit state (the current point of interrest). This sate especially remembers the path down from the root of the HighLevelModel, which was used to access the current scope. Because this path constitutes a hierarchy of scopes, it can be relevant for querying and resolving placement properties. (&rarr; SessionStructureQuery)
                                     
                                     !provided operations
                                    @@ -3476,7 +3476,7 @@ See also the notes on &rarr; QueryImplProlog
                                     * (typed) content discovery query on the current scope
                                     [>img[Scope Locating|uml/fig136325.png]]
                                     !!!relation to Scope
                                    -There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current scope.// But QueryFocus is more of a //binding// &mdash; it links or focusses the current state and into a specific scope with a ScopePath depending on the current state. Thus, while Scope is just a passive container allowing to locate and navigate, QueryFocus by virtue of this binding allows to [[Query]] at this current location.
                                    +There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current scope.// But QueryFocus is more of a //binding// &mdash; it links or focusses the current state into a specific scope with a ScopePath in turn depending on this current state. Thus, while Scope is just a passive container allowing to locate and navigate, QueryFocus by virtue of this binding allows to [[Query]] at this current location.
                                     
                                     !implementation notes
                                     we provide a static access API, meaning that there is a singleton behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. This link works by the current session contacting the query focus system (~ScopeLocator) and attaching to it. This attachment is shallow, i.e. the QueryFocus doesn't have knowledge about the session, which allows the focus to be unit tested.
                                    
                                    From bdb8bc2c982dee6334cdeb28d2e7f4a83b1a24e8 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 6 Nov 2009 19:27:53 +0100
                                    Subject: [PATCH 052/377] move PlacementIndex into namespace session
                                    
                                    ---
                                     src/proc/mobject/placement-ref.hpp              | 17 +++++++++--------
                                     .../mobject/{ => session}/placement-index.cpp   |  5 +++--
                                     .../mobject/{ => session}/placement-index.hpp   |  9 ++++++---
                                     src/proc/mobject/session/session-impl.hpp       |  2 +-
                                     .../handling-pattern-standard-impl-test.cpp     |  2 +-
                                     .../proc/mobject/mobject-ref-test.cpp           |  4 +++-
                                     .../proc/mobject/placement-ref-test.cpp         |  2 +-
                                     .../proc/mobject/placement-scope-test.cpp       |  2 +-
                                     .../proc/mobject/query-focus-test.cpp           |  2 +-
                                     .../components/proc/mobject/scope-path-test.cpp |  2 +-
                                     .../{ => session}/placement-index-test.cpp      |  5 +++--
                                     .../proc/mobject/session/test-scopes.hpp        |  2 +-
                                     12 files changed, 31 insertions(+), 23 deletions(-)
                                     rename src/proc/mobject/{ => session}/placement-index.cpp (97%)
                                     rename src/proc/mobject/{ => session}/placement-index.hpp (97%)
                                     rename tests/components/proc/mobject/{ => session}/placement-index-test.cpp (96%)
                                    
                                    diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp
                                    index 5677aeac4..73af653e8 100644
                                    --- a/src/proc/mobject/placement-ref.hpp
                                    +++ b/src/proc/mobject/placement-ref.hpp
                                    @@ -60,12 +60,13 @@ namespace mobject {
                                       
                                       class MObject;
                                       
                                    -  // see placement-index.cpp 
                                    -  Placement &
                                    -  fetch_PlacementIndex(Placement::ID const&) ;
                                    -  
                                    -  bool
                                    -  checkContains_PlacementIndex (Placement::ID const& pID) ;
                                    +  namespace session {
                                    +    
                                    +    // see placement-index.cpp 
                                    +    Placement & fetch_PlacementIndex(Placement::ID const&) ;
                                    +    bool checkContains_PlacementIndex (Placement::ID const& pID) ;
                                    +    
                                    +  }
                                       
                                       
                                       LUMIERA_ERROR_DECLARE (INVALID_PLACEMENTREF);  ///< unresolvable placement reference, or of incompatible type
                                    @@ -205,7 +206,7 @@ namespace mobject {
                                           bool
                                           checkValidity ()  const
                                             {
                                    -          return checkContains_PlacementIndex(this->id_);
                                    +          return session::checkContains_PlacementIndex(this->id_);
                                             }
                                           
                                           static void
                                    @@ -235,7 +236,7 @@ namespace mobject {
                                           static PlacementMO&
                                           access (_Id const& placementID)
                                             {
                                    -          Placement & pla (fetch_PlacementIndex (placementID));  // may throw
                                    +          Placement & pla (session::fetch_PlacementIndex (placementID));  // may throw
                                               REQUIRE (pla.isValid());
                                               ASSERT (pla.isCompatible());
                                               return static_cast (pla);
                                    diff --git a/src/proc/mobject/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp
                                    similarity index 97%
                                    rename from src/proc/mobject/placement-index.cpp
                                    rename to src/proc/mobject/session/placement-index.cpp
                                    index 6b01eeeaa..069de7012 100644
                                    --- a/src/proc/mobject/placement-index.cpp
                                    +++ b/src/proc/mobject/session/placement-index.cpp
                                    @@ -33,13 +33,14 @@
                                      */
                                     
                                     
                                    -#include "proc/mobject/placement-index.hpp"
                                    +#include "proc/mobject/session/placement-index.hpp"
                                     #include "proc/mobject/session/session-impl.hpp"
                                     
                                     //#include 
                                     //using boost::str;
                                     
                                     namespace mobject {
                                    +namespace session {
                                     
                                     
                                       class PlacementIndex::Table 
                                    @@ -204,4 +205,4 @@ namespace mobject {
                                       }
                                     
                                     
                                    -} // namespace mobject
                                    +}} // namespace mobject::session
                                    diff --git a/src/proc/mobject/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp
                                    similarity index 97%
                                    rename from src/proc/mobject/placement-index.hpp
                                    rename to src/proc/mobject/session/placement-index.hpp
                                    index 1bc193cbe..4ad794227 100644
                                    --- a/src/proc/mobject/placement-index.hpp
                                    +++ b/src/proc/mobject/session/placement-index.hpp
                                    @@ -48,14 +48,17 @@
                                     #include 
                                     
                                     
                                    -namespace mobject { ///////////////////////////////////////////TODO: shouldn't this go into namespace session ?
                                    +namespace mobject {
                                    +
                                    +  class MObject;
                                    +  
                                    +namespace session {
                                       
                                       using lib::factory::RefcountFac;
                                       using std::tr1::shared_ptr;
                                       using boost::scoped_ptr;
                                       using std::vector;
                                       
                                    -  class MObject;
                                       
                                       
                                       /**
                                    @@ -205,5 +208,5 @@ namespace mobject { ///////////////////////////////////////////TODO: shouldn't t
                                       
                                       
                                       
                                    -} // namespace mobject
                                    +}} // namespace mobject::session
                                     #endif
                                    diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp
                                    index 0ddc63381..4e4d90731 100644
                                    --- a/src/proc/mobject/session/session-impl.hpp
                                    +++ b/src/proc/mobject/session/session-impl.hpp
                                    @@ -39,7 +39,7 @@
                                     #include "proc/mobject/session.hpp"
                                     #include "proc/mobject/session/edl.hpp"
                                     #include "proc/mobject/session/fixture.hpp"
                                    -#include "proc/mobject/placement-index.hpp"
                                    +#include "proc/mobject/session/placement-index.hpp"
                                     
                                     #include 
                                     #include 
                                    diff --git a/tests/components/proc/control/handling-pattern-standard-impl-test.cpp b/tests/components/proc/control/handling-pattern-standard-impl-test.cpp
                                    index f9fdf0058..a83eed6d7 100644
                                    --- a/tests/components/proc/control/handling-pattern-standard-impl-test.cpp
                                    +++ b/tests/components/proc/control/handling-pattern-standard-impl-test.cpp
                                    @@ -30,7 +30,7 @@
                                     //#include "proc/mobject/test-dummy-mobject.hpp"
                                     //#include "lib/p.hpp"
                                     //#include "proc/mobject/placement.hpp"
                                    -//#include "proc/mobject/placement-index.hpp"
                                    +//#include "proc/mobject/session/placement-index.hpp"
                                     //#include "proc/mobject/explicitplacement.hpp"
                                     #include "proc/control/command.hpp"
                                     #include "proc/control/command-impl.hpp"
                                    diff --git a/tests/components/proc/mobject/mobject-ref-test.cpp b/tests/components/proc/mobject/mobject-ref-test.cpp
                                    index f851b4b06..b679df1d8 100644
                                    --- a/tests/components/proc/mobject/mobject-ref-test.cpp
                                    +++ b/tests/components/proc/mobject/mobject-ref-test.cpp
                                    @@ -28,7 +28,7 @@
                                     #include "proc/mobject/mobject-ref.hpp"
                                     #include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/placement-ref.hpp"
                                    -#include "proc/mobject/placement-index.hpp"
                                    +#include "proc/mobject/session/placement-index.hpp"
                                     #include "proc/mobject/session/clip.hpp"
                                     #include "proc/mobject/explicitplacement.hpp"
                                     #include "proc/mobject/test-dummy-mobject.hpp"
                                    @@ -46,6 +46,8 @@ namespace test    {
                                       
                                       using lumiera::Time;
                                       using session::Clip;
                                    +  
                                    +  using session::reset_PlacementIndex;
                                     
                                       
                                       /***************************************************************************
                                    diff --git a/tests/components/proc/mobject/placement-ref-test.cpp b/tests/components/proc/mobject/placement-ref-test.cpp
                                    index 9bbe17109..de2f7e5bb 100644
                                    --- a/tests/components/proc/mobject/placement-ref-test.cpp
                                    +++ b/tests/components/proc/mobject/placement-ref-test.cpp
                                    @@ -25,7 +25,7 @@
                                     #include "lib/lumitime.hpp"
                                     #include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/placement-ref.hpp"
                                    -#include "proc/mobject/placement-index.hpp"
                                    +#include "proc/mobject/session/placement-index.hpp"
                                     #include "proc/mobject/explicitplacement.hpp"
                                     #include "proc/mobject/test-dummy-mobject.hpp"
                                     #include "lib/util.hpp"
                                    diff --git a/tests/components/proc/mobject/placement-scope-test.cpp b/tests/components/proc/mobject/placement-scope-test.cpp
                                    index 87ba1a1bf..72f0c5aff 100644
                                    --- a/tests/components/proc/mobject/placement-scope-test.cpp
                                    +++ b/tests/components/proc/mobject/placement-scope-test.cpp
                                    @@ -27,7 +27,7 @@
                                     #include "proc/mobject/session/test-scopes.hpp"
                                     //#include "lib/lumitime.hpp"
                                     //#include "proc/mobject/placement-ref.hpp"
                                    -//#include "proc/mobject/placement-index.hpp"
                                    +//#include "proc/mobject/session/placement-index.hpp"
                                     //#include "proc/mobject/test-dummy-mobject.hpp"
                                     #include "lib/util.hpp"
                                     
                                    diff --git a/tests/components/proc/mobject/query-focus-test.cpp b/tests/components/proc/mobject/query-focus-test.cpp
                                    index 589dec521..e74b8e218 100644
                                    --- a/tests/components/proc/mobject/query-focus-test.cpp
                                    +++ b/tests/components/proc/mobject/query-focus-test.cpp
                                    @@ -25,7 +25,7 @@
                                     //#include "lib/lumitime.hpp"
                                     //#include "proc/mobject/placement-ref.hpp"
                                     #include "proc/mobject/session/test-scopes.hpp"
                                    -#include "proc/mobject/placement-index.hpp"
                                    +#include "proc/mobject/session/placement-index.hpp"
                                     #include "proc/mobject/session/query-focus.hpp"
                                     #include "proc/mobject/session/scope.hpp"
                                     //#include "lib/util.hpp"
                                    diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp
                                    index 9adcfb03d..5681e61df 100644
                                    --- a/tests/components/proc/mobject/scope-path-test.cpp
                                    +++ b/tests/components/proc/mobject/scope-path-test.cpp
                                    @@ -27,7 +27,7 @@
                                     #include "proc/mobject/session/scope-path.hpp"
                                     //#include "lib/lumitime.hpp"
                                     //#include "proc/mobject/placement-ref.hpp"
                                    -//#include "proc/mobject/placement-index.hpp"
                                    +//#include "proc/mobject/session/placement-index.hpp"
                                     //#include "proc/mobject/test-dummy-mobject.hpp"
                                     #include "lib/util.hpp"
                                     
                                    diff --git a/tests/components/proc/mobject/placement-index-test.cpp b/tests/components/proc/mobject/session/placement-index-test.cpp
                                    similarity index 96%
                                    rename from tests/components/proc/mobject/placement-index-test.cpp
                                    rename to tests/components/proc/mobject/session/placement-index-test.cpp
                                    index b9b003ede..080cb3461 100644
                                    --- a/tests/components/proc/mobject/placement-index-test.cpp
                                    +++ b/tests/components/proc/mobject/session/placement-index-test.cpp
                                    @@ -25,9 +25,9 @@
                                     //#include "proc/asset/media.hpp"
                                     //#include "proc/mobject/session.hpp"
                                     //#include "proc/mobject/session/edl.hpp"
                                    +#include "proc/mobject/session/placement-index.hpp"
                                     #include "proc/mobject/session/testclip.hpp"
                                     #include "proc/mobject/placement.hpp"
                                    -#include "proc/mobject/placement-index.hpp"
                                     //#include "proc/mobject/explicitplacement.hpp"
                                     //#include "lib/util.hpp"
                                     
                                    @@ -42,6 +42,7 @@ using std::string;
                                     
                                     
                                     namespace mobject {
                                    +namespace session {
                                     namespace test    {
                                           
                                       using asset::VIDEO;
                                    @@ -96,4 +97,4 @@ namespace test    {
                                       LAUNCHER (PlacementIndex_test, "unit session");
                                           
                                           
                                    -}} // namespace mobject::test
                                    +}}} // namespace mobject::session::test
                                    diff --git a/tests/components/proc/mobject/session/test-scopes.hpp b/tests/components/proc/mobject/session/test-scopes.hpp
                                    index bb9690902..31d9d7a9f 100644
                                    --- a/tests/components/proc/mobject/session/test-scopes.hpp
                                    +++ b/tests/components/proc/mobject/session/test-scopes.hpp
                                    @@ -29,7 +29,7 @@
                                     //#include "proc/mobject/placement-ref.hpp"
                                     #include "proc/mobject/session/test-scopes.hpp"
                                     #include "proc/mobject/test-dummy-mobject.hpp"
                                    -#include "proc/mobject/placement-index.hpp"
                                    +#include "proc/mobject/session/placement-index.hpp"
                                     //#include "lib/util.hpp"
                                     
                                     #include 
                                    
                                    From 78f9b2b1c57f7892339cbce648a21ad0fa299f19 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 7 Nov 2009 02:49:55 +0100
                                    Subject: [PATCH 053/377] WIP refactor ContentsQuery to share implementation
                                     with a PathQuery facility
                                    
                                    ---
                                     .../placement-index-query-resolver.hpp        | 212 ++++++++++++++++++
                                     src/proc/mobject/session/scope-locator.hpp    |   2 +-
                                     .../{contents-query.hpp => scope-query.hpp}   |  57 ++++-
                                     .../mobject/session/sess-manager-impl.cpp     |   2 +-
                                     tests/43session.tests                         |   2 +-
                                     .../session/placement-index-query-test.cpp    | 107 +++++++++
                                     ...ts-query-test.cpp => scope-query-test.cpp} |  46 ++--
                                     7 files changed, 394 insertions(+), 34 deletions(-)
                                     create mode 100644 src/proc/mobject/session/placement-index-query-resolver.hpp
                                     rename src/proc/mobject/session/{contents-query.hpp => scope-query.hpp} (78%)
                                     create mode 100644 tests/components/proc/mobject/session/placement-index-query-test.cpp
                                     rename tests/components/proc/mobject/session/{contents-query-test.cpp => scope-query-test.cpp} (59%)
                                    
                                    diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp
                                    new file mode 100644
                                    index 000000000..4ad794227
                                    --- /dev/null
                                    +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp
                                    @@ -0,0 +1,212 @@
                                    +/*
                                    +  PLACEMENT-INDEX.hpp  -  tracking individual Placements and their relations
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2009,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +*/
                                    +
                                    +
                                    +/** @file placement-index.hpp 
                                    + **
                                    + ** @see PlacementRef
                                    + ** @see PlacementIndex_test
                                    + **
                                    + */
                                    +
                                    +
                                    +
                                    +#ifndef MOBJECT_PLACEMENT_INDEX_H
                                    +#define MOBJECT_PLACEMENT_INDEX_H
                                    +
                                    +//#include "pre.hpp"
                                    +//#include "proc/mobject/session/locatingpin.hpp"
                                    +//#include "proc/asset/pipe.hpp"
                                    +#include "lib/util.hpp"
                                    +#include "lib/factory.hpp"
                                    +#include "proc/mobject/placement.hpp"
                                    +#include "proc/mobject/placement-ref.hpp"
                                    +#include "proc/mobject/session/query-resolver.hpp"
                                    +
                                    +#include 
                                    +#include 
                                    +#include 
                                    +#include 
                                    +
                                    +
                                    +namespace mobject {
                                    +
                                    +  class MObject;
                                    +  
                                    +namespace session {
                                    +  
                                    +  using lib::factory::RefcountFac;
                                    +  using std::tr1::shared_ptr;
                                    +  using boost::scoped_ptr;
                                    +  using std::vector;
                                    +  
                                    +  
                                    +  
                                    +  /**
                                    +   */
                                    +  class PlacementIndex
                                    +    : public session::QueryResolver        ////////TODO: really inherit here?
                                    +//  , boost::noncopyable                  ////////TODO : where to put the "noncopyable" base
                                    +    {
                                    +      class Table;
                                    +      
                                    +      scoped_ptr pTab_;
                                    +      
                                    +    public:
                                    +      typedef Placement PlacementMO;
                                    +      typedef PlacementRef PRef;
                                    +      typedef PlacementMO::ID const& ID;
                                    +      
                                    +      typedef session::Goal::QueryID const& QID;
                                    +      
                                    +      
                                    +      PlacementMO& find (ID)  const;
                                    +      
                                    +      template
                                    +      Placement&  find (PlacementMO::Id)  const;
                                    +      template
                                    +      Placement&  find (PlacementRef const&) const;
                                    +      
                                    +      PlacementMO& getScope (PlacementMO const&)  const;
                                    +      PlacementMO& getScope (ID)                  const;
                                    +      
                                    +      vector getReferrers (ID)              const;
                                    +      
                                    +      
                                    +      /** retrieve the logical root scope */
                                    +      PlacementMO& getRoot()                      const;
                                    +      
                                    +      size_t size()                               const;
                                    +      bool contains (PlacementMO const&)          const;
                                    +      bool contains (ID)                          const;
                                    +      
                                    +////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper      
                                    +      template
                                    +      typename session::Query >::iterator
                                    +      query (PlacementMO& scope)                  const;
                                    +      
                                    +      operator string()  const { return "PlacementIndex"; }
                                    +////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper      
                                    +      
                                    +      
                                    +      bool canHandleQuery(QID)                    const;
                                    +      
                                    +      
                                    +      /* == mutating operations == */
                                    +      
                                    +      ID   insert (PlacementMO& newObj, PlacementMO& targetScope);
                                    +      bool remove (PlacementMO&);
                                    +      bool remove (ID);
                                    +      
                                    +      
                                    +      typedef RefcountFac Factory;
                                    +      
                                    +      static Factory create;
                                    +      
                                    +      ~PlacementIndex();
                                    +      
                                    +      void clear();
                                    +      
                                    +    protected:
                                    +      PlacementIndex() ;
                                    +      
                                    +      friend class lib::factory::Factory > >;
                                    +    };
                                    +  ////////////////TODO currently just fleshing  out the API; probably have to split off an impl.class; but for now a PImpl is sufficient...
                                    +  
                                    +    
                                    +  typedef shared_ptr PPIdx;
                                    +
                                    +  
                                    +  
                                    +  /** @internal there is an implicit PlacementIndex available on a global scale,
                                    +   *            by default implemented within the current session. This function allows
                                    +   *            to re-define this implicit index temporarily, e.g. for unit tests. */
                                    +  void
                                    +  reset_PlacementIndex(PPIdx const&) ;
                                    +  
                                    +  /** @internal restore the implicit PlacementIndex to its default implementation (=the session) */
                                    +  void
                                    +  reset_PlacementIndex() ;
                                    +  
                                    +  /** @internal access point for PlacementRef to the implicit global PlacementIndex */
                                    +  Placement &
                                    +  fetch_PlacementIndex(Placement::ID const&) ;
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  /* === forwarding implementations of the templated API === */
                                    +  
                                    +  template
                                    +  inline Placement&
                                    +  PlacementIndex::find (PlacementMO::Id id)  const
                                    +  {
                                    +    PlacementMO& result (find (id));
                                    +    REQUIRE (INSTANCEOF (MO, &result) );
                                    +    return static_cast&> (result);
                                    +  }
                                    +  
                                    +    
                                    +  template
                                    +  inline Placement&
                                    +  PlacementIndex::find (PlacementRef const& pRef)  const
                                    +  {
                                    +    PlacementMO::Id id (pRef);
                                    +    return find (id);
                                    +  }
                                    +  
                                    +  
                                    +  /** @todo use query-resolver-test as an example.....
                                    +   *        return a result set object derived from Resolution
                                    +   *        For the additional type filtering: build a filter iterator,
                                    +   *        using a type-filtering predicate, based on Placement#isCompatible
                                    +   */
                                    +  template
                                    +  inline typename session::Query >::iterator
                                    +  PlacementIndex::query (PlacementMO& scope)  const
                                    +  {
                                    +    UNIMPLEMENTED ("actually run the containment query");
                                    +  }
                                    +  
                                    +  inline Placement&
                                    +  PlacementIndex::getScope (PlacementMO const& p)  const
                                    +  {
                                    +    return getScope(p.getID()); 
                                    +  }
                                    +  
                                    +  inline bool
                                    +  PlacementIndex::contains (PlacementMO const& p)  const
                                    +  {
                                    +    return contains (p.getID());
                                    +  }
                                    +  
                                    +  inline bool
                                    +  PlacementIndex::remove (PlacementMO& p)
                                    +  {
                                    +    return remove (p.getID());
                                    +  }
                                    +  
                                    +  
                                    +  
                                    +}} // namespace mobject::session
                                    +#endif
                                    diff --git a/src/proc/mobject/session/scope-locator.hpp b/src/proc/mobject/session/scope-locator.hpp
                                    index d75bdf980..67bbd2fad 100644
                                    --- a/src/proc/mobject/session/scope-locator.hpp
                                    +++ b/src/proc/mobject/session/scope-locator.hpp
                                    @@ -27,7 +27,7 @@
                                     //#include "proc/mobject/mobject.hpp"
                                     #include "proc/mobject/session/scope.hpp"
                                     #include "proc/mobject/placement.hpp"
                                    -#include "proc/mobject/session/contents-query.hpp"
                                    +#include "proc/mobject/session/scope-query.hpp"
                                     #include "lib/singleton.hpp"
                                     #include "lib/util.hpp"
                                     
                                    diff --git a/src/proc/mobject/session/contents-query.hpp b/src/proc/mobject/session/scope-query.hpp
                                    similarity index 78%
                                    rename from src/proc/mobject/session/contents-query.hpp
                                    rename to src/proc/mobject/session/scope-query.hpp
                                    index 07373b79c..5c9880f95 100644
                                    --- a/src/proc/mobject/session/contents-query.hpp
                                    +++ b/src/proc/mobject/session/scope-query.hpp
                                    @@ -27,6 +27,7 @@
                                     
                                     #include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/session/query-resolver.hpp"
                                    +#include "lib/symbol.hpp"
                                     
                                     #include 
                                     
                                    @@ -34,6 +35,7 @@
                                     namespace mobject {
                                     namespace session {
                                       
                                    +  using lib::Literal;
                                       using std::tr1::bind;
                                       using std::tr1::function;
                                       using std::tr1::placeholders::_1;
                                    @@ -41,10 +43,10 @@ namespace session {
                                       
                                       
                                       /**
                                    -   * Query a scope to discover it's contents.
                                    -   * This is a special kind of query, wired up such as to
                                    -   * enumerate the contents of a scope, filtered by a subtype-check.
                                    -   * For the actual resolution of the scope's contents, this query
                                    +   * Query a scope to discover it's contents or location.
                                    +   * This is a special kind of query, wired up such as to enumerate
                                    +   * the contents or parents of a scope, filtered by a subtype-check.
                                    +   * For the actual resolution of the elements to discover, this query
                                        * relies on an index like facility (usually Session's PlacementIndex),
                                        * which is abstracted as a QueryResolver, but actually is expected to
                                        * cooperate especially with this Query subclass to retrieve the scope
                                    @@ -66,14 +68,15 @@ namespace session {
                                        * defined to be non-copyable)
                                        */
                                       template
                                    -  class ContentsQuery
                                    +  class ScopeQuery
                                         : public Query >
                                         , public Query >::iterator
                                         {
                                           typedef Query > _Query;
                                           
                                    -      QueryResolver const&  index_;
                                    -      PlacementMO const& container_;
                                    +      QueryResolver const&    index_;
                                    +      PlacementMO const& startPoint_;
                                    +      Literal what_to_discover_;
                                           
                                           
                                           typedef typename _Query::iterator _QIter;
                                    @@ -85,12 +88,14 @@ namespace session {
                                           typedef function ContentFilter;
                                           
                                           
                                    -      ContentsQuery (QueryResolver const& resolver,
                                    -                     PlacementMO  const& scope)
                                    +      ScopeQuery (QueryResolver const& resolver,
                                    +                  PlacementMO  const& scope,
                                    +                  Literal direction)
                                             : _Query (_Query::defineQueryTypeID (Goal::DISCOVERY))
                                             , _QIter ()
                                             , index_(resolver)
                                    -        , container_(scope)
                                    +        , startPoint_(scope)
                                    +        , what_to_discover_(direction)
                                             {
                                               resetResultIteration (_Query::resolveBy(index_));
                                             }
                                    @@ -106,7 +111,13 @@ namespace session {
                                           PlacementMO const&
                                           searchScope ()  const
                                             {
                                    -          return container_;
                                    +          return startPoint_;
                                    +        }
                                    +      
                                    +      Literal
                                    +      searchDirection ()  const
                                    +        {
                                    +          return what_to_discover_;
                                             }
                                           
                                           ContentFilter
                                    @@ -138,5 +149,29 @@ namespace session {
                                         };
                                       
                                       
                                    +  template
                                    +  struct ContentsQuery
                                    +    : ScopeQuery
                                    +    {
                                    +      ContentsQuery (QueryResolver const& resolver,
                                    +                     PlacementMO  const& scope)
                                    +        : ScopeQuery (resolver,scope, "content")
                                    +        { }
                                    +      
                                    +    };
                                    +  
                                    +  
                                    +  template
                                    +  struct PathQuery
                                    +    : ScopeQuery
                                    +    {
                                    +      PathQuery (QueryResolver const& resolver,
                                    +                 PlacementMO  const& scope)
                                    +        : ScopeQuery (resolver,scope, "parents")
                                    +        { }
                                    +      
                                    +    };
                                    +  
                                    +  
                                     }} // namespace mobject::session
                                     #endif
                                    diff --git a/src/proc/mobject/session/sess-manager-impl.cpp b/src/proc/mobject/session/sess-manager-impl.cpp
                                    index 4428e587d..5d7d94e62 100644
                                    --- a/src/proc/mobject/session/sess-manager-impl.cpp
                                    +++ b/src/proc/mobject/session/sess-manager-impl.cpp
                                    @@ -115,7 +115,7 @@ namespace session {
                                         scoped_ptr tmpS (new SessionImpl (*tmpD));
                                         
                                         TODO ("reset the assets registered with AssetManager");
                                    -    // Ichthyo-intern: ticket #95
                                    +    /////////////////////////////////////////////////////////////////// TICKET #154
                                         
                                         TODO ("thread lock");
                                         pDefs_.swap (tmpD);
                                    diff --git a/tests/43session.tests b/tests/43session.tests
                                    index 7320329bc..f310e2d1d 100644
                                    --- a/tests/43session.tests
                                    +++ b/tests/43session.tests
                                    @@ -6,7 +6,7 @@ PLANNED "AddClip_test" AddClip_test <
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +#include "lib/test/run.hpp"
                                    +#include "proc/mobject/session/query-resolver.hpp"
                                    +#include "proc/mobject/session/scope-query.hpp"
                                    +#include "proc/mobject/session/placement-index-query-resolver.hpp"
                                    +#include "proc/mobject/session/test-scopes.hpp"
                                    +#include "lib/util.hpp"
                                    +
                                    +#include 
                                    +#include 
                                    +
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +namespace test    {
                                    +  
                                    +  using PathQuery;
                                    +  using ContentsQuery;
                                    +  using util::isSameObject;
                                    +  using std::string;
                                    +  using std::cout;
                                    +  using std::endl;
                                    +  
                                    +  
                                    +  /****************************************************************************
                                    +   * @test accessing the PlacementIndex through the generic query interface,
                                    +   *       for discovering scope contents and containing scope.
                                    +   *       
                                    +   * @see  mobject::session::PlacementIndex
                                    +   * @see  mobject::session::QueryResolver
                                    +   * @see  mobject::session::ContentsQuery
                                    +   */
                                    +  class PlacementIndexQuery_test : public Test
                                    +    {
                                    +      
                                    +      virtual void
                                    +      run (Arg) 
                                    +        {
                                    +          checkQueryResolverWrapper();
                                    +          checkQueryOperations();
                                    +        }
                                    +      
                                    +      void
                                    +      checkQueryResolverWrapper()
                                    +        {
                                    +          PPIdx index = build_testScopes();
                                    +          QueryResolver const& resolver1 (*index);
                                    +          QueryResolver const& resolver2 (*index);
                                    +          
                                    +          ASSERT (isSameObject (resolver1, resolver2));
                                    +          index = build_testScopes();
                                    +        }
                                    +      
                                    +      void
                                    +      checkQueryOperations()
                                    +        {
                                    +          // Prepare an (test)Index (dummy "session")
                                    +          PPIdx index = build_testScopes();
                                    +          PlacementIndexQueryResolver resolver(index);
                                    +          
                                    +          discover (ContentsQuery (resolver));
                                    +          
                                    +          PlacementMO& elm = *ContentsQuery(resolver);
                                    +          
                                    +          discover (PathQuery(resolver,elm));
                                    +        }
                                    +      
                                    +      
                                    +      template
                                    +      void
                                    +      discover (IT result)
                                    +        {
                                    +          for ( ; result; ++result)
                                    +            cout << string(*result) << endl;
                                    +        }
                                    +      
                                    +    };
                                    +  
                                    +  
                                    +  /** Register this test class... */
                                    +  LAUNCHER (PlacementIndexQuery_test, "unit session");
                                    +  
                                    +  
                                    +}}} // namespace mobject::session::test
                                    diff --git a/tests/components/proc/mobject/session/contents-query-test.cpp b/tests/components/proc/mobject/session/scope-query-test.cpp
                                    similarity index 59%
                                    rename from tests/components/proc/mobject/session/contents-query-test.cpp
                                    rename to tests/components/proc/mobject/session/scope-query-test.cpp
                                    index 3b200d07c..8ec2c9d49 100644
                                    --- a/tests/components/proc/mobject/session/contents-query-test.cpp
                                    +++ b/tests/components/proc/mobject/session/scope-query-test.cpp
                                    @@ -23,7 +23,7 @@
                                     
                                     #include "lib/test/run.hpp"
                                     #include "proc/mobject/session/query-resolver.hpp"
                                    -#include "proc/mobject/session/contents-query.hpp"
                                    +#include "proc/mobject/session/scope-query.hpp"
                                     #include "proc/mobject/session/test-scopes.hpp"
                                     //#include "lib/util.hpp"
                                     
                                    @@ -36,49 +36,55 @@ namespace mobject {
                                     namespace session {
                                     namespace test    {
                                       
                                    -  using session::ContentsQuery;
                                    +  using ContentsQuery;
                                       using std::string;
                                       using std::cout;
                                       using std::endl;
                                       
                                       
                                    -  /***************************************************************************************
                                    -   * @test how to discover the contents of a container-like part of the high-level model.
                                    -   *       As this container-like object is just a concept and actually implemented
                                    -   *       by the PlacementIndex, this includes enumerating a scope. The discovered
                                    -   *       contents will be filtered by a runtime type check.
                                    +  /**********************************************************************************************
                                    +   * @test how to discover contents or location of a container-like part of the high-level model.
                                    +   *       As this container-like object is just a concept and actually implemented by the
                                    +   *       PlacementIndex, this means querying the index for elements registered with
                                    +   *       a given scope or finding the enclosing scopes. The discovered
                                    +   *       elements will be filtered by a runtime type check.
                                        *       
                                        * @todo cover using an additional dynamic filter on the results
                                        *       
                                    -   * @see  mobject::PlacementIndex
                                    +   * @see  mobject::session::PlacementIndex
                                        * @see  mobject::session::QueryResolver
                                        * @see  mobject::session::ContentsQuery
                                        */
                                    -  class ContentsQuery_test : public Test
                                    +  class ScopeQuery_test : public Test
                                         {
                                           
                                           virtual void
                                           run (Arg) 
                                             {
                                    -          
                                    -          // Prepare an (test)Index backing the PlacementRefs
                                    +          // Prepare an (test)Index (dummy "session")
                                               PPIdx index = build_testScopes();
                                    -          PlacementMO scope (index->getRoot());
                                    +          PlacementMO& scope (index->getRoot());
                                               QueryResolver const& resolver (*index);
                                               
                                    -          discover (ContentsQuery    (resolver,scope));
                                    -          discover (ContentsQuery    (resolver,scope));
                                    -          discover (ContentsQuery (resolver,scope));
                                    -          discover (ContentsQuery (resolver,scope));
                                    -          discover (ContentsQuery(resolver,scope));
                                    +          discover (ScopeQuery    (resolver,scope, "contents"));
                                    +          discover (ScopeQuery    (resolver,scope, "contents"));
                                    +          discover (ScopeQuery (resolver,scope, "contents"));
                                    +          discover (ScopeQuery (resolver,scope, "contents"));
                                    +          
                                    +          ScopeQuery specialEl(resolver,scope, "contents");
                                    +          
                                    +          discover (specialEl);
                                    +          discover (ScopeQuery    (resolver,specialEL, "parents"));
                                    +          discover (ScopeQuery    (resolver,specialEL, "path"));
                                    +          discover (ScopeQuery (resolver,specialEL, "path"));
                                             }
                                           
                                           
                                           template
                                           void
                                    -      discover (ContentsQuery const& query)
                                    +      discover (ScopeQuery const& query)
                                             {
                                    -          typedef typename ContentsQuery::iterator I;
                                    +          typedef typename ScopeQuery::iterator I;
                                               
                                               for (I elm(query);
                                                    elm; ++elm)
                                    @@ -89,7 +95,7 @@ namespace test    {
                                       
                                       
                                       /** Register this test class... */
                                    -  LAUNCHER (ContentsQuery_test, "unit session");
                                    +  LAUNCHER (ScopeQuery_test, "unit session");
                                       
                                       
                                     }}} // namespace mobject::session::test
                                    
                                    From 0ed30225b6fea7e05218257ae092cfc9bad147ee Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 7 Nov 2009 05:01:53 +0100
                                    Subject: [PATCH 054/377] Initial considerations how to handle session
                                     lifecycle consistently
                                    
                                    ---
                                     wiki/renderengine.html | 34 +++++++++++++++++++++++++++-------
                                     1 file changed, 27 insertions(+), 7 deletions(-)
                                    
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 251817e61..e619d1b9b 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3911,8 +3911,8 @@ Later on we expect a distinct __query subsystem__ to emerge, presumably embeddin
                                     
                                    A facility allowing the Proc-Layer to work with abstracted [[media stream types|StreamType]], linking (abstract or opaque) [[type tags|StreamTypeDescriptor]] to an [[library|MediaImplLib]], which provides functionality for acutally dealing with data of this media stream type. Thus, the stream type manager is a kind of registry of all the external libraries which can be bridged and accessed by Lumiera (for working with media data, that is). The most basic set of libraries is instelled here automatically at application start, most notably the [[GAVL]] library for working with uncompressed video and audio data. //Later on, when plugins will introduce further external libraries, these need to be registered here too.//
                                    -
                                    -
                                    The Session contains all informations, state and objects to be edited by the User. From a users view, the Session is synonymous to the //current Project//. It can be saved and loaded. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]]. &rarr; [[Session design overview|SessionOverview]]
                                    +
                                    +
                                    The Session contains all informations, state and objects to be edited by the User. From a users view, the Session is synonymous to the //current Project//. It can be [[saved and loaded|SessionLifecycle]]. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]]. &rarr; [[Session design overview|SessionOverview]]
                                     
                                     !Session structure
                                     The Session object is a singleton &mdash; actually it is a »~PImpl«-Facade object (because the actual implementation object can be swapped for (re)loading Sessions).<br/>The Session is the access point to the HighLevelModel; it is comprised of
                                    @@ -3948,9 +3948,28 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl
                                     
                                     {{red{WIP ... just emerging}}}
                                    -
                                    +
                                    +
                                    The current [[Session]] is the root of any state found within Proc-Layer. Thus, events defining the session's lifecycle influence and synchronise the cooperative behaviour of the entities within the model, the ProcDispatcher, [[Fixture]] and any facility below.
                                    +* when ''starting'', by default an empty session is created, which puts any related facility into a defined initial state.
                                    +* when ''closing'' the session, any dependent facilities are disabled, disconnected, halted or closed
                                    +* ''loading'' an existing session &mdash; after closing the previous session &mdash; sets up an empty (default) session an populates it with de-serialised content.
                                    +* when encountering a ''mutation point'', [[command processing|ProcDispatcher]] is temporarily halted to trigger off an BuildProcess.
                                    +
                                    +!Role of the session manager
                                    +The session manager is responsible for conducting the session lifecycle. Accessible through the static interface {{{Session::current}}}, it exposes the actual session as a ~PImpl. Both session manager and session are indeed interfaces, backed by implementation classes belonging to ~Proc-Layer's internals. Loading, saving, resetting and closing are the primary public operations of the session manager, each causing the respective lifecycle event.
                                    +
                                    +!Synchronising access to session's implementation facilities
                                    +Some other parts and subsystems within the ~Proc-Layer need specialised access to implementation facilities within the session. Informations about some conditions and configurations might be retrieved through [[querrying the session|Query]], and especially default configurations for many objects are [[bound to the session|DefaultsImplementation]]. The [[discovery of session contents|SessionStructureQuery]] relies on an [[index facility|PlacementIndex]] embedded within the session implementation. Moreover, some "properties" of the [[media objects|MObject]] are actually due to the respective object being [[placed|Placement]] in some way into the session; consequently, there might be an dependency on the actual [[location as visible to the placement|PlacementScope]], which in turn is constituted by [[querying the index|QueryFocus]].
                                    +
                                    +Each of these facilities relies on a separate access point to session services, corresponding to distinct service interfaces. But &mdash; on the implementation side &mdash; all these services are provided by a (compound) implementation object. This approach allows to switch the actual implementation of all these services instantaneous by swapping the ~PImpl maintained by the session manager.
                                    +
                                    +!Interface and lifecycle hooks
                                    +{{red{draft as of 11/09}}}
                                    +
                                    +
                                    +
                                    The Session contains all informations, state and objects to be edited by the User (&rarr;[[def|Session]]).
                                    -As such, the SessionInterface is the main entrance point to Proc-Layer functionality, both for the primary EditingOperations and for playback/rendering processes.
                                    +As such, the SessionInterface is the main entrance point to Proc-Layer functionality, both for the primary EditingOperations and for playback/rendering processes. Proc-Layer state is rooted within the session and guided by the [[session's lifecycle events|SessionLifecycle]].
                                     
                                     Currently (as of 5/09), Ichthyo is [[targeting|PlanningSessionInMem]] a first preliminary implementation of the [[Session in Memory|SessionDataMem]]
                                     
                                    @@ -3958,15 +3977,16 @@ Currently (as of 5/09), Ichthyo is [[targeting|PlanningSessionInMem]] a first pr
                                     Objects are attached and manipulated by [[placements|Placement]]; thus the organisation of these placements is part of the session data layout. Effectively, such a placement within the session behaves like an //instances// of a given object, and at the same time it defines the "non-substantial" properties of the object, e.g. its positions and relations. [[References|MObjectRef]] to these placement entries are handed out as parameters, both down to the [[Builder]] and from there to the render processes within the engine, but also to external parts within the GUI and in plugins. The actual implementation of these object references is built on top of the PlacementRef tags, thus relying on the PlacementIndex the session maintains to keep track of all placements and their relations. While &mdash; using these references &mdash; an external client can access the objects and structures within the session, any actual ''mutations'' should be done based on the CommandHandling: a single operation of a sequence of operations is defined as [[Command]], to be [[dispatched as mutation operation|ProcDispatcher]]. Following this policy ensures integration with the&nbsp;SessionStorage and provides (unlimited) [[UNDO|UndoManager]].
                                     
                                    -
                                    +
                                    <<<
                                     {{red{WARNING: Naming is currently being discussed (11/08)}}}
                                     * [[EDL]] probably will be called ''Sequence'' (or maybe ''Arrangement'')
                                     * [[Session]] maybe renamed to ''Project''
                                     * there seems to be a new entity called [[Timeline]] which holds the global Pipes
                                     <<<
                                    -The [[Session]] (sometimes also called //Project// ) contains all informations and objects to be edited by the User. It can be saved and loaded. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]]. Moreover, the sesion contains references to all the Media files used, and it contains various default or user defined configuration, all being represented as [[Asset]]. At any given time, there is //only one current session// opened within the application.
                                    -The Session is close to what is visible in the GUI. From a user's perspective, you'll find a [[Timeline]]-like structure, containing an [[EDL (or Sequence)|EDL]], where various Media Objects are arranged and placed. The available building blocks and the rules how they can be combined together form Lumiera's [[high-level data model|HighLevelModel]]. Basically, besides the [[media objects|MObjects]] there are data connections and all processing is organized around processing chains or [[pipes|Pipe]], which can be either global (in the Session) or local (in real or virtual clips)
                                    +The [[Session]] (sometimes also called //Project// ) contains all informations and objects to be edited by the User. Any state within the Proc-Layer is directly or indirectly rooted in the session. It can be saved and loaded. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one or multiple collections within the Session, which we call [[Sequence(s)|EDL]]. Moreover, the sesion contains references to all the Media files used, and it contains various default or user defined configuration, all being represented as [[Asset]]. At any given time, there is //only one current session// opened within the application. The [[lifecycle events|SessionLifecycle]] of the session define the lifecycle of ~Proc-Layer as a whole.
                                    +
                                    +The Session is close to what is visible in the GUI. From a user's perspective, you'll find a [[Timeline]]-like structure, containing an [[Sequence|EDL]], where various Media Objects are arranged and placed. The available building blocks and the rules how they can be combined together form Lumiera's [[high-level data model|HighLevelModel]]. Basically, besides the [[media objects|MObjects]] there are data connections and all processing is organized around processing chains or [[pipes|Pipe]], which can be either global (in the Session) or local (in real or virtual clips).
                                     
                                     !!!larger projects
                                     For larger editing projects the simple structure of a session containing "the" timeline is not sufficient. Rather
                                    
                                    From 6dbbc54247e3c9ae07f3c337f9c13621e89ecf63 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 7 Nov 2009 17:37:37 +0100
                                    Subject: [PATCH 055/377] document better how SingletonRef works
                                    
                                    ---
                                     src/lib/singleton-ref.hpp | 16 ++++++++++++++--
                                     1 file changed, 14 insertions(+), 2 deletions(-)
                                    
                                    diff --git a/src/lib/singleton-ref.hpp b/src/lib/singleton-ref.hpp
                                    index 48e74635c..8fc9c289c 100644
                                    --- a/src/lib/singleton-ref.hpp
                                    +++ b/src/lib/singleton-ref.hpp
                                    @@ -23,7 +23,15 @@
                                     /** @file singleton-ref.hpp
                                      ** Helper for singleton-kind access without managing object creation and lifecycle. 
                                      ** A typical usage scenario is when implementing C Language Interfaces without any
                                    - ** canonical access to some "this" pointer.  
                                    + ** canonical access to some "this" pointer. In this case
                                    + ** - an instance of the \c Access policy class is created "somewhere" (usually as
                                    + **   global variable). Calls from within the C code would enter through this accessor.
                                    + ** - when the actual service implementation class comes up, it creates an SingletonRef
                                    + **   instance and thereby wires the (already existing) accessor up with \c *this
                                    + ** - when the service goes down, access is closed automatically and reliably.
                                    + **   Client code (from within C) should check the accessor (by \c bool check)
                                    + **   prior to any access, because accessing a closed connection will throw
                                    + **   (that's unfortunate, but at least throwing is better than segfaulting)
                                      ** 
                                      ** @see gui::NotificationService usage example
                                      */
                                    @@ -90,7 +98,11 @@ namespace lib {
                                       
                                       /*************************************************************
                                        * Helper template providing singleton access without managing
                                    -   * object creation and lifecycle.
                                    +   * object creation and lifecycle. Just the access to the
                                    +   * implementation instance is handled: on creation, access is
                                    +   * enabled, and disabled on destruction. Client code is assumed
                                    +   * to invoke through the Access (template template param),
                                    +   * handed in as ctor parameter.
                                        * @param TY the actual type to be made accessible
                                        * @param B  a base class to inherit from; defaults to noncopyable
                                        * @param Accessor how to implement the static instance access
                                    
                                    From aaf19f4d896713eb887eac887385d83b87652192 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 7 Nov 2009 19:49:29 +0100
                                    Subject: [PATCH 056/377] First draft regarding the access of session
                                     implementation services (Ticket #400)
                                    
                                    ---
                                     src/proc/mobject/session/session-impl.hpp     |  4 +-
                                     src/proc/mobject/session/session-services.hpp | 55 ++++++++++++
                                     tests/43session.tests                         |  4 +
                                     .../session/session-service-access-test.cpp   | 83 +++++++++++++++++++
                                     wiki/renderengine.html                        | 45 ++++++----
                                     5 files changed, 174 insertions(+), 17 deletions(-)
                                     create mode 100644 src/proc/mobject/session/session-services.hpp
                                     create mode 100644 tests/components/proc/mobject/session/session-service-access-test.cpp
                                    
                                    diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp
                                    index 4e4d90731..ee0f70236 100644
                                    --- a/src/proc/mobject/session/session-impl.hpp
                                    +++ b/src/proc/mobject/session/session-impl.hpp
                                    @@ -22,10 +22,10 @@
                                     
                                     
                                     /** @file session-impl.hpp
                                    - ** Session and SessionManager Implemention classes.
                                    + ** Session and SessionManager Implementation classes.
                                      ** Session and the corresponding Manager are primary Interfaces
                                      ** to control the behaviour of the editing part of the application.
                                    - ** All all implementaion complexities are hidden behind a "PImpl".
                                    + ** All all implementation complexities are hidden behind a "PImpl".
                                      **
                                      ** This file contains the implementation classes, it should never
                                      ** be included by client code.
                                    diff --git a/src/proc/mobject/session/session-services.hpp b/src/proc/mobject/session/session-services.hpp
                                    new file mode 100644
                                    index 000000000..e1ddfeb74
                                    --- /dev/null
                                    +++ b/src/proc/mobject/session/session-services.hpp
                                    @@ -0,0 +1,55 @@
                                    +/*
                                    +  SESSION-SERVICES.hpp  -  accessing Proc-Layer internal session implementation services
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2008,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +*/
                                    +
                                    +
                                    +/** @file session-services.hpp
                                    + ** A mechanism for exposing and accessing implementation level
                                    + ** services of the session. 
                                    + ** TODO TODO
                                    + **
                                    + */
                                    +
                                    +
                                    +#ifndef MOBJECT_SESSION_SESSION_SERVICES_H
                                    +#define MOBJECT_SESSION_SESSION_SERVICES_H
                                    +
                                    +#include "proc/mobject/session.hpp"
                                    +
                                    +//#include 
                                    +//#include 
                                    +
                                    +
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +  
                                    +//using std::vector;
                                    +//using boost::scoped_ptr;
                                    +//using std::tr1::shared_ptr;
                                    +
                                    +  
                                    +  
                                    +  
                                    +  
                                    +}} // namespace mobject::session
                                    +#endif
                                    diff --git a/tests/43session.tests b/tests/43session.tests
                                    index f310e2d1d..a4a7fafe8 100644
                                    --- a/tests/43session.tests
                                    +++ b/tests/43session.tests
                                    @@ -99,5 +99,9 @@ PLANNED "SessionManager_test" SessionManager_test <
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +#include "lib/test/run.hpp"
                                    +#include "proc/mobject/session.hpp"
                                    +//#include "proc/mobject/session/testsession1.hpp"
                                    +#include "proc/mobject/session/session-services.hpp"
                                    +//#include "lib/util.hpp"
                                    +//#include 
                                    +//#include 
                                    +
                                    +//using boost::format;
                                    +//using std::string;
                                    +//using std::cout;
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +namespace test    {
                                    +  
                                    +  
                                    +  /*******************************************************************************
                                    +   * Verify the access mechanism used by Proc-Layer internals for 
                                    +   * accessing implementation level APIs of the session.
                                    +   * 
                                    +   * @todo WIP-WIP
                                    +   */
                                    +  class SessionServiceAccess_test : public Test
                                    +    {
                                    +      virtual void
                                    +      run (Arg arg) 
                                    +        {
                                    +//          getCurrentSession ();
                                    +//          clearSession();
                                    +//          loadMockSession();
                                    +//          
                                    +//          clearSession();
                                    +//          buildTestsession1();
                                    +//          string serialized;
                                    +//          saveSession (serialized);
                                    +//          loadSession (serialized);
                                    +//          ASSERT (checkTestsession1());
                                    +        } 
                                    +      
                                    +      
                                    +      /** @test accessing the current (global) session */
                                    +      void
                                    +      getCurrentSession ()
                                    +        {
                                    +//          PSess sess = Session::current;
                                    +//          ASSERT (sess->isValid());
                                    +        }
                                    +      
                                    +      
                                    +    };
                                    +  
                                    +  
                                    +  /** Register this test class... */
                                    +  LAUNCHER (SessionServiceAccess_test, "function session");
                                    +  
                                    +  
                                    +  
                                    +}}} // namespace mobject::session::test
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index e619d1b9b..2e2252f1e 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3911,8 +3911,9 @@ Later on we expect a distinct __query subsystem__ to emerge, presumably embeddin
                                     
                                    A facility allowing the Proc-Layer to work with abstracted [[media stream types|StreamType]], linking (abstract or opaque) [[type tags|StreamTypeDescriptor]] to an [[library|MediaImplLib]], which provides functionality for acutally dealing with data of this media stream type. Thus, the stream type manager is a kind of registry of all the external libraries which can be bridged and accessed by Lumiera (for working with media data, that is). The most basic set of libraries is instelled here automatically at application start, most notably the [[GAVL]] library for working with uncompressed video and audio data. //Later on, when plugins will introduce further external libraries, these need to be registered here too.//
                                    -
                                    -
                                    The Session contains all informations, state and objects to be edited by the User. From a users view, the Session is synonymous to the //current Project//. It can be [[saved and loaded|SessionLifecycle]]. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]]. &rarr; [[Session design overview|SessionOverview]]
                                    +
                                    +
                                    The Session contains all informations, state and objects to be edited by the User. From a users view, the Session is synonymous to the //current Project//. It can be [[saved and loaded|SessionLifecycle]]. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]].
                                    +&rarr; [[Session design overview|SessionOverview]]
                                     
                                     !Session structure
                                     The Session object is a singleton &mdash; actually it is a »~PImpl«-Facade object (because the actual implementation object can be swapped for (re)loading Sessions).<br/>The Session is the access point to the HighLevelModel; it is comprised of
                                    @@ -3920,7 +3921,8 @@ The Session object is a singleton &mdash; actually it is a »~PImpl«-Facade
                                     * some [[sequences|EDL]] to be used within these timelines
                                     * a [[scope structure|PlacementScope]] backed by an index, and a current QueryFocus
                                     * a set of ConfigRules to guide default behaviour {{red{planned as of 10/09}}}
                                    -* the ''Fixture'' with a possibility to [[(re)build it|PlanningBuildFixture]] {{red{just partially designed as of 10/09}}}
                                    +* the ''Fixture'' with a possibility to [[(re)build it|PlanningBuildFixture]] {{red{just partially designed as of 01/09}}}
                                    +* the [[Asset subsystem|AssetManager]] is tightly integrated; besides, there are some SessionServices for internal use
                                     
                                     &rarr; see [[relation of timeline, sequences and objects|TimelineSequences]]
                                     
                                    @@ -3948,7 +3950,7 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl {{red{WIP ... just emerging}}}
                                    -
                                    +
                                    The current [[Session]] is the root of any state found within Proc-Layer. Thus, events defining the session's lifecycle influence and synchronise the cooperative behaviour of the entities within the model, the ProcDispatcher, [[Fixture]] and any facility below.
                                     * when ''starting'', by default an empty session is created, which puts any related facility into a defined initial state.
                                     * when ''closing'' the session, any dependent facilities are disabled, disconnected, halted or closed
                                    @@ -3956,7 +3958,7 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl
                                     * when encountering a ''mutation point'', [[command processing|ProcDispatcher]] is temporarily halted to trigger off an BuildProcess.
                                     
                                     !Role of the session manager
                                    -The session manager is responsible for conducting the session lifecycle. Accessible through the static interface {{{Session::current}}}, it exposes the actual session as a ~PImpl. Both session manager and session are indeed interfaces, backed by implementation classes belonging to ~Proc-Layer's internals. Loading, saving, resetting and closing are the primary public operations of the session manager, each causing the respective lifecycle event.
                                    +The SessionManager is responsible for conducting the session lifecycle. Accessible through the static interface {{{Session::current}}}, it exposes the actual session as a ~PImpl. Both session manager and session are indeed interfaces, backed by implementation classes belonging to ~Proc-Layer's internals. Loading, saving, resetting and closing are the primary public operations of the session manager, each causing the respective lifecycle event.
                                     
                                     !Synchronising access to session's implementation facilities
                                     Some other parts and subsystems within the ~Proc-Layer need specialised access to implementation facilities within the session. Informations about some conditions and configurations might be retrieved through [[querrying the session|Query]], and especially default configurations for many objects are [[bound to the session|DefaultsImplementation]]. The [[discovery of session contents|SessionStructureQuery]] relies on an [[index facility|PlacementIndex]] embedded within the session implementation. Moreover, some "properties" of the [[media objects|MObject]] are actually due to the respective object being [[placed|Placement]] in some way into the session; consequently, there might be an dependency on the actual [[location as visible to the placement|PlacementScope]], which in turn is constituted by [[querying the index|QueryFocus]].
                                    @@ -3967,9 +3969,10 @@ Each of these facilities relies on a separate access point to session services,
                                     {{red{draft as of 11/09}}}
                                     
                                    -
                                    +
                                    The Session contains all informations, state and objects to be edited by the User (&rarr;[[def|Session]]).
                                     As such, the SessionInterface is the main entrance point to Proc-Layer functionality, both for the primary EditingOperations and for playback/rendering processes. Proc-Layer state is rooted within the session and guided by the [[session's lifecycle events|SessionLifecycle]].
                                    +Implementation facilities within the Proc-Layer may access a somewhat richer [[session service API|SessionServices]].
                                     
                                     Currently (as of 5/09), Ichthyo is [[targeting|PlanningSessionInMem]] a first preliminary implementation of the [[Session in Memory|SessionDataMem]]
                                     
                                    @@ -3977,11 +3980,15 @@ Currently (as of 5/09), Ichthyo is [[targeting|PlanningSessionInMem]] a first pr
                                     Objects are attached and manipulated by [[placements|Placement]]; thus the organisation of these placements is part of the session data layout. Effectively, such a placement within the session behaves like an //instances// of a given object, and at the same time it defines the "non-substantial" properties of the object, e.g. its positions and relations. [[References|MObjectRef]] to these placement entries are handed out as parameters, both down to the [[Builder]] and from there to the render processes within the engine, but also to external parts within the GUI and in plugins. The actual implementation of these object references is built on top of the PlacementRef tags, thus relying on the PlacementIndex the session maintains to keep track of all placements and their relations. While &mdash; using these references &mdash; an external client can access the objects and structures within the session, any actual ''mutations'' should be done based on the CommandHandling: a single operation of a sequence of operations is defined as [[Command]], to be [[dispatched as mutation operation|ProcDispatcher]]. Following this policy ensures integration with the&nbsp;SessionStorage and provides (unlimited) [[UNDO|UndoManager]].
                                     
                                    -
                                    +
                                    +
                                    The session manager is responsible for maintaining session state as a whole and for conducting the session lifecycle. The session manager API allows for saving, loading, closing and resetting the session. Accessible through the static interface {{{Session::current}}}, it exposes the actual session as a ~PImpl. Actually, both session and session manager are interfaces.
                                    +
                                    +
                                    +
                                    <<<
                                    -{{red{WARNING: Naming is currently being discussed (11/08)}}}
                                    -* [[EDL]] probably will be called ''Sequence'' (or maybe ''Arrangement'')
                                    -* [[Session]] maybe renamed to ''Project''
                                    +{{red{WARNING: Naming was discussed (11/08) and decided to be changed....}}}
                                    +* [[EDL]] probably will be called ''Sequence''
                                    +* [[Session]] is largely synonymous to ''Project''
                                     * there seems to be a new entity called [[Timeline]] which holds the global Pipes
                                     <<<
                                     The [[Session]] (sometimes also called //Project// ) contains all informations and objects to be edited by the User. Any state within the Proc-Layer is directly or indirectly rooted in the session. It can be saved and loaded. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one or multiple collections within the Session, which we call [[Sequence(s)|EDL]]. Moreover, the sesion contains references to all the Media files used, and it contains various default or user defined configuration, all being represented as [[Asset]]. At any given time, there is //only one current session// opened within the application. The [[lifecycle events|SessionLifecycle]] of the session define the lifecycle of ~Proc-Layer as a whole.
                                    @@ -3992,27 +3999,35 @@ The Session is close to what is visible in the GUI. From a user's perspective, y
                                     For larger editing projects the simple structure of a session containing "the" timeline is not sufficient. Rather
                                     * we may have several [[EDLs (=Sequences)|EDL]], e.g. one for each scene. These sequences can be even layered or nested (compositional work).
                                     * within one project, there may be multiple, //independant Timelines// &mdash; each of which may have an associated Viewer or Monitor
                                    -To support these cases without making the default case more complicated, Lumiera introduces a //focus// for selecting the //current EDL,// which will receive all editing operations. [[Timelines|Timeline]] on the other hand are always top-level objects and can't be combined further. You can render a given timeline to output.
                                    +Usually, when working with this stucture, you'll drill down starting from a timeline, trough a (top-level) sequence, down into a track, a clip, maybe even a embedded Sequence (VirtualClip), and from there even more down into a single attached effect. This constitutes a set of [[nested scopes|PlacementScope]]. Operations are to be [[dispatched|ProcDispatcher]] through a [[command system|CommandHandling]], including the target object [[by reference|MObjectRef]]. [[Timelines|Timeline]] on the other hand are always top-level objects and can't be combined further. You can render a single given timeline to output.
                                     &rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
                                     
                                     !!!the definitive state
                                    -With all the structural complexities possible within such a session, we need an isolation layer to provide __one__ definitive state where all configuration has been made explicit. Thus the session manages one special object list, the [[Fixture]], which can be seen as all currently active objects placed onto a single timeline.
                                    +With all the structural complexities possible within such a session, we need an isolation layer to provide __one__ definitive state where all configuration has been made explicit. Thus the session manages a special consolidated view (object list), called [[the Fixture|Fixture]], which can be seen as all currently active objects placed onto a single timeline.
                                     
                                     !!!organisational devices
                                    -The possibility of having multiple ~EDLs helps organizing larger projects. Each [[EDL]] is just a logical grouping; because all effective properties of any MObject within this EDL are defined by the ~MObject itself and the [[Placement]], by which the object is anchored to some time point, some track, can be connected to some pipe, or linked to another object. In a similar manner, [[Tracks|Track]] are just another organisational aid for grouping objects, disabling them and defining common output pipes.
                                    +The possibility of having multiple Sequences helps organizing larger projects. Each [[Sequence|EDL]] is just a logical grouping; because all effective properties of any MObject within this sequence are defined by the ~MObject itself and the [[Placement]], by which the object is anchored to some time point, some track, can be connected to some pipe, or linked to another object. In a similar manner, [[Tracks|Track]] are just another organisational aid for grouping objects, disabling them and defining common output pipes.
                                     
                                     !!!global pipes
                                    -[>img[draw/Proc.builder1.png]] Any session should contain a number of global [[(destination) pipes|Pipe]], typically video out and audio out. The goal is, to get any content producing or transforming object in some way connected to one of these outputs, either //by [[placing|Placement]] it directly// to some pipe, or by //placing it to a track// and having the track refer to some pipe. Besides the global destination pipes, we can use internal pipes to form busses or subgroups, either on a global (session) level, or by using the processing pipe within a [[virtual clip|VirtualClip]], which can be placed freely within the EDL(s). Normally, pipes just gather and mix data, but of course any pipe can have an attached effect chain. (&rarr; see [[more on Tracks and Pipes within the EDL|TrackPipeEDL]])
                                    +[>img[draw/Proc.builder1.png]] Any session should contain a number of global [[(destination) pipes|Pipe]], typically video out and audio out. The goal is, to get any content producing or transforming object in some way connected to one of these outputs, either //by [[placing|Placement]] it directly// to some pipe, or by //placing it to a track// and having the track refer to some pipe. Besides the global destination pipes, we can use internal pipes to form busses or subgroups, either on a global (session) level, or by using the processing pipe within a [[virtual clip|VirtualClip]], which can be placed freely within the sequence(s). Normally, pipes just gather and mix data, but of course any pipe can have an attached effect chain.
                                    +&rarr; [[more on Tracks and Pipes within the Sequence|TrackPipeEDL]]
                                     
                                     !!!default configuration
                                     While all these possibilities may seem daunting, there is a simple default configuration loaded into any pristine new session:
                                    -It will contain a global video and audio out pipe, just one EDL with a single track; this track will have a internal video and audio pipe (bus) configured with one fading device sending to the global output ports. So, by adding some clip with a simple absolute placement to this track and some time position, the clip gets connected and rendered, after [[(re)building|PlanningBuildFixture]] the [[Fixture]] and passing the result to the [[Builder]] &mdash; and using the resulting render nodes network (Render Engine).
                                    +It will contain a global video and audio out pipe, just one timeline holding a single sequence with a single track; this track will be configured with a fading device, to send any video and audio data encountered on enclosed objects to the global (master) pipes. So, by adding a clip with a simple absolute placement to this track and to some time position, the clip gets connected and rendered, after [[(re)building|PlanningBuildFixture]] the [[Fixture]] and passing the result to the [[Builder]] &mdash; and using the resulting render nodes network (Render Engine).
                                     
                                     &rarr; [[anatomy of the high-level model|HighLevelModel]]
                                     &rarr; considerations regarding [[Tracks and Pipes within the EDL|TrackPipeEDL]]
                                     &rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
                                     
                                    +
                                    +
                                    Within Lumiera's Proc-Layer, there are some implementation facilities and subsystems needing more specialised access to implementation services provided by the session. Thus, besides the public SessionInterface and the [[lifecycle and state management API|SessionManager]], there are some additional service interfaces exposed by the session through a special access mechanism. This mechanism needs to be special in order to assure clean transactional behaviour when the session is opened, closed, cleared or loaded. Of course, there is the additional requirement to avoid direct dependencies of the mentioned Proc internals on session implementation details.
                                    +
                                    +!Accessing session services
                                    +For each of these services, there is an access interface, usually through an class with only static methods. Basically this means access //by name.//
                                    +On the //implementation side//&nbsp; of this access interface class (i.e. within a {{{*.cpp}}} file separate from the client code), there is a (down-casting) access through the top-level session-~PImpl pointer, which is then forwarded through another {{{operator->()}}} on the ~SessionImpl class finally to reach an ~SessionServices instance, owned and managed by ~SessionImpl. This ~SessionServices instance is configured (statically) to mix in implementations for all the exposed service interfaces. Thus, the implementaion of the access functions (to the session service we're discussing here) can use this forwarding mechanism (which technically is located as a static function on class ~SessionServices) to get the actual implementation basically by one-liners. The upside of this (admittedly convoluted) technique is that we've gotten at runtime only a single indirection, which moreover is through the top-level session-~PImpl. The downside is that, due to the separation in {{{*.h}}} and {{{*.c}}} files, we can't use any specifically typed generic operations, which forces us to use type erasure in case we need such (an example being the content discovery queries utilised by all high-level model objects).
                                    +
                                    The frontside interface of the session allows to query for contained objects; it is used to discover the structure and contents of the currently opened session/project. Access point is the public API of the Session class, which, besides exposing those queries, also provides functionality for adding and removing session contents.
                                     
                                    
                                    From f1ce05ea9dbfc3d42e78041dc03801ce2ab7aad9 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 8 Nov 2009 19:47:51 +0100
                                    Subject: [PATCH 057/377] clean up some overly clever definitions
                                    
                                    ---
                                     src/proc/mobject/session.hpp         | 8 ++++----
                                     src/proc/mobject/session/session.cpp | 7 ++++---
                                     2 files changed, 8 insertions(+), 7 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session.hpp b/src/proc/mobject/session.hpp
                                    index 0542e1da2..744113ccd 100644
                                    --- a/src/proc/mobject/session.hpp
                                    +++ b/src/proc/mobject/session.hpp
                                    @@ -80,7 +80,7 @@ namespace mobject {
                                         {
                                         protected:
                                           Session (session::DefsManager&)  throw();
                                    -      virtual ~Session () = 0;
                                    +      virtual ~Session ();
                                     
                                         public:
                                           static session::SessManager& current;
                                    @@ -128,13 +128,13 @@ namespace mobject {
                                             /** replace the current session by a new
                                              *  session loaded from serialised state.
                                              */
                                    -        virtual void load () =0;
                                    +        virtual void load ()  =0;
                                     
                                             /** create a complete, serialised representation
                                              *  of the current session config and contents.
                                              *  @todo how to serialise, parameters, return value?
                                              */
                                    -        virtual void save () =0;
                                    +        virtual void save ()  =0;
                                             
                                             /** access to the current session object instance.
                                              *  This is the sole access path available for clients.
                                    @@ -142,7 +142,7 @@ namespace mobject {
                                              */
                                             virtual Session* operator-> ()  throw() =0;
                                             
                                    -        virtual ~SessManager() {};
                                    +        virtual ~SessManager();
                                           };
                                     
                                           
                                    diff --git a/src/proc/mobject/session/session.cpp b/src/proc/mobject/session/session.cpp
                                    index dec115d15..317c8ef3b 100644
                                    --- a/src/proc/mobject/session/session.cpp
                                    +++ b/src/proc/mobject/session/session.cpp
                                    @@ -92,12 +92,13 @@ namespace mobject {
                                       
                                       
                                       
                                    -  Session::~Session () 
                                    -  { }
                                    -  
                                       Session::Session (session::DefsManager& def)  throw()
                                         : defaults(def)
                                       { }
                                    +  
                                    +  // Emit the vtables and other magic stuff here...
                                    +  SessManager::~SessManager() { }
                                    +  Session::~Session () { }
                                     
                                     
                                     
                                    
                                    From 2765981db9801d40001467674c3ef1731ec2c6eb Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 8 Nov 2009 20:13:11 +0100
                                    Subject: [PATCH 058/377] build a complete simplified mock
                                     Session/SessionManager
                                    
                                    ---
                                     src/proc/mobject/session.hpp                  |  15 +-
                                     src/proc/mobject/session/scope-query.hpp      |   4 +-
                                     src/proc/mobject/session/session-impl.hpp     |   2 +
                                     tests/43session.tests                         |   2 +-
                                     .../session/placement-index-query-test.cpp    |   6 +-
                                     .../proc/mobject/session/scope-query-test.cpp |  10 +-
                                     .../session/session-service-access-test.cpp   | 173 ++++++++++++++++--
                                     7 files changed, 182 insertions(+), 30 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session.hpp b/src/proc/mobject/session.hpp
                                    index 744113ccd..5e46e97a0 100644
                                    --- a/src/proc/mobject/session.hpp
                                    +++ b/src/proc/mobject/session.hpp
                                    @@ -23,9 +23,22 @@
                                     
                                     /** @file session.hpp
                                      ** Primary Interface to the current Session.
                                    + ** The session interface can be used to discover session's contents.
                                    + ** Mostly, these objects within the session are MObject subclasses, but they
                                    + ** are attached into the session by a Placement. Usually, you'd want to use
                                    + ** the discovered objects to invoke operations on them; in most cases,
                                    + ** invoking any mutating operation should be wrapped into a Command.
                                    + ** 
                                      ** The Interface Session is abstract and only accessible via the
                                      ** static field Session::current, which actually refers to a SessManager 
                                    - ** singleton instance. The latter acts as smart ptr-to-Impl.
                                    + ** singleton instance. The latter acts as smart ptr-to-Impl for accessing the
                                    + ** current session, but at the same time exposes a lifecycle/management API.
                                    + ** 
                                    + ** @note if interested in the interplay of Session, SessManager and the
                                    + **       internal service APIs (SessionServices), you should have a look
                                    + **       at session-service-access-test.cpp, as this test creates a complete
                                    + **       but simplified mock setup of the session and session manager, without
                                    + **       any access and synchronisation and similar concerns, to read top down.
                                      **
                                      */
                                     
                                    diff --git a/src/proc/mobject/session/scope-query.hpp b/src/proc/mobject/session/scope-query.hpp
                                    index 5c9880f95..72e895851 100644
                                    --- a/src/proc/mobject/session/scope-query.hpp
                                    +++ b/src/proc/mobject/session/scope-query.hpp
                                    @@ -21,8 +21,8 @@
                                     */
                                     
                                     
                                    -#ifndef MOBJECT_SESSION_CONTENTS_QUERY_H
                                    -#define MOBJECT_SESSION_CONTENTS_QUERY_H
                                    +#ifndef MOBJECT_SESSION_SCOPE_QUERY_H
                                    +#define MOBJECT_SESSION_SCOPE_QUERY_H
                                     
                                     
                                     #include "proc/mobject/placement.hpp"
                                    diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp
                                    index ee0f70236..7b36f6887 100644
                                    --- a/src/proc/mobject/session/session-impl.hpp
                                    +++ b/src/proc/mobject/session/session-impl.hpp
                                    @@ -29,6 +29,8 @@
                                      **
                                      ** This file contains the implementation classes, it should never
                                      ** be included by client code.
                                    + ** 
                                    + ** @see session-service-access-test.cpp for a complete simplified mock session manager 
                                      **
                                      */
                                     
                                    diff --git a/tests/43session.tests b/tests/43session.tests
                                    index a4a7fafe8..5c9b256b0 100644
                                    --- a/tests/43session.tests
                                    +++ b/tests/43session.tests
                                    @@ -99,7 +99,7 @@ PLANNED "SessionManager_test" SessionManager_test <(resolver);
                                               
                                               discover (PathQuery(resolver,elm));
                                    +#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!!
                                             }
                                           
                                           
                                    diff --git a/tests/components/proc/mobject/session/scope-query-test.cpp b/tests/components/proc/mobject/session/scope-query-test.cpp
                                    index 8ec2c9d49..b360e6457 100644
                                    --- a/tests/components/proc/mobject/session/scope-query-test.cpp
                                    +++ b/tests/components/proc/mobject/session/scope-query-test.cpp
                                    @@ -1,5 +1,5 @@
                                     /*
                                    -  ContentsQuery(Test)  -  running queries to discover container contents, filtering (sub)types 
                                    +  ScopeQuery(Test)  -  running queries to discover container contents, filtering (sub)types 
                                      
                                       Copyright (C)         Lumiera.org
                                         2009,               Hermann Vosseler 
                                    @@ -36,7 +36,7 @@ namespace mobject {
                                     namespace session {
                                     namespace test    {
                                       
                                    -  using ContentsQuery;
                                    +  using session::ContentsQuery;
                                       using std::string;
                                       using std::cout;
                                       using std::endl;
                                    @@ -73,10 +73,10 @@ namespace test    {
                                               
                                               ScopeQuery specialEl(resolver,scope, "contents");
                                               
                                    +          discover (ScopeQuery    (resolver,*specialEl, "parents"));
                                    +          discover (ScopeQuery    (resolver,*specialEl, "path"));
                                    +          discover (ScopeQuery (resolver,*specialEl, "path"));
                                               discover (specialEl);
                                    -          discover (ScopeQuery    (resolver,specialEL, "parents"));
                                    -          discover (ScopeQuery    (resolver,specialEL, "path"));
                                    -          discover (ScopeQuery (resolver,specialEL, "path"));
                                             }
                                           
                                           
                                    diff --git a/tests/components/proc/mobject/session/session-service-access-test.cpp b/tests/components/proc/mobject/session/session-service-access-test.cpp
                                    index 748cd795c..9214ea055 100644
                                    --- a/tests/components/proc/mobject/session/session-service-access-test.cpp
                                    +++ b/tests/components/proc/mobject/session/session-service-access-test.cpp
                                    @@ -25,13 +25,20 @@
                                     #include "proc/mobject/session.hpp"
                                     //#include "proc/mobject/session/testsession1.hpp"
                                     #include "proc/mobject/session/session-services.hpp"
                                    +#include "lib/singleton.hpp"
                                     //#include "lib/util.hpp"
                                     //#include 
                                    -//#include 
                                    +#include 
                                    +#include 
                                    +#include 
                                     
                                     //using boost::format;
                                    -//using std::string;
                                    -//using std::cout;
                                    +  using lib::Singleton;
                                    +  using boost::lexical_cast;
                                    +  using std::ostream;
                                    +  using std::string;
                                    +  using std::cout;
                                    +  using std::endl;
                                     
                                     
                                     namespace mobject {
                                    @@ -39,36 +46,164 @@ namespace session {
                                     namespace test    {
                                       
                                       
                                    +  namespace { // what follows is a simulated (simplified) version
                                    +             //  of the complete Session + SessionManager setup.....
                                    +    
                                    +    
                                    +    /* === Interface level === */
                                    +    
                                    +    struct TSessManager;
                                    +    typedef TSessManager& PSess;
                                    +    
                                    +    struct TSession
                                    +      {
                                    +        virtual ~TSession () { }
                                    +        static TSessManager& current;
                                    +        
                                    +        virtual void externalOperation ()    =0;
                                    +      };
                                    +    
                                    +    struct TSessManager
                                    +      {
                                    +        /** access to the current session */
                                    +        virtual TSession* operator-> ()      =0;
                                    +        
                                    +        virtual void reset ()                =0;
                                    +        virtual ~TSessManager() { };
                                    +      };
                                    +    
                                    +    
                                    +    /* === Implementation level === */
                                    +    
                                    +    struct TSessionImpl : TSession
                                    +      {
                                    +        static uint magic_;
                                    +        
                                    +        /* ==== Session API ==== */
                                    +        void externalOperation() ;
                                    +        
                                    +        /* ==== Implementation level API ==== */
                                    +        void implementationService() ;
                                    +        
                                    +        /* ==== internals ==== */
                                    +        TSessionImpl()
                                    +          {
                                    +            ++magic_;
                                    +            cout << "creating new Session " << magic_ << endl;
                                    +          }
                                    +        
                                    +        operator string() const
                                    +          {
                                    +            return string("Session-Impl(")
                                    +                 + lexical_cast(magic_)
                                    +                 + ")"; 
                                    +          }
                                    +      };
                                    +    
                                    +    inline ostream&
                                    +    operator<< (ostream& os, TSessionImpl const& simpl)
                                    +      {
                                    +        return os << string(simpl);
                                    +      }
                                    +    
                                    +    void
                                    +    TSessionImpl::externalOperation()
                                    +      {
                                    +        cout << *this << "::externalOperation()" << endl;
                                    +      }
                                    +    
                                    +    /* ==== Implementation level API ==== */
                                    +    void
                                    +    TSessionImpl::implementationService()
                                    +      {
                                    +        cout << *this << "::implementationService()" << endl;
                                    +      }
                                    +    
                                    +    
                                    +    
                                    +    struct TSessManagerImpl : TSessManager
                                    +      {
                                    +        scoped_ptr pImpl_;
                                    +        
                                    +        TSessManagerImpl()
                                    +          : pImpl_(0)
                                    +          { }
                                    +        
                                    +        TSessionImpl*
                                    +        operator-> ()
                                    +          {
                                    +            if (!pImpl_)
                                    +              this->reset();
                                    +            return pImpl_.get();
                                    +          }
                                    +        
                                    +        
                                    +        /* ==== Manager API ==== */
                                    +        void
                                    +        reset ()
                                    +          {
                                    +            scoped_ptr tmpS (new TSessionImpl);
                                    +            pImpl_.swap (tmpS);
                                    +          }
                                    +      };
                                    +    
                                    +    
                                    +    /* === storage and basic configuration === */
                                    +    
                                    +    uint TSessionImpl::magic_;
                                    +    
                                    +    TSessManager& TSession::current = Singleton()();
                                    +                                    //note: comes up already during static initialisation
                                    +    
                                    +    
                                    +  } // (END) simulated session management
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                       /*******************************************************************************
                                        * Verify the access mechanism used by Proc-Layer internals for 
                                        * accessing implementation level APIs of the session.
                                        * 
                                    -   * @todo WIP-WIP
                                    +   * Actually, this test uses setup of the real session,
                                    +   * complete with interfaces, implementation and a
                                    +   * session manager frontend.
                                    +   *
                                    +   * @see session-impl.hpp the real thing
                                    +   * @see SessionServices; 
                                        */
                                       class SessionServiceAccess_test : public Test
                                         {
                                           virtual void
                                    -      run (Arg arg) 
                                    +      run (Arg) 
                                             {
                                    -//          getCurrentSession ();
                                    -//          clearSession();
                                    -//          loadMockSession();
                                    -//          
                                    -//          clearSession();
                                    -//          buildTestsession1();
                                    -//          string serialized;
                                    -//          saveSession (serialized);
                                    -//          loadSession (serialized);
                                    -//          ASSERT (checkTestsession1());
                                    +          access_defaultSession();
                                    +          make_newSession();
                                    +          invoke_implService();
                                             } 
                                           
                                           
                                    -      /** @test accessing the current (global) session */
                                           void
                                    -      getCurrentSession ()
                                    +      access_defaultSession ()
                                             {
                                    -//          PSess sess = Session::current;
                                    -//          ASSERT (sess->isValid());
                                    +          cout << "Session not yet used...." << endl;
                                    +          TSession::current->externalOperation();
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      make_newSession ()
                                    +        {
                                    +          TSession::current.reset();
                                    +          TSession::current->externalOperation();
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      invoke_implService ()
                                    +        {
                                    +          ///////////////////////////////TODO
                                             }
                                           
                                           
                                    
                                    From 043d4f42fa88316c7a18ea0cacb1643ee3087150 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Mon, 9 Nov 2009 02:08:37 +0100
                                    Subject: [PATCH 059/377] working example implementation of the access
                                     mechanism to session internal APIs
                                    
                                    ---
                                     src/lib/meta/generator.hpp                    |  15 +-
                                     src/proc/mobject/session/session-services.hpp |  27 ++-
                                     .../session/session-service-access-test.cpp   | 173 ++++++++++++++----
                                     tests/lib/meta/generator-test.cpp             |   4 +-
                                     wiki/renderengine.html                        |   4 +-
                                     5 files changed, 185 insertions(+), 38 deletions(-)
                                    
                                    diff --git a/src/lib/meta/generator.hpp b/src/lib/meta/generator.hpp
                                    index 5469fbaeb..b248888d2 100644
                                    --- a/src/lib/meta/generator.hpp
                                    +++ b/src/lib/meta/generator.hpp
                                    @@ -42,8 +42,14 @@ This code is heavily inspired by
                                      ** Helpers for working with lumiera::typelist::Types (i.e. lists-of-types). 
                                      ** The main purpose is to build interfaces and polymorphic implementations
                                      ** (using virtual functions) based on templated Types or Collections of types,
                                    - ** which is not possible without Template Metaprogrmming.
                                    + ** which is not possible without Template Metaprogramming.
                                      ** 
                                    + ** The facilities in this header work by instantiating another template,
                                    + ** which is passed in as (template template) parameter, for each of a
                                    + ** given sequence of types. What varies is the way how this "for each"
                                    + ** instantiation is mixed or inherited into the resulting product. 
                                    + ** 
                                    + ** @see generator-test.cpp
                                      ** @see lumiera::query::ConfigRules usage example
                                      ** @see typelist.hpp
                                      ** 
                                    @@ -99,6 +105,13 @@ namespace typelist{
                                           };
                                         
                                         
                                    +    /** Helper to just inherit from the given type(s) */
                                    +    template
                                    +    struct InheritFrom : T
                                    +      { };
                                    +    
                                    +    
                                    +    
                                         
                                         /** 
                                          * Build a single inheritance chain of template instantiations.
                                    diff --git a/src/proc/mobject/session/session-services.hpp b/src/proc/mobject/session/session-services.hpp
                                    index e1ddfeb74..1c944094e 100644
                                    --- a/src/proc/mobject/session/session-services.hpp
                                    +++ b/src/proc/mobject/session/session-services.hpp
                                    @@ -33,6 +33,7 @@
                                     #define MOBJECT_SESSION_SESSION_SERVICES_H
                                     
                                     #include "proc/mobject/session.hpp"
                                    +#include "lib/meta/generator.hpp"
                                     
                                     //#include 
                                     //#include 
                                    @@ -46,10 +47,34 @@ namespace session {
                                     //using std::vector;
                                     //using boost::scoped_ptr;
                                     //using std::tr1::shared_ptr;
                                    -
                                    +  using lumiera::typelist::InstantiateChained;
                                    +  using lumiera::typelist::InheritFrom;
                                    +  using lumiera::typelist::NullType;
                                       
                                       
                                       
                                    +  template
                                    +  struct ServiceAccessPoint;
                                    +  
                                    +  
                                    +  /**
                                    +   * Collection of configured implementation-level services
                                    +   * to provide by the Session. An instance of this template
                                    +   * is created on top of SessionImpl, configured such as
                                    +   * to inherit from all the concrete services to be
                                    +   * exposed for use by Proc-Lyer's internals. 
                                    +   */
                                    +  template< typename IMPS
                                    +          , class FRONT
                                    +          , class BA =NullType
                                    +          >
                                    +  class SessionServicesX
                                    +    : public InstantiateChained
                                    +    {
                                    +      static FRONT& entrance_;
                                    +    };
                                    +  
                                    +  
                                       
                                     }} // namespace mobject::session
                                     #endif
                                    diff --git a/tests/components/proc/mobject/session/session-service-access-test.cpp b/tests/components/proc/mobject/session/session-service-access-test.cpp
                                    index 9214ea055..6d7e4f404 100644
                                    --- a/tests/components/proc/mobject/session/session-service-access-test.cpp
                                    +++ b/tests/components/proc/mobject/session/session-service-access-test.cpp
                                    @@ -48,6 +48,11 @@ namespace test    {
                                       
                                       namespace { // what follows is a simulated (simplified) version
                                                  //  of the complete Session + SessionManager setup.....
                                    +  
                                    +//    using boost::noncopyable;
                                    +//    using session::SessionServices;
                                    +    using lumiera::typelist::Types;
                                    +    
                                         
                                         
                                         /* === Interface level === */
                                    @@ -73,6 +78,23 @@ namespace test    {
                                           };
                                         
                                         
                                    +    /* === Service level API === */
                                    +    
                                    +    struct InternalAPI_1
                                    +      {
                                    +        virtual ~InternalAPI_1() {}
                                    +        virtual uint getMagic()     =0;
                                    +        
                                    +        static InternalAPI_1& access();
                                    +      };
                                    +    
                                    +    struct InternalAPI_2
                                    +      {
                                    +        static void invokeImplementationService();
                                    +      };
                                    +    
                                    +    
                                    +    
                                         /* === Implementation level === */
                                         
                                         struct TSessionImpl : TSession
                                    @@ -86,50 +108,79 @@ namespace test    {
                                             void implementationService() ;
                                             
                                             /* ==== internals ==== */
                                    -        TSessionImpl()
                                    -          {
                                    -            ++magic_;
                                    -            cout << "creating new Session " << magic_ << endl;
                                    -          }
                                             
                                    -        operator string() const
                                    +        TSessionImpl();
                                    +        operator string() const;
                                    +      };
                                    +    
                                    +    
                                    +    
                                    +    template
                                    +    struct ServiceAccessPoint;
                                    +    
                                    +    template
                                    +    struct ServiceAccessPoint
                                    +      : IMPL
                                    +      , InternalAPI_1
                                    +      {
                                    +        uint
                                    +        getMagic ()
                                               {
                                    -            return string("Session-Impl(")
                                    -                 + lexical_cast(magic_)
                                    -                 + ")"; 
                                    +            return IMPL::magic_;
                                               }
                                           };
                                         
                                    -    inline ostream&
                                    -    operator<< (ostream& os, TSessionImpl const& simpl)
                                    +    template
                                    +    struct ServiceAccessPoint
                                    +      : IMPL
                                           {
                                    -        return os << string(simpl);
                                    -      }
                                    +        void
                                    +        forwardServiceInvocation()
                                    +          {
                                    +            IMPL::implementationService();
                                    +          }
                                    +      };
                                         
                                    -    void
                                    -    TSessionImpl::externalOperation()
                                    +    template< typename IMPS
                                    +            , class FRONT
                                    +            , class SESS
                                    +            >
                                    +    class SessionServices
                                    +      : public InstantiateChained
                                           {
                                    -        cout << *this << "::externalOperation()" << endl;
                                    -      }
                                    +      public:
                                    +        
                                    +        static FRONT& current;
                                    +        
                                    +        template
                                    +        API&
                                    +        get()
                                    +          {
                                    +            return *this;
                                    +          }
                                    +      };
                                    +      
                                    +      
                                    +    /* === storage and basic configuration === */
                                         
                                    -    /* ==== Implementation level API ==== */
                                    -    void
                                    -    TSessionImpl::implementationService()
                                    -      {
                                    -        cout << *this << "::implementationService()" << endl;
                                    -      }
                                    +    struct TSessManagerImpl;
                                    +    
                                    +    typedef SessionServices< Types
                                    +                           , TSessManagerImpl
                                    +                           , TSessionImpl
                                    +                           > SessionImplAPI;
                                         
                                         
                                         
                                         struct TSessManagerImpl : TSessManager
                                           {
                                    -        scoped_ptr pImpl_;
                                    +        scoped_ptr pImpl_;
                                             
                                             TSessManagerImpl()
                                               : pImpl_(0)
                                               { }
                                             
                                    -        TSessionImpl*
                                    +        SessionImplAPI*
                                             operator-> ()
                                               {
                                                 if (!pImpl_)
                                    @@ -142,18 +193,72 @@ namespace test    {
                                             void
                                             reset ()
                                               {
                                    -            scoped_ptr tmpS (new TSessionImpl);
                                    +            scoped_ptr tmpS (new SessionImplAPI);
                                                 pImpl_.swap (tmpS);
                                               }
                                           };
                                         
                                         
                                    -    /* === storage and basic configuration === */
                                    -    
                                         uint TSessionImpl::magic_;
                                         
                                         TSessManager& TSession::current = Singleton()();
                                    -                                    //note: comes up already during static initialisation
                                    +                                     //note: already during static initialisation
                                    +
                                    +    template<>
                                    +    TSessManagerImpl& SessionImplAPI::current = static_cast (TSession::current);
                                    +    
                                    +      
                                    +      
                                    +    /* === Implementation of service access === */
                                    +    
                                    +    InternalAPI_1&
                                    +    InternalAPI_1::access()
                                    +    {
                                    +      return SessionImplAPI::current->get();
                                    +    }
                                    +    
                                    +    void
                                    +    InternalAPI_2::invokeImplementationService()
                                    +    {
                                    +      SessionImplAPI::current->forwardServiceInvocation();
                                    +    }
                                    +    
                                    +    
                                    +
                                    +    
                                    +    /* === Implementation of Session internals === */
                                    +      
                                    +    inline ostream&
                                    +    operator<< (ostream& os, TSessionImpl const& simpl)
                                    +    {
                                    +      return os << string(simpl);
                                    +    }
                                    +    
                                    +    TSessionImpl::operator string() const
                                    +    {
                                    +      return string("Session-Impl(")
                                    +           + lexical_cast(magic_)
                                    +           + ")"; 
                                    +    }
                                    +    
                                    +    TSessionImpl::TSessionImpl()
                                    +    {
                                    +      ++magic_;
                                    +      cout << "creating new Session " << magic_ << endl;
                                    +    }
                                    +    
                                    +    void
                                    +    TSessionImpl::externalOperation()
                                    +    {
                                    +      cout << *this << "::externalOperation()" << endl;
                                    +    }
                                    +    
                                    +    /* ==== Implementation level API ==== */
                                    +    inline void
                                    +    TSessionImpl::implementationService()
                                    +    {
                                    +      cout << *this << "::implementationService()" << endl;
                                    +    }
                                         
                                         
                                       } // (END) simulated session management
                                    @@ -180,7 +285,7 @@ namespace test    {
                                             {
                                               access_defaultSession();
                                               make_newSession();
                                    -          invoke_implService();
                                    +          invoke_implServices();
                                             } 
                                           
                                           
                                    @@ -201,9 +306,13 @@ namespace test    {
                                           
                                           
                                           void
                                    -      invoke_implService ()
                                    +      invoke_implServices ()
                                             {
                                    -          ///////////////////////////////TODO
                                    +          cout << "current Session-Impl-ID = " << InternalAPI_1::access().getMagic() << endl;
                                    +          InternalAPI_2::invokeImplementationService();
                                    +          
                                    +          TSession::current.reset();
                                    +          InternalAPI_2::invokeImplementationService();  // invocation creates new session as side effect
                                             }
                                           
                                           
                                    diff --git a/tests/lib/meta/generator-test.cpp b/tests/lib/meta/generator-test.cpp
                                    index 36a98b7a6..1726fc8ee 100644
                                    --- a/tests/lib/meta/generator-test.cpp
                                    +++ b/tests/lib/meta/generator-test.cpp
                                    @@ -56,7 +56,7 @@ namespace test {
                                           struct Block
                                             {
                                               static string name;
                                    -          string talk()   { return name+"::eat(..)"; }  
                                    +          string talk()   { return "__"+name+"__"; }  
                                             };
                                           
                                           
                                    @@ -85,7 +85,7 @@ namespace test {
                                               DoIt ()         { cout << "ctor DoIt<"<< X::name << " >\n";}
                                               virtual ~DoIt() { cout << "dtor DoIt<"<< X::name << " >\n";}
                                             public:
                                    -          void eat (X& x) { cout << x.talk() << "\n";}
                                    +          void eat (X& x) { cout << "devouring" << x.talk() << "\n";}
                                               using BASE::eat; // prevent shadowing
                                             };
                                           
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 2e2252f1e..843f37345 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -4021,12 +4021,12 @@ It will contain a global video and audio out pipe, just one timeline holding a s
                                     &rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
                                     
                                    -
                                    +
                                    Within Lumiera's Proc-Layer, there are some implementation facilities and subsystems needing more specialised access to implementation services provided by the session. Thus, besides the public SessionInterface and the [[lifecycle and state management API|SessionManager]], there are some additional service interfaces exposed by the session through a special access mechanism. This mechanism needs to be special in order to assure clean transactional behaviour when the session is opened, closed, cleared or loaded. Of course, there is the additional requirement to avoid direct dependencies of the mentioned Proc internals on session implementation details.
                                     
                                     !Accessing session services
                                     For each of these services, there is an access interface, usually through an class with only static methods. Basically this means access //by name.//
                                    -On the //implementation side//&nbsp; of this access interface class (i.e. within a {{{*.cpp}}} file separate from the client code), there is a (down-casting) access through the top-level session-~PImpl pointer, which is then forwarded through another {{{operator->()}}} on the ~SessionImpl class finally to reach an ~SessionServices instance, owned and managed by ~SessionImpl. This ~SessionServices instance is configured (statically) to mix in implementations for all the exposed service interfaces. Thus, the implementaion of the access functions (to the session service we're discussing here) can use this forwarding mechanism (which technically is located as a static function on class ~SessionServices) to get the actual implementation basically by one-liners. The upside of this (admittedly convoluted) technique is that we've gotten at runtime only a single indirection, which moreover is through the top-level session-~PImpl. The downside is that, due to the separation in {{{*.h}}} and {{{*.c}}} files, we can't use any specifically typed generic operations, which forces us to use type erasure in case we need such (an example being the content discovery queries utilised by all high-level model objects).
                                    +On the //implementation side//&nbsp; of this access interface class (i.e. within a {{{*.cpp}}} file separate from the client code), there is a (down-casting) access through the top-level session-~PImpl pointer, allowing to invoke functions on the ~SessionServices instance. Actually, this ~SessionServices instance is configured (statically) to stack up implementations for all the exposed service interfaces on top of the basic ~SessionImpl class. Thus, each of the individual service implementations is able to use the basic ~SessinImpl (becaus it inherits it) and the implementaion of the access functions (to the session service we're discussing here) is able to use this forwarding mechanism to get the actual implementation basically by one-liners. The upside of this (admittedly convoluted) technique is that we've gotten at runtime only a single indirection, which moreover is through the top-level session-~PImpl. The downside is that, due to the separation in {{{*.h}}} and {{{*.c}}} files, we can't use any specifically typed generic operations, which forces us to use type erasure in case we need such (an example being the content discovery queries utilised by all high-level model objects).
                                    The frontside interface of the session allows to query for contained objects; it is used to discover the structure and contents of the currently opened session/project. Access point is the public API of the Session class, which, besides exposing those queries, also provides functionality for adding and removing session contents.
                                    
                                    From 79d5e49a749c1b6f7d9ef993241dd83b8a179f51 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Mon, 9 Nov 2009 05:21:59 +0100
                                    Subject: [PATCH 060/377] defined basic session lifecycle and service access.
                                     Closes Ticket #400
                                    
                                    ---
                                     src/proc/mobject/session.hpp                  |   1 +
                                     src/proc/mobject/session/session-impl.hpp     |   1 +
                                     src/proc/mobject/session/session-services.cpp |  34 ++++++
                                     src/proc/mobject/session/session-services.hpp |  91 +++++++++++---
                                     src/proc/mobject/session/session.cpp          |  13 +-
                                     tests/40components.tests                      |   6 +-
                                     tests/43session.tests                         |  13 +-
                                     .../session/session-service-access-test.cpp   | 112 +++++++++++-------
                                     wiki/renderengine.html                        |  30 ++++-
                                     9 files changed, 234 insertions(+), 67 deletions(-)
                                     create mode 100644 src/proc/mobject/session/session-services.cpp
                                    
                                    diff --git a/src/proc/mobject/session.hpp b/src/proc/mobject/session.hpp
                                    index 5e46e97a0..e15eb78a1 100644
                                    --- a/src/proc/mobject/session.hpp
                                    +++ b/src/proc/mobject/session.hpp
                                    @@ -114,6 +114,7 @@ namespace mobject {
                                       
                                       extern const char* ON_SESSION_START;  ///< triggered before loading any content into a newly created session
                                       extern const char* ON_SESSION_INIT;   ///< triggered when initialising a new session, after adding content
                                    +  extern const char* ON_SESSION_READY;  ///< triggered after session is completely functional and all APIs are open.
                                       extern const char* ON_SESSION_END;    ///< triggered before discarding an existing session
                                       
                                       
                                    diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp
                                    index 7b36f6887..5740a4424 100644
                                    --- a/src/proc/mobject/session/session-impl.hpp
                                    +++ b/src/proc/mobject/session/session-impl.hpp
                                    @@ -89,6 +89,7 @@ namespace session {
                                       /**
                                        * Session manager implementation class holding the
                                        * actual smart pointer to the current Session impl.
                                    +   * @todo couldn't this be pushed down into session.cpp?
                                        */
                                       class SessManagerImpl : public SessManager
                                         {
                                    diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp
                                    new file mode 100644
                                    index 000000000..624666eb7
                                    --- /dev/null
                                    +++ b/src/proc/mobject/session/session-services.cpp
                                    @@ -0,0 +1,34 @@
                                    +/*
                                    +  SessionServices  -  accessing Proc-Layer internal session implementation services
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2008,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +#include "proc/mobject/session/session-services.hpp"
                                    +#include "proc/mobject/session/session-impl.hpp"
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +  
                                    +  /** TODO */
                                    +  
                                    +  
                                    +  
                                    +}} // namespace mobject::session
                                    diff --git a/src/proc/mobject/session/session-services.hpp b/src/proc/mobject/session/session-services.hpp
                                    index 1c944094e..a71e5664a 100644
                                    --- a/src/proc/mobject/session/session-services.hpp
                                    +++ b/src/proc/mobject/session/session-services.hpp
                                    @@ -23,8 +23,52 @@
                                     
                                     /** @file session-services.hpp
                                      ** A mechanism for exposing and accessing implementation level
                                    - ** services of the session. 
                                    - ** TODO TODO
                                    + ** services of the session. While any client code should always
                                    + ** use the public Session API, some implementation level facilities
                                    + ** within Proc-Layer need to cooperate with a wider SessionImpl API.
                                    + ** On the other hand, we don't want to create coupling between the
                                    + ** mentioned Proc internals and the session implementation. Another
                                    + ** concern addressed by this mechanism is to assure consistency
                                    + ** across all those implementation APIs. New APIs can be added
                                    + ** just by extending a template definition and will automatically
                                    + ** participate in the session management mechanisms, because any
                                    + ** access is routed through the top level Session PImpl.
                                    + ** 
                                    + ** \par structure of session implementation-level services
                                    + ** 
                                    + ** Assumed any part of the Proc implementation needs to cooperate
                                    + ** with the session implementation; the necessary link has to be
                                    + ** abstracted into an implementation level API. Typically, this
                                    + ** API provides an static access function, which is to be implemented
                                    + ** "somewhere else", so the Proc implementation isn't required to 
                                    + ** include anything of the session implementation level
                                    + ** 
                                    + ** In order to actually provide such a service, an specialisation of
                                    + ** the ServiceAccessPoint template has to be defined, which may mix in
                                    + ** the service API and implement it directly on top of SessionImpl.
                                    + ** Note, mixing in the API isn't required -- alternatively the API might
                                    + ** be completely bridged through the mentioned static access functions
                                    + ** (i.e. such would be kind of an generic API, relying on convention
                                    + ** rather than on a vtable)
                                    + ** 
                                    + ** When the SessManagerImpl creates the concrete session object,
                                    + ** it doesn't use the bare SessionImpl class; rather, an inheritance
                                    + ** chain is formed, starting with SessionImpl and stacking any of the
                                    + ** configured ServiceAccessPoint instantiations on top of it. Thus,
                                    + ** the public session access gets the concrete implementation of the
                                    + ** Session API (through the vtable), while any service level access
                                    + ** can use the corresponding service API directly. Service APIs have
                                    + ** to care to avoid name clashes though.
                                    + ** 
                                    + ** The implementation of all the service API access functions is
                                    + ** bundled within session-service.cpp -- where the full compound
                                    + ** of SessionImpl and the ServiceAccessPoint specialisations has
                                    + ** to be visible.
                                    + ** 
                                    + ** @see session-service-access-test.cpp simplified inline demo definition of this setup
                                    + ** @see session.hpp public session API
                                    + ** @see session-impl.hpp definition of ServiceAccessPoint specialisations
                                    + ** @see session-impl.cpp session implementation internals
                                      **
                                      */
                                     
                                    @@ -35,24 +79,25 @@
                                     #include "proc/mobject/session.hpp"
                                     #include "lib/meta/generator.hpp"
                                     
                                    -//#include 
                                    -//#include 
                                    -
                                     
                                     
                                     
                                     namespace mobject {
                                     namespace session {
                                       
                                    -//using std::vector;
                                    -//using boost::scoped_ptr;
                                    -//using std::tr1::shared_ptr;
                                       using lumiera::typelist::InstantiateChained;
                                       using lumiera::typelist::InheritFrom;
                                       using lumiera::typelist::NullType;
                                       
                                       
                                    -  
                                    +  /**
                                    +   * Access point to a single implementation-level API.
                                    +   * For each concrete service to provide, an specialisation
                                    +   * of this template is assumed to exist which inherits from
                                    +   * IMPL; it will be used in an inheritance-chain on top of
                                    +   * SessionImpl and thus can access the latter (= session
                                    +   * implementation API) just through its parent class IMPL
                                    +   */
                                       template
                                       struct ServiceAccessPoint;
                                       
                                    @@ -62,16 +107,32 @@ namespace session {
                                        * to provide by the Session. An instance of this template
                                        * is created on top of SessionImpl, configured such as
                                        * to inherit from all the concrete services to be
                                    -   * exposed for use by Proc-Lyer's internals. 
                                    +   * exposed for use by Proc-Lyer's internals.
                                    +   * 
                                    +   * @param APIS  sequence of API types to implement
                                    +   * @param FRONT type of the frontend used for access
                                    +   * @param SESS  the basic session implementation 
                                        */
                                    -  template< typename IMPS
                                    +  template< typename APIS
                                               , class FRONT
                                    -          , class BA =NullType
                                    +          , class SESS
                                               >
                                    -  class SessionServicesX
                                    -    : public InstantiateChained
                                    +  class TSessionServices
                                    +    : public InstantiateChained< typename APIS::List    // for each of the API types...
                                    +                               , ServiceAccessPoint    //  instantiate a service implementation
                                    +                               , SESS                 //   and stack all these on top of SessionImpl
                                    +                               >
                                         {
                                    -      static FRONT& entrance_;
                                    +    public:
                                    +      static FRONT& current;                      ///< intended to be hard-wired to SessManagerImpl singleton 
                                    +      
                                    +      /** access an service by explicit downcast.
                                    +       *  @warning this function is dangerous; never store the
                                    +       *           returned reference, as the referred object 
                                    +       *           might go away due to session close/reset/load
                                    +       */
                                    +      template
                                    +      API& get() { return *this; }
                                         };
                                       
                                       
                                    diff --git a/src/proc/mobject/session/session.cpp b/src/proc/mobject/session/session.cpp
                                    index 317c8ef3b..d0b6a6b2e 100644
                                    --- a/src/proc/mobject/session/session.cpp
                                    +++ b/src/proc/mobject/session/session.cpp
                                    @@ -53,7 +53,7 @@ namespace mobject {
                                        * 
                                        *  Consequently, if you want to talk to the session manager,
                                        *  you use dot-notation, while you access the session object
                                    -   *  via arrow notaion (e.g. \code Session::current->getFixture() )
                                    +   *  via arrow notation (e.g. \code Session::current->getFixture() )
                                        */
                                       SessManager& Session::current = Singleton()();
                                       
                                    @@ -79,6 +79,17 @@ namespace mobject {
                                        */
                                       const char* ON_SESSION_INIT ("ON_SESSION_INIT");
                                       
                                    +  /** \par
                                    +   *  LifecycleHook, to perform post loading tasks, requiring an already completely usable
                                    +   *  and configured session to be in place. When activated, the session is completely restored
                                    +   *  according to the standard or persisted definition and any access interfaces are already
                                    +   *  opened and enabled. Scripts and the GUI might even be accessing the session in parallel.
                                    +   *  Subsystems intending to perform additional processing should register here, if requiring
                                    +   *  fully functional client side APIs. Examples would be statistics gathering, validation
                                    +   *  or auto-correction of the session's contents.
                                    +   */
                                    +  const char* ON_SESSION_READY ("ON_SESSION_READY");
                                    +  
                                       /** \par
                                        *  LifecycleHook, to perform any state saving, deregistration or de-activation necessary 
                                        *  before bringing down an existing session. When invoked, the session is still fully valid
                                    diff --git a/tests/40components.tests b/tests/40components.tests
                                    index ccaa911c8..adc44631e 100644
                                    --- a/tests/40components.tests
                                    +++ b/tests/40components.tests
                                    @@ -561,9 +561,9 @@ out: ctor DoIt >
                                     out: ctor DoIt >
                                     out: ctor DoIt >
                                     out: ctor DoIt >
                                    -out: Block< 2>::eat\(..\)
                                    -out: Block< 5>::eat\(..\)
                                    -out: Block<13>::eat\(..\)
                                    +out: devouring__Block< 2>__
                                    +out: devouring__Block< 5>__
                                    +out: devouring__Block<13>__
                                     out: gulp!
                                     out: dtor DoIt >
                                     out: dtor DoIt >
                                    diff --git a/tests/43session.tests b/tests/43session.tests
                                    index 5c9b256b0..fd3f0b3db 100644
                                    --- a/tests/43session.tests
                                    +++ b/tests/43session.tests
                                    @@ -99,7 +99,18 @@ PLANNED "SessionManager_test" SessionManager_test <
                                     #include 
                                     #include 
                                     #include 
                                     
                                    -//using boost::format;
                                    -  using lib::Singleton;
                                    -  using boost::lexical_cast;
                                    -  using std::ostream;
                                    -  using std::string;
                                    -  using std::cout;
                                    -  using std::endl;
                                    -
                                     
                                     namespace mobject {
                                     namespace session {
                                     namespace test    {
                                       
                                    +  using lib::Singleton;
                                    +  using boost::lexical_cast;
                                    +  using std::ostream;
                                    +  using std::string;
                                    +  using std::cout;
                                    +  using std::endl;
                                    +  
                                       
                                       namespace { // what follows is a simulated (simplified) version
                                                  //  of the complete Session + SessionManager setup.....
                                       
                                    -//    using boost::noncopyable;
                                    -//    using session::SessionServices;
                                         using lumiera::typelist::Types;
                                    +    using lumiera::typelist::InstantiateChained;
                                         
                                         
                                         
                                    -    /* === Interface level === */
                                    +    /* === Interface level === */                              //----------------corresponding-to-session.hpp
                                         
                                         struct TSessManager;
                                         typedef TSessManager& PSess;
                                    @@ -78,7 +73,9 @@ namespace test    {
                                           };
                                         
                                         
                                    -    /* === Service level API === */
                                    +    
                                    +    
                                    +    /* === Service level API === */                            //----------------internal-API-definition-headers
                                         
                                         struct InternalAPI_1
                                           {
                                    @@ -95,7 +92,7 @@ namespace test    {
                                         
                                         
                                         
                                    -    /* === Implementation level === */
                                    +    /* === Implementation level === */                         //----------------corresponding-to-session-impl.hpp
                                         
                                         struct TSessionImpl : TSession
                                           {
                                    @@ -116,10 +113,10 @@ namespace test    {
                                         
                                         
                                         template
                                    -    struct ServiceAccessPoint;
                                    +    struct TServiceAccessPoint;
                                         
                                         template
                                    -    struct ServiceAccessPoint
                                    +    struct TServiceAccessPoint
                                           : IMPL
                                           , InternalAPI_1
                                           {
                                    @@ -131,7 +128,7 @@ namespace test    {
                                           };
                                         
                                         template
                                    -    struct ServiceAccessPoint
                                    +    struct TServiceAccessPoint
                                           : IMPL
                                           {
                                             void
                                    @@ -145,8 +142,8 @@ namespace test    {
                                                 , class FRONT
                                                 , class SESS
                                                 >
                                    -    class SessionServices
                                    -      : public InstantiateChained
                                    +    class TSessionServices
                                    +      : public InstantiateChained
                                           {
                                           public:
                                             
                                    @@ -159,16 +156,19 @@ namespace test    {
                                                 return *this;
                                               }
                                           };
                                    -      
                                    -      
                                    -    /* === storage and basic configuration === */
                                    +    
                                    +    
                                    +    
                                    +    
                                    +    
                                    +    /* === storage and basic session manager configuration === */
                                         
                                         struct TSessManagerImpl;
                                         
                                    -    typedef SessionServices< Types
                                    -                           , TSessManagerImpl
                                    -                           , TSessionImpl
                                    -                           > SessionImplAPI;
                                    +    typedef TSessionServices< Types
                                    +                            , TSessManagerImpl
                                    +                            , TSessionImpl
                                    +                            > SessionImplAPI;
                                         
                                         
                                         
                                    @@ -203,13 +203,18 @@ namespace test    {
                                         
                                         TSessManager& TSession::current = Singleton()();
                                                                          //note: already during static initialisation
                                    -
                                    +    
                                         template<>
                                         TSessManagerImpl& SessionImplAPI::current = static_cast (TSession::current);
                                         
                                    -      
                                    -      
                                    -    /* === Implementation of service access === */
                                    +    
                                    +    
                                    +    
                                    +    
                                    +    
                                    +    
                                    +    
                                    +    /* === Implementation of service access === */             //----------------corresponding-to-session-services.cpp
                                         
                                         InternalAPI_1&
                                         InternalAPI_1::access()
                                    @@ -224,9 +229,10 @@ namespace test    {
                                         }
                                         
                                         
                                    -
                                         
                                    -    /* === Implementation of Session internals === */
                                    +    
                                    +    
                                    +    /* === Implementation of Session internals === */          //----------------corresponding-to-session-impl.cpp
                                           
                                         inline ostream&
                                         operator<< (ostream& os, TSessionImpl const& simpl)
                                    @@ -267,14 +273,18 @@ namespace test    {
                                       
                                       
                                       
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                       /*******************************************************************************
                                    -   * Verify the access mechanism used by Proc-Layer internals for 
                                    -   * accessing implementation level APIs of the session.
                                    +   * Verify the access mechanism both to the pubic session API and
                                    +   * to implementation level APIs used by Proc-Layer internals.
                                    +   * 
                                    +   * Actually, this test uses a simulated setup of the real session,
                                    +   * complete with interfaces, implementation and session manager frontend.
                                        * 
                                    -   * Actually, this test uses setup of the real session,
                                    -   * complete with interfaces, implementation and a
                                    -   * session manager frontend.
                                    -   *
                                        * @see session-impl.hpp the real thing
                                        * @see SessionServices; 
                                        */
                                    @@ -289,6 +299,10 @@ namespace test    {
                                             } 
                                           
                                           
                                    +      /** @test accessing an non-existing session
                                    +       *        causes creation of a new TSessionImpl instance.
                                    +       *        After that, the public API function gets invoked. 
                                    +       */
                                           void
                                           access_defaultSession ()
                                             {
                                    @@ -297,6 +311,10 @@ namespace test    {
                                             }
                                           
                                           
                                    +      /** @test invoking the management API to close the session.
                                    +       *        The next public API invocation will create
                                    +       *        a new TSessionImpl instance. 
                                    +       */
                                           void
                                           make_newSession ()
                                             {
                                    @@ -305,17 +323,23 @@ namespace test    {
                                             }
                                           
                                           
                                    +      /** example of an one-liner, as it might be used
                                    +       *  internally by implementation code within Proc-Layer */
                                    +      uint magic() { return InternalAPI_1::access().getMagic(); }
                                    +      
                                    +      /** @test accessing implementation-level APIs */
                                           void
                                           invoke_implServices ()
                                             {
                                    -          cout << "current Session-Impl-ID = " << InternalAPI_1::access().getMagic() << endl;
                                    +          cout << "current Session-Impl-ID = " << magic() << endl;
                                               InternalAPI_2::invokeImplementationService();
                                               
                                    +          cout << "now resetting this session." << endl;
                                               TSession::current.reset();
                                    +          
                                               InternalAPI_2::invokeImplementationService();  // invocation creates new session as side effect
                                    +          cout << "current Session-Impl-ID = " << magic() << endl;
                                             }
                                    -      
                                    -      
                                         };
                                       
                                       
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 843f37345..9f66340c8 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3950,9 +3950,9 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl
                                     
                                     {{red{WIP ... just emerging}}}
                                    -
                                    +
                                    The current [[Session]] is the root of any state found within Proc-Layer. Thus, events defining the session's lifecycle influence and synchronise the cooperative behaviour of the entities within the model, the ProcDispatcher, [[Fixture]] and any facility below.
                                    -* when ''starting'', by default an empty session is created, which puts any related facility into a defined initial state.
                                    +* when ''starting'', on first access an empty session is created, which puts any related facility into a defined initial state.
                                     * when ''closing'' the session, any dependent facilities are disabled, disconnected, halted or closed
                                     * ''loading'' an existing session &mdash; after closing the previous session &mdash; sets up an empty (default) session an populates it with de-serialised content.
                                     * when encountering a ''mutation point'', [[command processing|ProcDispatcher]] is temporarily halted to trigger off an BuildProcess.
                                    @@ -3963,10 +3963,34 @@ The SessionManager is responsible for conducting the session lifecycle. Accessib
                                     !Synchronising access to session's implementation facilities
                                     Some other parts and subsystems within the ~Proc-Layer need specialised access to implementation facilities within the session. Informations about some conditions and configurations might be retrieved through [[querrying the session|Query]], and especially default configurations for many objects are [[bound to the session|DefaultsImplementation]]. The [[discovery of session contents|SessionStructureQuery]] relies on an [[index facility|PlacementIndex]] embedded within the session implementation. Moreover, some "properties" of the [[media objects|MObject]] are actually due to the respective object being [[placed|Placement]] in some way into the session; consequently, there might be an dependency on the actual [[location as visible to the placement|PlacementScope]], which in turn is constituted by [[querying the index|QueryFocus]].
                                     
                                    -Each of these facilities relies on a separate access point to session services, corresponding to distinct service interfaces. But &mdash; on the implementation side &mdash; all these services are provided by a (compound) implementation object. This approach allows to switch the actual implementation of all these services instantaneous by swapping the ~PImpl maintained by the session manager.
                                    +Each of these facilities relies on a separate access point to session services, corresponding to distinct service interfaces. But &mdash; on the implementation side &mdash; all these services are provided by a (compound) SessionServices implementation object. This approach allows to switch the actual implementation of all these services simply by swapping the ~PImpl maintained by the session manager. A new implementation level service can thus be added to the ~SessionImpl just by hooking it into the ~SessionServices compound object. But note, this mechanism as such is ''not thread safe'', unless the //implementation// of the invoked functions is synchronised in some way to prevent switching to a new session implementation while another thread is still executing session implementation code.
                                    +
                                    +Currently, the understanding is for some global mechanism to hold any command execution, script running and further object access by the GUI //prior//&nbsp; to invoking any of the session management operations (loading, closing, resetting). An alternative would be to change the top-level access to the session ~PImpl to go through an accessor value object, to acquire some lock automatically before any access can happen. C++ ensures the lifespan of any temporaries to surpass evaluation of the enclosing expression, which would be sufficient to prevent another thread to pull away the session during that timespan. Of course, any value returned from such an session API call isn't covered by this protection. Usually, objects are handed out as MObjectRef, which in turn means to resolve them (automatically) on dereferentiation by another session API access. But while it seems we could get locking to work automatically this way, still such a technique seems risky and involved; a plain flat lock at top level seems to be more appropriate.
                                     
                                     !Interface and lifecycle hooks
                                     {{red{draft as of 11/09}}}
                                    +As detailed above, {{{Session::current}}} exposes the management / lifecycle API, and at the same time can be dereferenced into the primary [[session API|SessionInterface]]. An default configured ~SessionImpl instance will be built automatically, in case no session implementation instance exists on executing this dereferentiation.
                                    +
                                    +!!!building (or loading) a session
                                    +# as a preparation step, a new implementation instance is created, alongside with any supporting facilities (especially the PlacementIndex)
                                    +# the basic default configuration is loaded into this new session instance
                                    +# when the new session is (technically) complete and usable, the switch on the ~PImpl happens
                                    +# the {{{ON_SESSION_START}}} LifecycleEvent is emitted
                                    +# content is loaded into the session, including hard wired content and any de-serialised data from persistent storage
                                    +# the {{{ON_SESSION_INIT}}} event is emitted
                                    +# additional initialisation, wiring and registration takes place; basically anything to make the session fully functional
                                    +# the session LayerSeparationInterface is opened and any further top-level blocking is released
                                    +# the {{{ON_SESSION_READY}}} event is emitted
                                    +
                                    +!!!closing the session
                                    +# top-level facilities accessing the session (GUI, command processing, scripts) are blocked and the LayerSeparationInterface is closed
                                    +# any render processes are ensured to be terminated
                                    +# the {{{ON_SESSION_END}}} event is emitted
                                    +# the command processing log is tagged
                                    +# the command queue(s) are emptied, discarding any commands not yet executed
                                    +# the PlacementIndex is cleared, effectively releasing any object "instances"
                                    +# the [[asset registry|AssetManager]] is cleared, thereby releasing any remaining external resource references
                                    +# destruction of session implementation instances
                                     
                                    From 7da8844581c6d6ebf89455243cbe6ea36144fef0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 9 Nov 2009 07:35:08 +0100 Subject: [PATCH 061/377] first steps towards using the new SessionServices access mechanism add the necessary hooks and change the SessionImpl accordingly. Still using the old access method for any real code --- src/proc/mobject/placement-ref.hpp | 6 +- src/proc/mobject/session.hpp | 2 +- src/proc/mobject/session/defsmanager.hpp | 5 +- .../placement-index-query-resolver.hpp | 180 +++--------------- .../mobject/session/sess-manager-impl.cpp | 9 +- src/proc/mobject/session/session-impl.cpp | 17 +- src/proc/mobject/session/session-impl.hpp | 91 ++++++++- .../session/session-service-defaults.hpp | 59 ++++++ .../session/session-service-explore-scope.hpp | 71 +++++++ .../mobject/session/session-service-fetch.hpp | 64 +++++++ .../session/session-service-mock-index.hpp | 62 ++++++ src/proc/mobject/session/session-services.cpp | 17 ++ src/proc/mobject/session/session-services.hpp | 5 +- src/proc/mobject/session/session.cpp | 10 + 14 files changed, 418 insertions(+), 180 deletions(-) create mode 100644 src/proc/mobject/session/session-service-defaults.hpp create mode 100644 src/proc/mobject/session/session-service-explore-scope.hpp create mode 100644 src/proc/mobject/session/session-service-fetch.hpp create mode 100644 src/proc/mobject/session/session-service-mock-index.hpp diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp index 73af653e8..0d0f8da63 100644 --- a/src/proc/mobject/placement-ref.hpp +++ b/src/proc/mobject/placement-ref.hpp @@ -197,7 +197,11 @@ namespace mobject { return false; } - ExplicitPlacement resolve() const { return access(id_).resolve();} + ExplicitPlacement + resolve() const + { + return access(id_).resolve(); + } ////////////////TODO more operations to come.... diff --git a/src/proc/mobject/session.hpp b/src/proc/mobject/session.hpp index e15eb78a1..29b1248ac 100644 --- a/src/proc/mobject/session.hpp +++ b/src/proc/mobject/session.hpp @@ -97,7 +97,7 @@ namespace mobject { public: static session::SessManager& current; - session::DefsManager& defaults; + session::DefsManager& defaults; ///////////////TODO this is a hack... better solve it based on the new SessionServices mechanism virtual bool isValid () = 0; virtual void add (PMO& placement) = 0; diff --git a/src/proc/mobject/session/defsmanager.hpp b/src/proc/mobject/session/defsmanager.hpp index a223a17e8..30aea7fff 100644 --- a/src/proc/mobject/session/defsmanager.hpp +++ b/src/proc/mobject/session/defsmanager.hpp @@ -57,12 +57,9 @@ namespace mobject { { scoped_ptr defsRegistry; - protected: + public: DefsManager () throw(); - friend class SessManagerImpl; - - public: ~DefsManager (); /** common access point: retrieve the default object fulfilling diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index 4ad794227..0061f801e 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -1,5 +1,5 @@ /* - PLACEMENT-INDEX.hpp - tracking individual Placements and their relations + PLACEMENT-INDEX-QUERY-RESOLVER.hpp - using PlacementIndex to resolve scope queries Copyright (C) Lumiera.org 2009, Hermann Vosseler @@ -21,7 +21,8 @@ */ -/** @file placement-index.hpp +/** @file placement-index-query-resolver.hpp + ** TODO WIP-WIP ** ** @see PlacementRef ** @see PlacementIndex_test @@ -30,182 +31,45 @@ -#ifndef MOBJECT_PLACEMENT_INDEX_H -#define MOBJECT_PLACEMENT_INDEX_H +#ifndef MOBJECT_SESSION_PLACEMENT_INDEX_QUERY_RESOLVER_H +#define MOBJECT_SESSION_PLACEMENT_INDEX_QUERY_RESOLVER_H //#include "pre.hpp" //#include "proc/mobject/session/locatingpin.hpp" //#include "proc/asset/pipe.hpp" -#include "lib/util.hpp" -#include "lib/factory.hpp" -#include "proc/mobject/placement.hpp" -#include "proc/mobject/placement-ref.hpp" +//#include "lib/util.hpp" +//#include "lib/factory.hpp" +//#include "proc/mobject/placement.hpp" +#include "proc/mobject/session/placement-index.hpp" #include "proc/mobject/session/query-resolver.hpp" -#include -#include -#include -#include +//#include +//#include +//#include +//#include namespace mobject { - class MObject; +// class MObject; /////////////////////////////////////???? namespace session { - using lib::factory::RefcountFac; - using std::tr1::shared_ptr; - using boost::scoped_ptr; - using std::vector; +// using lib::factory::RefcountFac; +// using std::tr1::shared_ptr; +// using boost::scoped_ptr; +// using std::vector; /** + * TODO type comment */ - class PlacementIndex - : public session::QueryResolver ////////TODO: really inherit here? -// , boost::noncopyable ////////TODO : where to put the "noncopyable" base + class PlacementIndexQueryResolver + : public session::QueryResolver { - class Table; - - scoped_ptr
                                    pTab_; - - public: - typedef Placement PlacementMO; - typedef PlacementRef PRef; - typedef PlacementMO::ID const& ID; - - typedef session::Goal::QueryID const& QID; - - - PlacementMO& find (ID) const; - - template - Placement& find (PlacementMO::Id) const; - template - Placement& find (PlacementRef const&) const; - - PlacementMO& getScope (PlacementMO const&) const; - PlacementMO& getScope (ID) const; - - vector getReferrers (ID) const; - - - /** retrieve the logical root scope */ - PlacementMO& getRoot() const; - - size_t size() const; - bool contains (PlacementMO const&) const; - bool contains (ID) const; - -////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper - template - typename session::Query >::iterator - query (PlacementMO& scope) const; - - operator string() const { return "PlacementIndex"; } -////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper - - - bool canHandleQuery(QID) const; - - - /* == mutating operations == */ - - ID insert (PlacementMO& newObj, PlacementMO& targetScope); - bool remove (PlacementMO&); - bool remove (ID); - - - typedef RefcountFac Factory; - - static Factory create; - - ~PlacementIndex(); - - void clear(); - - protected: - PlacementIndex() ; - - friend class lib::factory::Factory > >; + }; - ////////////////TODO currently just fleshing out the API; probably have to split off an impl.class; but for now a PImpl is sufficient... - - - typedef shared_ptr PPIdx; - - - - /** @internal there is an implicit PlacementIndex available on a global scale, - * by default implemented within the current session. This function allows - * to re-define this implicit index temporarily, e.g. for unit tests. */ - void - reset_PlacementIndex(PPIdx const&) ; - - /** @internal restore the implicit PlacementIndex to its default implementation (=the session) */ - void - reset_PlacementIndex() ; - - /** @internal access point for PlacementRef to the implicit global PlacementIndex */ - Placement & - fetch_PlacementIndex(Placement::ID const&) ; - - - - - /* === forwarding implementations of the templated API === */ - - template - inline Placement& - PlacementIndex::find (PlacementMO::Id id) const - { - PlacementMO& result (find (id)); - REQUIRE (INSTANCEOF (MO, &result) ); - return static_cast&> (result); - } - - - template - inline Placement& - PlacementIndex::find (PlacementRef const& pRef) const - { - PlacementMO::Id id (pRef); - return find (id); - } - - - /** @todo use query-resolver-test as an example..... - * return a result set object derived from Resolution - * For the additional type filtering: build a filter iterator, - * using a type-filtering predicate, based on Placement#isCompatible - */ - template - inline typename session::Query >::iterator - PlacementIndex::query (PlacementMO& scope) const - { - UNIMPLEMENTED ("actually run the containment query"); - } - - inline Placement& - PlacementIndex::getScope (PlacementMO const& p) const - { - return getScope(p.getID()); - } - - inline bool - PlacementIndex::contains (PlacementMO const& p) const - { - return contains (p.getID()); - } - - inline bool - PlacementIndex::remove (PlacementMO& p) - { - return remove (p.getID()); - } - }} // namespace mobject::session diff --git a/src/proc/mobject/session/sess-manager-impl.cpp b/src/proc/mobject/session/sess-manager-impl.cpp index 5d7d94e62..96b9e593b 100644 --- a/src/proc/mobject/session/sess-manager-impl.cpp +++ b/src/proc/mobject/session/sess-manager-impl.cpp @@ -59,7 +59,7 @@ namespace session { * @note any exceptions arising while building the basic * session object(s) will halt the system. */ - SessionImpl* + SessionImplAPI* SessManagerImpl::operator-> () throw() { if (!pImpl_) @@ -87,8 +87,7 @@ namespace session { * \link #operator-> access \endlink to the session object. */ SessManagerImpl::SessManagerImpl () throw() - : pDefs_ (0), - pImpl_ (0) + : pImpl_ (0) { } @@ -111,14 +110,12 @@ namespace session { void SessManagerImpl::reset () { - scoped_ptr tmpD (new DefsManager); - scoped_ptr tmpS (new SessionImpl (*tmpD)); + scoped_ptr tmpS (new SessionImplAPI); TODO ("reset the assets registered with AssetManager"); /////////////////////////////////////////////////////////////////// TICKET #154 TODO ("thread lock"); - pDefs_.swap (tmpD); pImpl_.swap (tmpS); } diff --git a/src/proc/mobject/session/session-impl.cpp b/src/proc/mobject/session/session-impl.cpp index d870e46a9..c3bc059a4 100644 --- a/src/proc/mobject/session/session-impl.cpp +++ b/src/proc/mobject/session/session-impl.cpp @@ -28,13 +28,26 @@ namespace mobject { namespace session { + /////////////////////////////////////////TODO temporary hack + namespace { + DefsManager& + getDummyDefaultsManager() + { + static scoped_ptr dummyDefaultsManagerInstance(new DefsManager); + + return *dummyDefaultsManagerInstance; + } + } + /////////////////////////////////////////TODO temporary hack + + /** create a new empty session with default values. * @note any exception arising while creating this * default session will inevitably halt the * system (and this is desirable) */ - SessionImpl::SessionImpl (DefsManager& defs) throw() - : Session(defs), + SessionImpl::SessionImpl () + : Session( getDummyDefaultsManager() ), ///////TODO temporary hack focusEDL_(0), edls(1), fixture(new Fixture), diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp index 5740a4424..265479d45 100644 --- a/src/proc/mobject/session/session-impl.hpp +++ b/src/proc/mobject/session/session-impl.hpp @@ -42,6 +42,13 @@ #include "proc/mobject/session/edl.hpp" #include "proc/mobject/session/fixture.hpp" #include "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/session-services.hpp" + +#include "proc/mobject/session/session-service-fetch.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" +#include "proc/mobject/session/session-service-defaults.hpp" + #include #include @@ -65,8 +72,12 @@ namespace session { uint focusEDL_; vector edls; PFix fixture; + shared_ptr pIdx_; + scoped_ptr defaultsManager_; ///////////TODO: later, this will be the real defaults manager. Currently this is just never initialised (11/09) + + /* ==== Session API ==== */ virtual bool isValid (); virtual void add (PMO& placement); @@ -78,7 +89,7 @@ namespace session { virtual void rebuildFixture (); protected: /* == management API === */ - SessionImpl (DefsManager&) throw(); + SessionImpl (); friend class SessManagerImpl; void clear (); @@ -86,6 +97,76 @@ namespace session { }; + /* ===== providing internal services for Proc ===== */ + + template + struct ServiceAccessPoint + : IMPL + { + bool + isRegisteredID (PMO::ID const& placementID) + { + UNIMPLEMENTED ("check if index contains the given ID"); + } + + PMO& + resolveID (PMO::ID const& placementID) + { + UNIMPLEMENTED ("fetch from PlacementIndex, throw on failure"); +// IMPL::implementationService(); + } + }; + + + template + struct ServiceAccessPoint + : IMPL + { + QueryResolver& + getResolver() + { + UNIMPLEMENTED ("how actually to manage the PlacementIndexQueryResolver wrapper instance"); + +// return IMPL::magic_; + } + }; + + + template + struct ServiceAccessPoint + : IMPL + { + ////////////////////////////TODO + }; + + + template + struct ServiceAccessPoint + : IMPL +// , SessionServiceDefaults + { + + ////////////////////////////TODO + }; + + + + + + class SessManagerImpl; + + typedef SessionServices< Types< SessionServiceFetch + , SessionServiceExploreScope + , SessionServiceMockIndex + , SessionServiceDefaults + > // List of the APIs to provide + , SessManagerImpl // frontend for access + , SessionImpl // implementation base class + > // + SessionImplAPI; + + + /** * Session manager implementation class holding the * actual smart pointer to the current Session impl. @@ -93,8 +174,7 @@ namespace session { */ class SessManagerImpl : public SessManager { - scoped_ptr pDefs_; - scoped_ptr pImpl_; + scoped_ptr pImpl_; SessManagerImpl() throw(); friend class lib::singleton::StaticCreate; @@ -106,14 +186,15 @@ namespace session { virtual void reset () ; virtual void load () ; virtual void save () ; - virtual SessionImpl* operator-> () throw() ; public: /* ==== proc layer internal API ==== */ /** @internal access point for PlacementIndex and PlacementRef */ - static shared_ptr& getCurrentIndex () ; + static shared_ptr& getCurrentIndex () ; + + virtual SessionImplAPI* operator-> () throw() ; }; diff --git a/src/proc/mobject/session/session-service-defaults.hpp b/src/proc/mobject/session/session-service-defaults.hpp new file mode 100644 index 000000000..e97a8409b --- /dev/null +++ b/src/proc/mobject/session/session-service-defaults.hpp @@ -0,0 +1,59 @@ +/* + SESSION-SERVICE-DEFAULTS.hpp - session implementation service API: manage default objects + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file session-service-defaults.hpp + ** Implementation level session API: manage default configured objects. + ** + ** @todo rework the existing DefsManager to fit into this scheme. TICKET #404 + ** + ** @see session-impl.hpp implementation of the service + ** @see session-services.cpp implementation of access + ** + */ + + +#ifndef MOBJECT_SESSION_SESSION_SERVICE_DEFAULTS_H +#define MOBJECT_SESSION_SESSION_SERVICE_DEFAULTS_H + +//#include "proc/mobject/session.hpp" +//#include "lib/meta/generator.hpp" + + + + +namespace mobject { +namespace session { + +// using lumiera::typelist::InstantiateChained; +// using lumiera::typelist::InheritFrom; +// using lumiera::typelist::NullType; + + + class SessionServiceDefaults + { + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-service-explore-scope.hpp b/src/proc/mobject/session/session-service-explore-scope.hpp new file mode 100644 index 000000000..356a29a29 --- /dev/null +++ b/src/proc/mobject/session/session-service-explore-scope.hpp @@ -0,0 +1,71 @@ +/* + SESSION-SERVICE-EXPLORE-SCOPE.hpp - session implementation service API: explore scope + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file session-service-explore-scope.hpp + ** Implementation level session API: query a scope. + ** This specialised service is intended to be used by the Scope and + ** QueryFocus framework for enumerating objects contained within a + ** given scope and for locating the scope's parent scope. Basically, + ** this service just exposes a QueryResolver, which is actually + ** backed by the PlacementIndex and is able to handle queries of + ** type ScopeQuery, especially ContentsQuery and PathQuery. + ** + ** By virtue of this service, QueryFocus, Scope and Placement can + ** remain completely agnostic of session's implementation details, + ** and especially aren't bound to PlacementIndex. This is important, + ** because the public session API is casted in terms of PlacementRef + ** and QueryFocus An implementation of this service is available + ** through the SessionServices access mechanism. + ** + ** @see session-impl.hpp implementation of the service + ** @see session-services.cpp implementation of access + ** + */ + + +#ifndef MOBJECT_SESSION_SESSION_SERVICE_EXPLORE_SCOPE_H +#define MOBJECT_SESSION_SESSION_SERVICE_EXPLORE_SCOPE_H + +#include "proc/mobject/session/query-resolver.hpp" +//#include "lib/meta/generator.hpp" + + + + +namespace mobject { +namespace session { + +// using lumiera::typelist::InstantiateChained; +// using lumiera::typelist::InheritFrom; +// using lumiera::typelist::NullType; + + + struct SessionServiceExploreScope + { + static QueryResolver& getResolver(); + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-service-fetch.hpp b/src/proc/mobject/session/session-service-fetch.hpp new file mode 100644 index 000000000..5e9349c0d --- /dev/null +++ b/src/proc/mobject/session/session-service-fetch.hpp @@ -0,0 +1,64 @@ +/* + SESSION-SERVICE-FETCH.hpp - session implementation service API: fetch PlacementRef + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file session-service-fetch.hpp + ** Implementation level session API: resolve a Placement by hash-ID. + ** This specialised service is intended to be used by PlacementRef, + ** in order to (re)-access the Placement instance within the session, + ** given the hash-ID of this placement. An implementation of this + ** service is available through the SessionServices access mechanism. + ** + ** @see session-impl.hpp implementation of the service + ** @see session-services.cpp implementation of access + ** + */ + + +#ifndef MOBJECT_SESSION_SESSION_SERVICE_FETCH_H +#define MOBJECT_SESSION_SESSION_SERVICE_FETCH_H + +//#include "proc/mobject/session.hpp" +//#include "lib/meta/generator.hpp" +#include "proc/mobject/placement.hpp" + + + + +namespace mobject { +namespace session { + +// using lumiera::typelist::InstantiateChained; +// using lumiera::typelist::InheritFrom; +// using lumiera::typelist::NullType; + + + class SessionServiceFetch + { + static PlacementMO& resolveID (PlacementMO::ID const&) ; + static bool isRegisteredID (PlacementMO::ID const&) ; + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-service-mock-index.hpp b/src/proc/mobject/session/session-service-mock-index.hpp new file mode 100644 index 000000000..6a8118982 --- /dev/null +++ b/src/proc/mobject/session/session-service-mock-index.hpp @@ -0,0 +1,62 @@ +/* + SESSION-SERVICE-MOCK-INDEX.hpp - session service API: mock PlacementIndex for tests + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file session-service-mock-index.hpp + ** Implementation level session API: PlacementIndex mock for tests. + ** Allows (temporarily) to replace the real Placement index within + ** the session by a mock instance handed in through this API. Unit + ** tests may use this \em backdoor to set up a specially prepared + ** index to verify the behaviour of Placement and Scope resolution + ** operations. + ** + ** @see session-impl.hpp implementation of the service + ** @see session-services.cpp implementation of access + ** + */ + + +#ifndef MOBJECT_SESSION_SESSION_SERVICE_MOCK_INDEX_H +#define MOBJECT_SESSION_SESSION_SERVICE_MOCK_INDEX_H + +//#include "proc/mobject/session.hpp" +//#include "lib/meta/generator.hpp" + + + + +namespace mobject { +namespace session { + +// using lumiera::typelist::InstantiateChained; +// using lumiera::typelist::InheritFrom; +// using lumiera::typelist::NullType; + + + class SessionServiceMockIndex + { + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp index 624666eb7..a5bfd8cf8 100644 --- a/src/proc/mobject/session/session-services.cpp +++ b/src/proc/mobject/session/session-services.cpp @@ -21,6 +21,11 @@ * *****************************************************/ +#include "proc/mobject/session/session-service-fetch.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" +#include "proc/mobject/session/session-service-defaults.hpp" + #include "proc/mobject/session/session-services.hpp" #include "proc/mobject/session/session-impl.hpp" @@ -28,6 +33,18 @@ namespace mobject { namespace session { /** TODO */ + bool + SessionServiceFetch::isRegisteredID (PlacementMO::ID const& placementID) + { + return SessionImplAPI::current->isRegisteredID (placementID); + } + + + PlacementMO& + SessionServiceFetch::resolveID (PlacementMO::ID const& placementID) + { + return SessionImplAPI::current->resolveID (placementID); + } diff --git a/src/proc/mobject/session/session-services.hpp b/src/proc/mobject/session/session-services.hpp index a71e5664a..889f70cbd 100644 --- a/src/proc/mobject/session/session-services.hpp +++ b/src/proc/mobject/session/session-services.hpp @@ -86,8 +86,7 @@ namespace mobject { namespace session { using lumiera::typelist::InstantiateChained; - using lumiera::typelist::InheritFrom; - using lumiera::typelist::NullType; + using lumiera::typelist::Types; /** @@ -117,7 +116,7 @@ namespace session { , class FRONT , class SESS > - class TSessionServices + class SessionServices : public InstantiateChained< typename APIS::List // for each of the API types... , ServiceAccessPoint // instantiate a service implementation , SESS // and stack all these on top of SessionImpl diff --git a/src/proc/mobject/session/session.cpp b/src/proc/mobject/session/session.cpp index d0b6a6b2e..f15f16192 100644 --- a/src/proc/mobject/session/session.cpp +++ b/src/proc/mobject/session/session.cpp @@ -43,6 +43,7 @@ using lib::Symbol; using lib::Singleton; using mobject::session::SessManager; using mobject::session::SessManagerImpl; +using mobject::session::SessionImplAPI; namespace mobject { @@ -58,6 +59,15 @@ namespace mobject { SessManager& Session::current = Singleton()(); + /** special access point allowing Proc-Layer internals + * to cooperate with session implementation level APIs + */ + template<> + SessManagerImpl& SessionImplAPI::current = static_cast (Session::current); + + + + /** \par * LifecycleHook, to perform all the basic setup for a new session, * prior to adding any specific data, configuration or content. Any subsystems From 1a76ce7a5f17966eda59bcc53888d815b3a7a912 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 11 Nov 2009 05:30:24 +0100 Subject: [PATCH 062/377] implement two of the SessionServices (internal APIs) providing implementation-level access to the PlacementIndex and especially installing a mock index for unit tests --- src/proc/mobject/placement-ref.hpp | 12 ++---- src/proc/mobject/session/session-impl.hpp | 42 ++++++++++++++++--- .../mobject/session/session-service-fetch.hpp | 9 +++- .../session/session-service-mock-index.hpp | 12 +++++- src/proc/mobject/session/session-services.cpp | 25 ++++++++++- wiki/renderengine.html | 11 ++--- 6 files changed, 88 insertions(+), 23 deletions(-) diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp index 0d0f8da63..19023fd53 100644 --- a/src/proc/mobject/placement-ref.hpp +++ b/src/proc/mobject/placement-ref.hpp @@ -49,6 +49,7 @@ #include "lib/error.hpp" #include "proc/mobject/placement.hpp" #include "proc/mobject/explicitplacement.hpp" /////////////TODO this is ugly! Why can't placement::resolve() return a reference?? +#include "proc/mobject/session/session-service-fetch.hpp" //#include @@ -60,13 +61,6 @@ namespace mobject { class MObject; - namespace session { - - // see placement-index.cpp - Placement & fetch_PlacementIndex(Placement::ID const&) ; - bool checkContains_PlacementIndex (Placement::ID const& pID) ; - - } LUMIERA_ERROR_DECLARE (INVALID_PLACEMENTREF); ///< unresolvable placement reference, or of incompatible type @@ -210,7 +204,7 @@ namespace mobject { bool checkValidity () const { - return session::checkContains_PlacementIndex(this->id_); + return session::SessionServiceFetch::isRegisteredID (this->id_); } static void @@ -240,7 +234,7 @@ namespace mobject { static PlacementMO& access (_Id const& placementID) { - Placement & pla (session::fetch_PlacementIndex (placementID)); // may throw + Placement & pla (session::SessionServiceFetch::resolveID (placementID)); // may throw REQUIRE (pla.isValid()); ASSERT (pla.isCompatible()); return static_cast (pla); diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp index 265479d45..8907b6654 100644 --- a/src/proc/mobject/session/session-impl.hpp +++ b/src/proc/mobject/session/session-impl.hpp @@ -27,9 +27,17 @@ ** to control the behaviour of the editing part of the application. ** All all implementation complexities are hidden behind a "PImpl". ** - ** This file contains the implementation classes, it should never - ** be included by client code. + ** This file contains the implementation level API, it should never + ** be included by client code. Besides the actual SessionImpl, a set + ** of further implementation level services is provided for use by + ** Proc-Layer's internals. These additional SessionServices are to be + ** accessed through dedicated headers and interface classes (typically + ** through static access functions), thereby abstracting from the actual + ** session implementation. Within this file, the implementation of these + ** SessionServices is wired up with the SessionImpl object. ** + ** @see Session public API + ** @see session-services.hpp ** @see session-service-access-test.cpp for a complete simplified mock session manager ** */ @@ -94,6 +102,13 @@ namespace session { void clear (); + PPIdx const& + getPlacementIndex() + { + ENSURE (pIdx_); + return pIdx_; + } + }; @@ -106,14 +121,13 @@ namespace session { bool isRegisteredID (PMO::ID const& placementID) { - UNIMPLEMENTED ("check if index contains the given ID"); + return IMPL::getPlacementIndex()->contains (placementID); //never throws } PMO& resolveID (PMO::ID const& placementID) { - UNIMPLEMENTED ("fetch from PlacementIndex, throw on failure"); -// IMPL::implementationService(); + return IMPL::getPlacementIndex()->find (placementID); //may throw } }; @@ -136,7 +150,23 @@ namespace session { struct ServiceAccessPoint : IMPL { - ////////////////////////////TODO + PPIdx const& + getPlacementIndex() + { + if (mockIndex_) + return mockIndex_; + else + return IMPL::getPlacementIndex(); + } + + void + reset_PlacementIndex (PPIdx const& alternativeIndex) + { + mockIndex_ = alternativeIndex; + } + + private: + PPIdx mockIndex_; }; diff --git a/src/proc/mobject/session/session-service-fetch.hpp b/src/proc/mobject/session/session-service-fetch.hpp index 5e9349c0d..7745d7365 100644 --- a/src/proc/mobject/session/session-service-fetch.hpp +++ b/src/proc/mobject/session/session-service-fetch.hpp @@ -51,9 +51,16 @@ namespace session { // using lumiera::typelist::InheritFrom; // using lumiera::typelist::NullType; - + /** + * Implementation-level service for resolving an Placement-ID. + * Usually, this service is backed by the PlacementIndex of the + * current session -- however, for the purpose of unit testing, + * this index may be overlaid temporarily, by using the + * SessionServiceMockIndex API. + */ class SessionServiceFetch { + public: static PlacementMO& resolveID (PlacementMO::ID const&) ; static bool isRegisteredID (PlacementMO::ID const&) ; }; diff --git a/src/proc/mobject/session/session-service-mock-index.hpp b/src/proc/mobject/session/session-service-mock-index.hpp index 6a8118982..39b891758 100644 --- a/src/proc/mobject/session/session-service-mock-index.hpp +++ b/src/proc/mobject/session/session-service-mock-index.hpp @@ -38,6 +38,7 @@ #ifndef MOBJECT_SESSION_SESSION_SERVICE_MOCK_INDEX_H #define MOBJECT_SESSION_SESSION_SERVICE_MOCK_INDEX_H +#include "proc/mobject/session/placement-index.hpp" //#include "proc/mobject/session.hpp" //#include "lib/meta/generator.hpp" @@ -51,9 +52,18 @@ namespace session { // using lumiera::typelist::InheritFrom; // using lumiera::typelist::NullType; - + + /** there is an implicit PlacementIndex available on a global level, + * by default implemented within the current session. This Service + * to re-define this implicit index temporarily, e.g. for unit tests. + * @param alternativeIndex alternative Index instance to install. + * when \c NIL, then restore access to the PlacementIndex + * instance always available within the SessionImpl + */ class SessionServiceMockIndex { + public: + void reset_PlacementIndex (PPIdx const& alternativeIndex =PPIdx()); }; diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp index a5bfd8cf8..6a76d2ee0 100644 --- a/src/proc/mobject/session/session-services.cpp +++ b/src/proc/mobject/session/session-services.cpp @@ -32,7 +32,10 @@ namespace mobject { namespace session { - /** TODO */ + /** verify the given placement-ID (hash) is valid, + * by checking if it refers to a Placement instance + * currently registered with the PlacementIndex of the + * active Session. */ bool SessionServiceFetch::isRegisteredID (PlacementMO::ID const& placementID) { @@ -40,6 +43,16 @@ namespace session { } + /** actually retrieve a Placement tracked by the index. + * @param placementID hash-ID, typically from a PlacementRef + * @throw error::Invalid if the ID isn't resolvable + * @note the returned ref is guaranteed to be valid and usable + * only \em now, which means, by virtue of the ProcDispatcher + * and command processing, during this operation. It can be + * used to invoke an operation, but should never be stored; + * rather, client code should create an MObjectRef, if + * bound to store an reference for later. + */ PlacementMO& SessionServiceFetch::resolveID (PlacementMO::ID const& placementID) { @@ -47,5 +60,15 @@ namespace session { } + /** */ + void + SessionServiceMockIndex::reset_PlacementIndex (PPIdx const& alternativeIndex) + { + return SessionImplAPI::current->reset_PlacementIndex (alternativeIndex); + } + + + + }} // namespace mobject::session diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 9f66340c8..897c8b74c 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3522,7 +3522,7 @@ Then, running the goal {{{:-resolve(T, stream(T,mpeg)).}}} would search a Track In the design of the Lumiera Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Pipe, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered "condiguration data" (including the actual plugin implementation to be loaded) -
                                    +
                                    Within the Lumiera Proc-Layer, there is a general preference for issuing [[queries|Query]] over hard wired configuration (or even mere table based configuration). This leads to the demand of exposing a //possibility to issue queries// &mdash; without actually disclosing much details of the facility implementing this service. For example, for shaping the general session interface (in 10/09), we need a means of exposing a hook to discover HighLevelModel contents, without disclosing how the model is actually organised internally (namely by using an PlacementIndex).
                                     
                                     !Analysis of the problem
                                    @@ -3541,7 +3541,7 @@ The situation can be decomposed as follows.[>img[QueryResolver|uml/fig137733.
                                     * and then there is the notorious problem of re-gaining the specifically typed context //behind//&nbsp; the invocation interface. Especially, the facility processing the query needs to know both the expected result type and details about the concrete query and its parametrisation. <br/>&rarr; TypedQueryProblem
                                     
                                     !!!Entities and Operations
                                    -The //client// &nbsp;(code using query-resolver.hpp) either wants a ''goal'' or ''query'' to be resolved; the former is just implicitly typed and usually given in predicate logic from, while the latter may be a specialised subclass templated to yield objects of a specific type as results. A ''query resolver'' is an (abstracted) entity capable of //resolving//&nbsp; such a goal. Actually, behind the scenes there is somehow a registration of the concrete resolving facilities, which are asumed to decide about their ability of handling a given goal. Issuing a goal or query yields a ''resolution'' &mdash; practically speaking, a set of indivitual solutions. These individual solution ''results'' can be explored by ''iteration'', thereby moving an embedded ''cursor'' through the ''result set''. Any result can be retrieved at most once &mdash; after that, the resolution is ''exhausted'' and will be released automatically when the expolration iterator goes out of scope.
                                    +The //client// &nbsp;(code using query-resolver.hpp) either wants a ''goal'' or ''query'' to be resolved; the former is just implicitly typed and usually given in predicate logic from ({{red{planned as of 11/09}}}), while the latter may be a specialised subclass templated to yield objects of a specific type as results. A ''query resolver'' is an (abstracted) entity capable of //resolving//&nbsp; such a goal. Actually, behind the scenes there is somehow a registration of the concrete resolving facilities, which are asumed to decide about their ability of handling a given goal. Issuing a goal or query yields a ''resolution'' &mdash; practically speaking, a set of indivitual solutions. These individual solution ''results'' can be explored by ''iteration'', thereby moving an embedded ''cursor'' through the ''result set''. Any result can be retrieved at most once &mdash; after that, the resolution is ''exhausted'' and will be released automatically when the expolration iterator goes out of scope.
                                     
                                     !!!Decisions
                                     * while, in the use case currently at hand, the query instance is created by the client on the stack, the possibility of managing the queries internally is deliberately kept open. Because otherwise, we had to commit to a specific way of obtaining results, for example by assuming always to use an embedded STL iterator.
                                    @@ -3950,7 +3950,7 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl
                                     
                                     {{red{WIP ... just emerging}}}
                                    -
                                    +
                                    The current [[Session]] is the root of any state found within Proc-Layer. Thus, events defining the session's lifecycle influence and synchronise the cooperative behaviour of the entities within the model, the ProcDispatcher, [[Fixture]] and any facility below.
                                     * when ''starting'', on first access an empty session is created, which puts any related facility into a defined initial state.
                                     * when ''closing'' the session, any dependent facilities are disabled, disconnected, halted or closed
                                    @@ -3991,6 +3991,7 @@ As detailed above, {{{Session::current}}} exposes the management / lifecycle API
                                     # the PlacementIndex is cleared, effectively releasing any object "instances"
                                     # the [[asset registry|AssetManager]] is cleared, thereby releasing any remaining external resource references
                                     # destruction of session implementation instances
                                    +{{red{none of the above is implemented as of 11/09}}}
                                     
                                    @@ -4004,8 +4005,8 @@ Currently (as of 5/09), Ichthyo is [[targeting|PlanningSessionInMem]] a first pr Objects are attached and manipulated by [[placements|Placement]]; thus the organisation of these placements is part of the session data layout. Effectively, such a placement within the session behaves like an //instances// of a given object, and at the same time it defines the "non-substantial" properties of the object, e.g. its positions and relations. [[References|MObjectRef]] to these placement entries are handed out as parameters, both down to the [[Builder]] and from there to the render processes within the engine, but also to external parts within the GUI and in plugins. The actual implementation of these object references is built on top of the PlacementRef tags, thus relying on the PlacementIndex the session maintains to keep track of all placements and their relations. While &mdash; using these references &mdash; an external client can access the objects and structures within the session, any actual ''mutations'' should be done based on the CommandHandling: a single operation of a sequence of operations is defined as [[Command]], to be [[dispatched as mutation operation|ProcDispatcher]]. Following this policy ensures integration with the&nbsp;SessionStorage and provides (unlimited) [[UNDO|UndoManager]].
                                    -
                                    -
                                    The session manager is responsible for maintaining session state as a whole and for conducting the session lifecycle. The session manager API allows for saving, loading, closing and resetting the session. Accessible through the static interface {{{Session::current}}}, it exposes the actual session as a ~PImpl. Actually, both session and session manager are interfaces.
                                    +
                                    +
                                    The session manager is responsible for maintaining session state as a whole and for conducting the session [[lifecycle|SessionLifecycle]]. The session manager API allows for saving, loading, closing and resetting the session. Accessible through the static interface {{{Session::current}}}, it exposes the actual session as a ~PImpl. Actually, both session and session manager are interfaces.
                                     
                                    From 5535a7a00e6f8a55c2278ba13f19c228a3f7234d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 11 Nov 2009 05:44:58 +0100 Subject: [PATCH 063/377] phase out the existing access functions, now superseeded by SessionServices --- src/proc/mobject/session/placement-index.cpp | 48 ------------------- src/proc/mobject/session/placement-index.hpp | 13 ----- .../mobject/session/sess-manager-impl.cpp | 7 --- src/proc/mobject/session/session-impl.hpp | 5 +- .../session/session-service-mock-index.hpp | 2 +- .../proc/mobject/mobject-ref-test.cpp | 7 +-- .../proc/mobject/placement-ref-test.cpp | 5 +- .../proc/mobject/session/test-scopes.cpp | 5 +- .../proc/mobject/session/test-scopes.hpp | 2 +- 9 files changed, 13 insertions(+), 81 deletions(-) diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index 069de7012..c1d10f5a3 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -155,54 +155,6 @@ namespace session { - namespace { // implementation detail: default global placement index access - - PPIdx globalIndex; - - PPIdx const& - getGlobalIndex() - { - if (globalIndex) - return globalIndex; - else - return session::SessManagerImpl::getCurrentIndex(); - } - - } // (End) implementation detail - - - - - - void - reset_PlacementIndex (PPIdx const& alternativeIndex) - { - globalIndex = alternativeIndex; - } - - /** @internal restore the implicit PlacementIndex to its default implementation (=the session) */ - void - reset_PlacementIndex() - { - globalIndex.reset(); - } - - /** by default, this reaches for the PlacementIndex maintained within - * the current session. But for the purpose of unit tests, an alternative - * PlacementIndex may have been \link #reset_PlacementIndex installed \endlink - */ - Placement & - fetch_PlacementIndex (Placement::ID const& pID) - { - return getGlobalIndex()->find (pID); - } - - /** @internal used by PlacementRef to implement a self-check */ - bool - checkContains_PlacementIndex (Placement::ID const& pID) - { - return getGlobalIndex()->contains (pID); - } }} // namespace mobject::session diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index 4ad794227..e1e163407 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -138,19 +138,6 @@ namespace session { - /** @internal there is an implicit PlacementIndex available on a global scale, - * by default implemented within the current session. This function allows - * to re-define this implicit index temporarily, e.g. for unit tests. */ - void - reset_PlacementIndex(PPIdx const&) ; - - /** @internal restore the implicit PlacementIndex to its default implementation (=the session) */ - void - reset_PlacementIndex() ; - - /** @internal access point for PlacementRef to the implicit global PlacementIndex */ - Placement & - fetch_PlacementIndex(Placement::ID const&) ; diff --git a/src/proc/mobject/session/sess-manager-impl.cpp b/src/proc/mobject/session/sess-manager-impl.cpp index 96b9e593b..a7de7b72e 100644 --- a/src/proc/mobject/session/sess-manager-impl.cpp +++ b/src/proc/mobject/session/sess-manager-impl.cpp @@ -142,12 +142,5 @@ namespace session { } - shared_ptr& - SessManagerImpl::getCurrentIndex () - { - return static_cast (Session::current).pImpl_->pIdx_; - } - - }} // namespace mobject::session diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp index 8907b6654..e185557f1 100644 --- a/src/proc/mobject/session/session-impl.hpp +++ b/src/proc/mobject/session/session-impl.hpp @@ -98,9 +98,9 @@ namespace session { protected: /* == management API === */ SessionImpl (); - friend class SessManagerImpl; void clear (); + friend class SessManagerImpl; PPIdx const& getPlacementIndex() @@ -221,9 +221,6 @@ namespace session { public: /* ==== proc layer internal API ==== */ - /** @internal access point for PlacementIndex and PlacementRef */ - static shared_ptr& getCurrentIndex () ; - virtual SessionImplAPI* operator-> () throw() ; }; diff --git a/src/proc/mobject/session/session-service-mock-index.hpp b/src/proc/mobject/session/session-service-mock-index.hpp index 39b891758..e4a22b45f 100644 --- a/src/proc/mobject/session/session-service-mock-index.hpp +++ b/src/proc/mobject/session/session-service-mock-index.hpp @@ -63,7 +63,7 @@ namespace session { class SessionServiceMockIndex { public: - void reset_PlacementIndex (PPIdx const& alternativeIndex =PPIdx()); + static void reset_PlacementIndex (PPIdx const& alternativeIndex =PPIdx()); }; diff --git a/tests/components/proc/mobject/mobject-ref-test.cpp b/tests/components/proc/mobject/mobject-ref-test.cpp index b679df1d8..89025cf0d 100644 --- a/tests/components/proc/mobject/mobject-ref-test.cpp +++ b/tests/components/proc/mobject/mobject-ref-test.cpp @@ -29,6 +29,7 @@ #include "proc/mobject/placement.hpp" #include "proc/mobject/placement-ref.hpp" #include "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" #include "proc/mobject/session/clip.hpp" #include "proc/mobject/explicitplacement.hpp" #include "proc/mobject/test-dummy-mobject.hpp" @@ -47,7 +48,7 @@ namespace test { using lumiera::Time; using session::Clip; - using session::reset_PlacementIndex; + using session::SessionServiceMockIndex; /*************************************************************************** @@ -91,7 +92,7 @@ namespace test { typedef shared_ptr PIdx; PIdx index (PlacementIndex::create()); PMO& root = index->getRoot(); - reset_PlacementIndex(index); + SessionServiceMockIndex::reset_PlacementIndex (index); // Add the Clips to "session" index->insert (pClip1, root); @@ -130,7 +131,7 @@ namespace test { ASSERT (2 == pClip1.use_count()); ASSERT (2 == pClip2.use_count()); #endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! - reset_PlacementIndex(); + SessionServiceMockIndex::reset_PlacementIndex(); } diff --git a/tests/components/proc/mobject/placement-ref-test.cpp b/tests/components/proc/mobject/placement-ref-test.cpp index de2f7e5bb..7be8be595 100644 --- a/tests/components/proc/mobject/placement-ref-test.cpp +++ b/tests/components/proc/mobject/placement-ref-test.cpp @@ -26,6 +26,7 @@ #include "proc/mobject/placement.hpp" #include "proc/mobject/placement-ref.hpp" #include "proc/mobject/session/placement-index.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" #include "proc/mobject/explicitplacement.hpp" #include "proc/mobject/test-dummy-mobject.hpp" #include "lib/util.hpp" @@ -70,7 +71,7 @@ namespace test { typedef shared_ptr PIdx; PIdx index (PlacementIndex::create()); PMO& root = index->getRoot(); - reset_PlacementIndex(index); + SessionServiceMockIndex::reset_PlacementIndex(index); index->insert (p1, root); index->insert (p2, root); @@ -179,7 +180,7 @@ namespace test { //consistency check; then reset PlacementRef index to default ASSERT (0 == index->size()); - reset_PlacementIndex(); + SessionServiceMockIndex::reset_PlacementIndex(); } }; diff --git a/tests/components/proc/mobject/session/test-scopes.cpp b/tests/components/proc/mobject/session/test-scopes.cpp index 2c46354fe..20cf0639e 100644 --- a/tests/components/proc/mobject/session/test-scopes.cpp +++ b/tests/components/proc/mobject/session/test-scopes.cpp @@ -22,6 +22,7 @@ #include "proc/mobject/session/test-scopes.hpp" +#include "proc/mobject/session/session-service-mock-index.hpp" //#include "lib/util.hpp" //#include @@ -46,7 +47,7 @@ namespace test { REQUIRE (testIdx); testIdx->clear(); ASSERT (0 == testIdx->size()); - reset_PlacementIndex(); // restore default Index from Session + SessionServiceMockIndex::reset_PlacementIndex(); // restore default Index from Session delete testIdx; } @@ -72,7 +73,7 @@ namespace test { // Prepare an (test)Index backing the PlacementRefs PPIdx index (PlacementIndex::create().get(), &remove_testIndex); // taking ownership - reset_PlacementIndex(index); + SessionServiceMockIndex::reset_PlacementIndex(index); PMO& root = index->getRoot(); index->insert (p1, root); diff --git a/tests/components/proc/mobject/session/test-scopes.hpp b/tests/components/proc/mobject/session/test-scopes.hpp index 31d9d7a9f..24147c399 100644 --- a/tests/components/proc/mobject/session/test-scopes.hpp +++ b/tests/components/proc/mobject/session/test-scopes.hpp @@ -62,7 +62,7 @@ namespace test { * * @see mobject::PlacementIndex * @see session::SessManagerImpl::getCurrentIndex() - * @see mobject::reset_PlacementIndex + * @see mobject::session::SessionServiceMockIndex::reset_PlacementIndex */ PPIdx build_testScopes(); From bfd97bd98ec45f78980d78c3684673d2273ec32f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 11 Nov 2009 06:01:25 +0100 Subject: [PATCH 064/377] now SessManagerImpl can go down entirely on implementation level --- .../mobject/session/sess-manager-impl.cpp | 2 +- .../mobject/session/sess-manager-impl.hpp | 65 ++++++ src/proc/mobject/session/session-impl.hpp | 198 ++++++++---------- src/proc/mobject/session/session-services.cpp | 1 + src/proc/mobject/session/session.cpp | 1 + 5 files changed, 156 insertions(+), 111 deletions(-) create mode 100644 src/proc/mobject/session/sess-manager-impl.hpp diff --git a/src/proc/mobject/session/sess-manager-impl.cpp b/src/proc/mobject/session/sess-manager-impl.cpp index a7de7b72e..2ad161383 100644 --- a/src/proc/mobject/session/sess-manager-impl.cpp +++ b/src/proc/mobject/session/sess-manager-impl.cpp @@ -37,7 +37,7 @@ #include "proc/mobject/session.hpp" -#include "proc/mobject/session/session-impl.hpp" +#include "proc/mobject/session/sess-manager-impl.hpp" #include "proc/mobject/session/defsmanager.hpp" //#include "proc/mobject/session/defsregistry.hpp" #include "lib/error.hpp" diff --git a/src/proc/mobject/session/sess-manager-impl.hpp b/src/proc/mobject/session/sess-manager-impl.hpp new file mode 100644 index 000000000..22eb310bf --- /dev/null +++ b/src/proc/mobject/session/sess-manager-impl.hpp @@ -0,0 +1,65 @@ +/* + SESS-MANAGER-IMPL.hpp - global session access and lifecycle + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef MOBJECT_SESSION_SESS_MANAGER_IMPL_H +#define MOBJECT_SESSION_SESS_MANAGER_IMPL_H + +#include "proc/mobject/session/session-impl.hpp" + + +namespace mobject { +namespace session { + + + + /** + * Session manager implementation class holding the + * actual smart pointer to the current Session impl. + */ + class SessManagerImpl : public SessManager + { + scoped_ptr pImpl_; + + SessManagerImpl() throw(); + friend class lib::singleton::StaticCreate; + + virtual ~SessManagerImpl() {} + + /* ==== SessManager API ==== */ + virtual void clear () ; + virtual void reset () ; + virtual void load () ; + virtual void save () ; + + + public: + /* ==== proc layer internal API ==== */ + + virtual SessionImplAPI* operator-> () throw() ; + + }; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp index e185557f1..c757c9c44 100644 --- a/src/proc/mobject/session/session-impl.hpp +++ b/src/proc/mobject/session/session-impl.hpp @@ -22,11 +22,11 @@ /** @file session-impl.hpp - ** Session and SessionManager Implementation classes. + ** Session and SessionServices Implementation classes. ** Session and the corresponding Manager are primary Interfaces ** to control the behaviour of the editing part of the application. ** All all implementation complexities are hidden behind a "PImpl". - ** + ** ** This file contains the implementation level API, it should never ** be included by client code. Besides the actual SessionImpl, a set ** of further implementation level services is provided for use by @@ -70,7 +70,7 @@ namespace session { using std::vector; using boost::scoped_ptr; using std::tr1::shared_ptr; - + /** * Implementation class for the Session interface @@ -112,120 +112,98 @@ namespace session { }; - /* ===== providing internal services for Proc ===== */ - - template - struct ServiceAccessPoint - : IMPL - { - bool - isRegisteredID (PMO::ID const& placementID) - { - return IMPL::getPlacementIndex()->contains (placementID); //never throws - } - - PMO& - resolveID (PMO::ID const& placementID) - { - return IMPL::getPlacementIndex()->find (placementID); //may throw - } - }; - - - template - struct ServiceAccessPoint - : IMPL - { - QueryResolver& - getResolver() - { - UNIMPLEMENTED ("how actually to manage the PlacementIndexQueryResolver wrapper instance"); - -// return IMPL::magic_; - } - }; - - - template - struct ServiceAccessPoint - : IMPL - { - PPIdx const& - getPlacementIndex() - { - if (mockIndex_) - return mockIndex_; - else - return IMPL::getPlacementIndex(); - } - - void - reset_PlacementIndex (PPIdx const& alternativeIndex) - { - mockIndex_ = alternativeIndex; - } - - private: - PPIdx mockIndex_; - }; - - - template - struct ServiceAccessPoint - : IMPL -// , SessionServiceDefaults - { - - ////////////////////////////TODO - }; - - - - - class SessManagerImpl; - - typedef SessionServices< Types< SessionServiceFetch - , SessionServiceExploreScope - , SessionServiceMockIndex - , SessionServiceDefaults - > // List of the APIs to provide - , SessManagerImpl // frontend for access - , SessionImpl // implementation base class - > // - SessionImplAPI; + /* ===== providing internal services for Proc ===== */ - - - /** - * Session manager implementation class holding the - * actual smart pointer to the current Session impl. - * @todo couldn't this be pushed down into session.cpp? - */ - class SessManagerImpl : public SessManager + template + struct ServiceAccessPoint + : IMPL { - scoped_ptr pImpl_; - - SessManagerImpl() throw(); - friend class lib::singleton::StaticCreate; - - virtual ~SessManagerImpl() {} - - /* ==== SessManager API ==== */ - virtual void clear () ; - virtual void reset () ; - virtual void load () ; - virtual void save () ; - - - public: - /* ==== proc layer internal API ==== */ - - virtual SessionImplAPI* operator-> () throw() ; + bool + isRegisteredID (PMO::ID const& placementID) + { + return IMPL::getPlacementIndex()->contains (placementID); //never throws + } + PMO& + resolveID (PMO::ID const& placementID) + { + return IMPL::getPlacementIndex()->find (placementID); //may throw + } }; + template + struct ServiceAccessPoint + : IMPL + { + QueryResolver& + getResolver() + { + UNIMPLEMENTED ("how actually to manage the PlacementIndexQueryResolver wrapper instance"); + +// return IMPL::magic_; + } + }; + + + template + struct ServiceAccessPoint + : IMPL + { + PPIdx const& + getPlacementIndex() + { + if (mockIndex_) + return mockIndex_; + else + return IMPL::getPlacementIndex(); + } + + void + reset_PlacementIndex (PPIdx const& alternativeIndex) + { + mockIndex_ = alternativeIndex; + } + + private: + PPIdx mockIndex_; + }; + + + template + struct ServiceAccessPoint + : IMPL +// , SessionServiceDefaults + { + ////////////////////////////TODO + }; + + + + + + + class SessManagerImpl; + + /** + * actual configuration of the session implementation compound: + * forming an inheritance chain of all internal SesssionServices + * stacked on top of the SessionImpl class. + * @note SessionImplAPI is actually an alias to the global Session PImpl + */ + typedef SessionServices< Types< SessionServiceFetch + , SessionServiceExploreScope + , SessionServiceMockIndex + , SessionServiceDefaults + > // List of the APIs to provide + , SessManagerImpl // frontend for access + , SessionImpl // implementation base class + > // + SessionImplAPI; + + + }} // namespace mobject::session #endif diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp index 6a76d2ee0..c0128ae38 100644 --- a/src/proc/mobject/session/session-services.cpp +++ b/src/proc/mobject/session/session-services.cpp @@ -28,6 +28,7 @@ #include "proc/mobject/session/session-services.hpp" #include "proc/mobject/session/session-impl.hpp" +#include "proc/mobject/session/sess-manager-impl.hpp" namespace mobject { namespace session { diff --git a/src/proc/mobject/session/session.cpp b/src/proc/mobject/session/session.cpp index f15f16192..f5513574a 100644 --- a/src/proc/mobject/session/session.cpp +++ b/src/proc/mobject/session/session.cpp @@ -34,6 +34,7 @@ #include "proc/mobject/session.hpp" #include "proc/mobject/session/defsmanager.hpp" #include "proc/mobject/session/session-impl.hpp" +#include "proc/mobject/session/sess-manager-impl.hpp" #include "lib/symbol.hpp" #include "lib/singleton.hpp" From d6584151443e16bd5204bb11d0cae6ff5406c4f1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 12 Nov 2009 02:15:02 +0100 Subject: [PATCH 065/377] WIP about providing scope contents discovery, backed by the index --- src/proc/mobject/session/placement-index.hpp | 6 ++--- src/proc/mobject/session/query-resolver.cpp | 2 +- src/proc/mobject/session/query-resolver.hpp | 9 ++++++++ src/proc/mobject/session/session-impl.hpp | 8 ++++++- .../session/session-service-explore-scope.hpp | 5 +++- src/proc/mobject/session/session-services.cpp | 16 ++++++++++++- .../session/placement-index-query-test.cpp | 23 +++++++++++++------ .../proc/mobject/session/scope-query-test.cpp | 9 ++++---- 8 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index e1e163407..6379f69b8 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -89,7 +89,7 @@ namespace session { PlacementMO& getScope (PlacementMO const&) const; PlacementMO& getScope (ID) const; - vector getReferrers (ID) const; + vector getReferrers (ID) const; ///////////////TODO: interface for low level enumeration /** retrieve the logical root scope */ @@ -105,10 +105,10 @@ namespace session { query (PlacementMO& scope) const; operator string() const { return "PlacementIndex"; } -////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper - bool canHandleQuery(QID) const; +////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper + /* == mutating operations == */ diff --git a/src/proc/mobject/session/query-resolver.cpp b/src/proc/mobject/session/query-resolver.cpp index af618310d..5b01ef3c5 100644 --- a/src/proc/mobject/session/query-resolver.cpp +++ b/src/proc/mobject/session/query-resolver.cpp @@ -103,7 +103,7 @@ namespace session { { TODO ("ensure proper initialisation"); - if (!canHandleQuery (query.getQID())) + if (!canHandle (query)) throw lumiera::error::Invalid ("unable to resolve this kind of query"); ////TICKET #197 return dispatcher_->handle(query); diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index 07808a3bf..5b979a315 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -259,6 +259,8 @@ namespace session { */ PReso issue (Goal const& query) const; + bool canHandle (Goal const&) const; + protected: /* ===== API for concrete query resolvers ===== */ @@ -295,5 +297,12 @@ namespace session { } + inline bool + QueryResolver::canHandle(Goal const& query) + { + return canHandleQuery (query.getQID()); + } + + }} // namespace mobject::session #endif diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp index c757c9c44..c120251cc 100644 --- a/src/proc/mobject/session/session-impl.hpp +++ b/src/proc/mobject/session/session-impl.hpp @@ -138,12 +138,18 @@ namespace session { : IMPL { QueryResolver& - getResolver() + getScopeQueryResolver() { UNIMPLEMENTED ("how actually to manage the PlacementIndexQueryResolver wrapper instance"); // return IMPL::magic_; } + + PlacementMO& + getScopeRoot() + { + return IMPL::getPlacementIndex()->getRoot(); + } }; diff --git a/src/proc/mobject/session/session-service-explore-scope.hpp b/src/proc/mobject/session/session-service-explore-scope.hpp index 356a29a29..f3ef6829b 100644 --- a/src/proc/mobject/session/session-service-explore-scope.hpp +++ b/src/proc/mobject/session/session-service-explore-scope.hpp @@ -46,6 +46,7 @@ #ifndef MOBJECT_SESSION_SESSION_SERVICE_EXPLORE_SCOPE_H #define MOBJECT_SESSION_SESSION_SERVICE_EXPLORE_SCOPE_H +#include "proc/mobject/placement.hpp" #include "proc/mobject/session/query-resolver.hpp" //#include "lib/meta/generator.hpp" @@ -62,7 +63,9 @@ namespace session { struct SessionServiceExploreScope { - static QueryResolver& getResolver(); + static QueryResolver const& getResolver(); + + static PlacementMO& getScopeRoot(); }; diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp index c0128ae38..87392fe55 100644 --- a/src/proc/mobject/session/session-services.cpp +++ b/src/proc/mobject/session/session-services.cpp @@ -67,9 +67,23 @@ namespace session { { return SessionImplAPI::current->reset_PlacementIndex (alternativeIndex); } - + /** */ + QueryResolver const& + SessionServiceExploreScope::getResolver() + { + return SessionImplAPI::current->getScopeQueryResolver(); + } + + + /** */ + PlacementMO& + SessionServiceExploreScope::getScopeRoot() + { + return SessionImplAPI::current->getScopeRoot(); + } + }} // namespace mobject::session diff --git a/tests/components/proc/mobject/session/placement-index-query-test.cpp b/tests/components/proc/mobject/session/placement-index-query-test.cpp index f77b270dc..f2d674af1 100644 --- a/tests/components/proc/mobject/session/placement-index-query-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-query-test.cpp @@ -24,6 +24,7 @@ #include "lib/test/run.hpp" #include "proc/mobject/session/query-resolver.hpp" #include "proc/mobject/session/scope-query.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" #include "proc/mobject/session/placement-index-query-resolver.hpp" #include "proc/mobject/session/test-scopes.hpp" #include "lib/util.hpp" @@ -59,19 +60,26 @@ namespace test { virtual void run (Arg) { - checkQueryResolverWrapper(); + checkQueryResolver(); checkQueryOperations(); } void - checkQueryResolverWrapper() + checkQueryResolver() { PPIdx index = build_testScopes(); - QueryResolver const& resolver1 (*index); - QueryResolver const& resolver2 (*index); + QueryResolver const& resolver1 (SessionServiceExploreScope::getResolver()); + QueryResolver const& resolver2 (SessionServiceExploreScope::getResolver()); ASSERT (isSameObject (resolver1, resolver2)); - index = build_testScopes(); + + PlacementMO& root1 = index->getRoot(); + PlacementMO& root2 = SessionServiceExploreScope::getScopeRoot(); + ASSERT (isSameObject (root1, root2)); + + PlacementMO& elm1 = *ContentsQuery(resolver1,root1); +// PlacementMO& elm2 = index->getReferrers(root1); //////////////TODO: interface for low level enumeration + ASSERT (isSameObject (elm1, elm2)); } void @@ -80,11 +88,12 @@ namespace test { #if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #384 !!!!!!!!! // Prepare an (test)Index (dummy "session") PPIdx index = build_testScopes(); + PlacementMO& root = index->getRoot(); PlacementIndexQueryResolver resolver(index); - discover (ContentsQuery (resolver)); + discover (ContentsQuery (resolver,root)); - PlacementMO& elm = *ContentsQuery(resolver); + PlacementMO& elm = *ContentsQuery(resolver,root); discover (PathQuery(resolver,elm)); #endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! diff --git a/tests/components/proc/mobject/session/scope-query-test.cpp b/tests/components/proc/mobject/session/scope-query-test.cpp index b360e6457..5714eafeb 100644 --- a/tests/components/proc/mobject/session/scope-query-test.cpp +++ b/tests/components/proc/mobject/session/scope-query-test.cpp @@ -22,7 +22,7 @@ #include "lib/test/run.hpp" -#include "proc/mobject/session/query-resolver.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" #include "proc/mobject/session/scope-query.hpp" #include "proc/mobject/session/test-scopes.hpp" //#include "lib/util.hpp" @@ -62,9 +62,10 @@ namespace test { run (Arg) { // Prepare an (test)Index (dummy "session") - PPIdx index = build_testScopes(); - PlacementMO& scope (index->getRoot()); - QueryResolver const& resolver (*index); + build_testScopes(); + + QueryResolver const& resolver = SessionServiceExploreScope::getResolver(); + PlacementMO const& scope = SessionServiceExploreScope::getScopeRoot(); discover (ScopeQuery (resolver,scope, "contents")); discover (ScopeQuery (resolver,scope, "contents")); From a1448ed6f6bb9d9d141885a3a65d26c6fbad94f6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 12 Nov 2009 20:15:52 +0100 Subject: [PATCH 066/377] WIP first attempt to remove the query-interface from PlacementIndex --- .../placement-index-query-resolver.hpp | 25 +++++++++++++ src/proc/mobject/session/placement-index.cpp | 5 ++- src/proc/mobject/session/placement-index.hpp | 37 ++++++------------- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index 0061f801e..62a381379 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -69,8 +69,33 @@ namespace session { : public session::QueryResolver { +////////////////////////////////////////////////////////////////TODO: moved in from PlacementIndex + template + typename session::Query >::iterator + query (PlacementMO& scope) const; + + operator string() const { return "PlacementIndex"; } + + bool canHandleQuery(QID) const; +////////////////////////////////////////////////////////////////TODO: }; + + /** @todo use query-resolver-test as an example..... + * return a result set object derived from Resolution + * For the additional type filtering: build a filter iterator, + * using a type-filtering predicate, based on Placement#isCompatible + */ + template + inline typename session::Query >::iterator + PlacementIndex::query (PlacementMO& scope) const + { + UNIMPLEMENTED ("actually run the containment query"); + } +////////////////////////////////////////////////////////////////TODO: + + + }} // namespace mobject::session #endif diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index c1d10f5a3..a02b48725 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -125,10 +125,13 @@ namespace session { } - vector + PlacementIndex::iterator PlacementIndex::getReferrers (ID) const { UNIMPLEMENTED ("query the Placement relation index and retrieve all other placements bound to this one by a placement-relation"); + // do a query using equal_range of the hashtable (unordered_multimap) + // build a RangeIter from them + // use this to build an auto-fetching IterAdapter } diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index 6379f69b8..db199b0c6 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -38,11 +38,13 @@ //#include "proc/asset/pipe.hpp" #include "lib/util.hpp" #include "lib/factory.hpp" +#include "lib/iter-adapter.hpp" #include "proc/mobject/placement.hpp" #include "proc/mobject/placement-ref.hpp" -#include "proc/mobject/session/query-resolver.hpp" +//#include "proc/mobject/session/query-resolver.hpp" #include +#include #include #include #include @@ -59,7 +61,7 @@ namespace session { using boost::scoped_ptr; using std::vector; - +//using boost::hash; /** */ @@ -71,12 +73,18 @@ namespace session { scoped_ptr
                                    pTab_; + + typedef PlacementMO::ID _PlID; + typedef std::tr1::unordered_multimap<_PlID,_PlID>::iterator ScopeIter; + + public: typedef Placement PlacementMO; typedef PlacementRef PRef; typedef PlacementMO::ID const& ID; - typedef session::Goal::QueryID const& QID; +// typedef session::Goal::QueryID const& QID; + typedef lib::RangeIter iterator; PlacementMO& find (ID) const; @@ -89,7 +97,7 @@ namespace session { PlacementMO& getScope (PlacementMO const&) const; PlacementMO& getScope (ID) const; - vector getReferrers (ID) const; ///////////////TODO: interface for low level enumeration + iterator getReferrers (ID) const; /** retrieve the logical root scope */ @@ -99,15 +107,6 @@ namespace session { bool contains (PlacementMO const&) const; bool contains (ID) const; -////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper - template - typename session::Query >::iterator - query (PlacementMO& scope) const; - - operator string() const { return "PlacementIndex"; } - - bool canHandleQuery(QID) const; -////////////////////////////////////////////////////////////////TODO: refactor into explicit query resolving wrapper @@ -163,18 +162,6 @@ namespace session { } - /** @todo use query-resolver-test as an example..... - * return a result set object derived from Resolution - * For the additional type filtering: build a filter iterator, - * using a type-filtering predicate, based on Placement#isCompatible - */ - template - inline typename session::Query >::iterator - PlacementIndex::query (PlacementMO& scope) const - { - UNIMPLEMENTED ("actually run the containment query"); - } - inline Placement& PlacementIndex::getScope (PlacementMO const& p) const { From a86517bd4f3671e013c66166ca008734a1573191 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 13 Nov 2009 01:02:31 +0100 Subject: [PATCH 067/377] extend the protocol of the itertools core, abstracting the increment --- src/lib/itertools.hpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/lib/itertools.hpp b/src/lib/itertools.hpp index 3c541242a..2e730634f 100644 --- a/src/lib/itertools.hpp +++ b/src/lib/itertools.hpp @@ -98,17 +98,23 @@ namespace lib { { } IT& - source () + pipe () { return source_; } IT const& - source () const + pipe () const { return source_; } + void + advance () + { + ++source_; + } + bool evaluate () const { @@ -146,11 +152,11 @@ namespace lib { bool iterate () { - if (!core_.source()) return false; + if (!core_.pipe()) return false; - do ++core_.source(); - while (core_.source() && !core_.evaluate()); - return core_.source(); + do core_.advance(); + while (core_.pipe() && !core_.evaluate()); + return core_.pipe(); } void @@ -182,14 +188,14 @@ namespace lib { operator*() const { _maybe_throw(); - return *core_.source(); + return *core_.pipe(); } pointer operator->() const { _maybe_throw(); - return core_.source(); + return core_.pipe(); } IterTool& @@ -213,7 +219,7 @@ namespace lib { } - /// comparison is allowed to access the source iterator + /// comparison is allowed to access the feed pipe from core template friend bool operator== (IterTool const& it1, IterTool const& it2); }; @@ -223,8 +229,8 @@ namespace lib { inline bool operator== (IterTool const& it1, IterTool const& it2) { - return it1.isValid() == it2.isValid() - && it1.core_.source() == it2.core_.source() + return it1.isValid() == it2.isValid() + && it1.core_.pipe() == it2.core_.pipe() ; } @@ -261,8 +267,8 @@ namespace lib { bool evaluate () const { - return _Par::source() - && predicate_(*_Par::source()); + return _Par::pipe() + && predicate_(*_Par::pipe()); } From d0c905b5c9fb5131c8b1fb19c5951ebc0b5c2b4a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 13 Nov 2009 03:26:20 +0100 Subject: [PATCH 068/377] add an transforming iterator to the itertools --- src/lib/itertools.hpp | 164 ++++++++++++++++++++++++++++++++--- tests/40components.tests | 3 + tests/lib/itertools-test.cpp | 36 +++++++- 3 files changed, 191 insertions(+), 12 deletions(-) diff --git a/src/lib/itertools.hpp b/src/lib/itertools.hpp index 2e730634f..b6fa7fb47 100644 --- a/src/lib/itertools.hpp +++ b/src/lib/itertools.hpp @@ -38,7 +38,7 @@ ** (IterTool) exposes the operations necessary to comply to the ** Forward Iterator Concept. ** - ** \par Filtering Iterator + ** \par filtering Iterator ** The FilterIter template can be used to build a filter into a pipeline, ** as it forwards only those elements from its source iterator, which pass ** the predicate evaluation. Anything acceptable as ctor parameter for a @@ -46,8 +46,15 @@ ** signature must be sensible. Please note, that -- depending on the ** predicate -- already the ctor or even a simple \c bool test might ** pull and exhaust the source iterator completely, in an attempt - ** to find the first element passing the predicate test. - ** + ** to find the first element passing the predicate test. + ** + ** \par processing Iterator + ** the TransformIter template can be used as processing (or transforming) + ** step within the pipeline. It is created with a functor, which, when + ** pulling elements, is invoked for each element pulled from the + ** source iterator. The signature of the functor must match the + ** desired value (output) type. + ** ** @todo WIP WIP WIP ** @todo see Ticket #347 ** @@ -63,6 +70,7 @@ #include "lib/bool-checkable.hpp" #include "lib/iter-adapter.hpp" +#include "lib/meta/function.hpp" #include "lib/util.hpp" #include @@ -91,7 +99,7 @@ namespace lib { template struct IdentityCore { - mutable IT source_; + IT source_; IdentityCore (IT const& orig) : source_(orig) @@ -218,10 +226,6 @@ namespace lib { return !isValid(); } - - /// comparison is allowed to access the feed pipe from core - template - friend bool operator== (IterTool const& it1, IterTool const& it2); }; @@ -229,8 +233,8 @@ namespace lib { inline bool operator== (IterTool const& it1, IterTool const& it2) { - return it1.isValid() == it2.isValid() - && it1.core_.pipe() == it2.core_.pipe() + return (!it1 && !it2 ) + || ( it1 && it2 && (*it1) == (*it2) ) ; } @@ -322,5 +326,145 @@ namespace lib { + + + + + /** + * Implementation of custom processing logic. + * This core stores a function object instance + * to treat each source element pulled. + */ + template + class TransformingCore + { + typedef typename IT::reference InType; + + function trafo_; + + IT source_; + VAL treated_; + + void + processItem () + { + if (source_) + treated_ = trafo_(*source_); + } + + VAL* + yieldResult () const + { + if (source_) + return &unConst(this)->treated_; // accessing processed value doesn't count as "mutation" of *this + else + return 0; // signalling exhausted source + } + + + public: + TransformingCore () ///< deactivated core + : trafo_() + , source_() + , treated_() + { } + + template + TransformingCore (IT const& orig, FUN processor) + : trafo_(processor) // induces a signature check + , source_(orig) + { + processItem(); + } + + VAL * + pipe () const + { + return yieldResult(); + } + + void + advance () + { + ++source_; + processItem(); + } + + bool + evaluate () const + { + return bool(source_); + } + + typedef VAL* pointer; + typedef VAL& reference; + typedef VAL value_type; + }; + + + /** + * Iterator tool treating pulled data by a custom transformation (function) + */ + template + class TransformIter + : public IterTool > + { + typedef TransformingCore _Trafo; + typedef IterTool<_Trafo> _IteratorImpl; + + public: + TransformIter () + : _IteratorImpl(_Trafo()) + { } + + template + TransformIter (IT const& src, FUN trafoFunc) + : _IteratorImpl(_Trafo(src,trafoFunc)) + { } + + }; + + + + namespace { // Helper to pick up the produced value type automatically + + using lumiera::typelist::FunctionSignature; + + template + struct _ProducedOutput + { + typedef typename FunctionSignature >::Ret Type; + }; + + template + struct _ProducedOutput > + { + typedef typename FunctionSignature >::Ret Type; + }; + + template + struct _ProducedOutput + { + typedef typename FunctionSignature >::Ret Type; + }; + } + + + /** Build a TransformIter: convenience free function shortcut, + * picking up the involved types automatically. + * @param processingFunc to be invoked for each source element + * @return Iterator processing the source feed + */ + template + inline TransformIter::Type> + transformIterator (IT const& src, FUN processingFunc) + { + typedef typename _ProducedOutput::Type OutVal; + return TransformIter(src,processingFunc); + } + + + + } // namespace lib #endif diff --git a/tests/40components.tests b/tests/40components.tests index adc44631e..bcdfa0f3c 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -334,6 +334,9 @@ out: ::19::17::15::13::11::9::7::5::3::1 out: ::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1 out: ::16::14::12::10::8::6::4::2 out: ::17::15::13::11::9::7::5::3::1 +out: ::10::9::8::7::6::5::4::3::2::1 +out: ::-10::-9::-8::-7::-6::-5::-4::-3::-2::-1 +out: ::12::11::10::9::8::7::6::5::4::3 END diff --git a/tests/lib/itertools-test.cpp b/tests/lib/itertools-test.cpp index baa74bc11..8599f080f 100644 --- a/tests/lib/itertools-test.cpp +++ b/tests/lib/itertools-test.cpp @@ -78,7 +78,7 @@ namespace test{ /******************************************************************************* * @test build combined and filtering iterators with the help of lib::IterTool. - * Check correct behaviour of the resulting iterator and + * Check correct behaviour of the resulting iterators and * verify they fulfil the Lumiera Forward Iterator concept * * @todo implement more iterator tools.... see Ticket #347 @@ -104,6 +104,8 @@ namespace test{ Iter ii (source.begin()); ++++++ii; buildFilterIterator (ii); + + buildTransformingIterator (source.begin()); } @@ -120,8 +122,8 @@ namespace test{ static bool takeAll (int) { return true; } - static bool takeEve (int i) { return 0 == i % 2; } static bool takeOdd (int i) { return 0 != i % 2; } + static bool takeEve (int i) { return 0 == i % 2; } void buildFilterIterator (Iter const& ii) @@ -145,6 +147,36 @@ namespace test{ + static ulong addTwo (int i) { return i+2; } + static int negate (int i) { return -i; } + static int idFunc (int i) { return i; } + + void + buildTransformingIterator (Iter const& ii) + { + pullOut (transformIterator(ii, idFunc)); + pullOut (transformIterator(ii, negate)); + pullOut (transformIterator(ii, addTwo)); // note: changing output type to unsigned + + TransformIter idi (ii, idFunc); + TransformIter neg (ii, negate); + verifyComparisons (idi); + verifyComparisons (neg); + + ASSERT (idi); + ASSERT (neg); + for ( ;idi&&neg; + ++idi,++neg) + ASSERT (idi != neg); + + ASSERT (!idi && !neg); + ASSERT (idi == neg); + } + + + + + /** @test verify equality handling and NIL detection * for the given iterator/wrapper handed in */ template From 981ea94708a388e35fab5844cbb93eebb33ea51e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 13 Nov 2009 04:52:48 +0100 Subject: [PATCH 069/377] finished the PlacementIndex API. --- src/lib/iter-adapter.hpp | 3 +- .../placement-index-query-resolver.hpp | 16 ++++++- src/proc/mobject/session/placement-index.cpp | 11 ----- src/proc/mobject/session/placement-index.hpp | 48 +++++++++++++------ src/proc/mobject/session/query-resolver.hpp | 4 +- .../session/placement-index-query-test.cpp | 2 +- wiki/renderengine.html | 25 ++++++---- 7 files changed, 68 insertions(+), 41 deletions(-) diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 4d386f86e..cdec86476 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -65,6 +65,7 @@ ** ** @todo WIP WIP WIP ** @todo see Ticket #182 + ** @todo naming of the iteration control function: TICKET #410 ** ** @see scoped-ptrvect.hpp */ @@ -236,7 +237,7 @@ namespace lib { bool checkPos() const { - return source_ && hasNext (source_,pos_); + return source_ && hasNext (source_,pos_); //////////////TICKET #410 } /** ask the controlling container to yield the next position. diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index 62a381379..66bb2be47 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -70,6 +70,8 @@ namespace session { { ////////////////////////////////////////////////////////////////TODO: moved in from PlacementIndex + typedef session::Goal::QueryID const& QID; + template typename session::Query >::iterator query (PlacementMO& scope) const; @@ -89,10 +91,22 @@ namespace session { */ template inline typename session::Query >::iterator - PlacementIndex::query (PlacementMO& scope) const + PlacementIndexQueryResolver::query (PlacementMO& scope) const { UNIMPLEMENTED ("actually run the containment query"); } + + + bool + PlacementIndexQueryResolver::canHandleQuery (QID qID) const + { + UNIMPLEMENTED ("decide by hard-wired check if the given Query can be resolved by PlacementIndex"); + return session::Goal::GENERIC == qID.kind; + // thats not enough! need to check the typeID (match to Placement, with some fixed MOX values) + } + + + ////////////////////////////////////////////////////////////////TODO: diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index a02b48725..b114e1a4e 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -64,8 +64,6 @@ namespace session { typedef PlacementIndex::PRef PRef; typedef PlacementIndex::ID ID; - typedef PlacementIndex::QID QID; //////////TODO - /** @internal Factory for creating a new placement index. * For use by the Session and for unit tests. @@ -79,15 +77,6 @@ namespace session { PlacementIndex::~PlacementIndex() { } - bool - PlacementIndex::canHandleQuery (QID qID) const - { - UNIMPLEMENTED ("decide by hard-wired check if the given Query can be resolved by PlacementIndex"); - return session::Goal::GENERIC == qID.kind; - // thats not enough! need to check the typeID (match to Placement, with some fixed MOX values) - } - - PlacementMO& PlacementIndex::getRoot() const { diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index db199b0c6..49a5a0863 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -21,7 +21,20 @@ */ -/** @file placement-index.hpp +/** @file placement-index.hpp + ** Key interface of the session implementation datastructure. + ** The PlacementIndex is attached to and controlled by the SessionImpl. + ** Client code is not intended to interface directly to this API. Even + ** Proc-Layer internal facilities use the session datastructure through + ** SessionServices. Embedded within the implementation of PlacementIndex + ** is a flat table structure holding all the Placement instances \em contained + ** in the session. Any further structuring exists on the logical level only. + ** + ** \par PlacementIndex, PlacementRef and MObjectRef + ** TODO + ** + ** \par Querying and contents discovery + ** TODO ** ** @see PlacementRef ** @see PlacementIndex_test @@ -38,10 +51,9 @@ //#include "proc/asset/pipe.hpp" #include "lib/util.hpp" #include "lib/factory.hpp" -#include "lib/iter-adapter.hpp" +#include "lib/itertools.hpp" #include "proc/mobject/placement.hpp" #include "proc/mobject/placement-ref.hpp" -//#include "proc/mobject/session/query-resolver.hpp" #include #include @@ -59,23 +71,33 @@ namespace session { using lib::factory::RefcountFac; using std::tr1::shared_ptr; using boost::scoped_ptr; - using std::vector; -//using boost::hash; + + class PlacementIndex; + typedef shared_ptr PPIdx; /** + * Structured compound of Placement instances + * with lookup capabilities. Core of the session datastructure. + * Adding a Placement creates a separate instance within this network, + * owned and managed by the backing implementation. All placements are + * related in a tree-like hierarchy of scopes, where each Placement is + * within the scope of a parent Placement. There is an additional + * reverse index, allowing to find the immediate children of any + * given Placement efficiently. All lookup is based on the + * Placement's hash-IDs. */ class PlacementIndex - : public session::QueryResolver ////////TODO: really inherit here? -// , boost::noncopyable ////////TODO : where to put the "noncopyable" base + : boost::noncopyable { class Table; scoped_ptr
                                    pTab_; - typedef PlacementMO::ID _PlID; - typedef std::tr1::unordered_multimap<_PlID,_PlID>::iterator ScopeIter; + typedef PlacementMO::ID _PID; + typedef std::tr1::unordered_multimap<_PID,_PID>::iterator ScopeIter; + public: @@ -83,8 +105,7 @@ namespace session { typedef PlacementRef PRef; typedef PlacementMO::ID const& ID; -// typedef session::Goal::QueryID const& QID; - typedef lib::RangeIter iterator; + typedef lib::TransformIter, PlacementMO> iterator; PlacementMO& find (ID) const; @@ -130,11 +151,8 @@ namespace session { friend class lib::factory::Factory > >; }; - ////////////////TODO currently just fleshing out the API; probably have to split off an impl.class; but for now a PImpl is sufficient... - - typedef shared_ptr PPIdx; - + diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index 5b979a315..344f31a28 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -213,7 +213,7 @@ namespace session { friend bool - hasNext (PReso const&, Result const& pos) ////TICKET #375 + hasNext (PReso const&, Result const& pos) ////TICKET #410 { return bool(pos); } @@ -298,7 +298,7 @@ namespace session { inline bool - QueryResolver::canHandle(Goal const& query) + QueryResolver::canHandle(Goal const& query) const { return canHandleQuery (query.getQID()); } diff --git a/tests/components/proc/mobject/session/placement-index-query-test.cpp b/tests/components/proc/mobject/session/placement-index-query-test.cpp index f2d674af1..b4b8cbb14 100644 --- a/tests/components/proc/mobject/session/placement-index-query-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-query-test.cpp @@ -78,7 +78,7 @@ namespace test { ASSERT (isSameObject (root1, root2)); PlacementMO& elm1 = *ContentsQuery(resolver1,root1); -// PlacementMO& elm2 = index->getReferrers(root1); //////////////TODO: interface for low level enumeration + PlacementMO& elm2 = *(index->getReferrers(root1)); ASSERT (isSameObject (elm1, elm2)); } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 897c8b74c..9cc4528a0 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3064,39 +3064,44 @@ Placements have //value semantics,// i.e. we don't stress the identity of a plac -
                                    +
                                    An implementation facility used to keep track of individual Placements and their relations.
                                     Especially, the [[Session]] maintains such an index, allowing to use the (opaque) PlacementRef tags for referring to a specific "instance" of an MObject, //placed// in a unique way into the current session. And, moreover, this index allows for one placement referring to another placement, so to implement a //relative// placement mode. Because there is an index behind the scenes, it is possible to actually access such a referral in the reverse direction, which is necessary for implementing the desired placement behaviour (if an object instance used as anchor is moved, all objects placed relatively to it have to move accordingly, which necessitates finding those other objects).
                                     
                                    -!questions {{red{WIP}}}
                                    -What implementation approach to take for the index. This of course largely depends on the usage pattern, which in turn is not-yet existent. To start with, we need a preliminary implementation!
                                    +Besides searching, [[placement instances|Placement]] can be added to the index, thereby creating a copy managed by the backing data structure. Thus, the session's PlacementIndex is the main interface to the session data structure, and the session's contents are actually contained within it.
                                     
                                    -Using a ''flat hashtable'' would allow to access a Placement denoted by ID in O(1). This way we could get the Placement, but nothing more. So, additionally we'd have to set up an data record holding additional information:
                                    +!discussion of implementation possibilities
                                    +What implementation approach to take for the index largely depends on the usage pattern. Generally speaking, the Lumiera [[Session]] is a collection of MObjects attached by [[Placement]]; any relations between these objects are established on a logical level, implemented as markers within the respective placements. For [[building the render nodes graph|BuildProcess]], a consolidated view of the session's effective contents is created ("[[Fixture]]"), then to be traversed while emitting the LowLevelModel. The GUI is expected to query the index to discover parts of the structure; the [[object reference tags|MObjectRef]] returned by these queries will be used as arguments to any mutating operation on the objects within the session.
                                    +
                                    +Using a ''flat hashtable'' allows to access a Placement denoted by ID in O(1). This way we get the Placement, but nothing more. So, additionally we'd have to set up an data record holding additional information:
                                     * the [[scope|PlacementScope]] containing this placement
                                     * especially the path "up" from this scope, which is used for resolving any queries
                                     * relations to other placements
                                     
                                    -Alternatively, we could try to use a ''structure based index''. Following this idea, we could try to avoid the mentioned description record by folding any of the contained informations into the surrounding data structure:
                                    +Alternatively, we could try to use a ''structure based index'', thereby avoiding the mentioned description record by folding any of the contained informations into the surrounding data structure:
                                     * the scope would be obvious from the index, resp. from the path used to resolve this index
                                     * any other informations, especially the relations, would be folded into the placement
                                     * this way, the "index" could be reduced to being the session data structure itself.
                                     
                                     
                                     !supported operations
                                    -The placement index is utilized by editing operations, by executing the build process. Besides these core operations it allows for resolving PlacementRef objects. This latter functionality is used by all kinds of relative placements and for dealing with them while building, but it is also used to resolve [[object reference tags|MObjectRef]], which possibly may have been handed out via an external API or may have crossed layer boundaries. From these use cases we derive the following main operations to support:
                                    +The placement index is utilized by editing operations and by executing the build process. Besides these core operations it allows for resolving PlacementRef objects. This latter functionality is used by all kinds of relative placements and for dealing with them while building, but it is also used to resolve [[object reference tags|MObjectRef]], which possibly may have been handed out via an external API or may have crossed layer boundaries. From these use cases we derive the following main operations to support:
                                     * find the actual [[Placement]] object for a given ID
                                     * find the //scope//&nbsp; a given placement resides in. More specifically, find the [[placement defining this scope|PlacementScope]]
                                    -* find (any/all) other placements referring to a given placement
                                    +* find (any/all) other placements referring to a given placement ("within this scope")
                                     * add a new placement to a scope given as parameter
                                     * remove a placement from index
                                     
                                     //does a placement need to know it's own ID?// &nbsp; Obviously, there needs to be a way to find out the ID for a given placement, especially in the following situations:
                                    -* for most of the operations above, when querying some additional informations from index for a given placement
                                    +* for most of the operations above, when querying additional informations from index for a given placement
                                     * to create a PlacementRef (this is a variant of the "shared ptr from this"-problem)
                                    -On second sight, this problem seems to be quite nasty, because either we have to keep a second index table for the reversed lookup (memory address -> ID), or have to tie the placement by a back-link when adding it to the index/session data structure, or (at least) it forces us to store a copy of the ID //within// the placement itself. The last possibility seems to create the least impact; but implementing it this way effectively gears the implementation towards a hashtable based approach.
                                    +On second sight, this problem turns out to be more involved, because either we have to keep a second index table for the reverse lookup (memory address -> ID), or have to tie the placement by a back-link when adding it to the index/session data structure, or (alternatively) it forces us to store a copy of the ID //within// the placement itself. The last possibility seems to create the least impact; but implementing it this way effectively gears the implementation towards a hashtable based approach.
                                     
                                     !implementation {{red{WIP}}}
                                    -Consequently, we incorporate a random hash (implemented as {{{LUID}}}) into the individual placement, this way creating an distinguishable //placement identity,// which is retained on copying of the placement. The actual ID tag is complemented by a compile time type (template parameter), thus allowing to pass on additional context information through API calls.
                                    +Consequently, we incorporate a random hash (implemented as {{{LUID}}}) into the individual placement, this way creating an distinguishable //placement identity,// which is //not retained on copying.// The actual ID tag is complemented by a compile time type (template parameter), thus allowing to pass on additional context information through API calls. Placements themselves use a vtable (and thus RTTI), allowing to re-discover the exact type at runtime. Any further relation information is contained within the placement's [[locating pins|LocatingPin]], thus, any further description records can be avoided by storing the placements immediately //within the index.// To summarise, the implementation is comprised of
                                    +* a main table resolving hash-ID to storage location
                                    +* a reverse lookup table to find the enclosing scope
                                    +* an instance holding and managing facility based on pooled allocation
                                     
                                    From 017c668d7aeb8656e98096742d1cbb0165c09757 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 13 Nov 2009 16:32:22 +0100 Subject: [PATCH 070/377] WIP outline of the index query resolution --- src/proc/mobject/placement.hpp | 2 +- .../placement-index-query-resolver.hpp | 72 ++++++++++++++++++- src/proc/mobject/session/query-resolver.hpp | 2 +- .../session/placement-index-query-test.cpp | 2 - 4 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/proc/mobject/placement.hpp b/src/proc/mobject/placement.hpp index 4f2ff9d95..d9622841c 100644 --- a/src/proc/mobject/placement.hpp +++ b/src/proc/mobject/placement.hpp @@ -230,7 +230,7 @@ namespace mobject { format_PlacementID (Placement const&) ; - /** @todo cleanup uses of ref-to-placement. See Trac #115 */ + /** @todo cleanup uses of ref-to-placement. See Ticket #115 */ typedef Placement PlacementMO; typedef Placement PMO; diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index 66bb2be47..2b5c5c203 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -42,6 +42,7 @@ //#include "proc/mobject/placement.hpp" #include "proc/mobject/session/placement-index.hpp" #include "proc/mobject/session/query-resolver.hpp" +#include "proc/mobject/session/scope-query.hpp" //#include //#include @@ -68,7 +69,9 @@ namespace session { class PlacementIndexQueryResolver : public session::QueryResolver { - + PPIdx index_; + + typedef PlacementIndex::ID PID; ////////////////////////////////////////////////////////////////TODO: moved in from PlacementIndex typedef session::Goal::QueryID const& QID; @@ -79,7 +82,72 @@ namespace session { operator string() const { return "PlacementIndex"; } bool canHandleQuery(QID) const; -////////////////////////////////////////////////////////////////TODO: +////////////////////////////////////////////////////////////////TODO: + + /** + * on query, an individual result set is prepared + * to be explored by the invoking client code. + * It is built wrapping the low-level scope iterator + * obtained from the index, controlled by an + * exploration strategy. + */ + template + struct ResultSet + : Resolution + { + DummySolutions solutions_; + + typedef typename Query::Cursor Cursor; + + Result + prepareResolution() + { + Cursor cursor; + cursor.point_at (solutions_.next()); + return cursor; + } + + void + nextResult(Result& pos) + { + Cursor& cursor = static_cast (pos); + + if (solutions_.exhausted()) + cursor.point_at (0); + else + cursor.point_at (solutions_.next()); + } + }; + + template + static Resolution* + resolutionFunction (Goal const& goal) + { + QID qID = goal.getQID(); + REQUIRE (qID.kind == Goal::DISCOVERY + && qID.type == getResultTypeID >()); /////////////////////////////TODO + REQUIRE (INSTANCEOF(ScopeQuery, &goal)); + ScopeQuery const& query = static_cast const&> (goal); + + Literal direction = query.searchDirection(); + PID scopeID = query.searchScope().getID(); //////////TICKET #411 + + ///////////////////////////TODO: where to put the exploration strategy? statically, dynamically? + //////////////////////////////// note: direction == "parents" works completely different, based on index_->getScope(..) + + return new ResultSet(); + } + + public: + PlacementIndexQueryResolver (PPIdx theIndex) + : index_(theIndex) + { + Goal::QueryID case1 = {Goal::DISCOVERY, getResultTypeID()}; /////////////////TODO + Goal::QueryID case2 = {Goal::DISCOVERY, getResultTypeID()}; + + installResolutionCase(case1, &resolutionFunction ); + installResolutionCase(case2, &resolutionFunction ); + } }; diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index 344f31a28..4328d899d 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -98,7 +98,7 @@ namespace session { class Result : public lib::BoolCheckable { - void *cur_; + void* cur_; protected: void point_at(void* p) { cur_ = p; } diff --git a/tests/components/proc/mobject/session/placement-index-query-test.cpp b/tests/components/proc/mobject/session/placement-index-query-test.cpp index b4b8cbb14..03d773eee 100644 --- a/tests/components/proc/mobject/session/placement-index-query-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-query-test.cpp @@ -85,7 +85,6 @@ namespace test { void checkQueryOperations() { -#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #384 !!!!!!!!! // Prepare an (test)Index (dummy "session") PPIdx index = build_testScopes(); PlacementMO& root = index->getRoot(); @@ -96,7 +95,6 @@ namespace test { PlacementMO& elm = *ContentsQuery(resolver,root); discover (PathQuery(resolver,elm)); -#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! } From a10a237b9017b27fbc9f13ec4a8baa3c170b425e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 14 Nov 2009 23:07:01 +0100 Subject: [PATCH 071/377] rename "MO" --> "MX" to avoid confusion with MObject --- src/proc/mobject/placement-ref.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp index 19023fd53..d4a77549c 100644 --- a/src/proc/mobject/placement-ref.hpp +++ b/src/proc/mobject/placement-ref.hpp @@ -68,12 +68,12 @@ namespace mobject { /** * TODO type comment */ - template + template class PlacementRef { - typedef Placement PlacementMO; + typedef Placement PlacementMX; typedef Placement::ID _ID; ////TODO: could we define const& here?? - typedef Placement::Id _Id; + typedef Placement::Id _Id; _Id id_; @@ -115,7 +115,7 @@ namespace mobject { } template - PlacementRef (PlacementRef const& r) ///< extended copy ctor, when type X is assignable to MO + PlacementRef (PlacementRef const& r) ///< extended copy ctor, when type X is assignable to MX : id_(recast(r)) { validate(id_); @@ -151,9 +151,9 @@ namespace mobject { /* == forwarding smart-ptr operations == */ - PlacementMO& operator*() const { return access(id_); } ///< dereferencing fetches referred Placement from Index + PlacementMX& operator*() const { return access(id_); } ///< dereferencing fetches referred Placement from Index - PlacementMO& operator->() const { return access(id_); } ///< provide access to pointee API by smart-ptr chaining + PlacementMX& operator->() const { return access(id_); } ///< provide access to pointee API by smart-ptr chaining operator string() const { return access(id_).operator string(); } size_t use_count() const { return access(id_).use_count(); } @@ -210,8 +210,8 @@ namespace mobject { static void validate (_Id const& rId) { - PlacementMO& pRef (access (rId)); - if (!(pRef.template isCompatible())) + PlacementMX& pRef (access (rId)); + if (!(pRef.template isCompatible())) throw lumiera::error::Invalid("actual type of the resolved placement is incompatible",LUMIERA_ERROR_INVALID_PLACEMENTREF); ////////////////////////TODO: 1. better message, including type? @@ -231,13 +231,13 @@ namespace mobject { return reinterpret_cast<_Id const&> (*luid); } - static PlacementMO& + static PlacementMX& access (_Id const& placementID) { Placement & pla (session::SessionServiceFetch::resolveID (placementID)); // may throw REQUIRE (pla.isValid()); - ASSERT (pla.isCompatible()); - return static_cast (pla); + ASSERT (pla.isCompatible()); + return static_cast (pla); } }; From 7dcb59333dbc6874d5c4fa6e02e51a9a65552ab1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 15 Nov 2009 01:08:29 +0100 Subject: [PATCH 072/377] WIP draft of the complete query-for-session-contents implementation --- .../builder/applicablebuildertargettypes.hpp | 2 +- .../placement-index-query-resolver.hpp | 257 +++++++++++++++--- src/proc/mobject/session/placement-index.cpp | 1 + src/proc/mobject/session/query-resolver.hpp | 1 + src/proc/mobject/session/scope-query.hpp | 2 +- 5 files changed, 222 insertions(+), 41 deletions(-) diff --git a/src/proc/mobject/builder/applicablebuildertargettypes.hpp b/src/proc/mobject/builder/applicablebuildertargettypes.hpp index b02fb9d45..e1c223781 100644 --- a/src/proc/mobject/builder/applicablebuildertargettypes.hpp +++ b/src/proc/mobject/builder/applicablebuildertargettypes.hpp @@ -1,5 +1,5 @@ /* - ApplicableBuilderTargetTypes - definitinon header specifying all types treated by builder tools + ApplicableBuilderTargetTypes - definition header specifying all types treated by builder tools Copyright (C) Lumiera.org 2008, Hermann Vosseler diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index 2b5c5c203..b1c88c3ce 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -46,8 +46,9 @@ //#include //#include -//#include +#include //#include +#include namespace mobject { @@ -58,7 +59,7 @@ namespace session { // using lib::factory::RefcountFac; // using std::tr1::shared_ptr; -// using boost::scoped_ptr; + using boost::scoped_ptr; // using std::vector; @@ -72,8 +73,9 @@ namespace session { PPIdx index_; typedef PlacementIndex::ID PID; -////////////////////////////////////////////////////////////////TODO: moved in from PlacementIndex - typedef session::Goal::QueryID const& QID; +////////////////////////////////////////////////////////////////TODO: moved in from PlacementIndex + typedef Goal::QueryID QueryID; + typedef QueryID const& QID; template typename session::Query >::iterator @@ -83,7 +85,124 @@ namespace session { bool canHandleQuery(QID) const; ////////////////////////////////////////////////////////////////TODO: - + + + typedef PlacementIndex::iterator PIter; + + + /** Interface: strategy for exploring the structure */ + class Explorer + { + public: + virtual ~Explorer() { }; + virtual bool exhausted () =0; + virtual PlacementMO& operator() () =0; + }; + + /** + * Strategy: explore the structure + * just by following the given iterator; + * usually this yields an element's children + */ + class ChildExplorer + { + PIter tip_; + + bool + exhausted() + { + return !tip_; + } + + PlacementMO& + operator() () + { + REQUIRE (tip_); + PlacementMO& pos = *tip_; + ++tip_; + return pos; + } + + public: + ChildExplorer(PIter start) + : tip_(start) + { } + }; + + /** + * Strategy: explore the structure depth first. + * After returning an element, delve into the scope + * defined by this element and so on recursively. + */ + class DeepExplorer + { + PPIdx index_; + std::stack scopes_; + + bool + exhausted() + { + while (!scopes_.empty() && !scopes_.top()) + scopes_.pop(); + return scopes_.empty(); + } + + PlacementMO& + operator() () + { + REQUIRE (!scopes_.empty() && scopes_.top()); + PlacementMO& pos = *scopes_.top(); + ++scopes_.top(); + scopes_.push(index_->getReferrers(pos.getID())); + return pos; + } + + public: + DeepExplorer(PIter start, PPIdx idx) + : index_(idx) + { + scopes_.push(start); + } + }; + + + /** + * Strategy: explore the structure upwards, + * ascending until reaching the root element. + */ + class UpExplorer + { + PPIdx index_; + PlacementMO* tip_; + + bool + exhausted() + { + return !tip_; + } + + PlacementMO& + operator() () + { + REQUIRE (tip_); + PlacementMO& pos = *tip_; + tip_ = &index_->getScope(*tip_); + if (tip_ == &pos) + tip_ = 0; + return pos; + } + + public: + UpExplorer(PlacementMO& start, PPIdx idx) + : index_(idx) + , tip_(&start) + { } + }; + + typedef function ContentFilter; + typedef function ExplorerBuilder; + + /** * on query, an individual result set is prepared * to be explored by the invoking client code. @@ -91,36 +210,89 @@ namespace session { * obtained from the index, controlled by an * exploration strategy. */ - template struct ResultSet : Resolution { - DummySolutions solutions_; + typedef PlacementMO Val; - typedef typename Query::Cursor Cursor; + ContentFilter acceptable_; + ExplorerBuilder buildExploartion_; + scoped_ptr explore_; + + void + exploreNext (Result& res) + { + typedef typename Query::Cursor Cursor; + Cursor& cursor = static_cast (res); + + while (!explore_->exhausted() ) + { + Val& elm (*explore_()); + if (acceptable_(elm)) + { + cursor.point_at (elm); + return; + } + } + + ASSERT (explore_->exhausted()); + cursor.point_at (0); + } Result prepareResolution() { - Cursor cursor; - cursor.point_at (solutions_.next()); + explore_.reset (buildExploartion_()); + + Result cursor; + exploreNext (cursor); return cursor; } void nextResult(Result& pos) { - Cursor& cursor = static_cast (pos); - - if (solutions_.exhausted()) - cursor.point_at (0); - else - cursor.point_at (solutions_.next()); + exploreNext (pos); + return pos; } + + public: + ResultSet (ExplorerBuilder b + ,ContentFilter a) + : acceptable_(a) + , buildExploartion_(b) + , explore_() + { } }; + Explorer* + setupExploration (PID startID, Literal direction) + { + if (direction == "contents") + return new DeepExplorer(index_->getReferrers(startID), index_); + + else if (direction == "children") + return new ChildExplorer(index_->getReferrers(startID)); + + else if (direction == "parents") + return new UpExplorer(index_->getScope(startID),index_); + + else if (direction == "path") + return new UpExplorer(index_->find(startID),index_); + } + template - static Resolution* + void + defineHandling() + { + installResolutionCase( whenQueryingFor() + , bind (&PlacementIndexQueryResolver::resolutionFunction, + this, _1 ) + ); + } + + template + Resolution* resolutionFunction (Goal const& goal) { QID qID = goal.getQID(); @@ -132,39 +304,46 @@ namespace session { Literal direction = query.searchDirection(); PID scopeID = query.searchScope().getID(); //////////TICKET #411 - ///////////////////////////TODO: where to put the exploration strategy? statically, dynamically? - //////////////////////////////// note: direction == "parents" works completely different, based on index_->getScope(..) - - return new ResultSet(); + return new ResultSet( bind (&PlacementIndexQueryResolver::setupExploration, + this, scopeID, direction) + , getContentFilter(query) + ); + } + + template + ContentFilter + getContentFilter (QUERY query) + { + return query.contentFilter(); + } + + ContentFilter + getContentFilter (ScopeQuery) ///< especially queries for MObjects need not be filtered + { + ContentFilter acceptAllObjects = bind (val(true), _1); + return acceptAllObjects; + } + + template + static QueryID + whenQueryingFor() + { + QueryID qID = {Goal::DISCOVERY, getResultTypeID >()}; + return qID; } public: PlacementIndexQueryResolver (PPIdx theIndex) : index_(theIndex) { - Goal::QueryID case1 = {Goal::DISCOVERY, getResultTypeID()}; /////////////////TODO - Goal::QueryID case2 = {Goal::DISCOVERY, getResultTypeID()}; - - installResolutionCase(case1, &resolutionFunction ); - installResolutionCase(case2, &resolutionFunction ); + defineHandling(); + defineHandling(); + defineHandling(); } }; - /** @todo use query-resolver-test as an example..... - * return a result set object derived from Resolution - * For the additional type filtering: build a filter iterator, - * using a type-filtering predicate, based on Placement#isCompatible - */ - template - inline typename session::Query >::iterator - PlacementIndexQueryResolver::query (PlacementMO& scope) const - { - UNIMPLEMENTED ("actually run the containment query"); - } - - bool PlacementIndexQueryResolver::canHandleQuery (QID qID) const { diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index b114e1a4e..3c236feea 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -111,6 +111,7 @@ namespace session { PlacementIndex::getScope (ID) const { UNIMPLEMENTED ("Secondary core operation of PlacmentIndex: find the 'parent' Placement by using the Placement relation index"); + /// decision: root is his own scope } diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index 4328d899d..62a8980d4 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -179,6 +179,7 @@ namespace session { RES* operator->() { return & access(); } void point_at(RES* r){ Goal::Result::point_at(r);} + void point_at(RES& r){ Goal::Result::point_at(&r);} }; diff --git a/src/proc/mobject/session/scope-query.hpp b/src/proc/mobject/session/scope-query.hpp index 72e895851..76db0b088 100644 --- a/src/proc/mobject/session/scope-query.hpp +++ b/src/proc/mobject/session/scope-query.hpp @@ -80,7 +80,7 @@ namespace session { typedef typename _Query::iterator _QIter; - typedef typename _QIter::reference Val; + typedef typename PlacementMO const& Val; public: From 34dc8fa4de71f10118c36a909df712f42ecaca13 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 15 Nov 2009 01:09:21 +0100 Subject: [PATCH 073/377] mark for later high-level model extension (Ticket #414) --- src/proc/mobject/builder/applicablebuildertargettypes.hpp | 1 + src/proc/mobject/session/placement-index-query-resolver.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/proc/mobject/builder/applicablebuildertargettypes.hpp b/src/proc/mobject/builder/applicablebuildertargettypes.hpp index e1c223781..5d4360131 100644 --- a/src/proc/mobject/builder/applicablebuildertargettypes.hpp +++ b/src/proc/mobject/builder/applicablebuildertargettypes.hpp @@ -47,6 +47,7 @@ namespace mobject { session::AbstractMO > ::List BuilderTargetTypes; + /////////////////////////////////TICKET #414 /** diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index b1c88c3ce..c1e21aaac 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -339,6 +339,7 @@ namespace session { defineHandling(); defineHandling(); defineHandling(); + ///////////////////////////////////////TICKET #414 } }; From 046dab0ca3729dd0a4aafae7378c1e20ad38a152 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 14 Nov 2009 22:19:04 -0500 Subject: [PATCH 074/377] Add missing nobugmt ld flags to test_threads --- tests/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index c33287932..765339aea 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -118,7 +118,7 @@ test_interfaces_LDADD = \ check_PROGRAMS += test-threads test_threads_SOURCES = $(tests_srcdir)/backend/test-threads.c test_threads_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_threads_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) -test_threads_LDADD = liblumierabackend.la liblumiera.la -lnobugmt -lpthread -ldl -lm liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_threads_CFLAGS = $(AM_CFLAGS) $(NOBUGMT_LUMIERA_CFLAGS) +test_threads_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumiera.la -ldl -lm liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt TESTS = $(tests_srcdir)/test.sh From 09c0cacee257cd5997913b5b01265b1bc36c3d4c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 15 Nov 2009 16:27:56 +0100 Subject: [PATCH 075/377] add comparison to c-string for Literal --- src/lib/symbol.hpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/lib/symbol.hpp b/src/lib/symbol.hpp index 562a6bf09..fcc9041ce 100644 --- a/src/lib/symbol.hpp +++ b/src/lib/symbol.hpp @@ -51,6 +51,7 @@ namespace lib { /** inline string literal * @todo improve interaction with Symbol * @todo make it non-nullable + * @todo maybe use boost/operators Ticket #417 */ class Literal { @@ -126,6 +127,32 @@ namespace lib { return ! (sy1 == sy2); } + /// comparison with c-strings //////TICKET #417 + inline bool + operator== (Literal sy1, const char* const sy2) + { + return (sy1 == Literal(sy2)); + } + + inline bool + operator== (const char* const sy1, Literal sy2) + { + return (Literal(sy1) == sy2); + } + + inline bool + operator!= (Literal sy1, const char* const sy2) + { + return ! (sy1 == Literal(sy2)); + } + + inline bool + operator!= (const char* const sy1, Literal sy2) + { + return ! (Literal(sy1) == sy2); + } + + /// string concatenation inline std::string operator+ (std::string str, Literal const& sym) { From 7d6fa03c5140de8aceb50c1b12a0164889dbc9da Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 15 Nov 2009 16:28:42 +0100 Subject: [PATCH 076/377] allow for Goal subclasses to provide copy operations, while prohibiting direct copy --- src/proc/mobject/session/query-resolver.hpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index 62a8980d4..59562dd60 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -50,6 +50,14 @@ namespace session { using std::tr1::function; using std::string; + class no_copy_by_client + { + protected: + ~no_copy_by_client() {} + no_copy_by_client() {} + no_copy_by_client (no_copy_by_client const&) {} + const no_copy_by_client& operator=(no_copy_by_client const&) {} + }; class Goal; class Resolution; @@ -58,15 +66,15 @@ namespace session { /** Allow for taking ownership of a result set */ typedef std::tr1::shared_ptr PReso; - - + + /** * TODO type comment * Query ABC */ class Goal - : noncopyable + : no_copy_by_client { public: virtual ~Goal() ; From 002a0a97e6ad8a32891f24213fbff115a0320a26 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 17 Nov 2009 03:01:18 +0100 Subject: [PATCH 077/377] add remaining bits to get query-for-session-contents impl to compile --- .../placement-index-query-resolver.hpp | 82 ++++++++++--------- src/proc/mobject/session/query-resolver.hpp | 17 +++- src/proc/mobject/session/scope-query.hpp | 61 ++++++++++---- .../session/placement-index-query-test.cpp | 2 +- 4 files changed, 107 insertions(+), 55 deletions(-) diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index c1e21aaac..117c9dc6b 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -44,6 +44,10 @@ #include "proc/mobject/session/query-resolver.hpp" #include "proc/mobject/session/scope-query.hpp" +///////////TODO +#include "proc/mobject/session/clip.hpp" +#include "proc/mobject/session/effect.hpp" + //#include //#include #include @@ -62,6 +66,9 @@ namespace session { using boost::scoped_ptr; // using std::vector; + class Clip; + class Effect; + /** @@ -73,30 +80,22 @@ namespace session { PPIdx index_; typedef PlacementIndex::ID PID; -////////////////////////////////////////////////////////////////TODO: moved in from PlacementIndex typedef Goal::QueryID QueryID; typedef QueryID const& QID; - - template - typename session::Query >::iterator - query (PlacementMO& scope) const; - - operator string() const { return "PlacementIndex"; } - - bool canHandleQuery(QID) const; -////////////////////////////////////////////////////////////////TODO: - typedef PlacementIndex::iterator PIter; + operator string() const { return "PlacementIndex"; } + + /** Interface: strategy for exploring the structure */ class Explorer { public: virtual ~Explorer() { }; - virtual bool exhausted () =0; - virtual PlacementMO& operator() () =0; + virtual bool exhausted () =0; + virtual PlacementMO& step () =0; }; /** @@ -105,6 +104,7 @@ namespace session { * usually this yields an element's children */ class ChildExplorer + : public Explorer { PIter tip_; @@ -115,7 +115,7 @@ namespace session { } PlacementMO& - operator() () + step () { REQUIRE (tip_); PlacementMO& pos = *tip_; @@ -135,6 +135,7 @@ namespace session { * defined by this element and so on recursively. */ class DeepExplorer + : public Explorer { PPIdx index_; std::stack scopes_; @@ -148,7 +149,7 @@ namespace session { } PlacementMO& - operator() () + step () { REQUIRE (!scopes_.empty() && scopes_.top()); PlacementMO& pos = *scopes_.top(); @@ -171,6 +172,7 @@ namespace session { * ascending until reaching the root element. */ class UpExplorer + : public Explorer { PPIdx index_; PlacementMO* tip_; @@ -182,7 +184,7 @@ namespace session { } PlacementMO& - operator() () + step () { REQUIRE (tip_); PlacementMO& pos = *tip_; @@ -199,7 +201,8 @@ namespace session { { } }; - typedef function ContentFilter; + typedef PlacementMO Pla; + typedef function ContentFilter; typedef function ExplorerBuilder; @@ -213,7 +216,6 @@ namespace session { struct ResultSet : Resolution { - typedef PlacementMO Val; ContentFilter acceptable_; ExplorerBuilder buildExploartion_; @@ -222,12 +224,12 @@ namespace session { void exploreNext (Result& res) { - typedef typename Query::Cursor Cursor; + typedef Query::Cursor Cursor; Cursor& cursor = static_cast (res); while (!explore_->exhausted() ) { - Val& elm (*explore_()); + Pla& elm (explore_->step()); if (acceptable_(elm)) { cursor.point_at (elm); @@ -253,7 +255,6 @@ namespace session { nextResult(Result& pos) { exploreNext (pos); - return pos; } public: @@ -279,6 +280,9 @@ namespace session { else if (direction == "path") return new UpExplorer(index_->find(startID),index_); + + else + throw lumiera::error::Invalid("unknown query direction"); //////TICKET #197 } template @@ -296,13 +300,12 @@ namespace session { resolutionFunction (Goal const& goal) { QID qID = goal.getQID(); - REQUIRE (qID.kind == Goal::DISCOVERY - && qID.type == getResultTypeID >()); /////////////////////////////TODO + REQUIRE (qID == whenQueryingFor()); REQUIRE (INSTANCEOF(ScopeQuery, &goal)); ScopeQuery const& query = static_cast const&> (goal); Literal direction = query.searchDirection(); - PID scopeID = query.searchScope().getID(); //////////TICKET #411 + PID scopeID = query.searchScope().getID(); ///////////////////////////////TICKET #411 return new ResultSet( bind (&PlacementIndexQueryResolver::setupExploration, this, scopeID, direction) @@ -312,7 +315,7 @@ namespace session { template ContentFilter - getContentFilter (QUERY query) + getContentFilter (QUERY query) ///< use filter predicate provided by the concrete query { return query.contentFilter(); } @@ -320,10 +323,14 @@ namespace session { ContentFilter getContentFilter (ScopeQuery) ///< especially queries for MObjects need not be filtered { - ContentFilter acceptAllObjects = bind (val(true), _1); + static ContentFilter acceptAllObjects = bind (&acceptAllObjects_, _1); return acceptAllObjects; } + static bool acceptAllObjects_(Pla) { return true; } + + + template static QueryID whenQueryingFor() @@ -332,6 +339,17 @@ namespace session { return qID; } + virtual bool + canHandleQuery(QID qID) const + { + return qID.kind == Goal::DISCOVERY + &&( qID.type == getResultTypeID >() + ||qID.type == getResultTypeID >() + ||qID.type == getResultTypeID >() + ///////////////////////////////////////TICKET #414 + ); + } + public: PlacementIndexQueryResolver (PPIdx theIndex) : index_(theIndex) @@ -339,24 +357,14 @@ namespace session { defineHandling(); defineHandling(); defineHandling(); - ///////////////////////////////////////TICKET #414 + ///////////////////////////////////////TICKET #414 } }; - bool - PlacementIndexQueryResolver::canHandleQuery (QID qID) const - { - UNIMPLEMENTED ("decide by hard-wired check if the given Query can be resolved by PlacementIndex"); - return session::Goal::GENERIC == qID.kind; - // thats not enough! need to check the typeID (match to Placement, with some fixed MOX values) - } - -////////////////////////////////////////////////////////////////TODO: - }} // namespace mobject::session diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index 59562dd60..e19d3e5c7 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -56,7 +56,8 @@ namespace session { ~no_copy_by_client() {} no_copy_by_client() {} no_copy_by_client (no_copy_by_client const&) {} - const no_copy_by_client& operator=(no_copy_by_client const&) {} + no_copy_by_client const& + operator=(no_copy_by_client const&) { return *this; } }; class Goal; @@ -137,6 +138,20 @@ namespace session { }; + inline bool + operator== (Goal::QueryID const& id1, Goal::QueryID const& id2) + { + return id1.kind == id2.kind + && id1.type == id2.type; + } + + inline bool + operator!= (Goal::QueryID const& id1, Goal::QueryID const& id2) + { + return ! (id1 == id2); + } + + /** Context used for generating type-IDs to denote * the specific result types of issued queries */ diff --git a/src/proc/mobject/session/scope-query.hpp b/src/proc/mobject/session/scope-query.hpp index 76db0b088..f575edd95 100644 --- a/src/proc/mobject/session/scope-query.hpp +++ b/src/proc/mobject/session/scope-query.hpp @@ -42,6 +42,42 @@ namespace session { + /** + * Mix-in ABC, combining a Query for placement-attached objects + * with an embedded result set iterator. Thus, an concrete (derived) + * DiscoveryQuery can be created by the invoking client code, and + * then immediately explored until exhaustion of the result iterator. + */ + template + class DiscoveryQuery + : public Query > + , public Query >::iterator + { + + /// Assignment explicitly disallowed (but copy ctor is ok) + DiscoveryQuery const& operator=(DiscoveryQuery const&); + + protected: + typedef Query > _Query; + typedef typename _Query::iterator _QIter; + + protected: + DiscoveryQuery () + : _Query (_Query::defineQueryTypeID (Goal::DISCOVERY)) + , _QIter () + { } + + + typedef PlacementMO const& Pla; + typedef function ContentFilter; + + /** yield an additional filter to be applied + * on the result set. */ + virtual ContentFilter buildContentFilter() const =0; + }; + + + /** * Query a scope to discover it's contents or location. * This is a special kind of query, wired up such as to enumerate @@ -69,31 +105,25 @@ namespace session { */ template class ScopeQuery - : public Query > - , public Query >::iterator + : public DiscoveryQuery { - typedef Query > _Query; + typedef DiscoveryQuery _Par; + typedef typename _Par::_Query _Query; + QueryResolver const& index_; PlacementMO const& startPoint_; - Literal what_to_discover_; - - - typedef typename _Query::iterator _QIter; - typedef typename PlacementMO const& Val; - + Literal what_to_discover_; public: - typedef _QIter iterator; - typedef function ContentFilter; + typedef typename _Par::ContentFilter ContentFilter; + typedef typename _Query::iterator iterator; ScopeQuery (QueryResolver const& resolver, PlacementMO const& scope, Literal direction) - : _Query (_Query::defineQueryTypeID (Goal::DISCOVERY)) - , _QIter () - , index_(resolver) + : index_(resolver) , startPoint_(scope) , what_to_discover_(direction) { @@ -127,7 +157,7 @@ namespace session { } - protected: + private: /** the default implementation of the content filtering * builds on the downcast-function available on each * Placement instance. By parametrising this function @@ -140,7 +170,6 @@ namespace session { return bind (&PlacementMO::isCompatible, _1 ); } - private: void resetResultIteration (iterator const& newQueryResults) { diff --git a/tests/components/proc/mobject/session/placement-index-query-test.cpp b/tests/components/proc/mobject/session/placement-index-query-test.cpp index 03d773eee..a07b85480 100644 --- a/tests/components/proc/mobject/session/placement-index-query-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-query-test.cpp @@ -94,7 +94,7 @@ namespace test { PlacementMO& elm = *ContentsQuery(resolver,root); - discover (PathQuery(resolver,elm)); + discover (PathQuery (resolver,elm)); } From 9514970b6c4b6ddbb17b26b8cf70dafff167c551 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 18 Nov 2009 04:11:27 +0100 Subject: [PATCH 078/377] refactor most of the session-contents-query impl into a dedicated *.cpp --- .../placement-index-query-resolver.cpp | 365 ++++++++++++++++++ .../placement-index-query-resolver.hpp | 344 ++--------------- 2 files changed, 407 insertions(+), 302 deletions(-) create mode 100644 src/proc/mobject/session/placement-index-query-resolver.cpp diff --git a/src/proc/mobject/session/placement-index-query-resolver.cpp b/src/proc/mobject/session/placement-index-query-resolver.cpp new file mode 100644 index 000000000..efc6224f8 --- /dev/null +++ b/src/proc/mobject/session/placement-index-query-resolver.cpp @@ -0,0 +1,365 @@ +/* + placementIndexQueryResolver - using PlacementIndex to resolve scope queries + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +//#include "pre.hpp" +#include "proc/mobject/session/placement-index-query-resolver.hpp" +#include "proc/mobject/session/scope-query.hpp" +#include "proc/mobject/placement.hpp" +#include "proc/mobject/session/clip.hpp" +#include "proc/mobject/session/effect.hpp" + +#include +#include + + +namespace mobject { +namespace session { + + using boost::scoped_ptr; + + + + typedef PlacementIndex::ID PID; + typedef Goal::QueryID QueryID; + typedef QueryID const& QID; + + typedef PlacementIndex::iterator PIter; + + /** @note all of this search implementation works on Placement refs. + * Only finally, when accessing the iterator, a downcast to a more specific + * object type may happen. In this case, there is also a ContentFilter to + * prevent accessing a placement of a non-matching object type, by trying + * a dynamic cast beforehand. The instantiation of a suitably typed + * PlacementIndexQueryResolver::resolutionFunction ensures that these + * types match reliably the type of the issued query. + */ + typedef PlacementMO Pla; + + + + /** Interface: strategy for exploring the structure */ + class Explorer + { + public: + virtual ~Explorer() { }; + virtual bool exhausted () =0; + virtual Pla& step () =0; + }; + + + + /* ==== special strategies to choose from ==== */ + + /** + * Strategy: explore the structure + * just by following the given iterator; + * usually this yields an element's children + */ + class ChildExplorer + : public Explorer + { + PIter tip_; + + bool + exhausted() + { + return !tip_; + } + + Pla& + step () + { + REQUIRE (tip_); + Pla& pos = *tip_; + ++tip_; + return pos; + } + + public: + ChildExplorer(PIter start) + : tip_(start) + { } + }; + + /** + * Strategy: explore the structure depth first. + * After returning an element, delve into the scope + * defined by this element and so on recursively. + */ + class DeepExplorer + : public Explorer + { + PPIdx index_; + std::stack scopes_; + + bool + exhausted() + { + while (!scopes_.empty() && !scopes_.top()) + scopes_.pop(); + return scopes_.empty(); + } + + Pla& + step () + { + REQUIRE (!scopes_.empty() && scopes_.top()); + Pla& pos = *scopes_.top(); + ++scopes_.top(); + scopes_.push(index_->getReferrers(pos.getID())); + return pos; + } + + public: + DeepExplorer(PIter start, PPIdx idx) + : index_(idx) + { + scopes_.push(start); + } + }; + + + /** + * Strategy: explore the structure upwards, + * ascending until reaching the root element. + */ + class UpExplorer + : public Explorer + { + PPIdx index_; + Pla* tip_; + + bool + exhausted() + { + return !tip_; + } + + Pla& + step () + { + REQUIRE (tip_); + Pla& pos = *tip_; + tip_ = &index_->getScope(*tip_); + if (tip_ == &pos) + tip_ = 0; + return pos; + } + + public: + UpExplorer(Pla& start, PPIdx idx) + : index_(idx) + , tip_(&start) + { } + }; + + + typedef function ContentFilter; + typedef function ExplorerBuilder; + + + /** + * on query, an individual result set is prepared + * to be explored by the invoking client code. + * It is built wrapping the low-level scope iterator + * obtained from the index, controlled by an + * exploration strategy. Embedded into the iterator + * there is a smart-ptr managing this ResultSet. + */ + class ResultSet + : public Resolution + { + ContentFilter acceptable_; + ExplorerBuilder buildExploartion_; + scoped_ptr explore_; + + + virtual Result + prepareResolution() + { + explore_.reset (buildExploartion_()); + + Result cursor; + exploreNext (cursor); + return cursor; + } + + virtual void + nextResult(Result& pos) + { + exploreNext (pos); + } + + void + exploreNext (Result& res) + { + typedef Query::Cursor Cursor; + Cursor& cursor = static_cast (res); + + while (!explore_->exhausted() ) + { + Pla& elm (explore_->step()); + if (acceptable_(elm)) + { + cursor.point_at (elm); + return; + } + } + + ASSERT (explore_->exhausted()); + cursor.point_at (0); + } + + public: + ResultSet (ExplorerBuilder b + ,ContentFilter a) + : acceptable_(a) + , buildExploartion_(b) + , explore_() + { } + }; + + + + + namespace { // Helpers for wiring up a suitable resolutionFunction.... + + + bool acceptAllObjects_(Pla) { return true; } + + /** use filter predicate provided by the concrete query */ + template + ContentFilter + getContentFilter (QUERY query) + { + return query.contentFilter(); + } + + /** especially queries for MObjects need not be filtered */ + ContentFilter + getContentFilter (ScopeQuery) + { + static ContentFilter acceptAllObjects = bind (&acceptAllObjects_, _1); + return acceptAllObjects; + } + + /** shortcut for a suitable QueryID */ + template + QueryID + whenQueryingFor() + { + QueryID qID = {Goal::DISCOVERY, getResultTypeID >()}; + return qID; + } + + } //(END) Helpers + + + + + PlacementIndexQueryResolver::PlacementIndexQueryResolver (PPIdx theIndex) + : index_(theIndex) + { + defineHandling(); + defineHandling(); + defineHandling(); + /////////////////////////////////////////////////////////////////TICKET #414 + } + + bool + PlacementIndexQueryResolver::canHandleQuery(QID qID) const + { + return qID.kind == Goal::DISCOVERY + &&( qID.type == getResultTypeID >() + ||qID.type == getResultTypeID >() + ||qID.type == getResultTypeID >() + /////////////////////////////////////////////////////////////////TICKET #414 + ); + } + + + template + void + PlacementIndexQueryResolver::defineHandling() + { + installResolutionCase( whenQueryingFor() + , bind (&PlacementIndexQueryResolver::resolutionFunction, + this, _1 ) + ); + } + + + /** an instance of this function is installed for each specifically typed + * kind of query to be handled. This allows the client code to retrieve + * just placements of this special type (e.g. Placement) in a + * typesafe manner. We ensure a suitable ContentFilter will be installed, + * dropping any other query results (of other type) before the point + * where they may get casted to the desired result type. The key for + * picking the right resolutionFunction is getResultTypeID() + */ + template + Resolution* + PlacementIndexQueryResolver::resolutionFunction (Goal const& goal) + { + QID qID = goal.getQID(); + REQUIRE (qID == whenQueryingFor()); + REQUIRE (INSTANCEOF(ScopeQuery, &goal)); + + ScopeQuery const& query = static_cast const&> (goal); + Literal direction = query.searchDirection(); + PID scopeID = query.searchScope().getID(); ///////////////////////////////TICKET #411 + + return new ResultSet( bind (&PlacementIndexQueryResolver::setupExploration, + this, scopeID, direction) + , getContentFilter(query) + ); + } + + + /** the builder function used to set up the actual result set object + * when issuing the query. It is preconfigured by the resolutionFunction. + * The object returned from this function is taken over and managed by a + * smart-ptr, which is embedded within the iterator given to the client. + */ + Explorer* + PlacementIndexQueryResolver::setupExploration (PID startID, Literal direction) + { + if (direction == "contents") + return new DeepExplorer(index_->getReferrers(startID), index_); + + else if (direction == "children") + return new ChildExplorer(index_->getReferrers(startID)); + + else if (direction == "parents") + return new UpExplorer(index_->getScope(startID),index_); + + else if (direction == "path") + return new UpExplorer(index_->find(startID),index_); + + else + throw lumiera::error::Invalid("unknown query direction"); //////TICKET #197 + } + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index 117c9dc6b..cbb847da8 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -22,7 +22,29 @@ /** @file placement-index-query-resolver.hpp - ** TODO WIP-WIP + ** Implementing resolution of "discover contents"-queries based on PlacementIndex. + ** This wrapper adds a service to resolve queries for exploring the contents or + ** the parent path of a given scope; the actual implementation is based on the + ** basic operations provided by the PlacementIndex; usually this wrapper is + ** instantiated as one of the SessionServices for use by Proc-Layer internals. + ** The PlacementIndex to use for the implementation is handed in to the ctor. + ** + ** As any of the QueryResolver services, the actual resolution is completely + ** decoupled from the querying client code, which retrieves the query results + ** through an iterator. Parametrisation is transmitted to the resolver using a + ** special subclass of Goal, a ScopeQuery. Especially, besides a filter to apply + ** on the results to retrieve, the direction and way* to search can be parametrised: + ** - ascending to the parents of the start scope + ** - enumerating the immediate child elements of the scope + ** - exhaustive depth-first search to get any content of the scope + ** + ** \par how the actual result set is created + ** On initialisation, a table with preconfigured resolution functions is built, + ** in order to re-gain the fully typed context when receiving a query. From within + ** this context, the concrete Query instance can be investigated to define a + ** constructor function for the actual result set, to determine the way how further + ** results will be searched and extracted. The further exploration is driven by the + ** client pulling values from the iterator until exhaustion. ** ** @see PlacementRef ** @see PlacementIndex_test @@ -35,337 +57,55 @@ #define MOBJECT_SESSION_PLACEMENT_INDEX_QUERY_RESOLVER_H //#include "pre.hpp" -//#include "proc/mobject/session/locatingpin.hpp" -//#include "proc/asset/pipe.hpp" -//#include "lib/util.hpp" -//#include "lib/factory.hpp" -//#include "proc/mobject/placement.hpp" #include "proc/mobject/session/placement-index.hpp" #include "proc/mobject/session/query-resolver.hpp" -#include "proc/mobject/session/scope-query.hpp" +#include "lib/symbol.hpp" -///////////TODO -#include "proc/mobject/session/clip.hpp" -#include "proc/mobject/session/effect.hpp" - -//#include -//#include -#include -//#include -#include namespace mobject { - -// class MObject; /////////////////////////////////////???? - namespace session { -// using lib::factory::RefcountFac; -// using std::tr1::shared_ptr; - using boost::scoped_ptr; -// using std::vector; - - class Clip; - class Effect; + using lib::Literal; + class Explorer; /** - * TODO type comment + * Wrapper for the PlacementIndex, allowing to resolve scope contents discovery + * - handles queries for placements of + * * MObjcect + * * Clip + * * Effect + * - is able to process + * * ContentsQuery for retrieving full contents of a scope depth-first + * * PathQuery for retrieving all the parent scopes + * * more generally, any ScopeQuery with these properties, in some variations */ class PlacementIndexQueryResolver : public session::QueryResolver { PPIdx index_; - typedef PlacementIndex::ID PID; - typedef Goal::QueryID QueryID; - typedef QueryID const& QID; - typedef PlacementIndex::iterator PIter; + virtual bool canHandleQuery(Goal::QueryID const&) const; + + virtual operator string() const { return "PlacementIndex"; } - operator string() const { return "PlacementIndex"; } - - - /** Interface: strategy for exploring the structure */ - class Explorer - { - public: - virtual ~Explorer() { }; - virtual bool exhausted () =0; - virtual PlacementMO& step () =0; - }; - - /** - * Strategy: explore the structure - * just by following the given iterator; - * usually this yields an element's children - */ - class ChildExplorer - : public Explorer - { - PIter tip_; - - bool - exhausted() - { - return !tip_; - } - - PlacementMO& - step () - { - REQUIRE (tip_); - PlacementMO& pos = *tip_; - ++tip_; - return pos; - } - - public: - ChildExplorer(PIter start) - : tip_(start) - { } - }; - - /** - * Strategy: explore the structure depth first. - * After returning an element, delve into the scope - * defined by this element and so on recursively. - */ - class DeepExplorer - : public Explorer - { - PPIdx index_; - std::stack scopes_; - - bool - exhausted() - { - while (!scopes_.empty() && !scopes_.top()) - scopes_.pop(); - return scopes_.empty(); - } - - PlacementMO& - step () - { - REQUIRE (!scopes_.empty() && scopes_.top()); - PlacementMO& pos = *scopes_.top(); - ++scopes_.top(); - scopes_.push(index_->getReferrers(pos.getID())); - return pos; - } - - public: - DeepExplorer(PIter start, PPIdx idx) - : index_(idx) - { - scopes_.push(start); - } - }; - - - /** - * Strategy: explore the structure upwards, - * ascending until reaching the root element. - */ - class UpExplorer - : public Explorer - { - PPIdx index_; - PlacementMO* tip_; - - bool - exhausted() - { - return !tip_; - } - - PlacementMO& - step () - { - REQUIRE (tip_); - PlacementMO& pos = *tip_; - tip_ = &index_->getScope(*tip_); - if (tip_ == &pos) - tip_ = 0; - return pos; - } - - public: - UpExplorer(PlacementMO& start, PPIdx idx) - : index_(idx) - , tip_(&start) - { } - }; - - typedef PlacementMO Pla; - typedef function ContentFilter; - typedef function ExplorerBuilder; - - - /** - * on query, an individual result set is prepared - * to be explored by the invoking client code. - * It is built wrapping the low-level scope iterator - * obtained from the index, controlled by an - * exploration strategy. - */ - struct ResultSet - : Resolution - { - - ContentFilter acceptable_; - ExplorerBuilder buildExploartion_; - scoped_ptr explore_; - - void - exploreNext (Result& res) - { - typedef Query::Cursor Cursor; - Cursor& cursor = static_cast (res); - - while (!explore_->exhausted() ) - { - Pla& elm (explore_->step()); - if (acceptable_(elm)) - { - cursor.point_at (elm); - return; - } - } - - ASSERT (explore_->exhausted()); - cursor.point_at (0); - } - - Result - prepareResolution() - { - explore_.reset (buildExploartion_()); - - Result cursor; - exploreNext (cursor); - return cursor; - } - - void - nextResult(Result& pos) - { - exploreNext (pos); - } - - public: - ResultSet (ExplorerBuilder b - ,ContentFilter a) - : acceptable_(a) - , buildExploartion_(b) - , explore_() - { } - }; - - Explorer* - setupExploration (PID startID, Literal direction) - { - if (direction == "contents") - return new DeepExplorer(index_->getReferrers(startID), index_); - - else if (direction == "children") - return new ChildExplorer(index_->getReferrers(startID)); - - else if (direction == "parents") - return new UpExplorer(index_->getScope(startID),index_); - - else if (direction == "path") - return new UpExplorer(index_->find(startID),index_); - - else - throw lumiera::error::Invalid("unknown query direction"); //////TICKET #197 - } + Explorer* setupExploration (PlacementIndex::ID startID, Literal direction); template - void - defineHandling() - { - installResolutionCase( whenQueryingFor() - , bind (&PlacementIndexQueryResolver::resolutionFunction, - this, _1 ) - ); - } + void defineHandling(); template - Resolution* - resolutionFunction (Goal const& goal) - { - QID qID = goal.getQID(); - REQUIRE (qID == whenQueryingFor()); - REQUIRE (INSTANCEOF(ScopeQuery, &goal)); - ScopeQuery const& query = static_cast const&> (goal); - - Literal direction = query.searchDirection(); - PID scopeID = query.searchScope().getID(); ///////////////////////////////TICKET #411 - - return new ResultSet( bind (&PlacementIndexQueryResolver::setupExploration, - this, scopeID, direction) - , getContentFilter(query) - ); - } + Resolution* resolutionFunction (Goal const& goal); - template - ContentFilter - getContentFilter (QUERY query) ///< use filter predicate provided by the concrete query - { - return query.contentFilter(); - } - - ContentFilter - getContentFilter (ScopeQuery) ///< especially queries for MObjects need not be filtered - { - static ContentFilter acceptAllObjects = bind (&acceptAllObjects_, _1); - return acceptAllObjects; - } - - static bool acceptAllObjects_(Pla) { return true; } - - - - template - static QueryID - whenQueryingFor() - { - QueryID qID = {Goal::DISCOVERY, getResultTypeID >()}; - return qID; - } - - virtual bool - canHandleQuery(QID qID) const - { - return qID.kind == Goal::DISCOVERY - &&( qID.type == getResultTypeID >() - ||qID.type == getResultTypeID >() - ||qID.type == getResultTypeID >() - ///////////////////////////////////////TICKET #414 - ); - } public: - PlacementIndexQueryResolver (PPIdx theIndex) - : index_(theIndex) - { - defineHandling(); - defineHandling(); - defineHandling(); - ///////////////////////////////////////TICKET #414 - } + PlacementIndexQueryResolver (PPIdx theIndex); }; - - - - - }} // namespace mobject::session #endif From c01f7743442564e39fc17fa1f3dc650e0c8a91ba Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 18 Nov 2009 04:23:46 +0100 Subject: [PATCH 079/377] expose the new query-for-contents facility as session service --- src/proc/mobject/session/session-impl.hpp | 16 +++++++++++++--- .../session/session-service-explore-scope.hpp | 10 +++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp index c120251cc..246b9f9c4 100644 --- a/src/proc/mobject/session/session-impl.hpp +++ b/src/proc/mobject/session/session-impl.hpp @@ -57,6 +57,7 @@ #include "proc/mobject/session/session-service-mock-index.hpp" #include "proc/mobject/session/session-service-defaults.hpp" +#include "proc/mobject/session/placement-index-query-resolver.hpp" #include #include @@ -133,6 +134,7 @@ namespace session { }; + template struct ServiceAccessPoint : IMPL @@ -140,9 +142,7 @@ namespace session { QueryResolver& getScopeQueryResolver() { - UNIMPLEMENTED ("how actually to manage the PlacementIndexQueryResolver wrapper instance"); - -// return IMPL::magic_; + return resolvingWrapper_; } PlacementMO& @@ -150,9 +150,18 @@ namespace session { { return IMPL::getPlacementIndex()->getRoot(); } + + protected: + ServiceAccessPoint() + : resolvingWrapper_(IMPL::getPlacementIndex()) + { } + + private: + PlacementIndexQueryResolver resolvingWrapper_; }; + template struct ServiceAccessPoint : IMPL @@ -177,6 +186,7 @@ namespace session { }; + template struct ServiceAccessPoint : IMPL diff --git a/src/proc/mobject/session/session-service-explore-scope.hpp b/src/proc/mobject/session/session-service-explore-scope.hpp index f3ef6829b..577705cb9 100644 --- a/src/proc/mobject/session/session-service-explore-scope.hpp +++ b/src/proc/mobject/session/session-service-explore-scope.hpp @@ -32,9 +32,9 @@ ** ** By virtue of this service, QueryFocus, Scope and Placement can ** remain completely agnostic of session's implementation details, - ** and especially aren't bound to PlacementIndex. This is important, + ** especially they aren't bound to PlacementIndex. This is important, ** because the public session API is casted in terms of PlacementRef - ** and QueryFocus An implementation of this service is available + ** and QueryFocus. An implementation of this service is available ** through the SessionServices access mechanism. ** ** @see session-impl.hpp implementation of the service @@ -48,7 +48,6 @@ #include "proc/mobject/placement.hpp" #include "proc/mobject/session/query-resolver.hpp" -//#include "lib/meta/generator.hpp" @@ -56,11 +55,8 @@ namespace mobject { namespace session { -// using lumiera::typelist::InstantiateChained; -// using lumiera::typelist::InheritFrom; -// using lumiera::typelist::NullType; - + struct SessionServiceExploreScope { static QueryResolver const& getResolver(); From 11463da4634e56802a09b866d982c479d175d566 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 18 Nov 2009 04:53:49 +0100 Subject: [PATCH 080/377] better use an enum for the ScopeQuery kinds --- .../placement-index-query-resolver.cpp | 30 ++++++++----------- .../placement-index-query-resolver.hpp | 5 ++-- src/proc/mobject/session/scope-query.hpp | 24 ++++++++------- .../proc/mobject/session/scope-query-test.cpp | 16 +++++----- 4 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/proc/mobject/session/placement-index-query-resolver.cpp b/src/proc/mobject/session/placement-index-query-resolver.cpp index efc6224f8..b85ca6e6f 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.cpp +++ b/src/proc/mobject/session/placement-index-query-resolver.cpp @@ -326,7 +326,7 @@ namespace session { REQUIRE (INSTANCEOF(ScopeQuery, &goal)); ScopeQuery const& query = static_cast const&> (goal); - Literal direction = query.searchDirection(); + ScopeQueryKind direction = query.searchDirection(); PID scopeID = query.searchScope().getID(); ///////////////////////////////TICKET #411 return new ResultSet( bind (&PlacementIndexQueryResolver::setupExploration, @@ -336,28 +336,24 @@ namespace session { } - /** the builder function used to set up the actual result set object + /** the builder function used to set up an concrete result set object * when issuing the query. It is preconfigured by the resolutionFunction. * The object returned from this function is taken over and managed by a * smart-ptr, which is embedded within the iterator given to the client. */ Explorer* - PlacementIndexQueryResolver::setupExploration (PID startID, Literal direction) + PlacementIndexQueryResolver::setupExploration (PID startID, ScopeQueryKind direction) { - if (direction == "contents") - return new DeepExplorer(index_->getReferrers(startID), index_); - - else if (direction == "children") - return new ChildExplorer(index_->getReferrers(startID)); - - else if (direction == "parents") - return new UpExplorer(index_->getScope(startID),index_); - - else if (direction == "path") - return new UpExplorer(index_->find(startID),index_); - - else - throw lumiera::error::Invalid("unknown query direction"); //////TICKET #197 + switch (direction) + { + case CONTENTS: return new DeepExplorer(index_->getReferrers(startID), index_); + case CHILDREN: return new ChildExplorer(index_->getReferrers(startID)); + case PARENTS: return new UpExplorer(index_->getScope(startID),index_); + case PATH: return new UpExplorer(index_->find(startID),index_); + + default: + throw lumiera::error::Invalid("unknown query direction"); //////TICKET #197 + } } diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index cbb847da8..26da4a824 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -59,14 +59,13 @@ //#include "pre.hpp" #include "proc/mobject/session/placement-index.hpp" #include "proc/mobject/session/query-resolver.hpp" -#include "lib/symbol.hpp" +#include "proc/mobject/session/scope-query.hpp" namespace mobject { namespace session { - using lib::Literal; class Explorer; @@ -93,7 +92,7 @@ namespace session { virtual operator string() const { return "PlacementIndex"; } - Explorer* setupExploration (PlacementIndex::ID startID, Literal direction); + Explorer* setupExploration (PlacementIndex::ID startID, ScopeQueryKind direction); template void defineHandling(); diff --git a/src/proc/mobject/session/scope-query.hpp b/src/proc/mobject/session/scope-query.hpp index f575edd95..d0e2f41ab 100644 --- a/src/proc/mobject/session/scope-query.hpp +++ b/src/proc/mobject/session/scope-query.hpp @@ -27,7 +27,6 @@ #include "proc/mobject/placement.hpp" #include "proc/mobject/session/query-resolver.hpp" -#include "lib/symbol.hpp" #include @@ -35,7 +34,6 @@ namespace mobject { namespace session { - using lib::Literal; using std::tr1::bind; using std::tr1::function; using std::tr1::placeholders::_1; @@ -61,7 +59,6 @@ namespace session { typedef Query > _Query; typedef typename _Query::iterator _QIter; - protected: DiscoveryQuery () : _Query (_Query::defineQueryTypeID (Goal::DISCOVERY)) , _QIter () @@ -77,6 +74,13 @@ namespace session { }; + enum ScopeQueryKind + { CONTENTS = 0 ///< discover any contained objects depth-first + , CHILDREN ///< discover the immediate children + , PARENTS ///< discover the enclosing scopes + , PATH ///< discover the path to root + }; + /** * Query a scope to discover it's contents or location. @@ -113,7 +117,7 @@ namespace session { QueryResolver const& index_; PlacementMO const& startPoint_; - Literal what_to_discover_; + ScopeQueryKind to_discover_; public: typedef typename _Par::ContentFilter ContentFilter; @@ -122,10 +126,10 @@ namespace session { ScopeQuery (QueryResolver const& resolver, PlacementMO const& scope, - Literal direction) + ScopeQueryKind direction) : index_(resolver) , startPoint_(scope) - , what_to_discover_(direction) + , to_discover_(direction) { resetResultIteration (_Query::resolveBy(index_)); } @@ -144,10 +148,10 @@ namespace session { return startPoint_; } - Literal + ScopeQueryKind searchDirection () const { - return what_to_discover_; + return to_discover_; } ContentFilter @@ -184,7 +188,7 @@ namespace session { { ContentsQuery (QueryResolver const& resolver, PlacementMO const& scope) - : ScopeQuery (resolver,scope, "content") + : ScopeQuery (resolver,scope, CONTENTS) { } }; @@ -196,7 +200,7 @@ namespace session { { PathQuery (QueryResolver const& resolver, PlacementMO const& scope) - : ScopeQuery (resolver,scope, "parents") + : ScopeQuery (resolver,scope, PARENTS) { } }; diff --git a/tests/components/proc/mobject/session/scope-query-test.cpp b/tests/components/proc/mobject/session/scope-query-test.cpp index 5714eafeb..a242de72a 100644 --- a/tests/components/proc/mobject/session/scope-query-test.cpp +++ b/tests/components/proc/mobject/session/scope-query-test.cpp @@ -67,16 +67,16 @@ namespace test { QueryResolver const& resolver = SessionServiceExploreScope::getResolver(); PlacementMO const& scope = SessionServiceExploreScope::getScopeRoot(); - discover (ScopeQuery (resolver,scope, "contents")); - discover (ScopeQuery (resolver,scope, "contents")); - discover (ScopeQuery (resolver,scope, "contents")); - discover (ScopeQuery (resolver,scope, "contents")); + discover (ScopeQuery (resolver,scope, CONTENTS)); + discover (ScopeQuery (resolver,scope, CONTENTS)); + discover (ScopeQuery (resolver,scope, CONTENTS)); + discover (ScopeQuery (resolver,scope, CONTENTS)); - ScopeQuery specialEl(resolver,scope, "contents"); + ScopeQuery specialEl(resolver,scope, CONTENTS); - discover (ScopeQuery (resolver,*specialEl, "parents")); - discover (ScopeQuery (resolver,*specialEl, "path")); - discover (ScopeQuery (resolver,*specialEl, "path")); + discover (ScopeQuery (resolver,*specialEl, PARENTS)); + discover (ScopeQuery (resolver,*specialEl, PATH)); + discover (ScopeQuery (resolver,*specialEl, PATH)); discover (specialEl); } From cdb84a9b1694e6a5e4ed2aa095fc7ebe0fd8cf33 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 20 Nov 2009 19:58:22 +0100 Subject: [PATCH 081/377] refining the draft for ScopeLocator --- doc/devel/uml/class153605.html | 5 +- doc/devel/uml/class153733.html | 5 +- doc/devel/uml/fig136325.png | Bin 23252 -> 24254 bytes src/proc/mobject/session/query-focus.hpp | 9 ++- src/proc/mobject/session/scope-locator.hpp | 40 +++++------ src/proc/mobject/session/scope-query.hpp | 10 +-- src/proc/mobject/session/scope.cpp | 21 ++++++ .../proc/mobject/session/scope-query-test.cpp | 1 - uml/lumiera/132357 | 22 +++--- uml/lumiera/136325.diagram | 63 ++++++++++++------ uml/lumiera/5.session | 8 +-- uml/lumiera/lumiera.prj | 2 +- wiki/renderengine.html | 17 ++++- 13 files changed, 128 insertions(+), 75 deletions(-) diff --git a/doc/devel/uml/class153605.html b/doc/devel/uml/class153605.html index abd092454..e4b3f0a0f 100644 --- a/doc/devel/uml/class153605.html +++ b/doc/devel/uml/class153605.html @@ -17,8 +17,7 @@

                                    Declaration :

                                    • C++ : class QueryFocus
                                    - -
                                    Relation scopes (<unidirectional association>)

                                    Declaration :

                                    Stereotype: owns

                                    -
                                    + +
                                    Relation <unidirectional association>

                                    Declaration :

                                    diff --git a/doc/devel/uml/class153733.html b/doc/devel/uml/class153733.html index aeffde979..1b5d0de72 100644 --- a/doc/devel/uml/class153733.html +++ b/doc/devel/uml/class153733.html @@ -17,8 +17,7 @@

                                    Declaration :

                                    • C++ : class QueryFocusStack
                                    - -
                                    Relation <directional composition>

                                    Declaration :

                                    Stereotype: vector

                                    -
                                    + +
                                    Relation <directional composition>

                                    Declaration :

                                    diff --git a/doc/devel/uml/fig136325.png b/doc/devel/uml/fig136325.png index 4df084bb6b83584293637c283b1dd680203ab1d1..d3247b41e4aa7ab852bfe7405faf85c492349050 100644 GIT binary patch literal 24254 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

                                    W3E5dk9}ivyEl zOEC=wUl&45AY=#=$eC%?i{~iyD2D{dXajuRnN-!JjlfaX=agr=e_!rp{6Unh1XnRZ$NHjlw^c559?v9EW z9PF{@QU|__xw&(Hh^9w^-;E@_0>OBF& z>hyQUW~rG+Lyf1SMuK-E8AabaOi$Mdy)&qqT#^~3buf(*Jp zX_$b|-QS%YjZ{Ehme*lLNK9d0laRh0|8j+UMzh?D=DiKl&B~rr<<%eY*I%FFjQzVc*~Fcs48xhW_p-;8i+UBdV_MIRR?B{@v>LBtYRu(HK8J z?{Fd_aIX|1G0w`V|9CO|9w`0@S^N7afH~k~d+&O@a+57tcfOlTtuyh3dI+?zbMRnX zz{m5CN)dBldXe9!Qa*^#w3Hvi_Sse$2v;MsZ|3LcN%=i(4a&DS{-iN8XE+!6@@H2m z!cx01f`L{O{ol0q_<$G2+#{!uv386XYLov3U&{~Ce#FASK1YQDS{_}e{h7GF($9R) zm;eHS%@XSUB!EShW)zKHzk=<5_>bK!7OiWU`l}-ymZL!^Uhmpq3Mb%4GI(5egI;2F zseu0|quHvS zzTJ#JBF_X}RMcBePB7$0va+(!FJ9a~JmkiM*YRv@Y;bXL2@WzUmW_L&!*U?%6sBLQ z3wN#KbA>=t$1rsDu8x+`5D`C=8?^uW1Px3DjBK#v8~ghU6BF^NsX9R1{`z%&YbyjD z@#V`uLqp5}<}or_+1Xv4oXj>jnR|HLTpr9PvFI~v#pUOl+uAaVYy*wn*VnhTwRNoD z;r~FWn2JzBB}#cancp-}t8)twI?8pMTn_+0^)F~jg}J`ACZ-aa>MfwJt=&{o5+#*2 zY5}_O?{0zno3oUZlpSZDn4UfGX)7znihY1!_xJai^_sctmYTnO!Q@F}Zb@x$+M)ml zsdfwzHzo-QI3^8jY+kd$7C?4@a8WpFB^E*2`i;J25g>FenNf{Z7{QV)Ii+qWqOkS7!?*S+VwhrHi+m<>a zf+!6goo2Ja@6umsFk1Wo_@$s1G8JN!Ow>S4HGF~d;tu2!|9pD#pB=%?Cv&0 zi`fCBF@`T8PB*|ZS-%QGFVobOCOTNf#NJzNg&$ zGR?!ST^gBSA{feU;Icq^DP2@xKuEa9`L>3NmK4{6F@1TOGk8$X&d5kf{lb0pN3YfN z7>3B!@Dt{%%|P_ZY9dm+Z$Gw&$?VinxFHC?j?jb@dSdM68_twOMZYE{<|QRn^=b>h zYlrgw53l3fsLSC3N%=v)5M=yNbb@!*O7erMUA`}Fvh906wLbUk6?VL-NzmnPE=Y=u zRaG-g`^^yBY(DY?q62Hq&q7bJjp=`bZwgeGN6SqOH#Tj)Eh#C>;6IXrgJGDVQLkGWzx(aQGqFlAchzq|2()wRj(3G~iwYe>|} zDtJsFGF7Q5i|i^GwK}x`;gWzXkfiaev%*kvPs|>ttqu{fkC39>x1?$0hO!^LYWE6b z6f0uT5G5O6{1Ma7qp@JOTX3;hEk&1P*6}z{W*~HJ}Ae1*Hh< z!_pT*1fzQcfncHwV2DddFjUZ(J)TG6s^sqUdC%=M3PI*-T{pLJm>b`J0L&BL~_7!KXx=Rj??uzXHux z;xvh%exvd;`mNaPBBU`el^6k-fC_QI{0Q+Yuhrp#OAFCb(a>PBm7$F_1()bHP5mPT1xUqJ zQV3s|&`Z{96n-Me7tnd-a^v)K7Y<5D4`vx7NC})z#>SL!M&{<4@85^5UxV#gQe4dQ zp;<9Q00g^Ehvte32f#A`-l5t31i)9o{`0!*#)pOdxjEZ%AQJStEKW|wuSjG!A6nt^ zUF&=aT6t9(S`f*!3CYbA5|xXi8+`*yVNgc@#lGi*mltoap%`Ks(9*3aPe&{`+O07D zuV=%Fro6oT+Ux&1B7zP1NMaQ7+kgcP&?Nwcj%kXiNhCUYeuRelsa6g=Aenf-jgM|` zZ*`b)drle~dETWgj#7X?jE|2G9@*H~NJvPK;nw>S7!k6ntE&Uy(ca)if};lbc^xX^ z;xHtijpLe1h7BV;?~v2o`8t-LedO$?J%lhNsfR28@(M{5 zF7$m`$)cfS`-lh;DkOehranq*bxFI!T7j)^AZmfVEyXbATCh0~59Nn(hkOy#PFhIs z%hr@5@i2Lq=j&!7_LADg@&pmd>;vDD1fr;FRwPZISHluJNYmRu9~?4JF%6fD)Lsl1;*XQ!ql_#W7~ zxw!=ep8y3$z+o{0w8X!IDItb4h3ZA|x~ezXopER-L_*SQHpDO|aAX`VyJ~9yp`N1o00eTH~bb6AuA;n`t>W;$$=h#P+%A9w|a-6d)}N?%tgwBCrBA6p-ZrUjeuV$g!RF@E1Q1cVSk)RUp=alXk1)eXT)pmTDm$KNN)gUK1+Cwqo?PgA6kjXY)X{OzndH7XD6XP zM%|m+_hsoZh73@qVjAM9&Z=id{>$5Vwf~ai?Zfr2PfoIl`voO~s;;>ZdIPoVmuO27 zMkPdxJ3MwO%d_aP zz%@+j*BlN)CaA=?x!EGTyGTj?e(Q&j^*{6Eps6nmzaIH}By*6mwp0oNFv;;nP|4x| zjbUyUyt$G3_MKi~e%;FM-$;q_!cbX_5%9wJ)QRXL}M7?r>Prhm6Eq zeCB1C4mV6{j6?LLq~?I5Q0#x^zt0ZEWKv{j!f4!8cTkkjDY#~1u8J-KxcNnpHyUK3 z`bk=d|DYF&E|{*65NAbyo!$0iJ33D2y4jar`|fe6g;rE_wn)S0q=&Qy30L7Q7_-X* zB8vGE?MZHKLVV2%>hKr%NM&Tc>>ms!GR=}-sq3_+x}O-`gCvlg z+>6T0{c>O3!s7eFv@9mzqr>%oMk_3Xv~hOUe1BhqRPa&N%#7>VN_@RN8ZkA+2=wxH zBW{Wy0FD*_-PdU{+a9k-f|O>Sj7i`rg2sQN@bl2MLm$a3%A5XfgM zUns!~B`95Z75F=t(ToTDsV=WzqX-6Ex5CaIOU`H>3JIV2-6b>vImm}GL{#(c&#*=G zm$htc^0}Q_Kib)8p8wrOM(&s@)wMDt2n9J3pN!209YHo8 zvls_8BA__xnH1{l=-@wG;xD%x|5BoTMIHnWEp!o3mn7!PSabr9Ch=TI;BtZW*)C=% zncvG*TwGjDEj}ZIRAd_*QqQ6I>D~!MaS@RhKxY&rCC@1;lHJg+`KbQ>{p?bUSAv!~ z@NdR{I~AJTf#&BKl54JaG8YuFSo!7K5#r~M{+)aL@7+;^LPl%AI#&iu7IBqP7by0a znyO8|-*#lRnd1nGt*SZ$*&v3`lDcpOGX%JcFhX5Z%K0I-ykmxq`>O_5H)_YMT~ zw^mkr0Hw{(%%F=}1zAm(zSq*4nVE6-^1`AAHgj<3spiRn@`F&|3U=MsGBhO5cxu~= z>Qrr%Tg#E(92&q*CS$n10>O>?9n{lflj#5+TDwvaPiCj0X!zTi3R}Uk!2S}pHy?iV zD&Qd-gAkM8E+4$-h`lU3{?L-=t~+l9$N@!p`Ax@$^z`(@!$Tkxtt)l%~lH=2AOw2#P8}NBFzBcHG`Y`Jqb^>$1nfZiwl(W^m#za z+MI72T3>of_JoNc+q;?n-AeLwmn-|}aXYTq#-cBfGKhLeSCyZyYI|r33Jp)s>X2wc z%}jzYTtpFk?oSXABdp->`rDg<;%*isHotL zkS+Ttx%KAM+6muG~TX7A6XX{T|K?{xX~|TW7y1f67{yez8N6q z8XU|~#bJhryAtBRRxWZEeWXEE>4+62`4%n^qGm(N%kh7a661jTt@6c-7u(J}8N?=LE`+A> zw(S?d2)#phj2FF+%#_Kutcl`5Am>RNGOEyGN;JUJrxGuJABsy+1sC)r7P&_T_zhJI zkx&2p1n>c(Y-3Fa$e=@drHnp`Y660CJ<(M=teyLZ$*LRRN6o79fBiR!Dw$Fz#2>yrZ%VcbnB4XuFF`|!U z4xBH2@#&fHk7_I>07Jww6`}z-qW3o;{ix{2hP18(t@z6YngFz#|?7CrTtkH zp`1ePWE*tClFE`$`j4HRVyo{J`6V}WBz6v!)L~EH=+b$H_Q;^6ab+3S`pdq-mpxz5 zfb=Jc%(;OmqoiffJdaB2J)jR~+x(s;eyY;SeIxsViH9epWAgZLwG6a)I2f4gySp=Y zKI9G+6%{5XCN83(@K=ni$m64<+@9xj4uQRMb8~=+1MD2w5ds-)=EEe6j9})24ckHc z8yc+N&3AQ)v#wvxR2YM|{-z&$Zp6e*tC&y&X#3Z5q?4c{gy)ccf~}}Hys)6-xWo5; z=RztMD4(r@LqmsaT@h!02N~(CbzPK;wJ?y$I-qZVpb;!1aQP3T}$u z<2~jY`F(ME0F-fX*gW1V#*ngvg}uKy;wd_XCBjrbIsG}L(y=J>Zo+C)=}>#LhE(IZ zaUg#OAqVtItI?TWL`q-3t-RbG#A?NKK6)l5F$6ZeNJh=lnfdwr+}w+!<>m45uXN4X z+R~UOdAytv@kyDP*urXLhXY!=x>p%b*L~C*2#8zug?i2IfE)>G@lw>#5MX`#P;UiW zTT_$#?VEkW!r`=hbnkn{%)bV=5NV97&}RG9-^Z&Riwg_BPY-S<*g>&LNt(8{hrd4~ zVTgd)0G1Yj*Ywkim!}D#||y0-*?j96Zp|KTX#tI-hSVv$I!$oYd9k zghXWM1C$WhvJAD3jmwE!fJV-~TBCOy#bU%)qD$GyjW>mb!7KcNj155vN?HGTVdxY)+@x@WQBY-H~HC^Tu3kpU`OZd{ut z3MlA6)cChjW(0Cx-ml?^wNkZ$k6cpC=%l(c;0pvU5BkM1!>lnQFyqPG$>|pQt-2eW zromOy1fL?3rXx#zX(qEkWl3LYKx4LE@29}vF|(oSlgr1;rItB|b?5PM(RgiqK;Q!* z5R{BhmpXvdqEQu_+t1)jm4;B7GSdcv-)9O+$^5Kn?dh#3E2)^@lCVGQ^loj z4D@dXB3ULw`%lCkhj4)`B8Us9FjM-{t7sg`12PE?OQ;LyiC56N9H8-Q*C86HnRxWe zj23$kAx9vDBs5>S5s49JriXT<-@^+6{)l?*MB<)T;;|K$Eb`u5noROPJv##!cV>d1k|K@1-RFiv(L@ zlsEqm>azw4f&KJM_sirN;Vw%-u}=XeF>ES^hAISncS)0DMd| zZ{J>kJOESm{{G(D+8PLLef|9yB09`&z{Uq+G{~bGfRWB1?m5ZQ)&^$?FqQrVeoJyp zHe@6uBoMl_8yu-c3Mwld$8w~>C-$aFDBl2e_W9k(Z-B#(f`&%I=)&{r@U>oiQ4ym^ zL2a#ucgwS$%EYvBb`yZvsS5F2_QmC34#TDJ3h&>f2ns@jjzccTRYO4)sslVD3oEPr z-+^QxReRrEmbfE|Yy+z|S9AuK!|$0HydDQ$-lo1j8KRz}SS_U3AanYUT9er$u4u|2 z0zyJ=qUcV3YG1t2BbgbbLKqR$STvFtx9ej=Nl8i65X$rb^xM;Z7NCkeo@G4UU(VZc z{Xb<~cQ}=Q|34gi3#qKK$sTcxW1T3QjF4T3tb>%5NRFLN*&~|}vPCE}$DW5{6Ed^? zKKeet>-Rj*@1Jv>b6?keU+2E>&wG5{uMr6vNq|XDPE3GLn#RYM7b-Ptw14^(_7u$y z_WfWX5~G96AJsp11h)ZFKIrxlVeGeVeH|Ja0__|cEdt1uR^-woFd)nUL>O9g!4JJQ zRy>}yl~&D3?8j_E#w z;+IJ)BW&pChlJ^6N@X~0$&pgsQn137RX8Yc{3|V9rnD7C)ta6-Qb6X?hvq>=wC89@ zd)787#-7U$TU;~1Q>oGww$x^Fhe&~xvlBf3B~)BO|JOV>Daf{tF042CuV+(m9NgsK zy-$33QQ5oVK=8aB!3e4zWbY;&;0yorV~AiGcPEzF!-BGq4k#P_nN`}WDHeIv|DF{p zUy=`{$LvuN!Tcw<-LFEgWK+QY-2C=|8CMG*AM!mtPF`_|055s{Yxl?h3KU!P%9TeAufwVZJG^4E}=^ppeSzscOHg zD1!Lg2fTykmsFl@b;iUbBqtSDRGHdX#oS;Frz*s{oN{T9B+0;r#*cad&{SGVlxbU4 zbuWKIv4P6mV5|lXZ@$>0QCtD^pYiDE>GQ{HinVOqLVnp6AgAUh=25cv#m9>Fp)2Ov z!(c3aUwGl?CM@ak<>fSa8q%?;zC{f(QgZ1bmP+m(PmBx>%QVx{=qZ>)fW|U5weje; z_dJW$aJ3{l|8Ft^Sa4xn9hpNAGOwWt5dbj?OkA^p8v0gEMB z*!nk$Iy)kqOkEv0k8K4x(V!&D;pzUsz&LV`Tk+oL&)-iqdWB>g$D5jP0OINH{>yGW zXnmBF9_~1hMf0rsjNY7kE)ZwDWi|q-@R_hs*@!aB$=O+Os{RjGr%h4c?c7{eBh z1|YPMQcz3tC9gH#qP$#9vxFkU`+Ll93}_23NyPagD2bd)W3G&V4AF=b@Qm%(Ta$Au zJ$*Mr>Ji<@O8f17k_6xYl0!S@cAH}l@yx$Z3=NjcP#=&}KQYVB$(-p59YybCRG`0iEOq*xER`6!opi+;FbndrSvSPf zmER*zWcV-9d(1=J+kEO)eRnf6>1_Lw#wG|V#{)j-OGw-aeY|8=e|3FXWfYB;xO26j z+JXn0kiC6=Uendh<+Jkx2z9OKNCN_$;}dJDs?lQNz<44<)*E#!is`+S}E5YEN^{xwz91$tEeFAq{KAK0jd2v0W(Dvm?(^qHPD6W znE3xrJ>PI$p1}LuEDL-{&K>&SkF-JfxwJC%#rV2 z9b}oQwLV|XyVTb10_|(iMQHQMhI#wkL!o4%TcU)7tN5zs1>dwLfM|P_qrq^ru6I^}IPi;`NkBwsFP9#P+U* zW7Jfs6jQL+0WjW^s}d8J%`av*TNl2Tg0%wB{?mdz+}tufESDpQLFZe#Bg3hd*H991 zkjpL*$#T2t#i7g6M~#Mrgik%{3RvJvU?(W3A=Ow?H7p@z+=UfcVs|p&PlJiEv5ky+ zVn#}o@7!VH7gyIR%eDeS_A9u!Vyk=4;c_y!!|u`6vK+kiJ;53j|6Cgmv$R$k^trg6 zksYskn&X#{P!Ya3D=9GMiWRJbV9E7chA8A6cN#lyJRslfPuSldrGX!Pn;1XRb=u5i zlCE%`)^)*8x`-5Rz3{B&PD)XReQJYLeRY)OQ8}zm3t+y3lCa0^0KN3r`@!hnp1Xrm z^*6sUga%9#EZh&;63O!7&ttCp0I6yr*8U1M`|m^<1uvN@lx;~}rHWD7KThw*v-U_G4Yz>-QThoW`@J-a}xaJ~bvaEl&DGpqJ)Y&zF-G7S=irC@rOq zYE@X$ovc%785qpzSi30RtH#nEa3TANudB zQ_@C6fg(G3SmD$a((wswyTuX>mLBD!U1Oi>?2oPfgfHf zKsEuxjz>5bSl%U zVq?PZ5d1jE2q|}>Yly#M(R}8Zg>G~J(skIMI`irPZq-eT#gC4eKi6pUOmpq(U#=o< z${W%Z&XQjr$?7=?Qq+k#+jin(lb=?eA@Y%ndey+#?=87?!fURHMD~em^;Zc96q%YD z0`HR`SZdog;DmE!wY1cLVL+92r-F3-&!b)IU%wQst#?uRO-Qosc=cm_2Y6$0LD(I({sf~xvK^gJqrR_{{92a|F0iq(0z)-3-I#}_sfIe`Y|R$X2!;E)Dr}0y}BPS>od4|)&N3HXid$+*&j+FIWc`Tg4R~ttzRo{ri_un)zyjG zU+(hyYSfLP{#r1KpkB^|BKuOw(~2WjA5Lug%ThCzxha1A}2Sa=zs?KSIxF z+%u=>5todN^-@nke0(hp*A0owd`W=QudT=C6Eh{%l6n)io$wd<~eeJci_} z+1RXhvb;L_!4)FdDCU@P<%v&I&>Gi$2Zs-br*u8#)d$V5l&%oj>@(Nbj@v%jkPs7_ zMPAgt@$)^SlaTOcB_ZEu%W4n9tPP@~2M!|`+PAk`!BUwVLv?qdfnr#P|9a@8&@(Y{ zUq!@x=epMWy#QowI%ewZHFG4ZXLiu%~fT?-iP;7sV-7`MRwG_DTYEN=EC#OPB zqTH#=2iU`=sXy5EEpN&NZuQL51iXr@aIFHBS&V6k}RlEdv!_HUQ5YbJ}7W8Po+Q3QvtU*!+&@4uMp+Z;_! z&J7CMzH)!_^hh|ELZ1My=Yiwn(b9??<{Dv=nUdvwxI6Qav3w|Sbr1tlXcE+!i%d*xZ1OzyE>5HZ^9Z*vE6chYMK+^F$Qq@)#-c_u#yBt) z=bG$q46yxr7;x#gns5_rM*KNYV1r{p3{Qj#d09q@SX^f%wAgE9f2!eWIrNnju&Y|G zAV6jLgcl9=PkagskfP#Z#iR}67cyX@6pUa`>?S9N`aP%A7Js?3uv+a1BzO{HJJUGI z3(XkA?bYdE_V9q&kjjpeue7K=uqbLPv^!@CclDjlVnwhwuW7#>a(0U5SlJ z`0)P5=&o>gC7L&NkzG}^dftQ~`a@$sdiva+te z+U>=+p+V~qRla%s1jT5f<>>f8zNH~0Mcmjp1tciQc($I+!kkTG^Zq?u<%@`<=QQPdKq!X_l43ZJ#~6#?+XTzk*6j zE7dzTHZt1ZTU~ivhVn&sFM4=r z=&m{}Eya3~zB(;0%FKib2z)8oIH-8Slc%`|V9B>{8rZI$fG<3>p``SsOwtD>dUcgq zR)jPRB1V2{-4UCcT!Kx9YOFCo`s(X;V2qk~?*>-xx(gWQRa5|MYG)w34<1iP5~Tjz zZ@4fqWM!y;zy{MVYAev$j_Y45F~tv+{XR^byHIEwDWuyxMYE?>V~ z#ZM}B1q7ZW+}HG=ZrVmiseys<_KN@~VUXAqvcB<=f*R-_a`U#HTsT3(HOJ^^-=gnL z+aVE7EHGV`kxGW>sC`(l&VK|71fnKnO%8&I&+>0n#p$L2q6f7udc!LGbeD7d(B`?3X814}~Z}qM>ajzP`KD^-(FQd6=fN+4`+g z`#Nce&^5qt7RS2CSXl@5r#h@|`k|-K;@UE&rm8^Ez{d{`4UG)H-sXGyMU)*ey9yJP zk}^?Isn1hMOBYO*oqP|Q?zA=ioAwva&&&-C{OFk)*?D=@YMEHOx=-d~I7$(pABQ+N zZL)Z7gbps?Lt8S0x^VV)_EQ03nH*dBv5>bWhh3PJH4rsYa+_N~Grzc}q_8Wto6gd5 ztMO!0HJMM2V=+Qv=H8a9A!t^Ny#i3rx8OIZsi~OLX7ZR=rM&jafaHv7px9_cCF)$C zCXoozPm;~3E%@3Zq4|OU{tACLx4QZ&weP{W^j1^-@?0AQvz7|qfup_sS+6rA>U&#T zdHJ?;<1zt3UHzBh$Ov+v0}@Vm)-jnJ0@ts5zOkjOJRf3*MYK7LP8c|tZ z0k@}@D?ZV=3b;GJ+;w_c8;$}tHt^$ng+<-oL6%HoeyO9=uv2SQuBEMwKG-Na0oS$Z zuLg$1Cq|VY#l@>c%0A(=xP@hFbBj$AUV}+8QgoBf#Krjxk38qPWocx;mS( zZ?B;hH8e0V;_eBt5CS3kw(;qpy7)9c{(y*fa2oQn!~0N0k3)!xxjkmr7JXn9wr|@MPyecW_zx|H&`(BNiyx?uk^0kkl=t z1vgKBEvDgRC4o0Cr2kgKCx8!MmVWTEJ{^P4Pk8@+>i_E{{$IxWr^WcU!>3SE1>U>e T)lS>sYLNSPH4&wX76JbQD0$0V literal 23252 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 diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp index 0507eb31b..20491af46 100644 --- a/src/proc/mobject/session/query-focus.hpp +++ b/src/proc/mobject/session/query-focus.hpp @@ -60,8 +60,15 @@ namespace session { ScopePath currentPath() const { return scopes_; } template - typename ContentsQuery::iterator + typename ScopeQuery::iterator query() const + { + ScopeLocator::instance().query (*this); + } + + template + typename ScopeQuery::iterator + explore() const { ScopeLocator::instance().explore (*this); } diff --git a/src/proc/mobject/session/scope-locator.hpp b/src/proc/mobject/session/scope-locator.hpp index 67bbd2fad..a978cc3ec 100644 --- a/src/proc/mobject/session/scope-locator.hpp +++ b/src/proc/mobject/session/scope-locator.hpp @@ -54,52 +54,52 @@ namespace session { class ScopeLocator { scoped_ptr focusStack_; - shared_ptr index_; public: static lib::Singleton instance; - void - activate (shared_ptr resolvingFacility); + QueryFocus currFocus(); template - typename ContentsQuery::iterator + typename ScopeQuery::iterator explore (Scope); + template + typename ScopeQuery::iterator + query (Scope); + protected: ScopeLocator(); friend class lib::singleton::StaticCreate; + + private: + QueryResolver const& theResolver(); }; ///////////////////////////TODO currently just fleshing the API - /** activate or de-activate the QueryFocus system. - * This is done by a link to a contents-query resolving facility, - * typically the PlacementIndex within the current session. + + /** use the currently installed contents-resolving facility + * to enumerate the contents (children) of the given scope */ - inline void - ScopeLocator::activate (shared_ptr resolvingFacility) + template + inline typename ScopeQuery::iterator + ScopeLocator::explore (Scope scope) { - index_ = resolvingFacility; - - if (index_) - INFO (config, "Enabling Scope resolution by %s.", cStr(*index_)); - else - INFO (config, "Disabling Scope resolution."); + return ScopeQuery (theResolver(), scope.getTop(), CHILDREN); } /** use the currently installed contents-resolving facility - * to enumerate the contents of the given scope + * to discover depth-first any object within this scope */ template - inline typename ContentsQuery::iterator - ScopeLocator::explore (Scope scope) + inline typename ScopeQuery::iterator + ScopeLocator::query (Scope scope) { - REQUIRE (index_); - return ContentsQuery (*index_, scope.getTop()); + return ScopeQuery (theResolver(), scope.getTop(), CONTENTS); } diff --git a/src/proc/mobject/session/scope-query.hpp b/src/proc/mobject/session/scope-query.hpp index d0e2f41ab..1012dd79f 100644 --- a/src/proc/mobject/session/scope-query.hpp +++ b/src/proc/mobject/session/scope-query.hpp @@ -94,18 +94,18 @@ namespace session { * Currently (11/09), there is a special, hard-wired Query-kind-ID * \c Goal::DISCOVERY to distinguish this special kind of a Query. * - * Contrary to the usual handling of a generic query, a ContentsQuery + * Contrary to the usual handling of a generic query, a ScopeQuery * object holds it's own discovery iterator and thus is completely * self contained. The query is issued automatically on construction, * thus the embedded iterator immediately points at the first result. * Moreover, as any Lumiera Forward Iterator is \c bool checkable, - * a ContentsQuery not yielding any results will evaluate to \c false + * a ScopeQuery not yielding any results will evaluate to \c false * immediately after construction, allowing convenient inline checks. * The query can be re-issued by the function operator, and the * embedded result iterator can of course be copied to a bare - * iterator instance, e.g. for passing it on (ContentsQuery - * itself is intended to be used polymorphically and thus - * defined to be non-copyable) + * iterator instance, e.g. for passing it on (ScopeQuery + * itself is intended to be used polymorphically and + * thus defined to be not assignable) */ template class ScopeQuery diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp index 04a99ea24..dad4294d3 100644 --- a/src/proc/mobject/session/scope.cpp +++ b/src/proc/mobject/session/scope.cpp @@ -24,6 +24,7 @@ #include "proc/mobject/session/scope.hpp" #include "proc/mobject/session/scope-locator.hpp" #include "proc/mobject/session/query-focus-stack.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" #include "proc/mobject/mobject.hpp" //#include "proc/mobject/session/track.hpp" //#include "proc/mobject/placement.hpp" @@ -74,6 +75,26 @@ namespace session { lib::Singleton ScopeLocator::instance; + /** @internal the one (and only) access point + * actually to link the system of Scope and QueryFocus + * to the current session, by delegating resolution + * of contents discovery queries to the PlacementIndex + * managed within the session + */ + QueryResolver const& + ScopeLocator::theResolver() + { + return SessionServiceExploreScope::getResolver(); + } + + + /** TODO */ + QueryFocus + ScopeLocator::currFocus() + { + UNIMPLEMENTED ("how to access and handle the current focus"); + } + /** discover the enclosing scope of a given Placement */ Scope const& diff --git a/tests/components/proc/mobject/session/scope-query-test.cpp b/tests/components/proc/mobject/session/scope-query-test.cpp index a242de72a..3e5e77240 100644 --- a/tests/components/proc/mobject/session/scope-query-test.cpp +++ b/tests/components/proc/mobject/session/scope-query-test.cpp @@ -36,7 +36,6 @@ namespace mobject { namespace session { namespace test { - using session::ContentsQuery; using std::string; using std::cout; using std::endl; diff --git a/uml/lumiera/132357 b/uml/lumiera/132357 index 8faaadd1a..cab7bbb9f 100644 --- a/uml/lumiera/132357 +++ b/uml/lumiera/132357 @@ -1,6 +1,6 @@ format 58 "Placement" // ProcessingLayer::MObject::Placement - revision 3 + revision 4 modified_by 5 "hiv" // class settings //class diagram settings @@ -125,14 +125,13 @@ ${inlines} idl_decl "" explicit_switch_type "" - classrelation 177797 // scopes () - relation 167813 ---> - stereotype "owns" - a role_name "scopes" protected + classrelation 193029 // + relation 182661 ---> + a role_name "" protected cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; " - classrelation_ref 177797 // scopes () - b parent class_ref 153477 // ScopePath + classrelation_ref 193029 // + b parent class_ref 152965 // Handle end end @@ -149,14 +148,13 @@ ${inlines} idl_decl "" explicit_switch_type "" - classrelation 177925 // - relation 167941 *--> - stereotype "vector" + classrelation 192901 // + relation 182533 *--> a role_name "" protected cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; " - classrelation_ref 177925 // - b parent class_ref 153605 // QueryFocus + classrelation_ref 192901 // + b parent class_ref 153477 // ScopePath end end diff --git a/uml/lumiera/136325.diagram b/uml/lumiera/136325.diagram index 2111137af..173cc1e39 100644 --- a/uml/lumiera/136325.diagram +++ b/uml/lumiera/136325.diagram @@ -14,15 +14,15 @@ classcanvas 128261 class_ref 153349 // Scope end classcanvas 128517 class_ref 153477 // ScopePath 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 46 212 2000 + xyz 58 213 2000 end classcanvas 128773 class_ref 153605 // QueryFocus 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 42 140 2000 + xyz 22 20 2005 end classcanvas 129029 class_ref 153733 // QueryFocusStack 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 114 77 2000 + xyz 120 75 2010 end classcanvas 129413 class_ref 152069 // PlacementIndex 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 @@ -33,36 +33,33 @@ implemented through the:" xyzwh 241 308 2000 140 45 classcanvas 129797 class_ref 153861 // ScopeLocator 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 196 17 2000 + xyz 196 17 2005 end classcanvas 130437 class_ref 153989 // QueryResolver 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 452 107 2000 end -note 131333 "this connection is established by the current session" - xyzwh 361 39 2000 158 47 +note 131333 "service provided +by the current session" + xyzwh 360 41 2000 129 46 textcanvas 131461 "the \"scope top\"" xyzwh 357 180 2010 73 13 +classcanvas 132101 class_ref 152965 // Handle + 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 22 76 2004 +end +textcanvas 132997 "current focus" + xyzwh 118 27 2004 61 13 +textcanvas 134277 "manage" + xyzwh 72 72 2009 39 13 relationcanvas 128389 relation_ref 167557 // from ref 128261 z 1999 stereotype "<>" xyz 281 219 3000 to ref 128133 no_role_a no_role_b multiplicity_a_pos 328 237 3000 multiplicity_b_pos 278 237 3000 end relationcanvas 128645 relation_ref 167685 // - from ref 128517 z 1999 stereotype "<>" xyz 130 231 3000 to ref 128261 - role_a_pos 166 214 3000 no_role_b - no_multiplicity_a no_multiplicity_b -end -relationcanvas 128901 relation_ref 167813 // - from ref 128773 z 1999 stereotype "<>" xyz 54 182 3000 to ref 128517 - role_a_pos 88 194 3000 no_role_b - no_multiplicity_a no_multiplicity_b -end -relationcanvas 129157 relation_ref 167941 // - geometry VHr - from ref 129029 z 1999 stereotype "<>" xyz 51 80 3000 to point 76 94 - line 129925 z 1999 to ref 128773 - no_role_a no_role_b + from ref 128517 z 1999 stereotype "<>" xyz 136 232 3000 to ref 128261 + role_a_pos 166 215 3000 no_role_b no_multiplicity_a no_multiplicity_b end relationcanvas 129285 relation_ref 168069 // @@ -77,7 +74,7 @@ relationcanvas 129541 relation_ref 167045 // end relationcanvas 130053 relation_ref 168197 // geometry VHr - from ref 129797 z 1999 to point 162 43 + from ref 129797 z 1999 to point 168 43 line 130181 z 1999 to ref 129029 no_role_a no_role_b no_multiplicity_a no_multiplicity_b @@ -98,5 +95,29 @@ relationcanvas 131205 relation_ref 168581 // no_role_a no_role_b no_multiplicity_a no_multiplicity_b end +relationcanvas 131845 relation_ref 182533 // + geometry VHr + from ref 129029 z 1999 to point 88 92 + line 131973 z 1999 to ref 128517 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +relationcanvas 132229 relation_ref 182661 // + geometry VHr + from ref 128773 z 1999 to point 43 37 + line 132485 z 1999 to ref 132101 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +end +line 132741 -_-_ geometry HV + from ref 128773 z 1999 to point 234 37 + line 132869 z 1999 to ref 129797 +line 133125 -_-_ geometry VHV unfixed + from ref 132101 z 1999 to point 43 83 + line 134021 z 1999 to point 168 83 + line 134149 z 1999 to ref 129029 +line 134405 -_-_ + from ref 132101 z 1999 to point 43 114 + line 134533 z 1999 to ref 128517 preferred_whz 582 515 1 end diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session index fab2f0520..9a72a4c41 100644 --- a/uml/lumiera/5.session +++ b/uml/lumiera/5.session @@ -1,9 +1,7 @@ window_sizes 1302 1004 270 1022 856 71 diagrams - classdiagram_ref 136325 // Focus of Query + active classdiagram_ref 136325 // Focus of Query 582 515 100 4 0 0 - active classdiagram_ref 137733 // Query Interface - 612 547 100 4 0 0 end show_stereotypes selected @@ -17,7 +15,7 @@ open classview_ref 128389 // Controller Workings classview_ref 131973 // Object ref class_ref 152069 // PlacementIndex - classview_ref 131845 // Scopes + class_ref 153733 // QueryFocusStack classview_ref 128261 // Builder Workings usecaseview_ref 128261 // config examples class_ref 133253 // Frame @@ -31,7 +29,7 @@ open class_ref 155141 // Query class_ref 155525 // ResolvingFacility class_ref 158085 // ResultSet - classview_ref 132229 // Custom holders + class_ref 152965 // Handle classview_ref 128266 // SmartPointers end end diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj index d39e4f756..51da44dac 100644 --- a/uml/lumiera/lumiera.prj +++ b/uml/lumiera/lumiera.prj @@ -1,6 +1,6 @@ format 58 "lumiera" - revision 58 + revision 59 modified_by 5 "hiv" cpp_root_dir "../../src/" diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 9cc4528a0..1c9c3c027 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3469,7 +3469,7 @@ For decoupling the query invocation from the facility actually processing the qu See also the notes on &rarr; QueryImplProlog

                                    -
                                    +
                                    When querying contents of the session or sub-containers within the session, the QueryFocus follows the current point-of-query. As such queries can be issued to explore the content of container-like objects holding other MObjects, the focus is always attached to a container, which also acts as [[scope|PlacementScope]] for the contained objects. QueryFocus is an implicit state (the current point of interrest). This sate especially remembers the path down from the root of the HighLevelModel, which was used to access the current scope. Because this path constitutes a hierarchy of scopes, it can be relevant for querying and resolving placement properties. (&rarr; SessionStructureQuery)
                                     
                                     !provided operations
                                    @@ -3484,9 +3484,9 @@ See also the notes on &rarr; QueryImplProlog
                                     There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current scope.// But QueryFocus is more of a //binding// &mdash; it links or focusses the current state into a specific scope with a ScopePath in turn depending on this current state. Thus, while Scope is just a passive container allowing to locate and navigate, QueryFocus by virtue of this binding allows to [[Query]] at this current location.
                                     
                                     !implementation notes
                                    -we provide a static access API, meaning that there is a singleton behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. This link works by the current session contacting the query focus system (~ScopeLocator) and attaching to it. This attachment is shallow, i.e. the QueryFocus doesn't have knowledge about the session, which allows the focus to be unit tested.
                                    +we provide a static access API, meaning that there is a singleton (the ScopeLocator) behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. But this link is kept opaque; it works by the current session exposing an [[query service|QueryResolver]], while QueryFocus doesn't rely on knowledge about the session, allowing the focus to be unit tested.
                                     
                                    -The stack of scopes must not be confused with the ScopePath. Each single frame on the stack is a QueryFocus and as such contains a current ScopePath. The purpose of the stack is to make the scope handling mostly transparent; especially this stack allows to write dedicated query functions directed at a given object: they work by pushing and then navigating to the object to use as new starting point. Not every placement is a scope, but every placement has an immediately enclosing scope, which is used as //current scope.//
                                    +The stack of scopes must not be confused with the ScopePath. Each single frame on the stack is a QueryFocus and as such contains a current ScopePath. The purpose of the stack is to make the scope handling mostly transparent; especially this stack allows to write dedicated query functions directed at a given object: they work by pushing and then navigating to the object to use as starting point for the query, i.e. the //current scope.//
                                     
                                     !!!simplifications
                                     The full implementation of this scope navigation is tricky, especially when it comes to determining the relation of two positions. It should be ''postponed'' and replaced by a ''dummy'' (no-op) implementation for the first integration round.
                                    @@ -3916,6 +3916,17 @@ Later on we expect a distinct __query subsystem__ to emerge, presumably embeddin
                                     
                                    A facility allowing the Proc-Layer to work with abstracted [[media stream types|StreamType]], linking (abstract or opaque) [[type tags|StreamTypeDescriptor]] to an [[library|MediaImplLib]], which provides functionality for acutally dealing with data of this media stream type. Thus, the stream type manager is a kind of registry of all the external libraries which can be bridged and accessed by Lumiera (for working with media data, that is). The most basic set of libraries is instelled here automatically at application start, most notably the [[GAVL]] library for working with uncompressed video and audio data. //Later on, when plugins will introduce further external libraries, these need to be registered here too.//
                                    +
                                    +
                                    A link to relate a compound of [[nested placement scopes|PlacementScope]] to the //current// session and the //current// [[focus for querying|QueryFocus]] and exploring the structure. ScopeLocator is a singleton service, allowing to ''explore'' a [[Placement]] as a scope, i.e. discover any other placements within this scope, and allowing to locate the position of this scope by navigating the ScopePath up to finally reach the root scope of the HighLevelModel.
                                    +
                                    +In the general case, this user visible model of the [[objects|MObject]] within the session allows for more than tree-like associations, as a given [[Sequence|EDL]] might be bound into multiple [[timelines|Timeline]]. Effectively, this makes the ScopePath context dependent. The ScopeLocator is the point where the strictly tree-like hierarchy of placements is connected to this more elaborate scope and path structure.
                                    +&rarr; see BindingScopeProblem
                                    +&rarr; see TimelineSequences
                                    +
                                    +!!a note about concurrency
                                    +While there //is// a "current state" involved, the effect of concurrent access deliberately remains unspecified, because it is expected to be serialised on a higher level. If this assumption were to break, then probably the ScopeLocator will involve some thread local state.
                                    +
                                    +
                                    The Session contains all informations, state and objects to be edited by the User. From a users view, the Session is synonymous to the //current Project//. It can be [[saved and loaded|SessionLifecycle]]. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]].
                                     &rarr; [[Session design overview|SessionOverview]]
                                    
                                    From ce98bd9bcad7346d99abd574046f89c50a00bfd6 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 20 Nov 2009 22:00:15 +0100
                                    Subject: [PATCH 082/377] Finished basic concept how to establish a current
                                     query focus (Ticket #403)
                                    
                                    ---
                                     src/proc/mobject/session/query-focus.cpp      | 27 ++++++++++---
                                     src/proc/mobject/session/query-focus.hpp      | 12 ++++--
                                     src/proc/mobject/session/scope-locator.hpp    | 38 ++++++++++---------
                                     src/proc/mobject/session/scope.cpp            | 15 ++++++--
                                     .../proc/mobject/query-focus-test.cpp         | 10 ++---
                                     wiki/renderengine.html                        | 14 +++----
                                     6 files changed, 74 insertions(+), 42 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/query-focus.cpp b/src/proc/mobject/session/query-focus.cpp
                                    index 5bbbf9a73..9ae9c9d9f 100644
                                    --- a/src/proc/mobject/session/query-focus.cpp
                                    +++ b/src/proc/mobject/session/query-focus.cpp
                                    @@ -37,6 +37,20 @@ namespace session {
                                       { }
                                       
                                       
                                    +  /** */
                                    +  ScopePath&
                                    +  QueryFocus::currPath()
                                    +  {
                                    +    UNIMPLEMENTED ("dereference and access the current scope path");
                                    +  }
                                    +
                                    +  ScopePath const&
                                    +  QueryFocus::currPath()  const
                                    +  {
                                    +    UNIMPLEMENTED ("dereference and access the current scope path");
                                    +  }
                                    +
                                    +  
                                       /** discard any state and clear
                                           the current focus path */
                                       QueryFocus&
                                    @@ -73,15 +87,16 @@ namespace session {
                                       
                                       
                                       /** cease to use \em this specific reference to the current frame.
                                    -      This operation immediately tries to re-access what is "current"
                                    -      and returns a new handle. But when the previously released reference
                                    -      was the last one, releasing it will cause the QueryFocusStack to pop,
                                    -      in which case we'll re-attach to the now uncovered previous stack top.
                                    +      This operation immediately tries to re-attach to what is "current"
                                    +      and readjusts the internal handle. But when the previously released
                                    +      reference was the last one, releasing it will cause the QueryFocusStack
                                    +      to pop, in which case we'll re-attach to the now uncovered previous stack top.
                                       */
                                    -  QueryFocus
                                    +  QueryFocus&
                                       QueryFocus::pop()
                                       {
                                    -    
                                    +    UNIMPLEMENTED ("pop, give up one reference, maybe drop stack top");
                                    +    return *this;
                                       }
                                       
                                       
                                    diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp
                                    index 20491af46..7fd5939c2 100644
                                    --- a/src/proc/mobject/session/query-focus.hpp
                                    +++ b/src/proc/mobject/session/query-focus.hpp
                                    @@ -45,7 +45,7 @@ namespace session {
                                        */
                                       class QueryFocus
                                         {
                                    -      ScopePath scopes_;
                                    +      ScopePath scopes_;  /////////////////////////////////////////////////////////////////TODO use intrusive pointer
                                           /////////////////////////////////////////////////////////////////////////////////////TODO how to integrate the ref-counting handle?
                                           
                                         public:
                                    @@ -54,10 +54,10 @@ namespace session {
                                           QueryFocus& reset ();
                                           QueryFocus& attach (Scope const&);
                                           static QueryFocus push (Scope const&);
                                    -      QueryFocus pop();
                                    +      QueryFocus& pop();
                                           
                                    -      operator Scope()        const { return scopes_.getLeaf(); }      
                                    -      ScopePath currentPath() const { return scopes_; }
                                    +      operator Scope()        const { return currPath().getLeaf(); }      
                                    +      ScopePath currentPath() const { return currPath(); }       ///< @note returns a copy
                                           
                                           template
                                           typename ScopeQuery::iterator
                                    @@ -72,6 +72,10 @@ namespace session {
                                             {
                                               ScopeLocator::instance().explore (*this);
                                             }
                                    +      
                                    +    private:
                                    +      ScopePath      & currPath();
                                    +      ScopePath const& currPath()  const;
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                     
                                    diff --git a/src/proc/mobject/session/scope-locator.hpp b/src/proc/mobject/session/scope-locator.hpp
                                    index a978cc3ec..ed83d674e 100644
                                    --- a/src/proc/mobject/session/scope-locator.hpp
                                    +++ b/src/proc/mobject/session/scope-locator.hpp
                                    @@ -24,33 +24,38 @@
                                     #ifndef MOBJECT_SESSION_SCOPE_LOCATOR_H
                                     #define MOBJECT_SESSION_SCOPE_LOCATOR_H
                                     
                                    -//#include "proc/mobject/mobject.hpp"
                                     #include "proc/mobject/session/scope.hpp"
                                    -#include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/session/scope-query.hpp"
                                    +#include "proc/mobject/placement.hpp"
                                     #include "lib/singleton.hpp"
                                    -#include "lib/util.hpp"
                                     
                                     #include 
                                    -#include 
                                    -//#include 
                                    -//#include 
                                     
                                    -//using std::vector;
                                    -//using std::string;
                                     
                                     namespace mobject {
                                     namespace session {
                                       
                                    -  using std::tr1::shared_ptr;
                                       using boost::scoped_ptr;
                                    -  using util::cStr;
                                    +  
                                    +  class QueryFocusStack;
                                    +  class ScopePath;
                                       
                                       
                                    -  class QueryFocusStack; //////TODO better include?
                                    -  
                                    -
                                       
                                    +  /**
                                    +   * Singleton service establishing a link to relate
                                    +   * any compound of nested placement scopes to the current session
                                    +   * and the \em current focus for querying and exploring this structure.
                                    +   * While it is OK to use this service directly, clients usually would
                                    +   * prefer to use QueryFocus as a frontend.
                                    +   * 
                                    +   * ScopeLocator is the access point both to the current query scope location
                                    +   * (as maintained with the help of the QueryFocusStack) and allows to explore
                                    +   * the current session data structures (building on a QueryResolver service
                                    +   * exposed by the session).
                                    +   * 
                                    +   * @note in its current form (11/09), ScopeLocator is deliberately not threadsafe
                                    +   */
                                       class ScopeLocator
                                         {
                                           scoped_ptr focusStack_;
                                    @@ -58,7 +63,7 @@ namespace session {
                                         public:
                                           static lib::Singleton instance;
                                           
                                    -      QueryFocus currFocus();
                                    +      ScopePath& currPath();
                                           
                                           template
                                           typename ScopeQuery::iterator
                                    @@ -76,12 +81,11 @@ namespace session {
                                         private:
                                           QueryResolver const& theResolver();
                                         };
                                    -///////////////////////////TODO currently just fleshing the API
                                       
                                       
                                       
                                       
                                    -  /** use the currently installed contents-resolving facility
                                    +  /** use the contents-resolving facility exposed by the session
                                        *  to enumerate the contents (children) of the given scope
                                        */
                                       template
                                    @@ -92,7 +96,7 @@ namespace session {
                                       }
                                       
                                       
                                    -  /** use the currently installed contents-resolving facility
                                    +  /** use the contents-resolving facility exposed by the session
                                        *  to discover depth-first any object within this scope
                                        */
                                       template
                                    diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp
                                    index dad4294d3..2e3917ece 100644
                                    --- a/src/proc/mobject/session/scope.cpp
                                    +++ b/src/proc/mobject/session/scope.cpp
                                    @@ -88,9 +88,18 @@ namespace session {
                                       }
                                       
                                       
                                    -  /** TODO */
                                    -  QueryFocus
                                    -  ScopeLocator::currFocus()
                                    +  /** establishes the \em current query focus location.
                                    +   *  Relies on the state of the QueryFocusStack.
                                    +   *  If there is no current focus location, a new
                                    +   *  one is created, referring to the root Scope.
                                    +   *  @return the current path corresponding to the
                                    +   *          most recently used QueryFocus, which is
                                    +   *          actually still referred from somewhere.
                                    +   *  @note may cause the QueryFocusStack to pop 
                                    +   *          path entries no longer in use.
                                    +   */
                                    +  ScopePath&
                                    +  ScopeLocator::currPath()
                                       {
                                         UNIMPLEMENTED ("how to access and handle the current focus");
                                       }
                                    diff --git a/tests/components/proc/mobject/query-focus-test.cpp b/tests/components/proc/mobject/query-focus-test.cpp
                                    index e74b8e218..4d9bb719e 100644
                                    --- a/tests/components/proc/mobject/query-focus-test.cpp
                                    +++ b/tests/components/proc/mobject/query-focus-test.cpp
                                    @@ -119,7 +119,7 @@ namespace test    {
                                           manipulate_subFocus()
                                             {
                                     #ifdef false  ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                    -          QueryFocus original;
                                    +          QueryFocus original; // automatically attaches to current stack top
                                               uint num_refs = original.ref_count();
                                               ASSERT (num_refs > 1);
                                               
                                    @@ -130,7 +130,7 @@ namespace test    {
                                               ASSERT (       1 == subF.ref_count());
                                               ASSERT (num_refs == original.ref_count());
                                               
                                    -          {
                                    +          { // temporarily creating an independent focus attached differently
                                                 QueryFocus subF2 = QueryFocus::push(Scope(subF).getParent());
                                                 ASSERT (subF2 != subF);
                                                 ASSERT (subF == original);
                                    @@ -145,13 +145,13 @@ namespace test    {
                                                   }
                                                 cout << string(subF2) << "<<<--discovery exhausted" << endl;
                                                 
                                    -            subF2.pop();
                                    +            subF2.pop(); // releasing this focus and re-attaching to what's on stack top
                                                 cout << string(subF2) << "<<<--after pop()" << endl;
                                                 ASSERT (subF2 == subF);
                                    -            ASSERT (2 == subF2.ref_count());
                                    +            ASSERT (2 == subF2.ref_count());  // both are now attached to the same path
                                                 ASSERT (2 == subF.ref_count());
                                               }
                                    -          // subF2 went out of scope, but no auto-pop happens
                                    +          // subF2 went out of scope, but no auto-pop happens (because subF is still there)
                                               cout << string(subF) << endl;
                                               
                                               ASSERT (       1 == subF.ref_count());
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 1c9c3c027..7b5946208 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3469,7 +3469,7 @@ For decoupling the query invocation from the facility actually processing the qu
                                     See also the notes on &rarr; QueryImplProlog
                                     
                                    -
                                    +
                                    When querying contents of the session or sub-containers within the session, the QueryFocus follows the current point-of-query. As such queries can be issued to explore the content of container-like objects holding other MObjects, the focus is always attached to a container, which also acts as [[scope|PlacementScope]] for the contained objects. QueryFocus is an implicit state (the current point of interrest). This sate especially remembers the path down from the root of the HighLevelModel, which was used to access the current scope. Because this path constitutes a hierarchy of scopes, it can be relevant for querying and resolving placement properties. (&rarr; SessionStructureQuery)
                                     
                                     !provided operations
                                    @@ -3481,10 +3481,10 @@ See also the notes on &rarr; QueryImplProlog
                                     * (typed) content discovery query on the current scope
                                     [>img[Scope Locating|uml/fig136325.png]]
                                     !!!relation to Scope
                                    -There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current scope.// But QueryFocus is more of a //binding// &mdash; it links or focusses the current state into a specific scope with a ScopePath in turn depending on this current state. Thus, while Scope is just a passive container allowing to locate and navigate, QueryFocus by virtue of this binding allows to [[Query]] at this current location.
                                    +There is a tight integration with PlacementScope through the ScopeLocator, which establishes the //current focus.// But while the [[scope|PlacementScope]] just decorates the placement defining a scope (called //&raquo;scope top&laquo;//), QueryFocus is more of a //binding// &mdash; it links or focusses the current state into a specific scope with a ScopePath in turn depending on this current state. Thus, while Scope is just a passive container allowing to locate and navigate, QueryFocus by virtue of this binding allows to [[Query]] at this current location.
                                     
                                     !implementation notes
                                    -we provide a static access API, meaning that there is a singleton (the ScopeLocator) behind the scenes, which manages the mentioned scope stack. Moreover, there is an link to the current session. But this link is kept opaque; it works by the current session exposing an [[query service|QueryResolver]], while QueryFocus doesn't rely on knowledge about the session, allowing the focus to be unit tested.
                                    +we provide a static access API, meaning that there is a singleton (the ScopeLocator) behind the scenes, which holds the mentioned scope stack. The current focus stack top, i.e. the current ScopePath is managed through an ref-counting handle embedded into each QueryFocus instance. Thus, effectively QueryFocus is an frontend object for accessing this state. Moreover, embedded into ScopeLocator, there is an link to the current session. But this link is kept opaque; it works by the current session exposing an [[query service|QueryResolver]], while QueryFocus doesn't rely on knowledge about the session, allowing the focus to be unit tested.
                                     
                                     The stack of scopes must not be confused with the ScopePath. Each single frame on the stack is a QueryFocus and as such contains a current ScopePath. The purpose of the stack is to make the scope handling mostly transparent; especially this stack allows to write dedicated query functions directed at a given object: they work by pushing and then navigating to the object to use as starting point for the query, i.e. the //current scope.//
                                     
                                    @@ -3916,15 +3916,15 @@ Later on we expect a distinct __query subsystem__ to emerge, presumably embeddin
                                     
                                    A facility allowing the Proc-Layer to work with abstracted [[media stream types|StreamType]], linking (abstract or opaque) [[type tags|StreamTypeDescriptor]] to an [[library|MediaImplLib]], which provides functionality for acutally dealing with data of this media stream type. Thus, the stream type manager is a kind of registry of all the external libraries which can be bridged and accessed by Lumiera (for working with media data, that is). The most basic set of libraries is instelled here automatically at application start, most notably the [[GAVL]] library for working with uncompressed video and audio data. //Later on, when plugins will introduce further external libraries, these need to be registered here too.//
                                    -
                                    -
                                    A link to relate a compound of [[nested placement scopes|PlacementScope]] to the //current// session and the //current// [[focus for querying|QueryFocus]] and exploring the structure. ScopeLocator is a singleton service, allowing to ''explore'' a [[Placement]] as a scope, i.e. discover any other placements within this scope, and allowing to locate the position of this scope by navigating the ScopePath up to finally reach the root scope of the HighLevelModel.
                                    +
                                    +
                                    A link to relate a compound of [[nested placement scopes|PlacementScope]] to the //current// session and the //current//&nbsp; [[focus for querying|QueryFocus]] and exploring the structure. ScopeLocator is a singleton service, allowing to ''explore'' a [[Placement]] as a scope, i.e. discover any other placements within this scope, and allowing to locate the position of this scope by navigating up the ScopePath finally to reach the root scope of the HighLevelModel.
                                     
                                    -In the general case, this user visible model of the [[objects|MObject]] within the session allows for more than tree-like associations, as a given [[Sequence|EDL]] might be bound into multiple [[timelines|Timeline]]. Effectively, this makes the ScopePath context dependent. The ScopeLocator is the point where the strictly tree-like hierarchy of placements is connected to this more elaborate scope and path structure.
                                    +In the general case, this user visible high-level-model of the [[objects|MObject]] within the session allows for more than tree-like associations, as a given [[Sequence|EDL]] might be bound into multiple [[timelines|Timeline]]. Effectively, this makes the ScopePath context dependent. The ScopeLocator is the point where the strictly tree-like hierarchy of placements is connected to this more elaborate scope and path structure. To this end, ScopeLocator maintaines a QueryFocusStack, to keep track of the current location in focus, in cooperation with the QueryFocus objects used by client code.
                                     &rarr; see BindingScopeProblem
                                     &rarr; see TimelineSequences
                                     
                                     !!a note about concurrency
                                    -While there //is// a "current state" involved, the effect of concurrent access deliberately remains unspecified, because it is expected to be serialised on a higher level. If this assumption were to break, then probably the ScopeLocator will involve some thread local state.
                                    +While there //is// a "current state" involved, the effect of concurrent access deliberately remains unspecified, because access is expected to be serialised on a higher level. If this assumption were to break, then probably the ScopeLocator would involve some thread local state.
                                     
                                    From 1a02239e2641342fbd70c638e1014afe6a248661 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 20 Nov 2009 23:06:27 +0100 Subject: [PATCH 083/377] write down all the ScopePath operations identified thus far --- .../proc/mobject/scope-path-test.cpp | 37 +++++++++++++----- wiki/renderengine.html | 39 +++++++++++++++---- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp index 5681e61df..9334f0e11 100644 --- a/tests/components/proc/mobject/scope-path-test.cpp +++ b/tests/components/proc/mobject/scope-path-test.cpp @@ -72,6 +72,7 @@ namespace test { ScopePath testPath = buildPath (startPlacement); checkRelations (testPath,startPlacement); invalildPath (testPath,startPlacement); + emptyPath (testPath); check_Identity_and_Copy (startPlacement); navigate (testPath, index); clear (testPath, index); @@ -97,12 +98,12 @@ namespace test { void - checkRelations (ScopePath path1, PMO& refPla) + checkRelations (ScopePath path1, PMO& refPlacement) { #if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 - ASSERT (path1.contains (refPla)); + ASSERT (path1.contains (refPlacement)); - Scope refScope (refPla); + Scope refScope (refPlacement); ASSERT (path1.contains (refScope)); ASSERT (path1.endsAt (refScope)); @@ -130,7 +131,25 @@ namespace test { void - invalidPath (ScopePath refPath, PMO& refPla) + emptyPath (ScopePath refPath) + { +#if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 + ASSERT (!isnil (refPath)); + refPath.goRoot(); + ASSERT ( isnil (refPath)); + ASSERT (refPath.empty()); + ASSERT (refPath.isValid()); + ASSERT (1 == refPath.length()); + + ScopePath defaultPath; + ASSERT (isnil (defaultPath)); + ASSERT (refPath == defaultPath); +#endif ////////////////////////////////////////////////////////////////////////////////TICKET 384 + } + + + void + invalidPath (ScopePath refPath, PMO& refPlacement) { #if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 ASSERT (refPath); @@ -141,10 +160,10 @@ namespace test { ASSERT (invalildP == ScopePath::INVALID); ASSERT (!isSameObject (invalidP, ScopePath::INVALID)); - ASSERT (refPath.contains (refPla)); - ASSERT (!invalidP.contains (refPla)); + ASSERT (refPath.contains (refPlacement)); + ASSERT (!invalidP.contains (refPlacement)); - Scope refScope (refPla); + Scope refScope (refPlacement); ASSERT (!invalidP.contains (refScope)); ASSERT (!invalidP.endsAt (refScope)); @@ -173,10 +192,10 @@ namespace test { void - check_Identity_and_Copy (PMO& refPla) + check_Identity_and_Copy (PMO& refPlacement) { #if false ////////////////////////////////////////////////////////////////////////////////TICKET 384 - Scope startScope (startPla); + Scope startScope (refPlacement); ScopePath path1 (startScope); ScopePath path2 (startScope); ScopePath path3 (path2); diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 7b5946208..584751a0c 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3118,8 +3118,8 @@ Placement references mimic the behaviour of a real placement, i.e. they proxy th {{red{WIP}}}
                                    -
                                    -
                                    MObjects are attached into the [[Session]] by adding a [[Placement]]. Because this especially includes the case of //grouping or container objects,// e.g. tracks or [[meta-clips|VirtualClip]], any placement may optionally define and root a scope, and every placement is at least contained in one encompassing scope &mdash; of course with the exception of the absolute top level, which can be thought off as being contained in a scope of handling rules.
                                    +
                                    +
                                    MObjects are attached into the [[Session]] by adding a [[Placement]]. Because this especially includes the possibility of //grouping or container objects,// e.g. [[sequences|EDL]] or [[tracks|Track]] or [[meta-clips|VirtualClip]], any placement may optionally define and root a scope, and every placement is at least contained in one encompassing scope &mdash; of course with the exception of the absolute top level, which can be thought off as being contained in a scope of handling rules.
                                     
                                     Thus, while the [[sequences (former called EDL)|EDL]] act as generic container holding a pile of placments, actually there is a more fine grained structure based on the nesting of the tracks, which especially in Lumiera's HighLevelModel belong to the sequence (they aren't a property of the top level timeline as one might expect). Building upon these observations, we actually require each addition of a placement to specify a scope. Consequently, for each Placement at hand it is possible to determine an //containing scope,// which in turn is associated with some Placement of a top-level ~MObject for this scope. The latter is called the ''scope top''. An example would be the {{{Placement<Track>}}} acting as scope of all the clips placed onto this track. The //implementation//&nbsp; of this tie-to-scope is provided by the same mechanism as utilised for relative placements, i.e. an directional placement relation. Actually, this relation is implemented by the PlacementIndex within the current [[Session]].
                                     
                                    @@ -3927,6 +3927,31 @@ In the general case, this user visible high-level-model of the [[objects|MObject
                                     While there //is// a "current state" involved, the effect of concurrent access deliberately remains unspecified, because access is expected to be serialised on a higher level. If this assumption were to break, then probably the ScopeLocator would involve some thread local state.
                                     
                                    +
                                    +
                                    The sequence of nested [[placement scopes|PlacementScope]] leading from the root (global) scope down to a specific [[Placement]] is called ''scope path''. Ascending this path yields all the scopes to search or query in proper order to be used when resolving some attribute of placement. Placements use visibility rules comparable to visibility of scoped definitions in common programming languages or in cascading style sheets, where a local definition can shadow a global one. In a similar way, properties not defined locally may be resolved by querying up the sequence of nested scopes.
                                    +
                                    +A scope path is a sequence of scopes, where each scope is implemented by a PlacementRef pointing to the &raquo;scope top&laquo;, i.e. the placement in the session //constituting this scope.// Each Placement is registered with the session as belonging to a scope, and each placement can contain other placements and thus form a scope. Thus, the ''leaf'' of this path can be considered the current scope. In addition to some search and query functions, a scope path has the ability to ''navigate'' to a given target scope, which must be reachable by ascending and descending into the branches of the overall tree or DAG. Navigating changes the current path. ({{red{WIP 11/09}}} navigation to scopes outside the current path and the immediate children of the current leaf is left out for now. We'll need it later, when actually implementing [[meta-clips|VirtualClip]].)
                                    +
                                    +!Operations
                                    +* the default scope path contains just the root (of the implicit PlacementIndex, i.e. usually the root of the model in the session)
                                    +* a scope path can be created staring from a given scope. This convenience shortcut uses the ScopeLocator to establish the position of the given start scope. This way, effectively the PlacementIndex within the current session is queried for parentship relations until reaching the root of the HighLevelModel.
                                    +* paths are ''copyable value objects'' without identity on their own
                                    +* there is a special //invalid//&nbsp; path token, {{{ScopePath::INVALID}}}
                                    +* length, validity and empty check
                                    +* paths are equality comparable
                                    +* relations
                                    +** if a scope in question is contained in the path
                                    +** if a scope in question is at the leaf position of the path
                                    +** if a path in question is prefix (contained) in the given path
                                    +** if two paths share a common prefix
                                    +** if two paths are disjoint (only connected at root)
                                    +* navigation
                                    +** move up one step
                                    +** move up to the root
                                    +** navigate to a given scope
                                    +** clear a path (reset to default)
                                    +
                                    +
                                    The Session contains all informations, state and objects to be edited by the User. From a users view, the Session is synonymous to the //current Project//. It can be [[saved and loaded|SessionLifecycle]]. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]].
                                     &rarr; [[Session design overview|SessionOverview]]
                                    @@ -5596,13 +5621,13 @@ Actually, what the GUI creates and uses is the //view// of a given timeline. Thi
                                     To complement this possibilities, I'd propose to give the //timeline view// the possibility to be re-linked to a sub-sequence. This way, it would stay connected to the main play control, but at the same time show a sub-sequence //in the way it will be treated as  embedded// within the top-level sequence. This would be the default operation mode when a meta-clip is opened (and showed in a separate tab with such a linked timeline view). The reason for this proposed handling is again to give the user the least surprising behaviour. Because, when &mdash; on the contrary &mdash; the sub-sequence would be opened as //separate timeline,// a different absolute time position and a different signal routing may result; doing such should be reserved for advanced use, e.g. when multiple editors cooperate on a single project and a sequence has to be prepared in isolation prior to being integrated in the global sequence (featuring the whole movie).
                                     
                                    -
                                    -
                                    Tracks are just a structure used to organize the Media Objects within the EDL. Tracks are associated allways to a specific EDL and the Tracks of an EDL form a //tree.// They can be considered to be an organizing grid, and besides that, they have no special meaning. They are grouping devices, not first-class entities. A track doesn't "have" a port or pipe or "is" a video track and the like; it can be configured to behave in such manner by using placements.
                                    +
                                    +
                                    Tracks are just a structure used to organize the Media Objects within the Sequence. Tracks are associated allways to a specific Sequence and the Tracks of an Sequence form a //tree.// They can be considered to be an organizing grid, and besides that, they have no special meaning. They are grouping devices, not first-class entities. A track doesn't "have" a port or pipe or "is" a video track and the like; it can be configured to behave in such manner by using placements.
                                     
                                    -The ~Track-IDs are assets on their own, but they can be found within a given EDL. So, several ~EDLs can share a single track or each EDL can have tracks with their own, separate identity. (the latter is the default)
                                    +The ~Track-IDs are assets on their own, but they can be found within a given sequence. So, several sequences can share a single track or each sequence can hold tracks with their own, separate identity. (the latter is the default)
                                     * Like most ~MObjects, tracks have a asset view: you can find a track asset (a track ID) in the asset manager.
                                    -* and they have an object view: there is an track MObject which can be [[placed|Placement]], thus defining properties of this track within one EDL, e.g. the starting point in time
                                    -Of course, we can place other ~MObjects relative to some track (that's the main reason why we want to have tracks). In this sense, the [[handling of Tracks|TrackHandling]] is somewhat special: the placement of some track can be found directly within the EDL (and not within the general collection of placed objects which form the contents of any EDL). This placement defines properties of the track, which will be inherited if necessary by all ~MObjects placed to this track. For example, if placing (=plugging) a track to some global [[Pipe]], and if placing a clip to this track, without placing the clip directly to another pipe, the associated-to-pipe information of the track will be fetched by the builder when needed to make the output connection of the clip.
                                    +* and they have an object view: there is an track MObject which can be [[placed|Placement]], thus defining properties of this track within one sequence, e.g. the starting point in time
                                    +Of course, we can place other ~MObjects relative to some track (that's the main reason why we want to have tracks). In this sense, the [[handling of Tracks|TrackHandling]] is somewhat special: the placements forming the tree of tracks can be accessed directly through the sequence, and a track acts as container, forming a scope to encompass all the objects "on" this track. Thus, the placement of a track defines properties of the track, which will be inherited (if necessary) by all ~MObjects placed to this track. For example, if placing (=plugging) a track to some global [[Pipe]], and if placing a clip to this track, without placing the clip directly to another pipe, the associated-to-pipe information of the track will be fetched by the builder when needed to make the output connection of the clip.
                                     &rarr; [[Handling of Tracks|TrackHandling]]
                                     &rarr; [[Handling of Pipes|PipeHandling]]
                                     
                                    
                                    From 218e1b8d60fc1b43373add8449236fa88f08ce92 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 21 Nov 2009 01:07:56 +0100
                                    Subject: [PATCH 084/377] add a start-element shortcut to the test-helper
                                    
                                    This allows to get a start Placement, which is known
                                    to be way down in the test-hierarchy of Placements
                                    created by build_testScopes()
                                    ---
                                     .../proc/mobject/scope-path-test.cpp          |  4 +--
                                     .../proc/mobject/session/scope-query-test.cpp |  2 +-
                                     .../proc/mobject/session/test-scopes.cpp      | 26 ++++++++++++-------
                                     .../proc/mobject/session/test-scopes.hpp      | 20 +++++---------
                                     4 files changed, 25 insertions(+), 27 deletions(-)
                                    
                                    diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp
                                    index 9334f0e11..4663ae388 100644
                                    --- a/tests/components/proc/mobject/scope-path-test.cpp
                                    +++ b/tests/components/proc/mobject/scope-path-test.cpp
                                    @@ -65,8 +65,7 @@ namespace test    {
                                             {
                                               // Prepare an (test)Index backing the PlacementRefs
                                               PPIdx index = build_testScopes();
                                    -#if false     ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                    -          PMO& startPlacement = *(index->query(index->getRoot()));
                                    +          PMO& startPlacement = retrieve_startElm();
                                               ASSERT (startPlacement);
                                               
                                               ScopePath testPath = buildPath (startPlacement);
                                    @@ -76,7 +75,6 @@ namespace test    {
                                               check_Identity_and_Copy (startPlacement);
                                               navigate (testPath, index);
                                               clear (testPath, index);
                                    -#endif
                                             }
                                           
                                           
                                    diff --git a/tests/components/proc/mobject/session/scope-query-test.cpp b/tests/components/proc/mobject/session/scope-query-test.cpp
                                    index 3e5e77240..e139b6452 100644
                                    --- a/tests/components/proc/mobject/session/scope-query-test.cpp
                                    +++ b/tests/components/proc/mobject/session/scope-query-test.cpp
                                    @@ -61,7 +61,7 @@ namespace test    {
                                           run (Arg) 
                                             {
                                               // Prepare an (test)Index (dummy "session")
                                    -          build_testScopes();
                                    +          PPIdx testSession (build_testScopes());
                                               
                                               QueryResolver const& resolver = SessionServiceExploreScope::getResolver();
                                               PlacementMO   const& scope    = SessionServiceExploreScope::getScopeRoot();
                                    diff --git a/tests/components/proc/mobject/session/test-scopes.cpp b/tests/components/proc/mobject/session/test-scopes.cpp
                                    index 20cf0639e..f7e4c3f6c 100644
                                    --- a/tests/components/proc/mobject/session/test-scopes.cpp
                                    +++ b/tests/components/proc/mobject/session/test-scopes.cpp
                                    @@ -23,16 +23,8 @@
                                     
                                     #include "proc/mobject/session/test-scopes.hpp"
                                     #include "proc/mobject/session/session-service-mock-index.hpp"
                                    -//#include "lib/util.hpp"
                                    -
                                    -//#include 
                                    -//#include 
                                    -
                                    -//using util::isSameObject;
                                    -//using lumiera::Time;
                                    -//using std::string;
                                    -//using std::cout;
                                    -//using std::endl;
                                    +#include "proc/mobject/session/session-service-explore-scope.hpp"
                                    +#include "proc/mobject/session/scope-query.hpp"
                                     
                                     
                                     namespace mobject {
                                    @@ -90,4 +82,18 @@ namespace test    {
                                       }
                                       
                                       
                                    +  /** @note this test helper only works if build_testScopes is invoked
                                    +   *  beforehand, and the returned smart-ptr to the created test/dummy index
                                    +   *  is retained. Moreover, this function makes assumptions about the actual
                                    +   *  objects created by the former test function.
                                    +   *  @throw lumiera::error::Invalid if the intended start element doesn't exist (anymore)
                                    +   */
                                    +  PlacementMO&
                                    +  retrieve_startElm()
                                    +  {
                                    +    return *ContentsQuery(SessionServiceExploreScope::getResolver()
                                    +                                     ,SessionServiceExploreScope::getScopeRoot());
                                    +  }
                                    +  
                                    +  
                                     }}} // namespace mobject::session::test
                                    diff --git a/tests/components/proc/mobject/session/test-scopes.hpp b/tests/components/proc/mobject/session/test-scopes.hpp
                                    index 24147c399..a95da5bde 100644
                                    --- a/tests/components/proc/mobject/session/test-scopes.hpp
                                    +++ b/tests/components/proc/mobject/session/test-scopes.hpp
                                    @@ -25,22 +25,10 @@
                                     #define MOBJECT_SESSION_TEST_TEST_SCOPES_H
                                     
                                     
                                    -//#include "lib/lumitime.hpp"
                                    -//#include "proc/mobject/placement-ref.hpp"
                                    -#include "proc/mobject/session/test-scopes.hpp"
                                     #include "proc/mobject/test-dummy-mobject.hpp"
                                     #include "proc/mobject/session/placement-index.hpp"
                                    -//#include "lib/util.hpp"
                                     
                                     #include 
                                    -//#include 
                                    -//#include 
                                    -
                                    -//using util::isSameObject;
                                    -//using lumiera::Time;
                                    -//using std::string;
                                    -//using std::cout;
                                    -//using std::endl;
                                     
                                     
                                     namespace mobject {
                                    @@ -48,7 +36,7 @@ namespace session {
                                     namespace test    {
                                       
                                       using std::tr1::shared_ptr;
                                    -
                                    +  
                                       using namespace mobject::test;
                                       typedef TestPlacement PDum;
                                       
                                    @@ -67,5 +55,11 @@ namespace test    {
                                       PPIdx build_testScopes();
                                       
                                       
                                    +  /** complement to the helper: retrieve one of the dummy placements
                                    +   *  which is a Placement<> and way down into the hierarchy
                                    +   */
                                    +  PlacementMO& retrieve_startElm();
                                    +  
                                    +  
                                     }}} // namespace mobject::session::test
                                     #endif
                                    
                                    From b2849c6099cb370829d4f40ab806a5370cbd20ac Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 21 Nov 2009 02:49:24 +0100
                                    Subject: [PATCH 085/377] defined and implemented equality of scopes
                                    
                                    ---
                                     src/proc/mobject/session/scope.hpp            | 32 +++++++++++++++++++
                                     .../proc/mobject/placement-scope-test.cpp     | 30 +++++++++++++++++
                                     2 files changed, 62 insertions(+)
                                    
                                    diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp
                                    index e12eae402..c77d43ac8 100644
                                    --- a/src/proc/mobject/session/scope.hpp
                                    +++ b/src/proc/mobject/session/scope.hpp
                                    @@ -31,6 +31,7 @@
                                     #include "lib/iter-adapter.hpp"
                                     //#include "lib/singleton.hpp"
                                     
                                    +#include 
                                     //#include 
                                     //#include 
                                     //#include 
                                    @@ -54,6 +55,9 @@ namespace session {
                                        *       maintains the current focus location.
                                        */
                                       class Scope
                                    +    : public boost::equality_comparable >
                                    +             
                                         {
                                           RefPlacement anchor_;
                                           
                                    @@ -75,11 +79,39 @@ namespace session {
                                           
                                           typedef IterType_ iterator;
                                           iterator ascend()  const;
                                    +      
                                    +      friend bool operator== (Scope const&, Scope const&);
                                    +      friend bool operator== (Scope const&, PlacementMO const&);
                                         };
                                       
                                       
                                     ///////////////////////////TODO currently just fleshing the API
                                       
                                    +    
                                    +  /** as scopes are constituted by a "scope top" element (placement)
                                    +   *  registered within the PlacementIndex of the current session,
                                    +   *  equality is defined in terms of this defining placement.
                                    +   *  Moreover, in this context, \em identity relates to 
                                    +   *  being the same thing, when used in the context
                                    +   *  of the session. Thus, it can be reduced
                                    +   *  to comparing the Placement-IDs 
                                    +   */
                                    +  inline bool
                                    +  operator== (Scope const& scope1, Scope const& scope2)
                                    +  {
                                    +    return scope1.anchor_ == scope2.anchor_;  
                                    +  }
                                    +  
                                    +  inline bool
                                    +  operator== (Scope const& scope, PlacementMO const& aScopeTop)
                                    +  {
                                    +    typedef PlacementMO::ID const& PlacementID;
                                    +    PlacementID id1 = static_cast (scope.anchor_);
                                    +    
                                    +    return id1 == aScopeTop.getID();
                                    +  }
                                    +  
                                    +  
                                       
                                       
                                     }} // namespace mobject::session
                                    diff --git a/tests/components/proc/mobject/placement-scope-test.cpp b/tests/components/proc/mobject/placement-scope-test.cpp
                                    index 72f0c5aff..936eb84ca 100644
                                    --- a/tests/components/proc/mobject/placement-scope-test.cpp
                                    +++ b/tests/components/proc/mobject/placement-scope-test.cpp
                                    @@ -72,6 +72,7 @@ namespace test    {
                                               // Prepare an (test)Index backing the PlacementRefs
                                               PPIdx index = build_testScopes();
                                               
                                    +          verifyEquality();
                                               UNIMPLEMENTED ("function test of placement scope interface");
                                     #if false  //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384  !!!!!!!!!
                                               verifyLookup (index);
                                    @@ -116,6 +117,35 @@ namespace test    {
                                             }
                                           
                                           
                                    +      /** @test equality of scopes is based on the ID of the scope top (Placement) */
                                    +      void
                                    +      verifyEquality ()
                                    +        {
                                    +          PlacementMO& aPlac = retrieve_startElm();
                                    +          Scope scope1(aPlac);
                                    +          Scope scope2(aPlac);
                                    +          Scope nil;
                                    +          
                                    +          ASSERT (scope1 == scope2); ASSERT (scope2 == scope1);
                                    +          ASSERT (scope1 != nil);    ASSERT (nil != scope1);
                                    +          ASSERT (scope2 != nil);    ASSERT (nil != scope2);
                                    +          
                                    +          ASSERT (aPlac == scope1);  ASSERT (scope1 == aPlac);  
                                    +          ASSERT (aPlac == scope2);  ASSERT (scope2 == aPlac);  
                                    +          ASSERT (aPlac != nil);     ASSERT (nil != aPlac);
                                    +          
                                    +          Scope par (scope1.getParent());
                                    +          ASSERT (scope1 != par);    ASSERT (par != scope1);
                                    +          ASSERT (scope2 != par);    ASSERT (par != scope2);
                                    +          
                                    +          PlacementMO& plac2 (scope2.getTop());
                                    +          ASSERT (aPlac.getID() == plac2.getID());
                                    +          
                                    +          PlacementMO& parPlac (par.getTop());
                                    +          ASSERT (aPlac.getID() != parPlac.getID());
                                    +        }
                                    +      
                                    +      
                                           /** @test navigate to root, starting from each Placement */
                                           void
                                           verifyNavigation (PPIdx ref_index)
                                    
                                    From b7987cf3ce1d5e9486911e0f9fa4f6a9daae3e84 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 21 Nov 2009 04:48:29 +0100
                                    Subject: [PATCH 086/377] define iteration on ScopePath as reverse iteration on
                                     the contained Scopes
                                    
                                    ---
                                     src/lib/iter-adapter.hpp                      |  6 ++---
                                     src/proc/mobject/session/scope-path.hpp       | 22 +++++++++++++++++++
                                     .../proc/mobject/scope-path-test.cpp          | 14 ++++++++++++
                                     3 files changed, 39 insertions(+), 3 deletions(-)
                                    
                                    diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp
                                    index cdec86476..8e085811a 100644
                                    --- a/src/lib/iter-adapter.hpp
                                    +++ b/src/lib/iter-adapter.hpp
                                    @@ -309,8 +309,8 @@ namespace lib {
                                             { }
                                           
                                           RangeIter ()
                                    -        : p_(0)
                                    -        , e_(0)
                                    +        : p_()
                                    +        , e_()
                                             { }
                                           
                                           
                                    @@ -358,7 +358,7 @@ namespace lib {
                                           bool
                                           isValid ()  const
                                             {
                                    -          return (p_!= IT(0)) && (p_ != e_);
                                    +          return (p_!= IT()) && (p_ != e_);
                                             }
                                           
                                           bool
                                    diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp
                                    index 054cdfe46..b99a4d85a 100644
                                    --- a/src/proc/mobject/session/scope-path.hpp
                                    +++ b/src/proc/mobject/session/scope-path.hpp
                                    @@ -27,6 +27,7 @@
                                     //#include "proc/mobject/mobject.hpp"
                                     //#include "proc/mobject/placement-ref.hpp"
                                     #include "proc/mobject/session/scope.hpp"
                                    +#include "lib/iter-adapter.hpp"
                                     
                                     #include 
                                     //#include 
                                    @@ -46,9 +47,17 @@ namespace session {
                                         {
                                           vector path_;
                                           
                                    +      typedef vector                  _VType;
                                    +      typedef _VType::const_reverse_iterator _VIter;
                                    +      typedef lib::RangeIter<_VIter>      _IterType;
                                    +      
                                         public:
                                           ScopePath();
                                           
                                    +      /// Iteration is always ascending from leaf to root
                                    +      typedef _IterType iterator;
                                    +      iterator begin()  const;
                                    +      iterator end()    const;
                                           
                                           Scope getLeaf()  const;
                                           
                                    @@ -58,5 +67,18 @@ namespace session {
                                     ///////////////////////////TODO currently just fleshing the API
                                       
                                       
                                    +  inline ScopePath::iterator
                                    +  ScopePath::begin()  const
                                    +  {
                                    +    return iterator (path_.rbegin(), path_.rend());
                                    +  }
                                    +  
                                    +  inline ScopePath::iterator
                                    +  ScopePath::end()    const
                                    +  {
                                    +    return iterator();
                                    +  }
                                    +  
                                    +  
                                     }} // namespace mobject::session
                                     #endif
                                    diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp
                                    index 4663ae388..c1946c087 100644
                                    --- a/tests/components/proc/mobject/scope-path-test.cpp
                                    +++ b/tests/components/proc/mobject/scope-path-test.cpp
                                    @@ -95,6 +95,20 @@ namespace test    {
                                             }
                                           
                                           
                                    +      void
                                    +      checkIteration (ScopePath path, PMO& refPlacement)
                                    +        {
                                    +          Scope refScope(refPlacement);
                                    +          ScopePath::iterator ii = path.begin();
                                    +          ASSERT (ii);
                                    +          while (++ii)
                                    +            {
                                    +              ASSERT (*ii == refScope.getParent());
                                    +              refScope = *ii;
                                    +            }
                                    +        }
                                    +      
                                    +      
                                           void
                                           checkRelations (ScopePath path1, PMO& refPlacement)
                                             {
                                    
                                    From ed86c978817c5106cf93caa4ca75a3a29869bef1 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 21 Nov 2009 20:55:14 +0100
                                    Subject: [PATCH 087/377] Defined/Stubbed all required ScopePath operations
                                    
                                    ---
                                     src/proc/mobject/session/scope-path.cpp       | 147 +++++++++++++++++-
                                     src/proc/mobject/session/scope-path.hpp       |  58 ++++++-
                                     src/proc/mobject/session/scope.cpp            |  11 +-
                                     src/proc/mobject/session/scope.hpp            |   1 +
                                     .../proc/mobject/scope-path-test.cpp          |  91 ++++++-----
                                     .../proc/mobject/session/test-scopes.cpp      |   8 +
                                     .../proc/mobject/session/test-scopes.hpp      |  10 ++
                                     7 files changed, 272 insertions(+), 54 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp
                                    index 5ecb64919..e511d356f 100644
                                    --- a/src/proc/mobject/session/scope-path.cpp
                                    +++ b/src/proc/mobject/session/scope-path.cpp
                                    @@ -22,43 +22,174 @@
                                     
                                     
                                     #include "proc/mobject/session/scope-path.hpp"
                                    +#include "lib/error.hpp"
                                    +#include "lib/util.hpp"
                                     //#include "proc/mobject/session/track.hpp"
                                    +
                                     //#include "proc/mobject/placement.hpp"
                                     //#include "proc/mobject/session/mobjectfactory.hpp"
                                     //#include "proc/asset/track.hpp"
                                    +#include 
                                     
                                     namespace mobject {
                                     namespace session {
                                       
                                    +  using std::tr1::bind;
                                    +  using std::tr1::function;
                                    +  using std::tr1::placeholders::_1;
                                    +  using util::and_all;
                                    +  
                                    +  using namespace lumiera;
                                       
                                       
                                    -  /** TODO??? */
                                    +  /** by default, a scope path just contains 
                                    +   *  the root scope of the current session (PlacementIndex).
                                    +   *  @note invoking this function accesses the session and thus
                                    +   *        may cause an empty default session to be created.
                                    +   */
                                       ScopePath::ScopePath ()
                                    -//  : track (makeDefaultTrack ())
                                    -//  , clips (0)
                                       {
                                    -    
                                    +    UNIMPLEMENTED ("default path just containing root");
                                       }
                                       
                                       
                                    -  Scope
                                    +  /** When creating a path to a given (leaf) scope,
                                    +   *  the complete sequence of nested scopes leading to 
                                    +   *  this special scope is discovered, using the query service
                                    +   *  exposed by the session (through ScopeLocator).
                                    +   *  @note when locating the default (invalid) scope,
                                    +   *         a special empty ScopePath is created
                                    +   *  @throw error::Invalid if the given target scope
                                    +   *         can't be connected to the (implicit) root
                                    +   */
                                    +  ScopePath::ScopePath (Scope const& leaf)
                                    +  {
                                    +    UNIMPLEMENTED ("initialise by discovering complete scope sequence");
                                    +  }
                                    +  
                                    +  
                                    +  /** constant \em invalid path token. Created by locating an invalid scope */
                                    +  const ScopePath ScopePath::INVALID = ScopePath(Scope());
                                    +  
                                    +  
                                    +  /* == Diagnostics == */
                                    +  
                                    +  /** a \em valid path consists of more than just the root element.
                                    +   *  @note contrary to this, an \em empty path doesn't even contain a root element
                                    +   */
                                    +  bool
                                    +  ScopePath::isValid()  const
                                    +  {
                                    +    UNIMPLEMENTED ("validity self check: more than just root");
                                    +  }
                                    +  
                                    +  /** an empty path doesn't even contain a root element.
                                    +   *  Many operations throw when invoked on such a path.
                                    +   *  Navigating up from an root path creates an empty path.
                                    +   */
                                    +  bool
                                    +  ScopePath::empty()  const
                                    +  {
                                    +    UNIMPLEMENTED ("empty == no elements, even no root!");
                                    +  }
                                    +  
                                    +  
                                    +  
                                    +  /* == Relations == */
                                    +  
                                    +  Scope&
                                       ScopePath::getLeaf()  const
                                       {
                                         UNIMPLEMENTED ("access end node of current path");
                                       }
                                       
                                    +  
                                    +  /** verify the scope in question is equivalent
                                    +   *  to our leaf scope. Equivalence of scopes means
                                    +   *  they are defined by the same scope top placement,
                                    +   *  i.e. registered with the same Placement-ID. 
                                    +   */
                                    +  bool
                                    +  ScopePath::endsAt(Scope const& aScope)  const
                                    +  {
                                    +    UNIMPLEMENTED ("verify the scope in question is identical (same ID) to our leaf scope");
                                    +  }
                                    +  
                                    +  
                                    +  bool
                                    +  ScopePath::contains (Scope const& aScope)  const
                                    +  {
                                    +    UNIMPLEMENTED ("containment check");
                                    +  }
                                    +  
                                    +  
                                    +  bool
                                    +  ScopePath::contains (ScopePath const& otherPath)  const
                                    +  {
                                    +    if ( empty())             return false;
                                    +    if (!otherPath.isValid()) return true;
                                    +    if (!isValid())           return false;
                                    +    
                                    +    ASSERT (1 < length());
                                    +    ASSERT (1 < otherPath.length());
                                    +    
                                    +    for (iterator ii = otherPath.begin(); ii; ++ii)
                                    +      if (!this->contains (*ii))
                                    +        return false;
                                    +    
                                    +    return true;
                                    +  }
                                    +  
                                    +  
                                    +  ScopePath
                                    +  commonPrefix (ScopePath const& path1, ScopePath const& path2)
                                    +  {
                                    +    UNIMPLEMENTED ("determine the common prefix, if any");
                                    +  }
                                    +  
                                    +  bool
                                    +  disjoint (ScopePath const& path1, ScopePath const& path2)
                                    +  {
                                    +    if (path1.empty() || path2.empty()) return false;
                                    +
                                    +    return (path1.isValid() && path2.isValid())
                                    +        && (path1.path_[1]  != path2.path_[1]) // no common prefix
                                    +         ; 
                                    +  }
                                    +
                                    +
                                    +  
                                     
                                       /* == Mutations == */
                                       
                                       void
                                       ScopePath::clear()
                                       {
                                    -    UNIMPLEMENTED ("reset the current path to empty state");
                                    +    UNIMPLEMENTED ("reset the current path to default state (just root)");
                                    +  }
                                    +  
                                    +  
                                    +  Scope&
                                    +  ScopePath::moveUp()
                                    +  {
                                    +    UNIMPLEMENTED ("navigate one level up, then return leaf");
                                    +  }
                                    +  
                                    +  
                                    +  Scope&
                                    +  ScopePath::goRoot()
                                    +  {
                                    +    UNIMPLEMENTED ("navigate up to the root scope");
                                    +  }
                                    +  
                                    +  
                                    +  void
                                    +  ScopePath::navigate (Scope const& target)
                                    +  {
                                    +    *this = ScopePath(target);             //////////////////////////////TICKET #424
                                       }
                                       
                                       
                                       
                                       
                                    -  
                                    -  
                                     }} // namespace mobject::session
                                    diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp
                                    index b99a4d85a..c8b912e14 100644
                                    --- a/src/proc/mobject/session/scope-path.hpp
                                    +++ b/src/proc/mobject/session/scope-path.hpp
                                    @@ -27,6 +27,7 @@
                                     //#include "proc/mobject/mobject.hpp"
                                     //#include "proc/mobject/placement-ref.hpp"
                                     #include "proc/mobject/session/scope.hpp"
                                    +#include "lib/bool-checkable.hpp"
                                     #include "lib/iter-adapter.hpp"
                                     
                                     #include 
                                    @@ -44,6 +45,7 @@ namespace session {
                                        * TODO type comment
                                        */
                                       class ScopePath
                                    +    : public lib::BoolCheckable
                                         {
                                           vector path_;
                                           
                                    @@ -52,21 +54,73 @@ namespace session {
                                           typedef lib::RangeIter<_VIter>      _IterType;
                                           
                                         public:
                                    -      ScopePath();
                                    +      ScopePath ();
                                    +      ScopePath (Scope const& leaf);
                                    +      
                                    +      static const ScopePath INVALID;
                                    +      
                                    +      /* == state diagnostics == */
                                    +      bool isValid()    const;
                                    +      bool empty()      const;
                                    +      size_t size()     const;
                                    +      size_t length()   const;
                                    +                        ////////////////////////////////////////TICKET #429 : diagnostic output to be added later
                                           
                                           /// Iteration is always ascending from leaf to root
                                           typedef _IterType iterator;
                                           iterator begin()  const;
                                           iterator end()    const;
                                           
                                    -      Scope getLeaf()  const;
                                           
                                    +      /* == relations == */
                                    +      Scope& getLeaf()                 const;
                                    +      bool endsAt (Scope const&)       const;
                                    +      bool contains (Scope const&)     const;
                                    +      bool contains (ScopePath const&) const;
                                    +      
                                    +      friend ScopePath commonPrefix (ScopePath const&, ScopePath const&);
                                    +      friend bool      disjoint     (ScopePath const&, ScopePath const&);
                                    +      
                                    +      friend bool operator== (ScopePath const&, ScopePath const&);
                                    +      
                                    +      
                                    +      /* == mutations == */
                                           void clear();
                                    +      Scope& moveUp();
                                    +      Scope& goRoot();
                                    +      void navigate (Scope const&);
                                           
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                       
                                       
                                    +  inline bool
                                    +  operator== (ScopePath const& path1, ScopePath const& path2)
                                    +  {
                                    +    return path1.path_ == path2.path_;
                                    +  }
                                    +  
                                    +  inline bool
                                    +  operator!= (ScopePath const& path1, ScopePath const& path2)
                                    +  {
                                    +    return !(path1 == path2);
                                    +  }
                                    +  
                                    +  
                                    +  inline size_t
                                    +  ScopePath::length()  const
                                    +  {
                                    +    return path_.size();
                                    +  }
                                    +  
                                    +  
                                    +  inline size_t
                                    +  ScopePath::size()  const
                                    +  {
                                    +    return path_.size();
                                    +  }
                                    +  
                                    +  
                                       inline ScopePath::iterator
                                       ScopePath::begin()  const
                                       {
                                    diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp
                                    index 2e3917ece..d9a08fe0f 100644
                                    --- a/src/proc/mobject/session/scope.cpp
                                    +++ b/src/proc/mobject/session/scope.cpp
                                    @@ -146,6 +146,16 @@ namespace session {
                                       }
                                       
                                       
                                    +  /** check if this scope can be located.
                                    +   *  An default constructed Scope (i.e without
                                    +   *  defining Placement) can't be located and returns false here */
                                    +  bool
                                    +  Scope::isValid()  const
                                    +  {
                                    +    return anchor_.isValid();
                                    +  }
                                    +  
                                    +  
                                       /** enumerate the path of nested scopes up to root scope.
                                        *  @return an iterator which starts with this scope and
                                        *          successively yields outer scopes, stopping at root.
                                    @@ -155,7 +165,6 @@ namespace session {
                                       {
                                         UNIMPLEMENTED ("ascend scope hierarchy up to root");
                                       }
                                    -
                                       
                                       
                                       
                                    diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp
                                    index c77d43ac8..592002b61 100644
                                    --- a/src/proc/mobject/session/scope.hpp
                                    +++ b/src/proc/mobject/session/scope.hpp
                                    @@ -75,6 +75,7 @@ namespace session {
                                           
                                           Scope const& getParent()  const;
                                           PlacementMO& getTop()  const;
                                    +      bool isValid() const;
                                           bool isRoot()  const;
                                           
                                           typedef IterType_ iterator;
                                    diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/scope-path-test.cpp
                                    index c1946c087..a2bcfb206 100644
                                    --- a/tests/components/proc/mobject/scope-path-test.cpp
                                    +++ b/tests/components/proc/mobject/scope-path-test.cpp
                                    @@ -40,6 +40,7 @@ namespace mobject {
                                     namespace session {
                                     namespace test    {
                                       
                                    +  using util::isnil;
                                       using util::isSameObject;
                                     //using lumiera::Time;
                                     //using std::string;
                                    @@ -47,6 +48,7 @@ namespace test    {
                                     //using std::endl;
                                     //  using namespace mobject::test;
                                       using lumiera::error::LUMIERA_ERROR_LOGIC;
                                    +  using lumiera::error::LUMIERA_ERROR_INVALID;
                                       
                                       
                                       /***************************************************************************
                                    @@ -66,15 +68,16 @@ namespace test    {
                                               // Prepare an (test)Index backing the PlacementRefs
                                               PPIdx index = build_testScopes();
                                               PMO& startPlacement = retrieve_startElm();
                                    -          ASSERT (startPlacement);
                                    +          ASSERT (startPlacement.isValid());
                                               
                                               ScopePath testPath = buildPath (startPlacement);
                                               checkRelations (testPath,startPlacement);
                                    -          invalildPath (testPath,startPlacement);
                                    -          emptyPath (testPath);
                                    +          invalidPath (testPath,startPlacement);
                                    +          rootPath (testPath);
                                               check_Identity_and_Copy (startPlacement);
                                               navigate (testPath, index);
                                               clear (testPath, index);
                                    +                                  ////////////////////////////////////////TICKET #429 : verify diagnostic output (to be added later)
                                             }
                                           
                                           
                                    @@ -82,16 +85,19 @@ namespace test    {
                                           buildPath (PMO& startPla)
                                             {
                                               Scope startScope (startPla);
                                    -#if false     ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                    -          ScopePath path (startScope);
                                    -          ASSERT (path);
                                    -          ASSERT (path.contains (startScope));
                                    -          return path;
                                    -          ScopePath path (startScope);
                                    -          
                                    +          ScopePath path  (startScope);
                                               ScopePath path2 (startScope);
                                               ScopePath path3 (path2);
                                    -#endif
                                    +          
                                    +          ASSERT (path);
                                    +          ASSERT (path.contains (startScope));
                                    +          ASSERT ( path.getLeaf() == path2.getLeaf());
                                    +          ASSERT (path2.getLeaf() == path3.getLeaf());
                                    +          
                                    +          Scope unrelatedScope (TestPlacement<> (*new DummyMO));
                                    +          VERIFY_ERROR (INVALID, ScopePath(unrelatedScope) );
                                    +          
                                    +          return path;
                                             }
                                           
                                           
                                    @@ -112,7 +118,6 @@ namespace test    {
                                           void
                                           checkRelations (ScopePath path1, PMO& refPlacement)
                                             {
                                    -#if false     ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                               ASSERT (path1.contains (refPlacement));
                                               
                                               Scope refScope (refPlacement);
                                    @@ -124,7 +129,7 @@ namespace test    {
                                               ASSERT (path2.endsAt (refScope));
                                               
                                               ASSERT (path1 == path2);
                                    -          ASSERT (!isSameObject (path,path2));
                                    +          ASSERT (!isSameObject (path1,path2));
                                               
                                               Scope parent = path2.moveUp();
                                               ASSERT (path2.endsAt (parent));
                                    @@ -138,38 +143,35 @@ namespace test    {
                                               ASSERT (path2 == commonPrefix(path2,path1));
                                               ASSERT (path1 != commonPrefix(path1,path2));
                                               ASSERT (path1 != commonPrefix(path2,path1));
                                    -#endif        ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                             }
                                           
                                           
                                           void
                                    -      emptyPath (ScopePath refPath)
                                    +      rootPath (ScopePath refPath)
                                             {
                                    -#if false     ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                    -          ASSERT (!isnil (refPath));
                                    +          ASSERT ( refPath);
                                               refPath.goRoot();
                                    -          ASSERT ( isnil (refPath));
                                    -          ASSERT (refPath.empty());
                                    -          ASSERT (refPath.isValid());
                                    +          ASSERT (!refPath);
                                    +          ASSERT (!refPath.empty());
                                    +          ASSERT (!refPath.isValid());
                                               ASSERT (1 == refPath.length());
                                               
                                               ScopePath defaultPath;
                                    -          ASSERT (isnil (defaultPath));
                                    +          ASSERT (!defaultPath);
                                               ASSERT (refPath == defaultPath);
                                    -#endif        ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                             }
                                           
                                           
                                           void
                                           invalidPath (ScopePath refPath, PMO& refPlacement)
                                             {
                                    -#if false     ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                               ASSERT (refPath);
                                               ASSERT (!ScopePath::INVALID);
                                    +          ASSERT (isnil (ScopePath::INVALID));
                                               
                                               ScopePath invalidP (ScopePath::INVALID);
                                    -          ASSERT (!invalildP);
                                    -          ASSERT (invalildP == ScopePath::INVALID);
                                    +          ASSERT (isnil (invalidP));
                                    +          ASSERT (invalidP == ScopePath::INVALID);
                                               ASSERT (!isSameObject (invalidP, ScopePath::INVALID));
                                               
                                               ASSERT (refPath.contains (refPlacement));
                                    @@ -189,24 +191,22 @@ namespace test    {
                                               ASSERT (1 == refPath.length());
                                               
                                               Scope nil = refPath.moveUp();
                                    -          ASSERT (!refPath);
                                    +          ASSERT (refPath.empty());
                                               ASSERT (!nil.isValid());
                                               ASSERT (refPath == invalidP);
                                               ASSERT (invalidP.contains (nil));
                                               
                                               refPath.navigate(root);
                                               ASSERT (refPath != invalidP);
                                    -          ASSERT (refPath);
                                    +          ASSERT (!isnil (refPath));
                                               
                                             //ScopePath::INVALID.navigate(root);  // doesn't compile
                                    -#endif        ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                             }
                                           
                                           
                                           void
                                           check_Identity_and_Copy (PMO& refPlacement)
                                             {
                                    -#if false     ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                               Scope startScope (refPlacement);
                                               ScopePath path1 (startScope);
                                               ScopePath path2 (startScope);
                                    @@ -237,7 +237,6 @@ namespace test    {
                                               ASSERT (path1 != path2);
                                               ASSERT (path2 != path3);
                                               ASSERT (path1 != path3);
                                    -#endif        ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                             }
                                           
                                           
                                    @@ -253,7 +252,6 @@ namespace test    {
                                           void
                                           navigate (const ScopePath refPath, PPIdx index)
                                             {
                                    -#if false     ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                               ScopePath path (refPath);
                                               ASSERT (path == refPath);
                                               
                                    @@ -278,8 +276,9 @@ namespace test    {
                                               ASSERT (!path.endsAt (root));
                                               ASSERT (!path.endsAt (leaf));
                                               
                                    -          PMO newNode (*new DummyMO);
                                    -          index->insert (newNode, parent); // place as sibling of "leaf"
                                    +          TestPlacement<> newNode (*new DummyMO);
                                    +          PMO& parentRefPoint = parent.getTop();
                                    +          index->insert (newNode, parentRefPoint); // place as sibling of "leaf"
                                               path.navigate (newNode);
                                               Scope sibling = path.getLeaf();
                                               ASSERT (parent == sibling.getParent());
                                    @@ -291,7 +290,7 @@ namespace test    {
                                               ASSERT (!disjoint (path,refPath));
                                               ASSERT (!disjoint (refPath,path));
                                               
                                    -          Path prefix = commonPrefix (path,refPath);
                                    +          ScopePath prefix = commonPrefix (path,refPath);
                                               ASSERT (prefix == commonPrefix (refPath,path));
                                               ASSERT (prefix.endsAt (parent));
                                               ASSERT (!prefix.contains (leaf));
                                    @@ -299,34 +298,40 @@ namespace test    {
                                               path.navigate (prefix.getLeaf());
                                               ASSERT (path == prefix);
                                               
                                    +          // try to navigate to an unconnected location...
                                    +          ScopePath beforeInvalidNavigation = path;
                                    +          Scope unrelatedScope (TestPlacement<> (*new DummyMO));
                                    +          VERIFY_ERROR (INVALID, path.navigate (unrelatedScope) );
                                    +          ASSERT (path == beforeInvalidNavigation); // not messed up by the incident
                                    +          
                                               // now explore a completely separate branch....
                                    -          PMO& separatePlacement = *index->query (
                                    -                                     *index->query (
                                    -                                       *index->query (root)));
                                    +          PMO& separatePlacement = *explore_testScope (
                                    +                                     *explore_testScope (
                                    +                                       *explore_testScope (
                                    +                                         root.getTop())));
                                               path.navigate (separatePlacement);
                                               ASSERT (path);
                                               ASSERT (disjoint (path,refPath));
                                               ASSERT (path.contains(separatePlacement));
                                               Scope other = path.getLeaf();
                                    -          ASSERT (other.getTop() == separatePlacement);
                                    +          ASSERT (isSameObject (other.getTop(), separatePlacement));
                                               ScopePath rootPrefix = commonPrefix (path,refPath);
                                               ASSERT (rootPrefix.endsAt (root));
                                    -#endif        ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                    +          
                                             }
                                           
                                           
                                           void
                                    -      clear (ScopePath& testPath, PPIdx index)
                                    +      clear (ScopePath& path, PPIdx index)
                                             {
                                    -#if false     ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                               ASSERT (path);
                                               PMO rootNode = index->getRoot();
                                               ASSERT (path.getLeaf() != rootNode);
                                               
                                               path.clear();
                                    -          ASSERT (path);
                                    +          ASSERT (!path);
                                    +          ASSERT (!isnil (path));
                                               ASSERT (path.getLeaf() == rootNode);
                                    -#endif        ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                             }
                                               
                                         };
                                    diff --git a/tests/components/proc/mobject/session/test-scopes.cpp b/tests/components/proc/mobject/session/test-scopes.cpp
                                    index f7e4c3f6c..0666ae0b8 100644
                                    --- a/tests/components/proc/mobject/session/test-scopes.cpp
                                    +++ b/tests/components/proc/mobject/session/test-scopes.cpp
                                    @@ -96,4 +96,12 @@ namespace test    {
                                       }
                                       
                                       
                                    +  ScopeQuery::iterator
                                    +  explore_testScope (PlacementMO const& scopeTop)
                                    +  {
                                    +    return ScopeQuery(SessionServiceExploreScope::getResolver(),
                                    +                               scopeTop, CHILDREN);
                                    +  }
                                    +  
                                    +  
                                     }}} // namespace mobject::session::test
                                    diff --git a/tests/components/proc/mobject/session/test-scopes.hpp b/tests/components/proc/mobject/session/test-scopes.hpp
                                    index a95da5bde..a88f94594 100644
                                    --- a/tests/components/proc/mobject/session/test-scopes.hpp
                                    +++ b/tests/components/proc/mobject/session/test-scopes.hpp
                                    @@ -27,6 +27,8 @@
                                     
                                     #include "proc/mobject/test-dummy-mobject.hpp"
                                     #include "proc/mobject/session/placement-index.hpp"
                                    +#include "proc/mobject/session/scope-query.hpp"
                                    +#include "proc/mobject/placement.hpp"
                                     
                                     #include 
                                     
                                    @@ -61,5 +63,13 @@ namespace test    {
                                       PlacementMO& retrieve_startElm();
                                       
                                       
                                    +  /** shortcut to explore the contents of a scope within the current index.
                                    +   *  Usually, clients would use QueryFocus or ScopeLocator to perform this task,
                                    +   *  but for the purpose of testing we're better off to invoke the query directly
                                    +   */
                                    +  ScopeQuery::iterator explore_testScope (PlacementMO const& scopeTop);
                                    +  
                                    +  
                                    +  
                                     }}} // namespace mobject::session::test
                                     #endif
                                    
                                    From c328945cb4c78f84d80f19e639dab71b5e4c24ed Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 21 Nov 2009 21:33:01 +0100
                                    Subject: [PATCH 088/377] commented the ScopePath API
                                    
                                    ---
                                     src/proc/mobject/session/scope-path.hpp | 68 ++++++++++++++++++++++++-
                                     1 file changed, 67 insertions(+), 1 deletion(-)
                                    
                                    diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp
                                    index c8b912e14..fc14faa74 100644
                                    --- a/src/proc/mobject/session/scope-path.hpp
                                    +++ b/src/proc/mobject/session/scope-path.hpp
                                    @@ -20,6 +20,65 @@
                                      
                                     */
                                     
                                    +/** @file scope-path.hpp
                                    + ** An Object representing a sequence of nested scopes within the Session.
                                    + ** MObjects are being attached to the model by Placements, and each Placement
                                    + ** is added as belonging \em into another Placement, which defines the Scope
                                    + ** of the addition. There is one (abstract) root element, containing the timelines;
                                    + ** from there a nested sequence of scopes leads down to each Placement.
                                    + ** Ascending this path yields all the scopes to search or query in proper order
                                    + ** to be used when resolving some attribute of placement. Placements use visibility
                                    + ** rules comparable to visibility of scoped definitions in common programming languages
                                    + ** or in cascading style sheets, where a local definition can shadow a global one.
                                    + ** In a similar way, properties not defined locally may be resolved by querying
                                    + ** up the sequence of nested scopes.
                                    + ** 
                                    + ** A scope path is represented as sequence of scopes, where each Scope is implemented
                                    + ** by a PlacementRef pointing to the »scope top«, i.e. the placement in the session
                                    + ** constituting this scope. The leaf of this path can be considered the current scope.
                                    + ** ScopePath is intended to remember a \em current location within the model, to be
                                    + ** used for resolving queries and discovering contents.
                                    + ** 
                                    + ** \par operations and behaviour
                                    + ** 
                                    + ** In addition to some search and query functions, a scope path has the ability to 
                                    + ** \em navigate to a given target scope, which must be reachable by ascending and
                                    + ** descending into the branches of the overall tree or DAG (in the general case).
                                    + ** Navigating changes the current path, which usually happens when the current
                                    + ** "focus" shifts while operating on the model.
                                    + ** 
                                    + ** - ScopePath can be default constructed, yielding an \em invalid path.
                                    + ** - When created with a given target Scope, a connection to the current Session
                                    + **   is created behind the scenes to discover the path starting from this target
                                    + **   Scope up to model root. This is the core "locating" operation. It may fail.
                                    + ** - There is a pre defined \c ScopePath::INVALID token
                                    + ** - ScopePaths are intended to be handled by value (as are Scopes and
                                    + **   PlacementRefs). They are equality comparable and provide several specialised
                                    + **   relation predicates.
                                    + ** - all implementations are focused on clarity, not uttermost performance, as
                                    + **   the assumption is for paths to be relatively short and path operations to
                                    + **   be executed rather in a GUI action triggered context.
                                    + ** - the iteration (Lumiera Forward Iterator) yields the path elements in
                                    + **   \em ascending order, starting with the leaf element
                                    + ** - a path containing just the root element evaluates to \c bool(false) 
                                    + **   (rationale is that any valid, usable path is below just root).
                                    + ** - an empty (nil) path doesn't even contain the root element and 
                                    + **   may throw on many operations.
                                    + ** 
                                    + ** \par relation to ScopeLocator
                                    + ** 
                                    + ** ScopeLocator holds the QueryFocusStack, which contains ScopePath objects.
                                    + ** Each of these stack frames represents the current location for some evaluation
                                    + ** context; it is organised as stack to allow intermediate evaluations. Management
                                    + ** of these stack frames is automated, with the assistance of ScopePath by
                                    + ** incorporating a ref-count.
                                    + ** 
                                    + ** @see scope-path-test.cpp
                                    + ** @see Scope
                                    + ** @see ScopeLocator
                                    + ** 
                                    + */
                                    +
                                     
                                     #ifndef MOBJECT_SESSION_SCOPE_PATH_H
                                     #define MOBJECT_SESSION_SCOPE_PATH_H
                                    @@ -42,7 +101,14 @@ namespace session {
                                       
                                       
                                       /**
                                    -   * TODO type comment
                                    +   * Sequence of nested scopes within the high-level model.
                                    +   * Implemented as vector of Scope elements. Providing
                                    +   * state and relation predicates, and the ability to
                                    +   * \em navigate the current location, as represented
                                    +   * by the current leaf element of the path. 
                                    +   * 
                                    +   * Incorporates a ref count to be utilised by ScopeLocator
                                    +   * and QueryFocus to establish the \em current focus (path).
                                        */
                                       class ScopePath
                                         : public lib::BoolCheckable
                                    
                                    From 451253ae8a9e13ddf6f38a562a274a1c873815c1 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 01:14:27 +0100
                                    Subject: [PATCH 089/377] utility to append elements from an Lumiera Forward
                                     Iterator until exhaustion
                                    
                                    ---
                                     src/lib/itertools.hpp | 13 +++++++++++++
                                     1 file changed, 13 insertions(+)
                                    
                                    diff --git a/src/lib/itertools.hpp b/src/lib/itertools.hpp
                                    index b6fa7fb47..2cc62518d 100644
                                    --- a/src/lib/itertools.hpp
                                    +++ b/src/lib/itertools.hpp
                                    @@ -466,5 +466,18 @@ namespace lib {
                                       
                                       
                                       
                                    +  /* === utility functions === */
                                    +  
                                    +  template
                                    +  inline void
                                    +  append_all (IT iter, CON& container)
                                    +  {
                                    +    for ( ; iter; ++iter )
                                    +      container.push_back (*iter);
                                    +  }
                                    +  
                                    +  
                                    +  
                                    +  
                                     } // namespace lib
                                     #endif
                                    
                                    From 27390b5732dde2dbb5f9c3a5737d0d13f85df859 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 01:15:31 +0100
                                    Subject: [PATCH 090/377] add query for path/location to ScopeLocator
                                    
                                    ---
                                     src/proc/mobject/session/scope-locator.hpp | 17 +++++++++++++++++
                                     src/proc/mobject/session/scope.cpp         |  5 ++++-
                                     2 files changed, 21 insertions(+), 1 deletion(-)
                                    
                                    diff --git a/src/proc/mobject/session/scope-locator.hpp b/src/proc/mobject/session/scope-locator.hpp
                                    index ed83d674e..aa4d03633 100644
                                    --- a/src/proc/mobject/session/scope-locator.hpp
                                    +++ b/src/proc/mobject/session/scope-locator.hpp
                                    @@ -73,6 +73,12 @@ namespace session {
                                           typename ScopeQuery::iterator
                                           query (Scope);
                                           
                                    +      template
                                    +      typename ScopeQuery::iterator
                                    +      locate (Scope scope);
                                    +      
                                    +     ~ScopeLocator();
                                    +     
                                         protected:
                                           ScopeLocator();
                                           
                                    @@ -107,5 +113,16 @@ namespace session {
                                       }
                                       
                                       
                                    +  /** use the contents-resolving facility exposed by the session
                                    +   *  to discover the path up from the given scope to model root
                                    +   */
                                    +  template
                                    +  inline typename ScopeQuery::iterator
                                    +  ScopeLocator::locate (Scope scope)
                                    +  {
                                    +    return ScopeQuery (theResolver(), scope.getTop(), PATH);
                                    +  }
                                    +  
                                    +  
                                     }} // namespace mobject::session
                                     #endif
                                    diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp
                                    index d9a08fe0f..f8a604115 100644
                                    --- a/src/proc/mobject/session/scope.cpp
                                    +++ b/src/proc/mobject/session/scope.cpp
                                    @@ -68,9 +68,12 @@ namespace session {
                                       ScopeLocator::ScopeLocator()
                                         : focusStack_(new QueryFocusStack)
                                       {
                                    -    
                                    +    TODO ("anything in initialise here?");
                                       }
                                       
                                    +  ScopeLocator::~ScopeLocator() { }
                                    +  
                                    +  
                                       /** Storage holding the single ScopeLocator instance */
                                       lib::Singleton ScopeLocator::instance;
                                       
                                    
                                    From 36e342fc111db51786de833e508b553ec5d9b5a7 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 01:16:33 +0100
                                    Subject: [PATCH 091/377] Implement ScopePath functionality. Closes #322
                                    
                                    ---
                                     src/proc/mobject/session/scope-path.cpp       | 166 +++++++++++++-----
                                     src/proc/mobject/session/scope-path.hpp       |  32 +++-
                                     .../session/session-service-explore-scope.hpp |   8 +
                                     src/proc/mobject/session/session-services.cpp |   6 +-
                                     4 files changed, 160 insertions(+), 52 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp
                                    index e511d356f..2b8896c10 100644
                                    --- a/src/proc/mobject/session/scope-path.cpp
                                    +++ b/src/proc/mobject/session/scope-path.cpp
                                    @@ -22,49 +22,90 @@
                                     
                                     
                                     #include "proc/mobject/session/scope-path.hpp"
                                    +#include "proc/mobject/session/scope-locator.hpp"
                                    +#include "proc/mobject/session/session-service-explore-scope.hpp"
                                    +#include "proc/mobject/mobject.hpp"
                                    +#include "lib/itertools.hpp"
                                    +#include "lib/symbol.hpp"
                                     #include "lib/error.hpp"
                                     #include "lib/util.hpp"
                                    -//#include "proc/mobject/session/track.hpp"
                                     
                                    -//#include "proc/mobject/placement.hpp"
                                    -//#include "proc/mobject/session/mobjectfactory.hpp"
                                    -//#include "proc/asset/track.hpp"
                                     #include 
                                    +#include 
                                     
                                     namespace mobject {
                                     namespace session {
                                       
                                    +  using std::reverse;
                                    +  
                                       using std::tr1::bind;
                                       using std::tr1::function;
                                       using std::tr1::placeholders::_1;
                                    +  using lib::append_all;
                                       using util::and_all;
                                       
                                       using namespace lumiera;
                                       
                                       
                                    -  /** by default, a scope path just contains 
                                    -   *  the root scope of the current session (PlacementIndex).
                                    -   *  @note invoking this function accesses the session and thus
                                    -   *        may cause an empty default session to be created.
                                    +  LUMIERA_ERROR_DEFINE (EMPTY_SCOPE_PATH, "Placement scope not locatable (empty model path)");
                                    +  
                                    +  
                                    +  
                                    +  namespace { // Helpers and shortcuts....
                                    +    
                                    +    /** issue a query to discover the path to root,
                                    +     *  starting with the given scope */
                                    +    inline ScopeQuery::iterator
                                    +    discoverScopePath (Scope const& leaf)
                                    +    {
                                    +      return ScopeLocator::instance().locate (leaf);
                                    +    }
                                    +    
                                    +    
                                    +    void
                                    +    ___check_notBottom (const ScopePath *path, lib::Literal operation_descr)
                                    +    {
                                    +      REQUIRE (path);
                                    +      if (path->empty())
                                    +        throw error::Invalid (operation_descr+" an empty placement scope path"
                                    +                             , LUMIERA_ERROR_EMPTY_SCOPE_PATH);
                                    +    }
                                    +  }//(End) helpers
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  /**
                                    +   * Create an \em empty path.
                                    +   * By default, a scope path just contains
                                    +   * the root scope of the current session (PlacementIndex).
                                    +   * @note invoking this function accesses the session and thus
                                    +   *       may cause an empty default session to be created.
                                        */
                                       ScopePath::ScopePath ()
                                    +    : path_()
                                       {
                                    -    UNIMPLEMENTED ("default path just containing root");
                                    +    clear();
                                       }
                                       
                                       
                                    -  /** When creating a path to a given (leaf) scope,
                                    -   *  the complete sequence of nested scopes leading to 
                                    -   *  this special scope is discovered, using the query service
                                    -   *  exposed by the session (through ScopeLocator).
                                    -   *  @note when locating the default (invalid) scope,
                                    -   *         a special empty ScopePath is created
                                    -   *  @throw error::Invalid if the given target scope
                                    -   *         can't be connected to the (implicit) root
                                    +  /**
                                    +   * When creating a path to a given (leaf) scope,
                                    +   * the complete sequence of nested scopes leading to
                                    +   * this special scope is discovered, using the query service
                                    +   * exposed by the session (through ScopeLocator).
                                    +   * @note when locating the default (invalid) scope,
                                    +   *        a special empty ScopePath is created
                                    +   * @throw error::Invalid if the given target scope
                                    +   *        can't be connected to the (implicit) root
                                        */
                                       ScopePath::ScopePath (Scope const& leaf)
                                    +    : path_()
                                       {
                                    -    UNIMPLEMENTED ("initialise by discovering complete scope sequence");
                                    +    if (!leaf.isValid()) return; // invalid leaf defines invalid path....
                                    +    
                                    +    append_all (discoverScopePath(leaf), path_);
                                    +    reverse (path_.begin(), path_.end());
                                       }
                                       
                                       
                                    @@ -72,54 +113,66 @@ namespace session {
                                       const ScopePath ScopePath::INVALID = ScopePath(Scope());
                                       
                                       
                                    -  /* == Diagnostics == */
                                    -  
                                       /** a \em valid path consists of more than just the root element.
                                        *  @note contrary to this, an \em empty path doesn't even contain a root element
                                        */
                                    -  bool
                                    +  inline bool
                                       ScopePath::isValid()  const
                                       {
                                    -    UNIMPLEMENTED ("validity self check: more than just root");
                                    +    return (0 < length())
                                    +#ifndef NDEBUG
                                    +        && hasValidRoot()
                                    +#endif      
                                    +           ;
                                       }
                                       
                                    -  /** an empty path doesn't even contain a root element.
                                    -   *  Many operations throw when invoked on such a path.
                                    -   *  Navigating up from an root path creates an empty path.
                                    -   */
                                       bool
                                    -  ScopePath::empty()  const
                                    +  ScopePath::hasValidRoot()  const
                                       {
                                    -    UNIMPLEMENTED ("empty == no elements, even no root!");
                                    +    REQUIRE (0 < length());
                                    +    return path_[0] == currModelRoot();
                                       }
                                       
                                    +  PlacementMO const&
                                    +  ScopePath::currModelRoot()  const
                                    +  {
                                    +    return SessionServiceExploreScope::getScopeRoot();
                                    +  }
                                    +  
                                    +  
                                    +  
                                       
                                       
                                       /* == Relations == */
                                       
                                    -  Scope&
                                    +  Scope const&
                                       ScopePath::getLeaf()  const
                                       {
                                    -    UNIMPLEMENTED ("access end node of current path");
                                    +    ___check_notBottom (this, "Inspecting");
                                    +    return path_.back();
                                       }
                                       
                                       
                                       /** verify the scope in question is equivalent
                                        *  to our leaf scope. Equivalence of scopes means
                                        *  they are defined by the same scope top placement,
                                    -   *  i.e. registered with the same Placement-ID. 
                                    +   *  i.e. registered with the same Placement-ID.
                                        */
                                       bool
                                       ScopePath::endsAt(Scope const& aScope)  const
                                       {
                                    -    UNIMPLEMENTED ("verify the scope in question is identical (same ID) to our leaf scope");
                                    +    return aScope == getLeaf();
                                       }
                                       
                                       
                                       bool
                                       ScopePath::contains (Scope const& aScope)  const
                                       {
                                    -    UNIMPLEMENTED ("containment check");
                                    +    for (iterator ii = this->begin(); ii; ++ii)
                                    +      if (aScope == *ii)
                                    +        return true;
                                    +    
                                    +    return false;
                                       }
                                       
                                       
                                    @@ -144,52 +197,83 @@ namespace session {
                                       ScopePath
                                       commonPrefix (ScopePath const& path1, ScopePath const& path2)
                                       {
                                    -    UNIMPLEMENTED ("determine the common prefix, if any");
                                    +    typedef std::vector::iterator VIter;
                                    +    ScopePath prefix (ScopePath::INVALID);
                                    +    uint len = std::min (path1.length(), path2.length());
                                    +    for (uint pos = 0; pos
                                    -//#include 
                                     
                                    -using std::vector;
                                    -//using std::string;
                                     
                                     namespace mobject {
                                     namespace session {
                                       
                                       
                                    +  LUMIERA_ERROR_DECLARE (EMPTY_SCOPE_PATH);  ///< Placement scope not locatable (empty model path)
                                    +  
                                       
                                       /**
                                        * Sequence of nested scopes within the high-level model.
                                    @@ -113,7 +110,7 @@ namespace session {
                                       class ScopePath
                                         : public lib::BoolCheckable
                                         {
                                    -      vector path_;
                                    +      std::vector path_;
                                           
                                           typedef vector                  _VType;
                                           typedef _VType::const_reverse_iterator _VIter;
                                    @@ -139,7 +136,7 @@ namespace session {
                                           
                                           
                                           /* == relations == */
                                    -      Scope& getLeaf()                 const;
                                    +      Scope const& getLeaf()           const;
                                           bool endsAt (Scope const&)       const;
                                           bool contains (Scope const&)     const;
                                           bool contains (ScopePath const&) const;
                                    @@ -156,8 +153,17 @@ namespace session {
                                           Scope& goRoot();
                                           void navigate (Scope const&);
                                           
                                    +      
                                    +    private:
                                    +      bool hasValidRoot()                 const;
                                    +      PlacementMO const& currModelRoot()  const;
                                    +      void appendScope (Scope const&);
                                         };
                                    -///////////////////////////TODO currently just fleshing the API
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                       
                                       
                                       inline bool
                                    @@ -186,6 +192,16 @@ namespace session {
                                         return path_.size();
                                       }
                                       
                                    +  /** an empty path doesn't even contain a root element.
                                    +   *  Many operations throw when invoked on such a path.
                                    +   *  Navigating up from an root path creates an empty path.
                                    +   */
                                    +  inline bool
                                    +  ScopePath::empty()  const
                                    +  {
                                    +    return path_.empty();
                                    +  }
                                    +  
                                       
                                       inline ScopePath::iterator
                                       ScopePath::begin()  const
                                    diff --git a/src/proc/mobject/session/session-service-explore-scope.hpp b/src/proc/mobject/session/session-service-explore-scope.hpp
                                    index 577705cb9..a93b08ba3 100644
                                    --- a/src/proc/mobject/session/session-service-explore-scope.hpp
                                    +++ b/src/proc/mobject/session/session-service-explore-scope.hpp
                                    @@ -57,6 +57,14 @@ namespace session {
                                       
                                       
                                     
                                    +  /**
                                    +   * Implementation-level service for issuing contents/discovery queries.
                                    +   * Actually, the implementation of this service is backed by the PlacementIndex
                                    +   * within the current session, but this link isn't disclosed to client code.
                                    +   * The exposed QueryResolver is able to handle typed DiscoveryQuery instances.
                                    +   * Usually, on invocation, a search scope needs to be specified. The root Scope
                                    +   * of the current model (session datastructure) can be obtained by #getScopeRoot
                                    +   */
                                       struct SessionServiceExploreScope
                                         {
                                           static QueryResolver const& getResolver();
                                    diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp
                                    index 87392fe55..65b9a3b2c 100644
                                    --- a/src/proc/mobject/session/session-services.cpp
                                    +++ b/src/proc/mobject/session/session-services.cpp
                                    @@ -61,7 +61,7 @@ namespace session {
                                       }
                                       
                                       
                                    -  /** */
                                    +  /** Re-define the implicit PlacementIndex temporarily, e.g. for unit tests. */
                                       void
                                       SessionServiceMockIndex::reset_PlacementIndex (PPIdx const& alternativeIndex)
                                       {
                                    @@ -69,7 +69,7 @@ namespace session {
                                       }
                                       
                                       
                                    -  /** */
                                    +  /** @return resolver for DiscoveryQuery instances, actually backed by PlacementIndex */
                                       QueryResolver const&
                                       SessionServiceExploreScope::getResolver()
                                       {
                                    @@ -77,7 +77,7 @@ namespace session {
                                       }
                                       
                                       
                                    -  /** */
                                    +  /** @return root scope of the current model (session datastructure) */
                                       PlacementMO& 
                                       SessionServiceExploreScope::getScopeRoot()
                                       {
                                    
                                    From 46eae1c03a85dd03f40bddd479b5011fc63e0056 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 03:48:52 +0100
                                    Subject: [PATCH 092/377] add a refcount field (for intrusive refcounting) to
                                     ScopePath
                                    
                                    ---
                                     src/proc/mobject/session/scope-path.cpp | 12 ++++++++++--
                                     src/proc/mobject/session/scope-path.hpp | 10 ++++++++++
                                     2 files changed, 20 insertions(+), 2 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp
                                    index 2b8896c10..5a2c7291b 100644
                                    --- a/src/proc/mobject/session/scope-path.cpp
                                    +++ b/src/proc/mobject/session/scope-path.cpp
                                    @@ -83,7 +83,8 @@ namespace session {
                                        *       may cause an empty default session to be created.
                                        */
                                       ScopePath::ScopePath ()
                                    -    : path_()
                                    +    : refcount_(0)
                                    +    , path_()
                                       {
                                         clear();
                                       }
                                    @@ -100,7 +101,8 @@ namespace session {
                                        *        can't be connected to the (implicit) root
                                        */
                                       ScopePath::ScopePath (Scope const& leaf)
                                    -    : path_()
                                    +    : refcount_(0)
                                    +    , path_()
                                       {
                                         if (!leaf.isValid()) return; // invalid leaf defines invalid path....
                                         
                                    @@ -109,6 +111,12 @@ namespace session {
                                       }
                                       
                                       
                                    +  ScopePath::~ScopePath()
                                    +  {
                                    +    WARN_IF (refcount_, "Destroying a scope path frame with ref-count=%u", refcount_);
                                    +  }
                                    +  
                                    +  
                                       /** constant \em invalid path token. Created by locating an invalid scope */
                                       const ScopePath ScopePath::INVALID = ScopePath(Scope());
                                       
                                    diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp
                                    index c0802db6d..a650ff2a4 100644
                                    --- a/src/proc/mobject/session/scope-path.hpp
                                    +++ b/src/proc/mobject/session/scope-path.hpp
                                    @@ -110,6 +110,7 @@ namespace session {
                                       class ScopePath
                                         : public lib::BoolCheckable
                                         {
                                    +      size_t refcount_;
                                           std::vector path_;
                                           
                                           typedef vector                  _VType;
                                    @@ -117,6 +118,7 @@ namespace session {
                                           typedef lib::RangeIter<_VIter>      _IterType;
                                           
                                         public:
                                    +     ~ScopePath ();
                                           ScopePath ();
                                           ScopePath (Scope const& leaf);
                                           
                                    @@ -127,6 +129,7 @@ namespace session {
                                           bool empty()      const;
                                           size_t size()     const;
                                           size_t length()   const;
                                    +      size_t ref_count()const;
                                                             ////////////////////////////////////////TICKET #429 : diagnostic output to be added later
                                           
                                           /// Iteration is always ascending from leaf to root
                                    @@ -179,6 +182,13 @@ namespace session {
                                       }
                                       
                                       
                                    +  inline size_t
                                    +  ScopePath::ref_count()  const
                                    +  {
                                    +    return refcount_;
                                    +  }
                                    +  
                                    +  
                                       inline size_t
                                       ScopePath::length()  const
                                       {
                                    
                                    From 665eed5f1b32587c5430e966ebe1f3d3e7aa21d3 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 04:35:37 +0100
                                    Subject: [PATCH 093/377] new logging flag for the session
                                    
                                    ---
                                     src/include/logging.h | 2 ++
                                     1 file changed, 2 insertions(+)
                                    
                                    diff --git a/src/include/logging.h b/src/include/logging.h
                                    index ad67cb300..2cbd07a82 100644
                                    --- a/src/include/logging.h
                                    +++ b/src/include/logging.h
                                    @@ -123,6 +123,8 @@ NOBUG_CPP_DEFINE_FLAG_PARENT    (    thread,                    backend);
                                     NOBUG_CPP_DEFINE_FLAG_PARENT    (   proc,                       progress);
                                     /** progress log for proc-layer command dispatch */
                                     NOBUG_CPP_DEFINE_FLAG_PARENT    (    command,                   proc);
                                    +/** progress log for session datastructure */
                                    +NOBUG_CPP_DEFINE_FLAG_PARENT    (    session,                   proc);
                                     /** progress log for the gui */
                                     NOBUG_CPP_DEFINE_FLAG_PARENT    (   gui,                        progress);
                                     /** progress log for the support lib */
                                    
                                    From d90812e64b6c9bea6a45b14aa25a6ac9ce935dcd Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 04:36:14 +0100
                                    Subject: [PATCH 094/377] implement a stack of ScopePath frames
                                    
                                    ---
                                     .../mobject/session/query-focus-stack.hpp     | 111 +++++++++++++++++-
                                     src/proc/mobject/session/scope-path.cpp       |   3 +-
                                     src/proc/mobject/session/scope-path.hpp       |  23 ++++
                                     3 files changed, 135 insertions(+), 2 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/query-focus-stack.hpp b/src/proc/mobject/session/query-focus-stack.hpp
                                    index 499bf22d7..0c6c95413 100644
                                    --- a/src/proc/mobject/session/query-focus-stack.hpp
                                    +++ b/src/proc/mobject/session/query-focus-stack.hpp
                                    @@ -26,12 +26,17 @@
                                     
                                     //#include "proc/mobject/mobject.hpp"
                                     //#include "proc/mobject/placement.hpp"
                                    +#include "proc/mobject/session/scope-path.hpp"
                                     
                                     //#include 
                                     //#include 
                                    +#include 
                                    +#include 
                                     
                                     //using std::vector;
                                     //using std::string;
                                    +using std::list;
                                    +
                                     
                                     namespace mobject {
                                     namespace session {
                                    @@ -42,13 +47,117 @@ namespace session {
                                        * TODO type comment
                                        */
                                       class QueryFocusStack
                                    +    : boost::noncopyable
                                         {
                                           
                                    -    public:
                                    +      std::list paths_;
                                           
                                    +    public:
                                    +      QueryFocusStack()
                                    +        : paths_()
                                    +        {
                                    +          openDefaultFrame();
                                    +        }
                                    +      
                                    +      
                                    +      bool empty()  const;
                                    +      size_t size() const;
                                    +      
                                    +      ScopePath& push (Scope const&);
                                    +      ScopePath& top  ();
                                    +      void pop_unused ();
                                    +      
                                    +      
                                    +    private:
                                    +      void openDefaultFrame();
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                       
                                       
                                    +  bool
                                    +  QueryFocusStack::empty()  const
                                    +  {
                                    +    return paths_.empty();
                                    +  }
                                    +  
                                    +  
                                    +  size_t
                                    +  QueryFocusStack::size()  const
                                    +  {
                                    +    return paths_.size();
                                    +  }
                                    +  
                                    +  
                                    +  /** Open a new path frame, pushing down the current frame.
                                    +   *  The new frame tries to locate the given start scope
                                    +   *  and navigates to this position.
                                    +   *  @note EXCEPTION_STRONG guarantee
                                    +   *  @return reference to the newly created path on top
                                    +   *  @throw error::Invalid if newStartPoint isn't locatable
                                    +   */
                                    +  ScopePath&
                                    +  QueryFocusStack::push (Scope const& newStartPoint)
                                    +  {
                                    +    ScopePath newPathFrame (newStartPoint); // may throw
                                    +    ENSURE (newPathFrame.isValid() || newStartPoint.isRoot());
                                    +    
                                    +    paths_.push_back (newPathFrame);
                                    +    ENSURE (0 < size());
                                    +    return paths_.back();
                                    +  }
                                    +  
                                    +  
                                    +  /** @return the topmost path frame actually in use
                                    +   *  @note may invoke #pop_unused()
                                    +   *  @note EXCEPTON_FREE    ///////TODO prove!
                                    +   */ 
                                    +  ScopePath&
                                    +  QueryFocusStack::top ()
                                    +  {
                                    +    if ( 0 == size()
                                    +      || 0 == paths_.back().ref_count()
                                    +       )
                                    +      pop_unused();
                                    +    
                                    +    ENSURE (!empty());
                                    +    ENSURE (!paths_.back().empty());
                                    +    return paths_.back();
                                    +  }
                                    +  
                                    +  
                                    +  /** investigate the stack top and discard any path frames
                                    +   *  which aren't referred anymore (as indicated by their
                                    +   *  ScopePath#use_count(). After executing this function
                                    +   *  the topmost frame is either in use, or a new default
                                    +   *  frame has been created at the bottom of an empty stack.
                                    +   *  @note EXCEPTON_FREE    ///////TODO prove!
                                    +   */
                                    +  void
                                    +  QueryFocusStack::pop_unused ()
                                    +  {
                                    +    while (size() && (0 == paths_.back().ref_count()))
                                    +      paths_.pop_back();
                                    +    
                                    +    if (0 == size())
                                    +      openDefaultFrame();
                                    +    ENSURE (!empty());
                                    +    ENSURE (!paths_.back().empty());
                                    +  }
                                    +  
                                    +  
                                    +  /** @internal open a default path frame at the bottom
                                    +   *  of an empty stack, locating to current model root
                                    +   *  @note EXCEPTON_FREE    ///////TODO prove!  
                                    +   */
                                    +  void
                                    +  QueryFocusStack::openDefaultFrame()
                                    +  {
                                    +    REQUIRE (0 == size());
                                    +    paths_.resize(1);
                                    +  }
                                    +  
                                    +  
                                    +  
                                    +  
                                     }} // namespace mobject::session
                                     #endif
                                    diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp
                                    index 5a2c7291b..f464cc7d9 100644
                                    --- a/src/proc/mobject/session/scope-path.cpp
                                    +++ b/src/proc/mobject/session/scope-path.cpp
                                    @@ -21,6 +21,7 @@
                                     * *****************************************************/
                                     
                                     
                                    +#include "include/logging.h"
                                     #include "proc/mobject/session/scope-path.hpp"
                                     #include "proc/mobject/session/scope-locator.hpp"
                                     #include "proc/mobject/session/session-service-explore-scope.hpp"
                                    @@ -113,7 +114,7 @@ namespace session {
                                       
                                       ScopePath::~ScopePath()
                                       {
                                    -    WARN_IF (refcount_, "Destroying a scope path frame with ref-count=%u", refcount_);
                                    +    WARN_IF (refcount_, session, "Destroying a scope path frame with ref-count=%lu", refcount_);
                                       }
                                       
                                       
                                    diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp
                                    index a650ff2a4..4f985e4a9 100644
                                    --- a/src/proc/mobject/session/scope-path.hpp
                                    +++ b/src/proc/mobject/session/scope-path.hpp
                                    @@ -149,6 +149,9 @@ namespace session {
                                           
                                           friend bool operator== (ScopePath const&, ScopePath const&);
                                           
                                    +      friend void intrusive_ptr_add_ref (ScopePath*);
                                    +      friend void intrusive_ptr_release (ScopePath*);
                                    +      
                                           
                                           /* == mutations == */
                                           void clear();
                                    @@ -182,6 +185,26 @@ namespace session {
                                       }
                                       
                                       
                                    +  /** management function for boost::intrusive_ptr
                                    +   *  to be picked up by ADL
                                    +   */
                                    +  void
                                    +  intrusive_ptr_add_ref (ScopePath* pathFrame)
                                    +  {
                                    +    REQUIRE (pathFrame);
                                    +    ++(pathFrame->refcount_);
                                    +  }
                                    +  
                                    +  void
                                    +  intrusive_ptr_release (ScopePath* pathFrame)
                                    +  {
                                    +    REQUIRE (pathFrame);
                                    +    if (0 < pathFrame->refcount_)
                                    +      --(pathFrame->refcount_);
                                    +  }
                                    +
                                    +  
                                    +  
                                       inline size_t
                                       ScopePath::ref_count()  const
                                       {
                                    
                                    From 89aacf385e0f0b9b596ef5f350611698129591c9 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 04:42:50 +0100
                                    Subject: [PATCH 095/377] relocate tests; they belong into namespace session
                                    
                                    ---
                                     .../proc/mobject/{ => session}/placement-scope-test.cpp           | 0
                                     tests/components/proc/mobject/{ => session}/query-focus-test.cpp  | 0
                                     tests/components/proc/mobject/{ => session}/scope-path-test.cpp   | 0
                                     3 files changed, 0 insertions(+), 0 deletions(-)
                                     rename tests/components/proc/mobject/{ => session}/placement-scope-test.cpp (100%)
                                     rename tests/components/proc/mobject/{ => session}/query-focus-test.cpp (100%)
                                     rename tests/components/proc/mobject/{ => session}/scope-path-test.cpp (100%)
                                    
                                    diff --git a/tests/components/proc/mobject/placement-scope-test.cpp b/tests/components/proc/mobject/session/placement-scope-test.cpp
                                    similarity index 100%
                                    rename from tests/components/proc/mobject/placement-scope-test.cpp
                                    rename to tests/components/proc/mobject/session/placement-scope-test.cpp
                                    diff --git a/tests/components/proc/mobject/query-focus-test.cpp b/tests/components/proc/mobject/session/query-focus-test.cpp
                                    similarity index 100%
                                    rename from tests/components/proc/mobject/query-focus-test.cpp
                                    rename to tests/components/proc/mobject/session/query-focus-test.cpp
                                    diff --git a/tests/components/proc/mobject/scope-path-test.cpp b/tests/components/proc/mobject/session/scope-path-test.cpp
                                    similarity index 100%
                                    rename from tests/components/proc/mobject/scope-path-test.cpp
                                    rename to tests/components/proc/mobject/session/scope-path-test.cpp
                                    
                                    From 12dc0e2c2d409b27ad2f81c251bc321af1c160ac Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 07:26:51 +0100
                                    Subject: [PATCH 096/377] add unit test, write documentation. Closes #420
                                    
                                    ---
                                     .../mobject/session/query-focus-stack.hpp     |  70 +++--
                                     src/proc/mobject/session/scope-path.hpp       |   4 +-
                                     tests/43session.tests                         |   4 +
                                     .../session/query-focus-stack-test.cpp        | 244 ++++++++++++++++++
                                     wiki/renderengine.html                        |  12 +-
                                     5 files changed, 309 insertions(+), 25 deletions(-)
                                     create mode 100644 tests/components/proc/mobject/session/query-focus-stack-test.cpp
                                    
                                    diff --git a/src/proc/mobject/session/query-focus-stack.hpp b/src/proc/mobject/session/query-focus-stack.hpp
                                    index 0c6c95413..7bac96683 100644
                                    --- a/src/proc/mobject/session/query-focus-stack.hpp
                                    +++ b/src/proc/mobject/session/query-focus-stack.hpp
                                    @@ -24,17 +24,11 @@
                                     #ifndef MOBJECT_SESSION_QUERY_FOCUS_STACK_H
                                     #define MOBJECT_SESSION_QUERY_FOCUS_STACK_H
                                     
                                    -//#include "proc/mobject/mobject.hpp"
                                    -//#include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/session/scope-path.hpp"
                                     
                                    -//#include 
                                    -//#include 
                                     #include 
                                     #include 
                                     
                                    -//using std::vector;
                                    -//using std::string;
                                     using std::list;
                                     
                                     
                                    @@ -44,7 +38,26 @@ namespace session {
                                       
                                       
                                       /**
                                    -   * TODO type comment
                                    +   * A custom stack holding ScopePath »frames«.
                                    +   * It is utilised by the ScopeLocator to establish the
                                    +   * \em current query focus location. Client code should
                                    +   * access this mechanism through QueryFocus instances 
                                    +   * used as frontend. These QueryFocus objects incorporate
                                    +   * a boost::intrusive_ptr, which stores the ref-count within
                                    +   * the mentioned ScopePath frames located in the stack.
                                    +   * 
                                    +   * \par automatic cleanup of unused frames
                                    +   * 
                                    +   * The stack is aware of this ref-counting mechanism and will --
                                    +   * on each access -- automatically clean up any unused frames starting
                                    +   * from stack top, until encountering the first frame still in use.
                                    +   * This frame, by definition, is the current focus location.
                                    +   * The stack ensures there is always at least one ScopePath frame,
                                    +   * default-creating a new one if necessary.
                                    +   * 
                                    +   * @see query-focus-stack-test.cpp
                                    +   * @see ScopeLocator
                                    +   * @see QueryFocus access point for client code
                                        */
                                       class QueryFocusStack
                                         : boost::noncopyable
                                    @@ -53,41 +66,55 @@ namespace session {
                                           std::list paths_;
                                           
                                         public:
                                    -      QueryFocusStack()
                                    +      QueryFocusStack ()
                                             : paths_()
                                             {
                                               openDefaultFrame();
                                             }
                                           
                                           
                                    -      bool empty()  const;
                                    -      size_t size() const;
                                    +      bool empty ()  const;
                                    +      size_t size () const;
                                           
                                           ScopePath& push (Scope const&);
                                           ScopePath& top  ();
                                           void pop_unused ();
                                    +      void clear ();
                                           
                                           
                                         private:
                                    -      void openDefaultFrame();
                                    +      void openDefaultFrame ();
                                         };
                                    -///////////////////////////TODO currently just fleshing the API
                                       
                                       
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  /* __implementation__ */ 
                                    +  
                                       bool
                                    -  QueryFocusStack::empty()  const
                                    +  QueryFocusStack::empty ()  const
                                       {
                                         return paths_.empty();
                                       }
                                       
                                       
                                       size_t
                                    -  QueryFocusStack::size()  const
                                    +  QueryFocusStack::size ()  const
                                       {
                                         return paths_.size();
                                       }
                                       
                                       
                                    +  void
                                    +  QueryFocusStack::clear ()
                                    +  {
                                    +    paths_.clear();
                                    +  }
                                    +  
                                    +  
                                       /** Open a new path frame, pushing down the current frame.
                                        *  The new frame tries to locate the given start scope
                                        *  and navigates to this position.
                                    @@ -120,7 +147,6 @@ namespace session {
                                           pop_unused();
                                         
                                         ENSURE (!empty());
                                    -    ENSURE (!paths_.back().empty());
                                         return paths_.back();
                                       }
                                       
                                    @@ -130,30 +156,36 @@ namespace session {
                                        *  ScopePath#use_count(). After executing this function
                                        *  the topmost frame is either in use, or a new default
                                        *  frame has been created at the bottom of an empty stack.
                                    -   *  @note EXCEPTON_FREE    ///////TODO prove!
                                    +   *  @note EXCEPTION_FREE    ///////TODO prove!
                                        */
                                       void
                                       QueryFocusStack::pop_unused ()
                                       {
                                    +    if (1 == size() && !paths_.front().isValid())
                                    +      return; // unnecessary to evict a base frame repeatedly
                                    +    
                                         while (size() && (0 == paths_.back().ref_count()))
                                           paths_.pop_back();
                                         
                                         if (0 == size())
                                           openDefaultFrame();
                                         ENSURE (!empty());
                                    -    ENSURE (!paths_.back().empty());
                                       }
                                       
                                       
                                       /** @internal open a default path frame at the bottom
                                        *  of an empty stack, locating to current model root
                                    -   *  @note EXCEPTON_FREE    ///////TODO prove!  
                                    +   *  @note EXCEPTION_FREE    ///////TODO prove!
                                        */
                                       void
                                    -  QueryFocusStack::openDefaultFrame()
                                    +  QueryFocusStack::openDefaultFrame ()
                                       {
                                         REQUIRE (0 == size());
                                    +    
                                         paths_.resize(1);
                                    +    
                                    +    ENSURE (!paths_.front().empty());
                                    +    ENSURE (!paths_.front().isValid()); // i.e. just root scope
                                       }
                                       
                                       
                                    diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp
                                    index 4f985e4a9..9ff0f911e 100644
                                    --- a/src/proc/mobject/session/scope-path.hpp
                                    +++ b/src/proc/mobject/session/scope-path.hpp
                                    @@ -188,14 +188,14 @@ namespace session {
                                       /** management function for boost::intrusive_ptr
                                        *  to be picked up by ADL
                                        */
                                    -  void
                                    +  inline void
                                       intrusive_ptr_add_ref (ScopePath* pathFrame)
                                       {
                                         REQUIRE (pathFrame);
                                         ++(pathFrame->refcount_);
                                       }
                                       
                                    -  void
                                    +  inline void
                                       intrusive_ptr_release (ScopePath* pathFrame)
                                       {
                                         REQUIRE (pathFrame);
                                    diff --git a/tests/43session.tests b/tests/43session.tests
                                    index fd3f0b3db..c9648e33b 100644
                                    --- a/tests/43session.tests
                                    +++ b/tests/43session.tests
                                    @@ -91,6 +91,10 @@ PLANNED "Query focus management" QueryFocus_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 "proc/mobject/session/test-scopes.hpp"
                                    +#include "proc/mobject/session/query-focus-stack.hpp"
                                    +#include "lib/util.hpp"
                                    +
                                    +
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +namespace test    {
                                    +  
                                    +  using util::isnil;
                                    +  using util::isSameObject;
                                    +  using lumiera::error::LUMIERA_ERROR_INVALID;
                                    +  
                                    +  
                                    +  /***************************************************************************
                                    +   * @test behaviour of the stack of focus location paths.
                                    +   *       Basically this is just a stack, but has a somewhat unusual behaviour
                                    +   *       on pop(), as it considers the (intrusive) ref-count maintained within
                                    +   *       the stack frames (ScopePath instances) and cleans up unused frames.
                                    +   *       Similar to the ScopePath_test, we use a pseudo-session to create
                                    +   *       some path frames to play with.
                                    +   *       
                                    +   * @see  mobject::session::QueryFocusStack
                                    +   * @see  mobject::session::ScopePath
                                    +   */
                                    +  class QueryFocusStack_test : public Test
                                    +    {
                                    +      
                                    +      virtual void
                                    +      run (Arg) 
                                    +        {
                                    +          // Prepare an (test)Index backing the PlacementRefs
                                    +          PPIdx index = build_testScopes();
                                    +          
                                    +          createStack();
                                    +          usePushedFrame();
                                    +          automaticFrameHandling();
                                    +          verify_errorHandling();
                                    +          clear();
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      createStack ()
                                    +        {
                                    +          QueryFocusStack stack;
                                    +          
                                    +          ASSERT (!isnil (stack));
                                    +          ASSERT (!isnil (stack.top()));
                                    +          ASSERT (stack.top().getLeaf().isRoot());
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      usePushedFrame ()
                                    +        {
                                    +          QueryFocusStack stack;
                                    +          PMO& startPoint = retrieve_startElm();
                                    +          
                                    +          ScopePath& firstFrame = stack.top();   // remember for later
                                    +          intrusive_ptr_add_ref (&firstFrame);
                                    +          stack.top().navigate(startPoint);
                                    +          stack.top().moveUp();
                                    +          ASSERT (Scope(startPoint).getParent() == stack.top().getLeaf());
                                    +          ASSERT (1 == stack.size());
                                    +          
                                    +          // now open a second path frame, pushing aside the initial one
                                    +          ScopePath& secondFrame = stack.push(startPoint);
                                    +          intrusive_ptr_add_ref (&secondFrame);
                                    +          ASSERT (2 == stack.size());
                                    +          ASSERT (secondFrame == stack.top());
                                    +          ASSERT (secondFrame.getLeaf() == startPoint);
                                    +          ASSERT (secondFrame.getLeaf() != firstFrame.getLeaf());
                                    +          
                                    +          // can still reach and manipulate the ref-count of the first frame
                                    +          intrusive_ptr_add_ref (&firstFrame);
                                    +          ASSERT (2 == firstFrame.ref_count());
                                    +          ASSERT (1 == secondFrame.ref_count());
                                    +          
                                    +          // can use/navigate the stack top frame
                                    +          stack.top().goRoot();
                                    +          ASSERT (isnil (stack.top())); // now indeed at root == empty path
                                    +          ASSERT (secondFrame.getLeaf().isRoot());
                                    +          ASSERT (secondFrame == stack.top());
                                    +          
                                    +          // now drop back to the first frame:
                                    +          ASSERT (1 == secondFrame.ref_count());
                                    +          intrusive_ptr_release (&secondFrame);
                                    +          ASSERT (0 == secondFrame.ref_count());
                                    +          stack.pop_unused();
                                    +          ASSERT (1 == stack.size());
                                    +          ASSERT (firstFrame == stack.top());
                                    +          
                                    +          // ...still pointing at the previous location
                                    +          ASSERT (Scope(startPoint).getParent() == stack.top().getLeaf());
                                    +          ASSERT (2 == firstFrame.ref_count());
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      automaticFrameHandling ()
                                    +        {
                                    +          QueryFocusStack stack;
                                    +          PMO& startPoint = retrieve_startElm();
                                    +          
                                    +          ScopePath& firstFrame = stack.top();   // remember for later
                                    +          stack.top().navigate(startPoint);
                                    +          ASSERT (1 == stack.size());
                                    +          intrusive_ptr_add_ref (&firstFrame);
                                    +          
                                    +          // now open two new frames, but don't add ref-counts on them
                                    +          ScopePath& secondFrame = stack.push(startPoint);
                                    +          ScopePath& thirdFrame  = stack.push(startPoint);
                                    +          ASSERT (3 == stack.size());
                                    +          ASSERT (1 == firstFrame.ref_count());
                                    +          ASSERT (0 == secondFrame.ref_count());
                                    +          ASSERT (0 == thirdFrame.ref_count());
                                    +          
                                    +          // any ref to top detects the non-referred-to state (by ref count==0)
                                    +          // and will automatically pop and clean up...
                                    +          ScopePath& newTop = stack.top();
                                    +          ASSERT (1 == stack.size());
                                    +          ASSERT (firstFrame == stack.top());
                                    +          ASSERT (isSameObject(newTop, firstFrame));
                                    +          ASSERT (stack.top().getLeaf() == startPoint);
                                    +          
                                    +          // second exercise: a pop_unused may even completely empty the stack
                                    +          ScopePath& anotherFrame = stack.push(startPoint);
                                    +          ASSERT (0 == anotherFrame.ref_count());
                                    +          ASSERT (1 == firstFrame.ref_count());
                                    +          intrusive_ptr_release (&anotherFrame);
                                    +          ASSERT (0 == firstFrame.ref_count());
                                    +          ASSERT (firstFrame.getLeaf() == startPoint);
                                    +          
                                    +          stack.pop_unused();
                                    +          ASSERT (1 == stack.size());
                                    +                          // Note: don't use previously taken pointers
                                    +                          //       or references anymore, after the stack
                                    +                          //       triggered a cleanup!
                                    +          ScopePath& anotherFrame2 = stack.top();
                                    +          ASSERT (0 == anotherFrame2.ref_count());
                                    +          ASSERT (anotherFrame2.getLeaf().isRoot());
                                    +          anotherFrame2.navigate(startPoint);
                                    +          ASSERT (anotherFrame2.getLeaf() == startPoint);
                                    +          
                                    +          stack.top();
                                    +          ASSERT (1 == stack.size());
                                    +          ASSERT (stack.top().getLeaf().isRoot());
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      verify_errorHandling ()
                                    +        {
                                    +          QueryFocusStack stack;
                                    +          PMO& startPoint = retrieve_startElm();
                                    +          
                                    +          ScopePath& firstFrame = stack.top();   // remember for later
                                    +          stack.top().navigate(startPoint);
                                    +          ASSERT (1 == stack.size());
                                    +          intrusive_ptr_add_ref (&firstFrame);
                                    +          
                                    +          ScopePath beforeInvalidNavigation = firstFrame;
                                    +          Scope unrelatedScope (TestPlacement<> (*new DummyMO));
                                    +          
                                    +          // try to navigate to an invalid place
                                    +          VERIFY_ERROR (INVALID, stack.top().navigate (unrelatedScope) );
                                    +          ASSERT (1 == stack.size());
                                    +          ASSERT (1 == firstFrame.ref_count());
                                    +          ASSERT (stack.top().getLeaf() == startPoint);
                                    +          
                                    +          // try to push an invalid place
                                    +          VERIFY_ERROR (INVALID, stack.push (unrelatedScope) );
                                    +          ASSERT (1 == stack.size());
                                    +          ASSERT (1 == firstFrame.ref_count());
                                    +          ASSERT (stack.top().getLeaf() == startPoint);
                                    +        }
                                    +      
                                    +      
                                    +      void
                                    +      clear ()
                                    +        {
                                    +          QueryFocusStack stack;
                                    +          intrusive_ptr_add_ref (&stack.top());
                                    +          stack.top().moveUp();
                                    +          ASSERT (stack.top().empty());
                                    +          
                                    +          PMO& startPoint = retrieve_startElm();
                                    +          intrusive_ptr_add_ref ( & stack.push(startPoint) );
                                    +          intrusive_ptr_add_ref ( & stack.push(startPoint) );
                                    +          intrusive_ptr_add_ref ( & stack.push(startPoint) );
                                    +          intrusive_ptr_add_ref ( & stack.push(startPoint) );
                                    +          intrusive_ptr_add_ref ( & stack.push(startPoint) );
                                    +          intrusive_ptr_add_ref ( & stack.push(startPoint) );
                                    +          intrusive_ptr_add_ref ( & stack.push(startPoint) );
                                    +          intrusive_ptr_add_ref ( & stack.push(startPoint) );
                                    +          intrusive_ptr_add_ref ( & stack.push(startPoint) );
                                    +          ASSERT (10 == stack.size());
                                    +          stack.pop_unused();
                                    +          ASSERT (10 == stack.size());
                                    +          ASSERT (1 == stack.top().ref_count());
                                    +          
                                    +          stack.clear();
                                    +          ASSERT (1 == stack.size());
                                    +          ASSERT (!stack.top().empty());
                                    +          ASSERT (stack.top().getLeaf().isRoot());
                                    +          ASSERT (0 == stack.top().ref_count());
                                    +        }
                                    +      
                                    +    };
                                    +  
                                    +  
                                    +  /** Register this test class... */
                                    +  LAUNCHER (QueryFocusStack_test, "unit session");
                                    +  
                                    +  
                                    +}}} // namespace mobject::session::test
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 584751a0c..2bcd4ccdb 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -3492,13 +3492,17 @@ The stack of scopes must not be confused with the ScopePath. Each single frame o
                                     The full implementation of this scope navigation is tricky, especially when it comes to determining the relation of two positions. It should be ''postponed'' and replaced by a ''dummy'' (no-op) implementation for the first integration round.
                                     
                                    -
                                    -
                                    What is the ''current'' QueryFocus? There is a state-dependent part involved, inasmuch the effective ScopePath depends on how the invoking client has navigated the //current location// down into the HighLevelModel structures. Especially, when a VirtualClip is involved, there can be discrepancies between the paths resulting when descending down through different paths. (See &rarr; BindingScopeProblem).
                                    +
                                    +
                                    The ScopeLocator uses a special stack of ScopePath &raquo;frames&laquo; to maintain the //current focus.//
                                    +What is the ''current'' QueryFocus and why is it necessary? There is a state-dependent part involved, inasmuch the effective ScopePath depends on how the invoking client has navigated the //current location// down into the HighLevelModel structures. Especially, when a VirtualClip is involved, there can be discrepancies between the paths resulting when descending down through different paths. (See &rarr; BindingScopeProblem).
                                     
                                    -Thus, doing something with the current location, and especially descending or querying adjacent scopes can modify this current path state. Thus we need a means of invoking a query in a way not interfering with the current path state, otherwise we wouldn't be able to provide side-effect free specific query operations.
                                    +Thus, doing something with the current location, and especially descending or querying adjacent scopes can modify this current path state. Thus we need a means of invoking a query in a way not interfering with the current path state, otherwise we wouldn't be able to provide side-effect free query operations accessible on individual objects within the model.
                                     
                                     !maintaining the current QueryFocus
                                    -As long as client code is just interested to use the current query location, we can provide a handle referring to it. But when a query needs to be run without side effect on the current location, we //push//&nbsp; it aside and start using a new QueryFocus on top, which starts out as a clone copy of the current QueryFocus. Client code again gets a handle (smart-ptr) to this location, and additionally may access the new "current location". When all references are out of scope and gone, we'll drop back to the focus put aside previously.
                                    +As long as client code is just interested to use the current query location, we can provide a handle referring to it. But when a query needs to be run without side effect on the current location, we //push//&nbsp; it aside and start using a new QueryFocus on top, which starts out at a new initial location. Client code again gets a handle (smart-ptr) to this location, and additionally may access the new //current location.// When all references are out of scope and gone, we'll drop back to the focus put aside previously.
                                    +
                                    +!implementation of ref-counting and clean-up
                                    +Actually, client code should use QueryFocus instances as frontend to access this &raquo;current focus&laquo;. Each ~QueryFocus instance incorporates a smart-ptr. But as in this case we're not managing objects allocated somewhere, we use an {{{boost::intrusive_ptr}}} and maintain the ref-count immediately within the target objects to be managed. These target objects are ScopePath instances and are living within the QueryFocusStack, which in turn in managed by the ScopeLocator singleton (see the UML diagram &rarr;[[here|QueryFocus]]). We use an (hand-written) stack implementation to ensure the memory locations of these ScopePath &raquo;frames&laquo; remain valid (and also to help with providing strong exception guarantees). The stack is aware of these ref-count and takes it into account on performing the {{{pop_unused()}}} operation: any unused frame on top will be evicted, stopping at the first frame still in use (which may be even just the old top). This cleanup also happens automatically when accessing the current top, re-initialising an potentially empty stack with a default-constructed new frame if necessary. This way, just accessing the stack top always yields the ''current focus location'', which thereby is //defined as the most recently used focus location still referred.//
                                     
                                     !concurrency
                                     This concept deliberately ignores parallelism. But, as the current path state is already encapsulated (and ref-counting is in place), the only central access point is to reach the current scope. Instead of using a plain-flat singleton here, this access can easily be routed through thread local storage.
                                    
                                    From 4082ff919eb9f05c01d444c079ee32b20c9d3c3c Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 10:32:08 +0100
                                    Subject: [PATCH 097/377] implemented connection between QueryFocus und current
                                     ScopePath
                                    
                                    ---
                                     src/proc/mobject/session/query-focus.cpp   | 100 ++++++++++++++-------
                                     src/proc/mobject/session/query-focus.hpp   |  42 ++++++---
                                     src/proc/mobject/session/scope-locator.hpp |   1 +
                                     src/proc/mobject/session/scope-path.hpp    |   1 +
                                     src/proc/mobject/session/scope.cpp         |  17 +++-
                                     src/proc/mobject/session/scope.hpp         |   3 +
                                     6 files changed, 120 insertions(+), 44 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/query-focus.cpp b/src/proc/mobject/session/query-focus.cpp
                                    index 9ae9c9d9f..b3ee76a7f 100644
                                    --- a/src/proc/mobject/session/query-focus.cpp
                                    +++ b/src/proc/mobject/session/query-focus.cpp
                                    @@ -22,80 +22,118 @@
                                     
                                     
                                     #include "proc/mobject/session/query-focus.hpp"
                                    -//#include "proc/mobject/session/track.hpp"
                                    -//#include "proc/mobject/placement.hpp"
                                    -//#include "proc/mobject/session/mobjectfactory.hpp"
                                    -//#include "proc/asset/track.hpp"
                                    +
                                     
                                     namespace mobject {
                                     namespace session {
                                       
                                       
                                       
                                    -  /** TODO??? */
                                    +  /** 
                                    +   * create a new QueryFocus (handle)
                                    +   * linked to the current focus for discovery queries.
                                    +   * The existence of this QueryFocus instance keeps this
                                    +   * current focus alive, but multiple instances share a
                                    +   * common focus location and may change this location.
                                    +   * 
                                    +   */
                                       QueryFocus::QueryFocus()
                                    -  { }
                                    +    : focus_( & currPath())
                                    +    { }
                                       
                                       
                                    -  /** */
                                    +  /**
                                    +   * @internal build a new QueryFocus
                                    +   * as attached to an existing path.
                                    +   */
                                    +  QueryFocus::QueryFocus(ScopePath& path_to_attach)
                                    +    : focus_( &path_to_attach)
                                    +    { }
                                    +  
                                    +  
                                    +  /** @internal access the path designating
                                    +   *  the current focus location */
                                       ScopePath&
                                       QueryFocus::currPath()
                                       {
                                    -    UNIMPLEMENTED ("dereference and access the current scope path");
                                    +    return ScopeLocator::instance().currPath();
                                       }
                                    -
                                    -  ScopePath const&
                                    -  QueryFocus::currPath()  const
                                    -  {
                                    -    UNIMPLEMENTED ("dereference and access the current scope path");
                                    -  }
                                    -
                                       
                                    -  /** discard any state and clear
                                    -      the current focus path */
                                    +  
                                    +  /** discard any state and navigate
                                    +   *  current focus path to model root
                                    +   */
                                       QueryFocus&
                                       QueryFocus::reset ()
                                       {
                                    -    scopes_.clear();
                                    +    REQUIRE (focus_);
                                    +    focus_->clear();
                                         return *this;
                                       }
                                       
                                       
                                    +  
                                    +  
                                    +  
                                    +  namespace {// error check shortcut....
                                    +    
                                    +    using lumiera::error::Invalid;
                                    +    
                                    +    void
                                    +    ___check_validTaget (Scope const& target)
                                    +    {
                                    +      if (!target.isValid())
                                    +        throw Invalid ("Invalid target location for QueryFocus"
                                    +                      , LUMIERA_ERROR_INVALID_SCOPE);
                                    +    }
                                    +  }//(End) shortcut
                                    +  
                                    +  
                                    +  
                                       /** attach this QueryFocus to a container-like scope,
                                    -      causing it to \em navigate, changing the
                                    -      current ScopePath as a side-effect 
                                    -  */
                                    +   *  causing it to \em navigate, changing the
                                    +   *  current ScopePath as a side-effect
                                    +   *  @throw error::Invalid if the given container is
                                    +   *         invalid or can't be located within the model 
                                    +   */
                                       QueryFocus&
                                       QueryFocus::attach (Scope const& container)
                                       {
                                    -    UNIMPLEMENTED ("navigate this focus to attach to the given container scop");
                                    +    ___check_validTaget (container);
                                    +    
                                    +    REQUIRE (focus_);
                                    +    focus_->navigate (container);
                                         return *this;
                                       }
                                       
                                       
                                       /** push the "current QueryFocus" aside and open a new focus frame.
                                    -      This new QueryFocus will act as "current" until going out of scope
                                    +   *  This new QueryFocus will act as "current" until going out of scope
                                    +   *  @throw error::Invalid in case of invalid or unlocatable target scope
                                        */
                                       QueryFocus
                                       QueryFocus::push (Scope const& otherContainer)
                                       {
                                    -    UNIMPLEMENTED ("push current, open a new QueryFocus frame");
                                    -    QueryFocus newFocus; // = do push and open new frame
                                    +    ___check_validTaget (otherContainer);
                                    +    
                                    +    QueryFocus newFocus (ScopeLocator::instance().pushPath());
                                         newFocus.attach (otherContainer);
                                         return newFocus;
                                       }
                                       
                                       
                                       /** cease to use \em this specific reference to the current frame.
                                    -      This operation immediately tries to re-attach to what is "current"
                                    -      and readjusts the internal handle. But when the previously released
                                    -      reference was the last one, releasing it will cause the QueryFocusStack
                                    -      to pop, in which case we'll re-attach to the now uncovered previous stack top.
                                    -  */
                                    +   *  This operation immediately tries to re-attach to what is "current"
                                    +   *  and readjusts the internal handle. But when the previously released
                                    +   *  reference was the last one, releasing it will cause the QueryFocusStack
                                    +   *  to pop, in which case we'll re-attach to the now uncovered previous stack top.
                                    +   */
                                       QueryFocus&
                                       QueryFocus::pop()
                                       {
                                    -    UNIMPLEMENTED ("pop, give up one reference, maybe drop stack top");
                                    +    focus_ = 0;
                                    +    focus_ = & currPath();
                                    +    
                                         return *this;
                                       }
                                       
                                    diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp
                                    index 7fd5939c2..712284da2 100644
                                    --- a/src/proc/mobject/session/query-focus.hpp
                                    +++ b/src/proc/mobject/session/query-focus.hpp
                                    @@ -29,6 +29,7 @@
                                     #include "proc/mobject/session/scope-path.hpp"
                                     #include "proc/mobject/session/scope-locator.hpp"
                                     
                                    +#include 
                                     //#include 
                                     //#include 
                                     
                                    @@ -45,8 +46,7 @@ namespace session {
                                        */
                                       class QueryFocus
                                         {
                                    -      ScopePath scopes_;  /////////////////////////////////////////////////////////////////TODO use intrusive pointer
                                    -      /////////////////////////////////////////////////////////////////////////////////////TODO how to integrate the ref-counting handle?
                                    +      boost::intrusive_ptr focus_;
                                           
                                         public:
                                           QueryFocus();
                                    @@ -61,26 +61,44 @@ namespace session {
                                           
                                           template
                                           typename ScopeQuery::iterator
                                    -      query()  const
                                    -        {
                                    -          ScopeLocator::instance().query (*this);
                                    -        }
                                    +      query()  const;
                                           
                                           template
                                           typename ScopeQuery::iterator
                                    -      explore()  const
                                    -        {
                                    -          ScopeLocator::instance().explore (*this);
                                    -        }
                                    +      explore()  const;
                                           
                                         private:
                                    -      ScopePath      & currPath();
                                    -      ScopePath const& currPath()  const;
                                    +      QueryFocus (ScopePath&);
                                    +      
                                    +      static ScopePath& currPath();
                                         };
                                     ///////////////////////////TODO currently just fleshing the API
                                     
                                       
                                    +
                                       
                                    +  /** discover depth-first any matching object
                                    +   *  within \em current focus. Resolution is 
                                    +   *  delegate to the \em current session */
                                    +  template
                                    +  typename ScopeQuery::iterator
                                    +  QueryFocus::query()  const
                                    +  {
                                    +    ScopeLocator::instance().query (*this);
                                    +  }
                                    +      
                                    +  
                                    +  /** discover any matching object contained 
                                    +   *  as immediate Child within \em current focus. 
                                    +   *  Resolution through \em current session */
                                    +  template
                                    +  typename ScopeQuery::iterator
                                    +  QueryFocus::explore()  const
                                    +  {
                                    +    ScopeLocator::instance().explore (*this);
                                    +  }
                                    +      
                                    +
                                       
                                     }} // namespace mobject::session
                                     #endif
                                    diff --git a/src/proc/mobject/session/scope-locator.hpp b/src/proc/mobject/session/scope-locator.hpp
                                    index aa4d03633..c6c9aba5d 100644
                                    --- a/src/proc/mobject/session/scope-locator.hpp
                                    +++ b/src/proc/mobject/session/scope-locator.hpp
                                    @@ -64,6 +64,7 @@ namespace session {
                                           static lib::Singleton instance;
                                           
                                           ScopePath& currPath();
                                    +      ScopePath& pushPath();
                                           
                                           template
                                           typename ScopeQuery::iterator
                                    diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp
                                    index 9ff0f911e..8087b89d1 100644
                                    --- a/src/proc/mobject/session/scope-path.hpp
                                    +++ b/src/proc/mobject/session/scope-path.hpp
                                    @@ -86,6 +86,7 @@
                                     #include "proc/mobject/session/scope.hpp"
                                     #include "lib/bool-checkable.hpp"
                                     #include "lib/iter-adapter.hpp"
                                    +#include "lib/error.hpp"
                                     
                                     #include 
                                     
                                    diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp
                                    index f8a604115..cf61747f4 100644
                                    --- a/src/proc/mobject/session/scope.cpp
                                    +++ b/src/proc/mobject/session/scope.cpp
                                    @@ -35,6 +35,9 @@ namespace mobject {
                                     namespace session {
                                       
                                       
                                    +  LUMIERA_ERROR_DEFINE (INVALID_SCOPE, "Placement scope invalid an not locatable within model");
                                    +
                                    +  
                                       
                                       /** TODO??? */
                                       Scope::Scope (PlacementMO const& constitutingPlacement)
                                    @@ -104,10 +107,22 @@ namespace session {
                                       ScopePath&
                                       ScopeLocator::currPath()
                                       {
                                    -    UNIMPLEMENTED ("how to access and handle the current focus");
                                    +    return focusStack_->top();
                                       }
                                       
                                       
                                    +  /** push aside the current focus location
                                    +   *  and open a new ScopePath frame, to serve
                                    +   *  as \em current location until released 
                                    +   */
                                    +  ScopePath&
                                    +  ScopeLocator::pushPath()
                                    +  {
                                    +    return focusStack_->push (SessionServiceExploreScope::getScopeRoot());
                                    +  }
                                    +  
                                    +  
                                    +  
                                       /** discover the enclosing scope of a given Placement */
                                       Scope const&
                                       Scope::containing (PlacementMO const& aPlacement)
                                    diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp
                                    index 592002b61..a51c0619b 100644
                                    --- a/src/proc/mobject/session/scope.hpp
                                    +++ b/src/proc/mobject/session/scope.hpp
                                    @@ -29,6 +29,7 @@
                                     #include "proc/mobject/placement-ref.hpp"
                                     //#include "proc/mobject/session/query-resolver.hpp"  ///////////TODO: really?
                                     #include "lib/iter-adapter.hpp"
                                    +#include "lib/error.hpp"
                                     //#include "lib/singleton.hpp"
                                     
                                     #include 
                                    @@ -45,6 +46,8 @@ namespace session {
                                       
                                       using lib::IterAdapter;
                                       
                                    +  LUMIERA_ERROR_DECLARE (INVALID_SCOPE);  ///< Placement scope invalid an not locatable within model
                                    +  
                                       
                                     
                                       /**
                                    
                                    From 0186343909e6312e74806ae687ddca3f90beccee Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 11:13:49 +0100
                                    Subject: [PATCH 098/377] finished implementation of QueryFocus (frontend
                                     handle)
                                    
                                    ---
                                     src/proc/asset/db.hpp                         |  2 +-
                                     src/proc/mobject/session/query-focus.hpp      | 98 ++++++++++++++-----
                                     .../proc/mobject/session/query-focus-test.cpp |  4 -
                                     3 files changed, 75 insertions(+), 29 deletions(-)
                                    
                                    diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp
                                    index f371b5efc..1676c96da 100644
                                    --- a/src/proc/asset/db.hpp
                                    +++ b/src/proc/asset/db.hpp
                                    @@ -162,7 +162,7 @@ namespace asset {
                                               static const PAsset NULLP;
                                               IdHashtable::const_iterator i = table.find (hash);
                                               if (i == table.end())
                                    -            return NULLP;  // empty ptr signaling "not found"
                                    +            return NULLP;  // empty ptr signalling "not found"
                                               else
                                                 return i->second;
                                             }
                                    diff --git a/src/proc/mobject/session/query-focus.hpp b/src/proc/mobject/session/query-focus.hpp
                                    index 712284da2..4a211d8ee 100644
                                    --- a/src/proc/mobject/session/query-focus.hpp
                                    +++ b/src/proc/mobject/session/query-focus.hpp
                                    @@ -24,17 +24,10 @@
                                     #ifndef MOBJECT_SESSION_QUERY_FOCUS_H
                                     #define MOBJECT_SESSION_QUERY_FOCUS_H
                                     
                                    -//#include "proc/mobject/mobject.hpp"
                                    -//#include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/session/scope-path.hpp"
                                     #include "proc/mobject/session/scope-locator.hpp"
                                     
                                     #include 
                                    -//#include 
                                    -//#include 
                                    -
                                    -//using std::vector;
                                    -//using std::string;
                                     
                                     namespace mobject {
                                     namespace session {
                                    @@ -42,7 +35,45 @@ namespace session {
                                       
                                       
                                       /**
                                    -   * TODO type comment
                                    +   * Current focus location to use as point-of reference
                                    +   * for contents and location discovery queries. This is the
                                    +   * frontend to be used by client code: a smart-handle, internally
                                    +   * linked through the ScopeLocaor singleton to a stack of current
                                    +   * focus path locations. The intention is for this current location
                                    +   * to follow the ongoing query/discovery operations mostly automatically.
                                    +   * 
                                    +   * \par usage
                                    +   * 
                                    +   * A QueryFocus (frontend handle) can be default constructed, in which
                                    +   * case it will automatically connect to what is currently the focus
                                    +   * location for any further queries. Here, the current focus location
                                    +   * is defined as the most recently used location which is still referred
                                    +   * by some QueryFocus handle.
                                    +   * 
                                    +   * Alternatively, through the static factory function #push(), a new
                                    +   * focus location may be opened, thereby pushing the currently used
                                    +   * focus location aside. This new focus location will remain the
                                    +   * current focus, while any handles referring to it is still in use.
                                    +   * 
                                    +   * Using an existing QueryFocus (handle), the current focus may be 
                                    +   * shifted to another scope within the current session.
                                    +   * 
                                    +   * The templated query functions allow to issue specifically typed
                                    +   * queries to retrieve all children (immediately contained in a
                                    +   * given scope), or do discover depth-first any content within
                                    +   * this scope. The result set of these queries will be filtered
                                    +   * to yield only placements compatible to the specified kind of
                                    +   * MObject. E.g, you may query all Clip objects within a given Track.
                                    +   * 
                                    +   * The implementation of these query operations is backed by the
                                    +   * PlacementIndex in the current session. The link to the session
                                    +   * is established the moment these query functions are invoked.
                                    +   * The returned iterator (Lumiera Forward Iterator) contains a
                                    +   * smart-ptr to keep the hidden result set alive. The results
                                    +   * are delivered without any defined order (implementation is
                                    +   * hashtable based)
                                    +   * 
                                    +   * @see query-focus-test.cpp
                                        */
                                       class QueryFocus
                                         {
                                    @@ -51,13 +82,14 @@ namespace session {
                                         public:
                                           QueryFocus();
                                           
                                    -      QueryFocus& reset ();
                                    -      QueryFocus& attach (Scope const&);
                                    -      static QueryFocus push (Scope const&);
                                    -      QueryFocus& pop();
                                    +      ScopePath currentPath()  const;
                                    +      operator Scope()         const;
                                    +      
                                    +      QueryFocus&     attach (Scope const&);
                                    +      static QueryFocus push (Scope const&);
                                    +      QueryFocus& reset ();
                                    +      QueryFocus& pop ();
                                           
                                    -      operator Scope()        const { return currPath().getLeaf(); }      
                                    -      ScopePath currentPath() const { return currPath(); }       ///< @note returns a copy
                                           
                                           template
                                           typename ScopeQuery::iterator
                                    @@ -67,18 +99,36 @@ namespace session {
                                           typename ScopeQuery::iterator
                                           explore()  const;
                                           
                                    +      
                                         private:
                                           QueryFocus (ScopePath&);
                                    -      
                                           static ScopePath& currPath();
                                         };
                                    -///////////////////////////TODO currently just fleshing the API
                                    -
                                       
                                    -
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  
                                    +  /** allowing direct conversion to Scope.
                                    +   *  Implemented by copying the scope at
                                    +   *  leaf position of the current focus path
                                    +   */
                                    +  QueryFocus::operator Scope() const
                                    +  {
                                    +    return currPath().getLeaf();
                                    +  }
                                    +  
                                    +  /**@note returning a copy */
                                    +  ScopePath
                                    +  QueryFocus::currentPath()  const
                                    +  {
                                    +    return currPath();
                                    +  }
                                    +  
                                       
                                       /** discover depth-first any matching object
                                    -   *  within \em current focus. Resolution is 
                                    +   *  within \em current focus. Resolution is
                                        *  delegate to the \em current session */
                                       template
                                       typename ScopeQuery::iterator
                                    @@ -86,10 +136,10 @@ namespace session {
                                       {
                                         ScopeLocator::instance().query (*this);
                                       }
                                    -      
                                       
                                    -  /** discover any matching object contained 
                                    -   *  as immediate Child within \em current focus. 
                                    +  
                                    +  /** discover any matching object contained
                                    +   *  as immediate Child within \em current focus.
                                        *  Resolution through \em current session */
                                       template
                                       typename ScopeQuery::iterator
                                    @@ -97,8 +147,8 @@ namespace session {
                                       {
                                         ScopeLocator::instance().explore (*this);
                                       }
                                    -      
                                    -
                                    +  
                                    +  
                                       
                                     }} // namespace mobject::session
                                     #endif
                                    diff --git a/tests/components/proc/mobject/session/query-focus-test.cpp b/tests/components/proc/mobject/session/query-focus-test.cpp
                                    index 4d9bb719e..93b3f0a04 100644
                                    --- a/tests/components/proc/mobject/session/query-focus-test.cpp
                                    +++ b/tests/components/proc/mobject/session/query-focus-test.cpp
                                    @@ -66,11 +66,8 @@ namespace test    {
                                               PPIdx index = build_testScopes();
                                               PMO& root = index->getRoot();
                                               
                                    -          UNIMPLEMENTED ("unit test to cover query focus management");
                                    -          
                                               QueryFocus theFocus;
                                               theFocus.reset();
                                    -#ifdef false  ////////////////////////////////////////////////////////////////////////////////TICKET 384
                                               ASSERT (Scope(root) == Scope(theFocus));
                                               
                                               checkNavigation (theFocus);
                                    @@ -81,7 +78,6 @@ namespace test    {
                                               QueryFocus currentFocus;
                                               ASSERT (scopePosition == Scope(currentFocus));
                                               ASSERT (currentFocus == theFocus);
                                    -#endif          
                                             }
                                           
                                           
                                    
                                    From 60fad5296181f3865d7bd8b40c6ed61325a4e9cb Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sun, 22 Nov 2009 18:33:34 +0100
                                    Subject: [PATCH 099/377] Advice concept: write down the basic colaboration
                                    
                                    ---
                                     wiki/renderengine.html | 9 ++++++++-
                                     1 file changed, 8 insertions(+), 1 deletion(-)
                                    
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 2bcd4ccdb..3c99dcc38 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 &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,14 @@ Expecting Advice and giving Advice &mdash; this collaboration ranges somewhe
                                     !!Collaborators
                                     * the ''advised'' entity 
                                     * the ''advisor''
                                    +* ''point of advice''
                                     * ''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'' &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.
                                    +
                                    +!!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. 
                                     
                                    From 4bac65df72218e0abe2b0b92480e8c7961c63501 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 26 Nov 2009 10:13:32 -0500 Subject: [PATCH 100/377] copied test.sh from nobug 1147947 --- tests/test.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/test.sh b/tests/test.sh index 89de9ae54..951d2fcea 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -30,7 +30,6 @@ NOBUG_LOGREGEX='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: \(TRACE\|INFO\|NOTICE\|WARNI arg0="$0" srcdir="$(dirname "$arg0")" -vgsuppression_mangle='/^\(\(==\)\|\(\*\*\)[0-9]*\(==\)\|\(\*\*\)\)\|\(\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: ECHO:\)/d;' ulimit -S -t 5 -v 524288 valgrind="" @@ -45,10 +44,10 @@ else if [[ -x ".libs/vgsuppression" ]]; then ./libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes -q --gen-suppressions=all vgsuppression 2>&1 \ - | sed -e "$vgsuppression_mangle" >vgsuppression.supp + | awk '/^{/ {i = 1;} /^}/ {i = 0; print $0;} {if (i == 1) print $0;}' >vgsuppression.supp else valgrind --leak-check=yes --show-reachable=yes -q --gen-suppressions=all ./vgsuppression 2>&1 \ - | sed -e "$vgsuppression_mangle" >vgsuppression.supp + | awk '/^{/ {i = 1;} /^}/ {i = 0; print $0;} {if (i == 1) print $0;}' >vgsuppression.supp fi fi valgrind="$(which valgrind) --leak-check=yes --show-reachable=no --suppressions=vgsuppression.supp -q $VALGRINDFLAGS" @@ -120,6 +119,11 @@ function TEST() rm -f ,expect_stderr expect_return=0 + local valgrind="$valgrind" + if [ "$VALGRINDFLAGS" = 'DISABLE' ]; then + valgrind= + fi + while read -r line; do cmd="${line%%:*}" arg="${line#*:}" @@ -185,7 +189,7 @@ function TEST() if declare -F | grep $TESTBIN >&/dev/null; then CALL= elif test -x $TESTBIN; then - CALL="env $TESTBIN_PREFIX" + CALL="env $TESTBIN_PREFIX $valgrind" else CALL='-' echo -n >,stdout @@ -302,9 +306,9 @@ function TESTING() echo -e "\n#### $1" >>,testlog if [[ -x ".libs/$2" ]]; then - TESTBIN_PREFIX="./libtool --mode=execute $valgrind" + TESTBIN_PREFIX="./libtool --mode=execute" else - TESTBIN_PREFIX="$valgrind" + TESTBIN_PREFIX= fi TESTBIN="$2" } From 00eb4eda46a6bfde81e69c985d2269b4e513f9e5 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sun, 22 Nov 2009 19:55:08 -0500 Subject: [PATCH 101/377] partial code skeleton --- src/backend/Makefile.am | 2 + src/backend/threadpool.c | 243 ++++++++++++++++++++++++++++++++ src/backend/threadpool.h | 109 ++++++++++++++ src/backend/threads.c | 38 ++++- src/backend/threads.h | 37 ++++- tests/50threadpool.tests | 5 + tests/backend/test-threadpool.c | 53 +++++++ tests/library/test-threadpool.c | 53 +++++++ 8 files changed, 535 insertions(+), 5 deletions(-) create mode 100644 src/backend/threadpool.c create mode 100644 src/backend/threadpool.h create mode 100644 tests/50threadpool.tests create mode 100644 tests/backend/test-threadpool.c create mode 100644 tests/library/test-threadpool.c diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 5729d910b..a1f85788c 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -26,6 +26,7 @@ liblumierabackend_la_SOURCES = \ $(liblumierabackend_la_srcdir)/mediaaccessfacade.cpp \ $(liblumierabackend_la_srcdir)/backend.c \ $(liblumierabackend_la_srcdir)/threads.c \ + $(liblumierabackend_la_srcdir)/threadpool.c \ $(liblumierabackend_la_srcdir)/file.c \ $(liblumierabackend_la_srcdir)/filehandle.c \ $(liblumierabackend_la_srcdir)/filedescriptor.c \ @@ -41,6 +42,7 @@ liblumierabackend_la_SOURCES = \ noinst_HEADERS += \ $(liblumierabackend_la_srcdir)/backend.h \ $(liblumierabackend_la_srcdir)/threads.h \ + $(liblumierabackend_la_srcdir)/threadpool.h \ $(liblumierabackend_la_srcdir)/file.h \ $(liblumierabackend_la_srcdir)/filehandle.h \ $(liblumierabackend_la_srcdir)/filedescriptor.h \ diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c new file mode 100644 index 000000000..27729895b --- /dev/null +++ b/src/backend/threadpool.c @@ -0,0 +1,243 @@ +/* + threadpool.c - Manage pools of threads + + Copyright (C) Lumiera.org + 2009, Michael Ploujnikov + + 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. +*/ + +//TODO: Support library includes// + +#include "include/logging.h" +#include "lib/safeclib.h" + +//TODO: Lumiera header includes// +#include "backend/threadpool.h" + +//TODO: internal/static forward declarations// +/** + * Find a suitable thread pool for the given thread type. + */ +static +LumieraThreadpool +lumiera_threadpool_findpool(enum lumiera_thread_class kind); + +typedef struct lumiera_threadpoolmanager_struct lumiera_threadpoolmanager; +typedef lumiera_threadpoolmanager* LumieraThreadpoolmanager; + +struct lumiera_threadpoolmanager_struct +{ + llist pools; +}; + +/** + * Create the singleton threadpool manager + */ +static +void +lumiera_threadpoolmanager_new(void); + +/** + * Delete/remove the singleton threadpool manager + */ +static +void +lumiera_threadpoolmanager_delete(void); + +// singleton threadpool manager instance +static LumieraThreadpoolmanager lumiera_tpmanager; + +typedef struct lumiera_threadpool_struct lumiera_threadpool; +typedef lumiera_threadpool* LumieraThreadpool; + +enum lumiera_threadpool_type + { + // TODO: the following types need to be more thought out: + /** the default kind of threadpool **/ + LUMIERA_DEFAULT_THREADPOOL, + /** a threadpool for special threads **/ + LUMIERA_SPECIAL_THREADPOOL + }; + +struct lumiera_threadpool_struct +{ + /* a list of threadpools for a threadpool manager */ + llist node; + + enum lumiera_threadpool_type type; + + llist threads; +}; + +/** + * Create a thread pool. + */ +static +LumieraThreadpool +lumiera_threadpool_new(enum lumiera_threadpool_type type); + +/** + * Delete/remove a threadpool. + */ +static +void +lumiera_threadpool_delete(LumieraThreadpool threadpool); + +//TODO: System includes// +#include + +/** + * @file + * + */ + +//NOBUG_DEFINE_FLAG_PARENT (threadpool, lumiera); /*TODO insert a suitable/better parent flag here */ + + +//code goes here// + +void* pool_thread_loop(void * arg) +{ + (void) arg; + while (1) + { + ; + } + return arg; +} + +static pthread_once_t attr_once = PTHREAD_ONCE_INIT; +static pthread_attr_t attrs; + +static void thread_attr_init (void) +{ + pthread_attr_init (&attrs); + pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_DETACHED); + //cancel ... +} + +LumieraThread +lumiera_thread_new (enum lumiera_thread_class kind, + LumieraReccondition finished, + const char* purpose, + struct nobug_flag* flag) +{ + (void) kind; + (void) purpose; + (void) flag; + + if (attr_once == PTHREAD_ONCE_INIT) + pthread_once (&attr_once, thread_attr_init); + + LumieraThread thread = lumiera_malloc (sizeof(*thread)); + + thread->finished = finished; + + pthread_t dummy; + printf("creating a thread\n"); + int error = pthread_create (&dummy, &attrs, &pool_thread_loop, thread); + + if (error) return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? + return thread; +} + +LumieraThreadpool +lumiera_threadpool_new(enum lumiera_threadpool_type type) +{ + LumieraThreadpool self = lumiera_malloc (sizeof (*self)); + self->type = type; + + /* we start with no threads in the list */ + llist_init (&self->threads); + + return self; +} + +LumieraThreadpoolmanager lumiera_tpmanager = NULL; + +void +lumiera_threadpoolmanager_new() +{ + REQUIRE (!lumiera_tpmanager, "Threadpool manager already initialized"); + lumiera_tpmanager = lumiera_malloc (sizeof (lumiera_threadpoolmanager)); + llist_init (&lumiera_tpmanager->pools); + + // create a default threadpool + LumieraThreadpool default_tp = lumiera_threadpool_new(LUMIERA_DEFAULT_THREADPOOL); + llist_insert_head (&lumiera_tpmanager->pools, &default_tp->node); +}; + +LumieraThread +lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, + const char* purpose, + struct nobug_flag* flag) +{ + LumieraThreadpool tp = + lumiera_threadpool_findpool(enum lumiera_thread_class kind); + + if (!tp) + { + // ERROR: could not find a suitable threadpool or there are no threadpools + return (LumieraThreadpool)0; + } + + // TODO: either get a thread from the pool or create a new one +} + +LumieraThreadpool +lumiera_threadpool_findpool(enum lumiera_thread_class thread_kind) +{ + if (!lumiera_tpmanager) + { + // create a threadpool manager if it doesn't exist yet + lumiera_threadpoolmanager_new(); + } + if (!lumiera_tpmanager) + { + // ERROR: if the threadpool manager still doesn't exist, something went wrong + return (LumieraThreadpool)0; + } + else + { + // for now, ignore the thread all together and just return the first threadpool + (void) thread_kind; + // BUG: what if there are no pools in the list??? + // where/when should I check for that case? + return (LumieraThreadpool)(llist_head (&lumiera_tpmanager->pools)); + } +} + +void +lumiera_threadpoolmanager_new(void) +{ + REQUIRE (!lumiera_tpmanager, "Threadpool manager already initialized"); + + lumiera_tpmanager = lumiera_malloc (sizeof (lumiera_tpmanager)); + llist_init (&lumiera_tpmanager->pools); + + // start with just one default threadpool in the list + LumieraThreadpool tp = + lumiera_threadpool_new(LUMIERA_DEFAULT_THREADPOOL); + llist_insert_head (&lumiera_tp->pools, &tp->node); +} + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h new file mode 100644 index 000000000..6d11cb093 --- /dev/null +++ b/src/backend/threadpool.h @@ -0,0 +1,109 @@ +/* + threadpool.h - Manage pools of threads + + Copyright (C) Lumiera.org + 2009, Michael Ploujnikov + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef LUMIERA_THREADPOOL_H +#define LUMIERA_THREADPOOL_H + +//TODO: Support library includes// +#include "lib/reccondition.h" +#include "lib/llist.h" + +//TODO: Forward declarations// + + +//TODO: Lumiera header includes// +#include "threads.h" + +//TODO: System includes// +#include + + +/** + * @file + * + */ + +//TODO: declarations go here// + +typedef struct lumiera_threadpool_struct lumiera_threadpool; +typedef lumiera_threadpool* LumieraThreadpool; + +enum lumiera_threadpool_type + { + // TODO: the following types need to be more thought out: + /** the default kind of threadpool **/ + LUMIERA_DEFAULT_THREADPOOL, + /** a threadpool for special threads **/ + LUMIERA_SPECIAL_THREADPOOL + }; + +struct lumiera_threadpool_struct +{ + /* a list of threadpools for a threadpool manager */ + llist node; + + enum lumiera_threadpool_type type; + + llist threads; +}; + + + +/** + * Create a thread pool. + */ +LumieraThreadpool +lumiera_threadpool_new(enum lumiera_threadpool_type type); + +/** + * Delete/remove a threadpool. + */ +void +lumiera_threadpool_delete(LumieraThreadpool threadpool); + + +/** + * Acquire a thread from a threadpool. + * This may either pick a thread from the list or create a new one when the list is empty. + * This function doesn't need to be accessible outside of the threadpool implementation. + */ +LumieraThread +lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, + const char* purpose, + struct nobug_flag* flag); + +/** + * Release a thread + * This ends up putting a (parked/idle) thread back on the list of a threadpool. + * This function doesn't need to be accessible outside of the threadpool implementation. + */ +void +lumiera_threadpool_release_thread(LumieraThread thread); + + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/threads.c b/src/backend/threads.c index 67f2d4aa4..e181b6902 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -50,7 +50,7 @@ struct lumiera_thread_mockup LumieraReccondition finished; }; - +#if 0 static void* pthread_runner (void* thread) { pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); @@ -79,8 +79,9 @@ static void thread_attr_init (void) pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_DETACHED); //cancel ... } +#endif - +#if 0 LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*start_routine)(void *), @@ -108,6 +109,39 @@ lumiera_thread_run (enum lumiera_thread_class kind, if (error) return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? return (LumieraThread) 1; } +#endif + +// TODO: new implementation, remove the above one +// maybe this shouldn't return LumieraThread at all +// when this is called it should have already been decided that the function +// shall run in parallel, as a thread +LumieraThread +lumiera_thread_run (enum lumiera_thread_class kind, + void (*function)(void *), + void * arg, + LumieraReccondition finished, + const char* purpose, + struct nobug_flag* flag) +{ + (void)finished; + (void)function; + (void)arg; + // ask the threadpool for a thread (it might create a new one) + LumieraThread self = lumiera_threadpool_acquire_thread(kind, purpose, flag); + + // set the function and data to be run + // lumiera_thread_set_func_data (self, start_routine, arg, purpose, flag); + + // and let it really run (signal the condition var, it waits there) + LUMIERA_RECCONDITION_SECTION(cond_sync, self->finished) + LUMIERA_RECCONDITION_SIGNAL; + + // NOTE: example only, add solid error handling! + + return self; +} + + /* diff --git a/src/backend/threads.h b/src/backend/threads.h index 9d420fa2f..d50a4fb5d 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -46,10 +46,12 @@ typedef struct lumiera_thread_struct lumiera_thread; typedef lumiera_thread* LumieraThread; + /** * Thread classes. * We define some 'classes' of threads for different purposes to abstract * priorities and other attributes. + ** TODO: rename these to LUMIERA_THREADCLASS_* */ enum lumiera_thread_class { @@ -74,6 +76,36 @@ enum lumiera_thread_class LUMIERA_THREAD_OR_NOT = 1<<16 }; +/** + * Thread state. + * These are the only states our threads can be in. + */ +typedef enum + { + LUMIERA_THREADSTATE_ERROR, + LUMIERA_THREADSTATE_IDLE, + LUMIERA_THREADSTATE_RUNNING + } + lumiera_thread_state; + +#include "threadpool.h" + +/** + * The actual thread data + */ +struct lumiera_thread_struct +{ + llist node; + // the function and argument can be passed to the thread at creation time + // void (*function)(void*); + // void* arg; + LumieraReccondition finished; + enum lumiera_thread_class type; + lumiera_thread_state state; + +}; + + /** * Start a thread. * Threads are implemented as procedures which take a void* and dont return anything. @@ -85,7 +117,7 @@ enum lumiera_thread_class * * Threads shall not handle signals (all signals will be disabled for them) unless explicitly acknowledged * * @param kind class of the thread to start - * @param start_routine pointer to a function to execute in a thread (returning void, not void* as in pthreads) + * @param function pointer to a function to execute in a thread (returning void, not void* as in pthreads) * @param arg generic pointer passed to the thread * @param finished a condition variable to be broadcasted, if not NULL. * The associated mutex should be locked at thread_run time already, else the signal can get lost. @@ -94,14 +126,13 @@ enum lumiera_thread_class */ LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, - void (*start_routine)(void *), + void (*function)(void *), void * arg, LumieraReccondition finished, const char* purpose, struct nobug_flag* flag); - #endif /* // Local Variables: diff --git a/tests/50threadpool.tests b/tests/50threadpool.tests new file mode 100644 index 000000000..1d005e151 --- /dev/null +++ b/tests/50threadpool.tests @@ -0,0 +1,5 @@ +TESTING "Thread Pool" ./test-threadpool + +TEST "Fake test" faketest < + + 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 "tests/test.h" + +#include "backend/threadpool.h" + +#include +#include + +TESTS_BEGIN + + +TEST ("faketest") +{ + printf("this is a fake test\n"); + /* create a threadpool manager, + it will automatically create all the threadpools */ + lumiera_threadpoolmanager_new(); +#if 0 + /* create some jobs */ + LumieraJob myjob = lumiera_job_new(functionpointer, parameters); // create a non timed (immediate job) */ + + /* find a suitable threadpool for a given job */ + LumieraThreadpool somepool = lumiera_threadpool_findpool(myjob); //you want to find a pool which is suitable to run a given job by asking: "hey on which pool can I run this job?" */ + + /* pass the jobs to the thread pool: */ + lumiera_threadpool_start_job(somepool, myjob); +#endif + /* wait for the job to finish */ + + /* retrive the job result from myjob */ +} + +TESTS_END diff --git a/tests/library/test-threadpool.c b/tests/library/test-threadpool.c new file mode 100644 index 000000000..66959f701 --- /dev/null +++ b/tests/library/test-threadpool.c @@ -0,0 +1,53 @@ +/* + test-threadpool.c - test thread pool creation and usage + + Copyright (C) Lumiera.org + 2009, Michael Ploujnikov + + 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 "tests/test.h" + +#include "backend/threads.h" + +#include +#include + +TESTS_BEGIN + + +TEST ("faketest") +{ + printf("this is a fake test\n"); + /* create a threadpool manager, + it will automatically create all the threadpools */ + lumiera_threadpoolmanager_new(); +#if 0 + /* create some jobs */ + LumieraJob myjob = lumiera_job_new(functionpointer, parameters); // create a non timed (immediate job) */ + + /* find a suitable threadpool for a given job */ + LumieraThreadpool somepool = lumiera_threadpool_findpool(myjob); //you want to find a pool which is suitable to run a given job by asking: "hey on which pool can I run this job?" */ + + /* pass the jobs to the thread pool: */ + lumiera_threadpool_start_job(somepool, myjob); +#endif + /* wait for the job to finish */ + + /* retrive the job result from myjob */ +} + +TESTS_END From 775f6cbb5d800c6dc223b3810b92b1e3e9540fdd Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sun, 22 Nov 2009 20:08:08 -0500 Subject: [PATCH 102/377] actually create or use a thread struct, still not associated with a pthread --- src/backend/threadpool.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 27729895b..70dbb528d 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -194,7 +194,16 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, return (LumieraThreadpool)0; } - // TODO: either get a thread from the pool or create a new one + if (llist_is_empty (tp->threads)) + { + // how does this become an actual pthread? + return lumiera_thread_new (kind, NULL, purpose, flag); + } + else + { + // use an existing thread, pick the first one + return (LumieraThread)(llist_head (&tp->threads)); + } } LumieraThreadpool From 9dd838b129f2315ccc88bcc471aea2721659c4b8 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Mon, 23 Nov 2009 16:40:31 -0500 Subject: [PATCH 103/377] acquire() test started, so far, everything just compiles --- src/backend/threadpool.c | 188 +++----------------------------- src/backend/threadpool.h | 59 ++++------ src/backend/threads.c | 42 ++++++- src/backend/threads.h | 20 +++- tests/50threadpool.tests | 14 ++- tests/Makefile.am | 6 + tests/backend/test-threadpool.c | 38 ++++--- 7 files changed, 129 insertions(+), 238 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 70dbb528d..608088137 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -28,73 +28,7 @@ #include "backend/threadpool.h" //TODO: internal/static forward declarations// -/** - * Find a suitable thread pool for the given thread type. - */ -static -LumieraThreadpool -lumiera_threadpool_findpool(enum lumiera_thread_class kind); - -typedef struct lumiera_threadpoolmanager_struct lumiera_threadpoolmanager; -typedef lumiera_threadpoolmanager* LumieraThreadpoolmanager; - -struct lumiera_threadpoolmanager_struct -{ - llist pools; -}; - -/** - * Create the singleton threadpool manager - */ -static -void -lumiera_threadpoolmanager_new(void); - -/** - * Delete/remove the singleton threadpool manager - */ -static -void -lumiera_threadpoolmanager_delete(void); - -// singleton threadpool manager instance -static LumieraThreadpoolmanager lumiera_tpmanager; - -typedef struct lumiera_threadpool_struct lumiera_threadpool; -typedef lumiera_threadpool* LumieraThreadpool; - -enum lumiera_threadpool_type - { - // TODO: the following types need to be more thought out: - /** the default kind of threadpool **/ - LUMIERA_DEFAULT_THREADPOOL, - /** a threadpool for special threads **/ - LUMIERA_SPECIAL_THREADPOOL - }; - -struct lumiera_threadpool_struct -{ - /* a list of threadpools for a threadpool manager */ - llist node; - - enum lumiera_threadpool_type type; - - llist threads; -}; - -/** - * Create a thread pool. - */ -static -LumieraThreadpool -lumiera_threadpool_new(enum lumiera_threadpool_type type); - -/** - * Delete/remove a threadpool. - */ -static -void -lumiera_threadpool_delete(LumieraThreadpool threadpool); +static lumiera_threadpool threadpool; //TODO: System includes// #include @@ -119,130 +53,38 @@ void* pool_thread_loop(void * arg) return arg; } -static pthread_once_t attr_once = PTHREAD_ONCE_INIT; -static pthread_attr_t attrs; - -static void thread_attr_init (void) -{ - pthread_attr_init (&attrs); - pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_DETACHED); - //cancel ... -} - -LumieraThread -lumiera_thread_new (enum lumiera_thread_class kind, - LumieraReccondition finished, - const char* purpose, - struct nobug_flag* flag) -{ - (void) kind; - (void) purpose; - (void) flag; - - if (attr_once == PTHREAD_ONCE_INIT) - pthread_once (&attr_once, thread_attr_init); - - LumieraThread thread = lumiera_malloc (sizeof(*thread)); - - thread->finished = finished; - - pthread_t dummy; - printf("creating a thread\n"); - int error = pthread_create (&dummy, &attrs, &pool_thread_loop, thread); - - if (error) return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? - return thread; -} - -LumieraThreadpool -lumiera_threadpool_new(enum lumiera_threadpool_type type) -{ - LumieraThreadpool self = lumiera_malloc (sizeof (*self)); - self->type = type; - - /* we start with no threads in the list */ - llist_init (&self->threads); - - return self; -} - -LumieraThreadpoolmanager lumiera_tpmanager = NULL; - void -lumiera_threadpoolmanager_new() +lumiera_threadpool_init(void) { - REQUIRE (!lumiera_tpmanager, "Threadpool manager already initialized"); - lumiera_tpmanager = lumiera_malloc (sizeof (lumiera_threadpoolmanager)); - llist_init (&lumiera_tpmanager->pools); - - // create a default threadpool - LumieraThreadpool default_tp = lumiera_threadpool_new(LUMIERA_DEFAULT_THREADPOOL); - llist_insert_head (&lumiera_tpmanager->pools, &default_tp->node); -}; + for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) + { + llist_init(&threadpool.kind[i].pool); + lumiera_mutex_init(&threadpool.kind[i].lock,"pool of threads", NULL); + } +} LumieraThread lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag) { - LumieraThreadpool tp = - lumiera_threadpool_findpool(enum lumiera_thread_class kind); + // TODO: do we need to check that index 'kind' is within range? + llist pool = threadpool.kind[kind].pool; + // TODO: do we need to check that we get a valid list? - if (!tp) + // TODO: do proper locking when manipulating the list + if (llist_is_empty (&pool)) { - // ERROR: could not find a suitable threadpool or there are no threadpools - return (LumieraThreadpool)0; - } - - if (llist_is_empty (tp->threads)) - { - // how does this become an actual pthread? return lumiera_thread_new (kind, NULL, purpose, flag); } else { // use an existing thread, pick the first one - return (LumieraThread)(llist_head (&tp->threads)); + // remove it from the pool's list + return (LumieraThread)(llist_unlink(llist_head (&pool))); } } -LumieraThreadpool -lumiera_threadpool_findpool(enum lumiera_thread_class thread_kind) -{ - if (!lumiera_tpmanager) - { - // create a threadpool manager if it doesn't exist yet - lumiera_threadpoolmanager_new(); - } - if (!lumiera_tpmanager) - { - // ERROR: if the threadpool manager still doesn't exist, something went wrong - return (LumieraThreadpool)0; - } - else - { - // for now, ignore the thread all together and just return the first threadpool - (void) thread_kind; - // BUG: what if there are no pools in the list??? - // where/when should I check for that case? - return (LumieraThreadpool)(llist_head (&lumiera_tpmanager->pools)); - } -} - -void -lumiera_threadpoolmanager_new(void) -{ - REQUIRE (!lumiera_tpmanager, "Threadpool manager already initialized"); - - lumiera_tpmanager = lumiera_malloc (sizeof (lumiera_tpmanager)); - llist_init (&lumiera_tpmanager->pools); - - // start with just one default threadpool in the list - LumieraThreadpool tp = - lumiera_threadpool_new(LUMIERA_DEFAULT_THREADPOOL); - llist_insert_head (&lumiera_tp->pools, &tp->node); -} - /* // Local Variables: // mode: C diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 6d11cb093..f6b359150 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -25,6 +25,7 @@ //TODO: Support library includes// #include "lib/reccondition.h" #include "lib/llist.h" +#include "lib/mutex.h" //TODO: Forward declarations// @@ -43,46 +44,9 @@ //TODO: declarations go here// -typedef struct lumiera_threadpool_struct lumiera_threadpool; -typedef lumiera_threadpool* LumieraThreadpool; - -enum lumiera_threadpool_type - { - // TODO: the following types need to be more thought out: - /** the default kind of threadpool **/ - LUMIERA_DEFAULT_THREADPOOL, - /** a threadpool for special threads **/ - LUMIERA_SPECIAL_THREADPOOL - }; - -struct lumiera_threadpool_struct -{ - /* a list of threadpools for a threadpool manager */ - llist node; - - enum lumiera_threadpool_type type; - - llist threads; -}; - - - -/** - * Create a thread pool. - */ -LumieraThreadpool -lumiera_threadpool_new(enum lumiera_threadpool_type type); - -/** - * Delete/remove a threadpool. - */ -void -lumiera_threadpool_delete(LumieraThreadpool threadpool); - - /** * Acquire a thread from a threadpool. - * This may either pick a thread from the list or create a new one when the list is empty. + * This may either pick a thread from an appropriate pool or create a new one when the pool is empty. * This function doesn't need to be accessible outside of the threadpool implementation. */ LumieraThread @@ -92,12 +56,29 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, /** * Release a thread - * This ends up putting a (parked/idle) thread back on the list of a threadpool. + * This ends up putting a (parked/idle) thread back on the list of an appropriate threadpool. * This function doesn't need to be accessible outside of the threadpool implementation. */ void lumiera_threadpool_release_thread(LumieraThread thread); +typedef struct lumiera_threadpool_struct lumiera_threadpool; +typedef lumiera_threadpool* LumieraThreadpool; + +struct lumiera_threadpool_struct +{ + struct + { + llist pool; + lumiera_mutex lock; + } kind[LUMIERA_THREADCLASS_COUNT]; +}; + +/** + * Initialize the thread pool. + */ +void +lumiera_threadpool_init(void); #endif /* diff --git a/src/backend/threads.c b/src/backend/threads.c index e181b6902..2c8548928 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -22,6 +22,9 @@ //TODO: Support library includes// #include "include/logging.h" +#include "lib/mutex.h" +#include "lib/safeclib.h" + //TODO: Lumiera header includes// #include "threads.h" @@ -50,7 +53,6 @@ struct lumiera_thread_mockup LumieraReccondition finished; }; -#if 0 static void* pthread_runner (void* thread) { pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); @@ -69,7 +71,6 @@ static void* pthread_runner (void* thread) return NULL; } - static pthread_once_t attr_once = PTHREAD_ONCE_INIT; static pthread_attr_t attrs; @@ -79,9 +80,9 @@ static void thread_attr_init (void) pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_DETACHED); //cancel ... } -#endif #if 0 +// TODO: rewrite this using lumiera_threadpool_acquire() LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*start_routine)(void *), @@ -129,10 +130,10 @@ lumiera_thread_run (enum lumiera_thread_class kind, // ask the threadpool for a thread (it might create a new one) LumieraThread self = lumiera_threadpool_acquire_thread(kind, purpose, flag); - // set the function and data to be run + // TODO: set the function and data to be run // lumiera_thread_set_func_data (self, start_routine, arg, purpose, flag); - // and let it really run (signal the condition var, it waits there) + // and let it really run (signal the condition var, the thread waits on it) LUMIERA_RECCONDITION_SECTION(cond_sync, self->finished) LUMIERA_RECCONDITION_SIGNAL; @@ -141,8 +142,39 @@ lumiera_thread_run (enum lumiera_thread_class kind, return self; } +/** + * Create a new thread structure with a matching pthread + */ +LumieraThread +lumiera_thread_new (enum lumiera_thread_class kind, + LumieraReccondition finished, + const char* purpose, + struct nobug_flag* flag) +{ + (void) purpose; + (void) flag; + if (attr_once == PTHREAD_ONCE_INIT) + pthread_once (&attr_once, thread_attr_init); + LumieraThread self = lumiera_malloc (sizeof (*self)); + llist_init(&self->node); + // self->id = (pthread_t)NULL; initialized by pthread_create() + self->finished = finished; + self->type = kind; + self->state = LUMIERA_THREADSTATE_IDLE; + + printf("creating a thread\n"); + int error = pthread_create (&self->id, &attrs, &pthread_runner, self); + + if (error) + { + free(self); + return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? + } + + return self; +} /* // Local Variables: diff --git a/src/backend/threads.h b/src/backend/threads.h index d50a4fb5d..67c036001 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -60,12 +60,16 @@ enum lumiera_thread_class /** busy at average priority **/ LUMIERA_THREAD_WORKER, /** busy, soft realtime, high priority **/ - LUMIERA_THREAD_URGEND, + LUMIERA_THREAD_URGENT, /** high latency, background jobs **/ LUMIERA_THREAD_BATCH, /** Something to do when there is really nothing else to do **/ LUMIERA_THREAD_IDLE, + /** this just denotes the number of classes listed above, + it is used to create arrays **/ + LUMIERA_THREADCLASS_COUNT, + // .. various thread flags follow /** * flag to let the decision to run the function in a thread open to the backend. * depending on load it might decide to run it sequentially. @@ -82,9 +86,9 @@ enum lumiera_thread_class */ typedef enum { - LUMIERA_THREADSTATE_ERROR, LUMIERA_THREADSTATE_IDLE, - LUMIERA_THREADSTATE_RUNNING + LUMIERA_THREADSTATE_RUNNING, + LUMIERA_THREADSTATE_ERROR } lumiera_thread_state; @@ -99,12 +103,20 @@ struct lumiera_thread_struct // the function and argument can be passed to the thread at creation time // void (*function)(void*); // void* arg; + pthread_t id; LumieraReccondition finished; enum lumiera_thread_class type; lumiera_thread_state state; - }; +/** + * Create a thread structure. + */ +LumieraThread +lumiera_thread_new (enum lumiera_thread_class kind, + LumieraReccondition finished, + const char* purpose, + struct nobug_flag* flag); /** * Start a thread. diff --git a/tests/50threadpool.tests b/tests/50threadpool.tests index 1d005e151..eadb1cd32 100644 --- a/tests/50threadpool.tests +++ b/tests/50threadpool.tests @@ -1,5 +1,15 @@ TESTING "Thread Pool" ./test-threadpool -TEST "Fake test" faketest < Date: Mon, 23 Nov 2009 16:51:18 -0500 Subject: [PATCH 104/377] add lumiera_threadpool_release_thread make the test compile change from type to kind --- src/backend/threadpool.c | 8 ++++++++ src/backend/threads.c | 2 +- src/backend/threads.h | 2 +- tests/50threadpool.tests | 4 ++-- tests/backend/test-threadpool.c | 8 ++++---- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 608088137..a6d58cfe0 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -85,6 +85,14 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, } } +void +lumiera_threadpool_release_thread(LumieraThread thread) +{ + // TODO: do we need to check that index 'kind' is within range? + llist pool = threadpool.kind[thread->kind].pool; + llist_insert_head(&pool, &thread->node); +} + /* // Local Variables: // mode: C diff --git a/src/backend/threads.c b/src/backend/threads.c index 2c8548928..7b18ab70a 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -161,7 +161,7 @@ lumiera_thread_new (enum lumiera_thread_class kind, llist_init(&self->node); // self->id = (pthread_t)NULL; initialized by pthread_create() self->finished = finished; - self->type = kind; + self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; printf("creating a thread\n"); diff --git a/src/backend/threads.h b/src/backend/threads.h index 67c036001..ec93c4df6 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -105,7 +105,7 @@ struct lumiera_thread_struct // void* arg; pthread_t id; LumieraReccondition finished; - enum lumiera_thread_class type; + enum lumiera_thread_class kind; lumiera_thread_state state; }; diff --git a/tests/50threadpool.tests b/tests/50threadpool.tests index eadb1cd32..935fb7169 100644 --- a/tests/50threadpool.tests +++ b/tests/50threadpool.tests @@ -4,9 +4,9 @@ TEST "Acquire/Release test" basic-acquire-release <kind); + printf("thread 1 state=%d\n", t1->state); + printf("thread 2 kind=%d\n", t2->kind); + printf("thread 2 state=%d\n", t2->state); printf("releasing thread 1\n"); lumiera_threadpool_release_thread(t1); From 75696986e4b87380b03a5afa4923f49b389ffc73 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Mon, 23 Nov 2009 19:05:57 -0500 Subject: [PATCH 105/377] test passes --- src/backend/threadpool.c | 5 ++--- tests/30backend-threadpool.tests | 13 ++++++++++++- tests/50threadpool.tests | 15 --------------- tests/backend/test-threadpool.c | 26 +++++++++++++++----------- 4 files changed, 29 insertions(+), 30 deletions(-) delete mode 100644 tests/50threadpool.tests diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index a6d58cfe0..063794012 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -37,8 +37,7 @@ static lumiera_threadpool threadpool; * @file * */ - -//NOBUG_DEFINE_FLAG_PARENT (threadpool, lumiera); /*TODO insert a suitable/better parent flag here */ +NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); //code goes here// @@ -59,7 +58,7 @@ lumiera_threadpool_init(void) for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.kind[i].pool); - lumiera_mutex_init(&threadpool.kind[i].lock,"pool of threads", NULL); + lumiera_mutex_init(&threadpool.kind[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); } } diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index dc178ba91..16fd316d4 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -1,6 +1,17 @@ -TESTING "Thread Pools" +TESTING "Thread Pools" ./test-threadpool PLANNED "create" PLANNED "yield" PLANNED "cancel" + +TEST "Acquire/Release test" basic-acquire-release <kind); - printf("thread 1 state=%d\n", t1->state); - printf("thread 2 kind=%d\n", t2->kind); - printf("thread 2 state=%d\n", t2->state); + //ECHO("thread 1 kind=%d", t1->kind); + CHECK(LUMIERA_THREAD_INTERACTIVE == t1->kind); + //ECHO("thread 1 state=%d", t1->state); + CHECK(LUMIERA_THREADSTATE_IDLE == t1->state); + //ECHO("thread 2 kind=%d", t2->kind); + // CHECK(LUMIERA_THREAD_IDLE == t2->kind); + //ECHO("thread 2 state=%d", t2->state); + CHECK(LUMIERA_THREADSTATE_IDLE == t2->state); - printf("releasing thread 1\n"); + ECHO("releasing thread 1"); lumiera_threadpool_release_thread(t1); - printf("thread 1 has been released\n"); + ECHO("thread 1 has been released"); - printf("releasing thread 2\n"); + ECHO("releasing thread 2"); lumiera_threadpool_release_thread(t2); - printf("thread 2 has been released\n"); + ECHO("thread 2 has been released"); } TESTS_END From 414b8b99c341b5fd8a1891074fd1bdfaf1c8095a Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Mon, 23 Nov 2009 19:47:20 -0500 Subject: [PATCH 106/377] updated test passes fixed problem with copying lists --- src/backend/threadpool.c | 6 ++---- src/backend/threads.c | 10 ++++++++-- tests/backend/test-threadpool.c | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 063794012..87ca3803c 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -68,11 +68,9 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, struct nobug_flag* flag) { // TODO: do we need to check that index 'kind' is within range? - llist pool = threadpool.kind[kind].pool; // TODO: do we need to check that we get a valid list? - // TODO: do proper locking when manipulating the list - if (llist_is_empty (&pool)) + if (llist_is_empty (&threadpool.kind[kind].pool)) { return lumiera_thread_new (kind, NULL, purpose, flag); } @@ -80,7 +78,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, { // use an existing thread, pick the first one // remove it from the pool's list - return (LumieraThread)(llist_unlink(llist_head (&pool))); + return (LumieraThread)(llist_unlink(llist_head (&threadpool.kind[kind].pool))); } } diff --git a/src/backend/threads.c b/src/backend/threads.c index 7b18ab70a..e87853765 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -53,6 +53,12 @@ struct lumiera_thread_mockup LumieraReccondition finished; }; +static void* thread_loop (void* arg) +{ + return arg; +} + +#if 0 static void* pthread_runner (void* thread) { pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); @@ -70,6 +76,7 @@ static void* pthread_runner (void* thread) return NULL; } +#endif static pthread_once_t attr_once = PTHREAD_ONCE_INIT; static pthread_attr_t attrs; @@ -164,8 +171,7 @@ lumiera_thread_new (enum lumiera_thread_class kind, self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; - printf("creating a thread\n"); - int error = pthread_create (&self->id, &attrs, &pthread_runner, self); + int error = pthread_create (&self->id, &attrs, &thread_loop, self); if (error) { diff --git a/tests/backend/test-threadpool.c b/tests/backend/test-threadpool.c index 902a948c2..301688f48 100644 --- a/tests/backend/test-threadpool.c +++ b/tests/backend/test-threadpool.c @@ -49,7 +49,7 @@ TEST ("basic-acquire-release") //ECHO("thread 1 state=%d", t1->state); CHECK(LUMIERA_THREADSTATE_IDLE == t1->state); //ECHO("thread 2 kind=%d", t2->kind); - // CHECK(LUMIERA_THREAD_IDLE == t2->kind); + CHECK(LUMIERA_THREAD_IDLE == t2->kind); //ECHO("thread 2 state=%d", t2->state); CHECK(LUMIERA_THREADSTATE_IDLE == t2->state); From d6d81f2e441b43d06021a025aabf06ebb2775fd8 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Tue, 24 Nov 2009 22:25:00 -0500 Subject: [PATCH 107/377] added lumiera_threadpool_destroy() added locking and checks to lumiera_threadpool_acquire_thread() added a nobug flag to threads.c added lumiera_thread_destroy() added lumiera_thread_delete() --- src/backend/threadpool.c | 36 +++++++++++++++++++++++++++------ src/backend/threadpool.h | 3 +++ src/backend/threads.c | 27 +++++++++++++++++++++++-- src/backend/threads.h | 6 ++++++ tests/backend/test-threadpool.c | 2 ++ 5 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 87ca3803c..970e7291c 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -37,7 +37,7 @@ static lumiera_threadpool threadpool; * @file * */ -NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); +NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/better parent flag here */ //code goes here// @@ -62,24 +62,48 @@ lumiera_threadpool_init(void) } } +void +lumiera_threadpool_destroy(void) +{ + for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) + { + // no locking is done at this point + LLIST_FOREACH(&threadpool.kind[i].pool, thread) + { + llist_unlink(thread); + lumiera_thread_delete((LumieraThread)thread); + } + + lumiera_mutex_destroy (&threadpool.kind[i].lock, &NOBUG_FLAG (threadpool)); + } +} + LumieraThread lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag) { - // TODO: do we need to check that index 'kind' is within range? - // TODO: do we need to check that we get a valid list? - // TODO: do proper locking when manipulating the list + LumieraThread ret; + + REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); + REQUIRE (&threadpool.kind[kind].pool, "threadpool kind %d does not exist", kind); if (llist_is_empty (&threadpool.kind[kind].pool)) { - return lumiera_thread_new (kind, NULL, purpose, flag); + // TODO: fill in the reccondition argument, currently NULL + ret = lumiera_thread_new (kind, NULL, purpose, flag); } else { + REQUIRE (&threadpool.kind[kind].lock, "invalid threadpool lock"); // use an existing thread, pick the first one // remove it from the pool's list - return (LumieraThread)(llist_unlink(llist_head (&threadpool.kind[kind].pool))); + LUMIERA_MUTEX_SECTION (threadpool, &threadpool.kind[kind].lock) + { + ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.kind[kind].pool))); + } } + REQUIRE(ret, "did not find a valid thread"); + return ret; } void diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index f6b359150..0d2a0257f 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -80,6 +80,9 @@ struct lumiera_threadpool_struct void lumiera_threadpool_init(void); +void +lumiera_threadpool_destroy(void); + #endif /* // Local Variables: diff --git a/src/backend/threads.c b/src/backend/threads.c index e87853765..6104a8011 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -40,7 +40,7 @@ * */ -//NOBUG_DEFINE_FLAG_PARENT (threads, lumiera); /*TODO insert a suitable/better parent flag here */ +NOBUG_DEFINE_FLAG_PARENT (threads, threads_dbg); /*TODO insert a suitable/better parent flag here */ //code goes here// @@ -158,6 +158,7 @@ lumiera_thread_new (enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag) { + // TODO: do something with these: (void) purpose; (void) flag; @@ -166,11 +167,15 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread self = lumiera_malloc (sizeof (*self)); llist_init(&self->node); - // self->id = (pthread_t)NULL; initialized by pthread_create() self->finished = finished; + REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; + REQUIRE (&self->id); + //REQUIRE (&attrs); + //REQUIRE (&thread_loop); + REQUIRE (self); int error = pthread_create (&self->id, &attrs, &thread_loop, self); if (error) @@ -182,6 +187,24 @@ lumiera_thread_new (enum lumiera_thread_class kind, return self; } +LumieraThread +lumiera_thread_destroy (LumieraThread self) +{ + // TODO: stop the pthread + // TODO: empty the list/node? + //finished = NULL; // or free(finished)? + lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG(threads)); + //kind = 0; + //state = 0; + return self; +} + +void +lumiera_thread_delete (LumieraThread self) +{ + lumiera_free (lumiera_thread_destroy (self)); +} + /* // Local Variables: // mode: C diff --git a/src/backend/threads.h b/src/backend/threads.h index ec93c4df6..51000782a 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -118,6 +118,12 @@ lumiera_thread_new (enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag); +LumieraThread +lumiera_thread_destroy (LumieraThread self); + +void +lumiera_thread_delete (LumieraThread self); + /** * Start a thread. * Threads are implemented as procedures which take a void* and dont return anything. diff --git a/tests/backend/test-threadpool.c b/tests/backend/test-threadpool.c index 301688f48..be3b4311c 100644 --- a/tests/backend/test-threadpool.c +++ b/tests/backend/test-threadpool.c @@ -60,6 +60,8 @@ TEST ("basic-acquire-release") ECHO("releasing thread 2"); lumiera_threadpool_release_thread(t2); ECHO("thread 2 has been released"); + + lumiera_threadpool_destroy(); } TESTS_END From 8e3d4e7b7aa96cb045b67fe98574a958c92a9249 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 25 Nov 2009 11:06:53 -0500 Subject: [PATCH 108/377] fixed lumiera_threadpool_destroy() by using LLIST_FOREACH added some checks to lumiera_threadpool_release_thread(), maybe too much modified thread_loop() to return a known value - 0 added checks to lumiera_thread_new() added a check to lumiera_thread_destroy() made lumiera_thread_destroy() unlink the thread from a pool list updated test case to match new debug messages --- src/backend/threadpool.c | 21 ++++++++++++--------- src/backend/threads.c | 13 ++++++++++--- tests/30backend-threadpool.tests | 30 ++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 970e7291c..5960c890f 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -65,16 +65,17 @@ lumiera_threadpool_init(void) void lumiera_threadpool_destroy(void) { + ECHO ("destroying threadpool"); for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { + ECHO ("destroying individual pool #%d", i); // no locking is done at this point - LLIST_FOREACH(&threadpool.kind[i].pool, thread) - { - llist_unlink(thread); - lumiera_thread_delete((LumieraThread)thread); - } - + ECHO ("number of threads in the pool=%d", llist_count(&threadpool.kind[i].pool)); + LLIST_WHILE_HEAD(&threadpool.kind[i].pool, thread) + lumiera_thread_delete((LumieraThread)thread); + ECHO ("destroying the pool mutex"); lumiera_mutex_destroy (&threadpool.kind[i].lock, &NOBUG_FLAG (threadpool)); + ECHO ("pool mutex destroyed"); } } @@ -109,9 +110,11 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, void lumiera_threadpool_release_thread(LumieraThread thread) { - // TODO: do we need to check that index 'kind' is within range? - llist pool = threadpool.kind[thread->kind].pool; - llist_insert_head(&pool, &thread->node); + REQUIRE (thread, "invalid thread given"); + REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); + REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); + llist_insert_head(&threadpool.kind[thread->kind].pool, &thread->node); + REQUIRE (!llist_is_empty (&threadpool.kind[thread->kind].pool), "thread pool is still empty after insertion"); } /* diff --git a/src/backend/threads.c b/src/backend/threads.c index 6104a8011..4471fb444 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -55,7 +55,8 @@ struct lumiera_thread_mockup static void* thread_loop (void* arg) { - return arg; + (void)arg; + return 0; } #if 0 @@ -165,10 +166,12 @@ lumiera_thread_new (enum lumiera_thread_class kind, if (attr_once == PTHREAD_ONCE_INIT) pthread_once (&attr_once, thread_attr_init); + REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); + //REQUIRE (finished, "invalid finished flag passed"); + LumieraThread self = lumiera_malloc (sizeof (*self)); llist_init(&self->node); self->finished = finished; - REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; @@ -190,8 +193,11 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread lumiera_thread_destroy (LumieraThread self) { + ECHO ("destroying thread"); + REQUIRE (self, "trying to destroy an invalid thread"); + // TODO: stop the pthread - // TODO: empty the list/node? + llist_unlink(&self->node); //finished = NULL; // or free(finished)? lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG(threads)); //kind = 0; @@ -202,6 +208,7 @@ lumiera_thread_destroy (LumieraThread self) void lumiera_thread_delete (LumieraThread self) { + ECHO ("deleting thread"); lumiera_free (lumiera_thread_destroy (self)); } diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index 16fd316d4..a23ff38ea 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -13,5 +13,35 @@ err: releasing thread 1 err: thread 1 has been released err: releasing thread 2 err: thread 2 has been released +err: destroying threadpool + +err: destroying individual pool #0 +err: number of threads in the pool=1 +err: deleting thread +err: destroying thread +err: destroying the pool mutex +err: pool mutex destroyed + +err: destroying individual pool #1 +err: number of threads in the pool=0 +err: destroying the pool mutex +err: pool mutex destroyed + +err: destroying individual pool #2 +err: number of threads in the pool=0 +err: destroying the pool mutex +err: pool mutex destroyed + +err: destroying individual pool #3 +err: number of threads in the pool=0 +err: destroying the pool mutex +err: pool mutex destroyed + +err: destroying individual pool #4 +err: number of threads in the pool=1 +err: deleting thread +err: destroying thread +err: destroying the pool mutex +err: pool mutex destroyed END From 07962b5314ab9d2b784f29e79fb21dd02a055e2d Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 25 Nov 2009 17:43:22 -0500 Subject: [PATCH 109/377] add comments about locking in lumiera_threadpool_release_thread() output the size of the created thread struct don't print "destroying thread" (lets tests become shorter with repeated matching) add a test which spans many threads in all pools --- src/backend/threadpool.c | 12 +++++++--- src/backend/threads.c | 2 +- tests/30backend-threadpool.tests | 39 ++++++++++++++++++++++++++++++-- tests/backend/test-threadpool.c | 28 +++++++++++++++++++++++ 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 5960c890f..1a48967dd 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -112,9 +112,15 @@ lumiera_threadpool_release_thread(LumieraThread thread) { REQUIRE (thread, "invalid thread given"); REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); - REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); - llist_insert_head(&threadpool.kind[thread->kind].pool, &thread->node); - REQUIRE (!llist_is_empty (&threadpool.kind[thread->kind].pool), "thread pool is still empty after insertion"); + REQUIRE (&threadpool.kind[thread->kind].lock, "invalid threadpool lock"); + + // TOOD: currently, locking produces memory leaks + // LUMIERA_MUTEX_SECTION (threadpool, &threadpool.kind[thread->kind].lock) + // { + //REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); + llist_insert_head(&threadpool.kind[thread->kind].pool, &thread->node); + // REQUIRE (!llist_is_empty (&threadpool.kind[thread->kind].pool), "thread pool is still empty after insertion"); + // } } /* diff --git a/src/backend/threads.c b/src/backend/threads.c index 4471fb444..52125fcef 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -170,6 +170,7 @@ lumiera_thread_new (enum lumiera_thread_class kind, //REQUIRE (finished, "invalid finished flag passed"); LumieraThread self = lumiera_malloc (sizeof (*self)); + ECHO ("allocated thread struct of size %zd", sizeof (*self)); llist_init(&self->node); self->finished = finished; self->kind = kind; @@ -193,7 +194,6 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread lumiera_thread_destroy (LumieraThread self) { - ECHO ("destroying thread"); REQUIRE (self, "trying to destroy an invalid thread"); // TODO: stop the pthread diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index a23ff38ea..44392f279 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -8,17 +8,19 @@ PLANNED "cancel" TEST "Acquire/Release test" basic-acquire-release < Date: Wed, 25 Nov 2009 17:47:43 -0500 Subject: [PATCH 110/377] remove "allocated thread*" messages from lumiera_thread_new() and update tests --- src/backend/threads.c | 1 - tests/30backend-threadpool.tests | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 52125fcef..5ea2aa56f 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -170,7 +170,6 @@ lumiera_thread_new (enum lumiera_thread_class kind, //REQUIRE (finished, "invalid finished flag passed"); LumieraThread self = lumiera_malloc (sizeof (*self)); - ECHO ("allocated thread struct of size %zd", sizeof (*self)); llist_init(&self->node); self->finished = finished; self->kind = kind; diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index 44392f279..0ce7ca67a 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -8,9 +8,7 @@ PLANNED "cancel" TEST "Acquire/Release test" basic-acquire-release < Date: Wed, 25 Nov 2009 18:58:15 -0500 Subject: [PATCH 111/377] check that we're creating valid lumiera_thread_structures die on pthread_create errors that we shouldn't be handling --- src/backend/threadpool.c | 3 ++- src/backend/threads.c | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 1a48967dd..3dbfd0c92 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -92,6 +92,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, { // TODO: fill in the reccondition argument, currently NULL ret = lumiera_thread_new (kind, NULL, purpose, flag); + ENSURE (ret, "did not create a valid thread"); } else { @@ -102,8 +103,8 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, { ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.kind[kind].pool))); } + ENSURE (ret, "did not find a valid thread"); } - REQUIRE(ret, "did not find a valid thread"); return ret; } diff --git a/src/backend/threads.c b/src/backend/threads.c index 5ea2aa56f..6cf4559be 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -34,6 +34,7 @@ //TODO: System includes// #include +#include /** * @file @@ -180,13 +181,16 @@ lumiera_thread_new (enum lumiera_thread_class kind, //REQUIRE (&thread_loop); REQUIRE (self); int error = pthread_create (&self->id, &attrs, &thread_loop, self); - + ENSURE(error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror(error)); + FIXME("handle EAGAIN"); if (error) { - free(self); +#if 0 return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? +#endif } + REQUIRE (self, "returning an invalid thread structure"); return self; } From bd076e4210d7623f9c0544d2fc2f5bafa82e5c69 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 25 Nov 2009 19:58:54 -0500 Subject: [PATCH 112/377] reduce the number of threads spawned in a test --- tests/30backend-threadpool.tests | 10 +++++----- tests/backend/test-threadpool.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index 0ce7ca67a..03808507a 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -48,31 +48,31 @@ TEST "Many Acquires/Releases test" many-acquire-release < Date: Wed, 25 Nov 2009 21:46:03 -0500 Subject: [PATCH 113/377] begin implementing a 'soft' thread count limit per pool add LUMIERA_DIE in cases where this soft limit is reached add LUMIERA_DIE when pthread_create fails to create threads - serious add a test which tries to break the soft limit --- src/backend/threadpool.c | 37 +++++++++++++++++++++++++++----- src/backend/threadpool.h | 6 +++++- src/backend/threads.c | 7 +++--- tests/30backend-threadpool.tests | 6 ++++++ tests/backend/test-threadpool.c | 32 +++++++++++++++++++++++++-- 5 files changed, 76 insertions(+), 12 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 3dbfd0c92..c77225f78 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -53,11 +53,14 @@ void* pool_thread_loop(void * arg) } void -lumiera_threadpool_init(void) +lumiera_threadpool_init(unsigned limit) { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.kind[i].pool); + threadpool.kind[i].max_threads = limit; + threadpool.kind[i].working_thread_count = 0; + threadpool.kind[i].idle_thread_count = 0; lumiera_mutex_init(&threadpool.kind[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); } } @@ -91,17 +94,34 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, if (llist_is_empty (&threadpool.kind[kind].pool)) { // TODO: fill in the reccondition argument, currently NULL - ret = lumiera_thread_new (kind, NULL, purpose, flag); - ENSURE (ret, "did not create a valid thread"); + FIXME ("this max thread logic needs to be deeply thought about and made more efficient as well as rebust"); + if (threadpool.kind[kind].working_thread_count + + threadpool.kind[kind].idle_thread_count + < threadpool.kind[kind].max_threads) { + ret = lumiera_thread_new (kind, NULL, purpose, flag); + threadpool.kind[kind].working_thread_count++; + ENSURE (ret, "did not create a valid thread"); + } + else + { + //ERROR (threadpool, "did not create a new thread because per-pool limit was reached: %d", threadpool.kind[kind].max_threads); + LUMIERA_DIE(ERRNO); + } } else { - REQUIRE (&threadpool.kind[kind].lock, "invalid threadpool lock"); // use an existing thread, pick the first one // remove it from the pool's list LUMIERA_MUTEX_SECTION (threadpool, &threadpool.kind[kind].lock) { ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.kind[kind].pool))); + threadpool.kind[kind].working_thread_count++; + threadpool.kind[kind].idle_thread_count--; // cheaper than using llist_count + ENSURE (threadpool.kind[kind].idle_thread_count == + llist_count(&threadpool.kind[kind].pool), + "idle thread count %d is wrong, should be %d", + threadpool.kind[kind].idle_thread_count, + llist_count(&threadpool.kind[kind].pool)); } ENSURE (ret, "did not find a valid thread"); } @@ -118,8 +138,15 @@ lumiera_threadpool_release_thread(LumieraThread thread) // TOOD: currently, locking produces memory leaks // LUMIERA_MUTEX_SECTION (threadpool, &threadpool.kind[thread->kind].lock) // { - //REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); + REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); llist_insert_head(&threadpool.kind[thread->kind].pool, &thread->node); + threadpool.kind[thread->kind].working_thread_count--; + threadpool.kind[thread->kind].idle_thread_count++; // cheaper than using llist_count + ENSURE (threadpool.kind[thread->kind].idle_thread_count == + llist_count(&threadpool.kind[thread->kind].pool), + "idle thread count %d is wrong, should be %d", + threadpool.kind[thread->kind].idle_thread_count, + llist_count(&threadpool.kind[thread->kind].pool)); // REQUIRE (!llist_is_empty (&threadpool.kind[thread->kind].pool), "thread pool is still empty after insertion"); // } } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 0d2a0257f..fbd45c8a4 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -71,14 +71,18 @@ struct lumiera_threadpool_struct { llist pool; lumiera_mutex lock; + unsigned max_threads; + unsigned working_thread_count; + unsigned idle_thread_count; } kind[LUMIERA_THREADCLASS_COUNT]; }; /** * Initialize the thread pool. + * @param limit the maximum number of threads (idle+working) allowed per pool */ void -lumiera_threadpool_init(void); +lumiera_threadpool_init(unsigned limit); void lumiera_threadpool_destroy(void); diff --git a/src/backend/threads.c b/src/backend/threads.c index 6cf4559be..f4277fd47 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -182,12 +182,11 @@ lumiera_thread_new (enum lumiera_thread_class kind, REQUIRE (self); int error = pthread_create (&self->id, &attrs, &thread_loop, self); ENSURE(error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror(error)); - FIXME("handle EAGAIN"); if (error) { -#if 0 - return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? -#endif + // error here can only be EAGAIN, given the above ENSURE + FIXME ("error is %d:%s, see if this can be improved", error, strerror(error)); + LUMIERA_DIE (ERRNO); } REQUIRE (self, "returning an invalid thread structure"); diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index 03808507a..a92b32059 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -77,3 +77,9 @@ err: deleting thread err: destroying the pool mutex err: pool mutex destroyed END + +TEST "Too Many Acquires/Releases test" toomany-acquire-release < Date: Thu, 26 Nov 2009 11:15:31 -0500 Subject: [PATCH 114/377] this was replaced with tests/backend/test-threadpool.c --- tests/library/test-threadpool.c | 53 --------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 tests/library/test-threadpool.c diff --git a/tests/library/test-threadpool.c b/tests/library/test-threadpool.c deleted file mode 100644 index 66959f701..000000000 --- a/tests/library/test-threadpool.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - test-threadpool.c - test thread pool creation and usage - - Copyright (C) Lumiera.org - 2009, Michael Ploujnikov - - 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 "tests/test.h" - -#include "backend/threads.h" - -#include -#include - -TESTS_BEGIN - - -TEST ("faketest") -{ - printf("this is a fake test\n"); - /* create a threadpool manager, - it will automatically create all the threadpools */ - lumiera_threadpoolmanager_new(); -#if 0 - /* create some jobs */ - LumieraJob myjob = lumiera_job_new(functionpointer, parameters); // create a non timed (immediate job) */ - - /* find a suitable threadpool for a given job */ - LumieraThreadpool somepool = lumiera_threadpool_findpool(myjob); //you want to find a pool which is suitable to run a given job by asking: "hey on which pool can I run this job?" */ - - /* pass the jobs to the thread pool: */ - lumiera_threadpool_start_job(somepool, myjob); -#endif - /* wait for the job to finish */ - - /* retrive the job result from myjob */ -} - -TESTS_END From 99eb7900276d2ee629081251e4412644eef55bf0 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 26 Nov 2009 11:21:31 -0500 Subject: [PATCH 115/377] rename LUMIERA_THREAD_* to LUMIERA_THREADCLASS_* in enum lumiera_thread_class --- src/backend/thread-wrapper.hpp | 4 ++-- src/backend/threads.h | 13 ++++++------- tests/backend/test-threadpool.c | 8 ++++---- tests/backend/test-threads.c | 6 +++--- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 730b4338b..3f897b582 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -207,7 +207,7 @@ namespace backend { : started_(false), operation_(operation) { - start_thread (LUMIERA_THREAD_INTERACTIVE, purpose, logging_flag); + start_thread (LUMIERA_THREADCLASS_INTERACTIVE, purpose, logging_flag); } /** Variant of the standard case, used to register a JoinHandle in addition to starting a thread. @@ -220,7 +220,7 @@ namespace backend { : started_(false), operation_(operation) { - start_thread (LUMIERA_THREAD_INTERACTIVE, purpose, logging_flag, + start_thread (LUMIERA_THREADCLASS_INTERACTIVE, purpose, logging_flag, join.accessLockedCondition()); } }; diff --git a/src/backend/threads.h b/src/backend/threads.h index 51000782a..3a45bc5e5 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -51,20 +51,19 @@ typedef lumiera_thread* LumieraThread; * Thread classes. * We define some 'classes' of threads for different purposes to abstract * priorities and other attributes. - ** TODO: rename these to LUMIERA_THREADCLASS_* */ enum lumiera_thread_class { /** mostly idle, low latency **/ - LUMIERA_THREAD_INTERACTIVE, + LUMIERA_THREADCLASS_INTERACTIVE, /** busy at average priority **/ - LUMIERA_THREAD_WORKER, + LUMIERA_THREADCLASS_WORKER, /** busy, soft realtime, high priority **/ - LUMIERA_THREAD_URGENT, + LUMIERA_THREADCLASS_URGENT, /** high latency, background jobs **/ - LUMIERA_THREAD_BATCH, + LUMIERA_THREADCLASS_BATCH, /** Something to do when there is really nothing else to do **/ - LUMIERA_THREAD_IDLE, + LUMIERA_THREADCLASS_IDLE, /** this just denotes the number of classes listed above, it is used to create arrays **/ LUMIERA_THREADCLASS_COUNT, @@ -99,7 +98,7 @@ typedef enum */ struct lumiera_thread_struct { - llist node; + llist node; // this should be first for easy casting // the function and argument can be passed to the thread at creation time // void (*function)(void*); // void* arg; diff --git a/tests/backend/test-threadpool.c b/tests/backend/test-threadpool.c index 530fc10de..66de5c1a3 100644 --- a/tests/backend/test-threadpool.c +++ b/tests/backend/test-threadpool.c @@ -35,21 +35,21 @@ TEST ("basic-acquire-release") lumiera_threadpool_init(100); ECHO("acquiring thread 1"); LumieraThread t1 = - lumiera_threadpool_acquire_thread(LUMIERA_THREAD_INTERACTIVE, + lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE, "test purpose", NULL); ECHO("acquiring thread 2"); LumieraThread t2 = - lumiera_threadpool_acquire_thread(LUMIERA_THREAD_IDLE, + lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_IDLE, "test purpose", NULL); //ECHO("thread 1 kind=%d", t1->kind); - CHECK(LUMIERA_THREAD_INTERACTIVE == t1->kind); + CHECK(LUMIERA_THREADCLASS_INTERACTIVE == t1->kind); //ECHO("thread 1 state=%d", t1->state); CHECK(LUMIERA_THREADSTATE_IDLE == t1->state); //ECHO("thread 2 kind=%d", t2->kind); - CHECK(LUMIERA_THREAD_IDLE == t2->kind); + CHECK(LUMIERA_THREADCLASS_IDLE == t2->kind); //ECHO("thread 2 state=%d", t2->state); CHECK(LUMIERA_THREADSTATE_IDLE == t2->state); diff --git a/tests/backend/test-threads.c b/tests/backend/test-threads.c index 14237f7a2..76da2f450 100644 --- a/tests/backend/test-threads.c +++ b/tests/backend/test-threads.c @@ -88,7 +88,7 @@ TEST ("simple_thread") { fprintf (stderr, "main before thread %s\n", NOBUG_THREAD_ID_GET); - lumiera_thread_run (LUMIERA_THREAD_WORKER, + lumiera_thread_run (LUMIERA_THREADCLASS_WORKER, threadfn, NULL, NULL, @@ -109,7 +109,7 @@ TEST ("thread_synced") { ECHO ("main before thread %s", NOBUG_THREAD_ID_GET); - lumiera_thread_run (LUMIERA_THREAD_WORKER, + lumiera_thread_run (LUMIERA_THREADCLASS_WORKER, threadsyncfn, &cnd, &cnd, @@ -140,7 +140,7 @@ TEST ("mutex_thread") { fprintf (stderr, "main before thread %s\n", NOBUG_THREAD_ID_GET); - lumiera_thread_run (LUMIERA_THREAD_WORKER, + lumiera_thread_run (LUMIERA_THREADCLASS_WORKER, mutexfn, NULL, NULL, From afd2035983205017bf12aa44eb5e0d9e44735bd6 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 26 Nov 2009 11:27:50 -0500 Subject: [PATCH 116/377] rename threadpool.kind[i].pool to threadpool.kind[i].list rename threadpool.kind to threadpool.pool --- src/backend/threadpool.c | 66 ++++++++++++++++++++-------------------- src/backend/threadpool.h | 4 +-- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index c77225f78..e5273d4c0 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -57,11 +57,11 @@ lumiera_threadpool_init(unsigned limit) { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { - llist_init(&threadpool.kind[i].pool); - threadpool.kind[i].max_threads = limit; - threadpool.kind[i].working_thread_count = 0; - threadpool.kind[i].idle_thread_count = 0; - lumiera_mutex_init(&threadpool.kind[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); + llist_init(&threadpool.pool[i].list); + threadpool.pool[i].max_threads = limit; + threadpool.pool[i].working_thread_count = 0; + threadpool.pool[i].idle_thread_count = 0; + lumiera_mutex_init(&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); } } @@ -73,11 +73,11 @@ lumiera_threadpool_destroy(void) { ECHO ("destroying individual pool #%d", i); // no locking is done at this point - ECHO ("number of threads in the pool=%d", llist_count(&threadpool.kind[i].pool)); - LLIST_WHILE_HEAD(&threadpool.kind[i].pool, thread) + ECHO ("number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); + LLIST_WHILE_HEAD(&threadpool.pool[i].list, thread) lumiera_thread_delete((LumieraThread)thread); ECHO ("destroying the pool mutex"); - lumiera_mutex_destroy (&threadpool.kind[i].lock, &NOBUG_FLAG (threadpool)); + lumiera_mutex_destroy (&threadpool.pool[i].lock, &NOBUG_FLAG (threadpool)); ECHO ("pool mutex destroyed"); } } @@ -90,21 +90,21 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, LumieraThread ret; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); - REQUIRE (&threadpool.kind[kind].pool, "threadpool kind %d does not exist", kind); - if (llist_is_empty (&threadpool.kind[kind].pool)) + REQUIRE (&threadpool.pool[kind].list, "threadpool kind %d does not exist", kind); + if (llist_is_empty (&threadpool.pool[kind].list)) { // TODO: fill in the reccondition argument, currently NULL FIXME ("this max thread logic needs to be deeply thought about and made more efficient as well as rebust"); - if (threadpool.kind[kind].working_thread_count - + threadpool.kind[kind].idle_thread_count - < threadpool.kind[kind].max_threads) { + if (threadpool.pool[kind].working_thread_count + + threadpool.pool[kind].idle_thread_count + < threadpool.pool[kind].max_threads) { ret = lumiera_thread_new (kind, NULL, purpose, flag); - threadpool.kind[kind].working_thread_count++; + threadpool.pool[kind].working_thread_count++; ENSURE (ret, "did not create a valid thread"); } else { - //ERROR (threadpool, "did not create a new thread because per-pool limit was reached: %d", threadpool.kind[kind].max_threads); + //ERROR (threadpool, "did not create a new thread because per-pool limit was reached: %d", threadpool.pool[kind].max_threads); LUMIERA_DIE(ERRNO); } } @@ -112,16 +112,16 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, { // use an existing thread, pick the first one // remove it from the pool's list - LUMIERA_MUTEX_SECTION (threadpool, &threadpool.kind[kind].lock) + LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[kind].lock) { - ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.kind[kind].pool))); - threadpool.kind[kind].working_thread_count++; - threadpool.kind[kind].idle_thread_count--; // cheaper than using llist_count - ENSURE (threadpool.kind[kind].idle_thread_count == - llist_count(&threadpool.kind[kind].pool), + ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.pool[kind].list))); + threadpool.pool[kind].working_thread_count++; + threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count + ENSURE (threadpool.pool[kind].idle_thread_count == + llist_count(&threadpool.pool[kind].list), "idle thread count %d is wrong, should be %d", - threadpool.kind[kind].idle_thread_count, - llist_count(&threadpool.kind[kind].pool)); + threadpool.pool[kind].idle_thread_count, + llist_count(&threadpool.pool[kind].list)); } ENSURE (ret, "did not find a valid thread"); } @@ -133,21 +133,21 @@ lumiera_threadpool_release_thread(LumieraThread thread) { REQUIRE (thread, "invalid thread given"); REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); - REQUIRE (&threadpool.kind[thread->kind].lock, "invalid threadpool lock"); + REQUIRE (&threadpool.pool[thread->kind].lock, "invalid threadpool lock"); // TOOD: currently, locking produces memory leaks - // LUMIERA_MUTEX_SECTION (threadpool, &threadpool.kind[thread->kind].lock) + // LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[thread->kind].lock) // { REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); - llist_insert_head(&threadpool.kind[thread->kind].pool, &thread->node); - threadpool.kind[thread->kind].working_thread_count--; - threadpool.kind[thread->kind].idle_thread_count++; // cheaper than using llist_count - ENSURE (threadpool.kind[thread->kind].idle_thread_count == - llist_count(&threadpool.kind[thread->kind].pool), + llist_insert_head(&threadpool.pool[thread->kind].list, &thread->node); + threadpool.pool[thread->kind].working_thread_count--; + threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count + ENSURE (threadpool.pool[thread->kind].idle_thread_count == + llist_count(&threadpool.pool[thread->kind].list), "idle thread count %d is wrong, should be %d", - threadpool.kind[thread->kind].idle_thread_count, - llist_count(&threadpool.kind[thread->kind].pool)); - // REQUIRE (!llist_is_empty (&threadpool.kind[thread->kind].pool), "thread pool is still empty after insertion"); + threadpool.pool[thread->kind].idle_thread_count, + llist_count(&threadpool.pool[thread->kind].list)); + // REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); // } } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index fbd45c8a4..b978e9e57 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -69,12 +69,12 @@ struct lumiera_threadpool_struct { struct { - llist pool; + llist list; lumiera_mutex lock; unsigned max_threads; unsigned working_thread_count; unsigned idle_thread_count; - } kind[LUMIERA_THREADCLASS_COUNT]; + } pool[LUMIERA_THREADCLASS_COUNT]; }; /** From 01223ef6ba927a8c4d40f2d40c604ec538f6bc49 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 26 Nov 2009 11:45:34 -0500 Subject: [PATCH 117/377] kind vs class naming rationale --- src/backend/threads.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/threads.h b/src/backend/threads.h index 3a45bc5e5..4c15a8ad8 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -104,6 +104,9 @@ struct lumiera_thread_struct // void* arg; pthread_t id; LumieraReccondition finished; + // the following member could have been called "class" except that it would conflict with C++ keyword + // as consequence, it's been decided to leave the type name containing the word "class", + // while all members/variables called "kind" enum lumiera_thread_class kind; lumiera_thread_state state; }; From c31bc2791b3c8f4fe5e20b3f5e001b4216205aff Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 26 Nov 2009 11:52:19 -0500 Subject: [PATCH 118/377] remove unnecessary REQUIREs based on my new understanding of nobug --- src/backend/threadpool.c | 2 -- src/backend/threads.c | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index e5273d4c0..ece74d92e 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -90,7 +90,6 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, LumieraThread ret; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); - REQUIRE (&threadpool.pool[kind].list, "threadpool kind %d does not exist", kind); if (llist_is_empty (&threadpool.pool[kind].list)) { // TODO: fill in the reccondition argument, currently NULL @@ -133,7 +132,6 @@ lumiera_threadpool_release_thread(LumieraThread thread) { REQUIRE (thread, "invalid thread given"); REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); - REQUIRE (&threadpool.pool[thread->kind].lock, "invalid threadpool lock"); // TOOD: currently, locking produces memory leaks // LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[thread->kind].lock) diff --git a/src/backend/threads.c b/src/backend/threads.c index f4277fd47..5d849943f 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -163,11 +163,11 @@ lumiera_thread_new (enum lumiera_thread_class kind, // TODO: do something with these: (void) purpose; (void) flag; + REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); if (attr_once == PTHREAD_ONCE_INIT) pthread_once (&attr_once, thread_attr_init); - REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); //REQUIRE (finished, "invalid finished flag passed"); LumieraThread self = lumiera_malloc (sizeof (*self)); @@ -176,10 +176,8 @@ lumiera_thread_new (enum lumiera_thread_class kind, self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; - REQUIRE (&self->id); //REQUIRE (&attrs); //REQUIRE (&thread_loop); - REQUIRE (self); int error = pthread_create (&self->id, &attrs, &thread_loop, self); ENSURE(error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror(error)); if (error) @@ -188,8 +186,6 @@ lumiera_thread_new (enum lumiera_thread_class kind, FIXME ("error is %d:%s, see if this can be improved", error, strerror(error)); LUMIERA_DIE (ERRNO); } - - REQUIRE (self, "returning an invalid thread structure"); return self; } From 0b289863e98db423064825ba48081bf02c526b62 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 27 Nov 2009 02:02:42 +0100 Subject: [PATCH 119/377] documentation correction. command entry is created on completed definition now. --- src/proc/control/command-registry.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/proc/control/command-registry.hpp b/src/proc/control/command-registry.hpp index 603aa5d9e..4dbd225be 100644 --- a/src/proc/control/command-registry.hpp +++ b/src/proc/control/command-registry.hpp @@ -34,10 +34,10 @@ ** \par Services during command lifecycle ** Each command starts out as command definition, accessed by client code through CommandDef. ** While collecting the necessary parts of such a definition, there is just an empty (pending) - ** Command (smart-ptr frontend), which is already registered with the intended command-ID. - ** A lookup on this ID would still fail at this point, as the \link #queryIndex search function \endlink - ** treats missing and incomplete command definitions similar. When the definition is complete, - ** a CommandImpl frame is allocated, configured and used to activate the Command (smart-ptr frontend). + ** Command (smart-ptr frontend), which is not yet usable, being held within the CommandDef. + ** When the definition is complete, a CommandImpl frame is allocated, configured and used to + ** activate the Command (smart-ptr frontend), at which point it also gets accessible + ** through the CommandRegistry. ** ** Later on, client code is assumed to re-access the command by ID. It may bind arguments, which are ** stored in the already allocated ArgumentHolder. (-->Ticket #269). As the Command frontend is a From cde45c021e591e324a068696cc771db524f3b8ac Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 27 Nov 2009 02:03:20 +0100 Subject: [PATCH 120/377] add basic storage and implementation of the PlacementIndex tables --- src/proc/mobject/session/placement-index.cpp | 142 +++++++++++++++--- src/proc/mobject/session/placement-index.hpp | 2 +- src/proc/mobject/session/query-focus.cpp | 2 +- .../mobject/session/placement-index-test.cpp | 4 +- 4 files changed, 124 insertions(+), 26 deletions(-) diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index 3c236feea..294907f5d 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -35,28 +35,40 @@ #include "proc/mobject/session/placement-index.hpp" #include "proc/mobject/session/session-impl.hpp" +#include "proc/mobject/session/scope.hpp" +#include "lib/typed-allocation-manager.hpp" +#include "proc/mobject/mobject.hpp" ///////////////////////TODO necessary? +#include "lib/util.hpp" + //#include //using boost::str; +#include +#include +#include +#include +#include +//#include + namespace mobject { namespace session { - - class PlacementIndex::Table - { - public: - Table () - { } - - size_t - size() const - { - UNIMPLEMENTED ("PlacementIndex datastructure"); - return 0; - } - - }; + using boost::hash; + using boost::noncopyable; + using std::tr1::shared_ptr; + using std::tr1::unordered_map; + using std::tr1::unordered_multimap; + using lib::TypedAllocationManager; +//using util::getValue_or_default; +//using util::contains; +//using std::string; +//using std::map; + using std::make_pair; + + using namespace lumiera; + + /* some type shorthands */ @@ -65,13 +77,83 @@ namespace session { typedef PlacementIndex::ID ID; + class PlacementIndex::Table + { + typedef shared_ptr PPlacement; + + // using a hashtables to implement the index + typedef unordered_map > IDTable; + typedef std::tr1::unordered_multimap > ScopeTable; + +// typedef PlacementMO::ID _PID; + + TypedAllocationManager allocator_; + IDTable placementTab_; + ScopeTable scopeTab_; + + + public: + Table () + { } + + ~Table () + { + try { clear(); } + catch(lumiera::Error& err) + { + WARN (session, "Problem while purging PlacementIndex: %s", err.what()); + lumiera_error(); + } } + + + size_t + size() const + { + return placementTab_.size(); + } + + bool + contains (ID id) const + { + return util::contains(placementTab_, id); + } + + void + clear() + { + INFO (session, "Purging Placement Tables..."); + scopeTab_.clear(); + placementTab_.clear(); + } + + ID + addEntry (PlacementMO const& newObj, PlacementMO const& targetScope) + { + ID scopeID = targetScope.getID(); + REQUIRE (contains (scopeID)); + + /////////////////////////////////////////////////////////////////////TICKET #436 + PPlacement newEntry = allocator_.create (newObj); + ID newID = newEntry->getID(); + + ASSERT (!contains (newID)); + placementTab_[newID] = newEntry; + scopeTab_.insert (make_pair (scopeID, newID)); + return newID; + } + + }; + + + + /** @internal Factory for creating a new placement index. * For use by the Session and for unit tests. */ PlacementIndex::Factory PlacementIndex::create; PlacementIndex::PlacementIndex() - : pTab_() + : pTab_(new Table) { } PlacementIndex::~PlacementIndex() { } @@ -94,8 +176,7 @@ namespace session { bool PlacementIndex::contains (ID id) const { - UNIMPLEMENTED ("containment test: is the given Placement known within this index"); - return false; + return pTab_->contains (id); } @@ -125,24 +206,41 @@ namespace session { } + /** Add a new Placement (Object "instance") into the index. + * Usually this means effectively adding this "Object" to the Session. + * The given Placement is copied into the storage managed within the session. + * This copy within the storage is what will be "the placement of this object". + * It can be discovered as index (Session) content, re-accessed by the ID returned + * from this call and modified in the course of editing the session. + * @param newObj reference placement pointing to the MObject to be added + * @param targetScope ref to a placement already added to the index, serving as + * container "into" which the new placement will be located + * @return placement ID of the newly added Placement + * @note the newly added Placement has an identity of its own. + */ ID - PlacementIndex::insert (PlacementMO& newObj, PlacementMO& targetScope) + PlacementIndex::insert (PlacementMO const& newObj, PlacementMO const& targetScope) { - UNIMPLEMENTED ("store a new information record into PlacmentIndex: ID -> (ref-to-Placement, parent-Placement)"); + if (!contains (targetScope)) + throw error::Logic ("Specified a non-registered Placement as scope " + "while adding another Placement to the index" + ,LUMIERA_ERROR_INVALID_SCOPE); ////////////////TICKET #197 + + return pTab_->addEntry(newObj, targetScope); } bool PlacementIndex::remove (ID) { - UNIMPLEMENTED ("remove a information record from PlacementIndex, and also deregister any placement-relations bound to it"); + UNIMPLEMENTED ("remove a information record from PlacementIndex, and also de-register any placement-relations bound to it"); } void PlacementIndex::clear() { - UNIMPLEMENTED ("purge the PlacementIndex, discarding any contained placements"); + pTab_->clear(); } diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index 49a5a0863..6cea528a2 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -133,7 +133,7 @@ namespace session { /* == mutating operations == */ - ID insert (PlacementMO& newObj, PlacementMO& targetScope); + ID insert (PlacementMO const& newObj, PlacementMO const& targetScope); bool remove (PlacementMO&); bool remove (ID); diff --git a/src/proc/mobject/session/query-focus.cpp b/src/proc/mobject/session/query-focus.cpp index b3ee76a7f..965d50b66 100644 --- a/src/proc/mobject/session/query-focus.cpp +++ b/src/proc/mobject/session/query-focus.cpp @@ -84,7 +84,7 @@ namespace session { { if (!target.isValid()) throw Invalid ("Invalid target location for QueryFocus" - , LUMIERA_ERROR_INVALID_SCOPE); + , LUMIERA_ERROR_INVALID_SCOPE); ////////////////TICKET #197 } }//(End) shortcut diff --git a/tests/components/proc/mobject/session/placement-index-test.cpp b/tests/components/proc/mobject/session/placement-index-test.cpp index 080cb3461..d01e61da6 100644 --- a/tests/components/proc/mobject/session/placement-index-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-test.cpp @@ -81,11 +81,11 @@ namespace test { ASSERT (0 == index->size()); ASSERT (!index->contains (clip)); -// index->insert (clip, root); + index->insert (clip, root); ASSERT (1 == index->size()); ASSERT ( index->contains (clip)); -// index->remove(clip); + index->remove(clip); ASSERT (0 == index->size()); ASSERT (!index->contains (clip)); ASSERT ( index->contains (root)); From 66175181dc30e5a900c7280199c3e920240a8a1f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 27 Nov 2009 02:43:09 +0100 Subject: [PATCH 121/377] basically implemented simple element access. But the scope registration and the type problem remains unsolved --- src/proc/mobject/session/placement-index.cpp | 37 ++++++++++++++++++-- src/proc/mobject/session/placement-index.hpp | 3 ++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index 294907f5d..a3d4c7420 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -68,8 +68,24 @@ namespace session { using namespace lumiera; + LUMIERA_ERROR_DEFINE (NOT_IN_SESSION, "referring to a Placement not known to the current session"); + namespace { // implementation helpers + + template + inline typename MAP::mapped_type const& + getEntry_or_throw (MAP& map, typename MAP::key_type const& key) + { + typename MAP::const_iterator pos = map.find (key); + if (pos == map.end()) + throw error::Logic("lost a Placement expected to be registered in the index."); + + return pos->second; + } + + } // (End) impl.helpers + /* some type shorthands */ typedef PlacementIndex::PlacementMO PlacementMO; @@ -85,7 +101,6 @@ namespace session { typedef unordered_map > IDTable; typedef std::tr1::unordered_multimap > ScopeTable; -// typedef PlacementMO::ID _PID; TypedAllocationManager allocator_; IDTable placementTab_; @@ -118,6 +133,18 @@ namespace session { return util::contains(placementTab_, id); } + PlacementMO& + fetch (ID id) const + { + REQUIRE (contains (id)); + PPlacement const& entry = getEntry_or_throw (placementTab_,id); + + ENSURE (entry); + ENSURE (id == entry->getID()); + return *entry; + } + + void clear() { @@ -181,9 +208,13 @@ namespace session { PlacementMO& - PlacementIndex::find (ID) const + PlacementIndex::find (ID id) const { - UNIMPLEMENTED ("main operation of PlacmentIndex: lookup a Placement by ID"); + if (!contains (id)) + throw error::Invalid ("Accessing Placement not registered within the index" + ,LUMIERA_ERROR_NOT_IN_SESSION); ///////////////////////TICKET #197 + + return pTab_->fetch (id); } diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index 6cea528a2..b4de007c6 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -68,6 +68,9 @@ namespace mobject { namespace session { + LUMIERA_ERROR_DECLARE (NOT_IN_SESSION); ///< referring to a Placement not known to the current session + + using lib::factory::RefcountFac; using std::tr1::shared_ptr; using boost::scoped_ptr; From 98519c57dad86d78632ab9d27a9fea03dfc49e34 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Fri, 27 Nov 2009 11:39:23 -0500 Subject: [PATCH 122/377] reduce the number of threads spawned in tests to avoid EAGAIN errors from pthread_create (at least on my 2.6.31.5-127.fc12.x86_64 Core2Duo T9600 system) --- tests/30backend-threadpool.tests | 10 +++++----- tests/backend/test-threadpool.c | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index a92b32059..ca2464bfe 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -48,31 +48,31 @@ TEST "Many Acquires/Releases test" many-acquire-release < Date: Fri, 27 Nov 2009 20:30:06 +0100 Subject: [PATCH 123/377] considerations regarding type handling in the PlacementIndex --- src/proc/mobject/explicitplacement.hpp | 3 +- src/proc/mobject/placement.cpp | 1 + src/proc/mobject/placement.hpp | 10 +++-- src/proc/mobject/session/locatingpin.hpp | 3 +- src/proc/mobject/session/placement-index.cpp | 2 + src/proc/mobject/session/placement-index.hpp | 20 ++++++++- src/proc/mobject/session/query-resolver.hpp | 2 +- wiki/renderengine.html | 46 +++++++++++++++++--- 8 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/proc/mobject/explicitplacement.hpp b/src/proc/mobject/explicitplacement.hpp index b9522a111..a4b947473 100644 --- a/src/proc/mobject/explicitplacement.hpp +++ b/src/proc/mobject/explicitplacement.hpp @@ -49,10 +49,11 @@ namespace mobject { const Time time; const Pipe pipe; - typedef std::pair SolutionData; //TODO (ichthyo consideres better passing of solution by subclass) + typedef std::pair SolutionData; //TODO (ichthyo considers better passing of solution by subclass) /** no need to resolve any further, as this ExplicitPlacement * already \e is the result of a resolve()-call. + * //////////////////////TICKET #439 */ virtual ExplicitPlacement resolve () const diff --git a/src/proc/mobject/placement.cpp b/src/proc/mobject/placement.cpp index 71a930e2d..fd2d02e9f 100644 --- a/src/proc/mobject/placement.cpp +++ b/src/proc/mobject/placement.cpp @@ -38,6 +38,7 @@ namespace mobject { * because we define the Placements of more specific * MObject kinds to be subclasses of Placement, * so they will inherit this function. + * //////////////////////TICKET #439 */ ExplicitPlacement Placement::resolve () const diff --git a/src/proc/mobject/placement.hpp b/src/proc/mobject/placement.hpp index d9622841c..cbd4677d8 100644 --- a/src/proc/mobject/placement.hpp +++ b/src/proc/mobject/placement.hpp @@ -117,7 +117,7 @@ namespace mobject { template<> class Placement : protected shared_ptr, - public HashIndexed, lib::hash::LuidH> //////TODO: really need to be inherited publicly? + public HashIndexed, lib::hash::LuidH> { protected: typedef HashIndexed, lib::hash::LuidH> HashInd; @@ -171,7 +171,9 @@ namespace mobject { * provide the resulting (explicit) placement. */ virtual ExplicitPlacement resolve () const; - //////////////////////////TODO could resolve() return a reference? Otherwise placement-ref.hpp needs to include ExplicitPlacement + //////////////////////////TODO (1) could resolve() return a reference? Otherwise placement-ref.hpp needs to include ExplicitPlacement + //////////////////////////TODO (2) does this really need to be virtual. Guess not. It's not abstract and not really polymorphic. But virtual here causes template bloat. + ////////////TICKET #439 protected: @@ -198,7 +200,7 @@ namespace mobject { { protected: typedef Placement _Parent; - typedef typename _Parent::template Id const& _ID; + typedef typename _Parent::template Id const& _Id; typedef typename _Parent::Deleter Deleter; typedef typename _Parent::_SmartPtr _SmartPtr; @@ -217,7 +219,7 @@ namespace mobject { (_SmartPtr::operator-> ()); } - _ID + _Id getID () const ///< @note overrides HashIndexed::getID to pass specific type information, { return _Parent::template recastID(); diff --git a/src/proc/mobject/session/locatingpin.hpp b/src/proc/mobject/session/locatingpin.hpp index be45a1ad2..99d2c92b1 100644 --- a/src/proc/mobject/session/locatingpin.hpp +++ b/src/proc/mobject/session/locatingpin.hpp @@ -99,7 +99,7 @@ namespace mobject { typedef lumiera::Time Time; typedef Time* Track; //TODO dummy declaration; we don't use Tracks as first-class entity any longer typedef std::tr1::shared_ptr Pipe; - typedef std::pair SolutionData; //TODO (ichthyo considers better passing of solution by subclass) + typedef std::pair SolutionData; //TICKET #100 (ichthyo considers better passing of solution by subclass) struct LocatingSolution; /** next additional Pin, if any */ @@ -124,6 +124,7 @@ namespace mobject { LocatingPin (const LocatingPin&); LocatingPin& operator= (const LocatingPin&); virtual LocatingPin* clone () const; + virtual ~LocatingPin() {}; // protected: diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index a3d4c7420..bda82bc90 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -69,6 +69,8 @@ namespace session { using namespace lumiera; LUMIERA_ERROR_DEFINE (NOT_IN_SESSION, "referring to a Placement not known to the current session"); + LUMIERA_ERROR_DEFINE (PLACEMENT_TYPE, "requested Placement (pointee) type not compatible with data or context"); + namespace { // implementation helpers diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index b4de007c6..e11496954 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -50,6 +50,7 @@ //#include "proc/mobject/session/locatingpin.hpp" //#include "proc/asset/pipe.hpp" #include "lib/util.hpp" +#include "lib/error.hpp" #include "lib/factory.hpp" #include "lib/itertools.hpp" #include "proc/mobject/placement.hpp" @@ -68,7 +69,8 @@ namespace mobject { namespace session { - LUMIERA_ERROR_DECLARE (NOT_IN_SESSION); ///< referring to a Placement not known to the current session + LUMIERA_ERROR_DECLARE (NOT_IN_SESSION); ///< referring to a Placement not known to the current session + LUMIERA_ERROR_DECLARE (PLACEMENT_TYPE); ///< requested Placement (pointee) type not compatible with data or context using lib::factory::RefcountFac; @@ -164,12 +166,26 @@ namespace session { /* === forwarding implementations of the templated API === */ + template + inline void + ___check_compatibleType(PlacementMO& questionable) + { + if (!questionable.isCompatible()) + throw lumiera::error::Logic ("Attempt to retrieve a Placement of specific type, " + "while the actual type of the pointee (MObject) " + "registered within the index isn't compatible with the " + "requested specific MObject subclass" + ,LUMIERA_ERROR_PLACEMENT_TYPE); + } + + template inline Placement& PlacementIndex::find (PlacementMO::Id id) const { PlacementMO& result (find (id)); - REQUIRE (INSTANCEOF (MO, &result) ); + + ___check_compatibleType (result); return static_cast&> (result); } diff --git a/src/proc/mobject/session/query-resolver.hpp b/src/proc/mobject/session/query-resolver.hpp index e19d3e5c7..7ea26ca14 100644 --- a/src/proc/mobject/session/query-resolver.hpp +++ b/src/proc/mobject/session/query-resolver.hpp @@ -306,7 +306,7 @@ namespace session { { PReso resultSet = resolver.issue (*this); Result first = resultSet->prepareResolution(); - Cursor& start = static_cast (first); + Cursor& start = static_cast (first); // note: type RES must be compatible! return iterator (resultSet, start); } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 3c99dcc38..ae2cdfcb3 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3044,10 +3044,10 @@ 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. Moreover, Placements are the actual content of the EDL(s) and Fixture and thus are small objects with //value semantics//. Many editing tasks include finding some Placement in the EDL or directly take a ref to some Placement. By acting on the Placement object, we can in some cases 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.
                                    +
                                    +
                                    [[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//&nbsp; 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 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
                                    +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
                                     * located at a specific point in time
                                     * related to and plugged into a specific output or global bus
                                     * defined to have a position within some [[context-dependant additional dimensions|PlacementDerivedDimension]] like
                                    @@ -3062,16 +3062,17 @@ Placements have //value semantics,// i.e. we don't stress the identity of a plac
                                     * the actual way of placing is implemented similar to the ''State Pattern'' by small embedded LocatingPin objects.
                                     * these LocatingPin objects form a ''decorator'' like chain
                                     * resolving into an ExplicitPlacement traverses this chain
                                    -* //overconstraining// a placement is not an error, we just stop traversing the chain (ignoring the remaining additional Placements) at the moment the position is completely defined. 
                                    -* we provide subclasses to be able to form collections of e.g. {{{Placement<Effect>}}}, but we don't stress polymorphism here. Instead we stick to value semantics and explicitly ''allow slicing'' (all subclasses have the same size and layout and differ only in their vtable contents). This is justified, because for the polymorphical treating of ~MObjects the visitor mechanism used by the builder and the EDL is sufficiant, and I don't want to add another layer of complexity by making Placement something like {{{boost::variant}}}.
                                    -* Why is the question how to access a ~MObject subinterface a Problem?
                                    +* //overconstraining// a placement is not an error, we just stop traversing the chain (ignoring the remaining additional Placements) at the moment the position is completely defined.
                                    +* placements can be treated like values, but incorporate an identity tag for the purpose of registering with the session.
                                    +* we provide subclasses to be able to form collections of e.g. {{{Placement<Effect>}}}, but we don't stress polymorphism here. &rarr; PlacementType
                                    +* Why was the question how to access a ~MObject subinterface a Problem?
                                     *# we want the EDL/Fixture to be a collection of Placements. This means, either we store pointers, or Placement needs to be //one// unique type!
                                     *# but if Placement is //a single type//, then we can get only MObjects from a Placement.
                                     *# then either we had to do everything by a visitor (which gets the concrete subtype dynamically), or we'd end up switching on type.
                                     
                                     
                                    -
                                    +
                                    An implementation facility used to keep track of individual Placements and their relations.
                                     Especially, the [[Session]] maintains such an index, allowing to use the (opaque) PlacementRef tags for referring to a specific "instance" of an MObject, //placed// in a unique way into the current session. And, moreover, this index allows for one placement referring to another placement, so to implement a //relative// placement mode. Because there is an index behind the scenes, it is possible to actually access such a referral in the reverse direction, which is necessary for implementing the desired placement behaviour (if an object instance used as anchor is moved, all objects placed relatively to it have to move accordingly, which necessitates finding those other objects).
                                     
                                    @@ -3104,6 +3105,14 @@ The placement index is utilized by editing operations and by executing the build
                                     * to create a PlacementRef (this is a variant of the "shared ptr from this"-problem)
                                     On second sight, this problem turns out to be more involved, because either we have to keep a second index table for the reverse lookup (memory address -> ID), or have to tie the placement by a back-link when adding it to the index/session data structure, or (alternatively) it forces us to store a copy of the ID //within// the placement itself. The last possibility seems to create the least impact; but implementing it this way effectively gears the implementation towards a hashtable based approach.
                                     
                                    +!!!Handling of Subtypes
                                    +While usually type relations don't carry over to smart-poitner like types, in case of Placement I used a special definition pattern to artificially create such type relations. Now, as we're going to copy and maintain Placements within the storage backing the index, the question is: do we actually store subtypes (all having the same size btw) or do we use a vtable based mechanism to recover the type information on access?
                                    +
                                    +Actually, the handling of placement types quite flexible; the actual hierarchy of Placement types can be determined in the //usage context// &mdash; it is not really stored within the placement, and there is no point in storing it within the index. Only the type of the //pointee//&nbsp; can be checked with the help of Placement's vtable.
                                    +
                                    +Thus, things just fall into place here, without the need of any additional implementation logic. The index stores {{{Placement<MObject>}}} instances. The usage context will provide a suitable meaning for more specifically typed placements, and as long as this is in line with the type relations on the pointee(s), as checked by the {{{Placement::isCompatible<TY>()}}} call, the placement relations will just work out right by the the cast happening automatically on results retrieval.
                                    +&rarr; see PlacementType
                                    +
                                     !implementation {{red{WIP}}}
                                     Consequently, we incorporate a random hash (implemented as {{{LUID}}}) into the individual placement, this way creating an distinguishable //placement identity,// which is //not retained on copying.// The actual ID tag is complemented by a compile time type (template parameter), thus allowing to pass on additional context information through API calls. Placements themselves use a vtable (and thus RTTI), allowing to re-discover the exact type at runtime. Any further relation information is contained within the placement's [[locating pins|LocatingPin]], thus, any further description records can be avoided by storing the placements immediately //within the index.// To summarise, the implementation is comprised of
                                     * a main table resolving hash-ID to storage location
                                    @@ -3144,6 +3153,29 @@ __note__: attaching a Sequence in multiple ways &rarr; [[causes scoping prob
                                     
                                     !Purpose of Placement scoping
                                     Similar to the common mechanisms of object visibility in programming languages, placement scopes guide the search for and resolution of properties of placement. Any such property //not defined locally// within the placement is queried ascending through the sequence of nested scopes. Thus, global definitions can be shadowed by local ones.
                                    +
                                    +
                                    +
                                    +
                                    Placement is a smart-ptr. As such, usually smart-pointers are templated on the pointee type, but a type relation between different target types doesn't carry over into a type relation on the corresponding smart-pointers. Now, as a [[Placement]] or a PlacementRef often is used to designate a specific "instance" of an MObject placed into the current session, the type parametrisation plays a crucial role when it comes to processing the objects contained within the session. Because the session deliberately has not much additional structure, besides the structure created by [[scopes and aggregations|PlacementScope]] within the session's contents.
                                    +
                                    +To this end, we're using a special definition pattern for Placements, so
                                    +* a placement can refer to a specific sub-Interface like Track, Clip, Effect
                                    +* a specialised placement can stand-in for the more generic type.
                                    +
                                    +!generic handling
                                    +Thus, ~MObject and Placement<~MObject> relate to the "everything is an object" view of affairs. More specific placements are registered, searched and retrieved within the session through this generic interface. In a similar vein, ~PlacementRef<~MObject> and MObjectRef is used on LayerSeparationInterfaces. This works, because it is possible to re-discover the more fine-grained target type. 
                                    +* ''active type rediscovery'' happens when a [[using visitors|VisitorUse]], which requires support by the pointee types (~MObject subclasses), so the visitor implementation is able to build a trampoline table to dispatch into a specifically typed context.
                                    +* ''passive type rediscovery'' is possible whenever the usage context //is already specifically typed.// Because in this case we can check the type (by RTTI) and filter out any placement not convertible to the type requested within the given context.
                                    +
                                    +!downcasting and slicing
                                    +Deliberately, all Placements have the same runtime size. Handling them value-like under certain circumstances is intended and acceptable. Of course then slicing on the level of the Placement will happen. But because the Placement actually is a smart-pointer, the pointee remains unaffected, and can be used later to re-gain the fully typed context.
                                    +
                                    +On the other hand, care has to be taken when ''downcasting'' a placement. When possible, this should be preceded by a {{{Placement::isCompatible<TY>()}}}-call, which checks based on the pointee's RTTI. Client code is encouraged to avoid explicit casting and rather rely on the provided facilities:
                                    +* invoking one of the templated access functions of the PlacementIndex
                                    +* using the QueryFocus to issue a specifically typed {{{ScopeQuery<TY>}}} (which yields an suitable iterator)
                                    +* create an specifically typed MObjectRef and bind it to some reference source (~Placement-ID, LUID, Placement instance within the session)
                                    +* implementing a visitor (~BuilderTool)
                                    +
                                     
                                    From feb4480f85cb5edb258c35518cc65d2e26c42963 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 28 Nov 2009 22:18:09 +0100 Subject: [PATCH 124/377] Scope handling within the PlacementIndex --- src/proc/mobject/session/placement-index.cpp | 121 ++++++++++++++++--- src/proc/mobject/session/placement-index.hpp | 37 ++++-- 2 files changed, 133 insertions(+), 25 deletions(-) diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index bda82bc90..ed6395a10 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -47,6 +47,7 @@ #include #include #include +//#include #include //#include @@ -60,16 +61,18 @@ namespace session { using std::tr1::unordered_map; using std::tr1::unordered_multimap; using lib::TypedAllocationManager; -//using util::getValue_or_default; + using util::getValue_or_default; //using util::contains; //using std::string; //using std::map; using std::make_pair; + using std::pair; using namespace lumiera; LUMIERA_ERROR_DEFINE (NOT_IN_SESSION, "referring to a Placement not known to the current session"); LUMIERA_ERROR_DEFINE (PLACEMENT_TYPE, "requested Placement (pointee) type not compatible with data or context"); + LUMIERA_ERROR_DEFINE (NONEMPTY_SCOPE, "Placement scope (still) contains other elements"); @@ -95,12 +98,22 @@ namespace session { typedef PlacementIndex::ID ID; + /** + * Storage and implementation + * backing the PlacementIndex + */ class PlacementIndex::Table { typedef shared_ptr PPlacement; + struct PlacementEntry + { + PPlacement element; + PPlacement scope; + }; + // using a hashtables to implement the index - typedef unordered_map > IDTable; + typedef unordered_map > IDTable; typedef std::tr1::unordered_multimap > ScopeTable; @@ -139,13 +152,25 @@ namespace session { fetch (ID id) const { REQUIRE (contains (id)); - PPlacement const& entry = getEntry_or_throw (placementTab_,id); + PPlacement const& entry = getEntry_or_throw (placementTab_,id).element; ENSURE (entry); ENSURE (id == entry->getID()); return *entry; } + PlacementMO& + fetchScope (ID id) const + { + REQUIRE (contains (id)); + PPlacement const& scope = getEntry_or_throw (placementTab_,id).scope; + + ENSURE (scope); + ENSURE (contains (scope->getID())); + return *scope; + } + + void clear() @@ -155,22 +180,83 @@ namespace session { placementTab_.clear(); } + /** Store a copy of the given Placement as new instance + * within the index, together with the Scope this Placement + * belongs to. + * @note we discard the specific type info. + * It can be rediscovered later with the help + * of the pointee's vtable + * @see Placement#isCompatible + */ ID addEntry (PlacementMO const& newObj, PlacementMO const& targetScope) { ID scopeID = targetScope.getID(); REQUIRE (contains (scopeID)); - /////////////////////////////////////////////////////////////////////TICKET #436 PPlacement newEntry = allocator_.create (newObj); ID newID = newEntry->getID(); ASSERT (!contains (newID)); - placementTab_[newID] = newEntry; + placementTab_[newID].element = newEntry; + placementTab_[newID].scope = placementTab_[scopeID].element; scopeTab_.insert (make_pair (scopeID, newID)); return newID; } + bool + removeEntry (ID id) + { + if (!contains (id)) + { + ENSURE (!util::contains(scopeTab_, id)); + return false; + } + + if (util::contains(scopeTab_, id)) + throw error::State ("Unable to remove the specified Placement, " + "because it defines an non-empty scope. " + "You need to delete any contents first." + ,LUMIERA_ERROR_NONEMPTY_SCOPE); ////////////////TICKET #197 + + ASSERT (contains (id)); + PlacementEntry toRemove = remove_base_entry (id); + remove_from_scope (toRemove.scope->getID(), id); + ENSURE (!util::contains(scopeTab_, id)); + ENSURE (!contains (id)); + return true; + } + + + private: + PlacementEntry + remove_base_entry (ID key) + { + IDTable::iterator pos = placementTab_.find (key); + REQUIRE (pos != placementTab_.end()); + PlacementEntry dataToRemove (pos->second); + placementTab_.erase(pos); + return dataToRemove; + } + + void + remove_from_scope (ID scopeID, ID entryID) + { + typedef ScopeTable::iterator Pos; + pair searchRange = scopeTab_.equal_range(scopeID); + + Pos pos = searchRange.first; + Pos end = searchRange.second; + for ( ; pos!=end; ++pos) + if (pos->second == entryID) + { + scopeTab_.erase(pos); + return; + } + + NOTREACHED(); + } + }; @@ -212,20 +298,22 @@ namespace session { PlacementMO& PlacementIndex::find (ID id) const { - if (!contains (id)) - throw error::Invalid ("Accessing Placement not registered within the index" - ,LUMIERA_ERROR_NOT_IN_SESSION); ///////////////////////TICKET #197 - + __check_knownID(*this,id); return pTab_->fetch (id); } + /** retrieve the Scope information + * registered alongside with the denoted Placement. + * @throw error::Invalid when the given ID isn't registered + * @note root is it's own scope, per definition. + */ PlacementMO& - PlacementIndex::getScope (ID) const + PlacementIndex::getScope (ID id) const { - UNIMPLEMENTED ("Secondary core operation of PlacmentIndex: find the 'parent' Placement by using the Placement relation index"); - /// decision: root is his own scope + __check_knownID(*this,id); + return pTab_->fetchScope (id); } @@ -263,10 +351,15 @@ namespace session { } + /** Remove and discard a Placement (Object "instance") from the index. + * Usually this means removing this Object from the session. + * @return \c true if actually removed an object. + * @throw error::State if the object to be removed is an non-empty scope + */ bool - PlacementIndex::remove (ID) + PlacementIndex::remove (ID id) { - UNIMPLEMENTED ("remove a information record from PlacementIndex, and also de-register any placement-relations bound to it"); + return pTab_->removeEntry (id); } diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index e11496954..823d826fd 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -71,6 +71,7 @@ namespace session { LUMIERA_ERROR_DECLARE (NOT_IN_SESSION); ///< referring to a Placement not known to the current session LUMIERA_ERROR_DECLARE (PLACEMENT_TYPE); ///< requested Placement (pointee) type not compatible with data or context + LUMIERA_ERROR_DECLARE (NONEMPTY_SCOPE); ///< Placement scope (still) contains other elements using lib::factory::RefcountFac; @@ -166,17 +167,31 @@ namespace session { /* === forwarding implementations of the templated API === */ - template - inline void - ___check_compatibleType(PlacementMO& questionable) - { - if (!questionable.isCompatible()) - throw lumiera::error::Logic ("Attempt to retrieve a Placement of specific type, " - "while the actual type of the pointee (MObject) " - "registered within the index isn't compatible with the " - "requested specific MObject subclass" - ,LUMIERA_ERROR_PLACEMENT_TYPE); - } + + namespace { // shortcuts... + + template + inline void + ___check_compatibleType(PlacementMO& questionable) + { + if (!questionable.isCompatible()) + throw lumiera::error::Logic ("Attempt to retrieve a Placement of specific type, " + "while the actual type of the pointee (MObject) " + "registered within the index isn't compatible with the " + "requested specific MObject subclass" + ,LUMIERA_ERROR_PLACEMENT_TYPE); + } + + inline void + __check_knownID(PlacementIndex const& idx, PlacementMO::ID id) + { + if (!idx.contains (id)) + throw lumiera::error::Invalid ("Accessing Placement not registered within the index" + ,LUMIERA_ERROR_NOT_IN_SESSION); ///////////////////////TICKET #197 + } + }//(End) shortcuts + + template From 488039c4c6426d5c3d4c2db480dc0982aeca74f4 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 28 Nov 2009 23:37:58 +0100 Subject: [PATCH 125/377] cleanup and write tests covering the newly implemented stuff --- src/proc/mobject/session/placement-index.cpp | 43 ++++---- src/proc/mobject/session/placement-index.hpp | 2 +- .../mobject/session/placement-index-test.cpp | 97 +++++++++++++++++-- .../proc/mobject/session/test-scopes.cpp | 17 ++-- .../proc/mobject/session/testclip.hpp | 2 +- 5 files changed, 121 insertions(+), 40 deletions(-) diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index ed6395a10..a9a48231a 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -61,7 +61,7 @@ namespace session { using std::tr1::unordered_map; using std::tr1::unordered_multimap; using lib::TypedAllocationManager; - using util::getValue_or_default; +//using util::getValue_or_default; //using util::contains; //using std::string; //using std::map; @@ -76,22 +76,6 @@ namespace session { - namespace { // implementation helpers - - template - inline typename MAP::mapped_type const& - getEntry_or_throw (MAP& map, typename MAP::key_type const& key) - { - typename MAP::const_iterator pos = map.find (key); - if (pos == map.end()) - throw error::Logic("lost a Placement expected to be registered in the index."); - - return pos->second; - } - - } // (End) impl.helpers - - /* some type shorthands */ typedef PlacementIndex::PlacementMO PlacementMO; typedef PlacementIndex::PRef PRef; @@ -152,7 +136,7 @@ namespace session { fetch (ID id) const { REQUIRE (contains (id)); - PPlacement const& entry = getEntry_or_throw (placementTab_,id).element; + PPlacement const& entry = base_entry(id).element; ENSURE (entry); ENSURE (id == entry->getID()); @@ -163,7 +147,7 @@ namespace session { fetchScope (ID id) const { REQUIRE (contains (id)); - PPlacement const& scope = getEntry_or_throw (placementTab_,id).scope; + PPlacement const& scope = base_entry(id).scope; ENSURE (scope); ENSURE (contains (scope->getID())); @@ -189,9 +173,8 @@ namespace session { * @see Placement#isCompatible */ ID - addEntry (PlacementMO const& newObj, PlacementMO const& targetScope) + addEntry (PlacementMO const& newObj, ID scopeID) { - ID scopeID = targetScope.getID(); REQUIRE (contains (scopeID)); PPlacement newEntry = allocator_.create (newObj); @@ -229,10 +212,22 @@ namespace session { private: + typedef IDTable::const_iterator Slot; + + PlacementEntry const& + base_entry (ID key) const + { + Slot pos = placementTab_.find (key); + if (pos == placementTab_.end()) + throw error::Logic("lost a Placement expected to be registered in the index."); + + return pos->second; + } + PlacementEntry remove_base_entry (ID key) { - IDTable::iterator pos = placementTab_.find (key); + Slot pos = placementTab_.find (key); REQUIRE (pos != placementTab_.end()); PlacementEntry dataToRemove (pos->second); placementTab_.erase(pos); @@ -242,7 +237,7 @@ namespace session { void remove_from_scope (ID scopeID, ID entryID) { - typedef ScopeTable::iterator Pos; + typedef ScopeTable::const_iterator Pos; pair searchRange = scopeTab_.equal_range(scopeID); Pos pos = searchRange.first; @@ -340,7 +335,7 @@ namespace session { * @note the newly added Placement has an identity of its own. */ ID - PlacementIndex::insert (PlacementMO const& newObj, PlacementMO const& targetScope) + PlacementIndex::insert (PlacementMO const& newObj, ID targetScope) { if (!contains (targetScope)) throw error::Logic ("Specified a non-registered Placement as scope " diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index 823d826fd..1e14c09ba 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -139,7 +139,7 @@ namespace session { /* == mutating operations == */ - ID insert (PlacementMO const& newObj, PlacementMO const& targetScope); + ID insert (PlacementMO const& newObj, ID targetScope); bool remove (PlacementMO&); bool remove (ID); diff --git a/tests/components/proc/mobject/session/placement-index-test.cpp b/tests/components/proc/mobject/session/placement-index-test.cpp index d01e61da6..54cbe8d86 100644 --- a/tests/components/proc/mobject/session/placement-index-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-test.cpp @@ -22,6 +22,7 @@ #include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" //#include "proc/asset/media.hpp" //#include "proc/mobject/session.hpp" //#include "proc/mobject/session/edl.hpp" @@ -29,7 +30,7 @@ #include "proc/mobject/session/testclip.hpp" #include "proc/mobject/placement.hpp" //#include "proc/mobject/explicitplacement.hpp" -//#include "lib/util.hpp" +#include "lib/util.hpp" //#include //#include @@ -37,6 +38,7 @@ //using boost::format; //using lumiera::Time; //using util::contains; +using util::isSameObject; using std::string; //using std::cout; @@ -60,20 +62,36 @@ namespace test { */ class PlacementIndex_test : public Test { - typedef shared_ptr PIdx; virtual void run (Arg) { - PIdx index (PlacementIndex::create()); + PPIdx index (PlacementIndex::create()); ASSERT (index); - /////////////////////////////////TODO - checkSimpleInsert (index); + checkSimpleInsertRemove (index); + has_size (0, index); + + checkSimpleAccess (index); + has_size (1, index); + + checkScopeHandling (index); + has_size (7, index); + + ////////////////////////////TODO + + index->clear(); + has_size (0, index); } void - checkSimpleInsert (PIdx index) + has_size(uint siz, PPIdx index) + { + ASSERT (siz == index->size()); + } + + void + checkSimpleInsertRemove (PPIdx index) { PMO clip = TestClip::create(); PMO& root = index->getRoot(); @@ -90,6 +108,73 @@ namespace test { ASSERT (!index->contains (clip)); ASSERT ( index->contains (root)); } + + + void + checkSimpleAccess (PPIdx index) + { + PMO testObj = TestClip::create(); + PMO& root = index->getRoot(); + PMO::ID elmID = index->insert (testObj, root); + + PMO& elm = index->find(elmID); + ASSERT (elmID == elm.getID()); + ASSERT (!isSameObject (elm,testObj)); // note: placements are registered as copy + ASSERT (elm == testObj); // they are semantically equivalent + ASSERT (elmID != testObj.getID()); // but have a distinct identity + + PMO::ID elmID2 = index->insert(testObj, root); + ASSERT (elmID != elmID); // ...and each insert creates a new instance + ASSERT (testObj == index->find(elmID2)); + ASSERT (!isSameObject (elm, index->find(elmID2))); + ASSERT ( isSameObject (elm, index->find(elmID ))); + + // can also re-access objects by previous ref + ASSERT ( isSameObject (elm, index->find(elm))); + } + + + void + checkScopeHandling (PPIdx index) + { + PMO testObj = TestClip::create(); + PMO& root = index->getRoot(); + + typedef PMO::ID ID; + ID e1 = index->insert (testObj, root); + ID e11 = index->insert (testObj, e1); + ID e12 = index->insert (testObj, e1); + ID e13 = index->insert (testObj, e1); + ID e131 = index->insert (testObj, e13); + ID e132 = index->insert (testObj, e13); + ID e133 = index->insert (testObj, e13); + ID e1331 = index->insert (testObj, e133); + + ASSERT (root == index->getScope(e1)); + ASSERT (e1 == index->getScope(e11).getID()); + ASSERT (e1 == index->getScope(e12).getID()); + ASSERT (e1 == index->getScope(e13).getID()); + ASSERT (e13 == index->getScope(e131).getID()); + ASSERT (e13 == index->getScope(e132).getID()); + ASSERT (e13 == index->getScope(e133).getID()); + ASSERT (e133 == index->getScope(e1331).getID()); + ASSERT (e1 != e13); + ASSERT (e13 != e133); + + ASSERT (index->getScope(e11) == index->getScope(index->find(e11))); + ASSERT (index->getScope(e131) == index->getScope(index->find(e131))); + + VERIFY_ERROR(NONEMPTY_SCOPE, index->remove(e13) ); // can't remove a scope-constituting element + VERIFY_ERROR(NONEMPTY_SCOPE, index->remove(e133) ); + + ASSERT (index->contains(e1331)); + ASSERT (index->remove(e1331)); + ASSERT (!index->contains(e1331)); + ASSERT (!index->remove(e1331)); + + ASSERT (index->remove(e133)); // but can remove an scope, after emptying it + ASSERT (!index->contains(e133)); + } }; diff --git a/tests/components/proc/mobject/session/test-scopes.cpp b/tests/components/proc/mobject/session/test-scopes.cpp index 0666ae0b8..f0e7cd1b8 100644 --- a/tests/components/proc/mobject/session/test-scopes.cpp +++ b/tests/components/proc/mobject/session/test-scopes.cpp @@ -68,15 +68,16 @@ namespace test { SessionServiceMockIndex::reset_PlacementIndex(index); PMO& root = index->getRoot(); - index->insert (p1, root); - index->insert (p2, p1 ); - index->insert (p3, p2 ); - index->insert (p4, p3 ); - index->insert (p5, p4 ); + typedef PMO::ID ID; + ID i1 = index->insert (p1, root); + ID i2 = index->insert (p2, i1 ); + ID i3 = index->insert (p3, i2 ); + ID i4 = index->insert (p4, i3 ); + ID i5 = index->insert (p5, i4 ); - index->insert (ps1,root); - index->insert (ps2,root); - index->insert (ps3, ps2); + ID is1 = index->insert (ps1,root); + ID is2 = index->insert (ps2,root); + ID is3 = index->insert (ps3, is2); return index; } diff --git a/tests/components/proc/mobject/session/testclip.hpp b/tests/components/proc/mobject/session/testclip.hpp index dbac88087..34fa5154f 100644 --- a/tests/components/proc/mobject/session/testclip.hpp +++ b/tests/components/proc/mobject/session/testclip.hpp @@ -46,7 +46,7 @@ namespace test { /** * Sample or Test Clip for checking * various EDL, session and builder operations. - * @todo make this usable as Mock object to record invoked operations. + * @todo maybe use this as Mock object to record invoked operations? * */ class TestClip : public mobject::session::Clip From 624820b81750dd9dc71d66e6892c4873bf8aef0b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 29 Nov 2009 18:16:29 +0100 Subject: [PATCH 126/377] considerations regarding the Binding of sequences to timelines --- wiki/renderengine.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/wiki/renderengine.html b/wiki/renderengine.html index ae2cdfcb3..bae402625 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -777,12 +777,20 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS } //}}}
                                    -
                                    +
                                    Sometimes, two entities within the [[Session]] are deliberately associated, and this association has to carry some specific mappings between properties or facilities within the entities to be linked together. When this connection isn't just the [[Placement]] of an object, and isn't just a logical or structural relationship either &mdash; then we create an explicit Binding object to be stored into the session.
                                     * When connecting a [[Sequence|EDL]] to a certain [[Timeline]], we also establish a mapping between the possible media stream channels produced by the sequence and the real output slots found within the timeline.
                                     * similarly, using a sequence within a [[meta-clip|VirtualClip]] requires to remember such a mapping.
                                     * another example is the root [[scope|PlacementScope]], which (conceptually) is a link between the definition part of the Session and the graph of MObjects, which are the session's contents.
                                     
                                    +!Properties of a Binding
                                    +Binding is a relation entity, maintaining a link between parts of the session. This 1:1 relation may be part of a n:1 (or maybe even n:m?) relation. In addition to representing this link, a binding allows to maintain a set of ''mappings'' attached to this link.
                                    +
                                    +This creates a typing related problem: In order to maintain the link and the mappings, in each case we need a common denominator to subsume the elements to be maintained.
                                    +* in the case of the basic link, this common denominator is given by the basic structure of the HighLevelModel: ~MObjects attached by ~Placements. Consequently, the link maintained through a binding is limited to linking together first-class entities within the model, and the implementation is tied into the existing mechanisms for associating Placements (&rarr; PlacementScope and PlacementIndex)
                                    +* in the case of the attached mappings it seems we're best off limiting ourselves to symbolic mappings (ID mappings). Because, going beyond that would either create sub-groupings (based on varying target types to be mapped), or push the »everything is an object« approach beyond the beneficial level.
                                    +
                                    +!Implementation
                                     On the implementation side, we use a special kind of MObject, acting as an anchor and providing an unique identity. Like any ~MObject, actually a placement establishes the connection and the scope, and typically constitutes a nested scope (e.g. the scope of all objects //within// the sequence to be bound into a timeline)
                                     
                                    From fc16de332f06e84b4b2bd71df9ec77fa1c7e2854 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sun, 29 Nov 2009 17:55:20 -0500 Subject: [PATCH 127/377] convert lumiera_thread_class to using the enum string trick and use it in a test --- src/backend/threads.c | 7 +++++++ src/backend/threads.h | 31 +++++++++++++++++++++---------- tests/30backend-threadpool.tests | 2 ++ tests/backend/test-threadpool.c | 6 +++--- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 5d849943f..4fe0c8ac5 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -46,6 +46,13 @@ NOBUG_DEFINE_FLAG_PARENT (threads, threads_dbg); /*TODO insert a suitable/better //code goes here// +#define LUMIERA_THREAD_CLASS(name) #name, +// enum string trick: expands as an array of thread class name strings +const char* lumiera_threadclass_names[] = { + LUMIERA_THREAD_CLASSES +}; + +#undef LUMIERA_THREAD_CLASS struct lumiera_thread_mockup { diff --git a/src/backend/threads.h b/src/backend/threads.h index 4c15a8ad8..ce9a7605b 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -46,6 +46,21 @@ typedef struct lumiera_thread_struct lumiera_thread; typedef lumiera_thread* LumieraThread; +// this is used for an enum string trick +#define LUMIERA_THREAD_CLASSES \ + /** mostly idle, low latency **/ \ + LUMIERA_THREAD_CLASS(INTERACTIVE) \ + /** busy at average priority **/ \ + LUMIERA_THREAD_CLASS(WORKER) \ + /** busy, soft realtime, high priority **/ \ + LUMIERA_THREAD_CLASS(URGENT) \ + /** high latency, background jobs **/ \ + LUMIERA_THREAD_CLASS(BATCH) \ + /** Something to do when there is really nothing else to do **/ \ + LUMIERA_THREAD_CLASS(IDLE) + +// enum string trick: expands as an enum of thread classes +#define LUMIERA_THREAD_CLASS(name) LUMIERA_THREADCLASS_##name, /** * Thread classes. @@ -54,16 +69,7 @@ typedef lumiera_thread* LumieraThread; */ enum lumiera_thread_class { - /** mostly idle, low latency **/ - LUMIERA_THREADCLASS_INTERACTIVE, - /** busy at average priority **/ - LUMIERA_THREADCLASS_WORKER, - /** busy, soft realtime, high priority **/ - LUMIERA_THREADCLASS_URGENT, - /** high latency, background jobs **/ - LUMIERA_THREADCLASS_BATCH, - /** Something to do when there is really nothing else to do **/ - LUMIERA_THREADCLASS_IDLE, + LUMIERA_THREAD_CLASSES /** this just denotes the number of classes listed above, it is used to create arrays **/ LUMIERA_THREADCLASS_COUNT, @@ -79,6 +85,11 @@ enum lumiera_thread_class LUMIERA_THREAD_OR_NOT = 1<<16 }; +#undef LUMIERA_THREAD_CLASS + +// defined in threads.c +extern const char* lumiera_threadclass_names[]; + /** * Thread state. * These are the only states our threads can be in. diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index ca2464bfe..e4f4e4005 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -9,6 +9,8 @@ TEST "Acquire/Release test" basic-acquire-release <kind); + ECHO("thread 1 kind=%s", lumiera_threadclass_names[t1->kind]); CHECK(LUMIERA_THREADCLASS_INTERACTIVE == t1->kind); //ECHO("thread 1 state=%d", t1->state); CHECK(LUMIERA_THREADSTATE_IDLE == t1->state); - //ECHO("thread 2 kind=%d", t2->kind); - CHECK(LUMIERA_THREADCLASS_IDLE == t2->kind); + ECHO("thread 2 kind=%s", lumiera_threadclass_names[t2->kind]); + CHECK(LUMIERA_THREADCLASS_IDLE == t2->kind); //ECHO("thread 2 state=%d", t2->state); CHECK(LUMIERA_THREADSTATE_IDLE == t2->state); From eedfafb0d07f3c17756d8d8c9c9c3e7177489e1b Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sun, 29 Nov 2009 18:06:14 -0500 Subject: [PATCH 128/377] convert lumiera_thread_state to using the enum string trick and use it in a test --- src/backend/threads.c | 6 ++++++ src/backend/threads.h | 16 +++++++++++++--- tests/30backend-threadpool.tests | 2 ++ tests/backend/test-threadpool.c | 4 ++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 4fe0c8ac5..b943d55fc 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -54,6 +54,12 @@ const char* lumiera_threadclass_names[] = { #undef LUMIERA_THREAD_CLASS +#define LUMIERA_THREAD_STATE(name) #name, +const char* lumiera_threadstate_names[] = { + LUMIERA_THREAD_STATES +}; +#undef LUMIERA_THREAD_STATE + struct lumiera_thread_mockup { void (*fn)(void*); diff --git a/src/backend/threads.h b/src/backend/threads.h index ce9a7605b..416e160a0 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -90,18 +90,28 @@ enum lumiera_thread_class // defined in threads.c extern const char* lumiera_threadclass_names[]; +#define LUMIERA_THREAD_STATES \ + LUMIERA_THREAD_STATE(IDLE) \ + LUMIERA_THREAD_STATE(RUNNING) \ + LUMIERA_THREAD_STATE(ERROR) + +#define LUMIERA_THREAD_STATE(name) LUMIERA_THREADSTATE_##name, + /** * Thread state. * These are the only states our threads can be in. */ typedef enum { - LUMIERA_THREADSTATE_IDLE, - LUMIERA_THREADSTATE_RUNNING, - LUMIERA_THREADSTATE_ERROR + LUMIERA_THREAD_STATES } lumiera_thread_state; +#undef LUMIERA_THREAD_STATE + +// defined in threads.c +extern const char* lumiera_threadstate_names[]; + #include "threadpool.h" /** diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index e4f4e4005..c136aff42 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -10,7 +10,9 @@ err: start by initializing the threadpool err: acquiring thread 1 err: acquiring thread 2 err: thread 1 kind=INTERACTIVE +err: thread 1 state=IDLE err: thread 2 kind=IDLE +err: thread 2 state=IDLE err: releasing thread 1 err: thread 1 has been released err: releasing thread 2 diff --git a/tests/backend/test-threadpool.c b/tests/backend/test-threadpool.c index 0a4319bfb..0c516e306 100644 --- a/tests/backend/test-threadpool.c +++ b/tests/backend/test-threadpool.c @@ -46,11 +46,11 @@ TEST ("basic-acquire-release") ECHO("thread 1 kind=%s", lumiera_threadclass_names[t1->kind]); CHECK(LUMIERA_THREADCLASS_INTERACTIVE == t1->kind); - //ECHO("thread 1 state=%d", t1->state); + ECHO("thread 1 state=%s", lumiera_threadstate_names[t1->state]); CHECK(LUMIERA_THREADSTATE_IDLE == t1->state); ECHO("thread 2 kind=%s", lumiera_threadclass_names[t2->kind]); CHECK(LUMIERA_THREADCLASS_IDLE == t2->kind); - //ECHO("thread 2 state=%d", t2->state); + ECHO("thread 2 state=%s", lumiera_threadstate_names[t2->state]); CHECK(LUMIERA_THREADSTATE_IDLE == t2->state); ECHO("releasing thread 1"); From afe135f43e9e89a7eaea022294705f99edf40677 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 2 Dec 2009 13:48:08 -0500 Subject: [PATCH 129/377] add a lock around thread pool list access in lumiera_threadpool_release_thread() --- src/backend/threadpool.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index ece74d92e..7c7d48fd8 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -133,9 +133,8 @@ lumiera_threadpool_release_thread(LumieraThread thread) REQUIRE (thread, "invalid thread given"); REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); - // TOOD: currently, locking produces memory leaks - // LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[thread->kind].lock) - // { + LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[thread->kind].lock) + { REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); llist_insert_head(&threadpool.pool[thread->kind].list, &thread->node); threadpool.pool[thread->kind].working_thread_count--; @@ -146,7 +145,7 @@ lumiera_threadpool_release_thread(LumieraThread thread) threadpool.pool[thread->kind].idle_thread_count, llist_count(&threadpool.pool[thread->kind].list)); // REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); - // } + } } /* From 098d801d00e87ecea9590ada88b2571a30d9c9f9 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 2 Dec 2009 22:21:49 -0500 Subject: [PATCH 130/377] give each thread pool a separate pthread_attr_t structure to configure --- src/backend/threadpool.c | 10 +++++++++- src/backend/threadpool.h | 1 + src/backend/threads.c | 23 ++++++----------------- src/backend/threads.h | 3 ++- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 7c7d48fd8..66ecd4e33 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -61,6 +61,12 @@ lumiera_threadpool_init(unsigned limit) threadpool.pool[i].max_threads = limit; threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; + + //TODO: configure each pools' pthread_attrs appropriately + pthread_attr_init (&threadpool.pool[i].pthread_attrs); + pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); + //cancel... + lumiera_mutex_init(&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); } } @@ -79,6 +85,7 @@ lumiera_threadpool_destroy(void) ECHO ("destroying the pool mutex"); lumiera_mutex_destroy (&threadpool.pool[i].lock, &NOBUG_FLAG (threadpool)); ECHO ("pool mutex destroyed"); + pthread_attr_destroy (&threadpool.pool[i].pthread_attrs); } } @@ -97,7 +104,8 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, if (threadpool.pool[kind].working_thread_count + threadpool.pool[kind].idle_thread_count < threadpool.pool[kind].max_threads) { - ret = lumiera_thread_new (kind, NULL, purpose, flag); + ret = lumiera_thread_new (kind, NULL, purpose, flag, + &threadpool.pool[kind].pthread_attrs); threadpool.pool[kind].working_thread_count++; ENSURE (ret, "did not create a valid thread"); } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index b978e9e57..03b56a4fe 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -74,6 +74,7 @@ struct lumiera_threadpool_struct unsigned max_threads; unsigned working_thread_count; unsigned idle_thread_count; + pthread_attr_t pthread_attrs; } pool[LUMIERA_THREADCLASS_COUNT]; }; diff --git a/src/backend/threads.c b/src/backend/threads.c index b943d55fc..62f0d14a6 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -93,16 +93,6 @@ static void* pthread_runner (void* thread) } #endif -static pthread_once_t attr_once = PTHREAD_ONCE_INIT; -static pthread_attr_t attrs; - -static void thread_attr_init (void) -{ - pthread_attr_init (&attrs); - pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_DETACHED); - //cancel ... -} - #if 0 // TODO: rewrite this using lumiera_threadpool_acquire() LumieraThread @@ -171,27 +161,26 @@ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, LumieraReccondition finished, const char* purpose, - struct nobug_flag* flag) + struct nobug_flag* flag, + pthread_attr_t* attrs) { // TODO: do something with these: (void) purpose; (void) flag; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); - - if (attr_once == PTHREAD_ONCE_INIT) - pthread_once (&attr_once, thread_attr_init); + REQUIRE (attrs, "invalid pthread attributes structure passed"); //REQUIRE (finished, "invalid finished flag passed"); + LumieraThread self = lumiera_malloc (sizeof (*self)); llist_init(&self->node); self->finished = finished; self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; - //REQUIRE (&attrs); - //REQUIRE (&thread_loop); - int error = pthread_create (&self->id, &attrs, &thread_loop, self); + //REQUIRE (thread_loop); + int error = pthread_create (&self->id, attrs, &thread_loop, self); ENSURE(error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror(error)); if (error) { diff --git a/src/backend/threads.h b/src/backend/threads.h index 416e160a0..e8b774299 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -139,7 +139,8 @@ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, LumieraReccondition finished, const char* purpose, - struct nobug_flag* flag); + struct nobug_flag* flag, + pthread_attr_t* attrs); LumieraThread lumiera_thread_destroy (LumieraThread self); From 41bb8b7e78b8df8f6724ce1b78edb0059d87324a Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 3 Dec 2009 09:29:56 -0500 Subject: [PATCH 131/377] make a TODO note about the finished condition variable --- src/backend/threads.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/threads.h b/src/backend/threads.h index e8b774299..ac8a163fd 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -124,6 +124,7 @@ struct lumiera_thread_struct // void (*function)(void*); // void* arg; pthread_t id; + // TODO: maybe this condition variable should be renamed when we have a better understanding of how it will be used LumieraReccondition finished; // the following member could have been called "class" except that it would conflict with C++ keyword // as consequence, it's been decided to leave the type name containing the word "class", From 54d0b3035820e00da3f537f0112560ef99c0e9e0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 8 Dec 2009 04:08:11 +0100 Subject: [PATCH 132/377] Planing the top-level entities of the Session... --- wiki/renderengine.html | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/wiki/renderengine.html b/wiki/renderengine.html index bae402625..153f68ad7 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -777,7 +777,7 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS } //}}}
                                    -
                                    +
                                    Sometimes, two entities within the [[Session]] are deliberately associated, and this association has to carry some specific mappings between properties or facilities within the entities to be linked together. When this connection isn't just the [[Placement]] of an object, and isn't just a logical or structural relationship either &mdash; then we create an explicit Binding object to be stored into the session.
                                     * When connecting a [[Sequence|EDL]] to a certain [[Timeline]], we also establish a mapping between the possible media stream channels produced by the sequence and the real output slots found within the timeline.
                                     * similarly, using a sequence within a [[meta-clip|VirtualClip]] requires to remember such a mapping.
                                    @@ -790,6 +790,16 @@ This creates a typing related problem: In order to maintain the link and the map
                                     * in the case of the basic link, this common denominator is given by the basic structure of the HighLevelModel: ~MObjects attached by ~Placements. Consequently, the link maintained through a binding is limited to linking together first-class entities within the model, and the implementation is tied into the existing mechanisms for associating Placements (&rarr; PlacementScope and PlacementIndex)
                                     * in the case of the attached mappings it seems we're best off limiting ourselves to symbolic mappings (ID mappings). Because, going beyond that would either create sub-groupings (based on varying target types to be mapped), or push the »everything is an object« approach beyond the beneficial level.
                                     
                                    +!Critique {{red{WIP 12/09}}}
                                    +Now I'm in doubt if there is any point in treating the "binding" in a abstract fashion. Is there any common denominator? It seems there is just a common conceptional pattern, but mapping this pattern onto distinct types (classes) seems unnecessary. Rather, we have tree very similar MObjects:
                                    +* ModelRootMO
                                    +* BindingMO
                                    +* [[Track]]
                                    +While each of these actually represents a high-level concept (the session, the timeline(s) the sequence(s)) and moreover links to other parts and provides mappings, it seems there is no re-usable similarity at the code level.
                                    +//According to this reasoning, I should proceed rather with these tree distinct entities and postpone any saearch for similarities to a later refactoring round.//
                                    +
                                    +&rarr; see also SessionInterface
                                    +
                                     !Implementation
                                     On the implementation side, we use a special kind of MObject, acting as an anchor and providing an unique identity. Like any ~MObject, actually a placement establishes the connection and the scope, and typically constitutes a nested scope (e.g. the scope of all objects //within// the sequence to be bound into a timeline)
                                     
                                    @@ -2317,6 +2327,9 @@ For the case here in question this seems to be the ''resource allocation is cons And, last but not least, doing large scale allocations is the job of the backend. Exceptions being long-lived objects, like the Session or the EDL, which are created once and don't bear the danger of causing memory pressure. Besides, the ProcLayer code shouldn't issue "new" and "delete" when it comes in hand, rather it should use some centralized [[Factories]] for all allocation and freeing, so we can redirect these calls down to the backend, which may use pooling or special placement allocators or the like. The rationale is, for modern hardware/architectures, care has to be taken with heap allocations, esp. with many small objects and irregular usage patterns.
                                    +
                                    +
                                    A special kind of MObject, serving as a marker or entry point at the root of the HighLevelModel. As any ~MObject, it is attached to the model by a [[Placement]]. And in this special case, this placement froms the ''root scope'' of the model, thus containing any other PlacementScope (e.g. tracks, clips with effects,...)
                                    +
                                    Based on practical experiences, Ichthyo tends to consider Multichannel Media as the base case, while counting media files providing just one single media stream as exotic corner cases. This may seem counter intuitive at first sight; you should think of  it as an attempt to avoid right from start some of the common shortcomings found in many video editors, especially
                                     * having to deal with keeping a "link" between audio and video clips
                                    @@ -3015,12 +3028,12 @@ The GUI can connect the viewer(s) to some pipe (and moreover can use [[probe poi
                                     
                                     
                                    -
                                    +
                                    !Identification
                                     Pipes are distinct objects and can be identified by their asset ~IDs. Besides, as for all [[structural assets|StructAsset]] there are extended query capabilities, including a symbolic pipe-id and a media (stream) type id. Any pipe can accept and deliver exactly one media stream kind (which may be inherently structured though, e.g. spatial sound systems or stereoscopic video)
                                     
                                     !creating pipes
                                    -Pipe assets are created automatically by being used and referred. The [[Session]] holds a collection of global pipes ({{red{todo: implementation missing as of 5/08}}}), and further pipes can be created by using a new pipe reference in some placement. Moreover, every clip has an (implicit) [[source port|ClipSourcePort]], which will appear as pipe asset when first used (referred) while [[building|BuildProcess]]. Note that creating a new pipe implies using a [[processing pattern|ProcPatt]], which will be queried from the [[Defaults Manager|DefaultsManagement]] (resulting in the use of some preconfigured pattern or maybe the creation of a new ProcPatt object if necessary)
                                    +Pipe assets are created automatically by being used and referred. Each [[Timeline]] holds a collection of global pipes, attached to the BindingMO, which is the representation or attachement point of the Timeline within the HighLevelModel ([[Session]]) ({{red{todo: implementation missing as of 11/09}}}), and further pipes can be created by using a new pipe reference in some placement. Moreover, every clip has an (implicit) [[source port|ClipSourcePort]], which will appear as pipe asset when first used (referred) while [[building|BuildProcess]]. Note that creating a new pipe implies using a [[processing pattern|ProcPatt]], which will be queried from the [[Defaults Manager|DefaultsManagement]] (resulting in the use of some preconfigured pattern or maybe the creation of a new ProcPatt object if necessary)
                                     
                                     !removal
                                     Deleting a Pipe is an advanced operation, because it includes finding and "detaching" all references, otherwise the pipe will leap back into existence immediately. Thus, global pipe entries in the Session and pipe references in [[locating pins|LocatingPin]] within any placement have to be removed, while clips using a given source port will be disabled. {{red{todo: implementation deferred}}}
                                    @@ -4025,7 +4038,7 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl
                                     
                                     {{red{TODO...}}}
                                    -
                                    +
                                    "Session Interface", when used in a more general sense, denotes a compound of several interfaces and facilities, together forming the primary access point to the user visible contents and state of the editing project.
                                     * the API of the session class
                                     * the accompanying management interface (SessionManager API)
                                    @@ -4040,7 +4053,15 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl
                                     ** Automation
                                     * the [[command|CommandHandling]] interface, including the [[UNDO|UndoManager]] facility
                                     
                                    -{{red{WIP ... just emerging}}}
                                    +{{red{WIP ... just emerging}}} + +!generic and explicit API +The HighLevelModel exposes two kinds of interfaces (which are interconnected btw): A generic, but somewhat low-level API, which is good for processing, and a more explicit API providing access to some meaningful entities within the model. Indeed, the latter (explicit top level entities) can be seen as a ''facade interface'' to the generic structures: +* the [[Session]] object itself corresponds to the ModelRootMO +* the one (or multiple) [[Timeline]] objects correspond to the BindingMO instances attached immediately below the model root +* the [[sequences|EDL]] bound into these timelines (by the ~BindingMOs) correspond to the top level [[Track]]-~MObjects within each of these sequences. +Thus, there is a convenient and meaningful access path through these facade objects, which of course actually is implemented by forwarding to the actual model elements (root, bindings, tracks) +
                                    The current [[Session]] is the root of any state found within Proc-Layer. Thus, events defining the session's lifecycle influence and synchronise the cooperative behaviour of the entities within the model, the ProcDispatcher, [[Fixture]] and any facility below.
                                    @@ -5685,11 +5706,12 @@ Of course, we can place other ~MObjects relative to some track (that's the main
                                     &rarr; [[Anatomy of the high-level model|HighLevelModel]]
                                     
                                    -
                                    +
                                    What //exactly&nbsp;// is denoted by &raquo;Track&laquo; &mdash; //basically&nbsp;// a working area to group media objects placed at this track at various time positions &mdash; varies depending on context:
                                     * viewed as [[structural asset|StructAsset]], tracks are nothing but global identifiers (possibly with attached tags and description)
                                     * regarding the structure //within each [[EDL]],// tracks form a tree-like grid, the individual track being attached to this tree by a [[Placement]], thus setting up properties of placement (time reference origin, output connection, layer, pan) which will be inherited down to any objects located on this track and on child tracks, if not overridden more locally.
                                     * with respect to //object identity,// a given track-ID can have an incarnation or manifestation as real track-object within several [[EDLs|EDL]] (meaning you could select, disable or choose for rendering all objects in any EDL placed onto this track). Moreover, the track-//object// and the //placement&nbsp;// of this track within the tree of tracks of a given EDL are two distinguishable entities (meaning a given track &mdash; with a couple of objects located on it &mdash; could be placed differently several times within the same EDL, for example with different start offset or with different layering, output mode or pan position)
                                    +{{red{WARNING: as of 11/09, the meaning and relations are rather reverted}}}... EDL == Sequence and holds the track tree.
                                     
                                     !Identification
                                     Tracks thus represent a blend of several concepts, but depending on the context it is allways clear which aspect is meant. Seen as [[assets|Asset]], tracks are known by a unique track-ID, which can be either [[queried|ConfigQuery]], or directly refered to by use of the asset-ID (which is a globally known hash). Usually, all referrals are via track-ID, including when you [[place|Placement]] an object onto a track. 
                                    
                                    From fd782eb1399b033d609c45e12d767452d7f9e51c Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 11 Dec 2009 02:49:12 +0100
                                    Subject: [PATCH 133/377] WIP: change management of test/mock PlacementIndex
                                    
                                    now lifecycle of this mock index is managed automatically
                                    from within the session services. This allows to get
                                    rid of the smart-ptr creating factory. As a consequence,
                                    PlacementIndex now resides directly within SessionImpl.
                                    ---
                                     src/proc/mobject/session/placement-index.cpp  |   2 +-
                                     src/proc/mobject/session/placement-index.hpp  |  17 +--
                                     src/proc/mobject/session/session-impl.hpp     |  16 +--
                                     .../session/session-service-mock-index.hpp    |  34 +++---
                                     src/proc/mobject/session/session-services.cpp |  25 ++++-
                                     .../proc/mobject/mobject-ref-test.cpp         |   9 +-
                                     .../proc/mobject/placement-ref-test.cpp       |   7 +-
                                     .../mobject/session/placement-index-test.cpp  | 105 +++++++++---------
                                     .../proc/mobject/session/test-scopes.cpp      |  24 +---
                                     9 files changed, 121 insertions(+), 118 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp
                                    index a9a48231a..d304ab5e4 100644
                                    --- a/src/proc/mobject/session/placement-index.cpp
                                    +++ b/src/proc/mobject/session/placement-index.cpp
                                    @@ -37,7 +37,7 @@
                                     #include "proc/mobject/session/session-impl.hpp"
                                     #include "proc/mobject/session/scope.hpp"
                                     #include "lib/typed-allocation-manager.hpp"
                                    -#include "proc/mobject/mobject.hpp" ///////////////////////TODO necessary?
                                    +//#include "proc/mobject/mobject.hpp" ///////////////////////TODO necessary?
                                     #include "lib/util.hpp"
                                     
                                     
                                    diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp
                                    index 1e14c09ba..928b53ad3 100644
                                    --- a/src/proc/mobject/session/placement-index.hpp
                                    +++ b/src/proc/mobject/session/placement-index.hpp
                                    @@ -51,12 +51,10 @@
                                     //#include "proc/asset/pipe.hpp"
                                     #include "lib/util.hpp"
                                     #include "lib/error.hpp"
                                    -#include "lib/factory.hpp"
                                     #include "lib/itertools.hpp"
                                     #include "proc/mobject/placement.hpp"
                                     #include "proc/mobject/placement-ref.hpp"
                                     
                                    -#include 
                                     #include 
                                     #include 
                                     #include 
                                    @@ -74,13 +72,9 @@ namespace session {
                                       LUMIERA_ERROR_DECLARE (NONEMPTY_SCOPE);   ///< Placement scope (still) contains other elements
                                       
                                       
                                    -  using lib::factory::RefcountFac;
                                    -  using std::tr1::shared_ptr;
                                       using boost::scoped_ptr;
                                       
                                       
                                    -  class PlacementIndex;
                                    -  typedef shared_ptr PPIdx;
                                       
                                       /**
                                        * Structured compound of Placement instances
                                    @@ -134,6 +128,8 @@ namespace session {
                                           bool contains (PlacementMO const&)          const;
                                           bool contains (ID)                          const;
                                           
                                    +      bool isValid()                              const;
                                    +      
                                           
                                           
                                           
                                    @@ -144,18 +140,13 @@ namespace session {
                                           bool remove (ID);
                                           
                                           
                                    -      typedef RefcountFac Factory;
                                           
                                    -      static Factory create;
                                    -      
                                    -      ~PlacementIndex();
                                    +      PlacementIndex() ;
                                    +     ~PlacementIndex() ;
                                           
                                           void clear();
                                           
                                         protected:
                                    -      PlacementIndex() ;
                                    -      
                                    -      friend class lib::factory::Factory > >;
                                         };
                                       
                                       
                                    diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp
                                    index 246b9f9c4..cd856bddb 100644
                                    --- a/src/proc/mobject/session/session-impl.hpp
                                    +++ b/src/proc/mobject/session/session-impl.hpp
                                    @@ -82,7 +82,7 @@ namespace session {
                                           vector edls;
                                           PFix fixture;
                                           
                                    -      shared_ptr pIdx_;
                                    +      PlacementIndex pIdx_;
                                           
                                           scoped_ptr defaultsManager_;   ///////////TODO: later, this will be the real defaults manager. Currently this is just never initialised (11/09)
                                           
                                    @@ -103,10 +103,10 @@ namespace session {
                                           void clear ();
                                           friend class SessManagerImpl;
                                           
                                    -      PPIdx const&
                                    +      PlacementIndex&
                                           getPlacementIndex()
                                             {
                                    -          ENSURE (pIdx_);
                                    +          ENSURE (pIdx_.isValid());
                                               return pIdx_;
                                             }
                                           
                                    @@ -166,23 +166,23 @@ namespace session {
                                       struct ServiceAccessPoint
                                         : IMPL
                                         {
                                    -      PPIdx const&
                                    +      PlacementIndex&
                                           getPlacementIndex()
                                             {
                                    -          if (mockIndex_)
                                    -            return mockIndex_;
                                    +          if (mockIndex_ && mockIndex_->isValid())
                                    +            return *mockIndex_;
                                               else
                                                 return IMPL::getPlacementIndex();
                                             }
                                           
                                           void
                                    -      reset_PlacementIndex (PPIdx const& alternativeIndex)
                                    +      reset_PlacementIndex (PlacementIndex* alternativeIndex =0)
                                           {
                                             mockIndex_ = alternativeIndex;
                                           }
                                           
                                         private:
                                    -      PPIdx mockIndex_;
                                    +      PlacementIndex* mockIndex_;
                                         };
                                       
                                       
                                    diff --git a/src/proc/mobject/session/session-service-mock-index.hpp b/src/proc/mobject/session/session-service-mock-index.hpp
                                    index e4a22b45f..4389a80f6 100644
                                    --- a/src/proc/mobject/session/session-service-mock-index.hpp
                                    +++ b/src/proc/mobject/session/session-service-mock-index.hpp
                                    @@ -24,10 +24,16 @@
                                     /** @file session-service-mock-index.hpp
                                      ** Implementation level session API: PlacementIndex mock for tests.
                                      ** Allows (temporarily) to replace the real Placement index within
                                    - ** the session by a mock instance handed in through this API. Unit
                                    - ** tests may use this \em backdoor to set up a specially prepared 
                                    - ** index to verify the behaviour of Placement and Scope resolution
                                    - ** operations.
                                    + ** the session by a mock instance installed and provided through
                                    + ** this API. Unit tests may use this \em backdoor to set up a
                                    + ** specially prepared index to verify the behaviour of Placement
                                    + ** and Scope resolution operations.
                                    + ** 
                                    + ** The test/mock instance of the placement index obtained by this API
                                    + ** is \em not wired with the session. Rather it is managed by smart-ptr.
                                    + ** When the last smart-ptr instance goes out of scope, the test index
                                    + ** instance will be shut down and removed, thereby uncovering the 
                                    + ** original PlacementIndex living within the session.
                                      ** 
                                      ** @see session-impl.hpp implementation of the service
                                      ** @see session-services.cpp implementation of access
                                    @@ -39,8 +45,8 @@
                                     #define MOBJECT_SESSION_SESSION_SERVICE_MOCK_INDEX_H
                                     
                                     #include "proc/mobject/session/placement-index.hpp"
                                    -//#include "proc/mobject/session.hpp"
                                    -//#include "lib/meta/generator.hpp"
                                    +
                                    +#include 
                                     
                                     
                                     
                                    @@ -48,22 +54,22 @@
                                     namespace mobject {
                                     namespace session {
                                       
                                    -//  using lumiera::typelist::InstantiateChained;
                                    -//  using lumiera::typelist::InheritFrom;
                                    -//  using lumiera::typelist::NullType;
                                    +  typedef std::tr1::shared_ptr PPIdx;
                                       
                                     
                                       /** there is an implicit PlacementIndex available on a global level,
                                        *  by default implemented within the current session. This Service
                                    -   *  to re-define this implicit index temporarily, e.g. for unit tests.
                                    -   *  @param alternativeIndex alternative Index instance to install. 
                                    -   *         when \c NIL, then restore access to the PlacementIndex
                                    -   *         instance always available within the SessionImpl
                                    +   *  temporarily overlays a newly created mock instance, e.g. for tests.
                                    +   *  @return smart-ptr managing a newly created mock index instance.
                                    +   *         Any implicit access to the session's placement index will
                                    +   *         be redirected to that instance. When the smart-ptr reaches
                                    +   *         use-count zero, access to the original PlacementIndex
                                    +   *         will be restored.
                                        */
                                       class SessionServiceMockIndex
                                         {
                                         public:
                                    -      static void reset_PlacementIndex (PPIdx const& alternativeIndex =PPIdx());
                                    +      static PPIdx install ();
                                         };
                                       
                                       
                                    diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp
                                    index 65b9a3b2c..e846dfbfa 100644
                                    --- a/src/proc/mobject/session/session-services.cpp
                                    +++ b/src/proc/mobject/session/session-services.cpp
                                    @@ -61,11 +61,30 @@ namespace session {
                                       }
                                       
                                       
                                    +  namespace { // deleter function to clean up test/mock PlacementIndex
                                    +    void
                                    +    remove_testIndex (PlacementIndex* testIdx)
                                    +    {
                                    +      REQUIRE (testIdx);
                                    +      SessionImplAPI::current->reset_PlacementIndex();  // restore default Index from Session
                                    +      
                                    +      testIdx->clear();
                                    +      ASSERT (0 == testIdx->size());
                                    +      delete testIdx;
                                    +    }
                                    +  }
                                    +  
                                       /** Re-define the implicit PlacementIndex temporarily, e.g. for unit tests. */
                                    -  void
                                    -  SessionServiceMockIndex::reset_PlacementIndex (PPIdx const& alternativeIndex)
                                    +  PPIdx
                                    +  SessionServiceMockIndex:: install ()
                                       {
                                    -    return SessionImplAPI::current->reset_PlacementIndex (alternativeIndex);
                                    +    PPIdx mockIndex (new PlacementIndex(), &remove_testIndex); // manage instance lifecycle
                                    +    ENSURE (mockIndex);
                                    +    ENSURE (mockIndex->isValid());
                                    +    ENSURE (1 == mockIndex.use_count());
                                    +    
                                    +    SessionImplAPI::current->reset_PlacementIndex (*mockIndex);
                                    +    return mockIndex;
                                       }
                                       
                                       
                                    diff --git a/tests/components/proc/mobject/mobject-ref-test.cpp b/tests/components/proc/mobject/mobject-ref-test.cpp
                                    index 89025cf0d..158de4395 100644
                                    --- a/tests/components/proc/mobject/mobject-ref-test.cpp
                                    +++ b/tests/components/proc/mobject/mobject-ref-test.cpp
                                    @@ -49,6 +49,7 @@ namespace test    {
                                       using session::Clip;
                                       
                                       using session::SessionServiceMockIndex;  
                                    +  
                                     
                                       
                                       /***************************************************************************
                                    @@ -89,10 +90,8 @@ namespace test    {
                                               
                                     #if false  //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 384  !!!!!!!!!
                                               // Prepare an (test)Index
                                    -          typedef shared_ptr PIdx;
                                    -          PIdx index (PlacementIndex::create());
                                    +          PPIdx index = SessionServiceMockIndex::install();
                                               PMO& root = index->getRoot();
                                    -          SessionServiceMockIndex::reset_PlacementIndex (index);
                                               
                                               // Add the Clips to "session"
                                               index->insert (pClip1, root);
                                    @@ -128,10 +127,12 @@ namespace test    {
                                               index->remove (pClip1);
                                               index->remove (pClip2);
                                               ASSERT (0 == index->size());
                                    +          ASSERT (1 == index.use_count());
                                               ASSERT (2 == pClip1.use_count());
                                               ASSERT (2 == pClip2.use_count());
                                    +          index.reset();
                                     #endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!!
                                    -          SessionServiceMockIndex::reset_PlacementIndex();
                                    +
                                             }
                                           
                                           
                                    diff --git a/tests/components/proc/mobject/placement-ref-test.cpp b/tests/components/proc/mobject/placement-ref-test.cpp
                                    index 7be8be595..55129eb60 100644
                                    --- a/tests/components/proc/mobject/placement-ref-test.cpp
                                    +++ b/tests/components/proc/mobject/placement-ref-test.cpp
                                    @@ -68,10 +68,8 @@ namespace test    {
                                               p2.chain(Time(2));         // define start time of Placement-2 to be at t=2
                                               
                                               // Prepare an (test)Index backing the PlacementRefs
                                    -          typedef shared_ptr PIdx;
                                    -          PIdx index (PlacementIndex::create());
                                    +          PPIdx index = SessionServiceMockIndex::install();
                                               PMO& root = index->getRoot();
                                    -          SessionServiceMockIndex::reset_PlacementIndex(index);
                                               
                                               index->insert (p1, root);
                                               index->insert (p2, root);
                                    @@ -180,7 +178,8 @@ namespace test    {
                                     
                                               //consistency check; then reset PlacementRef index to default
                                               ASSERT (0 == index->size());
                                    -          SessionServiceMockIndex::reset_PlacementIndex();
                                    +          ASSERT (1 == index.use_count());
                                    +          index.reset();
                                             }
                                         };
                                       
                                    diff --git a/tests/components/proc/mobject/session/placement-index-test.cpp b/tests/components/proc/mobject/session/placement-index-test.cpp
                                    index 54cbe8d86..7ad20f7a0 100644
                                    --- a/tests/components/proc/mobject/session/placement-index-test.cpp
                                    +++ b/tests/components/proc/mobject/session/placement-index-test.cpp
                                    @@ -50,6 +50,7 @@ namespace test    {
                                       using asset::VIDEO;
                                       using session::test::TestClip;
                                       
                                    +  typedef PlacementIndex& Idx;
                                       
                                       
                                       /***************************************************************************
                                    @@ -66,7 +67,7 @@ namespace test    {
                                           virtual void
                                           run (Arg) 
                                             {
                                    -          PPIdx index (PlacementIndex::create());
                                    +          PlacementIndex index;
                                               ASSERT (index);
                                               
                                               checkSimpleInsertRemove (index);
                                    @@ -80,100 +81,100 @@ namespace test    {
                                               
                                               ////////////////////////////TODO
                                               
                                    -          index->clear();
                                    +          index.clear();
                                               has_size (0, index);
                                             }
                                           
                                           void
                                    -      has_size(uint siz, PPIdx index)
                                    +      has_size(uint siz, Idx index)
                                             {
                                    -          ASSERT (siz == index->size());
                                    +          ASSERT (siz == index.size());
                                             }
                                           
                                           void
                                    -      checkSimpleInsertRemove (PPIdx index)
                                    +      checkSimpleInsertRemove (Idx index)
                                             {
                                               PMO clip = TestClip::create();
                                    -          PMO& root = index->getRoot();
                                    +          PMO& root = index.getRoot();
                                               
                                    -          ASSERT (0 == index->size());
                                    -          ASSERT (!index->contains (clip));
                                    +          ASSERT (0 == index.size());
                                    +          ASSERT (!index.contains (clip));
                                               
                                    -          index->insert (clip, root);
                                    -          ASSERT (1 == index->size());
                                    -          ASSERT ( index->contains (clip));
                                    +          index.insert (clip, root);
                                    +          ASSERT (1 == index.size());
                                    +          ASSERT ( index.contains (clip));
                                               
                                    -          index->remove(clip);
                                    -          ASSERT (0 == index->size());
                                    -          ASSERT (!index->contains (clip));
                                    -          ASSERT ( index->contains (root));
                                    +          index.remove(clip);
                                    +          ASSERT (0 == index.size());
                                    +          ASSERT (!index.contains (clip));
                                    +          ASSERT ( index.contains (root));
                                             }
                                           
                                           
                                           void
                                    -      checkSimpleAccess (PPIdx index)
                                    +      checkSimpleAccess (Idx index)
                                             {
                                               PMO testObj = TestClip::create();
                                    -          PMO& root = index->getRoot();
                                    -          PMO::ID elmID = index->insert (testObj, root);
                                    +          PMO& root = index.getRoot();
                                    +          PMO::ID elmID = index.insert (testObj, root);
                                               
                                    -          PMO& elm = index->find(elmID);
                                    +          PMO& elm = index.find(elmID);
                                               ASSERT (elmID == elm.getID());
                                               ASSERT (!isSameObject (elm,testObj));  // note: placements are registered as copy
                                               ASSERT (elm == testObj);              //        they are semantically equivalent
                                               ASSERT (elmID != testObj.getID());   //         but have a distinct identity
                                               
                                    -          PMO::ID elmID2 = index->insert(testObj, root);
                                    +          PMO::ID elmID2 = index.insert(testObj, root);
                                               ASSERT (elmID != elmID);          //            ...and each insert creates a new instance
                                    -          ASSERT (testObj == index->find(elmID2));
                                    -          ASSERT (!isSameObject (elm, index->find(elmID2)));
                                    -          ASSERT ( isSameObject (elm, index->find(elmID )));
                                    +          ASSERT (testObj == index.find(elmID2));
                                    +          ASSERT (!isSameObject (elm, index.find(elmID2)));
                                    +          ASSERT ( isSameObject (elm, index.find(elmID )));
                                               
                                               // can also re-access objects by previous ref
                                    -          ASSERT ( isSameObject (elm, index->find(elm)));
                                    +          ASSERT ( isSameObject (elm, index.find(elm)));
                                             }
                                           
                                           
                                           void
                                    -      checkScopeHandling (PPIdx index)
                                    +      checkScopeHandling (Idx index)
                                             {
                                               PMO testObj = TestClip::create();
                                    -          PMO& root = index->getRoot();
                                    +          PMO& root = index.getRoot();
                                               
                                               typedef PMO::ID ID;
                                    -          ID e1 = index->insert (testObj, root);
                                    -          ID e11 = index->insert (testObj, e1);
                                    -          ID e12 = index->insert (testObj, e1);
                                    -          ID e13 = index->insert (testObj, e1);
                                    -          ID e131 = index->insert (testObj, e13);
                                    -          ID e132 = index->insert (testObj, e13);
                                    -          ID e133 = index->insert (testObj, e13);
                                    -          ID e1331 = index->insert (testObj, e133);
                                    +          ID e1 = index.insert (testObj, root);
                                    +          ID e11 = index.insert (testObj, e1);
                                    +          ID e12 = index.insert (testObj, e1);
                                    +          ID e13 = index.insert (testObj, e1);
                                    +          ID e131 = index.insert (testObj, e13);
                                    +          ID e132 = index.insert (testObj, e13);
                                    +          ID e133 = index.insert (testObj, e13);
                                    +          ID e1331 = index.insert (testObj, e133);
                                               
                                    -          ASSERT (root == index->getScope(e1));
                                    -          ASSERT (e1   == index->getScope(e11).getID());
                                    -          ASSERT (e1   == index->getScope(e12).getID());
                                    -          ASSERT (e1   == index->getScope(e13).getID());
                                    -          ASSERT (e13  == index->getScope(e131).getID());
                                    -          ASSERT (e13  == index->getScope(e132).getID());
                                    -          ASSERT (e13  == index->getScope(e133).getID());
                                    -          ASSERT (e133 == index->getScope(e1331).getID());
                                    +          ASSERT (root == index.getScope(e1));
                                    +          ASSERT (e1   == index.getScope(e11).getID());
                                    +          ASSERT (e1   == index.getScope(e12).getID());
                                    +          ASSERT (e1   == index.getScope(e13).getID());
                                    +          ASSERT (e13  == index.getScope(e131).getID());
                                    +          ASSERT (e13  == index.getScope(e132).getID());
                                    +          ASSERT (e13  == index.getScope(e133).getID());
                                    +          ASSERT (e133 == index.getScope(e1331).getID());
                                               ASSERT (e1 != e13);
                                               ASSERT (e13 != e133);
                                               
                                    -          ASSERT (index->getScope(e11) == index->getScope(index->find(e11)));
                                    -          ASSERT (index->getScope(e131) == index->getScope(index->find(e131)));
                                    +          ASSERT (index.getScope(e11) == index.getScope(index.find(e11)));
                                    +          ASSERT (index.getScope(e131) == index.getScope(index.find(e131)));
                                               
                                    -          VERIFY_ERROR(NONEMPTY_SCOPE, index->remove(e13) ); // can't remove a scope-constituting element
                                    -          VERIFY_ERROR(NONEMPTY_SCOPE, index->remove(e133) );
                                    +          VERIFY_ERROR(NONEMPTY_SCOPE, index.remove(e13) ); // can't remove a scope-constituting element
                                    +          VERIFY_ERROR(NONEMPTY_SCOPE, index.remove(e133) );
                                               
                                    -          ASSERT (index->contains(e1331));
                                    -          ASSERT (index->remove(e1331));
                                    -          ASSERT (!index->contains(e1331));
                                    -          ASSERT (!index->remove(e1331));
                                    +          ASSERT (index.contains(e1331));
                                    +          ASSERT (index.remove(e1331));
                                    +          ASSERT (!index.contains(e1331));
                                    +          ASSERT (!index.remove(e1331));
                                               
                                    -          ASSERT (index->remove(e133));     // but can remove an scope, after emptying it 
                                    -          ASSERT (!index->contains(e133));
                                    +          ASSERT (index.remove(e133));     // but can remove an scope, after emptying it 
                                    +          ASSERT (!index.contains(e133));
                                             }
                                         };
                                       
                                    diff --git a/tests/components/proc/mobject/session/test-scopes.cpp b/tests/components/proc/mobject/session/test-scopes.cpp
                                    index f0e7cd1b8..578c7e638 100644
                                    --- a/tests/components/proc/mobject/session/test-scopes.cpp
                                    +++ b/tests/components/proc/mobject/session/test-scopes.cpp
                                    @@ -32,23 +32,9 @@ namespace session {
                                     namespace test    {
                                       
                                       
                                    -  namespace { // deleter function to clean up Test fixture
                                    -    void
                                    -    remove_testIndex (PlacementIndex* testIdx)
                                    -    {
                                    -      REQUIRE (testIdx);
                                    -      testIdx->clear();
                                    -      ASSERT (0 == testIdx->size());
                                    -      SessionServiceMockIndex::reset_PlacementIndex();  // restore default Index from Session
                                    -      
                                    -      delete testIdx;
                                    -    }
                                    -  }
                                    -  
                                    -  
                                    -  /** @note when this object goes out of scope, the activation of this
                                    -   *        test PlacementIndex will be cleared automatically, and the
                                    -   *        default Index within the session will be re-activated. 
                                    +  /** @note this dummy index isn't actively connected to the session;
                                    +   *        the unit tests rely on this dummy index containing
                                    +   *        a specific tree structure of test-dummy MObjects. 
                                        */
                                       PPIdx
                                       build_testScopes()
                                    @@ -64,8 +50,8 @@ namespace test    {
                                         PDum ps3(*new TestSubMO1);
                                         
                                         // Prepare an (test)Index backing the PlacementRefs
                                    -    PPIdx index (PlacementIndex::create().get(), &remove_testIndex); // taking ownership
                                    -    SessionServiceMockIndex::reset_PlacementIndex(index);
                                    +    PPIdx index (SessionServiceMockIndex::install());
                                    +    
                                         PMO& root = index->getRoot();
                                     
                                         typedef PMO::ID ID;
                                    
                                    From d949f0b7b6f5571a7ac8565a3a7df7fd1c7b7ec7 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Fri, 11 Dec 2009 03:46:34 +0100
                                    Subject: [PATCH 134/377] defining the model root MObject more clearly
                                    
                                    ---
                                     wiki/renderengine.html | 18 ++++++++++++------
                                     1 file changed, 12 insertions(+), 6 deletions(-)
                                    
                                    diff --git a/wiki/renderengine.html b/wiki/renderengine.html
                                    index 153f68ad7..b5ae8a595 100644
                                    --- a/wiki/renderengine.html
                                    +++ b/wiki/renderengine.html
                                    @@ -777,7 +777,7 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS
                                     }
                                     //}}}
                                    -
                                    +
                                    Sometimes, two entities within the [[Session]] are deliberately associated, and this association has to carry some specific mappings between properties or facilities within the entities to be linked together. When this connection isn't just the [[Placement]] of an object, and isn't just a logical or structural relationship either &mdash; then we create an explicit Binding object to be stored into the session.
                                     * When connecting a [[Sequence|EDL]] to a certain [[Timeline]], we also establish a mapping between the possible media stream channels produced by the sequence and the real output slots found within the timeline.
                                     * similarly, using a sequence within a [[meta-clip|VirtualClip]] requires to remember such a mapping.
                                    @@ -791,7 +791,7 @@ This creates a typing related problem: In order to maintain the link and the map
                                     * in the case of the attached mappings it seems we're best off limiting ourselves to symbolic mappings (ID mappings). Because, going beyond that would either create sub-groupings (based on varying target types to be mapped), or push the »everything is an object« approach beyond the beneficial level.
                                     
                                     !Critique {{red{WIP 12/09}}}
                                    -Now I'm in doubt if there is any point in treating the "binding" in a abstract fashion. Is there any common denominator? It seems there is just a common conceptional pattern, but mapping this pattern onto distinct types (classes) seems unnecessary. Rather, we have tree very similar MObjects:
                                    +Now I'm in doubt if there is any point in treating the "binding" in a abstract fashion. Is there any common denominator? It seems there is just a common conceptional pattern, but mapping this pattern onto distinct types (classes) seems unnecessary. Rather, we have three very similar kinds of ~MObjects:
                                     * ModelRootMO
                                     * BindingMO
                                     * [[Track]]
                                    @@ -2327,8 +2327,14 @@ For the case here in question this seems to be the ''resource allocation is cons
                                     And, last but not least, doing large scale allocations is the job of the backend. Exceptions being long-lived objects, like the Session or the EDL, which are created once and don't bear the danger of causing memory pressure. Besides, the ProcLayer code shouldn't issue "new" and "delete" when it comes in hand, rather it should use some centralized [[Factories]] for all allocation and freeing, so we can redirect these calls down to the backend, which may use pooling or special placement allocators or the like. The rationale is, for modern hardware/architectures, care has to be taken with heap allocations, esp. with many small objects and irregular usage patterns.
                                     
                                    -
                                    -
                                    A special kind of MObject, serving as a marker or entry point at the root of the HighLevelModel. As any ~MObject, it is attached to the model by a [[Placement]]. And in this special case, this placement froms the ''root scope'' of the model, thus containing any other PlacementScope (e.g. tracks, clips with effects,...)
                                    +
                                    +
                                    A special kind of MObject, serving as a marker or entry point at the root of the HighLevelModel. As any ~MObject, it is attached to the model by a [[Placement]]. And in this special case, this placement froms the ''root scope'' of the model, thus containing any other PlacementScope (e.g. tracks, clips with effects,...)
                                    +
                                    +This special ''session root object'' provides a link between the model part and the &raquo;bookkeeping&laquo; part of the session, i.e. the [[assets|Asset]]. It is created and maintained by the session (implementation level) &mdash; allowing to store and load the asset definitions as contents of the model root element.
                                    +
                                    +__Note__: nothing within the PlacementIndex requires the root object to be of a specific type; the index just assumes a {{{Placement<MObject>}}} (or subclass) to exist as root element. And indeed, for several unit tests we create an Index mock with a tree of dummy ~MObjects and temporarily shaddow the "real" PlacementIndex by this mock (&rarr; see SessionServices for the API allowing to access this //mock index//- functionality)
                                    +
                                    +
                                    Based on practical experiences, Ichthyo tends to consider Multichannel Media as the base case, while counting media files providing just one single media stream as exotic corner cases. This may seem counter intuitive at first sight; you should think of  it as an attempt to avoid right from start some of the common shortcomings found in many video editors, especially
                                    @@ -3093,7 +3099,7 @@ Placements have //value semantics,// i.e. we don't stress the identity of a plac
                                     
                                     
                                    -
                                    +
                                    An implementation facility used to keep track of individual Placements and their relations.
                                     Especially, the [[Session]] maintains such an index, allowing to use the (opaque) PlacementRef tags for referring to a specific "instance" of an MObject, //placed// in a unique way into the current session. And, moreover, this index allows for one placement referring to another placement, so to implement a //relative// placement mode. Because there is an index behind the scenes, it is possible to actually access such a referral in the reverse direction, which is necessary for implementing the desired placement behaviour (if an object instance used as anchor is moved, all objects placed relatively to it have to move accordingly, which necessitates finding those other objects).
                                     
                                    @@ -3127,7 +3133,7 @@ The placement index is utilized by editing operations and by executing the build
                                     On second sight, this problem turns out to be more involved, because either we have to keep a second index table for the reverse lookup (memory address -> ID), or have to tie the placement by a back-link when adding it to the index/session data structure, or (alternatively) it forces us to store a copy of the ID //within// the placement itself. The last possibility seems to create the least impact; but implementing it this way effectively gears the implementation towards a hashtable based approach.
                                     
                                     !!!Handling of Subtypes
                                    -While usually type relations don't carry over to smart-poitner like types, in case of Placement I used a special definition pattern to artificially create such type relations. Now, as we're going to copy and maintain Placements within the storage backing the index, the question is: do we actually store subtypes (all having the same size btw) or do we use a vtable based mechanism to recover the type information on access?
                                    +While usually type relations don't carry over to smart-poitner like types, in case of Placement I used a special definition pattern to artificially create such type relations ({{{Placement<session::Clip>}}} is subclass of {{{Placement<MObject>}}}). Now, as we're going to copy and maintain Placements within the storage backing the index, the question is: do we actually store subtypes (all having the same size btw) or do we use a vtable based mechanism to recover the type information on access?
                                     
                                     Actually, the handling of placement types quite flexible; the actual hierarchy of Placement types can be determined in the //usage context// &mdash; it is not really stored within the placement, and there is no point in storing it within the index. Only the type of the //pointee//&nbsp; can be checked with the help of Placement's vtable.
                                     
                                    
                                    From 628ad8a31dd859207b453904d81f23efbc42dd3a Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 12 Dec 2009 03:50:41 +0100
                                    Subject: [PATCH 135/377] WIP add a new kind of MObject: the model root
                                    
                                    ---
                                     ...pp => applicable-builder-target-types.hpp} |  0
                                     src/proc/mobject/mobject.hpp                  |  2 +-
                                     src/proc/mobject/session/defsmanager.hpp      | 11 +++
                                     src/proc/mobject/session/meta.hpp             |  2 +
                                     src/proc/mobject/session/mobjectfactory.cpp   | 25 +++++--
                                     src/proc/mobject/session/mobjectfactory.hpp   |  8 +-
                                     src/proc/mobject/session/root.cpp             | 53 +++++++++++++
                                     src/proc/mobject/session/root.hpp             | 74 +++++++++++++++++++
                                     8 files changed, 165 insertions(+), 10 deletions(-)
                                     rename src/proc/mobject/builder/{applicablebuildertargettypes.hpp => applicable-builder-target-types.hpp} (100%)
                                     create mode 100644 src/proc/mobject/session/root.cpp
                                     create mode 100644 src/proc/mobject/session/root.hpp
                                    
                                    diff --git a/src/proc/mobject/builder/applicablebuildertargettypes.hpp b/src/proc/mobject/builder/applicable-builder-target-types.hpp
                                    similarity index 100%
                                    rename from src/proc/mobject/builder/applicablebuildertargettypes.hpp
                                    rename to src/proc/mobject/builder/applicable-builder-target-types.hpp
                                    diff --git a/src/proc/mobject/mobject.hpp b/src/proc/mobject/mobject.hpp
                                    index fecb8ee81..f73fb33c8 100644
                                    --- a/src/proc/mobject/mobject.hpp
                                    +++ b/src/proc/mobject/mobject.hpp
                                    @@ -85,7 +85,7 @@ namespace mobject {
                                           /** MObject self-test (usable for asserting) */
                                           virtual bool isValid()  const =0;
                                           
                                    -      virtual Time& getLength() =0; ///< @todo how to deal with the time/length field??
                                    +      virtual Time& getLength() =0; ///< @todo how to deal with the time/length field?? ////TICKET #448
                                           
                                           virtual bool operator== (const MObject& oo)  const =0;
                                           
                                    diff --git a/src/proc/mobject/session/defsmanager.hpp b/src/proc/mobject/session/defsmanager.hpp
                                    index 30aea7fff..ac4bfa673 100644
                                    --- a/src/proc/mobject/session/defsmanager.hpp
                                    +++ b/src/proc/mobject/session/defsmanager.hpp
                                    @@ -52,6 +52,10 @@ namespace mobject {
                                          * code didn't give more specific parameters. Necessary sub-objects 
                                          * will be created on demand, and any default configuration, once
                                          * found, will be remembered and stored with the current session.
                                    +     * 
                                    +     * @note while the logic of defaults handling can be considered
                                    +     *       roughly final, as of 12/09 most of the actual object
                                    +     *       handling is placeholder code.
                                          */
                                         class DefsManager : private boost::noncopyable
                                           {
                                    @@ -108,6 +112,13 @@ namespace mobject {
                                     //            template  class SMP  ///<  smart pointer class to wrap the result
                                     //          >
                                     //        SMP operator() (const lumiera::Query&);
                                    +
                                    +// 12/09: according to my current knowledge of template metaprogramming, the answer is "no",
                                    +//        but we could use a traits template to set up a fixed association of smart pointers
                                    +//        and kinds of target object. This would allow to define a templated operator() returning
                                    +//        the result wrapped into the right holder. But currently I don't see how to build a sensible
                                    +//        implementation infrastructure backing such an interface.
                                    +//////////TICKET #452
                                             
                                           };
                                     
                                    diff --git a/src/proc/mobject/session/meta.hpp b/src/proc/mobject/session/meta.hpp
                                    index f1a69b98d..dffd8610c 100644
                                    --- a/src/proc/mobject/session/meta.hpp
                                    +++ b/src/proc/mobject/session/meta.hpp
                                    @@ -37,10 +37,12 @@ namespace session {
                                        * but rather all sorts of Processing Instructions
                                        * and other metadata, which can be placed and
                                        * attached within the EDL/Session.
                                    +   * @todo do we need this abstract baseclass?
                                        */
                                       class Meta : public AbstractMO
                                         {
                                           ///////////
                                    +      //////////////////////////////TICKET #448   what to do with the length here??
                                         };
                                       
                                       
                                    diff --git a/src/proc/mobject/session/mobjectfactory.cpp b/src/proc/mobject/session/mobjectfactory.cpp
                                    index e6e158731..4dcf1f3dc 100644
                                    --- a/src/proc/mobject/session/mobjectfactory.cpp
                                    +++ b/src/proc/mobject/session/mobjectfactory.cpp
                                    @@ -22,6 +22,7 @@
                                     
                                     
                                     #include "proc/mobject/session/mobjectfactory.hpp"
                                    +#include "proc/mobject/session/root.hpp"
                                     #include "proc/mobject/session/clip.hpp"
                                     #include "proc/mobject/session/track.hpp"
                                     #include "proc/mobject/session/effect.hpp"
                                    @@ -29,11 +30,23 @@
                                     #include "proc/asset/track.hpp"
                                     #include "proc/asset/effect.hpp"
                                     
                                    -namespace mobject
                                    -  {
                                    -  namespace session
                                    -    {
                                    +namespace mobject {
                                    +namespace session {
                                    +      ////////////////////////////////////////////////////////////////////////////////TICKET #414
                                     
                                    +
                                    +    
                                    +    /** variant of the Clip-MO factory function, creating
                                    +     *  a multichannel (compound) clip.
                                    +     *  @todo work out the details of multichannel handling
                                    +     */
                                    +    Placement
                                    +    MObjectFactory::operator() (DefsManager& sessionDefaultsHandler)
                                    +    {
                                    +      return Placement (*new Root (sessionDefaultsHandler), &deleterFunc);
                                    +    }
                                    +    
                                    +    
                                         /** creating a Clip-MObject to be placed within
                                          *  the EDL, based on a clip asset, which typically
                                          *  is obtained by calling the createClip()-function
                                    @@ -80,6 +93,4 @@ namespace mobject
                                     
                                     
                                     
                                    -  } // namespace mobject::session
                                    -
                                    -} // namespace mobject
                                    +}} // namespace mobject::session
                                    diff --git a/src/proc/mobject/session/mobjectfactory.hpp b/src/proc/mobject/session/mobjectfactory.hpp
                                    index e1a7a5695..6da52b614 100644
                                    --- a/src/proc/mobject/session/mobjectfactory.hpp
                                    +++ b/src/proc/mobject/session/mobjectfactory.hpp
                                    @@ -39,13 +39,15 @@ namespace asset {
                                     
                                     namespace mobject {
                                       namespace session {
                                    -  
                                    +    
                                    +    class Root;
                                         class Clip;
                                         class Track;
                                         class Effect;
                                         
                                         typedef P PTrackAsset;
                                    -
                                    +    
                                    +    class DefsManager;
                                     
                                         class MObjectFactory
                                           {
                                    @@ -56,11 +58,13 @@ namespace mobject {
                                             
                                           public:
                                             
                                    +        Placement   operator() (DefsManager&);
                                             Placement   operator() (asset::Clip const&, asset::Media const&);
                                             Placement   operator() (asset::Clip const&, vector);
                                             Placement  operator() (PTrackAsset&);
                                             Placement operator() (asset::Effect const&);
                                             
                                    +        ////////////////////////////////////////////////////////////////////////////////TICKET #414
                                           };
                                     
                                     
                                    diff --git a/src/proc/mobject/session/root.cpp b/src/proc/mobject/session/root.cpp
                                    new file mode 100644
                                    index 000000000..88a631c78
                                    --- /dev/null
                                    +++ b/src/proc/mobject/session/root.cpp
                                    @@ -0,0 +1,53 @@
                                    +/*
                                    +  Root  -  root element of the high-level model, global session scope
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2008,               Hermann Vosseler 
                                    + 
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +* *****************************************************/
                                    +
                                    +
                                    +#include "proc/mobject/session/root.hpp"
                                    +#include "proc/mobject/session/defsmanager.hpp"
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +  
                                    +  /** */
                                    +  Root::Root (DefsManager& dM)
                                    +    : defaults_(dM)
                                    +    { }
                                    +  
                                    +  
                                    +  
                                    +  /** @todo validity self-check of the model root
                                    +   *        should do substantial checks; the idea is
                                    +   *        to perform a complete sanity check by delegating
                                    +   *        to the parts.
                                    +   *  @note beware of performance problems here!
                                    +   */
                                    +  bool
                                    +  Root::isValid()  const
                                    +  {
                                    +    return true; //////////////////TICKET #447
                                    +  }
                                    +
                                    +  /////////////////////////////////TODO more to come.....
                                    +  
                                    +  
                                    +}} // namespace mobject::session
                                    diff --git a/src/proc/mobject/session/root.hpp b/src/proc/mobject/session/root.hpp
                                    new file mode 100644
                                    index 000000000..b6457bd77
                                    --- /dev/null
                                    +++ b/src/proc/mobject/session/root.hpp
                                    @@ -0,0 +1,74 @@
                                    +/*
                                    +  ROOT.hpp  -  root element of the high-level model, global session scope
                                    + 
                                    +  Copyright (C)         Lumiera.org
                                    +    2008,               Hermann Vosseler 
                                    +
                                    +  This program is free software; you can redistribute it and/or
                                    +  modify it under the terms of the GNU General Public License as
                                    +  published by the Free Software Foundation; either version 2 of the
                                    +  License, or (at your option) any later version.
                                    + 
                                    +  This program is distributed in the hope that it will be useful,
                                    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    +  GNU General Public License for more details.
                                    + 
                                    +  You should have received a copy of the GNU General Public License
                                    +  along with this program; if not, write to the Free Software
                                    +  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                    + 
                                    +*/
                                    +
                                    +
                                    +#ifndef MOBJECT_SESSION_ROOT_H
                                    +#define MOBJECT_SESSION_ROOT_H
                                    +
                                    +#include "proc/mobject/session/meta.hpp"
                                    +#include "proc/mobject/builder/buildertool.hpp"
                                    +
                                    +
                                    +namespace mobject {
                                    +namespace session {
                                    +    
                                    +    class DefsManager;
                                    +    
                                    +    
                                    +    /**
                                    +     * High-level model root element, corresponding to
                                    +     * the global session wide scope. Serves as link to any
                                    +     * definitions, rules and defaults valid throughout this
                                    +     * session. Will be created automatically and inserted into
                                    +     * the PlacementIndex of an empty session; causes the globals
                                    +     * to be saved/loaded alongside with the model.
                                    +     * 
                                    +     * @todo WIP-WIP.. Serialisation is postponed, the rules implementation
                                    +     *       is preliminary, the active link to the AssetManager is missing.
                                    +     *       Thus, as of 12/09 this is an empty placeholder and just serves
                                    +     *       as root scope.
                                    +     */
                                    +    class Root : public Meta
                                    +      {
                                    +        DefsManager& defaults_;
                                    +      
                                    +        ///////////TODO: timespan fields here or already in class Meta??
                                    +        ///////////TODO: any idea about the purpose of root's "timespan"??  ///////TICKET #448
                                    +      
                                    +        virtual bool isValid()  const;
                                    +        
                                    +      public:
                                    +        Root (DefsManager&);
                                    +        
                                    +        DEFINE_PROCESSABLE_BY (builder::BuilderTool);
                                    +        
                                    +      };
                                    +    
                                    +    
                                    +  } // namespace mobject::session
                                    +  
                                    +  /** Placement defined to be subclass of Placement */
                                    +  template class Placement;
                                    +  typedef Placement PRoot;
                                    +  
                                    +} // namespace mobject
                                    +#endif
                                    
                                    From 5fd2a854005a11cf868876be2da3f845dd3112d9 Mon Sep 17 00:00:00 2001
                                    From: Ichthyostega 
                                    Date: Sat, 12 Dec 2009 03:51:26 +0100
                                    Subject: [PATCH 136/377] cleanup of BuilderTool includes
                                    
                                    ---
                                     .../applicable-builder-target-types.hpp       | 55 +++++++++++++------
                                     src/proc/mobject/builder/buildertool.hpp      | 26 ++++-----
                                     src/proc/mobject/builder/nodecreatortool.cpp  | 14 +++--
                                     src/proc/mobject/builder/nodecreatortool.hpp  |  4 +-
                                     src/proc/mobject/builder/segmentationtool.cpp |  5 +-
                                     src/proc/mobject/builder/segmentationtool.hpp |  4 +-
                                     6 files changed, 66 insertions(+), 42 deletions(-)
                                    
                                    diff --git a/src/proc/mobject/builder/applicable-builder-target-types.hpp b/src/proc/mobject/builder/applicable-builder-target-types.hpp
                                    index 5d4360131..ac94da38b 100644
                                    --- a/src/proc/mobject/builder/applicable-builder-target-types.hpp
                                    +++ b/src/proc/mobject/builder/applicable-builder-target-types.hpp
                                    @@ -20,29 +20,54 @@
                                      
                                     */
                                     
                                    +/** @file applicable-builder-target-types.hpp
                                    + ** Declaration of all kinds of MObjects to be treated by some "Builder tool".
                                    + ** This is part of Lumiera's visitation mechanism: Individual MObject subclasses
                                    + ** may declare by the \c DEFINE_PROCESSABLE_BY macro to be specifically processable
                                    + ** by a builder tool (visitor). On the other hand, any concrete builder tool (visitor)
                                    + ** is free to define a \c treat(Type) function for each of these specific subclasses.
                                    + ** If the tool doesn't define such a specific \c treat(..) function, the next suitable
                                    + ** function for a supertype will be used.
                                    + ** 
                                    + ** Now there needs to be \em one location where all the specific kinds of treat-able
                                    + ** MObjects are declared together (in a typelist). Moreover, we need the full declaration
                                    + ** of these classes. This is the catch of using the visitor pattern. Thus, any class
                                    + ** to be treated \em specifically (as opposed to be just treated through a supertype
                                    + ** or super interface) has two liabilities:
                                    + ** - DEFINE_PROCESSABLE_BY
                                    + ** - declare the type here in this file, including the header.
                                    + ** 
                                    + ** @note actually the ApplicableBuilderTargetTypes template, when used (as a baseclass
                                    + **       of any concrete builder tool, causes the generation of the necessary
                                    + **       dispatcher tables used by our visitor implementation.
                                    + **       
                                    + ** @see buildertool.hpp
                                    + ** @see buildertooltest.hpp
                                    + ** @see nodecreatertool.hpp
                                    + */
                                    +
                                    +
                                     
                                     #ifndef MOBJECT_BUILDER_APPLICABLEBUILDERTARGETTYPES_H
                                     #define MOBJECT_BUILDER_APPLICABLEBUILDERTARGETTYPES_H
                                     
                                     #include "proc/mobject/builder/buildertool.hpp"
                                     
                                    +// NOTE:  need to include *all* classes using DEFINE_PROCESSABLE_BY(BuilderTool)
                                    +#include "proc/mobject/session/root.hpp"
                                    +#include "proc/mobject/session/clip.hpp"
                                    +#include "proc/mobject/session/effect.hpp"
                                    +#include "proc/mobject/session/auto.hpp"
                                    +
                                    +                                        /////////////////////////////////TICKET #414
                                    +
                                     
                                     
                                     namespace mobject {
                                    -  namespace session {
                                    -    
                                    -    class Clip;
                                    -    class Effect;
                                    -    class AbstractMO;
                                    -    template class Auto;
                                    -    // Forward declarations sufficient here...
                                    -    // actual definitions necessary only in the
                                    -    // implementation file (*cpp) of the builder tool.
                                    -  }
                                    +namespace builder {
                                       
                                    -  namespace builder {
                                    -  
                                    -    typedef Types< session::Clip, 
                                    +    typedef Types< session::Root, 
                                    +                   session::Clip, 
                                                        session::Effect,
                                                        session::AbstractMO
                                                      > ::List
                                    @@ -65,7 +90,5 @@ namespace mobject {
                                         
                                         
                                         
                                    -  } // namespace mobject::builder
                                    -
                                    -} // namespace mobject
                                    +}} // namespace mobject::builder
                                     #endif
                                    diff --git a/src/proc/mobject/builder/buildertool.hpp b/src/proc/mobject/builder/buildertool.hpp
                                    index e0b90979e..9f6a06a25 100644
                                    --- a/src/proc/mobject/builder/buildertool.hpp
                                    +++ b/src/proc/mobject/builder/buildertool.hpp
                                    @@ -28,22 +28,22 @@
                                      ** 
                                      ** As the objects to be treated are normally handled by smart-ptrs, BuilderTool provides
                                      ** a special facility for dealing with these wrapped objects. There are some liabilities.
                                    - ** 
                                    • each concrete Buildable subtype to be treated specifically needs to - ** declare \c DEFINE_PROCESSABLE_BY(BuilderTool)
                                    • - **
                                    • at the same time, the concrete BuilderTool subclass has to declare - ** being Applicable to this concrete Buildable subtype. The recommended way - ** of ensuring this, is to add an entry to applicablebuildertargettypes.hpp - ** and then derive the concrete BuilderTool subclass from - ** ApplicableBuilderTargetTypes
                                    • - **
                                    • when accessing the wrapper from within a \c treat() function, a suitable - ** concrete wrapper type has to be specified. If the wrapper type used for - ** invoking the BuilderTool (function \c apply(BuilderTool&l, WrappedObject&) ) - ** can not be converted to this type requested from within the call, an - ** assertion failure (or segmentation fault in a release build) will result.
                                    • + ** - each concrete Buildable subtype to be treated specifically needs to + ** declare \c DEFINE_PROCESSABLE_BY(BuilderTool) + ** - at the same time, the concrete BuilderTool subclass has to declare + ** being Applicable to this concrete Buildable subtype. The recommended way + ** of ensuring this, is to add an entry to applicable-builder-target-types.hpp + ** and then derive the concrete BuilderTool subclass from + ** ApplicableBuilderTargetTypes + ** - when accessing the wrapper from within a \c treat() function, a suitable + ** concrete wrapper type has to be specified. If the wrapper type used for + ** invoking the BuilderTool (function \c apply(BuilderTool&l, WrappedObject&) ) + ** can not be converted to this type requested from within the call, an + ** assertion failure (or segmentation fault in a release build) will result. **
                                    ** ** @see visitor.hpp - ** @see applicablebuildertargettypes.hpp + ** @see applicable-builder-target-types.hpp ** @see buildertooltest.hpp ** @see nodecreatertool.hpp */ diff --git a/src/proc/mobject/builder/nodecreatortool.cpp b/src/proc/mobject/builder/nodecreatortool.cpp index 8664a2b01..854d92dbc 100644 --- a/src/proc/mobject/builder/nodecreatortool.cpp +++ b/src/proc/mobject/builder/nodecreatortool.cpp @@ -22,9 +22,7 @@ #include "proc/mobject/builder/nodecreatortool.hpp" -#include "proc/mobject/session/clip.hpp" -#include "proc/mobject/session/effect.hpp" -#include "proc/mobject/session/auto.hpp" + using mobject::Buildable; using mobject::session::Clip; @@ -34,8 +32,12 @@ using mobject::session::Auto; namespace mobject { namespace builder { - - + /////////////////////////////////TICKET #414 + + + ////TODO: do we ever get to treat a model root element?? + + void NodeCreatorTool::treat (Buildable& something) { @@ -63,7 +65,7 @@ namespace mobject { void NodeCreatorTool::onUnknown (Buildable& target) { - UNIMPLEMENTED ("catch-all when partitioning timeline"); ////////TODO: verify why this gets enfoced here... + UNIMPLEMENTED ("catch-all when partitioning timeline"); ////////TODO: verify why this gets enforced here... } diff --git a/src/proc/mobject/builder/nodecreatortool.hpp b/src/proc/mobject/builder/nodecreatortool.hpp index 4d3d04b9c..6d2b5e9e8 100644 --- a/src/proc/mobject/builder/nodecreatortool.hpp +++ b/src/proc/mobject/builder/nodecreatortool.hpp @@ -25,7 +25,7 @@ #define MOBJECT_BUILDER_NODECREATORTOOL_H -#include "proc/mobject/builder/applicablebuildertargettypes.hpp" +#include "proc/mobject/builder/applicable-builder-target-types.hpp" #include "proc/engine/rendergraph.hpp" @@ -66,7 +66,7 @@ namespace builder { virtual void treat (mobject::session::Auto& automation) ; //TODO: the automation-type-problem virtual void treat (mobject::Buildable& something) ; - void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shaddow this?? + void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shadow this?? }; diff --git a/src/proc/mobject/builder/segmentationtool.cpp b/src/proc/mobject/builder/segmentationtool.cpp index 703f25150..d0a18595d 100644 --- a/src/proc/mobject/builder/segmentationtool.cpp +++ b/src/proc/mobject/builder/segmentationtool.cpp @@ -22,9 +22,7 @@ #include "proc/mobject/builder/segmentationtool.hpp" -#include "proc/mobject/session/clip.hpp" -#include "proc/mobject/session/effect.hpp" -#include "proc/mobject/session/segment.hpp" + using mobject::Buildable; using mobject::session::Clip; @@ -34,6 +32,7 @@ using mobject::session::Effect; namespace mobject { namespace builder { + /////////////////////////////////TICKET #414 SegmentationTool::SegmentationTool(mobject::session::Fixture&) diff --git a/src/proc/mobject/builder/segmentationtool.hpp b/src/proc/mobject/builder/segmentationtool.hpp index 7106874c5..2b88f572a 100644 --- a/src/proc/mobject/builder/segmentationtool.hpp +++ b/src/proc/mobject/builder/segmentationtool.hpp @@ -25,7 +25,7 @@ #define MOBJECT_BUILDER_SEGMENTATIONTOOL_H -#include "proc/mobject/builder/applicablebuildertargettypes.hpp" +#include "proc/mobject/builder/applicable-builder-target-types.hpp" #include "proc/mobject/session/segmentation.hpp" #include "proc/mobject/session/fixture.hpp" //////TODO really on the header?? @@ -59,7 +59,7 @@ namespace mobject { void treat (mobject::Buildable& something) ; - void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shaddow this?? + void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shadow this?? bool empty() const; From 6c187224ebb0347a765cade6a47858e64b987d54 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 12 Dec 2009 05:03:50 +0100 Subject: [PATCH 137/377] get it through the compiler again... --- .../placement-index-query-resolver.cpp | 23 ++++++++++--------- .../placement-index-query-resolver.hpp | 12 ++++++---- src/proc/mobject/session/placement-index.cpp | 13 +++++++---- src/proc/mobject/session/session-impl.cpp | 9 ++++---- src/proc/mobject/session/session-impl.hpp | 6 ++--- src/proc/mobject/session/session-services.cpp | 2 +- .../session/placement-index-query-test.cpp | 2 +- .../mobject/session/placement-index-test.cpp | 16 ++++++++----- .../proc/mobject/session/test-scopes.hpp | 4 ++-- 9 files changed, 50 insertions(+), 37 deletions(-) diff --git a/src/proc/mobject/session/placement-index-query-resolver.cpp b/src/proc/mobject/session/placement-index-query-resolver.cpp index b85ca6e6f..eb7b2731c 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.cpp +++ b/src/proc/mobject/session/placement-index-query-resolver.cpp @@ -43,6 +43,7 @@ namespace session { typedef Goal::QueryID QueryID; typedef QueryID const& QID; + typedef PlacementIndex& PIdx; typedef PlacementIndex::iterator PIter; /** @note all of this search implementation works on Placement refs. @@ -109,7 +110,7 @@ namespace session { class DeepExplorer : public Explorer { - PPIdx index_; + PIdx index_; std::stack scopes_; bool @@ -126,12 +127,12 @@ namespace session { REQUIRE (!scopes_.empty() && scopes_.top()); Pla& pos = *scopes_.top(); ++scopes_.top(); - scopes_.push(index_->getReferrers(pos.getID())); + scopes_.push(index_.getReferrers(pos.getID())); return pos; } public: - DeepExplorer(PIter start, PPIdx idx) + DeepExplorer(PIter start, PIdx idx) : index_(idx) { scopes_.push(start); @@ -146,7 +147,7 @@ namespace session { class UpExplorer : public Explorer { - PPIdx index_; + PIdx index_; Pla* tip_; bool @@ -160,14 +161,14 @@ namespace session { { REQUIRE (tip_); Pla& pos = *tip_; - tip_ = &index_->getScope(*tip_); + tip_ = &index_.getScope(*tip_); if (tip_ == &pos) tip_ = 0; return pos; } public: - UpExplorer(Pla& start, PPIdx idx) + UpExplorer(Pla& start, PIdx idx) : index_(idx) , tip_(&start) { } @@ -277,7 +278,7 @@ namespace session { - PlacementIndexQueryResolver::PlacementIndexQueryResolver (PPIdx theIndex) + PlacementIndexQueryResolver::PlacementIndexQueryResolver (PIdx theIndex) : index_(theIndex) { defineHandling(); @@ -346,10 +347,10 @@ namespace session { { switch (direction) { - case CONTENTS: return new DeepExplorer(index_->getReferrers(startID), index_); - case CHILDREN: return new ChildExplorer(index_->getReferrers(startID)); - case PARENTS: return new UpExplorer(index_->getScope(startID),index_); - case PATH: return new UpExplorer(index_->find(startID),index_); + case CONTENTS: return new DeepExplorer(index_.getReferrers(startID), index_); + case CHILDREN: return new ChildExplorer(index_.getReferrers(startID)); + case PARENTS: return new UpExplorer(index_.getScope(startID),index_); + case PATH: return new UpExplorer(index_.find(startID),index_); default: throw lumiera::error::Invalid("unknown query direction"); //////TICKET #197 diff --git a/src/proc/mobject/session/placement-index-query-resolver.hpp b/src/proc/mobject/session/placement-index-query-resolver.hpp index 26da4a824..e4846ec78 100644 --- a/src/proc/mobject/session/placement-index-query-resolver.hpp +++ b/src/proc/mobject/session/placement-index-query-resolver.hpp @@ -24,7 +24,7 @@ /** @file placement-index-query-resolver.hpp ** Implementing resolution of "discover contents"-queries based on PlacementIndex. ** This wrapper adds a service to resolve queries for exploring the contents or - ** the parent path of a given scope; the actual implementation is based on the + ** the parent path of a given scope; the actual implementation relies on the ** basic operations provided by the PlacementIndex; usually this wrapper is ** instantiated as one of the SessionServices for use by Proc-Layer internals. ** The PlacementIndex to use for the implementation is handed in to the ctor. @@ -33,7 +33,7 @@ ** decoupled from the querying client code, which retrieves the query results ** through an iterator. Parametrisation is transmitted to the resolver using a ** special subclass of Goal, a ScopeQuery. Especially, besides a filter to apply - ** on the results to retrieve, the direction and way* to search can be parametrised: + ** on the results to retrieve, the direction and way to search can be parametrised: ** - ascending to the parents of the start scope ** - enumerating the immediate child elements of the scope ** - exhaustive depth-first search to get any content of the scope @@ -42,7 +42,7 @@ ** On initialisation, a table with preconfigured resolution functions is built, ** in order to re-gain the fully typed context when receiving a query. From within ** this context, the concrete Query instance can be investigated to define a - ** constructor function for the actual result set, to determine the way how further + ** constructor function for the actual result set, determining the way how further ** results will be searched and extracted. The further exploration is driven by the ** client pulling values from the iterator until exhaustion. ** @@ -84,7 +84,9 @@ namespace session { class PlacementIndexQueryResolver : public session::QueryResolver { - PPIdx index_; + typedef PlacementIndex& PIdx; + + PIdx index_; virtual bool canHandleQuery(Goal::QueryID const&) const; @@ -102,7 +104,7 @@ namespace session { public: - PlacementIndexQueryResolver (PPIdx theIndex); + PlacementIndexQueryResolver (PIdx theIndex); }; diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index d304ab5e4..997c61197 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -257,10 +257,6 @@ namespace session { - /** @internal Factory for creating a new placement index. - * For use by the Session and for unit tests. - */ - PlacementIndex::Factory PlacementIndex::create; PlacementIndex::PlacementIndex() : pTab_(new Table) @@ -276,6 +272,15 @@ namespace session { } + /** validity self-check, used for sanity checks + * and the session self-check. */ + bool + PlacementIndex::isValid() const + { + UNIMPLEMENTED ("PlacementIndex validity self-check"); + } + + size_t PlacementIndex::size() const { diff --git a/src/proc/mobject/session/session-impl.cpp b/src/proc/mobject/session/session-impl.cpp index c3bc059a4..1d4f59ecc 100644 --- a/src/proc/mobject/session/session-impl.cpp +++ b/src/proc/mobject/session/session-impl.cpp @@ -28,14 +28,15 @@ namespace mobject { namespace session { - /////////////////////////////////////////TODO temporary hack + /////////////////////////////////////////TODO temporary hack: use Meyer's singleton namespace { DefsManager& getDummyDefaultsManager() { - static scoped_ptr dummyDefaultsManagerInstance(new DefsManager); + static scoped_ptr dummyInstance(0); + if (!dummyInstance) dummyInstance.reset (new DefsManager); - return *dummyDefaultsManagerInstance; + return *dummyInstance; } } /////////////////////////////////////////TODO temporary hack @@ -51,7 +52,7 @@ namespace session { focusEDL_(0), edls(1), fixture(new Fixture), - pIdx_(PlacementIndex::create()) + pIdx_() /////////////////////////////////////////////TODO { } diff --git a/src/proc/mobject/session/session-impl.hpp b/src/proc/mobject/session/session-impl.hpp index cd856bddb..475ec1a3b 100644 --- a/src/proc/mobject/session/session-impl.hpp +++ b/src/proc/mobject/session/session-impl.hpp @@ -123,13 +123,13 @@ namespace session { bool isRegisteredID (PMO::ID const& placementID) { - return IMPL::getPlacementIndex()->contains (placementID); //never throws + return IMPL::getPlacementIndex().contains (placementID); //never throws } PMO& resolveID (PMO::ID const& placementID) { - return IMPL::getPlacementIndex()->find (placementID); //may throw + return IMPL::getPlacementIndex().find (placementID); //may throw } }; @@ -148,7 +148,7 @@ namespace session { PlacementMO& getScopeRoot() { - return IMPL::getPlacementIndex()->getRoot(); + return IMPL::getPlacementIndex().getRoot(); } protected: diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp index e846dfbfa..261e4ce4b 100644 --- a/src/proc/mobject/session/session-services.cpp +++ b/src/proc/mobject/session/session-services.cpp @@ -83,7 +83,7 @@ namespace session { ENSURE (mockIndex->isValid()); ENSURE (1 == mockIndex.use_count()); - SessionImplAPI::current->reset_PlacementIndex (*mockIndex); + SessionImplAPI::current->reset_PlacementIndex (mockIndex.get()); return mockIndex; } diff --git a/tests/components/proc/mobject/session/placement-index-query-test.cpp b/tests/components/proc/mobject/session/placement-index-query-test.cpp index a07b85480..a0728fff2 100644 --- a/tests/components/proc/mobject/session/placement-index-query-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-query-test.cpp @@ -88,7 +88,7 @@ namespace test { // Prepare an (test)Index (dummy "session") PPIdx index = build_testScopes(); PlacementMO& root = index->getRoot(); - PlacementIndexQueryResolver resolver(index); + PlacementIndexQueryResolver resolver(*index); discover (ContentsQuery (resolver,root)); diff --git a/tests/components/proc/mobject/session/placement-index-test.cpp b/tests/components/proc/mobject/session/placement-index-test.cpp index 7ad20f7a0..63fd5ca32 100644 --- a/tests/components/proc/mobject/session/placement-index-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-test.cpp @@ -68,7 +68,7 @@ namespace test { run (Arg) { PlacementIndex index; - ASSERT (index); + ASSERT (index.isValid()); checkSimpleInsertRemove (index); has_size (0, index); @@ -121,12 +121,14 @@ namespace test { PMO& elm = index.find(elmID); ASSERT (elmID == elm.getID()); ASSERT (!isSameObject (elm,testObj)); // note: placements are registered as copy - ASSERT (elm == testObj); // they are semantically equivalent +// ///////////////////////////////////////////////////////////////////////////////TICKET #119 +// ASSERT (elm == testObj); // they are semantically equivalent ASSERT (elmID != testObj.getID()); // but have a distinct identity PMO::ID elmID2 = index.insert(testObj, root); ASSERT (elmID != elmID); // ...and each insert creates a new instance - ASSERT (testObj == index.find(elmID2)); +// ///////////////////////////////////////////////////////////////////////////////TICKET #119 +// ASSERT (testObj == index.find(elmID2)); ASSERT (!isSameObject (elm, index.find(elmID2))); ASSERT ( isSameObject (elm, index.find(elmID ))); @@ -151,7 +153,8 @@ namespace test { ID e133 = index.insert (testObj, e13); ID e1331 = index.insert (testObj, e133); - ASSERT (root == index.getScope(e1)); +// ///////////////////////////////////////////////////////////////////////////////TICKET #119 +// ASSERT (root == index.getScope(e1)); ASSERT (e1 == index.getScope(e11).getID()); ASSERT (e1 == index.getScope(e12).getID()); ASSERT (e1 == index.getScope(e13).getID()); @@ -162,8 +165,9 @@ namespace test { ASSERT (e1 != e13); ASSERT (e13 != e133); - ASSERT (index.getScope(e11) == index.getScope(index.find(e11))); - ASSERT (index.getScope(e131) == index.getScope(index.find(e131))); +// ///////////////////////////////////////////////////////////////////////////////TICKET #119 +// ASSERT (index.getScope(e11) == index.getScope(index.find(e11))); +// ASSERT (index.getScope(e131) == index.getScope(index.find(e131))); VERIFY_ERROR(NONEMPTY_SCOPE, index.remove(e13) ); // can't remove a scope-constituting element VERIFY_ERROR(NONEMPTY_SCOPE, index.remove(e133) ); diff --git a/tests/components/proc/mobject/session/test-scopes.hpp b/tests/components/proc/mobject/session/test-scopes.hpp index a88f94594..29da6ba88 100644 --- a/tests/components/proc/mobject/session/test-scopes.hpp +++ b/tests/components/proc/mobject/session/test-scopes.hpp @@ -37,11 +37,11 @@ namespace mobject { namespace session { namespace test { - using std::tr1::shared_ptr; - using namespace mobject::test; typedef TestPlacement PDum; + typedef std::tr1::shared_ptr PPIdx; + /** helper for tests: create a pseudo-session (actually just a PlacementIndex), From e89b4503fdef8398ae6e4975be3417e1df729f65 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 13 Dec 2009 04:27:57 +0100 Subject: [PATCH 138/377] detect if the session is up and opened, lock PlacementRef else --- src/proc/mobject/placement-ref.hpp | 3 ++- src/proc/mobject/session.hpp | 3 +++ src/proc/mobject/session/scope-path.cpp | 2 +- src/proc/mobject/session/sess-manager-impl.cpp | 7 +++++++ src/proc/mobject/session/sess-manager-impl.hpp | 2 ++ src/proc/mobject/session/session-service-fetch.hpp | 2 ++ src/proc/mobject/session/session-services.cpp | 9 +++++++++ 7 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp index d4a77549c..a1227ac66 100644 --- a/src/proc/mobject/placement-ref.hpp +++ b/src/proc/mobject/placement-ref.hpp @@ -204,7 +204,8 @@ namespace mobject { bool checkValidity () const { - return session::SessionServiceFetch::isRegisteredID (this->id_); + return session::SessionServiceFetch::isAccessible() // session interface opened? + && session::SessionServiceFetch::isRegisteredID (this->id_); } static void diff --git a/src/proc/mobject/session.hpp b/src/proc/mobject/session.hpp index 29b1248ac..d49a7397b 100644 --- a/src/proc/mobject/session.hpp +++ b/src/proc/mobject/session.hpp @@ -127,6 +127,9 @@ namespace mobject { class SessManager : private boost::noncopyable { public: + /** diagnostics: session interface opened? */ + virtual bool isUp () =0; + /** clear current session contents * without resetting overall session config. * Afterwards, the session will contain only one diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp index f464cc7d9..d20ae4ce1 100644 --- a/src/proc/mobject/session/scope-path.cpp +++ b/src/proc/mobject/session/scope-path.cpp @@ -119,7 +119,7 @@ namespace session { /** constant \em invalid path token. Created by locating an invalid scope */ - const ScopePath ScopePath::INVALID = ScopePath(Scope()); + const ScopePath ScopePath::INVALID = ScopePath(Scope()); ///////////////////////TODO can this initialisation be deferred? it causes creation of an default session very early /** a \em valid path consists of more than just the root element. diff --git a/src/proc/mobject/session/sess-manager-impl.cpp b/src/proc/mobject/session/sess-manager-impl.cpp index 2ad161383..879802c94 100644 --- a/src/proc/mobject/session/sess-manager-impl.cpp +++ b/src/proc/mobject/session/sess-manager-impl.cpp @@ -91,6 +91,13 @@ namespace session { { } + + bool + SessManagerImpl::isUp () + { + return bool(pImpl_); + } + /** @note no transactional behaviour. * may succeed partial. */ diff --git a/src/proc/mobject/session/sess-manager-impl.hpp b/src/proc/mobject/session/sess-manager-impl.hpp index 22eb310bf..5a07d5ec1 100644 --- a/src/proc/mobject/session/sess-manager-impl.hpp +++ b/src/proc/mobject/session/sess-manager-impl.hpp @@ -51,6 +51,8 @@ namespace session { virtual void load () ; virtual void save () ; + virtual bool isUp () ; + public: /* ==== proc layer internal API ==== */ diff --git a/src/proc/mobject/session/session-service-fetch.hpp b/src/proc/mobject/session/session-service-fetch.hpp index 7745d7365..50f62c7c5 100644 --- a/src/proc/mobject/session/session-service-fetch.hpp +++ b/src/proc/mobject/session/session-service-fetch.hpp @@ -63,6 +63,8 @@ namespace session { public: static PlacementMO& resolveID (PlacementMO::ID const&) ; static bool isRegisteredID (PlacementMO::ID const&) ; + + static bool isAccessible() ; }; diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp index 261e4ce4b..a8c2d55e4 100644 --- a/src/proc/mobject/session/session-services.cpp +++ b/src/proc/mobject/session/session-services.cpp @@ -33,6 +33,15 @@ namespace mobject { namespace session { + /** is the element-fetch service usable? + * Effectively this means: is the session up? + */ + bool + SessionServiceFetch::isAccessible () + { + return Session::current.isUp(); + } + /** verify the given placement-ID (hash) is valid, * by checking if it refers to a Placement instance * currently registered with the PlacementIndex of the From b74a505c4419ab1117e1cb9b3c4f64760b2fd6e7 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 13 Dec 2009 05:48:05 +0100 Subject: [PATCH 139/377] change implementation of "bottom" PlacementRef to 0-LUID --- src/lib/hash-indexed.hpp | 6 +++--- src/proc/mobject/placement-ref.hpp | 11 +++++++++-- src/proc/mobject/session/scope-path.cpp | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/lib/hash-indexed.hpp b/src/lib/hash-indexed.hpp index 5a814b131..e57565ea9 100644 --- a/src/lib/hash-indexed.hpp +++ b/src/lib/hash-indexed.hpp @@ -103,12 +103,12 @@ namespace lib { typedef lumiera_uid* LUID; - operator size_t () const { return lumiera_uid_hash ((LUID)&luid_); } - bool operator== (LuidH const& o) const { return lumiera_uid_eq ((LUID)&luid_, (LUID)&o.luid_); } + operator size_t () const { return lumiera_uid_hash (get()); } + bool operator== (LuidH const& o) const { return lumiera_uid_eq (get(), o.get()); } bool operator!= (LuidH const& o) const { return !operator== (o); } /** for passing to C APIs */ - LUID get() const { return (LUID)&luid_; } + LUID get() const { return const_cast (&luid_);} }; diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp index a1227ac66..649fad269 100644 --- a/src/proc/mobject/placement-ref.hpp +++ b/src/proc/mobject/placement-ref.hpp @@ -72,7 +72,7 @@ namespace mobject { class PlacementRef { typedef Placement PlacementMX; - typedef Placement::ID _ID; ////TODO: could we define const& here?? + typedef Placement::ID _ID; typedef Placement::Id _Id; _Id id_; @@ -103,7 +103,7 @@ namespace mobject { /** Default is an NIL Placement ref. It throws on any access. */ PlacementRef () - : id_() + : id_( bottomID() ) { REQUIRE (!isValid(), "hash-ID clash with existing ID"); } @@ -232,6 +232,13 @@ namespace mobject { return reinterpret_cast<_Id const&> (*luid); } + static _Id const& + bottomID () ///< @return marker for \em invalid reference + { + static lumiera_uid invalidLUID; + return recast (&invalidLUID); + } + static PlacementMX& access (_Id const& placementID) { diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp index d20ae4ce1..f464cc7d9 100644 --- a/src/proc/mobject/session/scope-path.cpp +++ b/src/proc/mobject/session/scope-path.cpp @@ -119,7 +119,7 @@ namespace session { /** constant \em invalid path token. Created by locating an invalid scope */ - const ScopePath ScopePath::INVALID = ScopePath(Scope()); ///////////////////////TODO can this initialisation be deferred? it causes creation of an default session very early + const ScopePath ScopePath::INVALID = ScopePath(Scope()); /** a \em valid path consists of more than just the root element. From 73fcc78cb3faee23366ee3738201483a5e9efa9f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 13 Dec 2009 05:49:08 +0100 Subject: [PATCH 140/377] PlacementIndex checks for bottom (invalid) ID --- src/proc/mobject/mobject-ref.cpp | 3 +- src/proc/mobject/placement-ref.hpp | 2 ++ src/proc/mobject/session/placement-index.hpp | 3 ++ .../proc/mobject/placement-ref-test.cpp | 32 ++++++++----------- .../mobject/session/placement-index-test.cpp | 25 +++++++++++++-- 5 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/proc/mobject/mobject-ref.cpp b/src/proc/mobject/mobject-ref.cpp index 69b4362f8..e711b26a8 100644 --- a/src/proc/mobject/mobject-ref.cpp +++ b/src/proc/mobject/mobject-ref.cpp @@ -46,7 +46,8 @@ namespace mobject { /** */ - LUMIERA_ERROR_DEFINE (INVALID_PLACEMENTREF, "unresolvable placement reference, or of incompatible type"); + LUMIERA_ERROR_DEFINE (INVALID_PLACEMENTREF, "unresolvable placement reference, or of incompatible type"); + LUMIERA_ERROR_DEFINE (BOTTOM_PLACEMENTREF, "NIL placement-ID marker encountered."); diff --git a/src/proc/mobject/placement-ref.hpp b/src/proc/mobject/placement-ref.hpp index 649fad269..08a42d660 100644 --- a/src/proc/mobject/placement-ref.hpp +++ b/src/proc/mobject/placement-ref.hpp @@ -64,6 +64,8 @@ namespace mobject { LUMIERA_ERROR_DECLARE (INVALID_PLACEMENTREF); ///< unresolvable placement reference, or of incompatible type + LUMIERA_ERROR_DECLARE (BOTTOM_PLACEMENTREF); ///< NIL placement-ID marker encountered + /** * TODO type comment diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index 928b53ad3..d591d58e9 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -176,6 +176,9 @@ namespace session { inline void __check_knownID(PlacementIndex const& idx, PlacementMO::ID id) { + if (!id) + throw lumiera::error::Logic ("Encountered a NIL Placement-ID marker" + ,LUMIERA_ERROR_BOTTOM_PLACEMENTREF); if (!idx.contains (id)) throw lumiera::error::Invalid ("Accessing Placement not registered within the index" ,LUMIERA_ERROR_NOT_IN_SESSION); ///////////////////////TICKET #197 diff --git a/tests/components/proc/mobject/placement-ref-test.cpp b/tests/components/proc/mobject/placement-ref-test.cpp index 55129eb60..14272322e 100644 --- a/tests/components/proc/mobject/placement-ref-test.cpp +++ b/tests/components/proc/mobject/placement-ref-test.cpp @@ -22,13 +22,14 @@ #include "lib/test/run.hpp" -#include "lib/lumitime.hpp" +#include "lib/test/test-helper.hpp" #include "proc/mobject/placement.hpp" #include "proc/mobject/placement-ref.hpp" #include "proc/mobject/session/placement-index.hpp" #include "proc/mobject/session/session-service-mock-index.hpp" #include "proc/mobject/explicitplacement.hpp" #include "proc/mobject/test-dummy-mobject.hpp" +#include "lib/lumitime.hpp" #include "lib/util.hpp" #include @@ -150,15 +151,9 @@ namespace test { // actually, the assignment has invalidated ref1, because of the changed ID ASSERT (p1.getID() == p2.getID()); - try - { - *ref1; - NOTREACHED(); - } - catch (...) - { - ASSERT (lumiera_error () == LUMIERA_ERROR_INVALID_PLACEMENTREF); - } + + VERIFY_ERROR(INVALID_PLACEMENTREF, *ref1 ); + ASSERT (!index->contains(p1)); // index indeed detected the invalid ref ASSERT (3 == ref2.use_count()); // but ref2 is still valid @@ -166,15 +161,14 @@ namespace test { index->remove (ref2); ASSERT (!ref2); // checks invalidity without throwing ASSERT (!refX); - try - { - *ref2; - NOTREACHED(); - } - catch (...) - { - ASSERT (lumiera_error () == LUMIERA_ERROR_INVALID_PLACEMENTREF); - } + VERIFY_ERROR(INVALID_PLACEMENTREF, *ref2 ); + + // deliberately create an invalid PlacementRef + PlacementRef bottom; + ASSERT (!bottom); + VERIFY_ERROR(INVALID_PLACEMENTREF, *bottom ); + VERIFY_ERROR(INVALID_PLACEMENTREF, bottom->specialAPI() ); + VERIFY_ERROR(INVALID_PLACEMENTREF, bottom.resolve() ); //consistency check; then reset PlacementRef index to default ASSERT (0 == index->size()); diff --git a/tests/components/proc/mobject/session/placement-index-test.cpp b/tests/components/proc/mobject/session/placement-index-test.cpp index 63fd5ca32..0e8a42b1b 100644 --- a/tests/components/proc/mobject/session/placement-index-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-test.cpp @@ -27,10 +27,10 @@ //#include "proc/mobject/session.hpp" //#include "proc/mobject/session/edl.hpp" #include "proc/mobject/session/placement-index.hpp" -#include "proc/mobject/session/testclip.hpp" +#include "proc/mobject/session/scope.hpp" #include "proc/mobject/placement.hpp" -//#include "proc/mobject/explicitplacement.hpp" #include "lib/util.hpp" +#include "proc/mobject/session/testclip.hpp" //#include //#include @@ -137,6 +137,27 @@ namespace test { } + void + checkInvalidRef (Idx index) + { + RefPlacement invalid; + PlacementMO::ID invalidID (invalid); + ASSERT (!bool(invalidID)); + ASSERT (!bool(invalid)); + + VERIFY_ERROR(BOTTOM_PLACEMENTREF, index.find(invalid) ); + VERIFY_ERROR(BOTTOM_PLACEMENTREF, index.find(invalidID) ); + VERIFY_ERROR(BOTTOM_PLACEMENTREF, index.getScope(invalidID) ); + + ASSERT (!index.contains(invalidID)); + + PMO testObj = TestClip::create(); + VERIFY_ERROR(INVALID_SCOPE, index.insert(testObj, invalidID) ); + + ASSERT (false == index.remove(invalidID)); + } + + void checkScopeHandling (Idx index) { From e3de0aac7cf8e570b4bacbb7a044ea0960c3ecaf Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 16 Dec 2009 04:54:36 +0100 Subject: [PATCH 141/377] WIP handling of the model root element within the index --- src/proc/mobject/session/mobjectfactory.cpp | 5 +- src/proc/mobject/session/placement-index.cpp | 82 +++++++++++++++++--- src/proc/mobject/session/placement-index.hpp | 5 +- src/proc/mobject/session/session-impl.cpp | 3 +- 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/proc/mobject/session/mobjectfactory.cpp b/src/proc/mobject/session/mobjectfactory.cpp index 4dcf1f3dc..934c12fd8 100644 --- a/src/proc/mobject/session/mobjectfactory.cpp +++ b/src/proc/mobject/session/mobjectfactory.cpp @@ -36,10 +36,7 @@ namespace session { - /** variant of the Clip-MO factory function, creating - * a multichannel (compound) clip. - * @todo work out the details of multichannel handling - */ + /** build a new session/model root element. */ Placement MObjectFactory::operator() (DefsManager& sessionDefaultsHandler) { diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index 997c61197..2894f6d4c 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -22,11 +22,18 @@ /** @file placement-index.cpp + ** Implementation of core session storage structure. + ** The PlacementIndex associates IDs to instances, and nested scope structure. + ** Moreover, it provides and manages the actual Placement instances (storage), + ** considered to be part of the session. ** - ** simple hash based implementation. Proof-of-concept - ** and for fleshing out the API + ** Simple hash based implementation. Proof-of-concept and for fleshing out the API. + ** The actual storage is provided by an embedded TypedAllocationManager instance, which + ** is planned (as of 12/09) to be backed later by a memory pool based custom allocator. ** ** @todo change PlacementIndex into an interface and create a separated implementation class + ** @todo really? it seems PlacementIndex has gotten an implementation class without much relevance on the Session API + ** ** @see PlacementRef ** @see PlacementIndex_test ** @@ -83,8 +90,11 @@ namespace session { /** - * Storage and implementation - * backing the PlacementIndex + * Storage and implementation backing the PlacementIndex + * - #placementTab_ is an hashtable mapping IDs to Placement + Scope + * - #scopeTab_ is an reverse association serving to keep track of + * any scope's contents + * - root scope element is stored and maintained explicitly. */ class PlacementIndex::Table { @@ -105,6 +115,7 @@ namespace session { IDTable placementTab_; ScopeTable scopeTab_; + PPlacement root_; public: Table () @@ -112,11 +123,15 @@ namespace session { ~Table () { - try { clear(); } + try + { + root_.reset(); + clear(); + } catch(lumiera::Error& err) { WARN (session, "Problem while purging PlacementIndex: %s", err.what()); - lumiera_error(); + lumiera_error(); // discard any error state } } @@ -162,8 +177,43 @@ namespace session { INFO (session, "Purging Placement Tables..."); scopeTab_.clear(); placementTab_.clear(); + + if (root_) + setupRoot (*root_); } - + + + /** insert a specially configured root entry into + * the yet empty table. Root is it's own scope + */ + void + setupRoot (PlacementMO const& rootDef) + { + REQUIRE (0 == placementTab_.size()); + REQUIRE (0 == scopeTab_.size()); + REQUIRE (!root_); + + root_ = allocator_.create (rootDef); + ID rootID = root_->getID(); + placementTab_[rootID].element = root_; + placementTab_[rootID].scope = root_; + + ENSURE (contains (rootID)); + ENSURE (scopeTab_.empty()); + ENSURE (1 == size()); + } + + PlacementMO& + getRootElement() + { + REQUIRE (root_); + REQUIRE (0 < size()); + REQUIRE (contains (root_->getID())); + + return *root_; + } + + /** Store a copy of the given Placement as new instance * within the index, together with the Scope this Placement * belongs to. @@ -258,9 +308,19 @@ namespace session { + PlacementIndex::PlacementIndex (PlacementMO const& rootDef) + : pTab_(new Table) + { + pTab_->setupRoot(rootDef); + ENSURE (isValid()); + } + PlacementIndex::PlacementIndex() : pTab_(new Table) - { } + { + pTab_->setupRoot(rootDef); //////////////////////////////////////////TODO what to put in here (it's a test dummy) + ENSURE (isValid()); + } PlacementIndex::~PlacementIndex() { } @@ -268,7 +328,7 @@ namespace session { PlacementMO& PlacementIndex::getRoot() const { - UNIMPLEMENTED ("managing the implicit root context within a scope hierarchy"); + return pTab_->getRootElement(); } @@ -284,6 +344,7 @@ namespace session { size_t PlacementIndex::size() const { + ASSERT (0 < pTab_->size()); return pTab_->size() - 1; } @@ -359,6 +420,9 @@ namespace session { bool PlacementIndex::remove (ID id) { + if (id == getRoot().getID()) + throw error::Fatal ("Request to kill the model root."); + return pTab_->removeEntry (id); } diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index d591d58e9..ef624c572 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -34,7 +34,9 @@ ** TODO ** ** \par Querying and contents discovery - ** TODO + ** TODO + ** + ** @note PlacementIndex is not threadsafe. ** ** @see PlacementRef ** @see PlacementIndex_test @@ -141,6 +143,7 @@ namespace session { + PlacementIndex(PlacementMO const&); PlacementIndex() ; ~PlacementIndex() ; diff --git a/src/proc/mobject/session/session-impl.cpp b/src/proc/mobject/session/session-impl.cpp index 1d4f59ecc..a8cde3c10 100644 --- a/src/proc/mobject/session/session-impl.cpp +++ b/src/proc/mobject/session/session-impl.cpp @@ -23,6 +23,7 @@ #include "proc/mobject/session/session-impl.hpp" #include "proc/mobject/placement.hpp" +#include "proc/mobject/mobject.hpp" #include "lib/error.hpp" namespace mobject { @@ -52,7 +53,7 @@ namespace session { focusEDL_(0), edls(1), fixture(new Fixture), - pIdx_() /////////////////////////////////////////////TODO + pIdx_( MObject::create (getDummyDefaultsManager())) ////TODO temporary hack { } From d7aab2990fdae772ac8b88dc5e13b121413eb170 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 17 Dec 2009 03:14:59 +0100 Subject: [PATCH 142/377] placeholder implementation of Label MObject --- src/proc/mobject/session/label.cpp | 27 ++++++----- src/proc/mobject/session/label.hpp | 52 +++++++++++++-------- src/proc/mobject/session/mobjectfactory.cpp | 9 ++++ src/proc/mobject/session/mobjectfactory.hpp | 3 ++ 4 files changed, 60 insertions(+), 31 deletions(-) diff --git a/src/proc/mobject/session/label.cpp b/src/proc/mobject/session/label.cpp index c5d85907d..6f6224fed 100644 --- a/src/proc/mobject/session/label.cpp +++ b/src/proc/mobject/session/label.cpp @@ -22,16 +22,21 @@ #include "proc/mobject/session/label.hpp" +#include "lib/util.hpp" -namespace mobject +using util::isnil; + +namespace mobject { +namespace session { + + + /** @todo real validity self-check for Label MObject */ + bool + Label::isValid() const { - namespace session - { - - /** */ - - - - } // namespace mobject::session - -} // namespace mobject + return !isnil (typeID_); + } + + + +}} // namespace mobject::session diff --git a/src/proc/mobject/session/label.hpp b/src/proc/mobject/session/label.hpp index b968baa68..8d349a91e 100644 --- a/src/proc/mobject/session/label.hpp +++ b/src/proc/mobject/session/label.hpp @@ -25,28 +25,40 @@ #define MOBJECT_SESSION_LABEL_H #include "proc/mobject/session/meta.hpp" +#include "lib/symbol.hpp" -namespace mobject - { - namespace session +namespace mobject { +namespace session { + + using lib::Symbol; + + + /** + * Any sort of User visible Marker or Tag, used + * to mark time positions and ranges, or specific + * locations to attach other MObjects to. + * + * @todo Placeholder code for now. + * @todo planning to provide some kind of dynamic properties (map) + */ + class Label : public Meta { - - - /** - * Any sort of User visible Marker or Tag, used - * to mark time positions and ranges, or specific - * locations to attach other MObjects to. - */ - class Label : public Meta - { - ///////////TODO: timespan fields here or already in class Meta?? - }; - - - - } // namespace mobject::session - -} // namespace mobject + ///////////TODO: timespan fields here or already in class Meta?? + + Symbol typeID_; + + virtual bool isValid() const; + + public: + Label (Symbol type) + : typeID_(type) + { } + + }; + + + +}} // namespace mobject::session #endif diff --git a/src/proc/mobject/session/mobjectfactory.cpp b/src/proc/mobject/session/mobjectfactory.cpp index 934c12fd8..8b4cf5d89 100644 --- a/src/proc/mobject/session/mobjectfactory.cpp +++ b/src/proc/mobject/session/mobjectfactory.cpp @@ -26,6 +26,7 @@ #include "proc/mobject/session/clip.hpp" #include "proc/mobject/session/track.hpp" #include "proc/mobject/session/effect.hpp" +#include "proc/mobject/session/label.hpp" #include "proc/asset/clip.hpp" #include "proc/asset/track.hpp" #include "proc/asset/effect.hpp" @@ -44,6 +45,14 @@ namespace session { } + /** build a new session/model root element. */ + Placement
                                    -
                                    +
                                    The situation focussed by this concept is when an API needs to expose a sequence of results, values or objects, instead of just yielding a function result value. As the naive solution of passing an pointer or array creates coupling to internals, it was superseded by the ~GoF [[Iterator pattern|http://en.wikipedia.org/wiki/Iterator]]. Iteration can be implemented by convention, polymorphically or by generic programming; we use the latter approach.
                                     
                                     !Lumiera Forward Iterator concept
                                    @@ -1533,7 +1533,7 @@ Another notable difference to the STL iterators is the default ctor and the {{{b
                                     * __~PtrDerefIter__ works similar, but can be used on an STL container holding //pointers,// to be dereferenced automatically on access
                                     
                                     Similar to the STL habits, Lumiera Forward Iterators should expose typedefs for {{{pointer}}}, {{{reference}}} and {{{value_type}}}.
                                    -Additionally, they may be used for resource management purposes by "hiding" a ref-counting facility, e.g. allowing to keep a snapshot or restult set around until it can't be accessed anymore.
                                    +Additionally, they may be used for resource management purposes by embedding a ref-counting facility, e.g. allowing to keep a snapshot or restult set around until it can't be accessed anymore.
                                     
                                    From 83eb6976cd03225c16009c60d88974cd1df36991 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 20 Dec 2009 04:33:24 +0100 Subject: [PATCH 149/377] draft an universal val/ref wrapper, needed by TransformIter. Seemingly I've hit a nasty problem here, because PlacementIndex should return an Placement&, but this is being fetched after-the fact from within the iterator. --- src/lib/error.hpp | 1 + src/lib/meta/trait.hpp | 44 +------- src/lib/scoped-holder.hpp | 3 +- src/lib/wrapper.hpp | 160 ++++++++++++++++++++++++++++ tests/40components.tests | 4 + tests/lib/item-wrapper-test.cpp | 183 ++++++++++++++++++++++++++++++++ 6 files changed, 353 insertions(+), 42 deletions(-) create mode 100644 src/lib/wrapper.hpp create mode 100644 tests/lib/item-wrapper-test.cpp diff --git a/src/lib/error.hpp b/src/lib/error.hpp index b17d808f8..daf2cf242 100644 --- a/src/lib/error.hpp +++ b/src/lib/error.hpp @@ -124,6 +124,7 @@ namespace lumiera { /* generic error situations */ LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached + LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value /** Macro for creating derived exception classes properly diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index 610a17e05..dce2f0030 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -26,6 +26,7 @@ #include "lib/meta/util.hpp" +#include "lib/wrapper.hpp" #include #include @@ -70,37 +71,6 @@ namespace typelist { }; - /** Extension to boost::reference_wrapper: - * Allows additionally to re-bind to another reference, - * almost like a pointer. For example this allows to cache - * results returned from an API call by reference. - * @warning potentially dangerous - */ - template - class AssignableRefWrapper - : public boost::reference_wrapper - { - typedef boost::reference_wrapper RefWrapper; - public: - - explicit AssignableRefWrapper(TY& ref) - : RefWrapper(ref) - { } - - AssignableRefWrapper& - operator= (RefWrapper const& o) - { - RefWrapper::operator= (o); - return *this; - } - - AssignableRefWrapper& - operator= (TY& newRef) - { - (*this) = RefWrapper(newRef); - return *this; - } - }; /** Type definition helper for pointer and reference types. @@ -125,23 +95,15 @@ namespace typelist { typedef pointer member_type; }; - template - struct RefTraits - { - typedef TY value_type; - typedef const TY* pointer; - typedef const TY& reference; - typedef pointer member_type; - }; - template struct RefTraits { typedef TY* pointer; typedef TY& reference; typedef TY value_type; - typedef AssignableRefWrapper member_type; + typedef lib::wrap::AssignableRefWrapper member_type; }; + //////////////////////////////////////////TODO: not needed 12/09 -- obsolete? useful? keep it? }} // namespace lumiera::typelist diff --git a/src/lib/scoped-holder.hpp b/src/lib/scoped-holder.hpp index 392a36d58..4e2c82627 100644 --- a/src/lib/scoped-holder.hpp +++ b/src/lib/scoped-holder.hpp @@ -145,7 +145,7 @@ namespace lib { char content_[sizeof(TY)]; char created_; - typedef ScopedHolder _ThisType; + typedef ScopedHolder _ThisType; ////TODO can get rid of this typedef, after using BoolCheckable static char must_be_empty (_ThisType const& ref) @@ -216,6 +216,7 @@ namespace lib { typedef char _ThisType::*unspecified_bool_type; + //////////////////////////////////TICKET #178 /** implicit conversion to "bool" */ operator unspecified_bool_type() const // never throws { diff --git a/src/lib/wrapper.hpp b/src/lib/wrapper.hpp new file mode 100644 index 000000000..095471c25 --- /dev/null +++ b/src/lib/wrapper.hpp @@ -0,0 +1,160 @@ +/* + WRAPPER.hpp - some smart wrapping and reference managing helper templates + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file wrapper.hpp + ** Library implementation: smart-pointer variations, wrappers and managing holders. + ** This is (intended to become) a loose collection of the various small helper templates + ** for wrapping, containing, placing or handling a somewhat \em problematic other object. + ** Mostly these are implemented to suit a specific need and then factored out later on. + ** + ** @see lib::TransformIter + ** + */ + + +#ifndef LIB_WRAPPER_H +#define LIB_WRAPPER_H + +//#include "lib/bool-checkable.hpp" + +//#include + + +namespace lib { +namespace wrap { + +//using std::tr1::shared_ptr; +//using std::tr1::weak_ptr; + + + + /** + * Extension to boost::reference_wrapper: + * Allows additionally to re-bind to another reference, + * almost like a pointer. For example this allows to cache + * results returned from an API call by reference. + * @warning potentially dangerous + */ + template + class AssignableRefWrapper + : public boost::reference_wrapper + { + typedef boost::reference_wrapper RefWrapper; + public: + + explicit AssignableRefWrapper(TY& ref) + : RefWrapper(ref) + { } + + AssignableRefWrapper& + operator= (RefWrapper const& o) + { + RefWrapper::operator= (o); + return *this; + } + + AssignableRefWrapper& + operator= (TY& newRef) + { + (*this) = RefWrapper(newRef); + return *this; + } + }; + + + + namespace impl { + template + struct ItemWrapperStorage + { + char content_[sizeof(TY)]; + char created_; + + }; + } + + /** + * Universal value/ref wrapper behaving like a pointer. + * A copyable, assignable value object, not managing ownership. + * It can be default constructed and \c bool evaluated to detect + * an empty holder. The value is retrieved pointer-like, by + * explicit dereferentiation. (Contrast this to boost::ref, + * where the original reference is retrieved by conversion) + * + * The purpose of this template is to be able to remember + * pretty much any kind of value or pointer or reference, + * and to subsume this handling in a single template. + * An example would be to remember the value yielded + * by a function, without any further assumptions + * regarding this function. + */ + template + class ItemWrapper + : public BoolCheckable > + { + typedef typename impl::ItemWrapperStorage Item; + + Item item_; + + public: + ItemWrapper() + : item_() + { } + + explicit + ItemWrapper(TY& o) + : item_(o) + { } + + //note: using default copy ctor and assignment operator! + + template + ItemWrapper& + operator= (X const& something) ///< accept anything assignable to TY + { + item_ = something; + } + + /* == value access == */ + TY& + operator* () + { + return item_; + } + + bool + isValid () const + { + return item_.isValid(); + } + + void + reset () + { + item_.clear(); + } + }; + + + +}} // namespace lib::wrap +#endif diff --git a/tests/40components.tests b/tests/40components.tests index bcdfa0f3c..2101294bf 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -321,6 +321,10 @@ return: 0 END +PLANNED "inline val/ref wrapper" ItemWrapper_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/util.hpp" + +#include "lib/wrapper.hpp" + +//#include +//#include +//#include +#include +#include + + + +namespace lib { +namespace test{ + + using ::Test; +// using boost::lexical_cast; + using util::isSameObject; +// using util::for_each; +// using util::isnil; +// using std::vector; + using std::string; +// using std::cout; +// using std::endl; + + + + namespace { // Test data + + ///////////TODO + + } // (END) Test data + + + + + + + + /******************************************************************************* + * @test use the ItemWrapper to define inline-storage holding values, + * pointers and references. Verify correct behaviour in each case, + * including assignment, empty check, invalid dereferentiation. + * + */ + class ItemWrapper_test : public Test + { + + + + virtual void + run (Arg) + { + UNIMPLEMENTED ("check ItemWrapper"); + + ulong ll (rand() % 1000); + string ss (randStr(50)); + const char* cp (ss.c_str()); + Tracker tt; + + verifyWrapper (ItemWrapper (ll), ll, -123); + verifyWrapper (ItemWrapper (ll), ll, 45678 ); + verifyWrapper (ItemWrapper (ll), ll, 0 ); + verifyWrapper (ItemWrapper (&ll), &ll, (ulong*) 0 ); + + verifyWrapper (ItemWrapper (ss), ss, "Lumiera"); + verifyWrapper (ItemWrapper (ss), ssl, string() ); + verifyWrapper (ItemWrapper (&ss), &ss, randStr(12)); + + verifyWrapper (ItemWrapper (tt), tt, Tracker()); + verifyWrapper (ItemWrapper (tt), tt, Tracker()); + verifyWrapper (ItemWrapper (&tt), &tt, (Tracker*) 0 ); + + verifyWrapper (ItemWrapper (cp), cp, "Lumiera"); + + verifyWrappedRef (); + } + + + template + void + verifyWrapper (ItemWrapper const& wrap, X const& val, X const& otherVal) + { + ASSERT (wrap); + + ItemWrapper copy1 (wrap); + ItemWrapper copy2; + ItemWrapper empty; + + ASSERT (copy1); + ASSERT (!copy2); + ASSERT (false == bool(empty)); + + ASSERT (wrap == copy1); + ASSERT (wrap != copy2); + ASSERT (wrap != empty); + + copy2 = copy1; + ASSERT (copy2); + ASSERT (wrap == copy2); + ASSERT (wrap != empty); + + copy2 = otherVal; + ASSERT (copy2); + ASSERT (wrap != copy2); + ASSERT (wrap != empty); + + ASSERT (val == *wrap); + ASSERT (val == *copy1); + ASSERT (val != *copy2); + VERIFY_ERROR (BOTTOM_VALUE, *empty ); + + ASSERT (otherVal == *copy2); + copy1 = copy2; + ASSERT (otherVal == *copy1); + ASSERT (otherVal == *copy2); + ASSERT (wrap != copy1); + ASSERT (wrap != copy2); + + copy1.clear(); + ASSERT (!copy1); + ASSERT (empty == copy1); + ASSERT (copy2 != copy1); + VERIFY_ERROR (BOTTOM_VALUE, *copy1 ); + }; + + + void + verifyWrappedRef () + { + int x = 5; + ItemWrapper refWrap; + ASSERT (!refWrap); + + refWrap = x; + ASSERT (refWrap); + ASSERT (5 == *refWrap); + ASSERT (x == *refWrap); + + *refWrap += 5; + ASSERT (x == 10); + + ItemWrapper ptrWrap (& *refWrap); + ASSERT (isSameObject (*ptrWrap, x)); + **ptrWrap += 13; + ASSERT (x == 23); + } + + + + }; + + LAUNCHER (ItemWrapper_test, "unit common"); + + +}} // namespace lib::test + From 3db676fa32ef1d6736113322c99b23c6dabe428b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 21 Dec 2009 05:44:29 +0100 Subject: [PATCH 150/377] base implementation fo the ItemWrapper --- src/lib/exception.cpp | 4 +- src/lib/meta/trait.hpp | 5 +- src/lib/wrapper.hpp | 95 ++++++++++++++++---- src/proc/mobject/session/placement-index.cpp | 7 +- tests/lib/item-wrapper-test.cpp | 20 ++++- 5 files changed, 104 insertions(+), 27 deletions(-) diff --git a/src/lib/exception.cpp b/src/lib/exception.cpp index a86d796ea..f3013009c 100644 --- a/src/lib/exception.cpp +++ b/src/lib/exception.cpp @@ -66,7 +66,9 @@ namespace lumiera { /* some further generic error situations */ LUMIERA_ERROR_DEFINE (WRONG_TYPE, "runtime type mismatch"); - LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached"); + LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached"); + LUMIERA_ERROR_DEFINE (BOTTOM_VALUE, "invalid or NIL value"); + } // namespace error diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index dce2f0030..010a7bcbc 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -26,12 +26,11 @@ #include "lib/meta/util.hpp" -#include "lib/wrapper.hpp" +#include "lib/wrapper.hpp" ////////////////////////TODO only because of AssignableRefWrapper -- can we get rid of this import? #include #include #include -#include #include @@ -101,7 +100,7 @@ namespace typelist { typedef TY* pointer; typedef TY& reference; typedef TY value_type; - typedef lib::wrap::AssignableRefWrapper member_type; + typedef lib::wrapper::AssignableRefWrapper member_type; }; //////////////////////////////////////////TODO: not needed 12/09 -- obsolete? useful? keep it? diff --git a/src/lib/wrapper.hpp b/src/lib/wrapper.hpp index 095471c25..04f6f42cd 100644 --- a/src/lib/wrapper.hpp +++ b/src/lib/wrapper.hpp @@ -34,16 +34,22 @@ #ifndef LIB_WRAPPER_H #define LIB_WRAPPER_H -//#include "lib/bool-checkable.hpp" +#include "lib/error.hpp" +#include "lib/bool-checkable.hpp" +#include "lib/util.hpp" //#include +#include ////////////////////////TODO only because of tr1::ref_wrapper, used by AssignableRefWrapper -- can we get rid of this import? namespace lib { -namespace wrap { +namespace wrapper { //using std::tr1::shared_ptr; //using std::tr1::weak_ptr; + using util::unConst; + using util::isSameObject; + using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE; @@ -56,9 +62,9 @@ namespace wrap { */ template class AssignableRefWrapper - : public boost::reference_wrapper + : public std::tr1::reference_wrapper { - typedef boost::reference_wrapper RefWrapper; + typedef std::tr1::reference_wrapper RefWrapper; public: explicit AssignableRefWrapper(TY& ref) @@ -111,46 +117,103 @@ namespace wrap { class ItemWrapper : public BoolCheckable > { - typedef typename impl::ItemWrapperStorage Item; + mutable + char content_[sizeof(TY)]; + bool created_; + + void + build (TY const& ref) + { + new(&content_) TY(ref); + created_ = true; + } + + void + discard () + { + if (created_) access().~TY(); + created_ = false; + } + + TY& + access () const + { + return reinterpret_cast (content_); + } - Item item_; public: ItemWrapper() - : item_() + : created_(false) { } explicit - ItemWrapper(TY& o) - : item_(o) - { } + ItemWrapper(TY const& o) + { + build (o); + } - //note: using default copy ctor and assignment operator! + ~ItemWrapper() + { + discard(); + } + + + /* == copy and assignment == */ + + ItemWrapper (ItemWrapper const& ref) + { + if (ref.isValid()) + build (*ref); + } + + ItemWrapper& + operator= (ItemWrapper const& ref) + { + if (!ref.isValid()) + discard(); + else + (*this) = (*ref); + + return *this; + } template ItemWrapper& operator= (X const& something) ///< accept anything assignable to TY { - item_ = something; + if (isSameObject (something, access() )) + { + if (created_) + access() = something; + else + build (something); + } + + return *this; } + /* == value access == */ TY& - operator* () + operator* () const { - return item_; + if (!created_) + throw lumiera::error::State ("accessing uninitialised value/ref wrapper" + , LUMIERA_ERROR_BOTTOM_VALUE); + return access(); } bool isValid () const { - return item_.isValid(); + return created_; } void reset () { - item_.clear(); + discard(); } }; diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index 0ba5f0836..b90f01de2 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -180,8 +180,9 @@ namespace session { { REQUIRE (contains (id)); ScopeContents contents = scopeTab_.equal_range (id); - return iterator (ScopeRangeIter(contents.first, contents.second) - ,rangeIndexElementsResolver() ); + UNIMPLEMENTED ("WIP-WIP-WIP"); +// return iterator (ScopeRangeIter(contents.first, contents.second) +// ,scopeIndexElementsResolver() ); } @@ -327,7 +328,7 @@ namespace session { * resolve it through the main index table (placementTab_). */ PlacementMO& - resolveScopeIndexElement(pair const& entry) + resolveScopeIndexElement(pair const& entry) const { ID elemID (entry.second); ASSERT (contains (elemID)); diff --git a/tests/lib/item-wrapper-test.cpp b/tests/lib/item-wrapper-test.cpp index 29af26510..28226bd7e 100644 --- a/tests/lib/item-wrapper-test.cpp +++ b/tests/lib/item-wrapper-test.cpp @@ -37,6 +37,7 @@ namespace lib { +namespace wrapper { namespace test{ using ::Test; @@ -46,6 +47,7 @@ namespace test{ // using util::isnil; // using std::vector; using std::string; + using lib::test::randStr; // using std::cout; // using std::endl; @@ -82,9 +84,10 @@ namespace test{ ulong ll (rand() % 1000); string ss (randStr(50)); const char* cp (ss.c_str()); - Tracker tt; +// Tracker tt; - verifyWrapper (ItemWrapper (ll), ll, -123); + verifyWrapper (ItemWrapper (ll), ll, -123); +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! verifyWrapper (ItemWrapper (ll), ll, 45678 ); verifyWrapper (ItemWrapper (ll), ll, 0 ); verifyWrapper (ItemWrapper (&ll), &ll, (ulong*) 0 ); @@ -98,6 +101,7 @@ namespace test{ verifyWrapper (ItemWrapper (&tt), &tt, (Tracker*) 0 ); verifyWrapper (ItemWrapper (cp), cp, "Lumiera"); +#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! verifyWrappedRef (); } @@ -117,13 +121,17 @@ namespace test{ ASSERT (!copy2); ASSERT (false == bool(empty)); +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! ASSERT (wrap == copy1); +#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! ASSERT (wrap != copy2); ASSERT (wrap != empty); copy2 = copy1; ASSERT (copy2); +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! ASSERT (wrap == copy2); +#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! ASSERT (wrap != empty); copy2 = otherVal; @@ -143,9 +151,11 @@ namespace test{ ASSERT (wrap != copy1); ASSERT (wrap != copy2); - copy1.clear(); + copy1.reset(); ASSERT (!copy1); +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! ASSERT (empty == copy1); +#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! ASSERT (copy2 != copy1); VERIFY_ERROR (BOTTOM_VALUE, *copy1 ); }; @@ -154,6 +164,7 @@ namespace test{ void verifyWrappedRef () { +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! int x = 5; ItemWrapper refWrap; ASSERT (!refWrap); @@ -170,6 +181,7 @@ namespace test{ ASSERT (isSameObject (*ptrWrap, x)); **ptrWrap += 13; ASSERT (x == 23); +#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! } @@ -179,5 +191,5 @@ namespace test{ LAUNCHER (ItemWrapper_test, "unit common"); -}} // namespace lib::test +}}} // namespace lib::wrapper::test From 6a7f325ecf4d970ec24e42589d64553a1026b673 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 21 Dec 2009 05:45:02 +0100 Subject: [PATCH 151/377] static assert to protect against misguided equality comparison --- src/lib/bool-checkable.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/lib/bool-checkable.hpp b/src/lib/bool-checkable.hpp index dd03610b8..db2a7ecfb 100644 --- a/src/lib/bool-checkable.hpp +++ b/src/lib/bool-checkable.hpp @@ -54,6 +54,7 @@ #define LIB_BOOL_CHECKABLE_H +#include namespace lib { @@ -117,6 +118,18 @@ namespace lib { return !(obj.*isValid)(); } + + /** safety guard: when this comparison kicks in, the compiler + * is about to use an implicit bool conversion on both sides to + * perform an equality test. This is most likely not what you want. + * Define an explicit equality comparison in the class using BoolCheckable! + */ + friend bool + operator== (BoolCheckable const&, BoolCheckable const&) + { + BOOST_STATIC_ASSERT (false && sizeof(T) ); + return false; + } }; From e5ab9d73ebeefeed240327bdd7ece672f4eba771 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 21 Dec 2009 06:19:56 +0100 Subject: [PATCH 152/377] add specialisation to deal with wrapping a reference... --- src/lib/wrapper.hpp | 59 +++++++++++++++++++++++++++++++++ tests/lib/item-wrapper-test.cpp | 40 ++++++++++++---------- 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/lib/wrapper.hpp b/src/lib/wrapper.hpp index 04f6f42cd..b37f79ce7 100644 --- a/src/lib/wrapper.hpp +++ b/src/lib/wrapper.hpp @@ -217,6 +217,65 @@ namespace wrapper { } }; + /** + * Specialisation of the ItemWrapper to deal with references, + * as if they were pointer values. Allows the reference value + * to be default constructed to \c NULL and to be re-assigned. + */ + template + class ItemWrapper + : public BoolCheckable > + { +// mutable + TY * content_; + + + public: + ItemWrapper() + : content_() + { } + + explicit + ItemWrapper(TY& o) + : content_( &o ) + { } + + + /* using default copy and assignment */ + + /** allowing to re-bind the reference */ + ItemWrapper& + operator= (TY& otherRef) + { + content_ = &otherRef; + return *this; + } + + + + /* == value access == */ + TY& + operator* () const + { + if (!content_) + throw lumiera::error::State ("accessing uninitialised reference wrapper" + , LUMIERA_ERROR_BOTTOM_VALUE); + return *content_; + } + + bool + isValid () const + { + return bool(content_); + } + + void + reset () + { + content_ = 0; + } + }; + }} // namespace lib::wrap diff --git a/tests/lib/item-wrapper-test.cpp b/tests/lib/item-wrapper-test.cpp index 28226bd7e..1bdf37e89 100644 --- a/tests/lib/item-wrapper-test.cpp +++ b/tests/lib/item-wrapper-test.cpp @@ -79,28 +79,31 @@ namespace test{ virtual void run (Arg) { - UNIMPLEMENTED ("check ItemWrapper"); + ulong l1 (rand() % 1000); + ulong l2 (rand() % 1000); + string s1 (randStr(50)); + string s2 (randStr(50)); + const char* cp (s1.c_str()); +// Tracker t1; +// Tracker t2; - ulong ll (rand() % 1000); - string ss (randStr(50)); - const char* cp (ss.c_str()); -// Tracker tt; - - verifyWrapper (ItemWrapper (ll), ll, -123); + verifyWrapper (l1, l2); + verifyWrapper (l1, l2); #if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! - verifyWrapper (ItemWrapper (ll), ll, 45678 ); - verifyWrapper (ItemWrapper (ll), ll, 0 ); - verifyWrapper (ItemWrapper (&ll), &ll, (ulong*) 0 ); + verifyWrapper (&l1, &l2); + verifyWrapper ((0), &l2); + verifyWrapper (&l1, (0)); + verifyWrapper (l1, l2); - verifyWrapper (ItemWrapper (ss), ss, "Lumiera"); - verifyWrapper (ItemWrapper (ss), ssl, string() ); - verifyWrapper (ItemWrapper (&ss), &ss, randStr(12)); + verifyWrapper (s1, s2); + verifyWrapper (s1, s2); + verifyWrapper (&s1, &s2); - verifyWrapper (ItemWrapper (tt), tt, Tracker()); - verifyWrapper (ItemWrapper (tt), tt, Tracker()); - verifyWrapper (ItemWrapper (&tt), &tt, (Tracker*) 0 ); + verifyWrapper (t1, t2); + verifyWrapper (t1, t2); + verifyWrapper (&t1, &t2); - verifyWrapper (ItemWrapper (cp), cp, "Lumiera"); + verifyWrapper (cp, "Lumiera"); #endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! verifyWrappedRef (); @@ -109,8 +112,9 @@ namespace test{ template void - verifyWrapper (ItemWrapper const& wrap, X const& val, X const& otherVal) + verifyWrapper (X val, X otherVal) { + const ItemWrapper wrap(val); ASSERT (wrap); ItemWrapper copy1 (wrap); From 97faf3dcb844746b7a984092f410eeead0c9f8b5 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 21 Dec 2009 07:52:58 +0100 Subject: [PATCH 153/377] ItemWrapper unit test pass. Closes #476 --- src/lib/wrapper.hpp | 38 +++++++++------ tests/40components.tests | 3 +- tests/lib/item-wrapper-test.cpp | 84 +++++++++++++++++++++++---------- 3 files changed, 86 insertions(+), 39 deletions(-) diff --git a/src/lib/wrapper.hpp b/src/lib/wrapper.hpp index b37f79ce7..7772965ab 100644 --- a/src/lib/wrapper.hpp +++ b/src/lib/wrapper.hpp @@ -87,16 +87,7 @@ namespace wrapper { }; - - namespace impl { - template - struct ItemWrapperStorage - { - char content_[sizeof(TY)]; - char created_; - - }; - } + /** * Universal value/ref wrapper behaving like a pointer. @@ -108,7 +99,7 @@ namespace wrapper { * * The purpose of this template is to be able to remember * pretty much any kind of value or pointer or reference, - * and to subsume this handling in a single template. + * and to subsume this handling within a single template. * An example would be to remember the value yielded * by a function, without any further assumptions * regarding this function. @@ -173,7 +164,7 @@ namespace wrapper { if (!ref.isValid()) discard(); else - (*this) = (*ref); + this->operator= (*ref); return *this; } @@ -182,7 +173,7 @@ namespace wrapper { ItemWrapper& operator= (X const& something) ///< accept anything assignable to TY { - if (isSameObject (something, access() )) + if (!isSameObject (something, access() )) { if (created_) access() = something; @@ -217,6 +208,7 @@ namespace wrapper { } }; + /** * Specialisation of the ItemWrapper to deal with references, * as if they were pointer values. Allows the reference value @@ -226,7 +218,7 @@ namespace wrapper { class ItemWrapper : public BoolCheckable > { -// mutable + TY * content_; @@ -278,5 +270,23 @@ namespace wrapper { + /** allow equality comparison if the wrapped types are comparable */ + template + inline bool + operator== (ItemWrapper const& w1, ItemWrapper const& w2) + { + return (!w1 && !w2) + || ( w1 && w2 && (*w1)==(*w2)); + } + + template + inline bool + operator!= (ItemWrapper const& w1, ItemWrapper const& w2) + { + return !(w1 == w2); + } + + + }} // namespace lib::wrap #endif diff --git a/tests/40components.tests b/tests/40components.tests index 2101294bf..6aae03697 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -321,7 +321,8 @@ return: 0 END -PLANNED "inline val/ref wrapper" ItemWrapper_test < -//#include +#include //#include #include #include @@ -48,14 +48,27 @@ namespace test{ // using std::vector; using std::string; using lib::test::randStr; -// using std::cout; -// using std::endl; + using lib::test::showSizeof; + using std::cout; + using std::endl; - namespace { // Test data + namespace { // Test helper: yet another ctor/dtor counting class + + long cntTracker = 0; - ///////////TODO + struct Tracker + { + uint i_; + + Tracker() : i_(rand() % 500) { ++cntTracker; } + Tracker(Tracker const& ot) : i_(ot.i_) { ++cntTracker; } + ~Tracker() { --cntTracker; } + }; + + bool operator== (Tracker const& t1, Tracker const& t2) { return t1.i_ == t2.i_; } + bool operator!= (Tracker const& t1, Tracker const& t2) { return t1.i_ != t2.i_; } } // (END) Test data @@ -68,14 +81,13 @@ namespace test{ /******************************************************************************* * @test use the ItemWrapper to define inline-storage holding values, * pointers and references. Verify correct behaviour in each case, - * including assignment, empty check, invalid dereferentiation. + * including (self)assignment, empty check, invalid dereferentiation. * */ class ItemWrapper_test : public Test { - virtual void run (Arg) { @@ -84,12 +96,9 @@ namespace test{ string s1 (randStr(50)); string s2 (randStr(50)); const char* cp (s1.c_str()); -// Tracker t1; -// Tracker t2; verifyWrapper (l1, l2); verifyWrapper (l1, l2); -#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! verifyWrapper (&l1, &l2); verifyWrapper ((0), &l2); verifyWrapper (&l1, (0)); @@ -99,13 +108,10 @@ namespace test{ verifyWrapper (s1, s2); verifyWrapper (&s1, &s2); - verifyWrapper (t1, t2); - verifyWrapper (t1, t2); - verifyWrapper (&t1, &t2); - verifyWrapper (cp, "Lumiera"); -#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! + + verifySaneInstanceHandling(); verifyWrappedRef (); } @@ -117,6 +123,8 @@ namespace test{ const ItemWrapper wrap(val); ASSERT (wrap); + cout << "ItemWrapper: " << showSizeof(wrap) << endl; + ItemWrapper copy1 (wrap); ItemWrapper copy2; ItemWrapper empty; @@ -125,17 +133,13 @@ namespace test{ ASSERT (!copy2); ASSERT (false == bool(empty)); -#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! ASSERT (wrap == copy1); -#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! ASSERT (wrap != copy2); ASSERT (wrap != empty); copy2 = copy1; ASSERT (copy2); -#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! ASSERT (wrap == copy2); -#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! ASSERT (wrap != empty); copy2 = otherVal; @@ -154,21 +158,53 @@ namespace test{ ASSERT (otherVal == *copy2); ASSERT (wrap != copy1); ASSERT (wrap != copy2); + + copy1 = empty; // assign empty to discard value + copy1 = copy1; // self-assign empty + ASSERT (!copy1); + copy1 = copy2; + ASSERT (otherVal == *copy1); + copy1 = copy1; // self-assign (will be suppressed) + ASSERT (otherVal == *copy1); + copy1 = *copy1; // self-assign also detected in this case + ASSERT (otherVal == *copy2); + + ASSERT (copy1); copy1.reset(); ASSERT (!copy1); -#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! ASSERT (empty == copy1); -#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! ASSERT (copy2 != copy1); VERIFY_ERROR (BOTTOM_VALUE, *copy1 ); }; + /** @test verify that ctor and dtor calls are balanced, + * even when assigning and self-assigning. + */ + void + verifySaneInstanceHandling() + { + cntTracker = 0; + { + Tracker t1; + Tracker t2; + + verifyWrapper (t1, t2); + verifyWrapper (t1, t2); + verifyWrapper (&t1, &t2); + + } + ASSERT (0 == cntTracker); + } + + + /** @test verify especially that we can wrap and handle + * a reference "value" in a pointer-like manner + */ void verifyWrappedRef () { -#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 475 !!!!!!!!! int x = 5; ItemWrapper refWrap; ASSERT (!refWrap); @@ -182,10 +218,10 @@ namespace test{ ASSERT (x == 10); ItemWrapper ptrWrap (& *refWrap); - ASSERT (isSameObject (*ptrWrap, x)); + ASSERT ( isSameObject (**ptrWrap, x)); + ASSERT (!isSameObject ( *ptrWrap, &x)); **ptrWrap += 13; ASSERT (x == 23); -#endif //////////////////////////////////////////////////////////////////////////////////////TODO using yet undefined facilities.....!!!!! } From 4cb32047aeca01b3bcf8448eee2754b403f8e20b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 23 Dec 2009 01:36:11 +0100 Subject: [PATCH 154/377] WIP: define behaviour of a result remembering function... --- tests/lib/item-wrapper-test.cpp | 42 ++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/tests/lib/item-wrapper-test.cpp b/tests/lib/item-wrapper-test.cpp index e341fd115..b7532ef4b 100644 --- a/tests/lib/item-wrapper-test.cpp +++ b/tests/lib/item-wrapper-test.cpp @@ -29,10 +29,11 @@ #include "lib/wrapper.hpp" //#include +#include #include -//#include #include #include +#include @@ -45,7 +46,8 @@ namespace test{ using util::isSameObject; // using util::for_each; // using util::isnil; -// using std::vector; + using std::tr1::bind; + using std::vector; using std::string; using lib::test::randStr; using lib::test::showSizeof; @@ -113,6 +115,8 @@ namespace test{ verifySaneInstanceHandling(); verifyWrappedRef (); + + verifyFunctionResult (); } @@ -225,7 +229,39 @@ namespace test{ } - + /** @test verify an extension built on top of the ItemWrapper: + * a function which remembers the last result */ + void + verifyFunctionResult() + { + vector testVec; + for (uint i=0; i<10; ++i) + testVec.push_back(i); + + FunctionResult funRes (bind (&vector::at, _1 )); + + // function was never invoked, thus the remembered result is NIL + ASSERT (!funRes); + VERIFY_ERROR (BOTTOM_VALUE, *funRes ); + + int& r5 = funRes (5); + ASSERT (5 == r5); + ASSERT (isSameObject (r5, testVec[5])); + + int r5x = *funRes; + ASSERT (isSameObject (r5, r5x)); + + ASSERT ( isSameObject (r5, *funRes)); + int r7 = funRes (7); + ASSERT (!isSameObject (r5, *funRes)); + ASSERT (!isSameObject (r7, *funRes)); + + -- r5x; + ++ *funRes; + ASSERT (5+1 == testVec[5]); + ASSERT (7+1 == testVec[7]); + ASSERT (7+1 == r7); + } }; LAUNCHER (ItemWrapper_test, "unit common"); From 534ae166052d43d39303907841ef4f5e45707186 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 23 Dec 2009 04:46:09 +0100 Subject: [PATCH 155/377] implemented this FunctionResult template, needed for Ticket #175 --- src/lib/wrapper.hpp | 81 +++++++++++++++++++++++++++++---- tests/lib/item-wrapper-test.cpp | 66 +++++++++++++++++---------- 2 files changed, 115 insertions(+), 32 deletions(-) diff --git a/src/lib/wrapper.hpp b/src/lib/wrapper.hpp index 7772965ab..76a9f6282 100644 --- a/src/lib/wrapper.hpp +++ b/src/lib/wrapper.hpp @@ -25,7 +25,15 @@ ** This is (intended to become) a loose collection of the various small helper templates ** for wrapping, containing, placing or handling a somewhat \em problematic other object. ** Mostly these are implemented to suit a specific need and then factored out later on. - ** + ** - AssignableRefWrapper is not used anymore as of 12/09 + ** - ItemWrapper is a similar concept, but more like a smart-ptr. Moreover, + ** it can be instantiated with a value type, a pointer or a reference type, + ** yielding the same behaviour in all cases (useful for building templates) + ** - FunctionResult is the combination of ItemWrapper with a functor object + ** to cache the function result value. It is used to implement a transforming + ** iterator, especially supporting the case when the transformation function + ** is to return a reference + ** ** @see lib::TransformIter ** */ @@ -36,28 +44,28 @@ #include "lib/error.hpp" #include "lib/bool-checkable.hpp" +#include "lib/meta/function.hpp" +#include "lib/meta/function-closure.hpp" #include "lib/util.hpp" -//#include -#include ////////////////////////TODO only because of tr1::ref_wrapper, used by AssignableRefWrapper -- can we get rid of this import? +#include namespace lib { namespace wrapper { -//using std::tr1::shared_ptr; -//using std::tr1::weak_ptr; using util::unConst; using util::isSameObject; + using lumiera::typelist::FunctionSignature; using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE; + using std::tr1::function; /** * Extension to boost::reference_wrapper: * Allows additionally to re-bind to another reference, - * almost like a pointer. For example this allows to cache - * results returned from an API call by reference. + * almost like a pointer. Helpful for building templates. * @warning potentially dangerous */ template @@ -87,7 +95,7 @@ namespace wrapper { }; - + /** * Universal value/ref wrapper behaving like a pointer. @@ -278,7 +286,6 @@ namespace wrapper { return (!w1 && !w2) || ( w1 && w2 && (*w1)==(*w2)); } - template inline bool operator!= (ItemWrapper const& w1, ItemWrapper const& w2) @@ -288,5 +295,61 @@ namespace wrapper { + /** + * Extension of ItemWrapper: a function remembering + * the result of the last invocation. Initially, the "value" + * is bottom (undefined, NIL), until the function is invoked + * for the first time. After that, the result of the last + * invocation can be accessed by \c operator*() + * + * @see TransformIter usage example + */ + template + class FunctionResult + : public function + , public lib::BoolCheckable > + { + typedef typename FunctionSignature >::Ret Res; + typedef ItemWrapper ResWrapper; + + ResWrapper lastResult_; + + + Res + captureResult (Res res) + { + lastResult_ = res; + return res; + } + + public: + /** Explanation: + * - *this is a \em function + * - initially it is defined as invalid + * - then we build the function composition of + * the target function, and a function storing + * the result value into the ResWrapper member + * - define ourselves by assigning the resulting + * composite function + */ + template + FunctionResult (FUN targetFunction) + { + using std::tr1::bind; + using std::tr1::placeholders::_1; + using lumiera::typelist::func::chained; + + function doCaptureResult = bind (&FunctionResult::captureResult, this, _1 ); + function chainedWithResCapture = chained (targetFunction, doCaptureResult); + + function::operator= (chainedWithResCapture); // define the function (baseclass) + } + + + Res operator*() const { return *lastResult_; } + bool isValid () const { return lastResult_.isValid(); } + }; + + }} // namespace lib::wrap #endif diff --git a/tests/lib/item-wrapper-test.cpp b/tests/lib/item-wrapper-test.cpp index b7532ef4b..2ed1e3b53 100644 --- a/tests/lib/item-wrapper-test.cpp +++ b/tests/lib/item-wrapper-test.cpp @@ -28,7 +28,6 @@ #include "lib/wrapper.hpp" -//#include #include #include #include @@ -42,15 +41,14 @@ namespace wrapper { namespace test{ using ::Test; -// using boost::lexical_cast; - using util::isSameObject; -// using util::for_each; -// using util::isnil; - using std::tr1::bind; - using std::vector; - using std::string; using lib::test::randStr; using lib::test::showSizeof; + using util::isSameObject; + + using std::tr1::placeholders::_1; + using std::tr1::ref; + using std::vector; + using std::string; using std::cout; using std::endl; @@ -59,7 +57,7 @@ namespace test{ namespace { // Test helper: yet another ctor/dtor counting class long cntTracker = 0; - + struct Tracker { uint i_; @@ -72,7 +70,22 @@ namespace test{ bool operator== (Tracker const& t1, Tracker const& t2) { return t1.i_ == t2.i_; } bool operator!= (Tracker const& t1, Tracker const& t2) { return t1.i_ != t2.i_; } - } // (END) Test data + + /// to be bound as test function.... + int& + pickElement (vector& vec, size_t idx) + { + return vec[idx]; + } + + function + pickElement_ofVector (vector& vec) + { + return std::tr1::bind (pickElement, ref(vec), _1 ); + } + + + } // (END) Test helpers @@ -81,10 +94,11 @@ namespace test{ /******************************************************************************* - * @test use the ItemWrapper to define inline-storage holding values, - * pointers and references. Verify correct behaviour in each case, - * including (self)assignment, empty check, invalid dereferentiation. - * + * @test use the ItemWrapper to define inline-storage holding values, + * pointers and references. Verify correct behaviour in each case, + * including (self)assignment, empty check, invalid dereferentiation. + * + * @see wrapper.hpp */ class ItemWrapper_test : public Test { @@ -162,16 +176,16 @@ namespace test{ ASSERT (otherVal == *copy2); ASSERT (wrap != copy1); ASSERT (wrap != copy2); - + copy1 = empty; // assign empty to discard value - copy1 = copy1; // self-assign empty + copy1 = copy1; // self-assign empty value ASSERT (!copy1); copy1 = copy2; ASSERT (otherVal == *copy1); copy1 = copy1; // self-assign (will be suppressed) ASSERT (otherVal == *copy1); - copy1 = *copy1; // self-assign also detected in this case + copy1 = *copy1; // self-assign also detected in this case ASSERT (otherVal == *copy2); ASSERT (copy1); @@ -230,7 +244,13 @@ namespace test{ /** @test verify an extension built on top of the ItemWrapper: - * a function which remembers the last result */ + * a function which remembers the last result. We use a + * test function, which picks a member of an vector and + * returns a \em reference to it. Thus the cached "result" + * can be used to access and change the values within the + * original vector. In a real world usage scenario, such a + * function could be an (expensive) data structure access. + */ void verifyFunctionResult() { @@ -238,7 +258,7 @@ namespace test{ for (uint i=0; i<10; ++i) testVec.push_back(i); - FunctionResult funRes (bind (&vector::at, _1 )); + FunctionResult funRes (pickElement_ofVector(testVec)); // function was never invoked, thus the remembered result is NIL ASSERT (!funRes); @@ -248,17 +268,17 @@ namespace test{ ASSERT (5 == r5); ASSERT (isSameObject (r5, testVec[5])); - int r5x = *funRes; + int& r5x = *funRes; ASSERT (isSameObject (r5, r5x)); ASSERT ( isSameObject (r5, *funRes)); - int r7 = funRes (7); + int& r7 = funRes (7); ASSERT (!isSameObject (r5, *funRes)); - ASSERT (!isSameObject (r7, *funRes)); + ASSERT ( isSameObject (r7, *funRes)); -- r5x; ++ *funRes; - ASSERT (5+1 == testVec[5]); + ASSERT (5-1 == testVec[5]); ASSERT (7+1 == testVec[7]); ASSERT (7+1 == r7); } From f2406c23a1ffda8a2938690ff389bf8660ab7b5e Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 23 Dec 2009 13:10:31 -0500 Subject: [PATCH 156/377] bork bork bork by pulling this you agree to... --- src/backend/thread-wrapper.hpp | 2 +- src/backend/threadpool.c | 96 ++++++++++++++++++-------------- src/backend/threadpool.h | 17 ++++-- src/backend/threads.c | 81 ++++++++++++++++++--------- src/backend/threads.h | 23 +++++--- tests/30backend-threadpool.tests | 63 +++------------------ tests/backend/test-threadpool.c | 70 +++++++++++++++++++++-- tests/backend/test-threads.c | 3 - tests/test.sh | 2 +- 9 files changed, 208 insertions(+), 149 deletions(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 3f897b582..f8ec2bc87 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -177,10 +177,10 @@ namespace backend { lumiera_thread_run ( kind , &run // invoking the run helper and.. , this // passing this start context as parameter - , joinCond // maybe wait-blocking for the thread to terminate , purpose.c() , logging_flag ); + (void)joinCond; if (!res) throw lumiera::error::State("failed to create new thread."); diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 66ecd4e33..2a33978d6 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -53,21 +53,22 @@ void* pool_thread_loop(void * arg) } void -lumiera_threadpool_init(unsigned limit) +lumiera_threadpool_init() { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.pool[i].list); - threadpool.pool[i].max_threads = limit; - threadpool.pool[i].working_thread_count = 0; + threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; //TODO: configure each pools' pthread_attrs appropriately pthread_attr_init (&threadpool.pool[i].pthread_attrs); - pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); + // cehteh prefers that threads are joinable by default + //pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); //cancel... lumiera_mutex_init(&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); + lumiera_reccondition_init (&threadpool.pool[i].signal, "thread-signal", &NOBUG_FLAG(threadpool)); } } @@ -78,10 +79,16 @@ lumiera_threadpool_destroy(void) for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { ECHO ("destroying individual pool #%d", i); - // no locking is done at this point - ECHO ("number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); - LLIST_WHILE_HEAD(&threadpool.pool[i].list, thread) - lumiera_thread_delete((LumieraThread)thread); + LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[i].lock) + { + REQUIRE (0 == threadpool.pool[i].working_thread_count, "%d threads are running", threadpool.pool[i].working_thread_count); + // TODO need to have a stronger assertion that no threads are really running because they will not even be in the list + ECHO ("number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); + LLIST_WHILE_HEAD(&threadpool.pool[i].list, t) + { + lumiera_thread_delete((LumieraThread)t); + } + } ECHO ("destroying the pool mutex"); lumiera_mutex_destroy (&threadpool.pool[i].lock, &NOBUG_FLAG (threadpool)); ECHO ("pool mutex destroyed"); @@ -89,6 +96,15 @@ lumiera_threadpool_destroy(void) } } +void lumiera_threadpool_unlink(LumieraThread thread) +{ + REQUIRE (thread, "invalid thread given"); + REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); + llist_unlink(&thread->node); + ENSURE (llist_is_empty(&thread->node), "failed to unlink the thread"); +} + + LumieraThread lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, const char* purpose, @@ -97,52 +113,45 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, LumieraThread ret; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); - if (llist_is_empty (&threadpool.pool[kind].list)) - { - // TODO: fill in the reccondition argument, currently NULL - FIXME ("this max thread logic needs to be deeply thought about and made more efficient as well as rebust"); - if (threadpool.pool[kind].working_thread_count - + threadpool.pool[kind].idle_thread_count - < threadpool.pool[kind].max_threads) { - ret = lumiera_thread_new (kind, NULL, purpose, flag, + LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[kind].signal) + { + if (llist_is_empty (&threadpool.pool[kind].list)) + { + + ret = lumiera_thread_new (kind, purpose, flag, &threadpool.pool[kind].pthread_attrs); - threadpool.pool[kind].working_thread_count++; + threadpool.pool[kind].idle_thread_count++; ENSURE (ret, "did not create a valid thread"); + LUMIERA_RECCONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].list)); } - else - { - //ERROR (threadpool, "did not create a new thread because per-pool limit was reached: %d", threadpool.pool[kind].max_threads); - LUMIERA_DIE(ERRNO); - } - } - else - { - // use an existing thread, pick the first one - // remove it from the pool's list - LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[kind].lock) - { - ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.pool[kind].list))); - threadpool.pool[kind].working_thread_count++; - threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count - ENSURE (threadpool.pool[kind].idle_thread_count == - llist_count(&threadpool.pool[kind].list), - "idle thread count %d is wrong, should be %d", - threadpool.pool[kind].idle_thread_count, - llist_count(&threadpool.pool[kind].list)); - } - ENSURE (ret, "did not find a valid thread"); - } - return ret; + // use an existing thread, pick the first one + // remove it from the pool's list + ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.pool[kind].list))); + REQUIRE (ret->state == LUMIERA_THREADSTATE_IDLE, "trying to return a non-idle thread (state=%s)", lumiera_threadstate_names[ret->state]); + threadpool.pool[kind].working_thread_count++; + threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count + ENSURE (threadpool.pool[kind].idle_thread_count == + llist_count(&threadpool.pool[kind].list), + "idle thread count %d is wrong, should be %d", + threadpool.pool[kind].idle_thread_count, + llist_count(&threadpool.pool[kind].list)); + ENSURE (ret, "did not find a valid thread"); + } + return ret; } +// TODO: rename to lumiera_threadpool_park_thread void -lumiera_threadpool_release_thread(LumieraThread thread) +lumiera_threadpool_park_thread(LumieraThread thread) { REQUIRE (thread, "invalid thread given"); REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); - LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[thread->kind].lock) + REQUIRE (thread->state != LUMIERA_THREADSTATE_IDLE, "trying to park an already idle thread"); + + LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[thread->kind].signal) { + thread->state = LUMIERA_THREADSTATE_IDLE; REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); llist_insert_head(&threadpool.pool[thread->kind].list, &thread->node); threadpool.pool[thread->kind].working_thread_count--; @@ -153,6 +162,7 @@ lumiera_threadpool_release_thread(LumieraThread thread) threadpool.pool[thread->kind].idle_thread_count, llist_count(&threadpool.pool[thread->kind].list)); // REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); + LUMIERA_RECCONDITION_BROADCAST; } } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 03b56a4fe..de545876c 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -55,12 +55,12 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, struct nobug_flag* flag); /** - * Release a thread - * This ends up putting a (parked/idle) thread back on the list of an appropriate threadpool. + * Park a thread + * This ends up putting a finished thread back on the list of an appropriate threadpool. * This function doesn't need to be accessible outside of the threadpool implementation. */ void -lumiera_threadpool_release_thread(LumieraThread thread); +lumiera_threadpool_park_thread(LumieraThread thread); typedef struct lumiera_threadpool_struct lumiera_threadpool; typedef lumiera_threadpool* LumieraThreadpool; @@ -71,23 +71,28 @@ struct lumiera_threadpool_struct { llist list; lumiera_mutex lock; - unsigned max_threads; unsigned working_thread_count; unsigned idle_thread_count; pthread_attr_t pthread_attrs; + lumiera_reccondition signal; } pool[LUMIERA_THREADCLASS_COUNT]; }; /** * Initialize the thread pool. - * @param limit the maximum number of threads (idle+working) allowed per pool */ void -lumiera_threadpool_init(unsigned limit); +lumiera_threadpool_init(); void lumiera_threadpool_destroy(void); +/** + * Just remove the thread structure from an associated pool list. + */ +void +lumiera_threadpool_unlink(LumieraThread thread); + #endif /* // Local Variables: diff --git a/src/backend/threads.c b/src/backend/threads.c index 0520de288..a75b7f81b 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -67,9 +67,29 @@ struct lumiera_thread_mockup LumieraReccondition finished; }; -static void* thread_loop (void* arg) +static void* thread_loop (void* thread) { - (void)arg; + LumieraThread t = (LumieraThread)thread; + + pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); + + REQUIRE (t, "thread does not exist"); + + ECHO ("entering section 1"); + // this seems to deadlock unexpectedly: + LUMIERA_RECCONDITION_SECTION (threads, &t->signal) + { + do { + // NULL function means: no work to do + if (t->function) + t->function (t->arguments); + lumiera_threadpool_park_thread(t); + LUMIERA_RECCONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); + } while (t->state != LUMIERA_THREADSTATE_SHUTDOWN); + // SHUTDOWN state + + ECHO ("thread quitting"); + } return 0; } @@ -79,22 +99,23 @@ LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*function)(void *), void * arg, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag) { - (void)finished; - (void)function; - (void)arg; + REQUIRE (function, "invalid function"); + // ask the threadpool for a thread (it might create a new one) LumieraThread self = lumiera_threadpool_acquire_thread(kind, purpose, flag); - // TODO: set the function and data to be run - // lumiera_thread_set_func_data (self, start_routine, arg, purpose, flag); + // set the function and data to be run + self->function = function; + self->arguments = arg; // and let it really run (signal the condition var, the thread waits on it) - LUMIERA_RECCONDITION_SECTION(cond_sync, self->finished) - LUMIERA_RECCONDITION_SIGNAL; + self->state = LUMIERA_THREADSTATE_WAKEUP; + ECHO ("entering section 2"); + LUMIERA_RECCONDITION_SECTION(threads, &self->signal) + LUMIERA_RECCONDITION_BROADCAST; // NOTE: example only, add solid error handling! @@ -106,29 +127,25 @@ lumiera_thread_run (enum lumiera_thread_class kind, */ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag, pthread_attr_t* attrs) { // TODO: do something with these: (void) purpose; - (void) flag; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); REQUIRE (attrs, "invalid pthread attributes structure passed"); - //REQUIRE (finished, "invalid finished flag passed"); - - LumieraThread self = lumiera_malloc (sizeof (*self)); llist_init(&self->node); - self->finished = finished; + lumiera_reccondition_init (&self->signal, "thread-control", flag); self->kind = kind; - self->state = LUMIERA_THREADSTATE_IDLE; + self->state = LUMIERA_THREADSTATE_STARTUP; + self->function = NULL; + self->arguments = NULL; - //REQUIRE (thread_loop); int error = pthread_create (&self->id, attrs, &thread_loop, self); - ENSURE(error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror(error)); + ENSURE(error == 0 || EAGAIN == error, "pthread_create returned %d:%s", error, strerror(error)); if (error) { // error here can only be EAGAIN, given the above ENSURE @@ -143,12 +160,26 @@ lumiera_thread_destroy (LumieraThread self) { REQUIRE (self, "trying to destroy an invalid thread"); - // TODO: stop the pthread - llist_unlink(&self->node); - //finished = NULL; // or free(finished)? - lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG(threads)); - //kind = 0; - //state = 0; + lumiera_threadpool_unlink(self); + + // get the pthread out of the processing loop + // need to signal to the thread that it should start quitting + // should this be within the section? + LUMIERA_RECCONDITION_SECTION(threads, &self->signal) + { + REQUIRE (self->state == LUMIERA_THREADSTATE_IDLE, "trying to delete a thread in state other than IDLE (%s)", lumiera_threadstate_names[self->state]); + self->state = LUMIERA_THREADSTATE_SHUTDOWN; + self->function = NULL; + self->arguments = NULL; + LUMIERA_RECCONDITION_SIGNAL; + } + + int error = pthread_join(self->id, NULL); + ENSURE (0 == error, "pthread_join returned %d:%s", error, strerror(error)); + + // condition has to be destroyed after joining with the thread + lumiera_reccondition_destroy (&self->signal, &NOBUG_FLAG(threads)); + return self; } diff --git a/src/backend/threads.h b/src/backend/threads.h index ac8a163fd..a55926123 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -90,10 +90,16 @@ enum lumiera_thread_class // defined in threads.c extern const char* lumiera_threadclass_names[]; -#define LUMIERA_THREAD_STATES \ - LUMIERA_THREAD_STATE(IDLE) \ - LUMIERA_THREAD_STATE(RUNNING) \ - LUMIERA_THREAD_STATE(ERROR) +// there is some confusion between the meaning of this +// on one hand it could be used to tell the current state of the thread +// on the other, it is used to tell the thread which state to enter on next iteration +#define LUMIERA_THREAD_STATES \ + LUMIERA_THREAD_STATE(IDLE) \ + LUMIERA_THREAD_STATE(ERROR) \ + LUMIERA_THREAD_STATE(RUNNING) \ + LUMIERA_THREAD_STATE(WAKEUP) \ + LUMIERA_THREAD_STATE(SHUTDOWN) \ + LUMIERA_THREAD_STATE(STARTUP) #define LUMIERA_THREAD_STATE(name) LUMIERA_THREADSTATE_##name, @@ -125,12 +131,15 @@ struct lumiera_thread_struct // void* arg; pthread_t id; // TODO: maybe this condition variable should be renamed when we have a better understanding of how it will be used - LumieraReccondition finished; + lumiera_reccondition signal; // control signal, state change signal // the following member could have been called "class" except that it would conflict with C++ keyword // as consequence, it's been decided to leave the type name containing the word "class", // while all members/variables called "kind" enum lumiera_thread_class kind; + // this is used both as a command and as a state tracker lumiera_thread_state state; + void (*function)(void *); + void * arguments; }; /** @@ -138,7 +147,6 @@ struct lumiera_thread_struct */ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag, pthread_attr_t* attrs); @@ -162,8 +170,6 @@ lumiera_thread_delete (LumieraThread self); * @param kind class of the thread to start * @param function pointer to a function to execute in a thread (returning void, not void* as in pthreads) * @param arg generic pointer passed to the thread - * @param finished a condition variable to be broadcasted, if not NULL. - * The associated mutex should be locked at thread_run time already, else the signal can get lost. * @param purpose descriptive name of this thread, used by NoBug * @param flag NoBug flag used for logging the thread startup and return */ @@ -171,7 +177,6 @@ LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*function)(void *), void * arg, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag); diff --git a/tests/30backend-threadpool.tests b/tests/30backend-threadpool.tests index c136aff42..2cad43477 100644 --- a/tests/30backend-threadpool.tests +++ b/tests/30backend-threadpool.tests @@ -5,24 +5,11 @@ PLANNED "create" PLANNED "yield" PLANNED "cancel" -TEST "Acquire/Release test" basic-acquire-release < #include +#include + +void is_prime(void * arg) +{ + int number = *(int *)arg; + int prime = 1; + + for (int x = number; x >= sqrt(number); --x) + { + if (number % x == 0) + { + prime = 0; + break; + } + } + *(int *)arg = prime; +} TESTS_BEGIN +TEST ("threadpool-basic") +{ + lumiera_threadpool_init(100); + lumiera_threadpool_destroy(); +} + +TEST ("threadpool1") +{ + ECHO("start by initializing the threadpool"); + lumiera_threadpool_init(100); + LumieraThread t1 = + lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE, + "test purpose", + &NOBUG_FLAG(NOBUG_ON)); + // lumiera_threadpool_release_thread(t1); + ECHO("acquired thread 1 %p",t1); + lumiera_threadpool_destroy(); +} + TEST ("basic-acquire-release") { @@ -37,12 +73,12 @@ TEST ("basic-acquire-release") LumieraThread t1 = lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE, "test purpose", - NULL); + &NOBUG_FLAG(NOBUG_ON)); ECHO("acquiring thread 2"); LumieraThread t2 = lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_IDLE, "test purpose", - NULL); + &NOBUG_FLAG(NOBUG_ON)); ECHO("thread 1 kind=%s", lumiera_threadclass_names[t1->kind]); CHECK(LUMIERA_THREADCLASS_INTERACTIVE == t1->kind); @@ -54,16 +90,17 @@ TEST ("basic-acquire-release") CHECK(LUMIERA_THREADSTATE_IDLE == t2->state); ECHO("releasing thread 1"); - lumiera_threadpool_release_thread(t1); + //lumiera_threadpool_release_thread(t1); ECHO("thread 1 has been released"); ECHO("releasing thread 2"); - lumiera_threadpool_release_thread(t2); + //lumiera_threadpool_release_thread(t2); ECHO("thread 2 has been released"); lumiera_threadpool_destroy(); } +#if 0 TEST ("many-acquire-release") { @@ -79,7 +116,7 @@ TEST ("many-acquire-release") threads[i+kind*threads_per_pool_count] = lumiera_threadpool_acquire_thread(kind, "test purpose", - NULL); + &NOBUG_FLAG(NOBUG_ON)); } } @@ -107,7 +144,7 @@ TEST ("toomany-acquire-release") threads[i+kind*threads_per_pool_count] = lumiera_threadpool_acquire_thread(kind, "test purpose", - NULL); + &NOBUG_FLAG(NOBUG_ON)); } } @@ -119,5 +156,26 @@ TEST ("toomany-acquire-release") lumiera_threadpool_destroy(); } +#endif + +TEST ("process-function") +{ + // this is what the scheduler would do once it figures out what function a job needs to run + LumieraThread t; + int number = 440616; + + lumiera_threadpool_init(10); + + ECHO ("the input to the function is %d", number); + + t = lumiera_thread_run (LUMIERA_THREADCLASS_INTERACTIVE, + &is_prime, + (void *)&number, //void * arg, + "process my test function", + &NOBUG_FLAG(NOBUG_ON)); // struct nobug_flag* flag) + + // cleanup + lumiera_threadpool_destroy(); +} TESTS_END diff --git a/tests/backend/test-threads.c b/tests/backend/test-threads.c index 76da2f450..21786ae8b 100644 --- a/tests/backend/test-threads.c +++ b/tests/backend/test-threads.c @@ -91,7 +91,6 @@ TEST ("simple_thread") lumiera_thread_run (LUMIERA_THREADCLASS_WORKER, threadfn, NULL, - NULL, argv[1], NULL); @@ -112,7 +111,6 @@ TEST ("thread_synced") lumiera_thread_run (LUMIERA_THREADCLASS_WORKER, threadsyncfn, &cnd, - &cnd, argv[1], NULL); @@ -143,7 +141,6 @@ TEST ("mutex_thread") lumiera_thread_run (LUMIERA_THREADCLASS_WORKER, mutexfn, NULL, - NULL, argv[1], NULL); diff --git a/tests/test.sh b/tests/test.sh index 951d2fcea..b1fd0d99b 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -26,7 +26,7 @@ # stop testing on the first failure export LC_ALL=C -NOBUG_LOGREGEX='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\|TODO\|PLANNED\|FIXME\|DEPRECATED\|UNIMPLEMENTED\):' +NOBUG_LOGREGEX='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\|TODO\|PLANNED\|FIXME\|DEPRECATED\|UNIMPLEMENTED\|RESOURCE_ENTER\|RESOURCE_LEAVE\|RESOURCE_STATE\):' arg0="$0" srcdir="$(dirname "$arg0")" From 6f5578ba1002b8e2290e64d98408e7aa82c5dfff Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 23 Dec 2009 18:14:29 -0500 Subject: [PATCH 157/377] fix a copy+paste mistake in LUMIERA_RECCONDITION_SECTION_CHAIN and add a test-case for it --- src/lib/reccondition.h | 6 +++--- tests/15locking.tests | 4 ++++ tests/library/test-locking.c | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/lib/reccondition.h b/src/lib/reccondition.h index f9bcd59d1..51ce6ef07 100644 --- a/src/lib/reccondition.h +++ b/src/lib/reccondition.h @@ -65,13 +65,13 @@ #define LUMIERA_RECCONDITION_SECTION_CHAIN(nobugflag, cnd) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + for (lumiera_sectionlock *lumiera_reccond_section_old_ = &lumiera_reccond_section_, \ NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_reccond_section_ = { \ (void*)1, lumiera_reccondition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ lumiera_reccond_section_.lock;) \ for ( \ ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + REQUIRE (lumiera_reccond_section_old_->lock, "section prematurely unlocked"); \ lumiera_reccond_section_.lock = (cnd); \ NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \ RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh) \ @@ -79,7 +79,7 @@ if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ LUMIERA_DIE (LOCK_ACQUIRE); \ RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + LUMIERA_SECTION_UNLOCK_(lumiera_reccond_section_old_); \ } \ }); \ lumiera_reccond_section_.lock; \ diff --git a/tests/15locking.tests b/tests/15locking.tests index 0936499f2..c72f88855 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -86,3 +86,7 @@ PLANNED "reccondition broadcasting" < Date: Thu, 24 Dec 2009 01:45:44 +0100 Subject: [PATCH 158/377] remove threadpool_unlink() thread removes itself from the list, this is trival in place --- src/backend/threadpool.c | 8 -------- src/backend/threadpool.h | 6 ------ src/backend/threads.c | 2 +- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 2a33978d6..d7c13551e 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -96,14 +96,6 @@ lumiera_threadpool_destroy(void) } } -void lumiera_threadpool_unlink(LumieraThread thread) -{ - REQUIRE (thread, "invalid thread given"); - REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); - llist_unlink(&thread->node); - ENSURE (llist_is_empty(&thread->node), "failed to unlink the thread"); -} - LumieraThread lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index de545876c..572727e3e 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -87,12 +87,6 @@ lumiera_threadpool_init(); void lumiera_threadpool_destroy(void); -/** - * Just remove the thread structure from an associated pool list. - */ -void -lumiera_threadpool_unlink(LumieraThread thread); - #endif /* // Local Variables: diff --git a/src/backend/threads.c b/src/backend/threads.c index a75b7f81b..9c4cc9f1f 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -160,7 +160,7 @@ lumiera_thread_destroy (LumieraThread self) { REQUIRE (self, "trying to destroy an invalid thread"); - lumiera_threadpool_unlink(self); + llist_unlink (&self->node); // get the pthread out of the processing loop // need to signal to the thread that it should start quitting From 026fab07dc845f0a7f696405fa8286cd456f0125 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 24 Dec 2009 01:46:43 +0100 Subject: [PATCH 159/377] cosmetics, deadcode removal --- src/backend/threadpool.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index d7c13551e..1f2a1cc71 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -42,23 +42,13 @@ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/bet //code goes here// -void* pool_thread_loop(void * arg) -{ - (void) arg; - while (1) - { - ; - } - return arg; -} - void lumiera_threadpool_init() { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.pool[i].list); - threadpool.pool[i].working_thread_count = 0; + threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; //TODO: configure each pools' pthread_attrs appropriately From 6b4415d8fa4bfb86757a5abf16f10a9f3f585372 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 24 Dec 2009 01:50:59 +0100 Subject: [PATCH 160/377] nobugify declare and init the nobug flags and use them for logging diagnostics --- src/backend/threadpool.c | 16 +++++++++++----- src/backend/threads.c | 10 ++++++++-- src/backend/threads.h | 1 + 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 1f2a1cc71..706f5bb3b 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -45,6 +45,10 @@ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/bet void lumiera_threadpool_init() { + NOBUG_INIT_FLAG(threadpool); + NOBUG_INIT_FLAG(threads); + TRACE(threadpool); + for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.pool[i].list); @@ -65,15 +69,16 @@ lumiera_threadpool_init() void lumiera_threadpool_destroy(void) { - ECHO ("destroying threadpool"); + TRACE(threadpool); + for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { - ECHO ("destroying individual pool #%d", i); + TRACE (threadpool, "destroying individual pool #%d", i); LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[i].lock) { REQUIRE (0 == threadpool.pool[i].working_thread_count, "%d threads are running", threadpool.pool[i].working_thread_count); // TODO need to have a stronger assertion that no threads are really running because they will not even be in the list - ECHO ("number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); + INFO (threadpool, "number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); LLIST_WHILE_HEAD(&threadpool.pool[i].list, t) { lumiera_thread_delete((LumieraThread)t); @@ -92,8 +97,8 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag) { - LumieraThread ret; - + TRACE(threadpool); + LumieraThread ret = NULL; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[kind].signal) { @@ -126,6 +131,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, void lumiera_threadpool_park_thread(LumieraThread thread) { + TRACE(threadpool); REQUIRE (thread, "invalid thread given"); REQUIRE (thread->kind < LUMIERA_THREADCLASS_COUNT, "thread belongs to an unknown pool kind: %d", thread->kind); diff --git a/src/backend/threads.c b/src/backend/threads.c index 9c4cc9f1f..a34dcde4a 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -69,6 +69,7 @@ struct lumiera_thread_mockup static void* thread_loop (void* thread) { + TRACE(threads); LumieraThread t = (LumieraThread)thread; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); @@ -81,14 +82,16 @@ static void* thread_loop (void* thread) { do { // NULL function means: no work to do + INFO(threads, "function %p", t->function); if (t->function) t->function (t->arguments); + INFO(threads, "Thread awaken with state %d", t->state); lumiera_threadpool_park_thread(t); LUMIERA_RECCONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); } while (t->state != LUMIERA_THREADSTATE_SHUTDOWN); // SHUTDOWN state - ECHO ("thread quitting"); + INFO(threads, "Thread Shutdown"); } return 0; } @@ -102,7 +105,8 @@ lumiera_thread_run (enum lumiera_thread_class kind, const char* purpose, struct nobug_flag* flag) { - REQUIRE (function, "invalid function"); + TRACE(threads); + // REQUIRE (function, "invalid function"); // ask the threadpool for a thread (it might create a new one) LumieraThread self = lumiera_threadpool_acquire_thread(kind, purpose, flag); @@ -158,6 +162,7 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread lumiera_thread_destroy (LumieraThread self) { + TRACE(threads); REQUIRE (self, "trying to destroy an invalid thread"); llist_unlink (&self->node); @@ -186,6 +191,7 @@ lumiera_thread_destroy (LumieraThread self) void lumiera_thread_delete (LumieraThread self) { + TRACE(threads); ECHO ("deleting thread"); lumiera_free (lumiera_thread_destroy (self)); } diff --git a/src/backend/threads.h b/src/backend/threads.h index a55926123..9a4e6bbdf 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -34,6 +34,7 @@ //TODO: System includes// #include +NOBUG_DECLARE_FLAG (threads); /** From 88195087d6817cf631beb5dc07b3be9ef400f415 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 24 Dec 2009 01:54:49 +0100 Subject: [PATCH 161/377] recondition to condition, remove the mutex from the pool rename park to release :P --- src/backend/threadpool.c | 58 ++++++++++++++++++------------------ src/backend/threadpool.h | 8 ++--- src/backend/threads.c | 26 ++++++++-------- src/backend/threads.h | 4 +-- tests/backend/test-threads.c | 22 +++++++------- 5 files changed, 57 insertions(+), 61 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 706f5bb3b..8b86617ff 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -57,12 +57,10 @@ lumiera_threadpool_init() //TODO: configure each pools' pthread_attrs appropriately pthread_attr_init (&threadpool.pool[i].pthread_attrs); - // cehteh prefers that threads are joinable by default - //pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); + // cehteh says that threads must be joinable //cancel... - lumiera_mutex_init(&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); - lumiera_reccondition_init (&threadpool.pool[i].signal, "thread-signal", &NOBUG_FLAG(threadpool)); + lumiera_condition_init (&threadpool.pool[i].sync, "threadpool", &NOBUG_FLAG(cond_sync)); } } @@ -74,7 +72,7 @@ lumiera_threadpool_destroy(void) for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { TRACE (threadpool, "destroying individual pool #%d", i); - LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[i].lock) + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[i].sync) { REQUIRE (0 == threadpool.pool[i].working_thread_count, "%d threads are running", threadpool.pool[i].working_thread_count); // TODO need to have a stronger assertion that no threads are really running because they will not even be in the list @@ -84,9 +82,8 @@ lumiera_threadpool_destroy(void) lumiera_thread_delete((LumieraThread)t); } } - ECHO ("destroying the pool mutex"); - lumiera_mutex_destroy (&threadpool.pool[i].lock, &NOBUG_FLAG (threadpool)); - ECHO ("pool mutex destroyed"); + + lumiera_condition_destroy (&threadpool.pool[i].sync, &NOBUG_FLAG (cond_sync)); pthread_attr_destroy (&threadpool.pool[i].pthread_attrs); } } @@ -100,16 +97,17 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, TRACE(threadpool); LumieraThread ret = NULL; REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "unknown pool kind specified: %d", kind); - LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[kind].signal) - { - if (llist_is_empty (&threadpool.pool[kind].list)) - { - ret = lumiera_thread_new (kind, purpose, flag, - &threadpool.pool[kind].pthread_attrs); - threadpool.pool[kind].idle_thread_count++; - ENSURE (ret, "did not create a valid thread"); - LUMIERA_RECCONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].list)); + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[kind].sync) + { + if (llist_is_empty (&threadpool.pool[kind].list)) + { + + ret = lumiera_thread_new (kind, purpose, flag, + &threadpool.pool[kind].pthread_attrs); + ENSURE (ret, "did not create a valid thread"); + TODO("no error handling but let the resourcecollector do, no need for return the thread"); + LUMIERA_CONDITION_WAIT (!llist_is_empty (&threadpool.pool[kind].list)); } // use an existing thread, pick the first one // remove it from the pool's list @@ -129,7 +127,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, // TODO: rename to lumiera_threadpool_park_thread void -lumiera_threadpool_park_thread(LumieraThread thread) +lumiera_threadpool_release_thread(LumieraThread thread) { TRACE(threadpool); REQUIRE (thread, "invalid thread given"); @@ -137,20 +135,22 @@ lumiera_threadpool_park_thread(LumieraThread thread) REQUIRE (thread->state != LUMIERA_THREADSTATE_IDLE, "trying to park an already idle thread"); - LUMIERA_RECCONDITION_SECTION (threadpool, &threadpool.pool[thread->kind].signal) + LUMIERA_CONDITION_SECTION (threadpool, &threadpool.pool[thread->kind].sync) { thread->state = LUMIERA_THREADSTATE_IDLE; - REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); + REQUIRE (!llist_is_empty(&thread->node), "thread already belongs to some list"); llist_insert_head(&threadpool.pool[thread->kind].list, &thread->node); - threadpool.pool[thread->kind].working_thread_count--; - threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count - ENSURE (threadpool.pool[thread->kind].idle_thread_count == - llist_count(&threadpool.pool[thread->kind].list), - "idle thread count %d is wrong, should be %d", - threadpool.pool[thread->kind].idle_thread_count, - llist_count(&threadpool.pool[thread->kind].list)); - // REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); - LUMIERA_RECCONDITION_BROADCAST; + + threadpool.pool[thread->kind].working_thread_count--; + threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count + + ENSURE (threadpool.pool[thread->kind].idle_thread_count == + llist_count(&threadpool.pool[thread->kind].list), + "idle thread count %d is wrong, should be %d", + threadpool.pool[thread->kind].idle_thread_count, + llist_count(&threadpool.pool[thread->kind].list)); + REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); + LUMIERA_CONDITION_BROADCAST; } } diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 572727e3e..a8fa457c5 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -23,9 +23,8 @@ #define LUMIERA_THREADPOOL_H //TODO: Support library includes// -#include "lib/reccondition.h" +#include "lib/condition.h" #include "lib/llist.h" -#include "lib/mutex.h" //TODO: Forward declarations// @@ -60,7 +59,7 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, * This function doesn't need to be accessible outside of the threadpool implementation. */ void -lumiera_threadpool_park_thread(LumieraThread thread); +lumiera_threadpool_release_thread(LumieraThread thread); typedef struct lumiera_threadpool_struct lumiera_threadpool; typedef lumiera_threadpool* LumieraThreadpool; @@ -70,11 +69,10 @@ struct lumiera_threadpool_struct struct { llist list; - lumiera_mutex lock; unsigned working_thread_count; unsigned idle_thread_count; pthread_attr_t pthread_attrs; - lumiera_reccondition signal; + lumiera_condition sync; } pool[LUMIERA_THREADCLASS_COUNT]; }; diff --git a/src/backend/threads.c b/src/backend/threads.c index a34dcde4a..a7f09b763 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -22,7 +22,6 @@ //TODO: Support library includes// #include "include/logging.h" -#include "lib/mutex.h" #include "lib/safeclib.h" @@ -64,7 +63,7 @@ struct lumiera_thread_mockup { void (*fn)(void*); void* arg; - LumieraReccondition finished; + LumieraCondition finished; }; static void* thread_loop (void* thread) @@ -73,21 +72,20 @@ static void* thread_loop (void* thread) LumieraThread t = (LumieraThread)thread; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); - + REQUIRE (t, "thread does not exist"); - ECHO ("entering section 1"); // this seems to deadlock unexpectedly: - LUMIERA_RECCONDITION_SECTION (threads, &t->signal) + LUMIERA_CONDITION_SECTION (threads, &t->signal) { do { // NULL function means: no work to do INFO(threads, "function %p", t->function); if (t->function) t->function (t->arguments); + lumiera_threadpool_release_thread(t); + LUMIERA_CONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); INFO(threads, "Thread awaken with state %d", t->state); - lumiera_threadpool_park_thread(t); - LUMIERA_RECCONDITION_WAIT(t->state != LUMIERA_THREADSTATE_IDLE); } while (t->state != LUMIERA_THREADSTATE_SHUTDOWN); // SHUTDOWN state @@ -117,9 +115,9 @@ lumiera_thread_run (enum lumiera_thread_class kind, // and let it really run (signal the condition var, the thread waits on it) self->state = LUMIERA_THREADSTATE_WAKEUP; - ECHO ("entering section 2"); - LUMIERA_RECCONDITION_SECTION(threads, &self->signal) - LUMIERA_RECCONDITION_BROADCAST; + + LUMIERA_CONDITION_SECTION(threads, &self->signal) + LUMIERA_CONDITION_SIGNAL; // NOTE: example only, add solid error handling! @@ -142,7 +140,7 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread self = lumiera_malloc (sizeof (*self)); llist_init(&self->node); - lumiera_reccondition_init (&self->signal, "thread-control", flag); + lumiera_condition_init (&self->signal, "thread-control", flag); self->kind = kind; self->state = LUMIERA_THREADSTATE_STARTUP; self->function = NULL; @@ -170,20 +168,20 @@ lumiera_thread_destroy (LumieraThread self) // get the pthread out of the processing loop // need to signal to the thread that it should start quitting // should this be within the section? - LUMIERA_RECCONDITION_SECTION(threads, &self->signal) + LUMIERA_CONDITION_SECTION(threads, &self->signal) { REQUIRE (self->state == LUMIERA_THREADSTATE_IDLE, "trying to delete a thread in state other than IDLE (%s)", lumiera_threadstate_names[self->state]); self->state = LUMIERA_THREADSTATE_SHUTDOWN; self->function = NULL; self->arguments = NULL; - LUMIERA_RECCONDITION_SIGNAL; + LUMIERA_CONDITION_SIGNAL; } int error = pthread_join(self->id, NULL); ENSURE (0 == error, "pthread_join returned %d:%s", error, strerror(error)); // condition has to be destroyed after joining with the thread - lumiera_reccondition_destroy (&self->signal, &NOBUG_FLAG(threads)); + lumiera_condition_destroy (&self->signal, &NOBUG_FLAG(threads)); return self; } diff --git a/src/backend/threads.h b/src/backend/threads.h index 9a4e6bbdf..d4282da17 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -23,7 +23,7 @@ #define LUMIERA_THREADS_H //TODO: Support library includes// -#include "lib/reccondition.h" +#include "lib/condition.h" //TODO: Forward declarations// @@ -132,7 +132,7 @@ struct lumiera_thread_struct // void* arg; pthread_t id; // TODO: maybe this condition variable should be renamed when we have a better understanding of how it will be used - lumiera_reccondition signal; // control signal, state change signal + lumiera_condition signal; // control signal, state change signal // the following member could have been called "class" except that it would conflict with C++ keyword // as consequence, it's been decided to leave the type name containing the word "class", // while all members/variables called "kind" diff --git a/tests/backend/test-threads.c b/tests/backend/test-threads.c index 21786ae8b..ddf43214e 100644 --- a/tests/backend/test-threads.c +++ b/tests/backend/test-threads.c @@ -47,15 +47,15 @@ void threadfn(void* blah) void threadsyncfn(void* blah) { struct timespec wait = {0,200000000}; - LumieraReccondition sync = (LumieraReccondition) blah; + LumieraCondition sync = (LumieraCondition) blah; ECHO ("thread starting up %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_SECTION(cond_sync, sync) + LUMIERA_CONDITION_SECTION(cond_sync, sync) { ECHO ("send startup signal %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_SIGNAL; + LUMIERA_CONDITION_SIGNAL; ECHO ("wait for trigger %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_WAIT(1); + LUMIERA_CONDITION_WAIT(1); } ECHO ("thread running %s", NOBUG_THREAD_ID_GET); @@ -101,10 +101,10 @@ TEST ("simple_thread") TEST ("thread_synced") { - lumiera_reccondition cnd; - lumiera_reccondition_init (&cnd, "threadsync", &NOBUG_FLAG(NOBUG_ON)); + lumiera_condition cnd; + lumiera_condition_init (&cnd, "threadsync", &NOBUG_FLAG(NOBUG_ON)); - LUMIERA_RECCONDITION_SECTION(cond_sync, &cnd) + LUMIERA_CONDITION_SECTION(cond_sync, &cnd) { ECHO ("main before thread %s", NOBUG_THREAD_ID_GET); @@ -115,17 +115,17 @@ TEST ("thread_synced") NULL); ECHO ("main wait for thread being ready %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_WAIT(1); + LUMIERA_CONDITION_WAIT(1); ECHO ("main trigger thread %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_SIGNAL; + LUMIERA_CONDITION_SIGNAL; ECHO ("wait for thread end %s", NOBUG_THREAD_ID_GET); - LUMIERA_RECCONDITION_WAIT(1); + LUMIERA_CONDITION_WAIT(1); ECHO ("thread ended %s", NOBUG_THREAD_ID_GET); } - lumiera_reccondition_destroy (&cnd, &NOBUG_FLAG(NOBUG_ON)); + lumiera_condition_destroy (&cnd, &NOBUG_FLAG(NOBUG_ON)); } From a698128cfc75aba631f0dec8da1d45bfc63b0464 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 24 Dec 2009 01:55:24 +0100 Subject: [PATCH 162/377] new no-function test, sleep a bit before destroying the threadpool --- tests/backend/test-threadpool.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/backend/test-threadpool.c b/tests/backend/test-threadpool.c index ea5d60a76..b83920330 100644 --- a/tests/backend/test-threadpool.c +++ b/tests/backend/test-threadpool.c @@ -26,6 +26,7 @@ #include #include #include +#include void is_prime(void * arg) { @@ -158,6 +159,25 @@ TEST ("toomany-acquire-release") } #endif +TEST ("no-function") +{ + LumieraThread t; + + lumiera_threadpool_init(10); + + t = lumiera_thread_run (LUMIERA_THREADCLASS_INTERACTIVE, + NULL, + NULL, + "process my test function", + &NOBUG_FLAG(NOBUG_ON)); + + // cleanup + ECHO("wait 1 sec"); + usleep(1000000); + ECHO("finished waiting"); + lumiera_threadpool_destroy(); +} + TEST ("process-function") { // this is what the scheduler would do once it figures out what function a job needs to run @@ -175,6 +195,9 @@ TEST ("process-function") &NOBUG_FLAG(NOBUG_ON)); // struct nobug_flag* flag) // cleanup + ECHO("wait 1 sec"); + usleep(1000000); + ECHO("finished waiting"); lumiera_threadpool_destroy(); } From 0a085acf74054eef0e4116fc8ca39349084a759a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 25 Dec 2009 05:24:49 +0100 Subject: [PATCH 163/377] add coverage for the simple standard case (function returing a value) --- tests/lib/item-wrapper-test.cpp | 39 ++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/tests/lib/item-wrapper-test.cpp b/tests/lib/item-wrapper-test.cpp index 2ed1e3b53..7eb343bf8 100644 --- a/tests/lib/item-wrapper-test.cpp +++ b/tests/lib/item-wrapper-test.cpp @@ -49,6 +49,7 @@ namespace test{ using std::tr1::ref; using std::vector; using std::string; + using std::rand; using std::cout; using std::endl; @@ -131,6 +132,7 @@ namespace test{ verifyWrappedRef (); verifyFunctionResult (); + verifyFunctionRefResult (); } @@ -244,15 +246,44 @@ namespace test{ /** @test verify an extension built on top of the ItemWrapper: - * a function which remembers the last result. We use a - * test function, which picks a member of an vector and + * a function which remembers the last result. As a simple test, + * we bind the \c rand() standard lib function and remember the + * last returned random value. + */ + void + verifyFunctionResult() + { + FunctionResult randomVal (std::rand); + + // function was never invoked, thus the remembered result is NIL + ASSERT (!randomVal); + VERIFY_ERROR (BOTTOM_VALUE, *randomVal ); + + int v1 = randomVal(); + ASSERT (v1 == *randomVal); + ASSERT (v1 == *randomVal); + ASSERT (v1 == *randomVal); + ASSERT (randomVal); + + int v2; + do v2 = randomVal(); + while (v1 == v2); + ASSERT (v2 == *randomVal); + ASSERT (v2 == *randomVal); + ASSERT (v1 != *randomVal); + } + + + /** @test verify an extension built on top of the ItemWrapper: + * a function which remembers the last result. Here we use + * a test function, which picks a member of an vector and * returns a \em reference to it. Thus the cached "result" * can be used to access and change the values within the * original vector. In a real world usage scenario, such a * function could be an (expensive) data structure access. */ void - verifyFunctionResult() + verifyFunctionRefResult() { vector testVec; for (uint i=0; i<10; ++i) @@ -265,6 +296,8 @@ namespace test{ VERIFY_ERROR (BOTTOM_VALUE, *funRes ); int& r5 = funRes (5); + ASSERT (funRes); // indicates existence of cached result + ASSERT (5 == r5); ASSERT (isSameObject (r5, testVec[5])); From 26c506c0d669f8311a5b1ef4613e2b0c801e4074 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 27 Dec 2009 04:03:00 +0100 Subject: [PATCH 164/377] rewrite TransformIter, allowing to return references (closes #475) --- src/lib/itertools.hpp | 14 +++++++------- src/lib/wrapper.hpp | 21 ++++++++++++++++----- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/lib/itertools.hpp b/src/lib/itertools.hpp index c18d01e35..4e0f4c673 100644 --- a/src/lib/itertools.hpp +++ b/src/lib/itertools.hpp @@ -72,6 +72,7 @@ #include "lib/iter-adapter.hpp" #include "lib/meta/function.hpp" #include "lib/meta/trait.hpp" +#include "lib/wrapper.hpp" #include "lib/util.hpp" #include @@ -341,11 +342,11 @@ namespace lib { class TransformingCore { typedef typename IT::reference InType; - typedef typename RefTraits::member_type Item; + typedef wrapper::ItemWrapper Item; function trafo_; - IT source_; + IT source_; Item treated_; void @@ -353,6 +354,8 @@ namespace lib { { if (source_) treated_ = trafo_(*source_); + else + treated_.reset(); } @@ -372,13 +375,10 @@ namespace lib { processItem(); } - Item * + Item const& pipe () const { - if (source_) - return & unConst(this)->treated_; // accessing, no "mutation" - else - return 0; // signalling exhausted source + return treated_; } void diff --git a/src/lib/wrapper.hpp b/src/lib/wrapper.hpp index 76a9f6282..b5a240593 100644 --- a/src/lib/wrapper.hpp +++ b/src/lib/wrapper.hpp @@ -48,6 +48,7 @@ #include "lib/meta/function-closure.hpp" #include "lib/util.hpp" +#include #include @@ -302,12 +303,14 @@ namespace wrapper { * for the first time. After that, the result of the last * invocation can be accessed by \c operator*() * - * @see TransformIter usage example + * @note non-copyable. (removing this limitation would + * require a much more expensive implementation, + * by implementing operator() ourselves) */ template class FunctionResult : public function - , public lib::BoolCheckable > + , boost::noncopyable { typedef typename FunctionSignature >::Ret Res; typedef ItemWrapper ResWrapper; @@ -323,7 +326,12 @@ namespace wrapper { } public: - /** Explanation: + /** default ctor yields an object + * locked to \em invalid state */ + FunctionResult () { } + + /** Create result-remembering functor + * by binding the given function. Explanation: * - *this is a \em function * - initially it is defined as invalid * - then we build the function composition of @@ -338,7 +346,7 @@ namespace wrapper { using std::tr1::bind; using std::tr1::placeholders::_1; using lumiera::typelist::func::chained; - + // note: binding "this" mandates noncopyable function doCaptureResult = bind (&FunctionResult::captureResult, this, _1 ); function chainedWithResCapture = chained (targetFunction, doCaptureResult); @@ -346,8 +354,11 @@ namespace wrapper { } - Res operator*() const { return *lastResult_; } + Res& operator*() const { return *lastResult_; } bool isValid () const { return lastResult_.isValid(); } + + operator bool() const { return isValid(); } + // can't use lib::BoolCheckable, because tr1::function implements safe-bool too }; From 7b7e9096a303fa556825fb5f941a9432175c36a4 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 27 Dec 2009 06:25:34 +0100 Subject: [PATCH 165/377] Hook up scope contents iterator in PlacementIndex (closes #343) --- src/lib/bool-checkable.hpp | 13 +++++++++++++ src/lib/itertools.hpp | 2 +- src/proc/control/memento-tie.hpp | 2 ++ src/proc/mobject/session/placement-index.cpp | 12 +++++------- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/lib/bool-checkable.hpp b/src/lib/bool-checkable.hpp index db2a7ecfb..8ff9ab063 100644 --- a/src/lib/bool-checkable.hpp +++ b/src/lib/bool-checkable.hpp @@ -133,6 +133,19 @@ namespace lib { }; +///////////////////////////////////////TICKET #477 : consider alternative safe-bool idiom +// struct _Hidden_type +// { +// _Hidden_type* _M_bool; +// }; +// +// /// This typedef is used to implement the safe_bool idiom. +// typedef _Hidden_type* _Hidden_type::* _Safe_bool; +// +// public: +// operator _Safe_bool() const +// { +// return isValid()? &_Hidden_type::_M_bool : 0; } } // namespace lib diff --git a/src/lib/itertools.hpp b/src/lib/itertools.hpp index 4e0f4c673..bda5a70ec 100644 --- a/src/lib/itertools.hpp +++ b/src/lib/itertools.hpp @@ -206,7 +206,7 @@ namespace lib { operator->() const { _maybe_throw(); - return core_.pipe(); + return & *core_.pipe(); } IterTool& diff --git a/src/proc/control/memento-tie.hpp b/src/proc/control/memento-tie.hpp index bbab73313..3c78b99f7 100644 --- a/src/proc/control/memento-tie.hpp +++ b/src/proc/control/memento-tie.hpp @@ -78,6 +78,8 @@ namespace control { * which needs to be stored within the MementoTie. On UNDO, the undo-operation functor needs * to be provided with a reference to this stored memento value through an additional * parameter (which by convention is always the last argument of the undo function). + * @warning take care of the MementoTie storage location, as the bound functions + * returned by #tieCaptureFunc and #tieUndoFunc refer to \c this internally. * * @param SIG signature of the command operation * @param MEM type of the memento state to capture. Needs to be default constructible and copyable diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index b90f01de2..0b09379c5 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -69,7 +69,7 @@ namespace session { using std::tr1::unordered_map; using std::tr1::unordered_multimap; using lib::TypedAllocationManager; -// using std::tr1::placeholders::_1; + using std::tr1::placeholders::_1; using std::tr1::function; using std::tr1::bind; //using util::contains; @@ -180,9 +180,8 @@ namespace session { { REQUIRE (contains (id)); ScopeContents contents = scopeTab_.equal_range (id); - UNIMPLEMENTED ("WIP-WIP-WIP"); -// return iterator (ScopeRangeIter(contents.first, contents.second) -// ,scopeIndexElementsResolver() ); + return iterator (ScopeRangeIter(contents.first, contents.second) + ,scopeIndexElementsResolver() ); } @@ -417,9 +416,8 @@ namespace session { /** Retrieve all the elements attached to the given entry (scope) - * Each element (Placement) can act as a scope, containing other - * Placements, which will be discovered by this query one level - * deep (not recursive). + * Each element (Placement) can act as a scope, containing other Placements, + * which will be discovered by this query one level deep (not recursive). * @return an Lumiera Forward Iterator, yielding the children, * possibly empty if the denoted element is a leaf. * @note results are returned in arbitrary order (hashtable) From c49d8321f6be2a0a6cfe9adb53af31f742533910 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 27 Dec 2009 06:36:52 +0100 Subject: [PATCH 166/377] fill in documentation and missing test cases --- src/proc/mobject/session/placement-index.cpp | 25 +++-- src/proc/mobject/session/placement-index.hpp | 100 ++++++++++++++---- .../mobject/session/placement-index-test.cpp | 61 ++++++++++- 3 files changed, 154 insertions(+), 32 deletions(-) diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index 0b09379c5..b3d2e2484 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -27,13 +27,23 @@ ** Moreover, it provides and manages the actual Placement instances (storage), ** considered to be part of the session. ** - ** Simple hash based implementation. Proof-of-concept and for fleshing out the API. + ** Simple hash based implementation. Seems adequate for now (12/09). + ** A main table associates Placement-ID to an Placement \em instance, which is contained + ** and managed within this index. A second hashtable allows to reverse lookup the scope + ** associations, especially for enumerating the contents of a scope. The latter is done + ** by wrapping up an STL iterator range into a "Lumiera Forward Iterator" (adapter). + ** Generally speaking, PlacementIndex is an implementation level facility and provides + ** the basic/low-level functionality. For example, the PlacementIndexQueryResolver + ** provides depth-first exploration of all the contents of an scope, including nested scopes, + ** building on top of these scope iterators from PlacementIndex. + ** + ** PlacementIndex can be seen as the core datastructure of the session. Objects are attached + ** to the session by adding (copying) a Placement instance, which is owned and managed by + ** the PlacementIndex. Adding this Placement instance creates a new Placement-ID, which + ** from then on acts as a shorthand for "the object instance" within the session. ** The actual storage is provided by an embedded TypedAllocationManager instance, which ** is planned (as of 12/09) to be backed later by a memory pool based custom allocator. ** - ** @todo change PlacementIndex into an interface and create a separated implementation class - ** @todo really? it seems PlacementIndex has gotten an implementation class without much relevance on the Session API - ** ** @see PlacementRef ** @see PlacementIndex_test ** @@ -109,7 +119,7 @@ namespace session { PPlacement scope; }; - // using a hashtables to implement the index + // using hashtables to implement the index typedef PlacementMO::ID PID; typedef unordered_map > IDTable; typedef std::tr1::unordered_multimap > ScopeTable; @@ -320,7 +330,7 @@ namespace session { /** Helper for building a scope exploring iterator - * for PlacementIndex: our "reverse index" (scopeTab_) + * for PlacementIndex: our "reverse index" (#scopeTab_) * tracks the contents of each scope as pairs (scopeID,elementID). * After fetching the range of matching entries, whenever the client * dereferences the iterator, we have to pick up the second ID and @@ -352,6 +362,9 @@ namespace session { + /* ============ PlacementIndex implementation functions ============ */ + + PlacementIndex::PlacementIndex (PlacementMO const& rootDef) : pTab_(new Table) { diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index 2fb64da29..49a5b66b3 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -22,7 +22,7 @@ /** @file placement-index.hpp - ** Key interface of the session implementation datastructure. + ** Core of the session implementation datastructure. ** The PlacementIndex is attached to and controlled by the SessionImpl. ** Client code is not intended to interface directly to this API. Even ** Proc-Layer internal facilities use the session datastructure through @@ -31,10 +31,67 @@ ** in the session. Any further structuring exists on the logical level only. ** ** \par PlacementIndex, PlacementRef and MObjectRef - ** TODO + ** Objects are attached to the session by adding (copying) a Placement instance, + ** and doing so creates a new Placement-ID, which from then on acts as a shorthand for + ** "the object instance" within the session. As long as this instance isn't removed from + ** the session / PlacementIndex, a direct (language) reference can be used to work with + ** "the object instance"; accessing this way is adequate for implementation code living + ** within Lumiera's Proc-Layer. ** - ** \par Querying and contents discovery - ** TODO + ** To avoid the dangerous dependency on a direct reference, external code would rather + ** rely on the Placement-ID. Moreover, being a simple value, such an ID can be passed + ** through plain C APIs. PlacementRef is a smart-ptr like wrapper, containing just + ** such an ID; dereferentiation transparently causes a lookup operation through the + ** PlacementIndex of the current session. (accessing an invalid PlacementRef throws) + ** + ** When it comes to ownership and lifecycle management, external client code should + ** use MObjectRef instances. In addition to containing a PlacementRef, these set up + ** a smart-ptr managing the MObject instance and sharing ownership with the Placement + ** contained within the PlacementIndex. Usually, the commands expressing any mutating + ** operations on the session, bind MObjectRef instances as arguments; similarly, the + ** public API functions on the Session interface (and similar facade interfaces) are + ** written in terms of MObectRef. + ** + ** \par placement scopes + ** When adding a Placement to the index, it is mandatory to specify a Scope: this is + ** another Placement already registered within the index; the new Placement can be thought + ** off as being located "within" or "below" this scope-defining reference Placement. An + ** typical example would be the addition of a \c Placement, specifying + ** a \c Placement as scope. Thus, all "object instances" within the + ** session are arranged in a tree-like fashion. On creation of the PlacementIndex, + ** a root element needs to be provided. While this root element has a meaning for + ** the session, within the index it is just a scope-providing element. + ** Note that a non-empty scope can't be deleted from the Index. + ** + ** \par querying and contents discovery + ** As "the object instance within the session" is synonymous to the placement instance + ** managed by PlacementIndex, the (hash)-ID of such a placement can be used as an + ** object identifier (it is implemented as LUID and stored within the Placement instance). + ** Thus, a basic operation of the index is to fetch a (language) reference to a Placement, + ** given this hash-ID. Another basic operation is to retrieve the scope an given object + ** is living in, represented by the Placement defining this scope (called "scope top"). + ** The reverse operation is also possible: given a scope-defining Placement, we can + ** \em discover all the other Placements directly contained within this scope: + ** \c getReferrers(ID) returns an (possibly empty) "Lumiera Forward Iterator", + ** allowing to enumerate the nested elements. Client code within Lumiera's Proc-Layer + ** typically uses this functionality through a ScopeQuery passed to the SessionServices, + ** while external client code would use either QueryFocus and the Scope wrapper objects, + ** or the specific query functions available on the facade objects accessible through + ** the public session API. + ** + ** \par type handling + ** MObjects form a hierarchy and contain RTTI. By special definition trickery, the + ** various instances of the Placement template mirror this hierarchy to some extent. + ** By using the vtable of the referred MObject, a given \c Placement can + ** be casted into a more specifically typed Placement, thus allowing to re-gain + ** the fully typed context. This technique plays an important role when it comes + ** to generic processing of the session contents by a visitor, and especially + ** within the Builder. This is a fundamental design decision within Proc-Layer: + ** code should not operate on MObjects and do type/capability queries -- rather + ** any processing is assumed to happen in a suitable typed context. Consequently, + ** client code will never need to fetch Placements directly from the index. This + ** allows all type information to be discarded on adding (copying) a Placement + ** instances into the PlacementIndex. ** ** @note PlacementIndex is not threadsafe. ** @@ -111,27 +168,29 @@ namespace session { typedef lib::TransformIter iterator; - PlacementMO& find (ID) const; + /* == query operations == */ + + PlacementMO& find (ID) const; template - Placement& find (PlacementMO::Id) const; + Placement& find (PlacementMO::Id) const; template Placement& find (PlacementRef const&) const; - PlacementMO& getScope (PlacementMO const&) const; - PlacementMO& getScope (ID) const; - - iterator getReferrers (ID) const; - - - /** retrieve the logical root scope */ - PlacementMO& getRoot() const; - - size_t size() const; - bool contains (PlacementMO const&) const; - bool contains (ID) const; - - bool isValid() const; + PlacementMO& getScope (PlacementMO const&) const; + PlacementMO& getScope (ID) const; + + iterator getReferrers (ID) const; + + + /** retrieve the logical root scope */ + PlacementMO& getRoot() const; + + size_t size() const; + bool contains (PlacementMO const&) const; + bool contains (ID) const; + + bool isValid() const; @@ -149,7 +208,6 @@ namespace session { void clear(); - protected: }; diff --git a/tests/components/proc/mobject/session/placement-index-test.cpp b/tests/components/proc/mobject/session/placement-index-test.cpp index 702ed206a..569e4b208 100644 --- a/tests/components/proc/mobject/session/placement-index-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-test.cpp @@ -33,15 +33,16 @@ #include "proc/mobject/session/testclip.hpp" #include "proc/mobject/session/testroot.hpp" -//#include -//#include +#include +#include -//using boost::format; +using boost::format; //using lumiera::Time; //using util::contains; using util::isSameObject; using std::string; -//using std::cout; +using std::cout; +using std::endl; namespace mobject { @@ -80,10 +81,14 @@ namespace test { checkScopeHandling (index); has_size (7, index); - ////////////////////////////TODO + checkContentsEnumeration (index); + + has_size (7, index); + ASSERT (index.isValid()); index.clear(); has_size (0, index); + ASSERT (index.isValid()); } void @@ -202,6 +207,52 @@ namespace test { ASSERT (index.remove(e133)); // but can remove an scope, after emptying it ASSERT (!index.contains(e133)); } + + + + typedef PlacementIndex::iterator Iter; + + /** @test drill down into the tree-like structure + * and enumerate the contents of each element, if any + */ + void + checkContentsEnumeration (Idx index) + { + PMO& root = index.getRoot(); + + Iter rootContents = index.getReferrers (root.getID()); + ASSERT (rootContents); + + discover (index, rootContents, 0); + } + + + void + discover (Idx index, Iter iter, uint level) + { + uint count (0); + for ( ; iter; ++iter ) + { + cout << indent(level) << "::" << string(*iter) << endl; + + ++count; + Iter scopeContents = index.getReferrers (iter->getID()); + if (scopeContents) + discover (index, scopeContents, level+1); + } + + static format summary ("...%i elements at Level %i"); + cout << indent(level) << summary % count % level << endl; + + ASSERT (!iter); + ASSERT (0 < count); + } + + static string + indent (uint level) + { + return string (level, ' '); + } }; From 6e956f24abaece56792971c096a154fd02d110d0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 28 Dec 2009 03:32:42 +0100 Subject: [PATCH 167/377] WIP: drafted PlacementIndex validity self-check --- src/proc/mobject/session/placement-index.cpp | 191 +++++++++++++++++-- 1 file changed, 180 insertions(+), 11 deletions(-) diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index b3d2e2484..59a20262b 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -60,6 +60,7 @@ //#include //using boost::str; +#include #include #include #include @@ -88,6 +89,8 @@ namespace session { using std::make_pair; using std::pair; + using util::for_each; + using namespace lumiera; LUMIERA_ERROR_DEFINE (NOT_IN_SESSION, "referring to a Placement not known to the current session"); @@ -156,7 +159,19 @@ namespace session { { return placementTab_.size(); } - + + size_t + scope_cnt() const + { + return scopeTab_.size(); + } + + size_t + element_cnt() const + { + return allocator_.numSlots(); + } + bool contains (ID id) const { @@ -287,6 +302,38 @@ namespace session { } + /* == access for self-test == */ + PlacementMO* + _root_4check () + { + return root_.get(); + } + + PlacementMO* + _element_4check (ID id) + { + return base_entry(id).element.get(); + } + + PlacementMO* + _scope_4check (ID id) + { + return base_entry(id).scope.get(); + } + + void + _eachEntry_4check () + { + UNIMPLEMENTED ("return each id in the base table"); + } + + void + _eachScope_4check() + { + UNIMPLEMENTED ("return each scope from the reverse table"); + } + + private: typedef IDTable::const_iterator Slot; @@ -368,6 +415,8 @@ namespace session { PlacementIndex::PlacementIndex (PlacementMO const& rootDef) : pTab_(new Table) { + INFO (session, "Initialising PlacementIndex..."); + pTab_->setupRoot(rootDef); ENSURE (isValid()); } @@ -382,15 +431,6 @@ namespace session { } - /** validity self-check, used for sanity checks - * and the session self-check. */ - bool - PlacementIndex::isValid() const - { - UNIMPLEMENTED ("PlacementIndex validity self-check"); - } - - size_t PlacementIndex::size() const { @@ -491,6 +531,135 @@ namespace session { + + /* ====== PlacementIndex validity self-check ====== */ + + namespace { // Implementation details of self-check + + LUMIERA_ERROR_DEFINE(INDEX_CORRUPTED, "PlacementIndex corrupted"); + + struct SelfCheckFailure + : error::Fatal + { + SelfCheckFailure (Literal currentTest, string failure) + : error::Fatal (string("Failed test: ")+currentTest+ " : "+failure + ,LUMIERA_ERROR_INDEX_CORRUPTED) + { } + }; + +#define VERIFY(_CHECK_, CHECK_ID, DESCRIPTION) \ + if (!(_CHECK_)) \ + throw SelfCheckFailure (CHECK_ID, (DESCRIPTION)); +#define ELM(ID) \ + (tab._element_4check ((ID))) +#define SCO(ID) \ + (tab._scope_4check ((ID))) + + + + using namespace boost::lambda; + typedef PlacementIndex::Table& Tab; + + void + checkRoot (PMO* root) + { + VERIFY ( root, "(0.1) Basics", "Root element missing"); + VERIFY ( root->isValid(), "(0.2) Basics", "Root Placement invalid"); + VERIFY ( (*root)->isValid(), "(0.3) Basics", "Root MObject self-check failure"); + } + + void + checkEntry (Tab tab, ID id) + { + VERIFY ( tab.contains(id), "(1.1) Elements", "PlacementIndex main table corrupted"); + VERIFY ( ELM(id), "(1.2) Elements", "Entry doesn't hold a Placement"); + VERIFY ( id==ELM(id)->getID(), "(1.3) Elements", "Element stored with wrong ID"); ////////////////TICKET #197 + VERIFY ( ELM(id)->isValid(), "(1.4) Elements", "Index contains invalid Placement") + VERIFY ( SCO(id), "(1.5) Elements", "Entry has undefined scope"); + VERIFY ( SCO(id)->isValid(), "(1.6) Elements", "Entry has invalid scope"); + VERIFY ( tab.contains (SCO(id)->getID()), + "(1.7) Elements", "Element associated with an unknown scope"); + + PMO* theElement = ELM(id); + ID theScope (SCO(id)->getID()); + bool properlyRegistered = + false; ////////////////////////////////////////////////////////////////////////TODO +// has_any (tab.queryScopeContents(theScope), _1 == *theElement ); + + VERIFY ( properlyRegistered, "(1.8) Elements", "Element isn't registered as member of the enclosing scope"); + } + + void + checkScope (Tab tab, ID id) + { + VERIFY ( tab.contains(id), "(2.1) Scopes", "Scope not registered in main table"); + VERIFY ( ELM(id), "(2.2) Scopes", "Scope entry doesn't hold a Placement"); + VERIFY ( SCO(id), "(2.3) Scopes", "Scope entry doesn't hold a containing Scope"); + + PMO* root = tab._root_4check(); + PMO* scope = SCO(id); + while (scope && scope != SCO(scope->getID())) + scope = SCO(scope->getID()); + + VERIFY ( root==scope, "(2.4) Scopes", "Found a scope not attached below root."); + } + + void + checkAllocation (Tab tab) + { + VERIFY ( 0 < tab.size(), "(4.1) Storage", "Implementation table is empty"); + VERIFY ( 0 < tab.element_cnt(),"(4.2) Storage", "No Placement instances allocated"); + VERIFY ( tab.size()==tab.scope_cnt(), + "(4.3) Storage", "Number of elements and scope entries disagree"); + VERIFY ( tab.size()==tab.element_cnt(), + "(4.4) Storage", "Number of entries doesn't match number of allocated Placement instances"); + } + + +#undef VERIFY +#undef ELM +#undef SCO + + }//(End) self-check implementation + + + + /** validity self-check, used for sanity checks and the session self-check. + * The following checks are performed (causing at least one full table scan) + * - root element exists and is valid. + * - each element + * - has a known scope + * - is registered as child of it's scope + * - can reach root from each scope + * - element count of the allocator matches table size + */ + bool + PlacementIndex::isValid() const + { + try + { + if (!pTab_) + throw SelfCheckFailure ("(0) Basics" + ,"Implementation tables not initialised"); + + checkRoot (pTab_->_root_4check()); - + ////////////////////////////////////////////////////////////////////////TODO +// for_each (pTab_->_eachEntry_4check(), bind (checkEntry, *pTab_, _1 )); +// for_each (pTab_->_eachScope_4check(), bind (checkScope, *pTab_, _1 )); + + return true; + } + + catch(SelfCheckFailure& failure) + { + lumiera_error(); + ERROR (session, "%s", failure.what()); + } + return false; + } + + + + }} // namespace mobject::session From c8c359d64844995945df3327eb608045782ee2d1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 29 Dec 2009 03:42:33 +0100 Subject: [PATCH 168/377] specify expected behaviour of the for_each helpers --- tests/lib/util-foreach-test.cpp | 352 ++++++++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 tests/lib/util-foreach-test.cpp diff --git a/tests/lib/util-foreach-test.cpp b/tests/lib/util-foreach-test.cpp new file mode 100644 index 000000000..927eb26cd --- /dev/null +++ b/tests/lib/util-foreach-test.cpp @@ -0,0 +1,352 @@ +/* + UtilForeach(Test) - helpers for doing something for each element + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/util.hpp" +#include "lib/iter-adapter.hpp" + + +#include +#include +#include +#include +#include + + +using ::Test; + +using util::for_each; +using util::has_any; +using util::and_all; + +using boost::lexical_cast; +using std::tr1::function; +using std::tr1::ref; +using std::cout; +using std::endl; + +using namespace boost::lambda; + + +namespace util { +namespace test { + + typedef std::vector VecI; + typedef lib::RangeIter RangeI; + + + + namespace{ // Test data and operations + + uint NUM_ELMS = 10; + + + // need explicit definitions here, because we use + // tr1/functional and boost::lambda at the same time + std::tr1::_Placeholder<1> _1; + boost::lambda::placeholder1_type _1_; + + + VecI + buildTestNumberz (uint count) + { + VecI numbers; + numbers.reserve(count); + while (count) + numbers.push_back(count--); + + return numbers; + } + + + /* == functions to bind and invoke == */ + bool + plainFunc (int i) + { + cout <<':'<< i; + return i; + } + + bool + function1 (int i, int j) + { + return plainFunc(i+j); + } + + bool + function2 (int i, int j, int& k) + { + k = i + j; + return plainFunc(k); + } + + +#define _NL_ cout << endl; + + } // (End) test data and operations + + + + /********************************************************************* + * @test Invoking an operation for each element of a collection. + * Covers the various flavours of these convenience helpers: + * They might operate either on a STL container (providing + * \c begin() and \c end() functions), or at a "Lumiera + * Forward Iterator", which is incremented and dereferenced + * for each value it yields, until exhaustion. + * + * Moreover for each of these cases, there are additional + * overloads allowing to create a bind-expression on-the fly. + * As a further variation of this scheme, an predicate can be + * evaluated for each element, either with universal quantisation + * (results are && combined), or with existential quantisation. + */ + class UtilForeach_test : public Test + { + + void + run (Arg arg) + { + if (0 < arg.size()) NUM_ELMS = lexical_cast (arg[0]); + + VecI container = buildTestNumberz (NUM_ELMS); + RangeI iterator(container.begin(), container.end()); + + check_foreach_plain (container); + check_foreach_plain (iterator); + + check_foreach_bind (container); + check_foreach_bind (iterator); + + check_foreach_memFun (container); + check_foreach_memFun (iterator); + + check_foreach_lambda (container); + check_foreach_lambda (iterator); + + check_existence_quant (container); + check_existence_quant (iterator); + + check_invoke_on_each (iterator); + } + + + /** @test invoke a simple free function, given + * as reference, function pointer or functor. + * The invoked test function will print its argument + */ + template + void + check_foreach_plain (CO coll) + { + function func(plainFunc); + + for_each (coll, plainFunc); _NL_ + for_each (coll, &plainFunc); _NL_ + for_each (coll, func); _NL_ + + and_all (coll, plainFunc); _NL_ + and_all (coll, &plainFunc); _NL_ + and_all (coll, func); _NL_ + + has_any (coll, plainFunc); _NL_ + has_any (coll, &plainFunc); _NL_ + has_any (coll, func); _NL_ + } + + + /** @test bind additional parameters on-the-fly, + * including the possibility to use a placeholder + * to denote the position of the variable parameter */ + template + void + check_foreach_bind (CO coll) + { + function fun1(function1); + function fun2(function2); + + for_each (coll, function1, 10, _1 ); _NL_ + for_each (coll, &function1,10, _1 ); _NL_ + for_each (coll, fun1, 10, _1 ); _NL_ + + and_all (coll, function1, 10, _1 ); _NL_ + and_all (coll, &function1, 10, _1 ); _NL_ + and_all (coll, fun1, 10, _1 ); _NL_ + + has_any (coll, function1, 10, _1 ); _NL_ + has_any (coll, &function1, 10, _1 ); _NL_ + has_any (coll, fun1, 10, _1 ); _NL_ + + for_each (coll, function1, _1, _1 ); _NL_ + for_each (coll, &function1,_1, _1 ); _NL_ + for_each (coll, fun1, _1, _1 ); _NL_ + + and_all (coll, function1, _1, _1 ); _NL_ + and_all (coll, &function1, _1, _1 ); _NL_ + and_all (coll, fun1, _1, _1 ); _NL_ + + has_any (coll, function1, _1, _1 ); _NL_ + has_any (coll, &function1, _1, _1 ); _NL_ + has_any (coll, fun1, _1, _1 ); _NL_ + + // does not compile: + for_each (coll, function1, 10, 20, _1 ); + for_each (coll, function1, 10, 20 ); + for_each (coll, function1, 10 ); + + + for_each (coll, function2, 10, 20, _1 ); _NL_ + for_each (coll, &function2,10, 20, _1 ); _NL_ + for_each (coll, fun2, 10, 20, _1 ); _NL_ + + and_all (coll, function2, 10, 20, _1 ); _NL_ + and_all (coll, &function2, 10, 20, _1 ); _NL_ + and_all (coll, fun2, 10, 20, _1 ); _NL_ + + has_any (coll, function2, 10, 20, _1 ); _NL_ + has_any (coll, &function2, 10, 20, _1 ); _NL_ + has_any (coll, fun2, 10, 20, _1 ); _NL_ + + int sum=0; + + for_each (coll, function2, _1, _1, ref(sum) ); _NL_ + for_each (coll, &function2,_1, _1, ref(sum) ); _NL_ + for_each (coll, fun2, _1, _1, ref(sum) ); _NL_ + + and_all (coll, function2, _1, _1, ref(sum) ); _NL_ + and_all (coll, &function2, _1, _1, ref(sum) ); _NL_ + and_all (coll, fun2, _1, _1, ref(sum) ); _NL_ + + has_any (coll, function2, _1, _1, ref(sum) ); _NL_ + has_any (coll, &function2, _1, _1, ref(sum) ); _NL_ + has_any (coll, fun2, _1, _1, ref(sum) ); _NL_ + + } + + + + struct Dummy + { + int sum_; + + bool + fun (int i) + { + sum_ += i; + return plainFunc (sum_); + } + }; + + /** @test bind a member function to be invoked for each element */ + template + void + check_foreach_memFun (CO coll) + { + Dummy dummy; + + for_each (coll, &Dummy::fun, dummy, _1 ); _NL_ + and_all (coll, &Dummy::fun, dummy, _1 ); _NL_ + has_any (coll, &Dummy::fun, dummy, _1 ); _NL_ + + for_each (coll, &Dummy::fun, &dummy, _1 ); _NL_ + and_all (coll, &Dummy::fun, &dummy, _1 ); _NL_ + has_any (coll, &Dummy::fun, &dummy, _1 ); _NL_ + + + } + + + /** @test use a lambda-expression, to be invoked for each element */ + template + void + check_foreach_lambda (CO coll) + { + uint sum; + for_each (coll, _1_ + var(sum)); + + ASSERT (sum == NUM_ELMS/2 * (NUM_ELMS+1)); + + ASSERT (!and_all (coll, _1_ - 1 )); + ASSERT ( has_any (coll, _1_ + 1 )); + } + + + /** @test verify the logic of universal and existential quantisation. + * We use a predicate generated on-the-fly as lambda expression */ + template + void + check_existence_quant (CO coll) + { + ASSERT ( and_all (coll, 0 < _1_ )); + ASSERT (!and_all (coll, 1 < _1_ )); + + ASSERT ( has_any (coll, 0 < _1_ )); + ASSERT ( has_any (coll, _1_ >= NUM_ELMS )); + ASSERT (!has_any (coll, _1_ > NUM_ELMS )); + } + + + struct TestElm + { + uint n_; + TestElm(uint i) : n_(i) {} + + void operation() { plainFunc (n_); } + }; + + + /** @test the binding can also be used to \em dispatch an operation + * on each element within a object collection: here the parameter + * is used as \c this pointer to specify the object instance */ + template + void + check_invoke_on_each (CO coll) + { + vector elms; + for (uint i=0; i<6; ++i) + elms.push_back (TestElm(i)); + + vector elmPtrs; + for (uint i=0; i<6; ++i) + elms.push_back (& elms[i]); + + // fed the element pointer as "this" pointer of the member function + for_each (elmPtrs, &TestElm::operation, _1 ); _NL_ + and_all (elmPtrs, &TestElm::operation, _1 ); _NL_ + has_any (elmPtrs, &TestElm::operation, _1 ); _NL_ + + // but works with references as well + for_each (elms, &TestElm::operation, _1 ); _NL_ + and_all (elms, &TestElm::operation, _1 ); _NL_ + has_any (elms, &TestElm::operation, _1 ); _NL_ + } + }; + + + + + LAUNCHER (UtilForeach_test, "unit common"); + + +}} // namespace util::test + From 0dca7cbb4df013334adf40235e83056d56d0b852 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 29 Dec 2009 04:30:11 +0100 Subject: [PATCH 169/377] not-yet-implemented.... --- src/proc/mobject/session/placement-index.cpp | 4 +++ tests/lib/util-foreach-test.cpp | 28 +++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index 59a20262b..174350c32 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -534,6 +534,7 @@ namespace session { /* ====== PlacementIndex validity self-check ====== */ +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 479 !!!!!!!!! namespace { // Implementation details of self-check LUMIERA_ERROR_DEFINE(INDEX_CORRUPTED, "PlacementIndex corrupted"); @@ -621,6 +622,7 @@ namespace session { #undef SCO }//(End) self-check implementation +#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! @@ -636,6 +638,7 @@ namespace session { bool PlacementIndex::isValid() const { +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 479 !!!!!!!!! try { if (!pTab_) @@ -656,6 +659,7 @@ namespace session { lumiera_error(); ERROR (session, "%s", failure.what()); } +#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! return false; } diff --git a/tests/lib/util-foreach-test.cpp b/tests/lib/util-foreach-test.cpp index 927eb26cd..e78f873b5 100644 --- a/tests/lib/util-foreach-test.cpp +++ b/tests/lib/util-foreach-test.cpp @@ -133,21 +133,21 @@ namespace test { RangeI iterator(container.begin(), container.end()); check_foreach_plain (container); - check_foreach_plain (iterator); +// check_foreach_plain (iterator); check_foreach_bind (container); - check_foreach_bind (iterator); +// check_foreach_bind (iterator); check_foreach_memFun (container); - check_foreach_memFun (iterator); +// check_foreach_memFun (iterator); check_foreach_lambda (container); - check_foreach_lambda (iterator); +// check_foreach_lambda (iterator); check_existence_quant (container); - check_existence_quant (iterator); +// check_existence_quant (iterator); - check_invoke_on_each (iterator); + check_invoke_on_each (); } @@ -185,6 +185,7 @@ namespace test { function fun1(function1); function fun2(function2); +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 479 !!!!!!!!! for_each (coll, function1, 10, _1 ); _NL_ for_each (coll, &function1,10, _1 ); _NL_ for_each (coll, fun1, 10, _1 ); _NL_ @@ -241,6 +242,7 @@ namespace test { has_any (coll, &function2, _1, _1, ref(sum) ); _NL_ has_any (coll, fun2, _1, _1, ref(sum) ); _NL_ +#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! } @@ -264,6 +266,7 @@ namespace test { { Dummy dummy; +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 479 !!!!!!!!! for_each (coll, &Dummy::fun, dummy, _1 ); _NL_ and_all (coll, &Dummy::fun, dummy, _1 ); _NL_ has_any (coll, &Dummy::fun, dummy, _1 ); _NL_ @@ -271,7 +274,7 @@ namespace test { for_each (coll, &Dummy::fun, &dummy, _1 ); _NL_ and_all (coll, &Dummy::fun, &dummy, _1 ); _NL_ has_any (coll, &Dummy::fun, &dummy, _1 ); _NL_ - +#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! } @@ -318,19 +321,19 @@ namespace test { /** @test the binding can also be used to \em dispatch an operation * on each element within a object collection: here the parameter * is used as \c this pointer to specify the object instance */ - template void - check_invoke_on_each (CO coll) + check_invoke_on_each () { - vector elms; + std::vector elms; for (uint i=0; i<6; ++i) elms.push_back (TestElm(i)); - vector elmPtrs; + std::vector elmPtrs; for (uint i=0; i<6; ++i) - elms.push_back (& elms[i]); + elmPtrs.push_back (& elms[i]); // fed the element pointer as "this" pointer of the member function +#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 479 !!!!!!!!! for_each (elmPtrs, &TestElm::operation, _1 ); _NL_ and_all (elmPtrs, &TestElm::operation, _1 ); _NL_ has_any (elmPtrs, &TestElm::operation, _1 ); _NL_ @@ -339,6 +342,7 @@ namespace test { for_each (elms, &TestElm::operation, _1 ); _NL_ and_all (elms, &TestElm::operation, _1 ); _NL_ has_any (elms, &TestElm::operation, _1 ); _NL_ +#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! } }; From 2b46574da3f680afc85183ec67ebe1734b1e50e8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 29 Dec 2009 04:39:27 +0100 Subject: [PATCH 170/377] move the for_each helpers into a separate header (because util.hpp is used pervasively, and I don't want in such a widely used header... --- src/common/subsystem-runner.hpp | 1 + src/lib/util-foreach.hpp | 87 ++++++++++++ src/lib/util.hpp | 26 ---- src/proc/asset.cpp | 1 + src/proc/assetmanager.cpp | 2 +- src/proc/engine/nodewiring-def.hpp | 1 + src/proc/mobject/session/defsregistry.hpp | 1 + src/proc/mobject/session/placement-index.cpp | 2 +- src/proc/mobject/session/scope-path.cpp | 2 +- tests/components/backend/mediaaccessmock.cpp | 1 + .../proc/asset/asset-diagnostics.hpp | 1 + .../proc/control/command-argument-test.cpp | 1 + .../mobject/session/rebuildfixturetest.cpp | 1 + tests/lib/allocationclustertest.cpp | 1 + tests/lib/iter-adapter-test.cpp | 1 + tests/lib/itertools-test.cpp | 1 + tests/lib/opaque-holder-test.cpp | 1 + tests/lib/query/queryutilstest.cpp | 1 + tests/lib/removefromsettest.cpp | 133 +++++++++--------- tests/lib/sub-id-test.cpp | 1 + tests/lib/test/cmdlinewrappertest.cpp | 124 ++++++++-------- tests/lib/test/test-helper-test.cpp | 2 +- tests/lib/typed-counter-test.cpp | 2 +- tests/lib/util-foreach-test.cpp | 2 +- 24 files changed, 233 insertions(+), 163 deletions(-) create mode 100644 src/lib/util-foreach.hpp diff --git a/src/common/subsystem-runner.hpp b/src/common/subsystem-runner.hpp index d8fa5bb6d..8e7edcffc 100644 --- a/src/common/subsystem-runner.hpp +++ b/src/common/subsystem-runner.hpp @@ -26,6 +26,7 @@ #include "lib/error.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "common/subsys.hpp" #include "lib/sync.hpp" diff --git a/src/lib/util-foreach.hpp b/src/lib/util-foreach.hpp new file mode 100644 index 000000000..2d11430d3 --- /dev/null +++ b/src/lib/util-foreach.hpp @@ -0,0 +1,87 @@ +/* + UTIL-FOREACH.hpp - helpers for doing something for each element + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef UTIL_FOREACH_H +#define UTIL_FOREACH_H + +#include "lib/util.hpp" + +#include + + + +namespace util { + + + + /** shortcut for operating on all elements of a container. + * Isn't this already defined somewhere? It's so obvious.. + */ + template + inline Oper + for_each (Container& c, Oper doIt) + { + return std::for_each (c.begin(),c.end(), doIt); + } + + + /** All quantification: check if all elements of a collection + * satisfy the given predicate. Actually a short-circuit + * evaluation is performed. + */ + template + inline bool + and_all (SEQ& coll, Oper predicate) + { + typename SEQ::const_iterator e = coll.end(); + typename SEQ::const_iterator i = coll.begin(); + + for ( ; i!=e; ++i ) + if (!predicate(*i)) + return false; + + return true; + } + + + /** Existential quantification: check if any element + * of a collection satisfies the given predicate. + * Actually, a short-circuit evaluation is performed. + */ + template + inline bool + has_any (SEQ& coll, Oper predicate) + { + typename SEQ::const_iterator e = coll.end(); + typename SEQ::const_iterator i = coll.begin(); + + for ( ; i!=e; ++i ) + if (predicate(*i)) + return true; + + return false; + } + + +} // namespace util +#endif /*UTIL_FOREACH_H*/ diff --git a/src/lib/util.hpp b/src/lib/util.hpp index 02a52941b..3d3abf038 100644 --- a/src/lib/util.hpp +++ b/src/lib/util.hpp @@ -191,32 +191,6 @@ namespace util { } - /** shortcut for operating on all elements of a container. - * Isn't this already defined somewhere? It's so obvious.. - */ - template - inline Oper - for_each (Container& c, Oper doIt) - { - return std::for_each (c.begin(),c.end(), doIt); - } - - - /** shortcut for testing all elements of a collection - * with the given predicate. - */ - template - inline bool - and_all (SEQ& coll, Oper predicate) - { - typename SEQ::const_iterator e = coll.end(); - typename SEQ::const_iterator i = coll.begin(); - - while (i!=e && predicate(*i)) ++i; - return i==e; - } - - /** shortcut to save some typing when having to define * const and non-const variants of member functions */ diff --git a/src/proc/asset.cpp b/src/proc/asset.cpp index 3d4b8fc79..0cdbcf8f1 100644 --- a/src/proc/asset.cpp +++ b/src/proc/asset.cpp @@ -23,6 +23,7 @@ #include "proc/asset.hpp" #include "proc/assetmanager.hpp" +#include "lib/util-foreach.hpp" #include "lib/util.hpp" #include diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index c26811bed..625c189c1 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -25,7 +25,7 @@ #include "proc/asset/db.hpp" #include "lib/sync.hpp" -#include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include #include diff --git a/src/proc/engine/nodewiring-def.hpp b/src/proc/engine/nodewiring-def.hpp index 4fc4f14c2..c659d2493 100644 --- a/src/proc/engine/nodewiring-def.hpp +++ b/src/proc/engine/nodewiring-def.hpp @@ -42,6 +42,7 @@ #include "proc/engine/procnode.hpp" #include "lib/refarray.hpp" +#include "lib/util-foreach.hpp" #include //#include diff --git a/src/proc/mobject/session/defsregistry.hpp b/src/proc/mobject/session/defsregistry.hpp index 3fbd4aa1f..f37f08109 100644 --- a/src/proc/mobject/session/defsregistry.hpp +++ b/src/proc/mobject/session/defsregistry.hpp @@ -43,6 +43,7 @@ #include "lib/sync-classlock.hpp" #include "lib/query.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "lib/p.hpp" #include diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index 174350c32..df5a6d206 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -55,7 +55,7 @@ #include "proc/mobject/session/scope.hpp" #include "lib/typed-allocation-manager.hpp" //#include "proc/mobject/mobject.hpp" ///////////////////////TODO necessary? -#include "lib/util.hpp" +#include "lib/util-foreach.hpp" //#include diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp index f464cc7d9..0179a1ed8 100644 --- a/src/proc/mobject/session/scope-path.cpp +++ b/src/proc/mobject/session/scope-path.cpp @@ -26,10 +26,10 @@ #include "proc/mobject/session/scope-locator.hpp" #include "proc/mobject/session/session-service-explore-scope.hpp" #include "proc/mobject/mobject.hpp" +#include "lib/util-foreach.hpp" #include "lib/itertools.hpp" #include "lib/symbol.hpp" #include "lib/error.hpp" -#include "lib/util.hpp" #include #include diff --git a/tests/components/backend/mediaaccessmock.cpp b/tests/components/backend/mediaaccessmock.cpp index 25b5c6a0d..718bc55ee 100644 --- a/tests/components/backend/mediaaccessmock.cpp +++ b/tests/components/backend/mediaaccessmock.cpp @@ -36,6 +36,7 @@ #include "backend/mediaaccessmock.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include #include diff --git a/tests/components/proc/asset/asset-diagnostics.hpp b/tests/components/proc/asset/asset-diagnostics.hpp index 2ae2a232f..856f131b3 100644 --- a/tests/components/proc/asset/asset-diagnostics.hpp +++ b/tests/components/proc/asset/asset-diagnostics.hpp @@ -34,6 +34,7 @@ #include "proc/assetmanager.hpp" +#include "lib/util-foreach.hpp" #include "lib/util.hpp" #include diff --git a/tests/components/proc/control/command-argument-test.cpp b/tests/components/proc/control/command-argument-test.cpp index 2b9368bd3..bdf7b2724 100644 --- a/tests/components/proc/control/command-argument-test.cpp +++ b/tests/components/proc/control/command-argument-test.cpp @@ -27,6 +27,7 @@ #include "lib/scoped-ptrvect.hpp" #include "lib/lumitime-fmt.hpp" #include "lib/meta/tuple.hpp" +#include "lib/util-foreach.hpp" #include "lib/util.hpp" #include diff --git a/tests/components/proc/mobject/session/rebuildfixturetest.cpp b/tests/components/proc/mobject/session/rebuildfixturetest.cpp index ae287786c..a0970ff8b 100644 --- a/tests/components/proc/mobject/session/rebuildfixturetest.cpp +++ b/tests/components/proc/mobject/session/rebuildfixturetest.cpp @@ -25,6 +25,7 @@ #include "proc/mobject/session.hpp" #include "proc/mobject/session/edl.hpp" #include "proc/mobject/session/testsession1.hpp" +#include "lib/util-foreach.hpp" #include "lib/util.hpp" //#include diff --git a/tests/lib/allocationclustertest.cpp b/tests/lib/allocationclustertest.cpp index 6b07775ad..ffbba08cd 100644 --- a/tests/lib/allocationclustertest.cpp +++ b/tests/lib/allocationclustertest.cpp @@ -24,6 +24,7 @@ #include "lib/test/run.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "lib/allocationcluster.hpp" #include "lib/scoped-holder.hpp" diff --git a/tests/lib/iter-adapter-test.cpp b/tests/lib/iter-adapter-test.cpp index 79732aaa1..6acf63f35 100644 --- a/tests/lib/iter-adapter-test.cpp +++ b/tests/lib/iter-adapter-test.cpp @@ -24,6 +24,7 @@ #include "lib/test/run.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "lib/iter-adapter.hpp" diff --git a/tests/lib/itertools-test.cpp b/tests/lib/itertools-test.cpp index 8599f080f..850c8a03e 100644 --- a/tests/lib/itertools-test.cpp +++ b/tests/lib/itertools-test.cpp @@ -24,6 +24,7 @@ #include "lib/test/run.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "lib/itertools.hpp" diff --git a/tests/lib/opaque-holder-test.cpp b/tests/lib/opaque-holder-test.cpp index b7be45f8a..09c595d07 100644 --- a/tests/lib/opaque-holder-test.cpp +++ b/tests/lib/opaque-holder-test.cpp @@ -25,6 +25,7 @@ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "lib/opaque-holder.hpp" #include "lib/bool-checkable.hpp" diff --git a/tests/lib/query/queryutilstest.cpp b/tests/lib/query/queryutilstest.cpp index 61b464118..9fd5e6677 100644 --- a/tests/lib/query/queryutilstest.cpp +++ b/tests/lib/query/queryutilstest.cpp @@ -23,6 +23,7 @@ #include "lib/test/run.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "lib/cmdline.hpp" #include "lib/query.hpp" diff --git a/tests/lib/removefromsettest.cpp b/tests/lib/removefromsettest.cpp index dd512782f..ce9f825ec 100644 --- a/tests/lib/removefromsettest.cpp +++ b/tests/lib/removefromsettest.cpp @@ -22,7 +22,7 @@ #include "lib/test/run.hpp" -#include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include #include @@ -36,75 +36,72 @@ using std::string; -namespace util - { - namespace test - { - using util::for_each; - using boost::lambda::_1; - using boost::lambda::bind; - using boost::lexical_cast; - - +namespace util { +namespace test { - template - void - show (COLL const& coll) + using util::for_each; + using boost::lambda::_1; + using boost::lambda::bind; + using boost::lexical_cast; + + + + template + void + show (COLL const& coll) + { + cout << "[ "; + for_each (coll, cout << _1 << ", "); + cout << "]\n"; + } + + bool + killerselector (string description, uint candidate) + { + return string::npos != description.find( lexical_cast (candidate)); + } + + + + class RemoveFromSet_test : public Test { - cout << "[ "; - for_each (coll, cout << _1 << ", "); - cout << "]\n"; - } - - bool - killerselector (string description, uint candidate) - { - return string::npos != description.find( lexical_cast (candidate)); - } - - - - class RemoveFromSet_test : public Test - { - virtual void - run (Arg) - { - test_remove (" nothing "); - test_remove ("0"); - test_remove ("9"); - test_remove ("5"); - test_remove ("0 2 4 6 8 "); - test_remove (" 1 3 5 7 9"); - test_remove ("0 1 2 3 4 5 6 7 8 9"); - test_remove ("0 1 2 3 4 5 6 7 8 "); - test_remove (" 1 2 3 4 5 6 7 8 9"); - test_remove ("0 1 2 3 4 6 7 8 9"); - } - - - /** @test populate a test set, - * remove the denoted elements - * and print the result... */ - void - test_remove (string elems_to_remove) - { - std::set theSet; - for (int i=0; i<10; ++i) - theSet.insert (i); - - util::remove_if (theSet, bind( killerselector, elems_to_remove, _1)); - - cout << "removed " << elems_to_remove << " ---> "; - show (theSet); - } - - }; - + virtual void + run (Arg) + { + test_remove (" nothing "); + test_remove ("0"); + test_remove ("9"); + test_remove ("5"); + test_remove ("0 2 4 6 8 "); + test_remove (" 1 3 5 7 9"); + test_remove ("0 1 2 3 4 5 6 7 8 9"); + test_remove ("0 1 2 3 4 5 6 7 8 "); + test_remove (" 1 2 3 4 5 6 7 8 9"); + test_remove ("0 1 2 3 4 6 7 8 9"); + } - LAUNCHER (RemoveFromSet_test, "unit common"); - - } // namespace test - -} // namespace util + /** @test populate a test set, + * remove the denoted elements + * and print the result... */ + void + test_remove (string elems_to_remove) + { + std::set theSet; + for (int i=0; i<10; ++i) + theSet.insert (i); + + util::remove_if (theSet, bind( killerselector, elems_to_remove, _1)); + + cout << "removed " << elems_to_remove << " ---> "; + show (theSet); + } + + }; + + + LAUNCHER (RemoveFromSet_test, "unit common"); + + +}} // namespace util::test diff --git a/tests/lib/sub-id-test.cpp b/tests/lib/sub-id-test.cpp index c61a6b8c4..b52778c21 100644 --- a/tests/lib/sub-id-test.cpp +++ b/tests/lib/sub-id-test.cpp @@ -23,6 +23,7 @@ #include "lib/test/run.hpp" #include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "lib/sub-id.hpp" diff --git a/tests/lib/test/cmdlinewrappertest.cpp b/tests/lib/test/cmdlinewrappertest.cpp index 7ef194c1d..00a016d9f 100644 --- a/tests/lib/test/cmdlinewrappertest.cpp +++ b/tests/lib/test/cmdlinewrappertest.cpp @@ -23,7 +23,7 @@ #include "lib/test/run.hpp" #include "lib/cmdline.hpp" -#include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include #include @@ -34,68 +34,66 @@ using std::cout; -namespace util - { - namespace test - { - using boost::lambda::_1; - using boost::lambda::var; - - +namespace util { +namespace test { + using boost::lambda::_1; + using boost::lambda::var; - /** @test for util::Cmdline, wrapping various example cmdlines */ - class CmdlineWrapper_test : public Test - { - void - run (Arg) - { - testLine(""); - testLine("\n\t "); - testLine("spam"); - testLine("\nspam"); - testLine("eat more spam"); - testLine(" oo _O()O_ ä + €"); - testLine("Ω\tooΩ\toΩo\tΩoo"); - - testStandardCmdlineformat(); - } - - void testLine (const string cmdline) - { - cout << "wrapping cmdline:" << cmdline << "..." << "\n"; - - int i=0; - Cmdline theCmdline (cmdline); - for_each(theCmdline, (cout << var(i)++ << "|" << _1 << "|\n")); - cout << "-->" << theCmdline << "\n"; - - // consistency checks - std::ostringstream output; - output << theCmdline; - ENSURE (output.str() == string(theCmdline)); - - i=0; - string token; - std::istringstream input(theCmdline); - while (input >> token) - ENSURE (token == theCmdline[i++]); - } - - /** @test wrapping a (albeit faked) standard commandline - * given as (argc, argv[]) - */ - void testStandardCmdlineformat() - { - const char* fakeArg[3] = {"CMD", "one ", "two"}; - Cmdline theCmdline(3, fakeArg); - cout << "Standard Cmdlineformat:" << theCmdline << "\n"; - } - }; - - LAUNCHER (CmdlineWrapper_test, "unit common"); - + + + /** @test for util::Cmdline, wrapping various example cmdlines */ + class CmdlineWrapper_test : public Test + { + void + run (Arg) + { + testLine(""); + testLine("\n\t "); + testLine("spam"); + testLine("\nspam"); + testLine("eat more spam"); + testLine(" oo _O()O_ ä + €"); + testLine("Ω\tooΩ\toΩo\tΩoo"); + + testStandardCmdlineformat(); + } - } // namespace test - -} // namespace util + void + testLine (const string cmdline) + { + cout << "wrapping cmdline:" << cmdline << "..." << "\n"; + + int i=0; + Cmdline theCmdline (cmdline); + for_each(theCmdline, (cout << var(i)++ << "|" << _1 << "|\n")); + cout << "-->" << theCmdline << "\n"; + + // consistency checks + std::ostringstream output; + output << theCmdline; + ENSURE (output.str() == string(theCmdline)); + + i=0; + string token; + std::istringstream input(theCmdline); + while (input >> token) + ENSURE (token == theCmdline[i++]); + } + + /** @test wrapping a (albeit faked) standard commandline + * given as (argc, argv[]) + */ + void + testStandardCmdlineformat() + { + const char* fakeArg[3] = {"CMD", "one ", "two"}; + Cmdline theCmdline(3, fakeArg); + cout << "Standard Cmdlineformat:" << theCmdline << "\n"; + } + }; + + LAUNCHER (CmdlineWrapper_test, "unit common"); + + +}} // namespace util::test diff --git a/tests/lib/test/test-helper-test.cpp b/tests/lib/test/test-helper-test.cpp index f9c940741..84d3cfe92 100644 --- a/tests/lib/test/test-helper-test.cpp +++ b/tests/lib/test/test-helper-test.cpp @@ -24,7 +24,7 @@ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "lib/error.hpp" -#include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include #include diff --git a/tests/lib/typed-counter-test.cpp b/tests/lib/typed-counter-test.cpp index a118d8d26..02d9e26d4 100644 --- a/tests/lib/typed-counter-test.cpp +++ b/tests/lib/typed-counter-test.cpp @@ -46,8 +46,8 @@ #include "lib/typed-counter.hpp" #include "lib/scoped-ptrvect.hpp" #include "backend/thread-wrapper.hpp" +#include "lib/util-foreach.hpp" #include "lib/sync.hpp" -#include "lib/util.hpp" #include #include diff --git a/tests/lib/util-foreach-test.cpp b/tests/lib/util-foreach-test.cpp index e78f873b5..a1f5294e8 100644 --- a/tests/lib/util-foreach-test.cpp +++ b/tests/lib/util-foreach-test.cpp @@ -22,7 +22,7 @@ #include "lib/test/run.hpp" -#include "lib/util.hpp" +#include "lib/util-foreach.hpp" #include "lib/iter-adapter.hpp" From 484213e42d09f2dc6366db715e6e60f9f36bd463 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 29 Dec 2009 05:34:32 +0100 Subject: [PATCH 171/377] Implementation draft --- tests/lib/util-foreach-test.cpp | 111 ++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/tests/lib/util-foreach-test.cpp b/tests/lib/util-foreach-test.cpp index a1f5294e8..0f25c91ea 100644 --- a/tests/lib/util-foreach-test.cpp +++ b/tests/lib/util-foreach-test.cpp @@ -49,6 +49,117 @@ using namespace boost::lambda; namespace util { +///////////////////////////////////////////////////////////////////////////TODO: Implementation draft + + using std::tr1::bind; + + template < typename CON, typename FUN + , typename P1 + > + inline void //________________________________ + for_each (CON& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument + { + for_each (elements, std::tr1::bind (function, bind1)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + > + inline void //________________________________ + for_each (CON& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments + { + for_each (elements, std::tr1::bind (function, bind1, bind2)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + , typename P3 + > + inline void //________________________________ + for_each (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments + { + for_each (elements, std::tr1::bind (function, bind1, bind2, bind3)); + } + + + + + + template < typename CON, typename FUN + , typename P1 + > + inline bool //________________________________ + and_all (CON& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument + { + return and_all (elements, std::tr1::bind (function, bind1)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + > + inline bool //________________________________ + and_all (CON& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments + { + return and_all (elements, std::tr1::bind (function, bind1, bind2)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + , typename P3 + > + inline bool //________________________________ + and_all (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments + { + return and_all (elements, std::tr1::bind (function, bind1, bind2, bind3)); + } + + + + + + template < typename CON, typename FUN + , typename P1 + > + inline bool //________________________________ + has_any (CON& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument + { + return has_any (elements, std::tr1::bind (function, bind1)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + > + inline bool //________________________________ + has_any (CON& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments + { + return has_any (elements, std::tr1::bind (function, bind1, bind2)); + } + + + template < typename CON, typename FUN + , typename P1 + , typename P2 + , typename P3 + > + inline bool //________________________________ + has_any (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments + { + return has_any (elements, std::tr1::bind (function, bind1, bind2, bind3)); + } + + + +///////////////////////////////////////////////////////////////////////////TODO: Implementation draft (END) namespace test { typedef std::vector VecI; From 12a2eed583634732479e0c976b63e79e8d66f8d2 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Tue, 29 Dec 2009 16:52:39 -0500 Subject: [PATCH 172/377] fix variable names in the LUMIERA_RECCONDITION_SECTION_CHAIN macro (seems like a copy+paste error from recmutex.h) --- src/lib/reccondition.h | 6 +++--- tests/15locking.tests | 9 +++++++++ tests/library/test-locking.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/lib/reccondition.h b/src/lib/reccondition.h index f9bcd59d1..51ce6ef07 100644 --- a/src/lib/reccondition.h +++ b/src/lib/reccondition.h @@ -65,13 +65,13 @@ #define LUMIERA_RECCONDITION_SECTION_CHAIN(nobugflag, cnd) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + for (lumiera_sectionlock *lumiera_reccond_section_old_ = &lumiera_reccond_section_, \ NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_reccond_section_ = { \ (void*)1, lumiera_reccondition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \ lumiera_reccond_section_.lock;) \ for ( \ ({ \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + REQUIRE (lumiera_reccond_section_old_->lock, "section prematurely unlocked"); \ lumiera_reccond_section_.lock = (cnd); \ NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \ RESOURCE_WAIT (nobugflag, (cnd)->rh, "acquire reccondmutex", lumiera_reccond_section_.rh) \ @@ -79,7 +79,7 @@ if (pthread_mutex_lock (&(cnd)->reccndmutex)) \ LUMIERA_DIE (LOCK_ACQUIRE); \ RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + LUMIERA_SECTION_UNLOCK_(lumiera_reccond_section_old_); \ } \ }); \ lumiera_reccond_section_.lock; \ diff --git a/tests/15locking.tests b/tests/15locking.tests index 0936499f2..7401d4b58 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -86,3 +86,12 @@ PLANNED "reccondition broadcasting" < Date: Thu, 31 Dec 2009 01:21:45 +0100 Subject: [PATCH 173/377] trying to track down a strange compiler warning --- src/tool/try.cpp | 87 ++++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 36 deletions(-) diff --git a/src/tool/try.cpp b/src/tool/try.cpp index de206c43e..b2823afc8 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -13,71 +13,86 @@ // 7/08 - combining partial specialisation and subclasses // 10/8 - abusing the STL containers to hold noncopyable values // 6/09 - investigating how to build a mixin template providing an operator bool() +// 12/9 - tracking down a strange "warning: type qualifiers ignored on function return type" #include #define LUMIERA_LOGGING_CXX #include "include/logging.h" //#include "include/nobugcfg.h" -#include "lib/bool-checkable.hpp" + +#include #include //#include -#include +#include #include #include +//using std::tr1::bind; +using std::tr1::placeholders::_1; + using std::rand; using std::string; using std::cout; -using boost::format; - namespace { - boost::format fmt ("<%2i>"); - long checksum = 0; + + template + inline bool + eat_all (SEQ& coll, Oper predicate) + { + typename SEQ::const_iterator e = coll.end(); + typename SEQ::const_iterator i = coll.begin(); + + predicate(*i); + +// for ( ; i!=e; ++i ) +// if (!predicate(*i)) +// return false; + + return true; } - struct TestIt1 - : lib::BoolCheckable - { - - int val_; - - TestIt1 (int v = (rand() % 10)) - : val_(v) - { } - - bool - isValid() const - { - return val_ % 2; - } - - }; +// template < typename CON, typename FUN +// , typename P1 +// , typename P2 +// > +// inline bool +// eat_all (CON& elements, FUN function, P1 bind1, P2 bind2) +// { +// return eat_all (elements, std::tr1::bind (function, bind1, bind2)); +// } + + + namespace { +// std::tr1::_Placeholder<1> _1; + bool + plainFunc (int i, int j) + { + cout <<':'<< i+j; + return i+j; + } + } int -main (int, char**) //(int argc, char* argv[]) +main (int, char**) { NOBUG_INIT; - for (int i=0; i<10; ++i) - { - TestIt1 testrosteron (i); - - if (testrosteron) - cout << "doIt \n"; - if (!testrosteron) - cout << i << "\n"; - } - cout << "size=" << sizeof(TestIt1) <<"\n"; + typedef std::vector VecI; - char* horror = 0; - ERROR (all, "note: %s is a horrible thing", horror); + uint count = 4; + VecI numberz; + while (count) + numberz.push_back(count--); + +// eat_all (numberz, plainFunc, 10, _1 ); + eat_all (numberz, std::tr1::bind (plainFunc, 10, _1)); cout << "\n.gulp.\n"; From e7fcfaca8dddbca4f0c5df217f597e34b29c119a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 31 Dec 2009 02:51:58 +0100 Subject: [PATCH 174/377] problem was: compiler couldn't figure out the return type thus let's give a hint... --- src/tool/try.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tool/try.cpp b/src/tool/try.cpp index b2823afc8..407116560 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -92,7 +92,7 @@ main (int, char**) numberz.push_back(count--); // eat_all (numberz, plainFunc, 10, _1 ); - eat_all (numberz, std::tr1::bind (plainFunc, 10, _1)); + eat_all (numberz, std::tr1::bind (plainFunc, 10, _1)); cout << "\n.gulp.\n"; From e94927d5a39329231b6565409ea2b786f219832e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 31 Dec 2009 03:25:25 +0100 Subject: [PATCH 175/377] standard case (using STL container) solved, incl. binding arguments and member functions --- src/lib/util-foreach.hpp | 30 +++++++++++ src/tool/try.cpp | 52 ++++++++---------- tests/lib/util-foreach-test.cpp | 94 +++++++++++++++++++++++---------- 3 files changed, 120 insertions(+), 56 deletions(-) diff --git a/src/lib/util-foreach.hpp b/src/lib/util-foreach.hpp index 2d11430d3..c5f1e2253 100644 --- a/src/lib/util-foreach.hpp +++ b/src/lib/util-foreach.hpp @@ -52,6 +52,21 @@ namespace util { template inline bool and_all (SEQ& coll, Oper predicate) + { + typename SEQ::iterator e = coll.end(); + typename SEQ::iterator i = coll.begin(); + + for ( ; i!=e; ++i ) + if (!predicate(*i)) + return false; + + return true; + } + + + template + inline bool + and_all (SEQ const& coll, Oper predicate) { typename SEQ::const_iterator e = coll.end(); typename SEQ::const_iterator i = coll.begin(); @@ -71,6 +86,21 @@ namespace util { template inline bool has_any (SEQ& coll, Oper predicate) + { + typename SEQ::iterator e = coll.end(); + typename SEQ::iterator i = coll.begin(); + + for ( ; i!=e; ++i ) + if (predicate(*i)) + return true; + + return false; + } + + + template + inline bool + has_any (SEQ const& coll, Oper predicate) { typename SEQ::const_iterator e = coll.end(); typename SEQ::const_iterator i = coll.begin(); diff --git a/src/tool/try.cpp b/src/tool/try.cpp index 407116560..412772c84 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -16,9 +16,9 @@ // 12/9 - tracking down a strange "warning: type qualifiers ignored on function return type" -#include -#define LUMIERA_LOGGING_CXX -#include "include/logging.h" +//#include +//#define LUMIERA_LOGGING_CXX +//#include "include/logging.h" //#include "include/nobugcfg.h" #include @@ -33,7 +33,7 @@ //using std::tr1::bind; using std::tr1::placeholders::_1; -using std::rand; +//using std::rand; using std::string; using std::cout; @@ -46,35 +46,30 @@ using std::cout; typename SEQ::const_iterator e = coll.end(); typename SEQ::const_iterator i = coll.begin(); - predicate(*i); - -// for ( ; i!=e; ++i ) -// if (!predicate(*i)) -// return false; + for ( ; i!=e; ++i ) + if (!predicate(*i)) + return false; return true; } -// template < typename CON, typename FUN -// , typename P1 -// , typename P2 -// > -// inline bool -// eat_all (CON& elements, FUN function, P1 bind1, P2 bind2) -// { -// return eat_all (elements, std::tr1::bind (function, bind1, bind2)); -// } + template < typename CON, typename FUN + , typename P1 + , typename P2 + > + inline bool + eat_all (CON& elements, FUN function, P1 bind1, P2 bind2) + { + return eat_all (elements, std::tr1::bind (function, bind1, bind2)); + } - namespace { -// std::tr1::_Placeholder<1> _1; - bool - plainFunc (int i, int j) - { - cout <<':'<< i+j; - return i+j; - } + bool + plainFunc (int i, int j) + { + cout <<':'<< i+j; + return i+j; } @@ -82,7 +77,7 @@ int main (int, char**) { - NOBUG_INIT; +// NOBUG_INIT; typedef std::vector VecI; @@ -91,8 +86,7 @@ main (int, char**) while (count) numberz.push_back(count--); -// eat_all (numberz, plainFunc, 10, _1 ); - eat_all (numberz, std::tr1::bind (plainFunc, 10, _1)); + eat_all (numberz, plainFunc, 10, _1 ); cout << "\n.gulp.\n"; diff --git a/tests/lib/util-foreach-test.cpp b/tests/lib/util-foreach-test.cpp index 0f25c91ea..9dfcf6c09 100644 --- a/tests/lib/util-foreach-test.cpp +++ b/tests/lib/util-foreach-test.cpp @@ -95,7 +95,7 @@ namespace util { inline bool //________________________________ and_all (CON& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument { - return and_all (elements, std::tr1::bind (function, bind1)); + return and_all (elements, std::tr1::bind (function, bind1)); } @@ -106,7 +106,7 @@ namespace util { inline bool //________________________________ and_all (CON& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments { - return and_all (elements, std::tr1::bind (function, bind1, bind2)); + return and_all (elements, std::tr1::bind (function, bind1, bind2)); } @@ -118,7 +118,7 @@ namespace util { inline bool //________________________________ and_all (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments { - return and_all (elements, std::tr1::bind (function, bind1, bind2, bind3)); + return and_all (elements, std::tr1::bind (function, bind1, bind2, bind3)); } @@ -131,7 +131,7 @@ namespace util { inline bool //________________________________ has_any (CON& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument { - return has_any (elements, std::tr1::bind (function, bind1)); + return has_any (elements, std::tr1::bind (function, bind1)); } @@ -142,7 +142,7 @@ namespace util { inline bool //________________________________ has_any (CON& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments { - return has_any (elements, std::tr1::bind (function, bind1, bind2)); + return has_any (elements, std::tr1::bind (function, bind1, bind2)); } @@ -154,7 +154,7 @@ namespace util { inline bool //________________________________ has_any (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments { - return has_any (elements, std::tr1::bind (function, bind1, bind2, bind3)); + return has_any (elements, std::tr1::bind (function, bind1, bind2, bind3)); } @@ -213,6 +213,7 @@ namespace test { #define _NL_ cout << endl; +#define ANNOUNCE(_LABEL_) cout << "---:" << STRINGIFY(_LABEL_) << endl; } // (End) test data and operations @@ -249,6 +250,8 @@ namespace test { check_foreach_bind (container); // check_foreach_bind (iterator); + check_foreach_bind_const (container); + check_foreach_memFun (container); // check_foreach_memFun (iterator); @@ -270,6 +273,7 @@ namespace test { void check_foreach_plain (CO coll) { + ANNOUNCE (check_foreach_plain); function func(plainFunc); for_each (coll, plainFunc); _NL_ @@ -293,10 +297,10 @@ namespace test { void check_foreach_bind (CO coll) { + ANNOUNCE (check_foreach_bind); function fun1(function1); function fun2(function2); -#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 479 !!!!!!!!! for_each (coll, function1, 10, _1 ); _NL_ for_each (coll, &function1,10, _1 ); _NL_ for_each (coll, fun1, 10, _1 ); _NL_ @@ -321,12 +325,13 @@ namespace test { has_any (coll, &function1, _1, _1 ); _NL_ has_any (coll, fun1, _1, _1 ); _NL_ - // does not compile: - for_each (coll, function1, 10, 20, _1 ); - for_each (coll, function1, 10, 20 ); - for_each (coll, function1, 10 ); + //does not compile..... + // for_each (coll, function1, 10, 20, _1 ); + // for_each (coll, function1, _1, _2 ); + // for_each (coll, function1, 10 ); + ANNOUNCE (assign_to_input); for_each (coll, function2, 10, 20, _1 ); _NL_ for_each (coll, &function2,10, 20, _1 ); _NL_ for_each (coll, fun2, 10, 20, _1 ); _NL_ @@ -340,20 +345,49 @@ namespace test { has_any (coll, fun2, 10, 20, _1 ); _NL_ int sum=0; - + ANNOUNCE (assign_to_var); for_each (coll, function2, _1, _1, ref(sum) ); _NL_ for_each (coll, &function2,_1, _1, ref(sum) ); _NL_ for_each (coll, fun2, _1, _1, ref(sum) ); _NL_ + cout << "sum=" << sum << endl; + and_all (coll, function2, _1, _1, ref(sum) ); _NL_ and_all (coll, &function2, _1, _1, ref(sum) ); _NL_ and_all (coll, fun2, _1, _1, ref(sum) ); _NL_ + cout << "sum=" << sum << endl; + has_any (coll, function2, _1, _1, ref(sum) ); _NL_ has_any (coll, &function2, _1, _1, ref(sum) ); _NL_ has_any (coll, fun2, _1, _1, ref(sum) ); _NL_ -#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! + cout << "sum=" << sum << endl; + } + + + /** @test the input sequence can be also taken + * from a const container (for iterators this + * obviously doesn't make sense */ + template + void + check_foreach_bind_const (CO const& coll) + { + ANNOUNCE (check_foreach_bind_const); + + for_each (coll,function1, 10, _1 ); _NL_ + and_all (coll, function1, 10, _1 ); _NL_ + has_any (coll, function1, 10, _1 ); _NL_ + + for_each (coll,function1, _1, _1 ); _NL_ + and_all (coll, function1, _1, _1 ); _NL_ + has_any (coll, function1, _1, _1 ); _NL_ + + int sum=0; + + for_each (coll,function2, _1, _1, ref(sum) ); _NL_ + and_all (coll, function2, _1, _1, ref(sum) ); _NL_ + has_any (coll, function2, _1, _1, ref(sum) ); _NL_ } @@ -375,18 +409,20 @@ namespace test { void check_foreach_memFun (CO coll) { + ANNOUNCE (check_foreach_memFun); + Dummy dummy; + dummy.sum_ = 0; -#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 479 !!!!!!!!! - for_each (coll, &Dummy::fun, dummy, _1 ); _NL_ - and_all (coll, &Dummy::fun, dummy, _1 ); _NL_ - has_any (coll, &Dummy::fun, dummy, _1 ); _NL_ + for_each (coll, &Dummy::fun, dummy, _1 ); _NL_ + and_all (coll, &Dummy::fun, dummy, _1 ); _NL_ + has_any (coll, &Dummy::fun, dummy, _1 ); _NL_ - for_each (coll, &Dummy::fun, &dummy, _1 ); _NL_ - and_all (coll, &Dummy::fun, &dummy, _1 ); _NL_ - has_any (coll, &Dummy::fun, &dummy, _1 ); _NL_ -#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! + for_each (coll, &Dummy::fun, &dummy, _1 ); _NL_ + and_all (coll, &Dummy::fun, &dummy, _1 ); _NL_ + has_any (coll, &Dummy::fun, &dummy, _1 ); _NL_ + cout << "sum=" << dummy.sum_ << endl; } @@ -395,8 +431,10 @@ namespace test { void check_foreach_lambda (CO coll) { - uint sum; - for_each (coll, _1_ + var(sum)); + ANNOUNCE (check_foreach_lambda); + uint sum(0); + + for_each (coll, var(sum) += _1_ ); ASSERT (sum == NUM_ELMS/2 * (NUM_ELMS+1)); @@ -411,6 +449,8 @@ namespace test { void check_existence_quant (CO coll) { + ANNOUNCE (check_existence_quant); + ASSERT ( and_all (coll, 0 < _1_ )); ASSERT (!and_all (coll, 1 < _1_ )); @@ -425,7 +465,7 @@ namespace test { uint n_; TestElm(uint i) : n_(i) {} - void operation() { plainFunc (n_); } + bool operation() { return plainFunc (n_); } }; @@ -435,6 +475,8 @@ namespace test { void check_invoke_on_each () { + ANNOUNCE (check_invoke_on_each); + std::vector elms; for (uint i=0; i<6; ++i) elms.push_back (TestElm(i)); @@ -444,16 +486,14 @@ namespace test { elmPtrs.push_back (& elms[i]); // fed the element pointer as "this" pointer of the member function -#if false //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 479 !!!!!!!!! for_each (elmPtrs, &TestElm::operation, _1 ); _NL_ and_all (elmPtrs, &TestElm::operation, _1 ); _NL_ has_any (elmPtrs, &TestElm::operation, _1 ); _NL_ - // but works with references as well + // the same works with references as well... for_each (elms, &TestElm::operation, _1 ); _NL_ and_all (elms, &TestElm::operation, _1 ); _NL_ has_any (elms, &TestElm::operation, _1 ); _NL_ -#endif ////////////////////////////////////////////////////////////////////////////////////////TODO lots of things unimplemented.....!!!!! } }; From 69277b6770983593713e58b4717981bd7e40a815 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:18:29 -0500 Subject: [PATCH 176/377] remove unused function pool_thread_loop() --- src/backend/threadpool.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 66ecd4e33..acde943e9 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -42,16 +42,6 @@ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/bet //code goes here// -void* pool_thread_loop(void * arg) -{ - (void) arg; - while (1) - { - ; - } - return arg; -} - void lumiera_threadpool_init(unsigned limit) { From 9c60d88c565dc8006cc71ca52223df1b63d9c197 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:24:07 -0500 Subject: [PATCH 177/377] remove thread limiting logic from the threadpool --- src/backend/threadpool.c | 21 +++++---------------- src/backend/threadpool.h | 4 +--- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index acde943e9..3ab589179 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -43,12 +43,11 @@ NOBUG_DEFINE_FLAG_PARENT (threadpool, threads_dbg); /*TODO insert a suitable/bet //code goes here// void -lumiera_threadpool_init(unsigned limit) +lumiera_threadpool_init(void) { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { llist_init(&threadpool.pool[i].list); - threadpool.pool[i].max_threads = limit; threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; @@ -90,20 +89,10 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, if (llist_is_empty (&threadpool.pool[kind].list)) { // TODO: fill in the reccondition argument, currently NULL - FIXME ("this max thread logic needs to be deeply thought about and made more efficient as well as rebust"); - if (threadpool.pool[kind].working_thread_count - + threadpool.pool[kind].idle_thread_count - < threadpool.pool[kind].max_threads) { - ret = lumiera_thread_new (kind, NULL, purpose, flag, - &threadpool.pool[kind].pthread_attrs); - threadpool.pool[kind].working_thread_count++; - ENSURE (ret, "did not create a valid thread"); - } - else - { - //ERROR (threadpool, "did not create a new thread because per-pool limit was reached: %d", threadpool.pool[kind].max_threads); - LUMIERA_DIE(ERRNO); - } + ret = lumiera_thread_new (kind, NULL, purpose, flag, + &threadpool.pool[kind].pthread_attrs); + threadpool.pool[kind].working_thread_count++; + ENSURE (ret, "did not create a valid thread"); } else { diff --git a/src/backend/threadpool.h b/src/backend/threadpool.h index 03b56a4fe..0c56de62d 100644 --- a/src/backend/threadpool.h +++ b/src/backend/threadpool.h @@ -71,7 +71,6 @@ struct lumiera_threadpool_struct { llist list; lumiera_mutex lock; - unsigned max_threads; unsigned working_thread_count; unsigned idle_thread_count; pthread_attr_t pthread_attrs; @@ -80,10 +79,9 @@ struct lumiera_threadpool_struct /** * Initialize the thread pool. - * @param limit the maximum number of threads (idle+working) allowed per pool */ void -lumiera_threadpool_init(unsigned limit); +lumiera_threadpool_init(void); void lumiera_threadpool_destroy(void); From d63a6066a0b8c5dfd592db321c5a12bd00ad81d5 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:27:45 -0500 Subject: [PATCH 178/377] insert a space between the function name and the ( in each function call --- src/backend/threadpool.c | 24 ++++++++++++------------ src/backend/threads.c | 16 ++++++++-------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 3ab589179..55ae77842 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -47,7 +47,7 @@ lumiera_threadpool_init(void) { for (int i = 0; i < LUMIERA_THREADCLASS_COUNT; ++i) { - llist_init(&threadpool.pool[i].list); + llist_init (&threadpool.pool[i].list); threadpool.pool[i].working_thread_count = 0; threadpool.pool[i].idle_thread_count = 0; @@ -56,7 +56,7 @@ lumiera_threadpool_init(void) pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); //cancel... - lumiera_mutex_init(&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG(threadpool)); + lumiera_mutex_init (&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG (threadpool)); } } @@ -68,9 +68,9 @@ lumiera_threadpool_destroy(void) { ECHO ("destroying individual pool #%d", i); // no locking is done at this point - ECHO ("number of threads in the pool=%d", llist_count(&threadpool.pool[i].list)); - LLIST_WHILE_HEAD(&threadpool.pool[i].list, thread) - lumiera_thread_delete((LumieraThread)thread); + ECHO ("number of threads in the pool=%d", llist_count (&threadpool.pool[i].list)); + LLIST_WHILE_HEAD (&threadpool.pool[i].list, thread) + lumiera_thread_delete ((LumieraThread)thread); ECHO ("destroying the pool mutex"); lumiera_mutex_destroy (&threadpool.pool[i].lock, &NOBUG_FLAG (threadpool)); ECHO ("pool mutex destroyed"); @@ -100,14 +100,14 @@ lumiera_threadpool_acquire_thread(enum lumiera_thread_class kind, // remove it from the pool's list LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[kind].lock) { - ret = (LumieraThread)(llist_unlink(llist_head (&threadpool.pool[kind].list))); + ret = (LumieraThread)(llist_unlink (llist_head (&threadpool.pool[kind].list))); threadpool.pool[kind].working_thread_count++; threadpool.pool[kind].idle_thread_count--; // cheaper than using llist_count ENSURE (threadpool.pool[kind].idle_thread_count == - llist_count(&threadpool.pool[kind].list), + llist_count (&threadpool.pool[kind].list), "idle thread count %d is wrong, should be %d", threadpool.pool[kind].idle_thread_count, - llist_count(&threadpool.pool[kind].list)); + llist_count (&threadpool.pool[kind].list)); } ENSURE (ret, "did not find a valid thread"); } @@ -122,15 +122,15 @@ lumiera_threadpool_release_thread(LumieraThread thread) LUMIERA_MUTEX_SECTION (threadpool, &threadpool.pool[thread->kind].lock) { - REQUIRE (llist_is_single(&thread->node), "thread already belongs to some list"); - llist_insert_head(&threadpool.pool[thread->kind].list, &thread->node); + REQUIRE (llist_is_single (&thread->node), "thread already belongs to some list"); + llist_insert_head (&threadpool.pool[thread->kind].list, &thread->node); threadpool.pool[thread->kind].working_thread_count--; threadpool.pool[thread->kind].idle_thread_count++; // cheaper than using llist_count ENSURE (threadpool.pool[thread->kind].idle_thread_count == - llist_count(&threadpool.pool[thread->kind].list), + llist_count (&threadpool.pool[thread->kind].list), "idle thread count %d is wrong, should be %d", threadpool.pool[thread->kind].idle_thread_count, - llist_count(&threadpool.pool[thread->kind].list)); + llist_count (&threadpool.pool[thread->kind].list)); // REQUIRE (!llist_is_empty (&threadpool.pool[thread->kind].list), "thread pool is still empty after insertion"); } } diff --git a/src/backend/threads.c b/src/backend/threads.c index 62f0d14a6..ef45b1ee8 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -62,7 +62,7 @@ const char* lumiera_threadstate_names[] = { struct lumiera_thread_mockup { - void (*fn)(void*); + void (*fn) (void*); void* arg; LumieraReccondition finished; }; @@ -86,7 +86,7 @@ static void* pthread_runner (void* thread) if (!thread_end_notification) return NULL; // no signalling of thread termination desired - LUMIERA_RECCONDITION_SECTION(cond_sync, thread_end_notification) + LUMIERA_RECCONDITION_SECTION (cond_sync, thread_end_notification) LUMIERA_RECCONDITION_BROADCAST; return NULL; @@ -140,13 +140,13 @@ lumiera_thread_run (enum lumiera_thread_class kind, (void)function; (void)arg; // ask the threadpool for a thread (it might create a new one) - LumieraThread self = lumiera_threadpool_acquire_thread(kind, purpose, flag); + LumieraThread self = lumiera_threadpool_acquire_thread (kind, purpose, flag); // TODO: set the function and data to be run // lumiera_thread_set_func_data (self, start_routine, arg, purpose, flag); // and let it really run (signal the condition var, the thread waits on it) - LUMIERA_RECCONDITION_SECTION(cond_sync, self->finished) + LUMIERA_RECCONDITION_SECTION (cond_sync, self->finished) LUMIERA_RECCONDITION_SIGNAL; // NOTE: example only, add solid error handling! @@ -174,14 +174,14 @@ lumiera_thread_new (enum lumiera_thread_class kind, LumieraThread self = lumiera_malloc (sizeof (*self)); - llist_init(&self->node); + llist_init (&self->node); self->finished = finished; self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; //REQUIRE (thread_loop); int error = pthread_create (&self->id, attrs, &thread_loop, self); - ENSURE(error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror(error)); + ENSURE (error == 0 || EAGAIN == error, "pthread returned %d:%s", error, strerror (error)); if (error) { // error here can only be EAGAIN, given the above ENSURE @@ -197,9 +197,9 @@ lumiera_thread_destroy (LumieraThread self) REQUIRE (self, "trying to destroy an invalid thread"); // TODO: stop the pthread - llist_unlink(&self->node); + llist_unlink (&self->node); //finished = NULL; // or free(finished)? - lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG(threads)); + lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG (threads)); //kind = 0; //state = 0; return self; From ad404bd41a91f1958ae76a620b8c07eaa722a868 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:30:46 -0500 Subject: [PATCH 179/377] remove unused old code --- src/backend/threads.c | 58 ------------------------------------------- 1 file changed, 58 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index ef45b1ee8..3a20901d8 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -60,70 +60,12 @@ const char* lumiera_threadstate_names[] = { }; #undef LUMIERA_THREAD_STATE -struct lumiera_thread_mockup -{ - void (*fn) (void*); - void* arg; - LumieraReccondition finished; -}; - static void* thread_loop (void* arg) { (void)arg; return 0; } -#if 0 -static void* pthread_runner (void* thread) -{ - pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); - - struct lumiera_thread_mockup* starter = (struct lumiera_thread_mockup*) thread; - LumieraReccondition thread_end_notification = starter->finished; - - starter->fn (starter->arg); - - if (!thread_end_notification) - return NULL; // no signalling of thread termination desired - - LUMIERA_RECCONDITION_SECTION (cond_sync, thread_end_notification) - LUMIERA_RECCONDITION_BROADCAST; - - return NULL; -} -#endif - -#if 0 -// TODO: rewrite this using lumiera_threadpool_acquire() -LumieraThread -lumiera_thread_run (enum lumiera_thread_class kind, - void (*start_routine)(void *), - void * arg, - LumieraReccondition finished, - const char* purpose, - struct nobug_flag* flag) -{ - (void) kind; - (void) purpose; - (void) flag; - - if (attr_once == PTHREAD_ONCE_INIT) - pthread_once (&attr_once, thread_attr_init); - - static struct lumiera_thread_mockup thread; - - thread.fn = start_routine; - thread.arg = arg; - thread.finished = finished; - - pthread_t dummy; - int error = pthread_create (&dummy, &attrs, pthread_runner, &thread); - - if (error) return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? - return (LumieraThread) 1; -} -#endif - // TODO: new implementation, remove the above one // maybe this shouldn't return LumieraThread at all // when this is called it should have already been decided that the function From c4e1fdaf9a239fa88af6bdfcdb8237db57c6f189 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:32:55 -0500 Subject: [PATCH 180/377] document lumiera_thread_destroy() and lumiera_thread_delete() --- src/backend/threads.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/backend/threads.h b/src/backend/threads.h index e8b774299..303b9acf2 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -142,9 +142,17 @@ lumiera_thread_new (enum lumiera_thread_class kind, struct nobug_flag* flag, pthread_attr_t* attrs); +/** + * Destroy and de-initialize a thread structure. + * Memory is not freed by this function. + */ LumieraThread lumiera_thread_destroy (LumieraThread self); +/** + * Actually free the memory used by the thread structure. + * Make sure to destroy the structure first. + */ void lumiera_thread_delete (LumieraThread self); From 03fe6dd65831a6c6d52a23048cc916586de5e552 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 07:37:28 -0500 Subject: [PATCH 181/377] properly initialize and de-initialize the thread condition variable --- src/backend/threads.c | 9 +-------- src/backend/threads.h | 4 ---- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 3a20901d8..7b03f57fe 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -74,11 +74,9 @@ LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*function)(void *), void * arg, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag) { - (void)finished; (void)function; (void)arg; // ask the threadpool for a thread (it might create a new one) @@ -101,7 +99,6 @@ lumiera_thread_run (enum lumiera_thread_class kind, */ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag, pthread_attr_t* attrs) @@ -112,12 +109,9 @@ lumiera_thread_new (enum lumiera_thread_class kind, REQUIRE (kind < LUMIERA_THREADCLASS_COUNT, "invalid thread kind specified: %d", kind); REQUIRE (attrs, "invalid pthread attributes structure passed"); - //REQUIRE (finished, "invalid finished flag passed"); - - LumieraThread self = lumiera_malloc (sizeof (*self)); llist_init (&self->node); - self->finished = finished; + lumiera_reccondition_init (&self->finished, "thread-control-condition", flag); self->kind = kind; self->state = LUMIERA_THREADSTATE_IDLE; @@ -140,7 +134,6 @@ lumiera_thread_destroy (LumieraThread self) // TODO: stop the pthread llist_unlink (&self->node); - //finished = NULL; // or free(finished)? lumiera_reccondition_destroy (self->finished, &NOBUG_FLAG (threads)); //kind = 0; //state = 0; diff --git a/src/backend/threads.h b/src/backend/threads.h index 303b9acf2..d91ae7bee 100644 --- a/src/backend/threads.h +++ b/src/backend/threads.h @@ -137,7 +137,6 @@ struct lumiera_thread_struct */ LumieraThread lumiera_thread_new (enum lumiera_thread_class kind, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag, pthread_attr_t* attrs); @@ -169,8 +168,6 @@ lumiera_thread_delete (LumieraThread self); * @param kind class of the thread to start * @param function pointer to a function to execute in a thread (returning void, not void* as in pthreads) * @param arg generic pointer passed to the thread - * @param finished a condition variable to be broadcasted, if not NULL. - * The associated mutex should be locked at thread_run time already, else the signal can get lost. * @param purpose descriptive name of this thread, used by NoBug * @param flag NoBug flag used for logging the thread startup and return */ @@ -178,7 +175,6 @@ LumieraThread lumiera_thread_run (enum lumiera_thread_class kind, void (*function)(void *), void * arg, - LumieraReccondition finished, const char* purpose, struct nobug_flag* flag); From 7a507a0ceeb8298719b0d16f47987256d0e8d8cb Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Thu, 31 Dec 2009 15:09:22 -0500 Subject: [PATCH 182/377] don't put threads in a detached state --- src/backend/threadpool.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backend/threadpool.c b/src/backend/threadpool.c index 55ae77842..fc6041b5f 100644 --- a/src/backend/threadpool.c +++ b/src/backend/threadpool.c @@ -53,7 +53,6 @@ lumiera_threadpool_init(void) //TODO: configure each pools' pthread_attrs appropriately pthread_attr_init (&threadpool.pool[i].pthread_attrs); - pthread_attr_setdetachstate (&threadpool.pool[i].pthread_attrs, PTHREAD_CREATE_DETACHED); //cancel... lumiera_mutex_init (&threadpool.pool[i].lock,"pool of threads", &NOBUG_FLAG (threadpool)); From f517cfb19acf4a44f30d013a054bc73264f14ec7 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 2 Jan 2010 06:26:56 +0100 Subject: [PATCH 183/377] Yess we can! Invented a statical duck-detector! --- src/tool/try.cpp | 89 ++++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/src/tool/try.cpp b/src/tool/try.cpp index 412772c84..af6b66ae1 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -14,6 +14,7 @@ // 10/8 - abusing the STL containers to hold noncopyable values // 6/09 - investigating how to build a mixin template providing an operator bool() // 12/9 - tracking down a strange "warning: type qualifiers ignored on function return type" +// 1/10 - can we determine at compile time the presence of a certain function (for duck-typing)? //#include @@ -21,7 +22,6 @@ //#include "include/logging.h" //#include "include/nobugcfg.h" -#include #include //#include @@ -30,47 +30,59 @@ #include -//using std::tr1::bind; -using std::tr1::placeholders::_1; - //using std::rand; using std::string; using std::cout; +using std::endl; - - template - inline bool - eat_all (SEQ& coll, Oper predicate) +struct A { - typename SEQ::const_iterator e = coll.end(); - typename SEQ::const_iterator i = coll.begin(); - - for ( ; i!=e; ++i ) - if (!predicate(*i)) - return false; - - return true; - } - - template < typename CON, typename FUN - , typename P1 - , typename P2 - > - inline bool - eat_all (CON& elements, FUN function, P1 bind1, P2 bind2) + int& funA (); + }; + +struct B { - return eat_all (elements, std::tr1::bind (function, bind1, bind2)); - } + void funA(); + }; + + + typedef char Yes_t; + struct No_t { char padding[8]; }; + + + template + class Detector1 + { + template + struct Probe + { }; + + template + static Yes_t check(Probe*); + template + static No_t check(...); + + public: + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); + }; - - bool - plainFunc (int i, int j) - { - cout <<':'<< i+j; - return i+j; - } + template + class Detector2 + { + template + struct Probe + { }; + + template + static Yes_t check(Probe*); + template + static No_t check(...); + + public: + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); + }; int @@ -79,14 +91,11 @@ main (int, char**) // NOBUG_INIT; - typedef std::vector VecI; + cout << "Detector1 = " << Detector1::value << endl; + cout << "Detector1 = " << Detector1::value << endl; - uint count = 4; - VecI numberz; - while (count) - numberz.push_back(count--); - - eat_all (numberz, plainFunc, 10, _1 ); + cout << "Detector2 = " << Detector2::value << endl; + cout << "Detector2 = " << Detector2::value << endl; cout << "\n.gulp.\n"; From 8777aa585a380d8abecdc035f90c4438a3318449 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 2 Jan 2010 08:09:40 +0100 Subject: [PATCH 184/377] duck detector (lib helpers): initial implementation draft --- src/lib/meta/duck-detector.hpp | 145 ++++++++++++++++++++++++++ tests/40components.tests | 5 + tests/lib/meta/duck-detector-test.cpp | 90 ++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 src/lib/meta/duck-detector.hpp create mode 100644 tests/lib/meta/duck-detector-test.cpp diff --git a/src/lib/meta/duck-detector.hpp b/src/lib/meta/duck-detector.hpp new file mode 100644 index 000000000..b670538fc --- /dev/null +++ b/src/lib/meta/duck-detector.hpp @@ -0,0 +1,145 @@ +/* + DUCK-DETECTOR.hpp - helpers for statically detecting properties of a type + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file duck-detector.hpp + ** Metaprogramming helpers to check for specific properties of a type in question. + ** Building upon the "SFINE" principle, it is possible to create \em metafunction templates, + ** which answer some questions about a given type at compile time. A lot of generic flavours of + ** this kind can be found in the boost-type-trait library (part of std::tr1). At times though, + ** you want to ask more specific questions, like e.g. "does this type provide an operation \c quack() "? + ** Because, if we can get a \c bool answer to such a question at compile time, we can use + ** \c boost::enable_if to pick a special implementation based on the test result. Together, these + ** techniques allow to adopt a duck-typed programming style, where an arbitrary object is allowed + ** to enter a given API function, provided this object supports some special operations. + ** + ** While C++ certainly isn't a dynamic language and doesn't provide any kind of run time introspection, + ** doing such check-and branch at compile time allows even to combine such a flexible approach with + ** static type safety, which is compelling. (The downside is the danger of code bloat, as is with all + ** template based techniques). + ** + ** \par how the implementation works + ** + ** Most of these trait templates rely on a creative use of function overloading. The C++ standard + ** requires the compiler silently to drop any candidate of overload resolution which has + ** gotten an invalid function signature as a result of instantiating a template (type). This allow + ** us to set up kind of a "trap" for the compiler: we present two overloaded candidate functions + ** with a different return type; by investigating the resulting return type we're able to figure + ** out the overload actually picked by the compiler. + ** + ** This header provides some pre-configured tests, available as macros. Each of them contains + ** a template based on the described setup, containing a \em probe type expression at some point. + ** The key is to build this probe expression in a way that it's valid only if the type in question + ** has a specific property + ** + ** - if the type should contain a nested type of typedef with a specific name, we simply use + ** this nested type in the signature of the overloaded function + ** - if the type should contain a \em member with a specific name, we initialise a member pointer + ** within a probe template with this member (if there isn't such a member, the probe template + ** initialisation fails and the other function overload gets picked) + ** - as an extension to this approach, we can even declare a member function pointer with a + ** specific function signature and then try to assign the named member. This allows even + ** to determine if a member function of a type in question has the desired signature. + ** + ** All these detection building blocks are written such as to provide a bool member \v ::value, + ** which is in accordance to the conventions of boost metaprogramming. I.e. you can immediately + ** use them within boost::enable_if + ** + ** @see util-foreach.hpp usage example + ** @see duck-detector-test.cpp + ** + */ + + +#ifndef LIB_META_DUCK_DETECTOR_H +#define LIB_META_DUCK_DETECTOR_H + + + +namespace lib { + + + /* types for figuring out the overload resolution chosen by the compiler */ + + typedef char Yes_t; + struct No_t { char padding[8]; }; + + ////////////////////////////////////TODO: after fixing the namespace of typelist/meta programming facilities, these can be dropped. + + + + namespace meta { + + /////////////////////////////TODO: still hard wired for a first test.... + + template + class DetectNested + { + + template + static Yes_t check(typename X::Core *); + template + static No_t check(...); + + public: + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); + }; + + + template + class DetectMember + { + template + struct Probe + { }; + + template + static Yes_t check(Probe*); + template + static No_t check(...); + + public: + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); + }; + + + template + class DetectFunSig + { + template + struct Probe + { }; + + template + static Yes_t check(Probe*); + template + static No_t check(...); + + public: + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); + }; + + + } // namespace meta + +} // namespace lib +#endif diff --git a/tests/40components.tests b/tests/40components.tests index 6aae03697..6fb0f0fa3 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -182,6 +182,11 @@ return: 0 END +PLANNED "Duck typing support" DuckDetector_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/meta/duck-detector.hpp" +#include "lib/util.hpp" /////////////TODO + +#include + + +namespace lib { +namespace meta{ +namespace test{ + + //using std::string; + using std::cout; + using std::endl; + + + namespace { // some test ducks.... + + struct PropperGander + { + class Core; + + PropperGander& honk(); + }; + + struct Propaganda + { + void honk(); + }; + +#define DO_CHECK(_EXPR_) cout << STRINGIFY(_EXPR_) << "\t = " << _EXPR_::value << endl; + + }//(End) with test ducks + + + /*********************************************************************************** + * @test verify building predicates to detect properties of a type at compile time. + * Especially, this allows us to detect if a type in question + * - has a nested type with a specific name + * - has a member with a specific name + * - defines a function with a specific signature + */ + class DuckDetector_test : public Test + { + void + run (Arg) + { + DO_CHECK( DetectNested ); + DO_CHECK( DetectNested ); + + DO_CHECK( DetectMember ); + DO_CHECK( DetectMember ); + + DO_CHECK( DetectFunSig ); + DO_CHECK( DetectFunSig ); + + UNIMPLEMENTED ("detect the propaganda"); + } + }; + + + /** Register this test class... */ + LAUNCHER (DuckDetector_test, "unit common"); + + + +}}} // namespace lib::meta::test From e27d03c5013ae7cf3f083f2a642588f0386905d2 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 2 Jan 2010 09:07:10 +0100 Subject: [PATCH 185/377] simple duck detecor components pass unit test --- src/lib/meta/duck-detector.hpp | 128 ++++++++++++++++---------- tests/40components.tests | 8 +- tests/lib/meta/duck-detector-test.cpp | 37 +++++--- 3 files changed, 107 insertions(+), 66 deletions(-) diff --git a/src/lib/meta/duck-detector.hpp b/src/lib/meta/duck-detector.hpp index b670538fc..5bc33d937 100644 --- a/src/lib/meta/duck-detector.hpp +++ b/src/lib/meta/duck-detector.hpp @@ -89,57 +89,85 @@ namespace lib { namespace meta { - /////////////////////////////TODO: still hard wired for a first test.... - - template - class DetectNested - { - - template - static Yes_t check(typename X::Core *); - template - static No_t check(...); - - public: - static const bool value = (sizeof(Yes_t)==sizeof(check(0))); - }; - - - template - class DetectMember - { - template - struct Probe - { }; - - template - static Yes_t check(Probe*); - template - static No_t check(...); - - public: - static const bool value = (sizeof(Yes_t)==sizeof(check(0))); - }; - - - template - class DetectFunSig - { - template - struct Probe - { }; - - template - static Yes_t check(Probe*); - template - static No_t check(...); - - public: - static const bool value = (sizeof(Yes_t)==sizeof(check(0))); - }; - - } // namespace meta } // namespace lib + + + + + + +/** Detector for a nested type. + * Defines a metafunction (template), allowing to detect + * if a type TY in question has a nested type or typedef + * with the given name. To answer this question, instantiate + * resulting HasNested_XXX template with the type in question + * and check the static bool value field. + */ +#define META_DETECT_NESTED(_TYPE_) \ + template \ + class HasNested_##_TYPE_ \ + { \ + \ + template \ + static Yes_t check(typename X::_TYPE_ *); \ + template \ + static No_t check(...); \ + \ + public: \ + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); \ + }; + + + +/** Detector for a nested member (field or function). + * Defines a metafunction (template), allowing to detect + * the presence of a member with the given name within + * a type in question. + */ +#define META_DETECT_MEMBER(_NAME_) \ + template \ + class HasMember_##_NAME_ \ + { \ + template \ + struct Probe \ + { }; \ + \ + template \ + static Yes_t check(Probe * ); \ + template \ + static No_t check(...); \ + \ + public: \ + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); \ + }; + + + +/** Detector for a specific member function. + * Defines a metafunction (template), allowing to detect + * the presence of a member function with the specific + * signature, as defined by the parameters. Note this + * check will probably fail if there are overloads + */ +#define META_DETECT_FUNCTION(_RET_TYPE_,_FUN_NAME_,_ARGS_) \ + template \ + class HasFunSig_##_FUN_NAME_ \ + { \ + template \ + struct Probe \ + { }; \ + \ + template \ + static Yes_t check(Probe * ); \ + template \ + static No_t check(...); \ + \ + public: \ + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); \ + }; + + + #endif diff --git a/tests/40components.tests b/tests/40components.tests index 6fb0f0fa3..585be3d6f 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -182,7 +182,13 @@ return: 0 END -PLANNED "Duck typing support" DuckDetector_test < : Yes +out: HasNested_Core : No +out: HasMember_honk : Yes +out: HasMember_honk : Yes +out: HasFunSig_honk : Yes +out: HasFunSig_honk : No return: 0 END diff --git a/tests/lib/meta/duck-detector-test.cpp b/tests/lib/meta/duck-detector-test.cpp index 25312ca33..bf0c15f5a 100644 --- a/tests/lib/meta/duck-detector-test.cpp +++ b/tests/lib/meta/duck-detector-test.cpp @@ -23,7 +23,7 @@ #include "lib/test/run.hpp" #include "lib/meta/duck-detector.hpp" -#include "lib/util.hpp" /////////////TODO +#include "lib/util.hpp" #include @@ -31,30 +31,33 @@ namespace lib { namespace meta{ namespace test{ - - //using std::string; + using std::cout; using std::endl; namespace { // some test ducks.... + struct PropperGander { class Core; - PropperGander& honk(); + PropperGander& honk (long,long); }; + struct Propaganda { - void honk(); + void honk(float); }; - -#define DO_CHECK(_EXPR_) cout << STRINGIFY(_EXPR_) << "\t = " << _EXPR_::value << endl; + }//(End) with test ducks +#define SHOW_CHECK(_EXPR_) cout << STRINGIFY(_EXPR_) << "\t : " << (_EXPR_::value? "Yes":"No") << endl; + + /*********************************************************************************** * @test verify building predicates to detect properties of a type at compile time. @@ -65,19 +68,23 @@ namespace test{ */ class DuckDetector_test : public Test { + + META_DETECT_NESTED(Core); + META_DETECT_MEMBER(honk); + META_DETECT_FUNCTION(PropperGander&, honk, (long,long)); + + void run (Arg) { - DO_CHECK( DetectNested ); - DO_CHECK( DetectNested ); + SHOW_CHECK( HasNested_Core ); + SHOW_CHECK( HasNested_Core ); - DO_CHECK( DetectMember ); - DO_CHECK( DetectMember ); + SHOW_CHECK( HasMember_honk ); + SHOW_CHECK( HasMember_honk ); - DO_CHECK( DetectFunSig ); - DO_CHECK( DetectFunSig ); - - UNIMPLEMENTED ("detect the propaganda"); + SHOW_CHECK( HasFunSig_honk ); + SHOW_CHECK( HasFunSig_honk ); } }; From ce6767b71f55d57e2b46c9353b94601f06d0fa19 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 3 Jan 2010 00:02:53 +0100 Subject: [PATCH 186/377] Testcase to verify the iterable type detection --- tests/40components.tests | 4 + .../lib/meta/iterable-classification-test.cpp | 155 ++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 tests/lib/meta/iterable-classification-test.cpp diff --git a/tests/40components.tests b/tests/40components.tests index 585be3d6f..1bc9b1717 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -356,6 +356,10 @@ out: ::12::11::10::9::8::7::6::5::4::3 END +PLANNED "Iterable type detection" IterableClassification_test < + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" + +#include "proc/mobject/session/scope-query.hpp" +#include "proc/mobject/session/effect.hpp" +#include "lib/meta/duck-detector.hpp" +#include "lib/util-foreach.hpp" +#include "lib/itertools.hpp" +#include "lib/lumitime.hpp" + +#include +#include +#include +#include +#include +#include + + +namespace lib { +/////////////////////////////////////////////////////////////TODO draft + + template + struct can_STL_ForEach + { + enum{ value = false }; ////////////////TODO unimplemented + }; + + template + struct can_IterForEach + { + enum{ value = false }; ////////////////TODO unimplemented + }; + +/////////////////////////////////////////////////////////////TODO draft +namespace meta{ +namespace test{ + + using lumiera::Time; + using mobject::session::Effect; + using mobject::session::ScopeQuery; + + using std::cout; + using std::endl; + + + namespace { // a custom test container.... + + + struct TestSource + { + vector data_; + + TestSource(uint num); + + typedef vector::iterator sourceIter; + typedef RangeIter iterator; + + iterator begin() ; + iterator end() ; + // note: a bare type definition is sufficient here.... + }; + + + + }//(End) test containers + +#define SHOW_CHECK(_EXPR_) cout << STRINGIFY(_EXPR_) << "\t : " << (_EXPR_::value? "Yes":"No") << endl; + + + + /*********************************************************************************** + * @test verify the (static) classification/detection of iterables. + * Currently (1/10) we're able to detect the following + * - a STL like container with \c begin() and \c end() + * - a Lumiera Forward Iterator + */ + class IterableClassification_test : public Test + { + + + + void + run (Arg) + { + typedef std::vector LongVector; + typedef std::multiset